@fayz-ai/storefront 0.77.0 → 0.77.5

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.
@@ -1,11 +1,12 @@
1
1
  import { create } from 'zustand';
2
2
  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 { 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';
3
7
  import { createMockAuthAdapter } from '@fayz-ai/auth';
4
8
  import { createAuthRuntime } from '@fayz-ai/auth/lib/runtime';
5
- import { getShopProvider, setShopProvider } from '@fayz-ai/shop/runtime';
6
9
  import { setShopCarrierQuotesResolver, setShopAccessTokenResolver, setShopShippingItemsResolver } from '@fayz-ai/sdk/shop';
7
- 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';
8
- import React38, { createContext, useContext, useEffect, useRef, useState, useSyncExternalStore, useMemo, useCallback } from 'react';
9
10
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
10
11
  import { isStorageImageUrl, imageVariantUrl, imageSrcSet, IMAGE_SRCSET_WIDTHS, validateDiscount, documentDigits, isChargeableProvider, supportsCard, formatDocument, isValidDocument, gatewayLabel, isValidCpf } from '@fayz-ai/shop';
11
12
  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,164 +14,7 @@ import { getLucideIcon } from '@fayz-ai/ui/icons';
13
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';
14
15
  import { createMockShopProvider } from '@fayz-ai/shop/mock';
15
16
 
16
- // src/stores/session.store.ts
17
- var useSessionStore = create()(
18
- persist(
19
- (set) => ({
20
- customerId: null,
21
- email: null,
22
- name: null,
23
- setSession: ({ customerId, email, name }) => set({ customerId, email, name: name ?? null }),
24
- signOut: () => set({ customerId: null, email: null, name: null })
25
- }),
26
- { name: "fayz.storefront.session.v1" }
27
- )
28
- );
29
- var EmailConfirmationRequiredError = class extends Error {
30
- constructor(email) {
31
- super("Cadastro realizado. Confirme seu e-mail para continuar.");
32
- this.name = "EmailConfirmationRequiredError";
33
- this.email = email;
34
- }
35
- };
36
- var _adapter = null;
37
- function isAuthAdapter(value) {
38
- return Boolean(
39
- value && typeof value === "object" && "getSession" in value && "signIn" in value && "signOut" in value
40
- );
41
- }
42
- function normalizeAuthConfig(configured) {
43
- if (!configured) return {};
44
- if (typeof configured === "string" || isAuthAdapter(configured)) return { adapter: configured };
45
- return configured;
46
- }
47
- function resolveAuthAdapter(configured, fallback) {
48
- const config = normalizeAuthConfig(configured);
49
- return createAuthRuntime({
50
- provider: config.provider ?? config.adapter ?? (fallback?.supabaseUrl ? "supabase" : "mock"),
51
- adapter: config.adapter,
52
- routes: config.routes,
53
- requireAuth: false,
54
- supabase: {
55
- url: config.supabase?.url ?? fallback?.supabaseUrl,
56
- anonKey: config.supabase?.anonKey ?? fallback?.supabaseAnonKey,
57
- client: config.supabase?.client,
58
- callbackUrl: config.supabase?.callbackUrl,
59
- resetPasswordUrl: config.supabase?.resetPasswordUrl
60
- }
61
- }).adapter;
62
- }
63
- var _accessToken = null;
64
- var _hadAuthUser = false;
65
- async function syncAccessToken(adapter) {
66
- try {
67
- const existing = await adapter.getSession();
68
- _accessToken = existing?.session.accessToken ?? null;
69
- } catch {
70
- _accessToken = null;
71
- }
72
- }
73
- function initCustomerAuth(adapter) {
74
- _adapter = adapter;
75
- setShopAccessTokenResolver(() => _accessToken);
76
- adapter.getSession().then((existing) => {
77
- _accessToken = existing?.session.accessToken ?? null;
78
- if (!existing) return;
79
- _hadAuthUser = true;
80
- void linkCustomer(existing.user).catch(() => {
81
- });
82
- }).catch(() => {
83
- });
84
- adapter.onAuthStateChange((user) => {
85
- if (!user) {
86
- _accessToken = null;
87
- if (_hadAuthUser) {
88
- _hadAuthUser = false;
89
- useSessionStore.getState().signOut();
90
- }
91
- return;
92
- }
93
- _hadAuthUser = true;
94
- const linked = useSessionStore.getState();
95
- const needsLink = !linked.customerId || (linked.email ?? "").toLowerCase() !== (user.email ?? "").toLowerCase();
96
- void syncAccessToken(adapter).then(() => {
97
- if (needsLink && user.email) return linkCustomer(user).then(() => void 0);
98
- }).catch(() => {
99
- });
100
- });
101
- }
102
- function hasCustomerAuth() {
103
- return _hadAuthUser;
104
- }
105
- async function relinkCustomer() {
106
- if (!_hadAuthUser) return null;
107
- const existing = await getCustomerAuthAdapter().getSession().catch(() => null);
108
- if (!existing?.user.email) return null;
109
- const customer = await resolveShopCustomer(existing.user.email.trim().toLowerCase(), existing.user.fullName ?? "");
110
- const store = useSessionStore.getState();
111
- store.setSession({ customerId: customer.id, email: existing.user.email.trim().toLowerCase(), name: store.name });
112
- return { customerId: customer.id, phone: customer.phone ?? null, document: customer.document ?? null };
113
- }
114
- function getCustomerAuthAdapter() {
115
- if (!_adapter) _adapter = createMockAuthAdapter();
116
- return _adapter;
117
- }
118
- async function resolveShopCustomer(email, name) {
119
- const provider = getShopProvider();
120
- if (provider.resolveCustomer) return provider.resolveCustomer({ email, name });
121
- const matches = await provider.listCustomers({ search: email, limit: 10 });
122
- const existing = matches.find((c) => (c.email ?? "").toLowerCase() === email);
123
- if (existing) return existing;
124
- const parts = name.trim().split(/\s+/).filter(Boolean);
125
- return provider.createCustomer({
126
- firstName: parts[0] ?? email.split("@")[0] ?? "Cliente",
127
- lastName: parts.slice(1).join(" "),
128
- email
129
- });
130
- }
131
- async function linkCustomer(user, fullName) {
132
- const email = (user.email ?? "").trim().toLowerCase();
133
- const name = fullName ?? user.fullName ?? "";
134
- const customer = await resolveShopCustomer(email, name);
135
- useSessionStore.getState().setSession({
136
- customerId: customer.id,
137
- email,
138
- name: name || `${customer.firstName} ${customer.lastName}`.trim()
139
- });
140
- return { customerId: customer.id };
141
- }
142
- async function establishCustomerSession(email, opts) {
143
- const normalized = email.trim().toLowerCase();
144
- if (opts?.password) {
145
- const adapter = getCustomerAuthAdapter();
146
- const session = await adapter.signIn(normalized, opts.password);
147
- _accessToken = session.accessToken ?? null;
148
- _hadAuthUser = true;
149
- return linkCustomer(session.user.email ? session.user : { ...session.user, email: normalized }, opts.name);
150
- }
151
- return linkCustomer({ email: normalized }, opts?.name);
152
- }
153
- function signInByEmail(email, name) {
154
- return establishCustomerSession(email, { name });
155
- }
156
- async function signUpCustomer(email, password, name) {
157
- const adapter = getCustomerAuthAdapter();
158
- const normalized = email.trim().toLowerCase();
159
- const session = await adapter.signUp(normalized, password, name);
160
- if (!session.accessToken) throw new EmailConfirmationRequiredError(normalized);
161
- _accessToken = session.accessToken;
162
- _hadAuthUser = true;
163
- return linkCustomer(session.user.email ? session.user : { ...session.user, email: normalized }, name);
164
- }
165
- async function signOutCustomer() {
166
- try {
167
- await getCustomerAuthAdapter().signOut();
168
- } finally {
169
- _accessToken = null;
170
- _hadAuthUser = false;
171
- useSessionStore.getState().signOut();
172
- }
173
- }
17
+ // src/stores/market.store.ts
174
18
  var useMarketStore = create()((set) => ({
175
19
  markets: [],
176
20
  active: null,
@@ -607,6 +451,339 @@ var selectShipping = (s2, cfg) => {
607
451
  };
608
452
  var selectTotal = (s2, cfg) => roundCents(selectSubtotal(s2) - selectDiscountTotal(s2) + selectShipping(s2, cfg));
609
453
 
454
+ // src/analytics/bus.ts
455
+ var MAX_PENDING = 50;
456
+ var listeners = /* @__PURE__ */ new Set();
457
+ var pending = [];
458
+ var identifier = null;
459
+ var pendingEmail = null;
460
+ var lastAt = /* @__PURE__ */ new Map();
461
+ function trackStorefront(name, properties = {}) {
462
+ if (typeof window === "undefined") return;
463
+ const event = { name, properties, at: Date.now() };
464
+ lastAt.set(name, event.at);
465
+ if (listeners.size === 0) {
466
+ pending.push(event);
467
+ if (pending.length > MAX_PENDING) pending = pending.slice(-MAX_PENDING);
468
+ return;
469
+ }
470
+ for (const listener of listeners) {
471
+ try {
472
+ listener(event);
473
+ } catch {
474
+ }
475
+ }
476
+ }
477
+ function onStorefrontEvent(listener) {
478
+ listeners.add(listener);
479
+ if (pending.length) {
480
+ const held = pending;
481
+ pending = [];
482
+ for (const event of held) {
483
+ try {
484
+ listener(event);
485
+ } catch {
486
+ }
487
+ }
488
+ }
489
+ return () => {
490
+ listeners.delete(listener);
491
+ };
492
+ }
493
+ function identifyStorefrontBuyer(email) {
494
+ const clean = email.trim().toLowerCase();
495
+ if (!clean.includes("@")) return;
496
+ if (identifier) identifier(clean);
497
+ else pendingEmail = clean;
498
+ }
499
+ function setStorefrontIdentifier(fn) {
500
+ identifier = fn;
501
+ if (fn && pendingEmail) {
502
+ fn(pendingEmail);
503
+ pendingEmail = null;
504
+ }
505
+ }
506
+ function lastStorefrontEventAt(name) {
507
+ return lastAt.get(name) ?? 0;
508
+ }
509
+
510
+ // src/analytics/identity.ts
511
+ async function storeBuyerId(storeId, email) {
512
+ const clean = email.trim().toLowerCase();
513
+ if (!storeId || !clean.includes("@")) return null;
514
+ const subtle = globalThis.crypto?.subtle;
515
+ if (!subtle) return null;
516
+ const digest = await subtle.digest("SHA-256", new TextEncoder().encode(clean));
517
+ const hex = Array.from(new Uint8Array(digest), (b) => b.toString(16).padStart(2, "0")).join("");
518
+ return `store:${storeId}:${hex}`;
519
+ }
520
+
521
+ // src/analytics/posthog.ts
522
+ var started = null;
523
+ function startStorefrontPostHog(config, context) {
524
+ if (typeof window === "undefined" || !config.key || !config.storeId) return null;
525
+ if (started) return started;
526
+ started = (async () => {
527
+ const { default: posthog } = await import('posthog-js');
528
+ const store = { store_id: config.storeId, store_name: context.storeName, commerce_mode: context.commerceMode };
529
+ posthog.init(config.key, {
530
+ api_host: config.apiHost ?? "/ingest",
531
+ ui_host: config.uiHost ?? "https://us.posthog.com",
532
+ defaults: "2026-08-30",
533
+ person_profiles: "identified_only",
534
+ capture_pageview: "history_change",
535
+ capture_dead_clicks: true,
536
+ capture_heatmaps: true,
537
+ disable_session_recording: config.replay === false,
538
+ session_recording: { maskAllInputs: true },
539
+ before_send: (event) => {
540
+ if (!event) return event;
541
+ const groups = event.properties.$groups ?? {};
542
+ event.properties.$groups = { ...groups, store: config.storeId };
543
+ return event;
544
+ }
545
+ });
546
+ posthog.register(store);
547
+ onStorefrontEvent((event) => {
548
+ posthog.capture(event.name, event.properties, { timestamp: new Date(event.at) });
549
+ });
550
+ setStorefrontIdentifier((email) => {
551
+ void storeBuyerId(config.storeId, email).then((id) => {
552
+ if (id && posthog.get_distinct_id() !== id) posthog.identify(id, { store_id: config.storeId });
553
+ });
554
+ });
555
+ })().catch(() => {
556
+ started = null;
557
+ });
558
+ return started;
559
+ }
560
+ function isOrderingPath(path, menuPath) {
561
+ const p = path.split(/[?#]/)[0] || "/";
562
+ if (menuPath && menuPath !== "/" && (p === menuPath || p.startsWith(`${menuPath}/`))) return true;
563
+ return /^\/(product|checkout|cart|order|account)(\/|$)/.test(p);
564
+ }
565
+ function cartChanges(prev, next) {
566
+ const key = (l) => l.lineId ?? l.productId;
567
+ const before = new Map(prev.lines.map((l) => [key(l), l]));
568
+ const after = new Map(next.lines.map((l) => [key(l), l]));
569
+ const out = [];
570
+ for (const [id, line] of after) {
571
+ const delta = line.quantity - (before.get(id)?.quantity ?? 0);
572
+ if (delta > 0) out.push({ kind: "added", line, quantity: delta });
573
+ if (delta < 0) out.push({ kind: "removed", line, quantity: -delta });
574
+ }
575
+ for (const [id, line] of before) if (!after.has(id)) out.push({ kind: "removed", line, quantity: line.quantity });
576
+ return out;
577
+ }
578
+ function StorefrontAnalytics({ config, path }) {
579
+ const posthog = config.analytics?.posthog;
580
+ const menuPath = config.delivery?.menuPath;
581
+ const previous = React39.useRef(null);
582
+ React39.useEffect(() => {
583
+ if (!posthog) return;
584
+ startStorefrontPostHog(posthog, { storeName: config.name, commerceMode: config.commerceMode });
585
+ }, [posthog, config.name, config.commerceMode]);
586
+ React39.useEffect(() => {
587
+ if (!posthog) return;
588
+ let ready = useCartStore.persist?.hasHydrated?.() ?? true;
589
+ const unhydrated = useCartStore.persist?.onFinishHydration?.(() => {
590
+ ready = true;
591
+ });
592
+ const unsubscribe = useCartStore.subscribe((next, prev) => {
593
+ if (!ready) return;
594
+ const totals = { cart_count: selectCount(next), cart_subtotal: selectSubtotal(next) };
595
+ const justOrdered = next.lines.length === 0 && Date.now() - lastStorefrontEventAt("checkout_completed") < 1e4;
596
+ for (const change of justOrdered ? [] : cartChanges(prev, next)) {
597
+ trackStorefront(change.kind === "added" ? "product_added_to_cart" : "product_removed_from_cart", {
598
+ product_id: change.line.productId,
599
+ product_name: change.line.name,
600
+ variant_id: change.line.variantId ?? null,
601
+ options: change.line.optionsLabel ?? null,
602
+ price: change.line.unitPrice,
603
+ quantity: change.quantity,
604
+ ...totals
605
+ });
606
+ }
607
+ if (next.isOpen && !prev.isOpen) trackStorefront("cart_viewed", totals);
608
+ if (next.discountCode && next.discountCode !== prev.discountCode) {
609
+ trackStorefront("coupon_applied", { coupon: next.discountCode, discount_percent: next.discountPercent, ...totals });
610
+ }
611
+ });
612
+ return () => {
613
+ unsubscribe();
614
+ unhydrated?.();
615
+ };
616
+ }, [posthog]);
617
+ React39.useEffect(() => {
618
+ if (!posthog) return;
619
+ const from = previous.current;
620
+ previous.current = path;
621
+ if (!from || from === path) return;
622
+ if (isOrderingPath(from, menuPath) && !isOrderingPath(path, menuPath)) {
623
+ const cart = useCartStore.getState();
624
+ trackStorefront("delivery_exit", { from, to: path, cart_count: selectCount(cart), cart_subtotal: selectSubtotal(cart) });
625
+ }
626
+ }, [posthog, path, menuPath]);
627
+ return null;
628
+ }
629
+ var useSessionStore = create()(
630
+ persist(
631
+ (set) => ({
632
+ customerId: null,
633
+ email: null,
634
+ name: null,
635
+ setSession: ({ customerId, email, name }) => set({ customerId, email, name: name ?? null }),
636
+ signOut: () => set({ customerId: null, email: null, name: null })
637
+ }),
638
+ { name: "fayz.storefront.session.v1" }
639
+ )
640
+ );
641
+ var EmailConfirmationRequiredError = class extends Error {
642
+ constructor(email) {
643
+ super("Cadastro realizado. Confirme seu e-mail para continuar.");
644
+ this.name = "EmailConfirmationRequiredError";
645
+ this.email = email;
646
+ }
647
+ };
648
+ var _adapter = null;
649
+ function isAuthAdapter(value) {
650
+ return Boolean(
651
+ value && typeof value === "object" && "getSession" in value && "signIn" in value && "signOut" in value
652
+ );
653
+ }
654
+ function normalizeAuthConfig(configured) {
655
+ if (!configured) return {};
656
+ if (typeof configured === "string" || isAuthAdapter(configured)) return { adapter: configured };
657
+ return configured;
658
+ }
659
+ function resolveAuthAdapter(configured, fallback) {
660
+ const config = normalizeAuthConfig(configured);
661
+ return createAuthRuntime({
662
+ provider: config.provider ?? config.adapter ?? (fallback?.supabaseUrl ? "supabase" : "mock"),
663
+ adapter: config.adapter,
664
+ routes: config.routes,
665
+ requireAuth: false,
666
+ supabase: {
667
+ url: config.supabase?.url ?? fallback?.supabaseUrl,
668
+ anonKey: config.supabase?.anonKey ?? fallback?.supabaseAnonKey,
669
+ client: config.supabase?.client,
670
+ callbackUrl: config.supabase?.callbackUrl,
671
+ resetPasswordUrl: config.supabase?.resetPasswordUrl
672
+ }
673
+ }).adapter;
674
+ }
675
+ var _accessToken = null;
676
+ var _hadAuthUser = false;
677
+ async function syncAccessToken(adapter) {
678
+ try {
679
+ const existing = await adapter.getSession();
680
+ _accessToken = existing?.session.accessToken ?? null;
681
+ } catch {
682
+ _accessToken = null;
683
+ }
684
+ }
685
+ function initCustomerAuth(adapter) {
686
+ _adapter = adapter;
687
+ setShopAccessTokenResolver(() => _accessToken);
688
+ adapter.getSession().then((existing) => {
689
+ _accessToken = existing?.session.accessToken ?? null;
690
+ if (!existing) return;
691
+ _hadAuthUser = true;
692
+ void linkCustomer(existing.user).catch(() => {
693
+ });
694
+ }).catch(() => {
695
+ });
696
+ adapter.onAuthStateChange((user) => {
697
+ if (!user) {
698
+ _accessToken = null;
699
+ if (_hadAuthUser) {
700
+ _hadAuthUser = false;
701
+ useSessionStore.getState().signOut();
702
+ }
703
+ return;
704
+ }
705
+ _hadAuthUser = true;
706
+ const linked = useSessionStore.getState();
707
+ const needsLink = !linked.customerId || (linked.email ?? "").toLowerCase() !== (user.email ?? "").toLowerCase();
708
+ void syncAccessToken(adapter).then(() => {
709
+ if (needsLink && user.email) return linkCustomer(user).then(() => void 0);
710
+ }).catch(() => {
711
+ });
712
+ });
713
+ }
714
+ function hasCustomerAuth() {
715
+ return _hadAuthUser;
716
+ }
717
+ async function relinkCustomer() {
718
+ if (!_hadAuthUser) return null;
719
+ const existing = await getCustomerAuthAdapter().getSession().catch(() => null);
720
+ if (!existing?.user.email) return null;
721
+ const customer = await resolveShopCustomer(existing.user.email.trim().toLowerCase(), existing.user.fullName ?? "");
722
+ const store = useSessionStore.getState();
723
+ store.setSession({ customerId: customer.id, email: existing.user.email.trim().toLowerCase(), name: store.name });
724
+ return { customerId: customer.id, phone: customer.phone ?? null, document: customer.document ?? null };
725
+ }
726
+ function getCustomerAuthAdapter() {
727
+ if (!_adapter) _adapter = createMockAuthAdapter();
728
+ return _adapter;
729
+ }
730
+ async function resolveShopCustomer(email, name) {
731
+ const provider = getShopProvider();
732
+ if (provider.resolveCustomer) return provider.resolveCustomer({ email, name });
733
+ const matches = await provider.listCustomers({ search: email, limit: 10 });
734
+ const existing = matches.find((c) => (c.email ?? "").toLowerCase() === email);
735
+ if (existing) return existing;
736
+ const parts = name.trim().split(/\s+/).filter(Boolean);
737
+ return provider.createCustomer({
738
+ firstName: parts[0] ?? email.split("@")[0] ?? "Cliente",
739
+ lastName: parts.slice(1).join(" "),
740
+ email
741
+ });
742
+ }
743
+ async function linkCustomer(user, fullName) {
744
+ const email = (user.email ?? "").trim().toLowerCase();
745
+ const name = fullName ?? user.fullName ?? "";
746
+ const customer = await resolveShopCustomer(email, name);
747
+ useSessionStore.getState().setSession({
748
+ customerId: customer.id,
749
+ email,
750
+ name: name || `${customer.firstName} ${customer.lastName}`.trim()
751
+ });
752
+ return { customerId: customer.id };
753
+ }
754
+ async function establishCustomerSession(email, opts) {
755
+ const normalized = email.trim().toLowerCase();
756
+ if (opts?.password) {
757
+ const adapter = getCustomerAuthAdapter();
758
+ const session = await adapter.signIn(normalized, opts.password);
759
+ _accessToken = session.accessToken ?? null;
760
+ _hadAuthUser = true;
761
+ return linkCustomer(session.user.email ? session.user : { ...session.user, email: normalized }, opts.name);
762
+ }
763
+ return linkCustomer({ email: normalized }, opts?.name);
764
+ }
765
+ function signInByEmail(email, name) {
766
+ return establishCustomerSession(email, { name });
767
+ }
768
+ async function signUpCustomer(email, password, name) {
769
+ const adapter = getCustomerAuthAdapter();
770
+ const normalized = email.trim().toLowerCase();
771
+ const session = await adapter.signUp(normalized, password, name);
772
+ if (!session.accessToken) throw new EmailConfirmationRequiredError(normalized);
773
+ _accessToken = session.accessToken;
774
+ _hadAuthUser = true;
775
+ return linkCustomer(session.user.email ? session.user : { ...session.user, email: normalized }, name);
776
+ }
777
+ async function signOutCustomer() {
778
+ try {
779
+ await getCustomerAuthAdapter().signOut();
780
+ } finally {
781
+ _accessToken = null;
782
+ _hadAuthUser = false;
783
+ useSessionStore.getState().signOut();
784
+ }
785
+ }
786
+
610
787
  // src/data/facets.ts
611
788
  function matchesFacets(metadata, facets) {
612
789
  for (const [key, wanted] of Object.entries(facets)) {
@@ -1626,7 +1803,7 @@ function Link({ to, children, onClick, target, ...rest }) {
1626
1803
  event.preventDefault();
1627
1804
  adapter.navigate(to);
1628
1805
  };
1629
- return React38.createElement(
1806
+ return React39__default.createElement(
1630
1807
  "a",
1631
1808
  { href: adapter.href(to), onClick: handleClick, target, ...rest },
1632
1809
  children
@@ -1866,9 +2043,9 @@ function SmoothImage({
1866
2043
  const easing = resolved.easing ?? "cubic-bezier(0.22, 1, 0.36, 1)";
1867
2044
  const blur = resolved.blur ?? true;
1868
2045
  const transform = resolved.transform ?? "none";
1869
- const ref = React38.useRef(null);
1870
- const [loaded, setLoaded] = React38.useState(() => mode === "none" || !clientMounted);
1871
- const delivered = React38.useMemo(() => {
2046
+ const ref = React39__default.useRef(null);
2047
+ const [loaded, setLoaded] = React39__default.useState(() => mode === "none" || !clientMounted);
2048
+ const delivered = React39__default.useMemo(() => {
1872
2049
  if (transform !== "supabase" || !src || srcSet || !isStorageImageUrl(src)) return { src, srcSet, sizes };
1873
2050
  if (variant?.width) {
1874
2051
  const w = variant.width;
@@ -1886,10 +2063,10 @@ function SmoothImage({
1886
2063
  sizes: variant?.sizes ?? sizes ?? "100vw"
1887
2064
  };
1888
2065
  }, [transform, src, srcSet, sizes, variant?.width, variant?.sizes, variant?.widths, variant?.quality]);
1889
- React38.useEffect(() => {
2066
+ React39__default.useEffect(() => {
1890
2067
  clientMounted = true;
1891
2068
  }, []);
1892
- React38.useEffect(() => {
2069
+ React39__default.useEffect(() => {
1893
2070
  if (mode === "none") {
1894
2071
  setLoaded(true);
1895
2072
  return;
@@ -2287,17 +2464,17 @@ function PageDataScope({ nodes, params, initial: initial2, children }) {
2287
2464
  }));
2288
2465
  const signature = own.map((need) => need.key).join("\n");
2289
2466
  useEffect(() => {
2290
- const pending = own.filter((need) => initial2?.[need.key]?.status !== "ready");
2291
- if (pending.length === 0) return;
2467
+ const pending2 = own.filter((need) => initial2?.[need.key]?.status !== "ready");
2468
+ if (pending2.length === 0) return;
2292
2469
  let cancelled = false;
2293
2470
  setEntries((prev) => {
2294
2471
  const next = { ...prev };
2295
- for (const need of pending) {
2472
+ for (const need of pending2) {
2296
2473
  if (next[need.key]?.status !== "ready") next[need.key] = { status: "loading" };
2297
2474
  }
2298
2475
  return next;
2299
2476
  });
2300
- for (const need of pending) {
2477
+ for (const need of pending2) {
2301
2478
  void resolvePageDataNeed(need).then((entry) => {
2302
2479
  if (!cancelled) setEntries((prev) => ({ ...prev, [need.key]: entry }));
2303
2480
  });
@@ -3165,8 +3342,8 @@ var BADGE_TONE_CLASSES = {
3165
3342
  warning: "bg-amber-500 text-white"
3166
3343
  };
3167
3344
  function useExtensionBadges(product) {
3168
- const [badges, setBadges] = React38.useState([]);
3169
- React38.useEffect(() => {
3345
+ const [badges, setBadges] = React39__default.useState([]);
3346
+ React39__default.useEffect(() => {
3170
3347
  let cancelled = false;
3171
3348
  getProductCardBadges(product).then((next) => {
3172
3349
  if (!cancelled && next.length > 0) setBadges(next);
@@ -4363,7 +4540,7 @@ function scalarToString(value) {
4363
4540
  }
4364
4541
  function ProductSpecs({ product }) {
4365
4542
  const config = useStorefrontConfig();
4366
- const extraExcluded = React38.useMemo(
4543
+ const extraExcluded = React39__default.useMemo(
4367
4544
  () => new Set(config.productSpecs?.exclude ?? []),
4368
4545
  [config.productSpecs?.exclude]
4369
4546
  );
@@ -4992,6 +5169,17 @@ function ProductDetailPage({ slug }) {
4992
5169
  useStorefrontHead(
4993
5170
  product ? productSeo(product, { config, path }) : { title: config.name }
4994
5171
  );
5172
+ useEffect(() => {
5173
+ if (!product) return;
5174
+ trackStorefront("product_viewed", {
5175
+ product_id: product.id,
5176
+ product_name: product.name,
5177
+ slug: product.slug,
5178
+ price: product.price,
5179
+ in_stock: product.inventoryCount > 0,
5180
+ surface: "product_page"
5181
+ });
5182
+ }, [product?.id]);
4995
5183
  useEffect(() => {
4996
5184
  if (!product) return;
4997
5185
  const defaults = Object.fromEntries(
@@ -6077,7 +6265,7 @@ function CollectionHero({
6077
6265
  {
6078
6266
  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"}`,
6079
6267
  children: /* @__PURE__ */ jsxs(Reveal, { className: centered ? "max-w-3xl" : "max-w-2xl", children: [
6080
- 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(React38.Fragment, { children: [
6268
+ 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: [
6081
6269
  i > 0 && /* @__PURE__ */ jsx("span", { className: "text-2xl font-light opacity-60", "aria-hidden": true, children: "\xD7" }),
6082
6270
  /* @__PURE__ */ jsx("img", { src: logo.src, alt: logo.alt, className: "h-10 w-auto object-contain sm:h-14" })
6083
6271
  ] }, logo.src)) }),
@@ -6859,10 +7047,10 @@ function StorefrontConfigHost({
6859
7047
  buyer,
6860
7048
  children
6861
7049
  }) {
6862
- const [policy, setPolicy] = React38.useState(null);
6863
- const [shipping, setShipping] = React38.useState(null);
6864
- const [delivery, setDelivery] = React38.useState(null);
6865
- React38.useEffect(() => {
7050
+ const [policy, setPolicy] = React39__default.useState(null);
7051
+ const [shipping, setShipping] = React39__default.useState(null);
7052
+ const [delivery, setDelivery] = React39__default.useState(null);
7053
+ React39__default.useEffect(() => {
6866
7054
  let cancelled = false;
6867
7055
  let provider;
6868
7056
  try {
@@ -6899,7 +7087,7 @@ function StorefrontConfigHost({
6899
7087
  cancelled = true;
6900
7088
  };
6901
7089
  }, [config]);
6902
- const resolved = React38.useMemo(
7090
+ const resolved = React39__default.useMemo(
6903
7091
  () => applyBuyer(applyDeliveryPolicy(applyShippingSettings(applyStoreSettings(config, policy), shipping), delivery), buyer),
6904
7092
  [config, policy, shipping, delivery, buyer?.language, buyer?.country]
6905
7093
  );
@@ -6911,7 +7099,7 @@ function MarketScope({ children }) {
6911
7099
  const markets = useMarketStore((s2) => s2.markets);
6912
7100
  const market = markets.length ? marketForCountry(markets, country) : null;
6913
7101
  const prices = useMarketStore((s2) => market ? s2.prices[market.code] : void 0);
6914
- React38.useEffect(() => {
7102
+ React39__default.useEffect(() => {
6915
7103
  useMarketStore.getState().setActive(market);
6916
7104
  if (!market || market.isDefault || prices) return;
6917
7105
  let provider;
@@ -6923,11 +7111,11 @@ function MarketScope({ children }) {
6923
7111
  void provider.getMarketPrices?.(market.code).then((list) => useMarketStore.getState().setPrices(market.code, list)).catch(() => {
6924
7112
  });
6925
7113
  }, [market?.code, prices]);
6926
- React38.useEffect(() => {
7114
+ React39__default.useEffect(() => {
6927
7115
  if (!market || !market.isDefault && !prices) return;
6928
7116
  useCartStore.getState().repriceForMarket();
6929
7117
  }, [market?.code, prices]);
6930
- const value = React38.useMemo(() => {
7118
+ const value = React39__default.useMemo(() => {
6931
7119
  if (!market) return base;
6932
7120
  return {
6933
7121
  ...base,
@@ -7057,7 +7245,7 @@ function StorefrontThemeStyle({
7057
7245
  document.getElementById(linkId)?.remove();
7058
7246
  };
7059
7247
  }, [fontsHref, linkId, selector]);
7060
- return React38.createElement(
7248
+ return React39__default.createElement(
7061
7249
  "style",
7062
7250
  { "data-sf-theme": theme.name },
7063
7251
  themeToCss(theme, { selector })
@@ -7156,7 +7344,7 @@ function SearchOverlay({ onClose }) {
7156
7344
  "\u201D."
7157
7345
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
7158
7346
  /* @__PURE__ */ jsx("div", { className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4", children: suggestions.map(
7159
- (product) => searchConfig.renderSuggestion ? /* @__PURE__ */ jsx(React38.Fragment, { children: searchConfig.renderSuggestion(product) }, product.id) : /* @__PURE__ */ jsx(SuggestionCard, { product, onNavigate: onClose }, product.id)
7347
+ (product) => searchConfig.renderSuggestion ? /* @__PURE__ */ jsx(React39__default.Fragment, { children: searchConfig.renderSuggestion(product) }, product.id) : /* @__PURE__ */ jsx(SuggestionCard, { product, onNavigate: onClose }, product.id)
7160
7348
  ) }),
7161
7349
  /* @__PURE__ */ jsx(
7162
7350
  "button",
@@ -7363,11 +7551,11 @@ function HeaderActions({ onMenuClick }) {
7363
7551
  const openDrawer = useCartStore((s2) => s2.openDrawer);
7364
7552
  const session = useSessionStore();
7365
7553
  const [accountOpen, setAccountOpen] = useState(false);
7366
- const accountRef = React38.useRef(null);
7554
+ const accountRef = React39__default.useRef(null);
7367
7555
  const pop = usePopOnChange(count);
7368
7556
  const firstName = session.name?.split(/\s+/)[0];
7369
7557
  const initial2 = (firstName ?? session.email ?? "C").slice(0, 1).toUpperCase();
7370
- React38.useEffect(() => {
7558
+ React39__default.useEffect(() => {
7371
7559
  if (!accountOpen) return;
7372
7560
  const onPointerDown = (event) => {
7373
7561
  if (!accountRef.current?.contains(event.target)) setAccountOpen(false);
@@ -7534,7 +7722,7 @@ function MobileMenuDrawer({ open, onClose }) {
7534
7722
  navigateTo(config.catalogPath);
7535
7723
  onClose();
7536
7724
  };
7537
- React38.useEffect(() => {
7725
+ React39__default.useEffect(() => {
7538
7726
  if (!open) return;
7539
7727
  const onKey = (e) => {
7540
7728
  if (e.key === "Escape") onClose();
@@ -8567,8 +8755,8 @@ function AddressForm({ country, language, value, onChange, onPostalCode, lookup,
8567
8755
  postalHint()
8568
8756
  ] }, "postalCode");
8569
8757
  }
8570
- if (row.length === 1) return /* @__PURE__ */ jsx(React38.Fragment, { children: input(specs.get(cells[0])) }, cells[0]);
8571
- return /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3", children: cells.map((key) => /* @__PURE__ */ jsx(React38.Fragment, { children: input(specs.get(key)) }, key)) }, cells.join("-"));
8758
+ if (row.length === 1) return /* @__PURE__ */ jsx(React39__default.Fragment, { children: input(specs.get(cells[0])) }, cells[0]);
8759
+ 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("-"));
8572
8760
  }) });
8573
8761
  }
8574
8762
  function flag(iso2) {
@@ -8924,13 +9112,13 @@ function CardBrick({ publicKey, amount, email, onSubmit, onError }) {
8924
9112
  var POLL_MS = 3e3;
8925
9113
  var RESUME_KEY = "fz.checkout.resume";
8926
9114
  function useExpiry(expiresAt) {
8927
- const target = React38.useMemo(() => {
9115
+ const target = React39__default.useMemo(() => {
8928
9116
  if (!expiresAt) return null;
8929
9117
  const t = new Date(expiresAt).getTime();
8930
9118
  return Number.isFinite(t) ? t : null;
8931
9119
  }, [expiresAt]);
8932
- const [now, setNow] = React38.useState(() => Date.now());
8933
- React38.useEffect(() => {
9120
+ const [now, setNow] = React39__default.useState(() => Date.now());
9121
+ React39__default.useEffect(() => {
8934
9122
  if (target === null) return;
8935
9123
  const id = setInterval(() => setNow(Date.now()), 1e3);
8936
9124
  return () => clearInterval(id);
@@ -9568,6 +9756,7 @@ var DEV_BUILD = (() => {
9568
9756
  return false;
9569
9757
  }
9570
9758
  })();
9759
+ var CHECKOUT_STEP_NAMES = { 1: "contact", 2: "delivery", 3: "payment", 4: "done" };
9571
9760
  function CheckoutPage() {
9572
9761
  const config = useStorefrontConfig();
9573
9762
  const cart = useCartStore();
@@ -9625,7 +9814,7 @@ function CheckoutPage() {
9625
9814
  district: "",
9626
9815
  state: ""
9627
9816
  });
9628
- React38.useEffect(() => {
9817
+ React39__default.useEffect(() => {
9629
9818
  if (!known.ready) return;
9630
9819
  setForm((current) => ({
9631
9820
  ...current,
@@ -9641,9 +9830,22 @@ function CheckoutPage() {
9641
9830
  }));
9642
9831
  }, [known.ready, known.phone, known.document, known.address]);
9643
9832
  const [step, setStep] = useState(resume ? 3 : 1);
9833
+ const reportedStart = React39__default.useRef(false);
9834
+ useEffect(() => {
9835
+ if (reportedStart.current) return;
9836
+ reportedStart.current = true;
9837
+ if (!resume) trackStorefront("checkout_started", { cart_count: cart.lines.reduce((n, l) => n + l.quantity, 0) });
9838
+ }, []);
9839
+ const reportedStep = React39__default.useRef(null);
9840
+ useEffect(() => {
9841
+ if (reportedStep.current === step) return;
9842
+ reportedStep.current = step;
9843
+ trackStorefront("checkout_step_viewed", { step, step_name: CHECKOUT_STEP_NAMES[step], resume: Boolean(resume) });
9844
+ if (step >= 2 && /.+@.+\..+/.test(form.email)) identifyStorefrontBuyer(form.email);
9845
+ }, [step]);
9644
9846
  const [contactKnown, setContactKnown] = useState(false);
9645
9847
  const [editingContact, setEditingContact] = useState(false);
9646
- const skippedContact = React38.useRef(false);
9848
+ const skippedContact = React39__default.useRef(false);
9647
9849
  const fulfillmentType = useDeliveryStore((s2) => s2.fulfillmentType);
9648
9850
  const scheduledFor = useDeliveryStore((s2) => s2.scheduledFor);
9649
9851
  const deliveryReference = useDeliveryStore((s2) => {
@@ -9672,7 +9874,7 @@ function CheckoutPage() {
9672
9874
  const [applyingDiscount, setApplyingDiscount] = useState(false);
9673
9875
  const [showSignin, setShowSignin] = useState(false);
9674
9876
  const [placing, setPlacing] = useState(false);
9675
- const leaving = React38.useRef(false);
9877
+ const leaving = React39__default.useRef(false);
9676
9878
  const [zipLookup, setZipLookup] = useState("idle");
9677
9879
  const subtotal = selectSubtotal(cart);
9678
9880
  const discountTotal = selectDiscountTotal(cart);
@@ -9680,7 +9882,7 @@ function CheckoutPage() {
9680
9882
  const shipping = isPickup ? 0 : shippingRaw;
9681
9883
  const total = selectTotal(cart, config) - (isPickup ? shippingRaw : 0);
9682
9884
  const checkoutSlotContext = { subtotal, total };
9683
- const checkoutSessionInput = React38.useMemo(() => ({
9885
+ const checkoutSessionInput = React39__default.useMemo(() => ({
9684
9886
  items: cart.lines.map((line) => ({
9685
9887
  productId: line.productId,
9686
9888
  variantId: line.variantId ?? null,
@@ -9857,7 +10059,7 @@ function CheckoutPage() {
9857
10059
  cancelled = true;
9858
10060
  };
9859
10061
  }, [session.customerId]);
9860
- const shownCountry = React38.useRef(country);
10062
+ const shownCountry = React39__default.useRef(country);
9861
10063
  useEffect(() => {
9862
10064
  if (shownCountry.current === country) return;
9863
10065
  shownCountry.current = country;
@@ -9924,6 +10126,7 @@ function CheckoutPage() {
9924
10126
  }
9925
10127
  function fail(message, testId) {
9926
10128
  setError(message);
10129
+ trackStorefront("checkout_error", { step, field: testId ?? null, reason: message });
9927
10130
  if (testId) {
9928
10131
  const field2 = document.querySelector(`[data-testid="${testId}"]`);
9929
10132
  field2?.scrollIntoView({ block: "center", behavior: prefersReducedMotion() ? "auto" : "smooth" });
@@ -10091,10 +10294,18 @@ function CheckoutPage() {
10091
10294
  });
10092
10295
  if (customerId) session.setSession({ customerId, email: form.email, name: form.name });
10093
10296
  leaving.current = true;
10297
+ trackStorefront("checkout_completed", {
10298
+ order_id: order.id,
10299
+ payment_method: paymentMethod,
10300
+ fulfillment: fulfillmentType ?? "delivery",
10301
+ total,
10302
+ online_payment: false
10303
+ });
10094
10304
  cart.clear();
10095
10305
  navigateTo(`/order/${order.id}`);
10096
10306
  } catch (err) {
10097
10307
  setError(placeOrderMessage(err, t));
10308
+ trackStorefront("checkout_error", { step, field: "place_order", reason: placeOrderMessage(err, t) });
10098
10309
  setPlacing(false);
10099
10310
  }
10100
10311
  }
@@ -10342,7 +10553,10 @@ function CheckoutPage() {
10342
10553
  role: "radio",
10343
10554
  "aria-checked": selected,
10344
10555
  "data-testid": `checkout-payment-${method}`,
10345
- onClick: () => setPaymentMethod(method),
10556
+ onClick: () => {
10557
+ setPaymentMethod(method);
10558
+ if (method !== paymentMethod) trackStorefront("checkout_payment_selected", { payment_method: method });
10559
+ },
10346
10560
  className: `w-full rounded-lg border p-3 text-left text-sm transition hover:bg-muted/40 ${selected ? "border-primary bg-primary/5" : "border-border bg-background"}`,
10347
10561
  children: [
10348
10562
  /* @__PURE__ */ jsxs("span", { className: "flex items-center justify-between gap-3 font-semibold", children: [
@@ -10368,6 +10582,13 @@ function CheckoutPage() {
10368
10582
  onPaid: (orderId) => {
10369
10583
  leaving.current = true;
10370
10584
  setPaidOrderId(orderId);
10585
+ trackStorefront("checkout_completed", {
10586
+ order_id: orderId,
10587
+ payment_method: method,
10588
+ fulfillment: fulfillmentType ?? "delivery",
10589
+ total,
10590
+ online_payment: true
10591
+ });
10371
10592
  goToStep(4);
10372
10593
  cart.clear();
10373
10594
  }
@@ -10751,8 +10972,8 @@ function AddressStrip({
10751
10972
  const money = (v) => formatMoney(v, config.currency, config.locale);
10752
10973
  const subtotal = selectSubtotal(useCartStore());
10753
10974
  const resolve = useDeliveryStore((s2) => s2.resolve);
10754
- const quotedOnce = React38.useRef(false);
10755
- React38.useEffect(() => {
10975
+ const quotedOnce = React39__default.useRef(false);
10976
+ React39__default.useEffect(() => {
10756
10977
  if (quotedOnce.current || isPickup) return;
10757
10978
  if (delivery.status !== "idle" || delivery.options.length > 0 || !delivery.postalCode) return;
10758
10979
  quotedOnce.current = true;
@@ -10814,17 +11035,17 @@ function MenuToolbar({
10814
11035
  onQuery,
10815
11036
  autoFocusSearch
10816
11037
  }) {
10817
- const inputRef = React38.useRef(null);
10818
- const [active2, setActive] = React38.useState(null);
10819
- React38.useEffect(() => {
11038
+ const inputRef = React39__default.useRef(null);
11039
+ const [active2, setActive] = React39__default.useState(null);
11040
+ React39__default.useEffect(() => {
10820
11041
  setActive(
10821
11042
  (current) => current && sections.some((s2) => s2.slug === current) ? current : sections[0]?.slug ?? null
10822
11043
  );
10823
11044
  }, [sections]);
10824
- React38.useEffect(() => {
11045
+ React39__default.useEffect(() => {
10825
11046
  if (autoFocusSearch) inputRef.current?.focus();
10826
11047
  }, [autoFocusSearch]);
10827
- React38.useEffect(() => {
11048
+ React39__default.useEffect(() => {
10828
11049
  if (typeof IntersectionObserver === "undefined") return;
10829
11050
  const seen = /* @__PURE__ */ new Map();
10830
11051
  const observer = new IntersectionObserver(
@@ -11011,10 +11232,10 @@ function ItemSheet({
11011
11232
  }) {
11012
11233
  const config = useStorefrontConfig();
11013
11234
  const money = (v) => formatMoney(v, config.currency, config.locale);
11014
- const groups = React38.useMemo(() => getProductOptionGroups(product), [product]);
11015
- const [options, setOptions] = React38.useState({});
11016
- const [notes, setNotes] = React38.useState("");
11017
- const [quantity, setQuantity] = React38.useState(1);
11235
+ const groups = React39__default.useMemo(() => getProductOptionGroups(product), [product]);
11236
+ const [options, setOptions] = React39__default.useState({});
11237
+ const [notes, setNotes] = React39__default.useState("");
11238
+ const [quantity, setQuantity] = React39__default.useState(1);
11018
11239
  const image = product.images?.find((i) => i.isPrimary) ?? product.images?.[0];
11019
11240
  const stock = product.inventoryCount;
11020
11241
  const missing = groups.filter((g) => !options[g.label]);
@@ -11208,8 +11429,8 @@ function ScheduleSheet({ onClose }) {
11208
11429
  const scheduledFor = useDeliveryStore((s2) => s2.scheduledFor);
11209
11430
  const setScheduledFor = useDeliveryStore((s2) => s2.setScheduledFor);
11210
11431
  const timezone = useServiceStore((s2) => s2.service?.timezone) ?? "America/Sao_Paulo";
11211
- const [slots, setSlots] = React38.useState(null);
11212
- React38.useEffect(() => {
11432
+ const [slots, setSlots] = React39__default.useState(null);
11433
+ React39__default.useEffect(() => {
11213
11434
  let alive = true;
11214
11435
  void (async () => {
11215
11436
  const rows = await getShopProvider()?.listScheduleSlots?.(fulfillmentType) ?? [];
@@ -11219,7 +11440,7 @@ function ScheduleSheet({ onClose }) {
11219
11440
  alive = false;
11220
11441
  };
11221
11442
  }, [fulfillmentType]);
11222
- const days = React38.useMemo(() => {
11443
+ const days = React39__default.useMemo(() => {
11223
11444
  const fmtDay = new Intl.DateTimeFormat("pt-BR", {
11224
11445
  weekday: "long",
11225
11446
  day: "2-digit",
@@ -11305,8 +11526,8 @@ function hhmm(time) {
11305
11526
  }
11306
11527
  function ServiceHoursModal({ onClose }) {
11307
11528
  const fulfillmentType = useServiceStore((s2) => s2.fulfillmentType);
11308
- const [hours, setHours] = React38.useState(null);
11309
- React38.useEffect(() => {
11529
+ const [hours, setHours] = React39__default.useState(null);
11530
+ React39__default.useEffect(() => {
11310
11531
  let alive = true;
11311
11532
  void (async () => {
11312
11533
  const rows = await getShopProvider()?.listServiceHours?.(fulfillmentType) ?? [];
@@ -11316,7 +11537,7 @@ function ServiceHoursModal({ onClose }) {
11316
11537
  alive = false;
11317
11538
  };
11318
11539
  }, [fulfillmentType]);
11319
- const byDay = React38.useMemo(() => {
11540
+ const byDay = React39__default.useMemo(() => {
11320
11541
  const map = /* @__PURE__ */ new Map();
11321
11542
  for (const h of hours ?? []) {
11322
11543
  const list = map.get(h.weekday) ?? [];
@@ -11401,7 +11622,7 @@ function AddressSheet({ onClose, onSignIn }) {
11401
11622
  const unsavedCurrent = current && !saved.some((a) => a.id === selectedId) ? current : null;
11402
11623
  const fromAccount = accountBook.filter((a) => !saved.some((b) => normalizePostalCode(b.postalCode) === normalizePostalCode(a.postalCode) && b.number.trim().toLowerCase() === (a.number ?? "").trim().toLowerCase()));
11403
11624
  const nothingToList = saved.length === 0 && !unsavedCurrent && fromAccount.length === 0 && !customerId;
11404
- const [editing, setEditing] = React38.useState(
11625
+ const [editing, setEditing] = React39__default.useState(
11405
11626
  nothingToList && !onSignIn ? {} : null
11406
11627
  );
11407
11628
  function pickAccountAddress(a) {
@@ -11420,13 +11641,13 @@ function AddressSheet({ onClose, onSignIn }) {
11420
11641
  void selectAddress(id, subtotal);
11421
11642
  onClose();
11422
11643
  }
11423
- const closeRef = React38.useRef(() => {
11644
+ const closeRef = React39__default.useRef(() => {
11424
11645
  });
11425
11646
  closeRef.current = () => {
11426
11647
  if (editing && !nothingToList) setEditing(null);
11427
11648
  else onClose();
11428
11649
  };
11429
- React38.useEffect(() => {
11650
+ React39__default.useEffect(() => {
11430
11651
  const onKey = (e) => {
11431
11652
  if (e.key === "Escape") closeRef.current();
11432
11653
  };
@@ -11607,8 +11828,8 @@ function AddressLines({ address }) {
11607
11828
  ] });
11608
11829
  }
11609
11830
  function useAccountAddresses(customerId) {
11610
- const [rows, setRows] = React38.useState([]);
11611
- React38.useEffect(() => {
11831
+ const [rows, setRows] = React39__default.useState([]);
11832
+ React39__default.useEffect(() => {
11612
11833
  if (!customerId) {
11613
11834
  setRows([]);
11614
11835
  return;
@@ -11636,24 +11857,24 @@ function AddressForm2({ onDone, initial: initial2, replaces }) {
11636
11857
  const storeError = useDeliveryStore((s2) => s2.error);
11637
11858
  const refusedZone = useDeliveryStore((s2) => s2.refusedZone);
11638
11859
  const subtotal = selectSubtotal(useCartStore());
11639
- const [cep, setCep] = React38.useState(initial2?.postalCode ? formatPostalCode(initial2.postalCode) : "");
11640
- const [number, setNumber] = React38.useState(initial2?.number ?? "");
11641
- const [complement, setComplement] = React38.useState(initial2?.complement ?? "");
11642
- const [reference, setReference] = React38.useState(initial2?.reference ?? "");
11643
- const [label, setLabel] = React38.useState(initial2?.label ?? "");
11644
- const [touched, setTouched] = React38.useState(false);
11645
- const numberRef = React38.useRef(null);
11860
+ const [cep, setCep] = React39__default.useState(initial2?.postalCode ? formatPostalCode(initial2.postalCode) : "");
11861
+ const [number, setNumber] = React39__default.useState(initial2?.number ?? "");
11862
+ const [complement, setComplement] = React39__default.useState(initial2?.complement ?? "");
11863
+ const [reference, setReference] = React39__default.useState(initial2?.reference ?? "");
11864
+ const [label, setLabel] = React39__default.useState(initial2?.label ?? "");
11865
+ const [touched, setTouched] = React39__default.useState(false);
11866
+ const numberRef = React39__default.useRef(null);
11646
11867
  const digits = normalizePostalCode(cep);
11647
11868
  const found = Boolean(looked) && normalizePostalCode(looked.postalCode) === digits;
11648
- React38.useEffect(() => {
11869
+ React39__default.useEffect(() => {
11649
11870
  if (found) numberRef.current?.focus();
11650
11871
  }, [found]);
11651
11872
  async function lookUp() {
11652
11873
  if (digits.length !== 8) return;
11653
11874
  await resolve(digits, subtotal);
11654
11875
  }
11655
- const prefilled = React38.useRef(false);
11656
- React38.useEffect(() => {
11876
+ const prefilled = React39__default.useRef(false);
11877
+ React39__default.useEffect(() => {
11657
11878
  if (prefilled.current || !initial2?.postalCode) return;
11658
11879
  prefilled.current = true;
11659
11880
  if (!found) void lookUp();
@@ -11869,7 +12090,7 @@ function AccountDrawer({ onClose, onSignIn, onAddresses, onShowHours }) {
11869
12090
  const session = useSessionStore();
11870
12091
  const signedIn = Boolean(session.email);
11871
12092
  const name = session.name || session.email?.split("@")[0] || "";
11872
- React38.useEffect(() => {
12093
+ React39__default.useEffect(() => {
11873
12094
  const onKey = (event) => {
11874
12095
  if (event.key === "Escape") onClose();
11875
12096
  };
@@ -11953,19 +12174,30 @@ function AccountDrawer({ onClose, onSignIn, onAddresses, onShowHours }) {
11953
12174
  function MenuPage() {
11954
12175
  const config = useStorefrontConfig();
11955
12176
  const addItem = useCartStore((s2) => s2.addItem);
11956
- const [openProduct, setOpenProduct] = React38.useState(null);
11957
- const [showHours, setShowHours] = React38.useState(false);
11958
- const [showClosed, setShowClosed] = React38.useState(false);
11959
- const [showAddress, setShowAddress] = React38.useState(false);
11960
- const [showAccount, setShowAccount] = React38.useState(false);
11961
- const [showSignIn, setShowSignIn] = React38.useState(false);
11962
- const [showSchedule, setShowSchedule] = React38.useState(false);
11963
- const [query, setQuery] = React38.useState("");
12177
+ const [openProduct, setOpenProduct] = React39__default.useState(null);
12178
+ React39__default.useEffect(() => {
12179
+ if (!openProduct) return;
12180
+ trackStorefront("product_viewed", {
12181
+ product_id: openProduct.id,
12182
+ product_name: openProduct.name,
12183
+ slug: openProduct.slug,
12184
+ price: openProduct.price,
12185
+ in_stock: openProduct.inventoryCount > 0,
12186
+ surface: "menu_sheet"
12187
+ });
12188
+ }, [openProduct?.id]);
12189
+ const [showHours, setShowHours] = React39__default.useState(false);
12190
+ const [showClosed, setShowClosed] = React39__default.useState(false);
12191
+ const [showAddress, setShowAddress] = React39__default.useState(false);
12192
+ const [showAccount, setShowAccount] = React39__default.useState(false);
12193
+ const [showSignIn, setShowSignIn] = React39__default.useState(false);
12194
+ const [showSchedule, setShowSchedule] = React39__default.useState(false);
12195
+ const [query, setQuery] = React39__default.useState("");
11964
12196
  const serviceState = useServiceStore();
11965
12197
  const refreshService = useServiceStore((s2) => s2.refresh);
11966
12198
  const paused = Boolean(config.delivery?.paused);
11967
12199
  const isOpen = selectIsOpen(serviceState) && !paused;
11968
- React38.useEffect(() => {
12200
+ React39__default.useEffect(() => {
11969
12201
  void refreshService();
11970
12202
  }, [refreshService]);
11971
12203
  const cart = useCartStore();
@@ -11987,7 +12219,7 @@ function MenuPage() {
11987
12219
  const loading = products.status === "loading" || products.status === "idle";
11988
12220
  const items = products.data ?? [];
11989
12221
  const cats = categories.data ?? [];
11990
- const allSections = React38.useMemo(() => {
12222
+ const allSections = React39__default.useMemo(() => {
11991
12223
  const byCategory = /* @__PURE__ */ new Map();
11992
12224
  const loose = [];
11993
12225
  for (const p of items) {
@@ -12015,7 +12247,7 @@ function MenuPage() {
12015
12247
  }
12016
12248
  return ordered;
12017
12249
  }, [items, cats]);
12018
- const highlights = React38.useMemo(
12250
+ const highlights = React39__default.useMemo(
12019
12251
  () => pickHighlights(items, {
12020
12252
  listingFeaturedIds: featured.data?.listing,
12021
12253
  menuFeaturedIds: featured.data?.menu,
@@ -12024,7 +12256,7 @@ function MenuPage() {
12024
12256
  [items, featured.data, config.delivery?.highlightSlugs]
12025
12257
  );
12026
12258
  const normalized = query.trim().toLowerCase();
12027
- const sections = React38.useMemo(() => {
12259
+ const sections = React39__default.useMemo(() => {
12028
12260
  if (!normalized) return allSections;
12029
12261
  return allSections.map((section) => ({
12030
12262
  ...section,
@@ -12197,7 +12429,7 @@ function MenuPage() {
12197
12429
  );
12198
12430
  }
12199
12431
  function BottomBarSpace() {
12200
- React38.useEffect(() => {
12432
+ React39__default.useEffect(() => {
12201
12433
  const root = document.documentElement;
12202
12434
  root.style.setProperty("--fayz-bottom-bar", "4.5rem");
12203
12435
  return () => {
@@ -12488,7 +12720,7 @@ function OrderConfirmationPage({ orderId }) {
12488
12720
  const [loading, setLoading] = useState(true);
12489
12721
  const money = (v) => formatMoney(v, config.currency, config.locale);
12490
12722
  useStorefrontHead({ title: order ? `Pedido #${order.orderNumber} \u2014 ${config.name}` : config.name });
12491
- const reload = React38.useCallback(() => {
12723
+ const reload = React39__default.useCallback(() => {
12492
12724
  let cancelled = false;
12493
12725
  getShopProvider().getOrder(orderId).then((o) => {
12494
12726
  if (!cancelled) setOrder(o);
@@ -12517,7 +12749,7 @@ function OrderConfirmationPage({ orderId }) {
12517
12749
  ] }, column)) }),
12518
12750
  /* @__PURE__ */ jsxs("div", { className: "mt-6", children: [
12519
12751
  /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-32" }),
12520
- /* @__PURE__ */ jsx("div", { className: "mt-3 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React38.Fragment, { children: [
12752
+ /* @__PURE__ */ jsx("div", { className: "mt-3 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React39__default.Fragment, { children: [
12521
12753
  /* @__PURE__ */ jsx(Skeleton, { className: "h-7 w-7 shrink-0 rounded-full" }),
12522
12754
  node < 3 && /* @__PURE__ */ jsx(Skeleton, { className: "h-px flex-1" })
12523
12755
  ] }, node)) })
@@ -12804,7 +13036,7 @@ function OrdersPanel() {
12804
13036
  /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-24 rounded-full" })
12805
13037
  ] }),
12806
13038
  /* @__PURE__ */ jsx(Skeleton, { className: "mt-2 h-3 w-20" }),
12807
- /* @__PURE__ */ jsx("div", { className: "mt-4 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React38.Fragment, { children: [
13039
+ /* @__PURE__ */ jsx("div", { className: "mt-4 flex items-center gap-2", children: [0, 1, 2, 3].map((node) => /* @__PURE__ */ jsxs(React39__default.Fragment, { children: [
12808
13040
  /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-6 shrink-0 rounded-full" }),
12809
13041
  node < 3 && /* @__PURE__ */ jsx(Skeleton, { className: "h-px flex-1" })
12810
13042
  ] }, node)) }),
@@ -12883,7 +13115,7 @@ function ProfilePanel() {
12883
13115
  const [saving, setSaving] = useState(false);
12884
13116
  const [saved, setSaved] = useState(false);
12885
13117
  const [error, setError] = useState(null);
12886
- React38.useEffect(() => {
13118
+ React39__default.useEffect(() => {
12887
13119
  if (!supported) return;
12888
13120
  let cancelled = false;
12889
13121
  provider.getMyProfile().then((p) => {
@@ -13176,7 +13408,7 @@ function PolicyPage({ kind }) {
13176
13408
  ] }) })
13177
13409
  ] });
13178
13410
  }
13179
- var StorefrontErrorBoundary = class extends React38.Component {
13411
+ var StorefrontErrorBoundary = class extends React39__default.Component {
13180
13412
  constructor() {
13181
13413
  super(...arguments);
13182
13414
  this.state = { error: null };
@@ -13432,7 +13664,8 @@ function StorefrontShellBody({ pathOverride }) {
13432
13664
  /* @__PURE__ */ jsx(StorefrontErrorBoundary, { children: /* @__PURE__ */ jsx(RouteSwitch, { path }) }, path),
13433
13665
  !focused && config.features.cart && /* @__PURE__ */ jsx(CartDrawer, {}),
13434
13666
  !focused && /* @__PURE__ */ jsx(footer.Component, { ...chromeProps, ...footer.props }),
13435
- /* @__PURE__ */ jsx(Toaster, {})
13667
+ /* @__PURE__ */ jsx(Toaster, {}),
13668
+ /* @__PURE__ */ jsx(StorefrontAnalytics, { config, path })
13436
13669
  ] });
13437
13670
  if (Shell) {
13438
13671
  return /* @__PURE__ */ jsx(Shell, { ...chromeProps, ...shellProps, children: body });
@@ -14792,6 +15025,6 @@ ${formatErrors(report.errors)}`;
14792
15025
  return config;
14793
15026
  }
14794
15027
 
14795
- 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, 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, initStorefrontRuntime, isJsonValue, isKnownPath, isNestedBlockRef, isPublicPath, isRecord, listSlots, marketForCountry, marketUnitPrice, matchContentPage, matchPath, matchesFacets, mergeCollectionFacet, mergePageTheme, navigateTo, nextMilestone, normalizeLanguage, normalizeProductOptionSelection, 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, storefrontComponentContracts, storefrontPaths, themeToCss, toBlockNodes, toFacetMap, 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 };
14796
- //# sourceMappingURL=chunk-AUARAE26.js.map
14797
- //# sourceMappingURL=chunk-AUARAE26.js.map
15028
+ 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, 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 };
15029
+ //# sourceMappingURL=chunk-3XECLBVJ.js.map
15030
+ //# sourceMappingURL=chunk-3XECLBVJ.js.map