@behio/storefront-sdk 0.22.0 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -110,6 +110,8 @@ function toSdkError(err2) {
110
110
  // src/client.ts
111
111
  var BehioStorefront = class {
112
112
  constructor(config) {
113
+ /** Consent-gated persistent visitor id — set by the analytics tracker. */
114
+ this.analyticsVisitorId = null;
113
115
  // Token refresh lock
114
116
  this.isRefreshing = false;
115
117
  this.refreshPromise = null;
@@ -146,6 +148,40 @@ var BehioStorefront = class {
146
148
  this.shipping = new ShippingModule(this);
147
149
  }
148
150
  // --- Public methods ---
151
+ /**
152
+ * Called by the analytics tracker when the visitor grants (id) or revokes
153
+ * (null) analytics consent. When set, requests carry the X-Behio-Vid header
154
+ * so the backend can attribute orders to the visitor journey.
155
+ */
156
+ setAnalyticsVisitorId(id) {
157
+ this.analyticsVisitorId = id;
158
+ }
159
+ /** The consent-gated visitor id, if analytics consent was granted. */
160
+ getAnalyticsVisitorId() {
161
+ return this.analyticsVisitorId;
162
+ }
163
+ /**
164
+ * Fire-and-forget Behio Analytics ingest. Uses a bare keepalive fetch (not
165
+ * the interceptor pipeline) so flushes on pagehide still land, and swallows
166
+ * every error — analytics must never break the shop. The client sends no
167
+ * identity; the visitor hash is computed server-side from a daily salt.
168
+ */
169
+ async sendAnalyticsEvents(input) {
170
+ try {
171
+ const headers = {
172
+ "X-Api-Key": this.apiKey,
173
+ "Content-Type": "application/json"
174
+ };
175
+ if (this.shopDomain) headers["X-Shop-Domain"] = this.shopDomain;
176
+ await fetch(`${this.baseUrl}/storefront/v1/analytics/events`, {
177
+ method: "POST",
178
+ keepalive: true,
179
+ headers,
180
+ body: JSON.stringify(input)
181
+ });
182
+ } catch {
183
+ }
184
+ }
149
185
  /** Get basic shop info */
150
186
  async getShopInfo() {
151
187
  return this.request("GET", "/shop");
@@ -342,6 +378,9 @@ var BehioStorefront = class {
342
378
  if (this.cartSession) {
343
379
  headers["X-Cart-Session"] = this.cartSession;
344
380
  }
381
+ if (this.analyticsVisitorId) {
382
+ headers["X-Behio-Vid"] = this.analyticsVisitorId;
383
+ }
345
384
  if (options?.headers) {
346
385
  Object.assign(headers, options.headers);
347
386
  }
@@ -110,6 +110,8 @@ function toSdkError(err2) {
110
110
  // src/client.ts
111
111
  var BehioStorefront = class {
112
112
  constructor(config) {
113
+ /** Consent-gated persistent visitor id — set by the analytics tracker. */
114
+ this.analyticsVisitorId = null;
113
115
  // Token refresh lock
114
116
  this.isRefreshing = false;
115
117
  this.refreshPromise = null;
@@ -146,6 +148,40 @@ var BehioStorefront = class {
146
148
  this.shipping = new ShippingModule(this);
147
149
  }
148
150
  // --- Public methods ---
151
+ /**
152
+ * Called by the analytics tracker when the visitor grants (id) or revokes
153
+ * (null) analytics consent. When set, requests carry the X-Behio-Vid header
154
+ * so the backend can attribute orders to the visitor journey.
155
+ */
156
+ setAnalyticsVisitorId(id) {
157
+ this.analyticsVisitorId = id;
158
+ }
159
+ /** The consent-gated visitor id, if analytics consent was granted. */
160
+ getAnalyticsVisitorId() {
161
+ return this.analyticsVisitorId;
162
+ }
163
+ /**
164
+ * Fire-and-forget Behio Analytics ingest. Uses a bare keepalive fetch (not
165
+ * the interceptor pipeline) so flushes on pagehide still land, and swallows
166
+ * every error — analytics must never break the shop. The client sends no
167
+ * identity; the visitor hash is computed server-side from a daily salt.
168
+ */
169
+ async sendAnalyticsEvents(input) {
170
+ try {
171
+ const headers = {
172
+ "X-Api-Key": this.apiKey,
173
+ "Content-Type": "application/json"
174
+ };
175
+ if (this.shopDomain) headers["X-Shop-Domain"] = this.shopDomain;
176
+ await fetch(`${this.baseUrl}/storefront/v1/analytics/events`, {
177
+ method: "POST",
178
+ keepalive: true,
179
+ headers,
180
+ body: JSON.stringify(input)
181
+ });
182
+ } catch (e) {
183
+ }
184
+ }
149
185
  /** Get basic shop info */
150
186
  async getShopInfo() {
151
187
  return this.request("GET", "/shop");
@@ -231,7 +267,7 @@ var BehioStorefront = class {
231
267
  _optionalChain([this, 'access', _7 => _7.listeners, 'access', _8 => _8.get, 'call', _9 => _9(event), 'optionalAccess', _10 => _10.forEach, 'call', _11 => _11((fn) => {
232
268
  try {
233
269
  fn(data);
234
- } catch (e) {
270
+ } catch (e2) {
235
271
  }
236
272
  })]);
237
273
  }
@@ -342,6 +378,9 @@ var BehioStorefront = class {
342
378
  if (this.cartSession) {
343
379
  headers["X-Cart-Session"] = this.cartSession;
344
380
  }
381
+ if (this.analyticsVisitorId) {
382
+ headers["X-Behio-Vid"] = this.analyticsVisitorId;
383
+ }
345
384
  if (_optionalChain([options, 'optionalAccess', _14 => _14.headers])) {
346
385
  Object.assign(headers, options.headers);
347
386
  }
@@ -405,7 +444,7 @@ var BehioStorefront = class {
405
444
  try {
406
445
  await this.handleTokenRefresh();
407
446
  return this.rawRequest(method, path, { ...options, _isRetryAfterRefresh: true });
408
- } catch (e2) {
447
+ } catch (e3) {
409
448
  this.emit("error", apiError);
410
449
  throw apiError;
411
450
  }
@@ -421,7 +460,7 @@ var BehioStorefront = class {
421
460
  for (const interceptor of this.responseInterceptors) {
422
461
  try {
423
462
  await interceptor({ status: res.status, data: responseData, headers: res.headers });
424
- } catch (e3) {
463
+ } catch (e4) {
425
464
  }
426
465
  }
427
466
  return responseData;
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/react/utils/format-price.ts
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/react/utils/format-price.ts
2
2
  function formatPrice(amount, currency, locale) {
3
3
  const resolvedLocale = _nullishCoalesce(locale, () => ( "cs"));
4
4
  try {
@@ -17,6 +17,10 @@ function formatPrice(amount, currency, locale) {
17
17
  function trackEcommerceEvent(event, payload) {
18
18
  if (typeof window === "undefined") return;
19
19
  const w = window;
20
+ try {
21
+ _optionalChain([w, 'access', _ => _.__behioEcommerceSink, 'optionalCall', _2 => _2(event, payload)]);
22
+ } catch (e2) {
23
+ }
20
24
  try {
21
25
  if (typeof w.gtag === "function") {
22
26
  w.gtag("event", event, payload);
@@ -26,7 +30,7 @@ function trackEcommerceEvent(event, payload) {
26
30
  w.dataLayer.push({ ecommerce: null });
27
31
  w.dataLayer.push({ event, ecommerce: payload });
28
32
  }
29
- } catch (e2) {
33
+ } catch (e3) {
30
34
  }
31
35
  }
32
36
 
@@ -17,6 +17,10 @@ function formatPrice(amount, currency, locale) {
17
17
  function trackEcommerceEvent(event, payload) {
18
18
  if (typeof window === "undefined") return;
19
19
  const w = window;
20
+ try {
21
+ w.__behioEcommerceSink?.(event, payload);
22
+ } catch {
23
+ }
20
24
  try {
21
25
  if (typeof w.gtag === "function") {
22
26
  w.gtag("event", event, payload);
@@ -454,6 +454,12 @@ interface CheckoutAddress {
454
454
  phone?: string;
455
455
  }
456
456
  interface CheckoutInput {
457
+ /**
458
+ * Consent-gated Behio Analytics visitor id (behio_visitor_id). Optional;
459
+ * lets the backend attribute the order to the visitor journey. Send it only
460
+ * when the visitor granted analytics consent.
461
+ */
462
+ analyticsVisitorId?: string;
457
463
  shippingAddress: CheckoutAddress;
458
464
  billingAddress: CheckoutAddress;
459
465
  email: string;
@@ -993,6 +999,8 @@ interface SubmitQuoteInput {
993
999
  declare class BehioStorefront {
994
1000
  private baseUrl;
995
1001
  private apiKey;
1002
+ /** Consent-gated persistent visitor id — set by the analytics tracker. */
1003
+ private analyticsVisitorId;
996
1004
  private shopDomain?;
997
1005
  private defaultLocale?;
998
1006
  private defaultCurrency?;
@@ -1025,6 +1033,39 @@ declare class BehioStorefront {
1025
1033
  readonly quotes: QuotesModule;
1026
1034
  readonly addresses: AddressModule;
1027
1035
  readonly shipping: ShippingModule;
1036
+ /**
1037
+ * Called by the analytics tracker when the visitor grants (id) or revokes
1038
+ * (null) analytics consent. When set, requests carry the X-Behio-Vid header
1039
+ * so the backend can attribute orders to the visitor journey.
1040
+ */
1041
+ setAnalyticsVisitorId(id: string | null): void;
1042
+ /** The consent-gated visitor id, if analytics consent was granted. */
1043
+ getAnalyticsVisitorId(): string | null;
1044
+ /**
1045
+ * Fire-and-forget Behio Analytics ingest. Uses a bare keepalive fetch (not
1046
+ * the interceptor pipeline) so flushes on pagehide still land, and swallows
1047
+ * every error — analytics must never break the shop. The client sends no
1048
+ * identity; the visitor hash is computed server-side from a daily salt.
1049
+ */
1050
+ sendAnalyticsEvents(input: {
1051
+ sessionId?: string;
1052
+ /** Persistent consent-gated visitor id (behio_visitor_id). */
1053
+ visitorId?: string;
1054
+ events: Array<{
1055
+ type: "pageview" | "ecommerce" | "custom";
1056
+ name?: string;
1057
+ ts?: number;
1058
+ path?: string;
1059
+ referrer?: string;
1060
+ utmSource?: string;
1061
+ utmMedium?: string;
1062
+ utmCampaign?: string;
1063
+ dwellMs?: number;
1064
+ value?: number;
1065
+ currency?: string;
1066
+ props?: Record<string, unknown>;
1067
+ }>;
1068
+ }): Promise<void>;
1028
1069
  /** Get basic shop info */
1029
1070
  getShopInfo(): Promise<SdkResult<ShopInfo>>;
1030
1071
  /** Get SEO metadata for the shop homepage in the given locale (defaults to shop default). */
@@ -454,6 +454,12 @@ interface CheckoutAddress {
454
454
  phone?: string;
455
455
  }
456
456
  interface CheckoutInput {
457
+ /**
458
+ * Consent-gated Behio Analytics visitor id (behio_visitor_id). Optional;
459
+ * lets the backend attribute the order to the visitor journey. Send it only
460
+ * when the visitor granted analytics consent.
461
+ */
462
+ analyticsVisitorId?: string;
457
463
  shippingAddress: CheckoutAddress;
458
464
  billingAddress: CheckoutAddress;
459
465
  email: string;
@@ -993,6 +999,8 @@ interface SubmitQuoteInput {
993
999
  declare class BehioStorefront {
994
1000
  private baseUrl;
995
1001
  private apiKey;
1002
+ /** Consent-gated persistent visitor id — set by the analytics tracker. */
1003
+ private analyticsVisitorId;
996
1004
  private shopDomain?;
997
1005
  private defaultLocale?;
998
1006
  private defaultCurrency?;
@@ -1025,6 +1033,39 @@ declare class BehioStorefront {
1025
1033
  readonly quotes: QuotesModule;
1026
1034
  readonly addresses: AddressModule;
1027
1035
  readonly shipping: ShippingModule;
1036
+ /**
1037
+ * Called by the analytics tracker when the visitor grants (id) or revokes
1038
+ * (null) analytics consent. When set, requests carry the X-Behio-Vid header
1039
+ * so the backend can attribute orders to the visitor journey.
1040
+ */
1041
+ setAnalyticsVisitorId(id: string | null): void;
1042
+ /** The consent-gated visitor id, if analytics consent was granted. */
1043
+ getAnalyticsVisitorId(): string | null;
1044
+ /**
1045
+ * Fire-and-forget Behio Analytics ingest. Uses a bare keepalive fetch (not
1046
+ * the interceptor pipeline) so flushes on pagehide still land, and swallows
1047
+ * every error — analytics must never break the shop. The client sends no
1048
+ * identity; the visitor hash is computed server-side from a daily salt.
1049
+ */
1050
+ sendAnalyticsEvents(input: {
1051
+ sessionId?: string;
1052
+ /** Persistent consent-gated visitor id (behio_visitor_id). */
1053
+ visitorId?: string;
1054
+ events: Array<{
1055
+ type: "pageview" | "ecommerce" | "custom";
1056
+ name?: string;
1057
+ ts?: number;
1058
+ path?: string;
1059
+ referrer?: string;
1060
+ utmSource?: string;
1061
+ utmMedium?: string;
1062
+ utmCampaign?: string;
1063
+ dwellMs?: number;
1064
+ value?: number;
1065
+ currency?: string;
1066
+ props?: Record<string, unknown>;
1067
+ }>;
1068
+ }): Promise<void>;
1028
1069
  /** Get basic shop info */
1029
1070
  getShopInfo(): Promise<SdkResult<ShopInfo>>;
1030
1071
  /** Get SEO metadata for the shop homepage in the given locale (defaults to shop default). */
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- export { u as ActivePromotion, K as AddToCartInput, j as AddressDetail, A as AddressSuggestion, a4 as AddressType, a5 as AddressTypes, L as AuthTokens, J as BackInStockSubscription, M as BehioApiError, a6 as BehioErrorCode, a7 as BehioEventHandler, a8 as BehioEventType, a9 as BehioNetworkError, a as BehioStorefront, B as BehioStorefrontConfig, s as Bundle, N as BundleItem, g as Cart, aa as CartBundleLine, ab as CartBundleLineItem, T as CartDiscount, U as CartItem, ac as CartItemProduct, C as Category, e as CategoryDetail, V as CheckoutAddress, n as CheckoutInput, ad as CheckoutPaymentMethod, E as CookieConsent, H as CookieConsentInput, t as CrossSellItem, i as CustomerAddress, h as CustomerProfile, ae as DataGroupFieldType, F as FilterField, X as FulfillmentStatus, af as FulfillmentStatuses, G as GiftCardBalance, ag as GiftCardSummary, Y as LoginInput, Z as MessageResponse, l as OrderAccessRequestResponse, m as OrderAccessVerifyResponse, k as OrderDetail, _ as OrderItem, O as OrderListItem, $ as OrderStatus, ah as OrderStatusHistory, ai as OrderStatuses, aj as OrderTracking, p as Page, ak as PageAttachment, o as PageDetail, b as PaginatedResponse, a0 as PaymentStatus, al as PaymentStatuses, d as ProductDetail, f as ProductLabel, c as ProductListItem, am as ProductMedia, an as ProductMediaVariant, a1 as ProductPrice, a2 as ProductReview, v as ProductReviewsResponse, ao as ProductSort, ap as ProductSortValue, a3 as ProductVariant, aq as ProductVolumePrice, P as ProductsQuery, ar as QuoteItem, Q as QuoteRequest, R as RegisterInput, as as RegisterResult, at as RequestInterceptor, au as RequestInterceptorConfig, av as ResponseInterceptor, aw as ResponseInterceptorData, z as ReturnRequest, ax as ReturnRequestItem, y as ReturnStatus, ay as ReturnStatusItem, x as ReturnableOrder, az as ReturnableOrderItem, aA as SdkError, aB as SdkResult, aC as ShippingMethodSummary, aD as ShippingQuote, aE as ShippingQuoteInput, S as ShopInfo, aF as ShopScript, aG as ShopScriptPlacement, aH as ShopScriptType, q as ShopScripts, r as ShopSeo, I as SubmitQuoteInput, D as SubmitReturnInput, w as SubmitReviewInput, W as WishlistItem, aI as err, aJ as ok, aK as toSdkError } from './client-hCuGQERQ.mjs';
1
+ export { u as ActivePromotion, K as AddToCartInput, j as AddressDetail, A as AddressSuggestion, a4 as AddressType, a5 as AddressTypes, L as AuthTokens, J as BackInStockSubscription, M as BehioApiError, a6 as BehioErrorCode, a7 as BehioEventHandler, a8 as BehioEventType, a9 as BehioNetworkError, a as BehioStorefront, B as BehioStorefrontConfig, s as Bundle, N as BundleItem, g as Cart, aa as CartBundleLine, ab as CartBundleLineItem, T as CartDiscount, U as CartItem, ac as CartItemProduct, C as Category, e as CategoryDetail, V as CheckoutAddress, n as CheckoutInput, ad as CheckoutPaymentMethod, E as CookieConsent, H as CookieConsentInput, t as CrossSellItem, i as CustomerAddress, h as CustomerProfile, ae as DataGroupFieldType, F as FilterField, X as FulfillmentStatus, af as FulfillmentStatuses, G as GiftCardBalance, ag as GiftCardSummary, Y as LoginInput, Z as MessageResponse, l as OrderAccessRequestResponse, m as OrderAccessVerifyResponse, k as OrderDetail, _ as OrderItem, O as OrderListItem, $ as OrderStatus, ah as OrderStatusHistory, ai as OrderStatuses, aj as OrderTracking, p as Page, ak as PageAttachment, o as PageDetail, b as PaginatedResponse, a0 as PaymentStatus, al as PaymentStatuses, d as ProductDetail, f as ProductLabel, c as ProductListItem, am as ProductMedia, an as ProductMediaVariant, a1 as ProductPrice, a2 as ProductReview, v as ProductReviewsResponse, ao as ProductSort, ap as ProductSortValue, a3 as ProductVariant, aq as ProductVolumePrice, P as ProductsQuery, ar as QuoteItem, Q as QuoteRequest, R as RegisterInput, as as RegisterResult, at as RequestInterceptor, au as RequestInterceptorConfig, av as ResponseInterceptor, aw as ResponseInterceptorData, z as ReturnRequest, ax as ReturnRequestItem, y as ReturnStatus, ay as ReturnStatusItem, x as ReturnableOrder, az as ReturnableOrderItem, aA as SdkError, aB as SdkResult, aC as ShippingMethodSummary, aD as ShippingQuote, aE as ShippingQuoteInput, S as ShopInfo, aF as ShopScript, aG as ShopScriptPlacement, aH as ShopScriptType, q as ShopScripts, r as ShopSeo, I as SubmitQuoteInput, D as SubmitReturnInput, w as SubmitReviewInput, W as WishlistItem, aI as err, aJ as ok, aK as toSdkError } from './client-B0VFrsad.mjs';
2
2
 
3
3
  /**
4
4
  * Format a price amount with currency using Intl.NumberFormat.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { u as ActivePromotion, K as AddToCartInput, j as AddressDetail, A as AddressSuggestion, a4 as AddressType, a5 as AddressTypes, L as AuthTokens, J as BackInStockSubscription, M as BehioApiError, a6 as BehioErrorCode, a7 as BehioEventHandler, a8 as BehioEventType, a9 as BehioNetworkError, a as BehioStorefront, B as BehioStorefrontConfig, s as Bundle, N as BundleItem, g as Cart, aa as CartBundleLine, ab as CartBundleLineItem, T as CartDiscount, U as CartItem, ac as CartItemProduct, C as Category, e as CategoryDetail, V as CheckoutAddress, n as CheckoutInput, ad as CheckoutPaymentMethod, E as CookieConsent, H as CookieConsentInput, t as CrossSellItem, i as CustomerAddress, h as CustomerProfile, ae as DataGroupFieldType, F as FilterField, X as FulfillmentStatus, af as FulfillmentStatuses, G as GiftCardBalance, ag as GiftCardSummary, Y as LoginInput, Z as MessageResponse, l as OrderAccessRequestResponse, m as OrderAccessVerifyResponse, k as OrderDetail, _ as OrderItem, O as OrderListItem, $ as OrderStatus, ah as OrderStatusHistory, ai as OrderStatuses, aj as OrderTracking, p as Page, ak as PageAttachment, o as PageDetail, b as PaginatedResponse, a0 as PaymentStatus, al as PaymentStatuses, d as ProductDetail, f as ProductLabel, c as ProductListItem, am as ProductMedia, an as ProductMediaVariant, a1 as ProductPrice, a2 as ProductReview, v as ProductReviewsResponse, ao as ProductSort, ap as ProductSortValue, a3 as ProductVariant, aq as ProductVolumePrice, P as ProductsQuery, ar as QuoteItem, Q as QuoteRequest, R as RegisterInput, as as RegisterResult, at as RequestInterceptor, au as RequestInterceptorConfig, av as ResponseInterceptor, aw as ResponseInterceptorData, z as ReturnRequest, ax as ReturnRequestItem, y as ReturnStatus, ay as ReturnStatusItem, x as ReturnableOrder, az as ReturnableOrderItem, aA as SdkError, aB as SdkResult, aC as ShippingMethodSummary, aD as ShippingQuote, aE as ShippingQuoteInput, S as ShopInfo, aF as ShopScript, aG as ShopScriptPlacement, aH as ShopScriptType, q as ShopScripts, r as ShopSeo, I as SubmitQuoteInput, D as SubmitReturnInput, w as SubmitReviewInput, W as WishlistItem, aI as err, aJ as ok, aK as toSdkError } from './client-hCuGQERQ.js';
1
+ export { u as ActivePromotion, K as AddToCartInput, j as AddressDetail, A as AddressSuggestion, a4 as AddressType, a5 as AddressTypes, L as AuthTokens, J as BackInStockSubscription, M as BehioApiError, a6 as BehioErrorCode, a7 as BehioEventHandler, a8 as BehioEventType, a9 as BehioNetworkError, a as BehioStorefront, B as BehioStorefrontConfig, s as Bundle, N as BundleItem, g as Cart, aa as CartBundleLine, ab as CartBundleLineItem, T as CartDiscount, U as CartItem, ac as CartItemProduct, C as Category, e as CategoryDetail, V as CheckoutAddress, n as CheckoutInput, ad as CheckoutPaymentMethod, E as CookieConsent, H as CookieConsentInput, t as CrossSellItem, i as CustomerAddress, h as CustomerProfile, ae as DataGroupFieldType, F as FilterField, X as FulfillmentStatus, af as FulfillmentStatuses, G as GiftCardBalance, ag as GiftCardSummary, Y as LoginInput, Z as MessageResponse, l as OrderAccessRequestResponse, m as OrderAccessVerifyResponse, k as OrderDetail, _ as OrderItem, O as OrderListItem, $ as OrderStatus, ah as OrderStatusHistory, ai as OrderStatuses, aj as OrderTracking, p as Page, ak as PageAttachment, o as PageDetail, b as PaginatedResponse, a0 as PaymentStatus, al as PaymentStatuses, d as ProductDetail, f as ProductLabel, c as ProductListItem, am as ProductMedia, an as ProductMediaVariant, a1 as ProductPrice, a2 as ProductReview, v as ProductReviewsResponse, ao as ProductSort, ap as ProductSortValue, a3 as ProductVariant, aq as ProductVolumePrice, P as ProductsQuery, ar as QuoteItem, Q as QuoteRequest, R as RegisterInput, as as RegisterResult, at as RequestInterceptor, au as RequestInterceptorConfig, av as ResponseInterceptor, aw as ResponseInterceptorData, z as ReturnRequest, ax as ReturnRequestItem, y as ReturnStatus, ay as ReturnStatusItem, x as ReturnableOrder, az as ReturnableOrderItem, aA as SdkError, aB as SdkResult, aC as ShippingMethodSummary, aD as ShippingQuote, aE as ShippingQuoteInput, S as ShopInfo, aF as ShopScript, aG as ShopScriptPlacement, aH as ShopScriptType, q as ShopScripts, r as ShopSeo, I as SubmitQuoteInput, D as SubmitReturnInput, w as SubmitReviewInput, W as WishlistItem, aI as err, aJ as ok, aK as toSdkError } from './client-B0VFrsad.js';
2
2
 
3
3
  /**
4
4
  * Format a price amount with currency using Intl.NumberFormat.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
3
 
4
- var _chunkBFF5BKR2js = require('./chunk-BFF5BKR2.js');
4
+ var _chunkJIAOZ5YWjs = require('./chunk-JIAOZ5YW.js');
5
5
 
6
6
 
7
7
 
@@ -14,7 +14,7 @@ var _chunkBFF5BKR2js = require('./chunk-BFF5BKR2.js');
14
14
 
15
15
 
16
16
 
17
- var _chunkBF4YVFHXjs = require('./chunk-BF4YVFHX.js');
17
+ var _chunk3RI2QBQOjs = require('./chunk-3RI2QBQO.js');
18
18
 
19
19
 
20
20
 
@@ -29,4 +29,4 @@ var _chunkBF4YVFHXjs = require('./chunk-BF4YVFHX.js');
29
29
 
30
30
 
31
31
 
32
- exports.AddressTypes = _chunkBF4YVFHXjs.AddressTypes; exports.BehioApiError = _chunkBF4YVFHXjs.BehioApiError; exports.BehioNetworkError = _chunkBF4YVFHXjs.BehioNetworkError; exports.BehioStorefront = _chunkBF4YVFHXjs.BehioStorefront; exports.FulfillmentStatuses = _chunkBF4YVFHXjs.FulfillmentStatuses; exports.OrderStatuses = _chunkBF4YVFHXjs.OrderStatuses; exports.PaymentStatuses = _chunkBF4YVFHXjs.PaymentStatuses; exports.ProductSort = _chunkBF4YVFHXjs.ProductSort; exports.err = _chunkBF4YVFHXjs.err; exports.formatPrice = _chunkBFF5BKR2js.formatPrice; exports.ok = _chunkBF4YVFHXjs.ok; exports.toSdkError = _chunkBF4YVFHXjs.toSdkError; exports.trackEcommerceEvent = _chunkBFF5BKR2js.trackEcommerceEvent;
32
+ exports.AddressTypes = _chunk3RI2QBQOjs.AddressTypes; exports.BehioApiError = _chunk3RI2QBQOjs.BehioApiError; exports.BehioNetworkError = _chunk3RI2QBQOjs.BehioNetworkError; exports.BehioStorefront = _chunk3RI2QBQOjs.BehioStorefront; exports.FulfillmentStatuses = _chunk3RI2QBQOjs.FulfillmentStatuses; exports.OrderStatuses = _chunk3RI2QBQOjs.OrderStatuses; exports.PaymentStatuses = _chunk3RI2QBQOjs.PaymentStatuses; exports.ProductSort = _chunk3RI2QBQOjs.ProductSort; exports.err = _chunk3RI2QBQOjs.err; exports.formatPrice = _chunkJIAOZ5YWjs.formatPrice; exports.ok = _chunk3RI2QBQOjs.ok; exports.toSdkError = _chunk3RI2QBQOjs.toSdkError; exports.trackEcommerceEvent = _chunkJIAOZ5YWjs.trackEcommerceEvent;
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  formatPrice,
3
3
  trackEcommerceEvent
4
- } from "./chunk-AN3QTDNM.mjs";
4
+ } from "./chunk-ZOZAJG6T.mjs";
5
5
  import {
6
6
  AddressTypes,
7
7
  BehioApiError,
@@ -14,7 +14,7 @@ import {
14
14
  err,
15
15
  ok,
16
16
  toSdkError
17
- } from "./chunk-PZED7VMQ.mjs";
17
+ } from "./chunk-2CD4CPEV.mjs";
18
18
  export {
19
19
  AddressTypes,
20
20
  BehioApiError,
package/dist/next.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { B as BehioStorefrontConfig, a as BehioStorefront } from './client-hCuGQERQ.mjs';
1
+ import { B as BehioStorefrontConfig, a as BehioStorefront } from './client-B0VFrsad.mjs';
2
2
 
3
3
  interface GetBehioOptions extends Partial<BehioStorefrontConfig> {
4
4
  /** Override the cart session cookie name (default: "behio_cart_session"). */
package/dist/next.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { B as BehioStorefrontConfig, a as BehioStorefront } from './client-hCuGQERQ.js';
1
+ import { B as BehioStorefrontConfig, a as BehioStorefront } from './client-B0VFrsad.js';
2
2
 
3
3
  interface GetBehioOptions extends Partial<BehioStorefrontConfig> {
4
4
  /** Override the cart session cookie name (default: "behio_cart_session"). */
package/dist/next.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
- var _chunkBF4YVFHXjs = require('./chunk-BF4YVFHX.js');
3
+ var _chunk3RI2QBQOjs = require('./chunk-3RI2QBQO.js');
4
4
 
5
5
  // src/next.ts
6
6
  var _headers = require('next/headers');
@@ -18,7 +18,7 @@ async function getBehio(options = {}) {
18
18
  const locale = _nullishCoalesce(options.locale, () => ( process.env.BEHIO_LOCALE));
19
19
  const currency = _nullishCoalesce(options.currency, () => ( process.env.BEHIO_CURRENCY));
20
20
  const cookieName = _nullishCoalesce(options.cartCookieName, () => ( CART_COOKIE_NAME));
21
- const client = new (0, _chunkBF4YVFHXjs.BehioStorefront)({
21
+ const client = new (0, _chunk3RI2QBQOjs.BehioStorefront)({
22
22
  apiKey,
23
23
  ...baseUrl ? { baseUrl } : {},
24
24
  ...locale ? { locale } : {},
package/dist/next.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  BehioStorefront
3
- } from "./chunk-PZED7VMQ.mjs";
3
+ } from "./chunk-2CD4CPEV.mjs";
4
4
 
5
5
  // src/next.ts
6
6
  import { cookies } from "next/headers";
package/dist/react.d.mts CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as _tanstack_react_query from '@tanstack/react-query';
3
3
  import { QueryClient } from '@tanstack/react-query';
4
- import { a as BehioStorefront, P as ProductsQuery, b as PaginatedResponse, c as ProductListItem, d as ProductDetail, C as Category, e as CategoryDetail, f as ProductLabel, F as FilterField, g as Cart, h as CustomerProfile, R as RegisterInput, i as CustomerAddress, A as AddressSuggestion, j as AddressDetail, O as OrderListItem, k as OrderDetail, l as OrderAccessRequestResponse, m as OrderAccessVerifyResponse, n as CheckoutInput, o as PageDetail, p as Page, S as ShopInfo, q as ShopScripts, r as ShopSeo, s as Bundle, t as CrossSellItem, u as ActivePromotion, G as GiftCardBalance, W as WishlistItem, v as ProductReviewsResponse, w as SubmitReviewInput, x as ReturnableOrder, y as ReturnStatus, z as ReturnRequest, D as SubmitReturnInput, E as CookieConsent, H as CookieConsentInput, Q as QuoteRequest, I as SubmitQuoteInput, J as BackInStockSubscription } from './client-hCuGQERQ.mjs';
5
- export { K as AddToCartInput, L as AuthTokens, M as BehioApiError, N as BundleItem, T as CartDiscount, U as CartItem, V as CheckoutAddress, X as FulfillmentStatus, Y as LoginInput, Z as MessageResponse, _ as OrderItem, $ as OrderStatus, a0 as PaymentStatus, a1 as ProductPrice, a2 as ProductReview, a3 as ProductVariant } from './client-hCuGQERQ.mjs';
4
+ import { a as BehioStorefront, P as ProductsQuery, b as PaginatedResponse, c as ProductListItem, d as ProductDetail, C as Category, e as CategoryDetail, f as ProductLabel, F as FilterField, g as Cart, h as CustomerProfile, R as RegisterInput, i as CustomerAddress, A as AddressSuggestion, j as AddressDetail, O as OrderListItem, k as OrderDetail, l as OrderAccessRequestResponse, m as OrderAccessVerifyResponse, n as CheckoutInput, o as PageDetail, p as Page, S as ShopInfo, q as ShopScripts, r as ShopSeo, s as Bundle, t as CrossSellItem, u as ActivePromotion, G as GiftCardBalance, W as WishlistItem, v as ProductReviewsResponse, w as SubmitReviewInput, x as ReturnableOrder, y as ReturnStatus, z as ReturnRequest, D as SubmitReturnInput, E as CookieConsent, H as CookieConsentInput, Q as QuoteRequest, I as SubmitQuoteInput, J as BackInStockSubscription } from './client-B0VFrsad.mjs';
5
+ export { K as AddToCartInput, L as AuthTokens, M as BehioApiError, N as BundleItem, T as CartDiscount, U as CartItem, V as CheckoutAddress, X as FulfillmentStatus, Y as LoginInput, Z as MessageResponse, _ as OrderItem, $ as OrderStatus, a0 as PaymentStatus, a1 as ProductPrice, a2 as ProductReview, a3 as ProductVariant } from './client-B0VFrsad.mjs';
6
6
  import * as _tanstack_query_core from '@tanstack/query-core';
7
7
  export { EcommerceEventName, EcommerceItem, EcommercePayload, formatPrice, trackEcommerceEvent } from './index.mjs';
8
8
 
@@ -504,6 +504,27 @@ interface StorefrontScriptsProps {
504
504
  */
505
505
  declare function StorefrontScripts({ visitorId: visitorIdProp }?: StorefrontScriptsProps): null;
506
506
 
507
+ /**
508
+ * Behio Analytics auto-tracker. Mount ONCE in the root layout (next to
509
+ * <StorefrontScripts/>).
510
+ *
511
+ * Identity is three-tiered:
512
+ * - anonymous: no consent needed — the server computes a daily-rotating hash,
513
+ * the client sends nothing identifying
514
+ * - consented: once the visitor grants analytics consent (the shop's consent
515
+ * banner, keyed by the existing `behio_visitor_id`), events carry that
516
+ * persistent first-party id — enabling returning-visitor metrics and the
517
+ * customer journey
518
+ * - customer: the backend links the id to the customer at checkout/login
519
+ *
520
+ * Captures: pageviews (load + SPA route changes), visibility-aware dwell time
521
+ * per page, click events on interactive elements, UTM + referrer on landing.
522
+ * Events are batched (flush on 20 events / 5 s / route change / pagehide) via
523
+ * keepalive fetch. Listens for the `behio:consent-changed` window event to
524
+ * pick up consent grants/revocations immediately.
525
+ */
526
+ declare function BehioAnalyticsTracker(): null;
527
+
507
528
  /** List all active bundles. */
508
529
  declare function useBundles(options?: {
509
530
  enabled?: boolean;
@@ -1028,4 +1049,4 @@ declare function useNotifyWhenAvailable(): _tanstack_react_query.UseMutationResu
1028
1049
  */
1029
1050
  declare function useBehioClient(): BehioStorefront;
1030
1051
 
1031
- export { ActivePromotion, BehioProvider, type BehioProviderProps, Bundle, Cart, Category, CategoryDetail, CheckoutInput, CookieConsent, CookieConsentInput, CrossSellItem, CurrencySwitcher, type CurrencySwitcherProps, type CurrencySwitcherRenderProps, CustomerAddress, CustomerProfile, FilterField, GiftCardBalance, OrderDetail, OrderListItem, Page, PageDetail, PaginatedResponse, ProductDetail, ProductLabel, ProductListItem, ProductReviewsResponse, ProductsQuery, QuoteRequest, RegisterInput, ReturnRequest, ShopInfo, ShopSeo, type StorageAdapter, StorefrontScripts, type StorefrontScriptsProps, SubmitQuoteInput, SubmitReturnInput, SubmitReviewInput, type UseAddressAutocompleteOptions, type UseAddressAutocompleteReturn, type UseAddressesOptions, type UseCartCountOptions, type UseCartOptions, type UseCategoriesOptions, type UseCategoryOptions, type UseCurrencyResult, type UseCustomerOptions, type UseFeaturedOptions, type UseFiltersOptions, type UseLabelsOptions, type UseOrderOptions, type UseOrdersOptions, type UsePageOptions, type UsePagesOptions, type UseProductOptions, type UseProductsOptions, type UseSearchOptions, type UseShopInfoOptions, type UseShopScriptsOptions, type UseShopSeoOptions, WishlistItem, cookieStorage, createMemoryStorage, detectStorage, localStorageAdapter, memoryStorage, useAddressAutocomplete, useAddresses, useAuth, useBehio, useBehioClient, useBundle, useBundles, useCart, useCartCount, useCategories, useCategory, useCheckout, useCookieConsent, useCrossSell, useCurrency, useCustomer, useFeatured, useFilters, useGiftCardBalance, useIsInWishlist, useLabels, useLookupReturnableOrder, useNotifyWhenAvailable, useOrder, useOrderAccess, useOrders, usePage, usePages, useProduct, useProductPromotions, useProductReviews, useProducts, useQuoteStatus, useReturnStatus, useSearch, useShopInfo, useShopScripts, useShopSeo, useSubmitQuote, useSubmitReturn, useSubmitReview, useWishlist };
1052
+ export { ActivePromotion, BehioAnalyticsTracker, BehioProvider, type BehioProviderProps, Bundle, Cart, Category, CategoryDetail, CheckoutInput, CookieConsent, CookieConsentInput, CrossSellItem, CurrencySwitcher, type CurrencySwitcherProps, type CurrencySwitcherRenderProps, CustomerAddress, CustomerProfile, FilterField, GiftCardBalance, OrderDetail, OrderListItem, Page, PageDetail, PaginatedResponse, ProductDetail, ProductLabel, ProductListItem, ProductReviewsResponse, ProductsQuery, QuoteRequest, RegisterInput, ReturnRequest, ShopInfo, ShopSeo, type StorageAdapter, StorefrontScripts, type StorefrontScriptsProps, SubmitQuoteInput, SubmitReturnInput, SubmitReviewInput, type UseAddressAutocompleteOptions, type UseAddressAutocompleteReturn, type UseAddressesOptions, type UseCartCountOptions, type UseCartOptions, type UseCategoriesOptions, type UseCategoryOptions, type UseCurrencyResult, type UseCustomerOptions, type UseFeaturedOptions, type UseFiltersOptions, type UseLabelsOptions, type UseOrderOptions, type UseOrdersOptions, type UsePageOptions, type UsePagesOptions, type UseProductOptions, type UseProductsOptions, type UseSearchOptions, type UseShopInfoOptions, type UseShopScriptsOptions, type UseShopSeoOptions, WishlistItem, cookieStorage, createMemoryStorage, detectStorage, localStorageAdapter, memoryStorage, useAddressAutocomplete, useAddresses, useAuth, useBehio, useBehioClient, useBundle, useBundles, useCart, useCartCount, useCategories, useCategory, useCheckout, useCookieConsent, useCrossSell, useCurrency, useCustomer, useFeatured, useFilters, useGiftCardBalance, useIsInWishlist, useLabels, useLookupReturnableOrder, useNotifyWhenAvailable, useOrder, useOrderAccess, useOrders, usePage, usePages, useProduct, useProductPromotions, useProductReviews, useProducts, useQuoteStatus, useReturnStatus, useSearch, useShopInfo, useShopScripts, useShopSeo, useSubmitQuote, useSubmitReturn, useSubmitReview, useWishlist };
package/dist/react.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as _tanstack_react_query from '@tanstack/react-query';
3
3
  import { QueryClient } from '@tanstack/react-query';
4
- import { a as BehioStorefront, P as ProductsQuery, b as PaginatedResponse, c as ProductListItem, d as ProductDetail, C as Category, e as CategoryDetail, f as ProductLabel, F as FilterField, g as Cart, h as CustomerProfile, R as RegisterInput, i as CustomerAddress, A as AddressSuggestion, j as AddressDetail, O as OrderListItem, k as OrderDetail, l as OrderAccessRequestResponse, m as OrderAccessVerifyResponse, n as CheckoutInput, o as PageDetail, p as Page, S as ShopInfo, q as ShopScripts, r as ShopSeo, s as Bundle, t as CrossSellItem, u as ActivePromotion, G as GiftCardBalance, W as WishlistItem, v as ProductReviewsResponse, w as SubmitReviewInput, x as ReturnableOrder, y as ReturnStatus, z as ReturnRequest, D as SubmitReturnInput, E as CookieConsent, H as CookieConsentInput, Q as QuoteRequest, I as SubmitQuoteInput, J as BackInStockSubscription } from './client-hCuGQERQ.js';
5
- export { K as AddToCartInput, L as AuthTokens, M as BehioApiError, N as BundleItem, T as CartDiscount, U as CartItem, V as CheckoutAddress, X as FulfillmentStatus, Y as LoginInput, Z as MessageResponse, _ as OrderItem, $ as OrderStatus, a0 as PaymentStatus, a1 as ProductPrice, a2 as ProductReview, a3 as ProductVariant } from './client-hCuGQERQ.js';
4
+ import { a as BehioStorefront, P as ProductsQuery, b as PaginatedResponse, c as ProductListItem, d as ProductDetail, C as Category, e as CategoryDetail, f as ProductLabel, F as FilterField, g as Cart, h as CustomerProfile, R as RegisterInput, i as CustomerAddress, A as AddressSuggestion, j as AddressDetail, O as OrderListItem, k as OrderDetail, l as OrderAccessRequestResponse, m as OrderAccessVerifyResponse, n as CheckoutInput, o as PageDetail, p as Page, S as ShopInfo, q as ShopScripts, r as ShopSeo, s as Bundle, t as CrossSellItem, u as ActivePromotion, G as GiftCardBalance, W as WishlistItem, v as ProductReviewsResponse, w as SubmitReviewInput, x as ReturnableOrder, y as ReturnStatus, z as ReturnRequest, D as SubmitReturnInput, E as CookieConsent, H as CookieConsentInput, Q as QuoteRequest, I as SubmitQuoteInput, J as BackInStockSubscription } from './client-B0VFrsad.js';
5
+ export { K as AddToCartInput, L as AuthTokens, M as BehioApiError, N as BundleItem, T as CartDiscount, U as CartItem, V as CheckoutAddress, X as FulfillmentStatus, Y as LoginInput, Z as MessageResponse, _ as OrderItem, $ as OrderStatus, a0 as PaymentStatus, a1 as ProductPrice, a2 as ProductReview, a3 as ProductVariant } from './client-B0VFrsad.js';
6
6
  import * as _tanstack_query_core from '@tanstack/query-core';
7
7
  export { EcommerceEventName, EcommerceItem, EcommercePayload, formatPrice, trackEcommerceEvent } from './index.js';
8
8
 
@@ -504,6 +504,27 @@ interface StorefrontScriptsProps {
504
504
  */
505
505
  declare function StorefrontScripts({ visitorId: visitorIdProp }?: StorefrontScriptsProps): null;
506
506
 
507
+ /**
508
+ * Behio Analytics auto-tracker. Mount ONCE in the root layout (next to
509
+ * <StorefrontScripts/>).
510
+ *
511
+ * Identity is three-tiered:
512
+ * - anonymous: no consent needed — the server computes a daily-rotating hash,
513
+ * the client sends nothing identifying
514
+ * - consented: once the visitor grants analytics consent (the shop's consent
515
+ * banner, keyed by the existing `behio_visitor_id`), events carry that
516
+ * persistent first-party id — enabling returning-visitor metrics and the
517
+ * customer journey
518
+ * - customer: the backend links the id to the customer at checkout/login
519
+ *
520
+ * Captures: pageviews (load + SPA route changes), visibility-aware dwell time
521
+ * per page, click events on interactive elements, UTM + referrer on landing.
522
+ * Events are batched (flush on 20 events / 5 s / route change / pagehide) via
523
+ * keepalive fetch. Listens for the `behio:consent-changed` window event to
524
+ * pick up consent grants/revocations immediately.
525
+ */
526
+ declare function BehioAnalyticsTracker(): null;
527
+
507
528
  /** List all active bundles. */
508
529
  declare function useBundles(options?: {
509
530
  enabled?: boolean;
@@ -1028,4 +1049,4 @@ declare function useNotifyWhenAvailable(): _tanstack_react_query.UseMutationResu
1028
1049
  */
1029
1050
  declare function useBehioClient(): BehioStorefront;
1030
1051
 
1031
- export { ActivePromotion, BehioProvider, type BehioProviderProps, Bundle, Cart, Category, CategoryDetail, CheckoutInput, CookieConsent, CookieConsentInput, CrossSellItem, CurrencySwitcher, type CurrencySwitcherProps, type CurrencySwitcherRenderProps, CustomerAddress, CustomerProfile, FilterField, GiftCardBalance, OrderDetail, OrderListItem, Page, PageDetail, PaginatedResponse, ProductDetail, ProductLabel, ProductListItem, ProductReviewsResponse, ProductsQuery, QuoteRequest, RegisterInput, ReturnRequest, ShopInfo, ShopSeo, type StorageAdapter, StorefrontScripts, type StorefrontScriptsProps, SubmitQuoteInput, SubmitReturnInput, SubmitReviewInput, type UseAddressAutocompleteOptions, type UseAddressAutocompleteReturn, type UseAddressesOptions, type UseCartCountOptions, type UseCartOptions, type UseCategoriesOptions, type UseCategoryOptions, type UseCurrencyResult, type UseCustomerOptions, type UseFeaturedOptions, type UseFiltersOptions, type UseLabelsOptions, type UseOrderOptions, type UseOrdersOptions, type UsePageOptions, type UsePagesOptions, type UseProductOptions, type UseProductsOptions, type UseSearchOptions, type UseShopInfoOptions, type UseShopScriptsOptions, type UseShopSeoOptions, WishlistItem, cookieStorage, createMemoryStorage, detectStorage, localStorageAdapter, memoryStorage, useAddressAutocomplete, useAddresses, useAuth, useBehio, useBehioClient, useBundle, useBundles, useCart, useCartCount, useCategories, useCategory, useCheckout, useCookieConsent, useCrossSell, useCurrency, useCustomer, useFeatured, useFilters, useGiftCardBalance, useIsInWishlist, useLabels, useLookupReturnableOrder, useNotifyWhenAvailable, useOrder, useOrderAccess, useOrders, usePage, usePages, useProduct, useProductPromotions, useProductReviews, useProducts, useQuoteStatus, useReturnStatus, useSearch, useShopInfo, useShopScripts, useShopSeo, useSubmitQuote, useSubmitReturn, useSubmitReview, useWishlist };
1052
+ export { ActivePromotion, BehioAnalyticsTracker, BehioProvider, type BehioProviderProps, Bundle, Cart, Category, CategoryDetail, CheckoutInput, CookieConsent, CookieConsentInput, CrossSellItem, CurrencySwitcher, type CurrencySwitcherProps, type CurrencySwitcherRenderProps, CustomerAddress, CustomerProfile, FilterField, GiftCardBalance, OrderDetail, OrderListItem, Page, PageDetail, PaginatedResponse, ProductDetail, ProductLabel, ProductListItem, ProductReviewsResponse, ProductsQuery, QuoteRequest, RegisterInput, ReturnRequest, ShopInfo, ShopSeo, type StorageAdapter, StorefrontScripts, type StorefrontScriptsProps, SubmitQuoteInput, SubmitReturnInput, SubmitReviewInput, type UseAddressAutocompleteOptions, type UseAddressAutocompleteReturn, type UseAddressesOptions, type UseCartCountOptions, type UseCartOptions, type UseCategoriesOptions, type UseCategoryOptions, type UseCurrencyResult, type UseCustomerOptions, type UseFeaturedOptions, type UseFiltersOptions, type UseLabelsOptions, type UseOrderOptions, type UseOrdersOptions, type UsePageOptions, type UsePagesOptions, type UseProductOptions, type UseProductsOptions, type UseSearchOptions, type UseShopInfoOptions, type UseShopScriptsOptions, type UseShopSeoOptions, WishlistItem, cookieStorage, createMemoryStorage, detectStorage, localStorageAdapter, memoryStorage, useAddressAutocomplete, useAddresses, useAuth, useBehio, useBehioClient, useBundle, useBundles, useCart, useCartCount, useCategories, useCategory, useCheckout, useCookieConsent, useCrossSell, useCurrency, useCustomer, useFeatured, useFilters, useGiftCardBalance, useIsInWishlist, useLabels, useLookupReturnableOrder, useNotifyWhenAvailable, useOrder, useOrderAccess, useOrders, usePage, usePages, useProduct, useProductPromotions, useProductReviews, useProducts, useQuoteStatus, useReturnStatus, useSearch, useShopInfo, useShopScripts, useShopSeo, useSubmitQuote, useSubmitReturn, useSubmitReview, useWishlist };
package/dist/react.js CHANGED
@@ -1,10 +1,10 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
3
 
4
- var _chunkBFF5BKR2js = require('./chunk-BFF5BKR2.js');
4
+ var _chunkJIAOZ5YWjs = require('./chunk-JIAOZ5YW.js');
5
5
 
6
6
 
7
- var _chunkBF4YVFHXjs = require('./chunk-BF4YVFHX.js');
7
+ var _chunk3RI2QBQOjs = require('./chunk-3RI2QBQO.js');
8
8
 
9
9
  // src/react/provider.tsx
10
10
  var _react = require('react');
@@ -134,7 +134,7 @@ function BehioProvider({
134
134
  const [activeCurrency, setActiveCurrency] = _react.useState.call(void 0, resolveInitialCurrency);
135
135
  const clientRef = _react.useRef.call(void 0, null);
136
136
  if (!clientRef.current) {
137
- clientRef.current = new (0, _chunkBF4YVFHXjs.BehioStorefront)({
137
+ clientRef.current = new (0, _chunk3RI2QBQOjs.BehioStorefront)({
138
138
  apiKey,
139
139
  baseUrl,
140
140
  ...shopDomain ? { shopDomain } : {},
@@ -1274,6 +1274,221 @@ function StorefrontScripts({ visitorId: visitorIdProp } = {}) {
1274
1274
  return null;
1275
1275
  }
1276
1276
 
1277
+ // src/react/components/behio-analytics.tsx
1278
+
1279
+
1280
+ // src/react/hooks/use-behio-client.ts
1281
+ function useBehioClient() {
1282
+ return useBehio().client;
1283
+ }
1284
+
1285
+ // src/react/components/behio-analytics.tsx
1286
+ function BehioAnalyticsTracker() {
1287
+ const client = useBehioClient();
1288
+ _react.useEffect.call(void 0, () => {
1289
+ if (typeof window === "undefined") return;
1290
+ const w = window;
1291
+ if (w.__behioAnalytics) return;
1292
+ w.__behioAnalytics = true;
1293
+ const teardown = initTracker(client);
1294
+ return () => {
1295
+ w.__behioAnalytics = false;
1296
+ teardown();
1297
+ };
1298
+ }, [client]);
1299
+ return null;
1300
+ }
1301
+ var VISITOR_KEY2 = "behio_visitor_id";
1302
+ var FLUSH_MAX_EVENTS = 20;
1303
+ var FLUSH_INTERVAL_MS = 5e3;
1304
+ function initTracker(client) {
1305
+ const sessionId = getSessionId();
1306
+ let visitorId;
1307
+ let currentPath = window.location.pathname;
1308
+ let visibleSince = document.visibilityState === "visible" ? Date.now() : null;
1309
+ let dwellAccumMs = 0;
1310
+ const refreshIdentity = async () => {
1311
+ try {
1312
+ const stored = _nullishCoalesce(localStorage.getItem(VISITOR_KEY2), () => ( void 0));
1313
+ if (!stored) {
1314
+ visitorId = void 0;
1315
+ client.setAnalyticsVisitorId(null);
1316
+ return;
1317
+ }
1318
+ const { data } = await client.consent.get(stored);
1319
+ const granted = Boolean(_optionalChain([data, 'optionalAccess', _71 => _71.analytics]));
1320
+ visitorId = granted ? stored : void 0;
1321
+ client.setAnalyticsVisitorId(granted ? stored : null);
1322
+ } catch (e7) {
1323
+ visitorId = void 0;
1324
+ }
1325
+ };
1326
+ void refreshIdentity();
1327
+ const onConsentChanged = () => void refreshIdentity();
1328
+ window.addEventListener("behio:consent-changed", onConsentChanged);
1329
+ let queue = [];
1330
+ let flushTimer = null;
1331
+ const flush = () => {
1332
+ if (flushTimer) {
1333
+ clearTimeout(flushTimer);
1334
+ flushTimer = null;
1335
+ }
1336
+ if (queue.length === 0) return;
1337
+ const events = queue;
1338
+ queue = [];
1339
+ void client.sendAnalyticsEvents({ sessionId, ...visitorId ? { visitorId } : {}, events });
1340
+ };
1341
+ const enqueue = (event) => {
1342
+ queue.push(event);
1343
+ if (queue.length >= FLUSH_MAX_EVENTS) {
1344
+ flush();
1345
+ return;
1346
+ }
1347
+ if (!flushTimer) flushTimer = setTimeout(flush, FLUSH_INTERVAL_MS);
1348
+ };
1349
+ const landing = utmFromSearch(window.location.search);
1350
+ enqueue({
1351
+ type: "pageview",
1352
+ path: currentPath,
1353
+ referrer: document.referrer || void 0,
1354
+ ...landing,
1355
+ ts: Date.now()
1356
+ });
1357
+ const settleDwell = () => {
1358
+ if (visibleSince != null) {
1359
+ dwellAccumMs += Date.now() - visibleSince;
1360
+ visibleSince = document.visibilityState === "visible" ? Date.now() : null;
1361
+ }
1362
+ };
1363
+ const takeDwell = () => {
1364
+ settleDwell();
1365
+ const dwell = dwellAccumMs;
1366
+ dwellAccumMs = 0;
1367
+ return dwell;
1368
+ };
1369
+ const onRouteChange = () => {
1370
+ const nextPath = window.location.pathname;
1371
+ if (nextPath === currentPath) return;
1372
+ const dwellMs = takeDwell();
1373
+ if (dwellMs > 0) {
1374
+ enqueue({ type: "custom", name: "dwell", path: currentPath, dwellMs, ts: Date.now() });
1375
+ }
1376
+ currentPath = nextPath;
1377
+ visibleSince = document.visibilityState === "visible" ? Date.now() : null;
1378
+ enqueue({
1379
+ type: "pageview",
1380
+ path: currentPath,
1381
+ ...utmFromSearch(window.location.search),
1382
+ ts: Date.now()
1383
+ });
1384
+ flush();
1385
+ };
1386
+ const onVisibility = () => {
1387
+ if (document.visibilityState === "hidden") {
1388
+ settleDwell();
1389
+ visibleSince = null;
1390
+ } else if (visibleSince == null) {
1391
+ visibleSince = Date.now();
1392
+ }
1393
+ };
1394
+ const onPageHide = () => {
1395
+ const dwellMs = takeDwell();
1396
+ if (dwellMs > 0) {
1397
+ enqueue({ type: "custom", name: "dwell", path: currentPath, dwellMs, ts: Date.now() });
1398
+ }
1399
+ flush();
1400
+ };
1401
+ const onClick = (ev) => {
1402
+ const target = ev.target;
1403
+ const el = _optionalChain([target, 'optionalAccess', _72 => _72.closest, 'optionalCall', _73 => _73("a,button,[role=button],[data-behio-event]")]);
1404
+ if (!el) return;
1405
+ const explicit = _nullishCoalesce(el.getAttribute("data-behio-event"), () => ( void 0));
1406
+ const text = (_nullishCoalesce(el.textContent, () => ( ""))).trim().replace(/\s+/g, " ").slice(0, 80) || void 0;
1407
+ const hrefRaw = _nullishCoalesce(el.getAttribute("href"), () => ( void 0));
1408
+ let href;
1409
+ if (hrefRaw) {
1410
+ try {
1411
+ const u = new URL(hrefRaw, window.location.origin);
1412
+ href = u.origin === window.location.origin ? u.pathname : u.hostname;
1413
+ } catch (e8) {
1414
+ href = void 0;
1415
+ }
1416
+ }
1417
+ enqueue({
1418
+ type: "custom",
1419
+ name: explicit || "click",
1420
+ path: currentPath,
1421
+ ts: Date.now(),
1422
+ props: {
1423
+ tag: el.tagName.toLowerCase(),
1424
+ ...text ? { text } : {},
1425
+ ...href ? { href } : {}
1426
+ }
1427
+ });
1428
+ };
1429
+ const w = window;
1430
+ w.__behioEcommerceSink = (event, payload) => {
1431
+ if (event === "purchase") return;
1432
+ enqueue({
1433
+ type: "ecommerce",
1434
+ name: event,
1435
+ path: currentPath,
1436
+ ts: Date.now(),
1437
+ ...payload.value != null ? { value: payload.value } : {},
1438
+ ...payload.currency ? { currency: payload.currency } : {},
1439
+ ...Array.isArray(payload.items) && payload.items.length > 0 ? { props: { items: payload.items.length } } : {}
1440
+ });
1441
+ };
1442
+ const origPush = history.pushState.bind(history);
1443
+ const origReplace = history.replaceState.bind(history);
1444
+ history.pushState = (...args) => {
1445
+ origPush(...args);
1446
+ onRouteChange();
1447
+ };
1448
+ history.replaceState = (...args) => {
1449
+ origReplace(...args);
1450
+ onRouteChange();
1451
+ };
1452
+ window.addEventListener("popstate", onRouteChange);
1453
+ document.addEventListener("visibilitychange", onVisibility);
1454
+ window.addEventListener("pagehide", onPageHide);
1455
+ document.addEventListener("click", onClick, { capture: true, passive: true });
1456
+ return () => {
1457
+ flush();
1458
+ delete w.__behioEcommerceSink;
1459
+ history.pushState = origPush;
1460
+ history.replaceState = origReplace;
1461
+ window.removeEventListener("popstate", onRouteChange);
1462
+ document.removeEventListener("visibilitychange", onVisibility);
1463
+ window.removeEventListener("pagehide", onPageHide);
1464
+ document.removeEventListener("click", onClick, { capture: true });
1465
+ window.removeEventListener("behio:consent-changed", onConsentChanged);
1466
+ };
1467
+ }
1468
+ function getSessionId() {
1469
+ try {
1470
+ const existing = sessionStorage.getItem("behio.sid");
1471
+ if (existing) return existing;
1472
+ const sid = `s-${Math.random().toString(36).slice(2, 12)}${Date.now().toString(36)}`;
1473
+ sessionStorage.setItem("behio.sid", sid);
1474
+ return sid;
1475
+ } catch (e9) {
1476
+ return `s-${Math.random().toString(36).slice(2, 12)}`;
1477
+ }
1478
+ }
1479
+ function utmFromSearch(search) {
1480
+ try {
1481
+ const p = new URLSearchParams(search);
1482
+ return {
1483
+ utmSource: _nullishCoalesce(p.get("utm_source"), () => ( void 0)),
1484
+ utmMedium: _nullishCoalesce(p.get("utm_medium"), () => ( void 0)),
1485
+ utmCampaign: _nullishCoalesce(p.get("utm_campaign"), () => ( void 0))
1486
+ };
1487
+ } catch (e10) {
1488
+ return {};
1489
+ }
1490
+ }
1491
+
1277
1492
  // src/react/hooks/use-bundles.ts
1278
1493
 
1279
1494
  function useBundles(options) {
@@ -1281,8 +1496,8 @@ function useBundles(options) {
1281
1496
  return _reactquery.useQuery.call(void 0, {
1282
1497
  queryKey: ["behio", "bundles"],
1283
1498
  queryFn: () => unwrap(client.catalog.getBundles()),
1284
- enabled: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _71 => _71.enabled]), () => ( true)),
1285
- initialData: _optionalChain([options, 'optionalAccess', _72 => _72.initialData])
1499
+ enabled: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _74 => _74.enabled]), () => ( true)),
1500
+ initialData: _optionalChain([options, 'optionalAccess', _75 => _75.initialData])
1286
1501
  });
1287
1502
  }
1288
1503
  function useBundle(slug, options) {
@@ -1290,8 +1505,8 @@ function useBundle(slug, options) {
1290
1505
  return _reactquery.useQuery.call(void 0, {
1291
1506
  queryKey: ["behio", "bundle", slug],
1292
1507
  queryFn: () => unwrap(client.catalog.getBundle(slug)),
1293
- enabled: Boolean(slug) && (_nullishCoalesce(_optionalChain([options, 'optionalAccess', _73 => _73.enabled]), () => ( true))),
1294
- initialData: _optionalChain([options, 'optionalAccess', _74 => _74.initialData])
1508
+ enabled: Boolean(slug) && (_nullishCoalesce(_optionalChain([options, 'optionalAccess', _76 => _76.enabled]), () => ( true))),
1509
+ initialData: _optionalChain([options, 'optionalAccess', _77 => _77.initialData])
1295
1510
  });
1296
1511
  }
1297
1512
 
@@ -1302,8 +1517,8 @@ function useCrossSell(productSlug, options) {
1302
1517
  return _reactquery.useQuery.call(void 0, {
1303
1518
  queryKey: ["behio", "cross-sell", productSlug],
1304
1519
  queryFn: () => unwrap(client.catalog.getCrossSell(productSlug)),
1305
- enabled: Boolean(productSlug) && (_nullishCoalesce(_optionalChain([options, 'optionalAccess', _75 => _75.enabled]), () => ( true))),
1306
- initialData: _optionalChain([options, 'optionalAccess', _76 => _76.initialData])
1520
+ enabled: Boolean(productSlug) && (_nullishCoalesce(_optionalChain([options, 'optionalAccess', _78 => _78.enabled]), () => ( true))),
1521
+ initialData: _optionalChain([options, 'optionalAccess', _79 => _79.initialData])
1307
1522
  });
1308
1523
  }
1309
1524
 
@@ -1314,8 +1529,8 @@ function useProductPromotions(productSlug, options) {
1314
1529
  return _reactquery.useQuery.call(void 0, {
1315
1530
  queryKey: ["behio", "product-promotions", productSlug],
1316
1531
  queryFn: () => unwrap(client.catalog.getProductPromotions(productSlug)),
1317
- enabled: Boolean(productSlug) && (_nullishCoalesce(_optionalChain([options, 'optionalAccess', _77 => _77.enabled]), () => ( true))),
1318
- refetchInterval: _optionalChain([options, 'optionalAccess', _78 => _78.refetchIntervalMs])
1532
+ enabled: Boolean(productSlug) && (_nullishCoalesce(_optionalChain([options, 'optionalAccess', _80 => _80.enabled]), () => ( true))),
1533
+ refetchInterval: _optionalChain([options, 'optionalAccess', _81 => _81.refetchIntervalMs])
1319
1534
  });
1320
1535
  }
1321
1536
 
@@ -1323,11 +1538,11 @@ function useProductPromotions(productSlug, options) {
1323
1538
 
1324
1539
  function useGiftCardBalance(code, options) {
1325
1540
  const { client } = useBehio();
1326
- const trimmed = _optionalChain([code, 'optionalAccess', _79 => _79.trim, 'call', _80 => _80()]);
1541
+ const trimmed = _optionalChain([code, 'optionalAccess', _82 => _82.trim, 'call', _83 => _83()]);
1327
1542
  return _reactquery.useQuery.call(void 0, {
1328
1543
  queryKey: ["behio", "gift-card-balance", trimmed],
1329
1544
  queryFn: () => unwrap(client.catalog.checkGiftCard(trimmed)),
1330
- enabled: Boolean(trimmed && trimmed.length >= 6) && (_nullishCoalesce(_optionalChain([options, 'optionalAccess', _81 => _81.enabled]), () => ( true)))
1545
+ enabled: Boolean(trimmed && trimmed.length >= 6) && (_nullishCoalesce(_optionalChain([options, 'optionalAccess', _84 => _84.enabled]), () => ( true)))
1331
1546
  });
1332
1547
  }
1333
1548
 
@@ -1339,7 +1554,7 @@ function useWishlist(options) {
1339
1554
  const query = _reactquery.useQuery.call(void 0, {
1340
1555
  queryKey: ["behio", "wishlist"],
1341
1556
  queryFn: () => unwrap(client.wishlist.get()),
1342
- enabled: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _82 => _82.enabled]), () => ( true))
1557
+ enabled: _nullishCoalesce(_optionalChain([options, 'optionalAccess', _85 => _85.enabled]), () => ( true))
1343
1558
  });
1344
1559
  const addMutation = _reactquery.useMutation.call(void 0, {
1345
1560
  mutationFn: (productId) => unwrap(client.wishlist.add(productId)),
@@ -1371,9 +1586,9 @@ function useIsInWishlist(productId) {
1371
1586
  function useProductReviews(productId, options) {
1372
1587
  const { client } = useBehio();
1373
1588
  return _reactquery.useQuery.call(void 0, {
1374
- queryKey: ["behio", "reviews", productId, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _83 => _83.page]), () => ( 1))],
1375
- queryFn: () => unwrap(client.reviews.getProductReviews(productId, _optionalChain([options, 'optionalAccess', _84 => _84.page]), _optionalChain([options, 'optionalAccess', _85 => _85.limit]))),
1376
- enabled: Boolean(productId) && (_nullishCoalesce(_optionalChain([options, 'optionalAccess', _86 => _86.enabled]), () => ( true)))
1589
+ queryKey: ["behio", "reviews", productId, _nullishCoalesce(_optionalChain([options, 'optionalAccess', _86 => _86.page]), () => ( 1))],
1590
+ queryFn: () => unwrap(client.reviews.getProductReviews(productId, _optionalChain([options, 'optionalAccess', _87 => _87.page]), _optionalChain([options, 'optionalAccess', _88 => _88.limit]))),
1591
+ enabled: Boolean(productId) && (_nullishCoalesce(_optionalChain([options, 'optionalAccess', _89 => _89.enabled]), () => ( true)))
1377
1592
  });
1378
1593
  }
1379
1594
  function useSubmitReview() {
@@ -1434,10 +1649,6 @@ function useNotifyWhenAvailable() {
1434
1649
  });
1435
1650
  }
1436
1651
 
1437
- // src/react/hooks/use-behio-client.ts
1438
- function useBehioClient() {
1439
- return useBehio().client;
1440
- }
1441
1652
 
1442
1653
 
1443
1654
 
@@ -1491,4 +1702,4 @@ function useBehioClient() {
1491
1702
 
1492
1703
 
1493
1704
 
1494
- exports.BehioProvider = BehioProvider; exports.CurrencySwitcher = CurrencySwitcher; exports.StorefrontScripts = StorefrontScripts; exports.cookieStorage = cookieStorage; exports.createMemoryStorage = createMemoryStorage; exports.detectStorage = detectStorage; exports.formatPrice = _chunkBFF5BKR2js.formatPrice; exports.localStorageAdapter = localStorageAdapter; exports.memoryStorage = memoryStorage; exports.trackEcommerceEvent = _chunkBFF5BKR2js.trackEcommerceEvent; exports.useAddressAutocomplete = useAddressAutocomplete; exports.useAddresses = useAddresses; exports.useAuth = useAuth; exports.useBehio = useBehio; exports.useBehioClient = useBehioClient; exports.useBundle = useBundle; exports.useBundles = useBundles; exports.useCart = useCart; exports.useCartCount = useCartCount; exports.useCategories = useCategories; exports.useCategory = useCategory; exports.useCheckout = useCheckout; exports.useCookieConsent = useCookieConsent; exports.useCrossSell = useCrossSell; exports.useCurrency = useCurrency; exports.useCustomer = useCustomer; exports.useFeatured = useFeatured; exports.useFilters = useFilters; exports.useGiftCardBalance = useGiftCardBalance; exports.useIsInWishlist = useIsInWishlist; exports.useLabels = useLabels; exports.useLookupReturnableOrder = useLookupReturnableOrder; exports.useNotifyWhenAvailable = useNotifyWhenAvailable; exports.useOrder = useOrder; exports.useOrderAccess = useOrderAccess; exports.useOrders = useOrders; exports.usePage = usePage; exports.usePages = usePages; exports.useProduct = useProduct; exports.useProductPromotions = useProductPromotions; exports.useProductReviews = useProductReviews; exports.useProducts = useProducts; exports.useQuoteStatus = useQuoteStatus; exports.useReturnStatus = useReturnStatus; exports.useSearch = useSearch; exports.useShopInfo = useShopInfo; exports.useShopScripts = useShopScripts; exports.useShopSeo = useShopSeo; exports.useSubmitQuote = useSubmitQuote; exports.useSubmitReturn = useSubmitReturn; exports.useSubmitReview = useSubmitReview; exports.useWishlist = useWishlist;
1705
+ exports.BehioAnalyticsTracker = BehioAnalyticsTracker; exports.BehioProvider = BehioProvider; exports.CurrencySwitcher = CurrencySwitcher; exports.StorefrontScripts = StorefrontScripts; exports.cookieStorage = cookieStorage; exports.createMemoryStorage = createMemoryStorage; exports.detectStorage = detectStorage; exports.formatPrice = _chunkJIAOZ5YWjs.formatPrice; exports.localStorageAdapter = localStorageAdapter; exports.memoryStorage = memoryStorage; exports.trackEcommerceEvent = _chunkJIAOZ5YWjs.trackEcommerceEvent; exports.useAddressAutocomplete = useAddressAutocomplete; exports.useAddresses = useAddresses; exports.useAuth = useAuth; exports.useBehio = useBehio; exports.useBehioClient = useBehioClient; exports.useBundle = useBundle; exports.useBundles = useBundles; exports.useCart = useCart; exports.useCartCount = useCartCount; exports.useCategories = useCategories; exports.useCategory = useCategory; exports.useCheckout = useCheckout; exports.useCookieConsent = useCookieConsent; exports.useCrossSell = useCrossSell; exports.useCurrency = useCurrency; exports.useCustomer = useCustomer; exports.useFeatured = useFeatured; exports.useFilters = useFilters; exports.useGiftCardBalance = useGiftCardBalance; exports.useIsInWishlist = useIsInWishlist; exports.useLabels = useLabels; exports.useLookupReturnableOrder = useLookupReturnableOrder; exports.useNotifyWhenAvailable = useNotifyWhenAvailable; exports.useOrder = useOrder; exports.useOrderAccess = useOrderAccess; exports.useOrders = useOrders; exports.usePage = usePage; exports.usePages = usePages; exports.useProduct = useProduct; exports.useProductPromotions = useProductPromotions; exports.useProductReviews = useProductReviews; exports.useProducts = useProducts; exports.useQuoteStatus = useQuoteStatus; exports.useReturnStatus = useReturnStatus; exports.useSearch = useSearch; exports.useShopInfo = useShopInfo; exports.useShopScripts = useShopScripts; exports.useShopSeo = useShopSeo; exports.useSubmitQuote = useSubmitQuote; exports.useSubmitReturn = useSubmitReturn; exports.useSubmitReview = useSubmitReview; exports.useWishlist = useWishlist;
package/dist/react.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  formatPrice,
3
3
  trackEcommerceEvent
4
- } from "./chunk-AN3QTDNM.mjs";
4
+ } from "./chunk-ZOZAJG6T.mjs";
5
5
  import {
6
6
  BehioStorefront
7
- } from "./chunk-PZED7VMQ.mjs";
7
+ } from "./chunk-2CD4CPEV.mjs";
8
8
 
9
9
  // src/react/provider.tsx
10
10
  import { useRef, useEffect, useMemo, useState, useCallback } from "react";
@@ -1274,6 +1274,221 @@ function StorefrontScripts({ visitorId: visitorIdProp } = {}) {
1274
1274
  return null;
1275
1275
  }
1276
1276
 
1277
+ // src/react/components/behio-analytics.tsx
1278
+ import { useEffect as useEffect5 } from "react";
1279
+
1280
+ // src/react/hooks/use-behio-client.ts
1281
+ function useBehioClient() {
1282
+ return useBehio().client;
1283
+ }
1284
+
1285
+ // src/react/components/behio-analytics.tsx
1286
+ function BehioAnalyticsTracker() {
1287
+ const client = useBehioClient();
1288
+ useEffect5(() => {
1289
+ if (typeof window === "undefined") return;
1290
+ const w = window;
1291
+ if (w.__behioAnalytics) return;
1292
+ w.__behioAnalytics = true;
1293
+ const teardown = initTracker(client);
1294
+ return () => {
1295
+ w.__behioAnalytics = false;
1296
+ teardown();
1297
+ };
1298
+ }, [client]);
1299
+ return null;
1300
+ }
1301
+ var VISITOR_KEY2 = "behio_visitor_id";
1302
+ var FLUSH_MAX_EVENTS = 20;
1303
+ var FLUSH_INTERVAL_MS = 5e3;
1304
+ function initTracker(client) {
1305
+ const sessionId = getSessionId();
1306
+ let visitorId;
1307
+ let currentPath = window.location.pathname;
1308
+ let visibleSince = document.visibilityState === "visible" ? Date.now() : null;
1309
+ let dwellAccumMs = 0;
1310
+ const refreshIdentity = async () => {
1311
+ try {
1312
+ const stored = localStorage.getItem(VISITOR_KEY2) ?? void 0;
1313
+ if (!stored) {
1314
+ visitorId = void 0;
1315
+ client.setAnalyticsVisitorId(null);
1316
+ return;
1317
+ }
1318
+ const { data } = await client.consent.get(stored);
1319
+ const granted = Boolean(data?.analytics);
1320
+ visitorId = granted ? stored : void 0;
1321
+ client.setAnalyticsVisitorId(granted ? stored : null);
1322
+ } catch {
1323
+ visitorId = void 0;
1324
+ }
1325
+ };
1326
+ void refreshIdentity();
1327
+ const onConsentChanged = () => void refreshIdentity();
1328
+ window.addEventListener("behio:consent-changed", onConsentChanged);
1329
+ let queue = [];
1330
+ let flushTimer = null;
1331
+ const flush = () => {
1332
+ if (flushTimer) {
1333
+ clearTimeout(flushTimer);
1334
+ flushTimer = null;
1335
+ }
1336
+ if (queue.length === 0) return;
1337
+ const events = queue;
1338
+ queue = [];
1339
+ void client.sendAnalyticsEvents({ sessionId, ...visitorId ? { visitorId } : {}, events });
1340
+ };
1341
+ const enqueue = (event) => {
1342
+ queue.push(event);
1343
+ if (queue.length >= FLUSH_MAX_EVENTS) {
1344
+ flush();
1345
+ return;
1346
+ }
1347
+ if (!flushTimer) flushTimer = setTimeout(flush, FLUSH_INTERVAL_MS);
1348
+ };
1349
+ const landing = utmFromSearch(window.location.search);
1350
+ enqueue({
1351
+ type: "pageview",
1352
+ path: currentPath,
1353
+ referrer: document.referrer || void 0,
1354
+ ...landing,
1355
+ ts: Date.now()
1356
+ });
1357
+ const settleDwell = () => {
1358
+ if (visibleSince != null) {
1359
+ dwellAccumMs += Date.now() - visibleSince;
1360
+ visibleSince = document.visibilityState === "visible" ? Date.now() : null;
1361
+ }
1362
+ };
1363
+ const takeDwell = () => {
1364
+ settleDwell();
1365
+ const dwell = dwellAccumMs;
1366
+ dwellAccumMs = 0;
1367
+ return dwell;
1368
+ };
1369
+ const onRouteChange = () => {
1370
+ const nextPath = window.location.pathname;
1371
+ if (nextPath === currentPath) return;
1372
+ const dwellMs = takeDwell();
1373
+ if (dwellMs > 0) {
1374
+ enqueue({ type: "custom", name: "dwell", path: currentPath, dwellMs, ts: Date.now() });
1375
+ }
1376
+ currentPath = nextPath;
1377
+ visibleSince = document.visibilityState === "visible" ? Date.now() : null;
1378
+ enqueue({
1379
+ type: "pageview",
1380
+ path: currentPath,
1381
+ ...utmFromSearch(window.location.search),
1382
+ ts: Date.now()
1383
+ });
1384
+ flush();
1385
+ };
1386
+ const onVisibility = () => {
1387
+ if (document.visibilityState === "hidden") {
1388
+ settleDwell();
1389
+ visibleSince = null;
1390
+ } else if (visibleSince == null) {
1391
+ visibleSince = Date.now();
1392
+ }
1393
+ };
1394
+ const onPageHide = () => {
1395
+ const dwellMs = takeDwell();
1396
+ if (dwellMs > 0) {
1397
+ enqueue({ type: "custom", name: "dwell", path: currentPath, dwellMs, ts: Date.now() });
1398
+ }
1399
+ flush();
1400
+ };
1401
+ const onClick = (ev) => {
1402
+ const target = ev.target;
1403
+ const el = target?.closest?.("a,button,[role=button],[data-behio-event]");
1404
+ if (!el) return;
1405
+ const explicit = el.getAttribute("data-behio-event") ?? void 0;
1406
+ const text = (el.textContent ?? "").trim().replace(/\s+/g, " ").slice(0, 80) || void 0;
1407
+ const hrefRaw = el.getAttribute("href") ?? void 0;
1408
+ let href;
1409
+ if (hrefRaw) {
1410
+ try {
1411
+ const u = new URL(hrefRaw, window.location.origin);
1412
+ href = u.origin === window.location.origin ? u.pathname : u.hostname;
1413
+ } catch {
1414
+ href = void 0;
1415
+ }
1416
+ }
1417
+ enqueue({
1418
+ type: "custom",
1419
+ name: explicit || "click",
1420
+ path: currentPath,
1421
+ ts: Date.now(),
1422
+ props: {
1423
+ tag: el.tagName.toLowerCase(),
1424
+ ...text ? { text } : {},
1425
+ ...href ? { href } : {}
1426
+ }
1427
+ });
1428
+ };
1429
+ const w = window;
1430
+ w.__behioEcommerceSink = (event, payload) => {
1431
+ if (event === "purchase") return;
1432
+ enqueue({
1433
+ type: "ecommerce",
1434
+ name: event,
1435
+ path: currentPath,
1436
+ ts: Date.now(),
1437
+ ...payload.value != null ? { value: payload.value } : {},
1438
+ ...payload.currency ? { currency: payload.currency } : {},
1439
+ ...Array.isArray(payload.items) && payload.items.length > 0 ? { props: { items: payload.items.length } } : {}
1440
+ });
1441
+ };
1442
+ const origPush = history.pushState.bind(history);
1443
+ const origReplace = history.replaceState.bind(history);
1444
+ history.pushState = (...args) => {
1445
+ origPush(...args);
1446
+ onRouteChange();
1447
+ };
1448
+ history.replaceState = (...args) => {
1449
+ origReplace(...args);
1450
+ onRouteChange();
1451
+ };
1452
+ window.addEventListener("popstate", onRouteChange);
1453
+ document.addEventListener("visibilitychange", onVisibility);
1454
+ window.addEventListener("pagehide", onPageHide);
1455
+ document.addEventListener("click", onClick, { capture: true, passive: true });
1456
+ return () => {
1457
+ flush();
1458
+ delete w.__behioEcommerceSink;
1459
+ history.pushState = origPush;
1460
+ history.replaceState = origReplace;
1461
+ window.removeEventListener("popstate", onRouteChange);
1462
+ document.removeEventListener("visibilitychange", onVisibility);
1463
+ window.removeEventListener("pagehide", onPageHide);
1464
+ document.removeEventListener("click", onClick, { capture: true });
1465
+ window.removeEventListener("behio:consent-changed", onConsentChanged);
1466
+ };
1467
+ }
1468
+ function getSessionId() {
1469
+ try {
1470
+ const existing = sessionStorage.getItem("behio.sid");
1471
+ if (existing) return existing;
1472
+ const sid = `s-${Math.random().toString(36).slice(2, 12)}${Date.now().toString(36)}`;
1473
+ sessionStorage.setItem("behio.sid", sid);
1474
+ return sid;
1475
+ } catch {
1476
+ return `s-${Math.random().toString(36).slice(2, 12)}`;
1477
+ }
1478
+ }
1479
+ function utmFromSearch(search) {
1480
+ try {
1481
+ const p = new URLSearchParams(search);
1482
+ return {
1483
+ utmSource: p.get("utm_source") ?? void 0,
1484
+ utmMedium: p.get("utm_medium") ?? void 0,
1485
+ utmCampaign: p.get("utm_campaign") ?? void 0
1486
+ };
1487
+ } catch {
1488
+ return {};
1489
+ }
1490
+ }
1491
+
1277
1492
  // src/react/hooks/use-bundles.ts
1278
1493
  import { useQuery as useQuery19 } from "@tanstack/react-query";
1279
1494
  function useBundles(options) {
@@ -1433,12 +1648,8 @@ function useNotifyWhenAvailable() {
1433
1648
  mutationFn: ({ productId, email }) => unwrap(client.catalog.notifyWhenAvailable(productId, email))
1434
1649
  });
1435
1650
  }
1436
-
1437
- // src/react/hooks/use-behio-client.ts
1438
- function useBehioClient() {
1439
- return useBehio().client;
1440
- }
1441
1651
  export {
1652
+ BehioAnalyticsTracker,
1442
1653
  BehioProvider,
1443
1654
  CurrencySwitcher,
1444
1655
  StorefrontScripts,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@behio/storefront-sdk",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "description": "TypeScript SDK for Behio Headless E-Shop — core client + React hooks",
5
5
  "author": "Behio",
6
6
  "license": "MIT",