@replohq/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. package/LICENSE +11 -0
  2. package/_vendor/replo-utils/lib/crypto.d.ts +30 -0
  3. package/_vendor/replo-utils/lib/errors.d.ts +83 -0
  4. package/_vendor/replo-utils/lib/json.d.ts +6 -0
  5. package/_vendor/replo-utils/lib/json.mjs +43 -0
  6. package/_vendor/replo-utils/lib/misc.d.ts +145 -0
  7. package/_vendor/replo-utils/lib/object.d.ts +31 -0
  8. package/_vendor/schemas/errors.d.ts +459 -0
  9. package/_vendor/schemas/generated/consent.d.ts +55 -0
  10. package/_vendor/schemas/generated/errors.d.ts +61 -0
  11. package/_vendor/schemas/loaderKeys.d.ts +1 -0
  12. package/_vendor/schemas/loaderKeys.mjs +27 -0
  13. package/_vendor/schemas/money.d.ts +60 -0
  14. package/_vendor/schemas/money.mjs +2051 -0
  15. package/analytics/analytics-provider.d.ts +16 -0
  16. package/analytics/analytics-provider.js +113 -0
  17. package/analytics/analytics-provider.js.map +7 -0
  18. package/analytics/analytics-sink.d.ts +26 -0
  19. package/analytics/analytics-sink.js +1 -0
  20. package/analytics/analytics-sink.js.map +7 -0
  21. package/analytics/get-analytics-sinks.d.ts +27 -0
  22. package/analytics/get-analytics-sinks.js +52 -0
  23. package/analytics/get-analytics-sinks.js.map +7 -0
  24. package/analytics/hooks/use-product-viewed-analytics.d.ts +23 -0
  25. package/analytics/hooks/use-product-viewed-analytics.js +34 -0
  26. package/analytics/hooks/use-product-viewed-analytics.js.map +7 -0
  27. package/analytics/replo-first-party-pixel.d.ts +12 -0
  28. package/analytics/replo-first-party-pixel.js +31 -0
  29. package/analytics/replo-first-party-pixel.js.map +7 -0
  30. package/analytics/replo-pixel-script.d.ts +13 -0
  31. package/analytics/replo-pixel-script.js +30 -0
  32. package/analytics/replo-pixel-script.js.map +7 -0
  33. package/analytics/sinks/ga4-sink.d.ts +15 -0
  34. package/analytics/sinks/ga4-sink.js +60 -0
  35. package/analytics/sinks/ga4-sink.js.map +7 -0
  36. package/analytics/sinks/meta-sink.d.ts +14 -0
  37. package/analytics/sinks/meta-sink.js +56 -0
  38. package/analytics/sinks/meta-sink.js.map +7 -0
  39. package/analytics/sinks/pinterest-sink.d.ts +14 -0
  40. package/analytics/sinks/pinterest-sink.js +76 -0
  41. package/analytics/sinks/pinterest-sink.js.map +7 -0
  42. package/analytics/sinks/reddit-sink.d.ts +14 -0
  43. package/analytics/sinks/reddit-sink.js +80 -0
  44. package/analytics/sinks/reddit-sink.js.map +7 -0
  45. package/analytics/sinks/replo-sink.d.ts +14 -0
  46. package/analytics/sinks/replo-sink.js +57 -0
  47. package/analytics/sinks/replo-sink.js.map +7 -0
  48. package/analytics/sinks/snapchat-sink.d.ts +14 -0
  49. package/analytics/sinks/snapchat-sink.js +67 -0
  50. package/analytics/sinks/snapchat-sink.js.map +7 -0
  51. package/analytics/sinks/tiktok-sink.d.ts +14 -0
  52. package/analytics/sinks/tiktok-sink.js +79 -0
  53. package/analytics/sinks/tiktok-sink.js.map +7 -0
  54. package/analytics/sinks/window-sink.d.ts +18 -0
  55. package/analytics/sinks/window-sink.js +46 -0
  56. package/analytics/sinks/window-sink.js.map +7 -0
  57. package/analytics/utils/analytics-utils.d.ts +7 -0
  58. package/analytics/utils/analytics-utils.js +130 -0
  59. package/analytics/utils/analytics-utils.js.map +7 -0
  60. package/analytics/utils/navigation-tracker.d.ts +16 -0
  61. package/analytics/utils/navigation-tracker.js +44 -0
  62. package/analytics/utils/navigation-tracker.js.map +7 -0
  63. package/analytics/utils/shopify-funnel-gate.d.ts +8 -0
  64. package/analytics/utils/shopify-funnel-gate.js +22 -0
  65. package/analytics/utils/shopify-funnel-gate.js.map +7 -0
  66. package/cart/buy-now-action.d.ts +21 -0
  67. package/cart/buy-now-action.js +104 -0
  68. package/cart/buy-now-action.js.map +7 -0
  69. package/cart/cart-actions.d.ts +63 -0
  70. package/cart/cart-actions.js +90 -0
  71. package/cart/cart-actions.js.map +7 -0
  72. package/cart/cart-loader.d.ts +9 -0
  73. package/cart/cart-loader.js +11 -0
  74. package/cart/cart-loader.js.map +7 -0
  75. package/cart/cart-provider.d.ts +85 -0
  76. package/cart/cart-provider.js +372 -0
  77. package/cart/cart-provider.js.map +7 -0
  78. package/cart/cart-schema.d.ts +74 -0
  79. package/cart/cart-schema.js +69 -0
  80. package/cart/cart-schema.js.map +7 -0
  81. package/cart/cart-types.d.ts +132 -0
  82. package/cart/cart-types.js +8 -0
  83. package/cart/cart-types.js.map +7 -0
  84. package/cart/gateways/cart-constants.d.ts +1 -0
  85. package/cart/gateways/cart-constants.js +5 -0
  86. package/cart/gateways/cart-constants.js.map +7 -0
  87. package/cart/gateways/cart-gateway.d.ts +10 -0
  88. package/cart/gateways/cart-gateway.js +19 -0
  89. package/cart/gateways/cart-gateway.js.map +7 -0
  90. package/cart/gateways/cookie-cart-gateway.d.ts +28 -0
  91. package/cart/gateways/cookie-cart-gateway.js +109 -0
  92. package/cart/gateways/cookie-cart-gateway.js.map +7 -0
  93. package/cart/gateways/default-cart-gateway.d.ts +19 -0
  94. package/cart/gateways/default-cart-gateway.js +30 -0
  95. package/cart/gateways/default-cart-gateway.js.map +7 -0
  96. package/cart/gateways/resolver-cart-gateway.d.ts +2 -0
  97. package/cart/gateways/resolver-cart-gateway.js +109 -0
  98. package/cart/gateways/resolver-cart-gateway.js.map +7 -0
  99. package/cart/gateways/stripe-cart-gateway.d.ts +19 -0
  100. package/cart/gateways/stripe-cart-gateway.js +28 -0
  101. package/cart/gateways/stripe-cart-gateway.js.map +7 -0
  102. package/cart/hooks/use-add-to-cart.d.ts +63 -0
  103. package/cart/hooks/use-add-to-cart.js +124 -0
  104. package/cart/hooks/use-add-to-cart.js.map +7 -0
  105. package/cart/hooks/use-buy-now.d.ts +49 -0
  106. package/cart/hooks/use-buy-now.js +62 -0
  107. package/cart/hooks/use-buy-now.js.map +7 -0
  108. package/cart/utils/cart-utils.d.ts +43 -0
  109. package/cart/utils/cart-utils.js +46 -0
  110. package/cart/utils/cart-utils.js.map +7 -0
  111. package/cart/utils/cookie-cart-persistence.d.ts +55 -0
  112. package/cart/utils/cookie-cart-persistence.js +166 -0
  113. package/cart/utils/cookie-cart-persistence.js.map +7 -0
  114. package/cart/utils/variant-to-cart-line.d.ts +74 -0
  115. package/cart/utils/variant-to-cart-line.js +162 -0
  116. package/cart/utils/variant-to-cart-line.js.map +7 -0
  117. package/chunk-UJCSKKID.mjs +27 -0
  118. package/consent/consent-action.d.ts +9 -0
  119. package/consent/consent-action.js +25 -0
  120. package/consent/consent-action.js.map +7 -0
  121. package/consent/consent-actions.d.ts +28 -0
  122. package/consent/consent-actions.js +36 -0
  123. package/consent/consent-actions.js.map +7 -0
  124. package/consent/consent-store.d.ts +69 -0
  125. package/consent/consent-store.js +194 -0
  126. package/consent/consent-store.js.map +7 -0
  127. package/consent/cookie.d.ts +36 -0
  128. package/consent/cookie.js +82 -0
  129. package/consent/cookie.js.map +7 -0
  130. package/consent/replo-scripts.d.ts +23 -0
  131. package/consent/replo-scripts.js +102 -0
  132. package/consent/replo-scripts.js.map +7 -0
  133. package/consent/script-registration-store.d.ts +25 -0
  134. package/consent/script-registration-store.js +61 -0
  135. package/consent/script-registration-store.js.map +7 -0
  136. package/consent/script-snippets.d.ts +24 -0
  137. package/consent/script-snippets.js +122 -0
  138. package/consent/script-snippets.js.map +7 -0
  139. package/consent/types.d.ts +34 -0
  140. package/consent/types.js +1 -0
  141. package/consent/types.js.map +7 -0
  142. package/consent/window-api.d.ts +41 -0
  143. package/consent/window-api.js +73 -0
  144. package/consent/window-api.js.map +7 -0
  145. package/env.d.ts +9 -0
  146. package/env.js +42 -0
  147. package/env.js.map +7 -0
  148. package/gateways/canopy-api.d.ts +83 -0
  149. package/gateways/canopy-api.js +197 -0
  150. package/gateways/canopy-api.js.map +7 -0
  151. package/hooks/use-client-value.d.ts +10 -0
  152. package/hooks/use-client-value.js +12 -0
  153. package/hooks/use-client-value.js.map +7 -0
  154. package/hooks/use-formatted-price.d.ts +15 -0
  155. package/hooks/use-formatted-price.js +20 -0
  156. package/hooks/use-formatted-price.js.map +7 -0
  157. package/lib/canopy-error.d.ts +25 -0
  158. package/lib/canopy-error.js +24 -0
  159. package/lib/canopy-error.js.map +7 -0
  160. package/lib/get-query-client.d.ts +2 -0
  161. package/lib/get-query-client.js +34 -0
  162. package/lib/get-query-client.js.map +7 -0
  163. package/lib/integration-utils.d.ts +2 -0
  164. package/lib/integration-utils.js +9 -0
  165. package/lib/integration-utils.js.map +7 -0
  166. package/lib/shopify-utils.d.ts +10 -0
  167. package/lib/shopify-utils.js +7 -0
  168. package/lib/shopify-utils.js.map +7 -0
  169. package/lib/url-utils.d.ts +4 -0
  170. package/lib/url-utils.js +8 -0
  171. package/lib/url-utils.js.map +7 -0
  172. package/loaders/collection-loader.d.ts +11 -0
  173. package/loaders/collection-loader.js +55 -0
  174. package/loaders/collection-loader.js.map +7 -0
  175. package/loaders/collection-products-loader.d.ts +12 -0
  176. package/loaders/collection-products-loader.js +58 -0
  177. package/loaders/collection-products-loader.js.map +7 -0
  178. package/loaders/contentful-entries-loader.d.ts +17 -0
  179. package/loaders/contentful-entries-loader.js +78 -0
  180. package/loaders/contentful-entries-loader.js.map +7 -0
  181. package/loaders/contentful-entry-loader.d.ts +14 -0
  182. package/loaders/contentful-entry-loader.js +60 -0
  183. package/loaders/contentful-entry-loader.js.map +7 -0
  184. package/loaders/invoke-loader-action.d.ts +11 -0
  185. package/loaders/invoke-loader-action.js +14 -0
  186. package/loaders/invoke-loader-action.js.map +7 -0
  187. package/loaders/invoke-loader-server.d.ts +18 -0
  188. package/loaders/invoke-loader-server.js +40 -0
  189. package/loaders/invoke-loader-server.js.map +7 -0
  190. package/loaders/invoke-loader.d.ts +16 -0
  191. package/loaders/invoke-loader.js +37 -0
  192. package/loaders/invoke-loader.js.map +7 -0
  193. package/loaders/levanta-product-loader.d.ts +11 -0
  194. package/loaders/levanta-product-loader.js +53 -0
  195. package/loaders/levanta-product-loader.js.map +7 -0
  196. package/loaders/loader-error-boundary.d.ts +25 -0
  197. package/loaders/loader-error-boundary.js +24 -0
  198. package/loaders/loader-error-boundary.js.map +7 -0
  199. package/loaders/loader-keys.d.ts +34 -0
  200. package/loaders/loader-keys.js +26 -0
  201. package/loaders/loader-keys.js.map +7 -0
  202. package/loaders/loader-schemas.d.ts +946 -0
  203. package/loaders/loader-schemas.js +353 -0
  204. package/loaders/loader-schemas.js.map +7 -0
  205. package/loaders/metaobject-loader.d.ts +12 -0
  206. package/loaders/metaobject-loader.js +54 -0
  207. package/loaders/metaobject-loader.js.map +7 -0
  208. package/loaders/metaobjects-loader.d.ts +14 -0
  209. package/loaders/metaobjects-loader.js +60 -0
  210. package/loaders/metaobjects-loader.js.map +7 -0
  211. package/loaders/okendo-review-aggregate-loader.d.ts +17 -0
  212. package/loaders/okendo-review-aggregate-loader.js +56 -0
  213. package/loaders/okendo-review-aggregate-loader.js.map +7 -0
  214. package/loaders/okendo-reviews-loader.d.ts +23 -0
  215. package/loaders/okendo-reviews-loader.js +54 -0
  216. package/loaders/okendo-reviews-loader.js.map +7 -0
  217. package/loaders/prefetch-loaders.d.ts +33 -0
  218. package/loaders/prefetch-loaders.js +46 -0
  219. package/loaders/prefetch-loaders.js.map +7 -0
  220. package/loaders/preview-placeholder.d.ts +25 -0
  221. package/loaders/preview-placeholder.js +222 -0
  222. package/loaders/preview-placeholder.js.map +7 -0
  223. package/loaders/product-loader-args.d.ts +21 -0
  224. package/loaders/product-loader-args.js +17 -0
  225. package/loaders/product-loader-args.js.map +7 -0
  226. package/loaders/product-loader.d.ts +10 -0
  227. package/loaders/product-loader.js +52 -0
  228. package/loaders/product-loader.js.map +7 -0
  229. package/loaders/rebuy-recommendations-loader.d.ts +165 -0
  230. package/loaders/rebuy-recommendations-loader.js +57 -0
  231. package/loaders/rebuy-recommendations-loader.js.map +7 -0
  232. package/loaders/reviews-io-review-aggregate-loader.d.ts +12 -0
  233. package/loaders/reviews-io-review-aggregate-loader.js +43 -0
  234. package/loaders/reviews-io-review-aggregate-loader.js.map +7 -0
  235. package/loaders/reviews-io-reviews-loader.d.ts +14 -0
  236. package/loaders/reviews-io-reviews-loader.js +65 -0
  237. package/loaders/reviews-io-reviews-loader.js.map +7 -0
  238. package/loaders/smile-earning-rules-loader.d.ts +19 -0
  239. package/loaders/smile-earning-rules-loader.js +44 -0
  240. package/loaders/smile-earning-rules-loader.js.map +7 -0
  241. package/loaders/smile-rewards-loader.d.ts +19 -0
  242. package/loaders/smile-rewards-loader.js +44 -0
  243. package/loaders/smile-rewards-loader.js.map +7 -0
  244. package/loaders/smile-vip-tiers-loader.d.ts +18 -0
  245. package/loaders/smile-vip-tiers-loader.js +43 -0
  246. package/loaders/smile-vip-tiers-loader.js.map +7 -0
  247. package/loaders/statsig-experiment-loader.d.ts +20 -0
  248. package/loaders/statsig-experiment-loader.js +81 -0
  249. package/loaders/statsig-experiment-loader.js.map +7 -0
  250. package/loaders/yotpo-review-aggregate-loader.d.ts +12 -0
  251. package/loaders/yotpo-review-aggregate-loader.js +50 -0
  252. package/loaders/yotpo-review-aggregate-loader.js.map +7 -0
  253. package/loaders/yotpo-reviews-loader.d.ts +14 -0
  254. package/loaders/yotpo-reviews-loader.js +65 -0
  255. package/loaders/yotpo-reviews-loader.js.map +7 -0
  256. package/money.d.ts +9 -0
  257. package/money.js +13 -0
  258. package/money.js.map +7 -0
  259. package/next/config.d.ts +4 -0
  260. package/next/config.js +91 -0
  261. package/next/config.js.map +7 -0
  262. package/next/image-loader.d.ts +2 -0
  263. package/next/image-loader.js +52 -0
  264. package/next/image-loader.js.map +7 -0
  265. package/next/open-next.d.ts +2 -0
  266. package/next/open-next.js +24 -0
  267. package/next/open-next.js.map +7 -0
  268. package/orders/order-status-schema.d.ts +161 -0
  269. package/orders/order-status-schema.js +83 -0
  270. package/orders/order-status-schema.js.map +7 -0
  271. package/orders/order-status.d.ts +11 -0
  272. package/orders/order-status.js +41 -0
  273. package/orders/order-status.js.map +7 -0
  274. package/package.json +216 -0
  275. package/providers/query-provider.d.ts +1 -0
  276. package/providers/query-provider.js +12 -0
  277. package/providers/query-provider.js.map +7 -0
  278. package/providers/replo-provider.d.ts +1 -0
  279. package/providers/replo-provider.js +22 -0
  280. package/providers/replo-provider.js.map +7 -0
@@ -0,0 +1,16 @@
1
+ import type React from "react";
2
+ import type { CheckoutProvider } from "../lib/integration-utils";
3
+ import type { AnalyticsSink } from "./analytics-sink";
4
+ export declare function AnalyticsProvider({ children, checkoutProvider, }: React.PropsWithChildren<{
5
+ checkoutProvider?: CheckoutProvider;
6
+ }>): import("react/jsx-runtime").JSX.Element;
7
+ /**
8
+ * Returns the AnalyticsSink from the nearest AnalyticsProvider.
9
+ * Throws if used outside of an AnalyticsProvider.
10
+ */
11
+ export declare function useAnalytics(): AnalyticsSink | null;
12
+ /**
13
+ * Returns the AnalyticsSink if an AnalyticsProvider is present, or null otherwise.
14
+ * Does not throw -- safe to use in components that may render with or without analytics.
15
+ */
16
+ export declare function useAnalyticsOptional(): AnalyticsSink | null;
@@ -0,0 +1,113 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useEffect, useMemo, useRef } from "react";
4
+ import { useConsent } from "../consent/consent-store";
5
+ import { useRegisteredScripts } from "../consent/script-registration-store";
6
+ import { getAnalyticsSinks } from "./get-analytics-sinks";
7
+ import { NavigationTracker } from "./utils/navigation-tracker";
8
+ function combineSinks(sinks) {
9
+ const broadcast = async (method, ...args) => {
10
+ if (typeof window !== "undefined") {
11
+ console.debug(
12
+ "[analytics] broadcast",
13
+ method,
14
+ "to",
15
+ sinks.length,
16
+ "sinks",
17
+ { args }
18
+ );
19
+ }
20
+ await Promise.all(
21
+ sinks.map(async (sink) => {
22
+ try {
23
+ const sinkMethod = sink[method];
24
+ await sinkMethod.apply(sink, args);
25
+ } catch {
26
+ if (typeof window !== "undefined") {
27
+ console.warn("[analytics] sink error", { method, sink });
28
+ }
29
+ }
30
+ })
31
+ );
32
+ };
33
+ return {
34
+ pageView: (...args) => broadcast("pageView", ...args),
35
+ purchase: (...args) => broadcast("purchase", ...args),
36
+ click: (...args) => broadcast("click", ...args),
37
+ productViewed: (...args) => broadcast("productViewed", ...args),
38
+ addToCart: (...args) => broadcast("addToCart", ...args),
39
+ removeFromCart: (...args) => broadcast("removeFromCart", ...args),
40
+ viewCart: (...args) => broadcast("viewCart", ...args),
41
+ startCheckout: (...args) => broadcast("startCheckout", ...args),
42
+ viewCollection: (...args) => broadcast("viewCollection", ...args)
43
+ };
44
+ }
45
+ const AnalyticsContext = createContext(null);
46
+ function AnalyticsProvider({
47
+ children,
48
+ checkoutProvider
49
+ }) {
50
+ const consent = useConsent();
51
+ const registeredScripts = useRegisteredScripts();
52
+ const analytics = useMemo(() => {
53
+ return combineSinks(
54
+ getAnalyticsSinks({
55
+ consent: {
56
+ mode: consent.mode,
57
+ categories: consent.categories,
58
+ decidedAt: consent.decidedAt
59
+ },
60
+ registeredScripts,
61
+ checkoutProvider
62
+ })
63
+ );
64
+ }, [
65
+ consent.mode,
66
+ consent.categories,
67
+ consent.decidedAt,
68
+ registeredScripts,
69
+ checkoutProvider
70
+ ]);
71
+ const analyticsRef = useRef(analytics);
72
+ analyticsRef.current = analytics;
73
+ const navigationTracker = useRef(null);
74
+ useEffect(() => {
75
+ if (typeof window === "undefined") {
76
+ return;
77
+ }
78
+ navigationTracker.current = new NavigationTracker(
79
+ (metadata) => {
80
+ void analyticsRef.current.pageView(metadata);
81
+ }
82
+ );
83
+ navigationTracker.current.init();
84
+ return () => {
85
+ navigationTracker.current?.cleanup();
86
+ };
87
+ }, []);
88
+ return /* @__PURE__ */ jsx(AnalyticsContext.Provider, { value: { analytics }, children });
89
+ }
90
+ class AnalyticsContextError extends Error {
91
+ constructor({ message }) {
92
+ super(message);
93
+ }
94
+ }
95
+ function useAnalytics() {
96
+ const context = useContext(AnalyticsContext);
97
+ if (!context) {
98
+ throw new AnalyticsContextError({
99
+ message: "useAnalytics must be used within <AnalyticsProvider>"
100
+ });
101
+ }
102
+ return context.analytics;
103
+ }
104
+ function useAnalyticsOptional() {
105
+ const context = useContext(AnalyticsContext);
106
+ return context?.analytics ?? null;
107
+ }
108
+ export {
109
+ AnalyticsProvider,
110
+ useAnalytics,
111
+ useAnalyticsOptional
112
+ };
113
+ //# sourceMappingURL=analytics-provider.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../analytics/analytics-provider.tsx"],
4
+ "sourcesContent": ["\"use client\";\n\nimport type React from \"react\";\nimport type { CheckoutProvider } from \"../lib/integration-utils\";\nimport type { AnalyticsSink } from \"./analytics-sink\";\nimport type { PageMetadata } from \"./utils/navigation-tracker\";\n\nimport { createContext, useContext, useEffect, useMemo, useRef } from \"react\";\n\nimport { useConsent } from \"../consent/consent-store\";\nimport { useRegisteredScripts } from \"../consent/script-registration-store\";\nimport { getAnalyticsSinks } from \"./get-analytics-sinks\";\nimport { NavigationTracker } from \"./utils/navigation-tracker\";\n\nfunction combineSinks(sinks: AnalyticsSink[]): AnalyticsSink {\n // oxlint-disable-next-line typescript/no-explicit-any -- legacy any, may or may not be needed\n const broadcast = async (method: keyof AnalyticsSink, ...args: any[]) => {\n if (typeof window !== \"undefined\") {\n console.debug(\n \"[analytics] broadcast\",\n method,\n \"to\",\n sinks.length,\n \"sinks\",\n { args },\n );\n }\n\n await Promise.all(\n sinks.map(async (sink) => {\n try {\n // Legacy cast - may or may not be necessary\n // oxlint-disable-next-line replo/no-as-cast, typescript/no-explicit-any -- legacy any/cast, may or may not be needed\n const sinkMethod = sink[method] as (...args: any[]) => Promise<void>;\n await sinkMethod.apply(sink, args);\n } catch {\n if (typeof window !== \"undefined\") {\n console.warn(\"[analytics] sink error\", { method, sink });\n }\n }\n }),\n );\n };\n\n return {\n pageView: (...args) => broadcast(\"pageView\", ...args),\n purchase: (...args) => broadcast(\"purchase\", ...args),\n click: (...args) => broadcast(\"click\", ...args),\n productViewed: (...args) => broadcast(\"productViewed\", ...args),\n addToCart: (...args) => broadcast(\"addToCart\", ...args),\n removeFromCart: (...args) => broadcast(\"removeFromCart\", ...args),\n viewCart: (...args) => broadcast(\"viewCart\", ...args),\n startCheckout: (...args) => broadcast(\"startCheckout\", ...args),\n viewCollection: (...args) => broadcast(\"viewCollection\", ...args),\n };\n}\n\ninterface AnalyticsContextType {\n analytics: AnalyticsSink | null;\n}\n\nconst AnalyticsContext = createContext<AnalyticsContextType | null>(null);\n\nexport function AnalyticsProvider({\n children,\n checkoutProvider,\n}: React.PropsWithChildren<{ checkoutProvider?: CheckoutProvider }>) {\n const consent = useConsent();\n const registeredScripts = useRegisteredScripts();\n\n // Sinks are derived from consent + which managed scripts are on the page, so\n // the set rebuilds whenever the visitor changes consent or a script mounts.\n const analytics = useMemo(() => {\n return combineSinks(\n getAnalyticsSinks({\n consent: {\n mode: consent.mode,\n categories: consent.categories,\n decidedAt: consent.decidedAt,\n },\n registeredScripts,\n checkoutProvider,\n }),\n );\n }, [\n consent.mode,\n consent.categories,\n consent.decidedAt,\n registeredScripts,\n checkoutProvider,\n ]);\n\n // The navigation tracker is set up once, but always dispatches to the latest\n // combined sink via a ref so consent/registration changes take effect.\n const analyticsRef = useRef(analytics);\n analyticsRef.current = analytics;\n const navigationTracker = useRef<NavigationTracker | null>(null);\n\n // eslint-disable-next-line replo/no-use-effect -- one-time SPA navigation tracking setup; dispatches through analyticsRef to stay current\n useEffect(() => {\n if (typeof window === \"undefined\") {\n return;\n }\n navigationTracker.current = new NavigationTracker(\n (metadata: PageMetadata) => {\n void analyticsRef.current.pageView(metadata);\n },\n );\n navigationTracker.current.init();\n\n return () => {\n navigationTracker.current?.cleanup();\n };\n }, []);\n\n return (\n <AnalyticsContext.Provider value={{ analytics }}>\n {children}\n </AnalyticsContext.Provider>\n );\n}\n\nclass AnalyticsContextError extends Error {\n constructor({ message }: { message: string }) {\n super(message);\n }\n}\n\n/**\n * Returns the AnalyticsSink from the nearest AnalyticsProvider.\n * Throws if used outside of an AnalyticsProvider.\n */\nexport function useAnalytics(): AnalyticsSink | null {\n const context = useContext(AnalyticsContext);\n if (!context) {\n throw new AnalyticsContextError({\n message: \"useAnalytics must be used within <AnalyticsProvider>\",\n });\n }\n return context.analytics;\n}\n\n/**\n * Returns the AnalyticsSink if an AnalyticsProvider is present, or null otherwise.\n * Does not throw -- safe to use in components that may render with or without analytics.\n */\nexport function useAnalyticsOptional(): AnalyticsSink | null {\n const context = useContext(AnalyticsContext);\n return context?.analytics ?? null;\n}\n"],
5
+ "mappings": ";AAoHI;AA7GJ,SAAS,eAAe,YAAY,WAAW,SAAS,cAAc;AAEtE,SAAS,kBAAkB;AAC3B,SAAS,4BAA4B;AACrC,SAAS,yBAAyB;AAClC,SAAS,yBAAyB;AAElC,SAAS,aAAa,OAAuC;AAE3D,QAAM,YAAY,OAAO,WAAgC,SAAgB;AACvE,QAAI,OAAO,WAAW,aAAa;AACjC,cAAQ;AAAA,QACN;AAAA,QACA;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN;AAAA,QACA,EAAE,KAAK;AAAA,MACT;AAAA,IACF;AAEA,UAAM,QAAQ;AAAA,MACZ,MAAM,IAAI,OAAO,SAAS;AACxB,YAAI;AAGF,gBAAM,aAAa,KAAK,MAAM;AAC9B,gBAAM,WAAW,MAAM,MAAM,IAAI;AAAA,QACnC,QAAQ;AACN,cAAI,OAAO,WAAW,aAAa;AACjC,oBAAQ,KAAK,0BAA0B,EAAE,QAAQ,KAAK,CAAC;AAAA,UACzD;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU,IAAI,SAAS,UAAU,YAAY,GAAG,IAAI;AAAA,IACpD,UAAU,IAAI,SAAS,UAAU,YAAY,GAAG,IAAI;AAAA,IACpD,OAAO,IAAI,SAAS,UAAU,SAAS,GAAG,IAAI;AAAA,IAC9C,eAAe,IAAI,SAAS,UAAU,iBAAiB,GAAG,IAAI;AAAA,IAC9D,WAAW,IAAI,SAAS,UAAU,aAAa,GAAG,IAAI;AAAA,IACtD,gBAAgB,IAAI,SAAS,UAAU,kBAAkB,GAAG,IAAI;AAAA,IAChE,UAAU,IAAI,SAAS,UAAU,YAAY,GAAG,IAAI;AAAA,IACpD,eAAe,IAAI,SAAS,UAAU,iBAAiB,GAAG,IAAI;AAAA,IAC9D,gBAAgB,IAAI,SAAS,UAAU,kBAAkB,GAAG,IAAI;AAAA,EAClE;AACF;AAMA,MAAM,mBAAmB,cAA2C,IAAI;AAEjE,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AACF,GAAqE;AACnE,QAAM,UAAU,WAAW;AAC3B,QAAM,oBAAoB,qBAAqB;AAI/C,QAAM,YAAY,QAAQ,MAAM;AAC9B,WAAO;AAAA,MACL,kBAAkB;AAAA,QAChB,SAAS;AAAA,UACP,MAAM,QAAQ;AAAA,UACd,YAAY,QAAQ;AAAA,UACpB,WAAW,QAAQ;AAAA,QACrB;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,GAAG;AAAA,IACD,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,EACF,CAAC;AAID,QAAM,eAAe,OAAO,SAAS;AACrC,eAAa,UAAU;AACvB,QAAM,oBAAoB,OAAiC,IAAI;AAG/D,YAAU,MAAM;AACd,QAAI,OAAO,WAAW,aAAa;AACjC;AAAA,IACF;AACA,sBAAkB,UAAU,IAAI;AAAA,MAC9B,CAAC,aAA2B;AAC1B,aAAK,aAAa,QAAQ,SAAS,QAAQ;AAAA,MAC7C;AAAA,IACF;AACA,sBAAkB,QAAQ,KAAK;AAE/B,WAAO,MAAM;AACX,wBAAkB,SAAS,QAAQ;AAAA,IACrC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SACE,oBAAC,iBAAiB,UAAjB,EAA0B,OAAO,EAAE,UAAU,GAC3C,UACH;AAEJ;AAEA,MAAM,8BAA8B,MAAM;AAAA,EACxC,YAAY,EAAE,QAAQ,GAAwB;AAC5C,UAAM,OAAO;AAAA,EACf;AACF;AAMO,SAAS,eAAqC;AACnD,QAAM,UAAU,WAAW,gBAAgB;AAC3C,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,sBAAsB;AAAA,MAC9B,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACA,SAAO,QAAQ;AACjB;AAMO,SAAS,uBAA6C;AAC3D,QAAM,UAAU,WAAW,gBAAgB;AAC3C,SAAO,SAAS,aAAa;AAC/B;",
6
+ "names": []
7
+ }
@@ -0,0 +1,26 @@
1
+ import type { PageMetadata } from "./utils/navigation-tracker";
2
+ export type DataPayload = {
3
+ data: Record<string, any>;
4
+ };
5
+ export type PurchasePayload = {
6
+ /**
7
+ * Decimal major units (e.g. 19.99), NOT minor units — every downstream ad
8
+ * sink (GA4/Meta/TikTok value fields) and the Replo analytics store speak
9
+ * decimal money. Convert with fromMinorUnitsToMajorUnits at the caller when the source
10
+ * amount is integer minor units.
11
+ */
12
+ amount: number;
13
+ currency: string;
14
+ data: Record<string, any>;
15
+ };
16
+ export interface AnalyticsSink {
17
+ pageView(metadata?: PageMetadata): Promise<void>;
18
+ purchase(payload: PurchasePayload): Promise<void>;
19
+ click(payload: DataPayload): Promise<void>;
20
+ productViewed(payload: DataPayload): Promise<void>;
21
+ addToCart(payload: DataPayload): Promise<void>;
22
+ removeFromCart(payload: DataPayload): Promise<void>;
23
+ viewCart(payload: DataPayload): Promise<void>;
24
+ startCheckout(payload: DataPayload): Promise<void>;
25
+ viewCollection(payload: DataPayload): Promise<void>;
26
+ }
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=analytics-sink.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }
@@ -0,0 +1,27 @@
1
+ import type { ConsentState } from "../consent/consent-store";
2
+ import type { RegisteredScript } from "../consent/script-registration-store";
3
+ import type { CheckoutProvider } from "../lib/integration-utils";
4
+ import type { AnalyticsSink } from "./analytics-sink";
5
+ /**
6
+ * Builds the set of analytics sinks that may fire given the current consent
7
+ * state and which managed scripts are registered on the page.
8
+ *
9
+ * Consent gates data egress, not in-page plumbing:
10
+ * - `WindowSink` is a local `CustomEvent` bus (no data leaves the device), so it
11
+ * always ships regardless of consent. Its consumers self-gate: managed pixels
12
+ * are already gated at the injection layer (they never mount without consent,
13
+ * so they never subscribe), and unmanaged custom scripts are the author's
14
+ * responsibility.
15
+ * - `ReploSink` forwards into Replo's first-party analytics pipeline (real
16
+ * egress / processing), so it counts as `analytics`-category tracking and is
17
+ * gated by that consent. It is an implicit sink this scaffold always ships
18
+ * (not tied to a registered entry) and is never editable in the miniapp.
19
+ *
20
+ * Third-party provider sinks are created only when a matching `<ReploScripts>`
21
+ * entry is registered AND its required consent is granted.
22
+ */
23
+ export declare function getAnalyticsSinks({ consent, registeredScripts, checkoutProvider, }: {
24
+ consent: ConsentState;
25
+ registeredScripts: RegisteredScript[];
26
+ checkoutProvider?: CheckoutProvider;
27
+ }): AnalyticsSink[];
@@ -0,0 +1,52 @@
1
+ import { isConsentAllowed } from "../consent/consent-store";
2
+ import { GA4Sink } from "./sinks/ga4-sink";
3
+ import { MetaSink } from "./sinks/meta-sink";
4
+ import { PinterestSink } from "./sinks/pinterest-sink";
5
+ import { RedditSink } from "./sinks/reddit-sink";
6
+ import { ReploSink } from "./sinks/replo-sink";
7
+ import { SnapchatSink } from "./sinks/snapchat-sink";
8
+ import { TikTokSink } from "./sinks/tiktok-sink";
9
+ import { WindowSink } from "./sinks/window-sink";
10
+ import { gateShopifyOwnedFunnelEvents } from "./utils/shopify-funnel-gate";
11
+ const PROVIDER_SINK_FACTORIES = {
12
+ GA4: () => new GA4Sink(),
13
+ Meta: () => new MetaSink(),
14
+ TikTok: () => new TikTokSink(),
15
+ Snapchat: () => new SnapchatSink(),
16
+ Pinterest: () => new PinterestSink(),
17
+ Reddit: () => new RedditSink()
18
+ };
19
+ function getAnalyticsSinks({
20
+ consent,
21
+ registeredScripts,
22
+ checkoutProvider
23
+ }) {
24
+ const sinks = [new WindowSink()];
25
+ const firstPartyAllowed = consent.mode === "off" || consent.categories.analytics;
26
+ if (firstPartyAllowed) {
27
+ sinks.push(new ReploSink());
28
+ }
29
+ const shopifyOwnsCheckout = checkoutProvider === "shopify";
30
+ const addedTypes = /* @__PURE__ */ new Set();
31
+ for (const script of registeredScripts) {
32
+ const factory = PROVIDER_SINK_FACTORIES[script.type];
33
+ if (!factory || addedTypes.has(script.type)) {
34
+ continue;
35
+ }
36
+ if (isConsentAllowed({
37
+ state: consent,
38
+ requiredConsent: script.requiredConsent
39
+ })) {
40
+ const sink = factory();
41
+ sinks.push(
42
+ shopifyOwnsCheckout ? gateShopifyOwnedFunnelEvents(sink) : sink
43
+ );
44
+ addedTypes.add(script.type);
45
+ }
46
+ }
47
+ return sinks;
48
+ }
49
+ export {
50
+ getAnalyticsSinks
51
+ };
52
+ //# sourceMappingURL=get-analytics-sinks.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../analytics/get-analytics-sinks.ts"],
4
+ "sourcesContent": ["import type { ReploScriptType } from \"schemas/generated/consent\";\nimport type { ConsentState } from \"../consent/consent-store\";\nimport type { RegisteredScript } from \"../consent/script-registration-store\";\nimport type { CheckoutProvider } from \"../lib/integration-utils\";\nimport type { AnalyticsSink } from \"./analytics-sink\";\n\nimport { isConsentAllowed } from \"../consent/consent-store\";\nimport { GA4Sink } from \"./sinks/ga4-sink\";\nimport { MetaSink } from \"./sinks/meta-sink\";\nimport { PinterestSink } from \"./sinks/pinterest-sink\";\nimport { RedditSink } from \"./sinks/reddit-sink\";\nimport { ReploSink } from \"./sinks/replo-sink\";\nimport { SnapchatSink } from \"./sinks/snapchat-sink\";\nimport { TikTokSink } from \"./sinks/tiktok-sink\";\nimport { WindowSink } from \"./sinks/window-sink\";\nimport { gateShopifyOwnedFunnelEvents } from \"./utils/shopify-funnel-gate\";\n\n/**\n * Named providers that have a corresponding ecommerce-event sink. The other\n * managed providers (GoogleTagManager, Hotjar, MicrosoftClarity, Segment) and\n * generic `snippet`/`custom` entries load scripts but do not map to\n * `AnalyticsSink` events today, so they never produce a sink here.\n */\nconst PROVIDER_SINK_FACTORIES: Partial<\n Record<ReploScriptType, () => AnalyticsSink>\n> = {\n GA4: () => new GA4Sink(),\n Meta: () => new MetaSink(),\n TikTok: () => new TikTokSink(),\n Snapchat: () => new SnapchatSink(),\n Pinterest: () => new PinterestSink(),\n Reddit: () => new RedditSink(),\n};\n\n/**\n * Builds the set of analytics sinks that may fire given the current consent\n * state and which managed scripts are registered on the page.\n *\n * Consent gates data egress, not in-page plumbing:\n * - `WindowSink` is a local `CustomEvent` bus (no data leaves the device), so it\n * always ships regardless of consent. Its consumers self-gate: managed pixels\n * are already gated at the injection layer (they never mount without consent,\n * so they never subscribe), and unmanaged custom scripts are the author's\n * responsibility.\n * - `ReploSink` forwards into Replo's first-party analytics pipeline (real\n * egress / processing), so it counts as `analytics`-category tracking and is\n * gated by that consent. It is an implicit sink this scaffold always ships\n * (not tied to a registered entry) and is never editable in the miniapp.\n *\n * Third-party provider sinks are created only when a matching `<ReploScripts>`\n * entry is registered AND its required consent is granted.\n */\nexport function getAnalyticsSinks({\n consent,\n registeredScripts,\n checkoutProvider,\n}: {\n consent: ConsentState;\n registeredScripts: RegisteredScript[];\n checkoutProvider?: CheckoutProvider;\n}): AnalyticsSink[] {\n const sinks: AnalyticsSink[] = [new WindowSink()];\n\n const firstPartyAllowed =\n consent.mode === \"off\" || consent.categories.analytics;\n if (firstPartyAllowed) {\n sinks.push(new ReploSink());\n }\n\n // When Shopify hosts checkout, its native channels report the checkout-funnel\n // events to ad platforms server-side. Suppress those events on third-party\n // storefront pixels so they don't double-count Shopify's copy.\n const shopifyOwnsCheckout = checkoutProvider === \"shopify\";\n\n const addedTypes = new Set<ReploScriptType>();\n for (const script of registeredScripts) {\n const factory = PROVIDER_SINK_FACTORIES[script.type];\n if (!factory || addedTypes.has(script.type)) {\n continue;\n }\n if (\n isConsentAllowed({\n state: consent,\n requiredConsent: script.requiredConsent,\n })\n ) {\n const sink = factory();\n sinks.push(\n shopifyOwnsCheckout ? gateShopifyOwnedFunnelEvents(sink) : sink,\n );\n addedTypes.add(script.type);\n }\n }\n\n return sinks;\n}\n"],
5
+ "mappings": "AAMA,SAAS,wBAAwB;AACjC,SAAS,eAAe;AACxB,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB;AAC3B,SAAS,iBAAiB;AAC1B,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAC3B,SAAS,kBAAkB;AAC3B,SAAS,oCAAoC;AAQ7C,MAAM,0BAEF;AAAA,EACF,KAAK,MAAM,IAAI,QAAQ;AAAA,EACvB,MAAM,MAAM,IAAI,SAAS;AAAA,EACzB,QAAQ,MAAM,IAAI,WAAW;AAAA,EAC7B,UAAU,MAAM,IAAI,aAAa;AAAA,EACjC,WAAW,MAAM,IAAI,cAAc;AAAA,EACnC,QAAQ,MAAM,IAAI,WAAW;AAC/B;AAoBO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AACF,GAIoB;AAClB,QAAM,QAAyB,CAAC,IAAI,WAAW,CAAC;AAEhD,QAAM,oBACJ,QAAQ,SAAS,SAAS,QAAQ,WAAW;AAC/C,MAAI,mBAAmB;AACrB,UAAM,KAAK,IAAI,UAAU,CAAC;AAAA,EAC5B;AAKA,QAAM,sBAAsB,qBAAqB;AAEjD,QAAM,aAAa,oBAAI,IAAqB;AAC5C,aAAW,UAAU,mBAAmB;AACtC,UAAM,UAAU,wBAAwB,OAAO,IAAI;AACnD,QAAI,CAAC,WAAW,WAAW,IAAI,OAAO,IAAI,GAAG;AAC3C;AAAA,IACF;AACA,QACE,iBAAiB;AAAA,MACf,OAAO;AAAA,MACP,iBAAiB,OAAO;AAAA,IAC1B,CAAC,GACD;AACA,YAAM,OAAO,QAAQ;AACrB,YAAM;AAAA,QACJ,sBAAsB,6BAA6B,IAAI,IAAI;AAAA,MAC7D;AACA,iBAAW,IAAI,OAAO,IAAI;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,23 @@
1
+ interface AnalyticsProduct {
2
+ id: string;
3
+ title: string;
4
+ slug?: string;
5
+ description?: string;
6
+ }
7
+ interface AnalyticsProductVariant {
8
+ id: string;
9
+ title?: string;
10
+ sku?: string;
11
+ price?: number;
12
+ }
13
+ interface UseProductViewedAnalyticsProps {
14
+ product: AnalyticsProduct | null;
15
+ selectedVariant?: AnalyticsProductVariant | null;
16
+ }
17
+ /**
18
+ * Fires a `productViewed` analytics event when the product or selected variant
19
+ * changes. Deduplicates by product+variant ID so the same combination is only
20
+ * tracked once per component lifecycle.
21
+ */
22
+ export declare function useProductViewedAnalytics({ product, selectedVariant, }: UseProductViewedAnalyticsProps): void;
23
+ export {};
@@ -0,0 +1,34 @@
1
+ "use client";
2
+ import { useEffect, useRef } from "react";
3
+ import { useAnalytics } from "../analytics-provider";
4
+ function useProductViewedAnalytics({
5
+ product,
6
+ selectedVariant
7
+ }) {
8
+ const analytics = useAnalytics();
9
+ const lastTrackedRef = useRef(null);
10
+ useEffect(() => {
11
+ if (analytics && product && selectedVariant) {
12
+ const trackingKey = `${product.id}-${selectedVariant.id}`;
13
+ if (lastTrackedRef.current !== trackingKey) {
14
+ lastTrackedRef.current = trackingKey;
15
+ void analytics.productViewed({
16
+ data: {
17
+ productId: product.id,
18
+ productTitle: product.title,
19
+ productSlug: product.slug,
20
+ productDescription: product.description,
21
+ variantId: selectedVariant.id ?? "",
22
+ variantTitle: selectedVariant.title ?? "",
23
+ variantSku: selectedVariant.sku ?? "",
24
+ price: selectedVariant.price ?? 0
25
+ }
26
+ });
27
+ }
28
+ }
29
+ }, [analytics, product, selectedVariant]);
30
+ }
31
+ export {
32
+ useProductViewedAnalytics
33
+ };
34
+ //# sourceMappingURL=use-product-viewed-analytics.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../analytics/hooks/use-product-viewed-analytics.ts"],
4
+ "sourcesContent": ["\"use client\";\n\nimport { useEffect, useRef } from \"react\";\n\nimport { useAnalytics } from \"../analytics-provider\";\n\ninterface AnalyticsProduct {\n id: string;\n title: string;\n slug?: string;\n description?: string;\n}\n\ninterface AnalyticsProductVariant {\n id: string;\n title?: string;\n sku?: string;\n price?: number;\n}\n\ninterface UseProductViewedAnalyticsProps {\n product: AnalyticsProduct | null;\n selectedVariant?: AnalyticsProductVariant | null;\n}\n\n/**\n * Fires a `productViewed` analytics event when the product or selected variant\n * changes. Deduplicates by product+variant ID so the same combination is only\n * tracked once per component lifecycle.\n */\nexport function useProductViewedAnalytics({\n product,\n selectedVariant,\n}: UseProductViewedAnalyticsProps) {\n const analytics = useAnalytics();\n const lastTrackedRef = useRef<string | null>(null);\n\n // eslint-disable-next-line replo/no-use-effect -- Legacy effect - may or may not be necessary\n useEffect(() => {\n if (analytics && product && selectedVariant) {\n const trackingKey = `${product.id}-${selectedVariant.id}`;\n\n if (lastTrackedRef.current !== trackingKey) {\n lastTrackedRef.current = trackingKey;\n\n void analytics.productViewed({\n data: {\n productId: product.id,\n productTitle: product.title,\n productSlug: product.slug,\n productDescription: product.description,\n variantId: selectedVariant.id ?? \"\",\n variantTitle: selectedVariant.title ?? \"\",\n variantSku: selectedVariant.sku ?? \"\",\n price: selectedVariant.price ?? 0,\n },\n });\n }\n }\n }, [analytics, product, selectedVariant]);\n}\n"],
5
+ "mappings": ";AAEA,SAAS,WAAW,cAAc;AAElC,SAAS,oBAAoB;AA0BtB,SAAS,0BAA0B;AAAA,EACxC;AAAA,EACA;AACF,GAAmC;AACjC,QAAM,YAAY,aAAa;AAC/B,QAAM,iBAAiB,OAAsB,IAAI;AAGjD,YAAU,MAAM;AACd,QAAI,aAAa,WAAW,iBAAiB;AAC3C,YAAM,cAAc,GAAG,QAAQ,EAAE,IAAI,gBAAgB,EAAE;AAEvD,UAAI,eAAe,YAAY,aAAa;AAC1C,uBAAe,UAAU;AAEzB,aAAK,UAAU,cAAc;AAAA,UAC3B,MAAM;AAAA,YACJ,WAAW,QAAQ;AAAA,YACnB,cAAc,QAAQ;AAAA,YACtB,aAAa,QAAQ;AAAA,YACrB,oBAAoB,QAAQ;AAAA,YAC5B,WAAW,gBAAgB,MAAM;AAAA,YACjC,cAAc,gBAAgB,SAAS;AAAA,YACvC,YAAY,gBAAgB,OAAO;AAAA,YACnC,OAAO,gBAAgB,SAAS;AAAA,UAClC;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,GAAG,CAAC,WAAW,SAAS,eAAe,CAAC;AAC1C;",
6
+ "names": []
7
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Resolves the Replo first-party pixel's config from the worker env and hands it
3
+ * to the consent-gated client injector. This lives inside `ReploProvider` (not
4
+ * the site's `app/layout.tsx`) so every agent site ships the implicit
5
+ * first-party pixel automatically — mirroring how `ReploSink` is an always-on
6
+ * sink that is never authored in the layout or editable in the miniapp.
7
+ *
8
+ * Renders nothing when the analytics pipeline isn't wired (e.g. lean local dev,
9
+ * where `REPLO_ANALYTICS_PIXEL_URL` / `ANALYTICS_FIRE_API_URL` are unset),
10
+ * mirroring the self-disabling consent action.
11
+ */
12
+ export declare function ReploFirstPartyPixel(): Promise<import("react/jsx-runtime").JSX.Element | null>;
@@ -0,0 +1,31 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { getEnv } from "../env";
3
+ import { ReploPixelScript } from "./replo-pixel-script";
4
+ async function ReploFirstPartyPixel() {
5
+ let pixelUrl;
6
+ let apiUrl;
7
+ let projectId;
8
+ try {
9
+ const env = await getEnv();
10
+ pixelUrl = env.REPLO_ANALYTICS_PIXEL_URL;
11
+ apiUrl = env.ANALYTICS_FIRE_API_URL;
12
+ projectId = env.PROJECT_ID;
13
+ } catch {
14
+ return null;
15
+ }
16
+ if (!pixelUrl || !apiUrl || !projectId) {
17
+ return null;
18
+ }
19
+ return /* @__PURE__ */ jsx(
20
+ ReploPixelScript,
21
+ {
22
+ pixelUrl,
23
+ apiUrl,
24
+ projectId
25
+ }
26
+ );
27
+ }
28
+ export {
29
+ ReploFirstPartyPixel
30
+ };
31
+ //# sourceMappingURL=replo-first-party-pixel.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../analytics/replo-first-party-pixel.tsx"],
4
+ "sourcesContent": ["import { getEnv } from \"../env\";\nimport { ReploPixelScript } from \"./replo-pixel-script\";\n\n/**\n * Resolves the Replo first-party pixel's config from the worker env and hands it\n * to the consent-gated client injector. This lives inside `ReploProvider` (not\n * the site's `app/layout.tsx`) so every agent site ships the implicit\n * first-party pixel automatically \u2014 mirroring how `ReploSink` is an always-on\n * sink that is never authored in the layout or editable in the miniapp.\n *\n * Renders nothing when the analytics pipeline isn't wired (e.g. lean local dev,\n * where `REPLO_ANALYTICS_PIXEL_URL` / `ANALYTICS_FIRE_API_URL` are unset),\n * mirroring the self-disabling consent action.\n */\nexport async function ReploFirstPartyPixel() {\n let pixelUrl: string | undefined;\n let apiUrl: string | undefined;\n let projectId: string | undefined;\n try {\n const env = await getEnv();\n pixelUrl = env.REPLO_ANALYTICS_PIXEL_URL;\n apiUrl = env.ANALYTICS_FIRE_API_URL;\n projectId = env.PROJECT_ID;\n } catch {\n // No Cloudflare env (e.g. running the site outside the worker): no pixel.\n return null;\n }\n\n if (!pixelUrl || !apiUrl || !projectId) {\n return null;\n }\n\n return (\n <ReploPixelScript\n pixelUrl={pixelUrl}\n apiUrl={apiUrl}\n projectId={projectId}\n />\n );\n}\n"],
5
+ "mappings": "AAiCI;AAjCJ,SAAS,cAAc;AACvB,SAAS,wBAAwB;AAajC,eAAsB,uBAAuB;AAC3C,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI;AACF,UAAM,MAAM,MAAM,OAAO;AACzB,eAAW,IAAI;AACf,aAAS,IAAI;AACb,gBAAY,IAAI;AAAA,EAClB,QAAQ;AAEN,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,YAAY,CAAC,UAAU,CAAC,WAAW;AACtC,WAAO;AAAA,EACT;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Consent-gated injector for Replo's first-party analytics pixel. The loaded
3
+ * script sets `window.ReploPixel`, which the always-on `ReploSink` forwards
4
+ * events into, so gating it on `analytics` consent keeps the first-party sink
5
+ * consent-correct without the pixel loading unconditionally in `<head>` the way
6
+ * the legacy scaffold does. `analytics` consent here matches the
7
+ * `firstPartyAllowed` gate that controls whether `ReploSink` is created at all.
8
+ */
9
+ export declare function ReploPixelScript({ pixelUrl, apiUrl, projectId, }: {
10
+ pixelUrl: string;
11
+ apiUrl: string;
12
+ projectId: string;
13
+ }): import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { isConsentAllowed, useConsent } from "../consent/consent-store";
4
+ import { InjectedScript } from "../consent/replo-scripts";
5
+ const PIXEL_SCRIPT_ID = "replo:first-party-pixel";
6
+ function ReploPixelScript({
7
+ pixelUrl,
8
+ apiUrl,
9
+ projectId
10
+ }) {
11
+ const consent = useConsent();
12
+ if (!isConsentAllowed({ state: consent, requiredConsent: ["analytics"] })) {
13
+ return null;
14
+ }
15
+ const descriptors = [
16
+ {
17
+ kind: "external",
18
+ src: `${pixelUrl}/latest.js`,
19
+ attributes: {
20
+ "data-api-url": apiUrl,
21
+ "data-project-id": projectId
22
+ }
23
+ }
24
+ ];
25
+ return /* @__PURE__ */ jsx(InjectedScript, { baseId: PIXEL_SCRIPT_ID, descriptors });
26
+ }
27
+ export {
28
+ ReploPixelScript
29
+ };
30
+ //# sourceMappingURL=replo-pixel-script.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../analytics/replo-pixel-script.tsx"],
4
+ "sourcesContent": ["\"use client\";\n\nimport type { ScriptTagDescriptor } from \"schemas/generated/consent\";\n\nimport { isConsentAllowed, useConsent } from \"../consent/consent-store\";\nimport { InjectedScript } from \"../consent/replo-scripts\";\n\n// Stable injection id so re-renders and React Strict Mode double-invokes never\n// inject the pixel twice (the loader itself also guards via `__reploPixelLoaded`).\nconst PIXEL_SCRIPT_ID = \"replo:first-party-pixel\";\n\n/**\n * Consent-gated injector for Replo's first-party analytics pixel. The loaded\n * script sets `window.ReploPixel`, which the always-on `ReploSink` forwards\n * events into, so gating it on `analytics` consent keeps the first-party sink\n * consent-correct without the pixel loading unconditionally in `<head>` the way\n * the legacy scaffold does. `analytics` consent here matches the\n * `firstPartyAllowed` gate that controls whether `ReploSink` is created at all.\n */\nexport function ReploPixelScript({\n pixelUrl,\n apiUrl,\n projectId,\n}: {\n pixelUrl: string;\n apiUrl: string;\n projectId: string;\n}) {\n const consent = useConsent();\n if (!isConsentAllowed({ state: consent, requiredConsent: [\"analytics\"] })) {\n return null;\n }\n\n const descriptors: ScriptTagDescriptor[] = [\n {\n kind: \"external\",\n src: `${pixelUrl}/latest.js`,\n attributes: {\n \"data-api-url\": apiUrl,\n \"data-project-id\": projectId,\n },\n },\n ];\n\n return <InjectedScript baseId={PIXEL_SCRIPT_ID} descriptors={descriptors} />;\n}\n"],
5
+ "mappings": ";AA4CS;AAxCT,SAAS,kBAAkB,kBAAkB;AAC7C,SAAS,sBAAsB;AAI/B,MAAM,kBAAkB;AAUjB,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,UAAU,WAAW;AAC3B,MAAI,CAAC,iBAAiB,EAAE,OAAO,SAAS,iBAAiB,CAAC,WAAW,EAAE,CAAC,GAAG;AACzE,WAAO;AAAA,EACT;AAEA,QAAM,cAAqC;AAAA,IACzC;AAAA,MACE,MAAM;AAAA,MACN,KAAK,GAAG,QAAQ;AAAA,MAChB,YAAY;AAAA,QACV,gBAAgB;AAAA,QAChB,mBAAmB;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAEA,SAAO,oBAAC,kBAAe,QAAQ,iBAAiB,aAA0B;AAC5E;",
6
+ "names": []
7
+ }
@@ -0,0 +1,15 @@
1
+ import type { AnalyticsSink, DataPayload, PurchasePayload } from "../analytics-sink";
2
+ import type { PageMetadata } from "../utils/navigation-tracker";
3
+ export declare class GA4Sink implements AnalyticsSink {
4
+ private send;
5
+ constructor();
6
+ pageView(metadata?: PageMetadata): Promise<void>;
7
+ purchase({ amount, currency, data }: PurchasePayload): Promise<void>;
8
+ click({ data }: DataPayload): Promise<void>;
9
+ productViewed({ data }: DataPayload): Promise<void>;
10
+ addToCart({ data }: DataPayload): Promise<void>;
11
+ removeFromCart({ data }: DataPayload): Promise<void>;
12
+ viewCart({ data }: DataPayload): Promise<void>;
13
+ startCheckout({ data }: DataPayload): Promise<void>;
14
+ viewCollection({ data }: DataPayload): Promise<void>;
15
+ }
@@ -0,0 +1,60 @@
1
+ import { createEventQueue } from "../utils/analytics-utils";
2
+ class GA4Sink {
3
+ // oxlint-disable-next-line typescript/no-explicit-any -- legacy any, may or may not be needed
4
+ send;
5
+ constructor() {
6
+ this.send = createEventQueue(
7
+ // Legacy cast - may or may not be necessary
8
+ // oxlint-disable-next-line replo/no-as-cast, typescript/no-explicit-any -- legacy any/cast, may or may not be needed
9
+ () => typeof window !== "undefined" && Boolean(window.gtag),
10
+ (event, params) => {
11
+ const gtag = window.gtag;
12
+ gtag("event", event, params);
13
+ },
14
+ "GA4"
15
+ );
16
+ }
17
+ async pageView(metadata) {
18
+ const params = metadata ? {
19
+ page_title: metadata.title,
20
+ page_location: metadata.url
21
+ } : {};
22
+ this.send("page_view", params);
23
+ }
24
+ async purchase({ amount, currency, data }) {
25
+ this.send("purchase", { value: amount, currency, ...data });
26
+ }
27
+ async click({ data }) {
28
+ this.send("select_content", data);
29
+ }
30
+ async productViewed({ data }) {
31
+ this.send("view_item", {
32
+ value: data.price,
33
+ currency: data.currency,
34
+ ...data
35
+ });
36
+ }
37
+ async addToCart({ data }) {
38
+ this.send("add_to_cart", {
39
+ value: data.price,
40
+ currency: data.currency,
41
+ ...data
42
+ });
43
+ }
44
+ async removeFromCart({ data }) {
45
+ this.send("remove_from_cart", data);
46
+ }
47
+ async viewCart({ data }) {
48
+ this.send("view_cart", data);
49
+ }
50
+ async startCheckout({ data }) {
51
+ this.send("begin_checkout", data);
52
+ }
53
+ async viewCollection({ data }) {
54
+ this.send("view_item_list", data);
55
+ }
56
+ }
57
+ export {
58
+ GA4Sink
59
+ };
60
+ //# sourceMappingURL=ga4-sink.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../analytics/sinks/ga4-sink.ts"],
4
+ "sourcesContent": ["import type {\n AnalyticsSink,\n DataPayload,\n PurchasePayload,\n} from \"../analytics-sink\";\nimport type { PageMetadata } from \"../utils/navigation-tracker\";\n\nimport { createEventQueue } from \"../utils/analytics-utils\";\n\nexport class GA4Sink implements AnalyticsSink {\n // oxlint-disable-next-line typescript/no-explicit-any -- legacy any, may or may not be needed\n private send: (event: string, params?: Record<string, any>) => void;\n\n constructor() {\n this.send = createEventQueue(\n // Legacy cast - may or may not be necessary\n // oxlint-disable-next-line replo/no-as-cast, typescript/no-explicit-any -- legacy any/cast, may or may not be needed\n () => typeof window !== \"undefined\" && Boolean((window as any).gtag),\n (event, params) => {\n // Legacy cast - may or may not be necessary\n // oxlint-disable-next-line replo/no-as-cast, typescript/no-explicit-any -- legacy any/cast, may or may not be needed\n const gtag = (window as any).gtag;\n gtag(\"event\", event, params);\n },\n \"GA4\",\n );\n }\n\n async pageView(metadata?: PageMetadata) {\n const params = metadata\n ? {\n page_title: metadata.title,\n page_location: metadata.url,\n }\n : {};\n this.send(\"page_view\", params);\n }\n\n async purchase({ amount, currency, data }: PurchasePayload) {\n this.send(\"purchase\", { value: amount, currency, ...data });\n }\n\n async click({ data }: DataPayload) {\n this.send(\"select_content\", data);\n }\n\n async productViewed({ data }: DataPayload) {\n this.send(\"view_item\", {\n value: data.price,\n currency: data.currency,\n ...data,\n });\n }\n\n async addToCart({ data }: DataPayload) {\n this.send(\"add_to_cart\", {\n value: data.price,\n currency: data.currency,\n ...data,\n });\n }\n\n async removeFromCart({ data }: DataPayload) {\n this.send(\"remove_from_cart\", data);\n }\n\n async viewCart({ data }: DataPayload) {\n this.send(\"view_cart\", data);\n }\n\n async startCheckout({ data }: DataPayload) {\n this.send(\"begin_checkout\", data);\n }\n\n async viewCollection({ data }: DataPayload) {\n this.send(\"view_item_list\", data);\n }\n}\n"],
5
+ "mappings": "AAOA,SAAS,wBAAwB;AAE1B,MAAM,QAAiC;AAAA;AAAA,EAEpC;AAAA,EAER,cAAc;AACZ,SAAK,OAAO;AAAA;AAAA;AAAA,MAGV,MAAM,OAAO,WAAW,eAAe,QAAS,OAAe,IAAI;AAAA,MACnE,CAAC,OAAO,WAAW;AAGjB,cAAM,OAAQ,OAAe;AAC7B,aAAK,SAAS,OAAO,MAAM;AAAA,MAC7B;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,UAAyB;AACtC,UAAM,SAAS,WACX;AAAA,MACE,YAAY,SAAS;AAAA,MACrB,eAAe,SAAS;AAAA,IAC1B,IACA,CAAC;AACL,SAAK,KAAK,aAAa,MAAM;AAAA,EAC/B;AAAA,EAEA,MAAM,SAAS,EAAE,QAAQ,UAAU,KAAK,GAAoB;AAC1D,SAAK,KAAK,YAAY,EAAE,OAAO,QAAQ,UAAU,GAAG,KAAK,CAAC;AAAA,EAC5D;AAAA,EAEA,MAAM,MAAM,EAAE,KAAK,GAAgB;AACjC,SAAK,KAAK,kBAAkB,IAAI;AAAA,EAClC;AAAA,EAEA,MAAM,cAAc,EAAE,KAAK,GAAgB;AACzC,SAAK,KAAK,aAAa;AAAA,MACrB,OAAO,KAAK;AAAA,MACZ,UAAU,KAAK;AAAA,MACf,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,UAAU,EAAE,KAAK,GAAgB;AACrC,SAAK,KAAK,eAAe;AAAA,MACvB,OAAO,KAAK;AAAA,MACZ,UAAU,KAAK;AAAA,MACf,GAAG;AAAA,IACL,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,eAAe,EAAE,KAAK,GAAgB;AAC1C,SAAK,KAAK,oBAAoB,IAAI;AAAA,EACpC;AAAA,EAEA,MAAM,SAAS,EAAE,KAAK,GAAgB;AACpC,SAAK,KAAK,aAAa,IAAI;AAAA,EAC7B;AAAA,EAEA,MAAM,cAAc,EAAE,KAAK,GAAgB;AACzC,SAAK,KAAK,kBAAkB,IAAI;AAAA,EAClC;AAAA,EAEA,MAAM,eAAe,EAAE,KAAK,GAAgB;AAC1C,SAAK,KAAK,kBAAkB,IAAI;AAAA,EAClC;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,14 @@
1
+ import type { AnalyticsSink, DataPayload, PurchasePayload } from "../analytics-sink";
2
+ export declare class MetaSink implements AnalyticsSink {
3
+ private track;
4
+ constructor();
5
+ pageView(): Promise<void>;
6
+ purchase({ amount, currency, data }: PurchasePayload): Promise<void>;
7
+ click(): Promise<void>;
8
+ productViewed({ data }: DataPayload): Promise<void>;
9
+ addToCart({ data }: DataPayload): Promise<void>;
10
+ removeFromCart(): Promise<void>;
11
+ viewCart(): Promise<void>;
12
+ startCheckout({ data }: DataPayload): Promise<void>;
13
+ viewCollection(): Promise<void>;
14
+ }
@@ -0,0 +1,56 @@
1
+ import { createEventQueue } from "../utils/analytics-utils";
2
+ class MetaSink {
3
+ // oxlint-disable-next-line typescript/no-explicit-any -- legacy any, may or may not be needed
4
+ track;
5
+ constructor() {
6
+ this.track = createEventQueue(
7
+ // Legacy cast - may or may not be necessary
8
+ // oxlint-disable-next-line replo/no-as-cast, typescript/no-explicit-any -- legacy any/cast, may or may not be needed
9
+ () => typeof window !== "undefined" && Boolean(window.fbq),
10
+ (event, params) => {
11
+ const fbq = window.fbq;
12
+ fbq("track", event, params);
13
+ },
14
+ "Meta"
15
+ );
16
+ }
17
+ async pageView() {
18
+ this.track("PageView");
19
+ }
20
+ async purchase({ amount, currency, data }) {
21
+ this.track("Purchase", { value: amount, currency, ...data });
22
+ }
23
+ async click() {
24
+ }
25
+ async productViewed({ data }) {
26
+ this.track("ViewContent", {
27
+ value: data.price,
28
+ currency: data.currency,
29
+ ...data
30
+ });
31
+ }
32
+ async addToCart({ data }) {
33
+ this.track("AddToCart", {
34
+ value: data.price,
35
+ currency: data.currency,
36
+ ...data
37
+ });
38
+ }
39
+ async removeFromCart() {
40
+ }
41
+ async viewCart() {
42
+ }
43
+ async startCheckout({ data }) {
44
+ this.track("InitiateCheckout", {
45
+ value: data.totalPrice?.amount,
46
+ currency: data.currencyCode,
47
+ ...data
48
+ });
49
+ }
50
+ async viewCollection() {
51
+ }
52
+ }
53
+ export {
54
+ MetaSink
55
+ };
56
+ //# sourceMappingURL=meta-sink.js.map