@fayz-ai/storefront 0.78.0 → 0.79.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"StorefrontAnalytics.d.ts","sourceRoot":"","sources":["../../src/analytics/StorefrontAnalytics.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAA;AAClE,OAAO,EAAE,YAAY,EAA+B,MAAM,sBAAsB,CAAA;AAIhF,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAA;AAE5D,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAIlF;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC;UAIrE,OAAO,GAAG,SAAS;UAAQ,YAAY,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;cAAY,MAAM;IAQpG;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IAAE,MAAM,EAAE,wBAAwB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,QAoDvG"}
1
+ {"version":3,"file":"StorefrontAnalytics.d.ts","sourceRoot":"","sources":["../../src/analytics/StorefrontAnalytics.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAA;AAClE,OAAO,EAAE,YAAY,EAA+B,MAAM,sBAAsB,CAAA;AAKhF,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,QAAQ,CAAC,CAAA;AAE5D,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAIlF;AAED,4EAA4E;AAC5E,wBAAgB,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC;UAIrE,OAAO,GAAG,SAAS;UAAQ,YAAY,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;cAAY,MAAM;IAQpG;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE;IAAE,MAAM,EAAE,wBAAwB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,QAmEvG"}
@@ -3,8 +3,9 @@
3
3
  * analytics vendor: components report here, and whatever is listening (the
4
4
  * PostHog client, a test, nothing) decides what to do with it.
5
5
  *
6
- * Events reported before anyone listens are held, so the first product view of
7
- * a page load is not lost while the analytics client is still loading.
6
+ * The page's recent events are kept and handed to every listener when it
7
+ * starts, so the first product view of a page load reaches a client that is
8
+ * still loading — each listener hears each event once.
8
9
  */
9
10
  export type StorefrontEventName = 'product_viewed' | 'product_added_to_cart' | 'product_removed_from_cart' | 'cart_viewed' | 'coupon_applied' | 'checkout_started' | 'checkout_step_viewed' | 'checkout_payment_selected' | 'checkout_error' | 'checkout_completed' | 'delivery_exit';
10
11
  export type StorefrontEventProperties = Record<string, string | number | boolean | null | undefined>;
@@ -23,6 +24,8 @@ export declare function onStorefrontEvent(listener: Listener): () => void;
23
24
  * an event property.
24
25
  */
25
26
  export declare function identifyStorefrontBuyer(email: string): void;
27
+ /** Hear the buyer's e-mail (now, if already known, and on every change). */
28
+ export declare function onStorefrontBuyer(listener: Identifier): () => void;
26
29
  export declare function setStorefrontIdentifier(fn: Identifier | null): void;
27
30
  /** When this event was last reported on this page (0 = never). */
28
31
  export declare function lastStorefrontEventAt(name: StorefrontEventName): number;
@@ -1 +1 @@
1
- {"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../../src/analytics/bus.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,mBAAmB,GAC3B,gBAAgB,GAChB,uBAAuB,GACvB,2BAA2B,GAC3B,aAAa,GACb,gBAAgB,GAChB,kBAAkB,GAClB,sBAAsB,GACtB,2BAA2B,GAC3B,gBAAgB,GAChB,oBAAoB,GACpB,eAAe,CAAA;AAEnB,MAAM,MAAM,yBAAyB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;AAEpG,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,mBAAmB,CAAA;IACzB,UAAU,EAAE,yBAAyB,CAAA;IACrC,EAAE,EAAE,MAAM,CAAA;CACX;AAED,KAAK,QAAQ,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAA;AAChD,KAAK,UAAU,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;AASzC,wBAAgB,eAAe,CAAC,IAAI,EAAE,mBAAmB,EAAE,UAAU,GAAE,yBAA8B,GAAG,IAAI,CAY3G;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,IAAI,CAUhE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAK3D;AAED,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAMnE;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAEvE;AAED,mDAAmD;AACnD,wBAAgB,qBAAqB,IAAI,IAAI,CAM5C"}
1
+ {"version":3,"file":"bus.d.ts","sourceRoot":"","sources":["../../src/analytics/bus.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,mBAAmB,GAC3B,gBAAgB,GAChB,uBAAuB,GACvB,2BAA2B,GAC3B,aAAa,GACb,gBAAgB,GAChB,kBAAkB,GAClB,sBAAsB,GACtB,2BAA2B,GAC3B,gBAAgB,GAChB,oBAAoB,GACpB,eAAe,CAAA;AAEnB,MAAM,MAAM,yBAAyB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;AAEpG,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,mBAAmB,CAAA;IACzB,UAAU,EAAE,yBAAyB,CAAA;IACrC,EAAE,EAAE,MAAM,CAAA;CACX;AAED,KAAK,QAAQ,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAA;AAChD,KAAK,UAAU,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;AAazC,wBAAgB,eAAe,CAAC,IAAI,EAAE,mBAAmB,EAAE,UAAU,GAAE,yBAA8B,GAAG,IAAI,CAa3G;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,IAAI,CAMhE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAS3D;AAED,4EAA4E;AAC5E,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,UAAU,GAAG,MAAM,IAAI,CAMlE;AAED,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAMnE;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,CAEvE;AAED,mDAAmD;AACnD,wBAAgB,qBAAqB,IAAI,IAAI,CAQ5C"}
@@ -1,5 +1,6 @@
1
- export { trackStorefront, onStorefrontEvent, identifyStorefrontBuyer, type StorefrontEvent, type StorefrontEventName, type StorefrontEventProperties, } from './bus';
1
+ export { trackStorefront, onStorefrontEvent, identifyStorefrontBuyer, onStorefrontBuyer, type StorefrontEvent, type StorefrontEventName, type StorefrontEventProperties, } from './bus';
2
2
  export { storeBuyerId } from './identity';
3
3
  export { startStorefrontPostHog, type StorefrontAnalyticsConfig, type StorefrontPostHogConfig } from './posthog';
4
+ export { startStorefrontMetaPixel, metaEventFor, type StorefrontMetaPixelConfig, type MetaEvent } from './meta-pixel';
4
5
  export { StorefrontAnalytics, isOrderingPath, cartChanges } from './StorefrontAnalytics';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analytics/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,uBAAuB,EACvB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,GAC/B,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzC,OAAO,EAAE,sBAAsB,EAAE,KAAK,yBAAyB,EAAE,KAAK,uBAAuB,EAAE,MAAM,WAAW,CAAA;AAChH,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/analytics/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,uBAAuB,EACvB,iBAAiB,EACjB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,GAC/B,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzC,OAAO,EAAE,sBAAsB,EAAE,KAAK,yBAAyB,EAAE,KAAK,uBAAuB,EAAE,MAAM,WAAW,CAAA;AAChH,OAAO,EAAE,wBAAwB,EAAE,YAAY,EAAE,KAAK,yBAAyB,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAA;AACrH,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA"}
@@ -0,0 +1,52 @@
1
+ import { type StorefrontEvent } from './bus';
2
+ /**
3
+ * The store's Meta Pixel as one more listener on the storefront's own events.
4
+ *
5
+ * Components never call Meta: they report to the bus (product viewed, added to
6
+ * cart, checkout started, payment chosen, order placed) and this maps each one
7
+ * to the standard event Meta's ads optimise for. The pixel id is the store's —
8
+ * Loja › Configurações › Loja › Rastreamento (shop 0148), or `analytics.metaPixel`
9
+ * in code.
10
+ *
11
+ * Purchase carries the order id as its `eventID`, so a server-side Conversions
12
+ * API sending the same order later is deduplicated by Meta, not counted twice.
13
+ */
14
+ export interface StorefrontMetaPixelConfig {
15
+ /** Digits only, as Meta shows it in the Events Manager. */
16
+ pixelId: string;
17
+ }
18
+ type Fbq = ((...args: unknown[]) => void) & {
19
+ callMethod?: (...args: unknown[]) => void;
20
+ queue: unknown[];
21
+ push: unknown;
22
+ loaded: boolean;
23
+ version: string;
24
+ };
25
+ declare global {
26
+ interface Window {
27
+ fbq?: Fbq;
28
+ _fbq?: Fbq;
29
+ }
30
+ }
31
+ export declare const META_PIXEL_ID: RegExp;
32
+ export interface MetaEvent {
33
+ name: 'ViewContent' | 'AddToCart' | 'InitiateCheckout' | 'AddPaymentInfo' | 'Purchase';
34
+ params: Record<string, unknown>;
35
+ /** Meta's dedup key; set on Purchase (the order id). */
36
+ eventId?: string;
37
+ }
38
+ /** A storefront event in Meta's words, or null when Meta has no standard event for it. */
39
+ export declare function metaEventFor(event: StorefrontEvent, currency: string): MetaEvent | null;
40
+ /**
41
+ * Loads the pixel once per page (browser only) and starts reporting. Calling it
42
+ * again with the same id is a no-op; with another id, the old listener stops.
43
+ */
44
+ export declare function startStorefrontMetaPixel(config: StorefrontMetaPixelConfig, context: {
45
+ currency: string;
46
+ }): void;
47
+ /** A page view for the single-page navigation (the base code only reports the first load). */
48
+ export declare function trackMetaPageView(): void;
49
+ /** Test seam. */
50
+ export declare function resetStorefrontMetaPixel(): void;
51
+ export {};
52
+ //# sourceMappingURL=meta-pixel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-pixel.d.ts","sourceRoot":"","sources":["../../src/analytics/meta-pixel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,KAAK,eAAe,EAAE,MAAM,OAAO,CAAA;AAElF;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,yBAAyB;IACxC,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,KAAK,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC,GAAG;IAC1C,UAAU,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;IACzC,KAAK,EAAE,OAAO,EAAE,CAAA;IAChB,IAAI,EAAE,OAAO,CAAA;IACb,MAAM,EAAE,OAAO,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,GAAG,CAAC,EAAE,GAAG,CAAA;QACT,IAAI,CAAC,EAAE,GAAG,CAAA;KACX;CACF;AAED,eAAO,MAAM,aAAa,QAAmB,CAAA;AAE7C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,aAAa,GAAG,WAAW,GAAG,kBAAkB,GAAG,gBAAgB,GAAG,UAAU,CAAA;IACtF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAKD,0FAA0F;AAC1F,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAyCvF;AAuCD;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,yBAAyB,EAAE,OAAO,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAqB/G;AAED,8FAA8F;AAC9F,wBAAgB,iBAAiB,IAAI,IAAI,CAGxC;AAED,iBAAiB;AACjB,wBAAgB,wBAAwB,IAAI,IAAI,CAG/C"}
@@ -12,6 +12,12 @@ export interface StorefrontPostHogConfig {
12
12
  }
13
13
  export interface StorefrontAnalyticsConfig {
14
14
  posthog?: StorefrontPostHogConfig;
15
+ /**
16
+ * The store's Meta Pixel. Usually left out: the id the merchant saves in
17
+ * Loja › Configurações › Loja › Rastreamento (shop 0148) is used. Set it here
18
+ * only to pin one in code.
19
+ */
20
+ metaPixel?: import('./meta-pixel').StorefrontMetaPixelConfig;
15
21
  }
16
22
  interface StartContext {
17
23
  storeName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"posthog.d.ts","sourceRoot":"","sources":["../../src/analytics/posthog.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,GAAG,EAAE,MAAM,CAAA;IACX,sFAAsF;IACtF,OAAO,EAAE,MAAM,CAAA;IACf,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,4DAA4D;IAC5D,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,EAAE,uBAAuB,CAAA;CAClC;AAED,UAAU,YAAY;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;CACrB;AAID;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,uBAAuB,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAkCnH"}
1
+ {"version":3,"file":"posthog.d.ts","sourceRoot":"","sources":["../../src/analytics/posthog.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,uBAAuB;IACtC,8EAA8E;IAC9E,GAAG,EAAE,MAAM,CAAA;IACX,sFAAsF;IACtF,OAAO,EAAE,MAAM,CAAA;IACf,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sFAAsF;IACtF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,4DAA4D;IAC5D,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,EAAE,uBAAuB,CAAA;IACjC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,cAAc,EAAE,yBAAyB,CAAA;CAC7D;AAED,UAAU,YAAY;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;CACrB;AAID;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,uBAAuB,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAkCnH"}
@@ -35,16 +35,16 @@ export interface LinkProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorEle
35
35
  * explicit targets are still handed to the browser.
36
36
  */
37
37
  export declare function Link({ to, children, onClick, target, ...rest }: LinkProps): React.DetailedReactHTMLElement<{
38
- prefix?: string | undefined | undefined;
39
- style?: React.CSSProperties | undefined;
40
38
  slot?: string | undefined | undefined;
39
+ style?: React.CSSProperties | undefined;
41
40
  title?: string | undefined | undefined;
41
+ prefix?: string | undefined | undefined;
42
+ referrerPolicy?: React.HTMLAttributeReferrerPolicy | undefined;
43
+ type?: string | undefined | undefined;
42
44
  download?: any;
43
45
  hrefLang?: string | undefined | undefined;
44
46
  media?: string | undefined | undefined;
45
47
  ping?: string | undefined | undefined;
46
- type?: string | undefined | undefined;
47
- referrerPolicy?: React.HTMLAttributeReferrerPolicy | undefined;
48
48
  defaultChecked?: boolean | undefined | undefined;
49
49
  defaultValue?: string | number | readonly string[] | undefined;
50
50
  suppressContentEditableWarning?: boolean | undefined | undefined;
@@ -457,16 +457,15 @@ var listeners = /* @__PURE__ */ new Set();
457
457
  var pending = [];
458
458
  var identifier = null;
459
459
  var pendingEmail = null;
460
+ var buyerListeners = /* @__PURE__ */ new Set();
461
+ var lastEmail = null;
460
462
  var lastAt = /* @__PURE__ */ new Map();
461
463
  function trackStorefront(name, properties = {}) {
462
464
  if (typeof window === "undefined") return;
463
465
  const event = { name, properties, at: Date.now() };
464
466
  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
- }
467
+ pending.push(event);
468
+ if (pending.length > MAX_PENDING) pending = pending.slice(-MAX_PENDING);
470
469
  for (const listener of listeners) {
471
470
  try {
472
471
  listener(event);
@@ -476,14 +475,10 @@ function trackStorefront(name, properties = {}) {
476
475
  }
477
476
  function onStorefrontEvent(listener) {
478
477
  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
- }
478
+ for (const event of pending) {
479
+ try {
480
+ listener(event);
481
+ } catch {
487
482
  }
488
483
  }
489
484
  return () => {
@@ -495,6 +490,25 @@ function identifyStorefrontBuyer(email) {
495
490
  if (!clean.includes("@")) return;
496
491
  if (identifier) identifier(clean);
497
492
  else pendingEmail = clean;
493
+ lastEmail = clean;
494
+ for (const listener of buyerListeners) {
495
+ try {
496
+ listener(clean);
497
+ } catch {
498
+ }
499
+ }
500
+ }
501
+ function onStorefrontBuyer(listener) {
502
+ buyerListeners.add(listener);
503
+ if (lastEmail) {
504
+ try {
505
+ listener(lastEmail);
506
+ } catch {
507
+ }
508
+ }
509
+ return () => {
510
+ buyerListeners.delete(listener);
511
+ };
498
512
  }
499
513
  function setStorefrontIdentifier(fn) {
500
514
  identifier = fn;
@@ -557,6 +571,109 @@ function startStorefrontPostHog(config, context) {
557
571
  });
558
572
  return started;
559
573
  }
574
+
575
+ // src/analytics/meta-pixel.ts
576
+ var META_PIXEL_ID = /^[0-9]{10,20}$/;
577
+ var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
578
+ var str = (v) => typeof v === "string" && v ? v : void 0;
579
+ function metaEventFor(event, currency) {
580
+ const p = event.properties;
581
+ switch (event.name) {
582
+ case "product_viewed": {
583
+ const id = str(p.product_id);
584
+ if (!id) return null;
585
+ return {
586
+ name: "ViewContent",
587
+ params: { content_ids: [id], content_name: str(p.product_name), content_type: "product", value: num(p.price), currency }
588
+ };
589
+ }
590
+ case "product_added_to_cart": {
591
+ const id = str(p.product_id);
592
+ if (!id) return null;
593
+ const quantity = num(p.quantity) ?? 1;
594
+ const price = num(p.price);
595
+ return {
596
+ name: "AddToCart",
597
+ params: {
598
+ content_ids: [id],
599
+ content_name: str(p.product_name),
600
+ content_type: "product",
601
+ contents: [{ id, quantity, item_price: price }],
602
+ value: price === void 0 ? void 0 : Math.round(price * quantity * 100) / 100,
603
+ currency
604
+ }
605
+ };
606
+ }
607
+ case "checkout_started":
608
+ return { name: "InitiateCheckout", params: { num_items: num(p.cart_count), value: num(p.cart_subtotal), currency } };
609
+ case "checkout_payment_selected":
610
+ return { name: "AddPaymentInfo", params: { payment_method: str(p.payment_method), currency } };
611
+ case "checkout_completed": {
612
+ const orderId = str(p.order_id);
613
+ const value = num(p.total);
614
+ if (!orderId || value === void 0) return null;
615
+ return { name: "Purchase", params: { value, currency, order_id: orderId }, eventId: orderId };
616
+ }
617
+ default:
618
+ return null;
619
+ }
620
+ }
621
+ var strip = (params) => Object.fromEntries(Object.entries(params).filter(([, v]) => v !== void 0 && v !== null));
622
+ function installFbq() {
623
+ if (window.fbq) return window.fbq;
624
+ const fbq = function(...args) {
625
+ if (fbq.callMethod) fbq.callMethod(...args);
626
+ else fbq.queue.push(args);
627
+ };
628
+ fbq.push = fbq;
629
+ fbq.loaded = true;
630
+ fbq.version = "2.0";
631
+ fbq.queue = [];
632
+ window.fbq = fbq;
633
+ if (!window._fbq) window._fbq = fbq;
634
+ const script = document.createElement("script");
635
+ script.async = true;
636
+ script.src = "https://connect.facebook.net/en_US/fbevents.js";
637
+ document.head.appendChild(script);
638
+ return fbq;
639
+ }
640
+ var PURCHASES_KEY = "fayz.meta.purchases";
641
+ function purchaseSeen(orderId) {
642
+ try {
643
+ const seen = JSON.parse(sessionStorage.getItem(PURCHASES_KEY) ?? "[]");
644
+ if (seen.includes(orderId)) return true;
645
+ sessionStorage.setItem(PURCHASES_KEY, JSON.stringify([...seen.slice(-19), orderId]));
646
+ } catch {
647
+ }
648
+ return false;
649
+ }
650
+ var started2 = null;
651
+ function startStorefrontMetaPixel(config, context) {
652
+ if (typeof window === "undefined") return;
653
+ const pixelId = config.pixelId.trim();
654
+ if (!META_PIXEL_ID.test(pixelId)) return;
655
+ if (started2?.pixelId === pixelId) return;
656
+ started2?.stop();
657
+ const fbq = installFbq();
658
+ fbq("init", pixelId);
659
+ const offEvents = onStorefrontEvent((event) => {
660
+ const meta = metaEventFor(event, context.currency);
661
+ if (!meta) return;
662
+ if (meta.name === "Purchase" && meta.eventId && purchaseSeen(meta.eventId)) return;
663
+ fbq("trackSingle", pixelId, meta.name, strip(meta.params), meta.eventId ? { eventID: meta.eventId } : void 0);
664
+ });
665
+ const offBuyer = onStorefrontBuyer((email) => fbq("init", pixelId, { em: email }));
666
+ started2 = { pixelId, stop: () => {
667
+ offEvents();
668
+ offBuyer();
669
+ } };
670
+ }
671
+ function trackMetaPageView() {
672
+ if (typeof window === "undefined" || !started2) return;
673
+ window.fbq?.("trackSingle", started2.pixelId, "PageView");
674
+ }
675
+
676
+ // src/analytics/StorefrontAnalytics.tsx
560
677
  function isOrderingPath(path, menuPath) {
561
678
  const p = path.split(/[?#]/)[0] || "/";
562
679
  if (menuPath && menuPath !== "/" && (p === menuPath || p.startsWith(`${menuPath}/`))) return true;
@@ -577,6 +694,9 @@ function cartChanges(prev, next) {
577
694
  }
578
695
  function StorefrontAnalytics({ config, path }) {
579
696
  const posthog = config.analytics?.posthog;
697
+ const pixelId = config.analytics?.metaPixel?.pixelId ?? config.policy?.metaPixelId ?? null;
698
+ const metaPixel = pixelId && META_PIXEL_ID.test(pixelId) ? pixelId : null;
699
+ const reporting = Boolean(posthog || metaPixel);
580
700
  const menuPath = config.delivery?.menuPath;
581
701
  const previous = React39.useRef(null);
582
702
  React39.useEffect(() => {
@@ -584,7 +704,14 @@ function StorefrontAnalytics({ config, path }) {
584
704
  startStorefrontPostHog(posthog, { storeName: config.name, commerceMode: config.commerceMode });
585
705
  }, [posthog, config.name, config.commerceMode]);
586
706
  React39.useEffect(() => {
587
- if (!posthog) return;
707
+ if (!metaPixel) return;
708
+ startStorefrontMetaPixel({ pixelId: metaPixel }, { currency: config.currency ?? "BRL" });
709
+ }, [metaPixel, config.currency]);
710
+ React39.useEffect(() => {
711
+ if (metaPixel) trackMetaPageView();
712
+ }, [metaPixel, path]);
713
+ React39.useEffect(() => {
714
+ if (!reporting) return;
588
715
  let ready = useCartStore.persist?.hasHydrated?.() ?? true;
589
716
  const unhydrated = useCartStore.persist?.onFinishHydration?.(() => {
590
717
  ready = true;
@@ -613,9 +740,9 @@ function StorefrontAnalytics({ config, path }) {
613
740
  unsubscribe();
614
741
  unhydrated?.();
615
742
  };
616
- }, [posthog]);
743
+ }, [reporting]);
617
744
  React39.useEffect(() => {
618
- if (!posthog) return;
745
+ if (!reporting) return;
619
746
  const from = previous.current;
620
747
  previous.current = path;
621
748
  if (!from || from === path) return;
@@ -623,7 +750,7 @@ function StorefrontAnalytics({ config, path }) {
623
750
  const cart = useCartStore.getState();
624
751
  trackStorefront("delivery_exit", { from, to: path, cart_count: selectCount(cart), cart_subtotal: selectSubtotal(cart) });
625
752
  }
626
- }, [posthog, path, menuPath]);
753
+ }, [reporting, path, menuPath]);
627
754
  return null;
628
755
  }
629
756
  var useSessionStore = create()(
@@ -4551,8 +4678,8 @@ function ProductSpecs({ product }) {
4551
4678
  if (product.weight != null) rows.push(["Peso", `${product.weight} ${product.weightUnit}`]);
4552
4679
  for (const [key, value] of Object.entries(product.metadata ?? {})) {
4553
4680
  if (isInternalKey(key, extraExcluded)) continue;
4554
- const str = scalarToString(value);
4555
- if (str) rows.push([humanize(key, extraLabels), str]);
4681
+ const str2 = scalarToString(value);
4682
+ if (str2) rows.push([humanize(key, extraLabels), str2]);
4556
4683
  }
4557
4684
  if (rows.length === 0) return null;
4558
4685
  return /* @__PURE__ */ jsxs("section", { className: "mt-14", children: [
@@ -9834,7 +9961,14 @@ function CheckoutPage() {
9834
9961
  useEffect(() => {
9835
9962
  if (reportedStart.current) return;
9836
9963
  reportedStart.current = true;
9837
- if (!resume) trackStorefront("checkout_started", { cart_count: cart.lines.reduce((n, l) => n + l.quantity, 0) });
9964
+ if (!resume) {
9965
+ trackStorefront("checkout_started", {
9966
+ cart_count: cart.lines.reduce((n, l) => n + l.quantity, 0),
9967
+ // What the cart is worth when the checkout opens: the value an ad
9968
+ // platform optimises InitiateCheckout for.
9969
+ cart_subtotal: Math.round(cart.lines.reduce((sum, l) => sum + l.unitPrice * l.quantity, 0) * 100) / 100
9970
+ });
9971
+ }
9838
9972
  }, []);
9839
9973
  const reportedStep = React39__default.useRef(null);
9840
9974
  useEffect(() => {
@@ -15026,5 +15160,5 @@ ${formatErrors(report.errors)}`;
15026
15160
  }
15027
15161
 
15028
15162
  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
15163
+ //# sourceMappingURL=chunk-6H5VD6OB.js.map
15164
+ //# sourceMappingURL=chunk-6H5VD6OB.js.map