@probat/react 0.1.1 → 0.1.2

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.
package/dist/index.js CHANGED
@@ -62,7 +62,7 @@ async function sendMetric(baseUrl, proposalId, metricName, variantLabel = "contr
62
62
  captured_at: (/* @__PURE__ */ new Date()).toISOString()
63
63
  };
64
64
  try {
65
- await fetch(url, {
65
+ const response = await fetch(url, {
66
66
  method: "POST",
67
67
  headers: {
68
68
  Accept: "application/json",
@@ -72,7 +72,26 @@ async function sendMetric(baseUrl, proposalId, metricName, variantLabel = "contr
72
72
  // CRITICAL: Include cookies to distinguish different users
73
73
  body: JSON.stringify(body)
74
74
  });
75
- } catch {
75
+ if (!response.ok) {
76
+ console.warn("[PROBAT] Metric send failed:", {
77
+ status: response.status,
78
+ statusText: response.statusText,
79
+ url,
80
+ body
81
+ });
82
+ } else {
83
+ console.log("[PROBAT] Metric sent successfully:", {
84
+ metricName,
85
+ proposalId,
86
+ variantLabel
87
+ });
88
+ }
89
+ } catch (error) {
90
+ console.error("[PROBAT] Error sending metric:", {
91
+ error: error instanceof Error ? error.message : String(error),
92
+ url,
93
+ body
94
+ });
76
95
  }
77
96
  }
78
97
  function extractClickMeta(event) {
@@ -209,7 +228,9 @@ function handleDocumentClick(event) {
209
228
  const target = event.target;
210
229
  if (!target) return;
211
230
  const metadata = getProposalMetadata(target);
212
- if (!metadata) return;
231
+ if (!metadata) {
232
+ return;
233
+ }
213
234
  const now2 = Date.now();
214
235
  const lastClick = lastClickTime.get(metadata.proposalId) || 0;
215
236
  if (now2 - lastClick < DEBOUNCE_MS) {
@@ -217,19 +238,32 @@ function handleDocumentClick(event) {
217
238
  }
218
239
  lastClickTime.set(metadata.proposalId, now2);
219
240
  const clickMeta = extractClickMeta(event);
220
- const hasTrackAttribute = target.hasAttribute("data-probat-track") || target.closest("[data-probat-track]") !== null;
221
- const shouldTrack = clickMeta !== void 0 || hasTrackAttribute;
222
- if (!shouldTrack) {
223
- return;
224
- }
241
+ target.hasAttribute("data-probat-track") || target.closest("[data-probat-track]") !== null;
242
+ const finalMeta = clickMeta || {
243
+ target_tag: target.tagName,
244
+ target_class: target.className || "",
245
+ target_id: target.id || "",
246
+ clicked_inside_probat: true
247
+ // Flag to indicate this was tracked via document-level listener
248
+ };
249
+ const experimentId = metadata.variantLabel === "control" ? void 0 : metadata.experimentId && !metadata.experimentId.startsWith("exp_") ? metadata.experimentId : void 0;
225
250
  void sendMetric(
226
251
  metadata.apiBaseUrl,
227
252
  metadata.proposalId,
228
253
  "click",
229
254
  metadata.variantLabel,
230
- metadata.experimentId || void 0,
231
- clickMeta
255
+ experimentId,
256
+ finalMeta
232
257
  );
258
+ console.log("[PROBAT] Click tracked:", {
259
+ proposalId: metadata.proposalId,
260
+ variantLabel: metadata.variantLabel,
261
+ target: target.tagName,
262
+ targetId: target.id || "none",
263
+ targetClass: target.className || "none",
264
+ meta: finalMeta
265
+ });
266
+ console.log("[PROBAT] Sending metric to:", `${metadata.apiBaseUrl}/send_metrics/${metadata.proposalId}`);
233
267
  }
234
268
  function initDocumentClickTracking() {
235
269
  if (isListenerAttached) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/environment.ts","../src/utils/api.ts","../src/utils/documentClickTracker.ts","../src/context/ProbatContext.tsx","../src/components/ProbatProviderClient.tsx","../src/hooks/useProbatMetrics.ts","../src/utils/storage.ts","../src/hooks/useExperiment.ts","../src/hoc/withExperiment.tsx"],"names":["React","now","createContext","useMemo","useEffect","useContext","useCallback","useState","meta","label"],"mappings":";;;;;;;;;;AAIO,SAAS,iBAAA,GAAoC;AAChD,EAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AAC/B,IAAA,OAAO,MAAA;AAAA,EACX;AAEA,EAAA,MAAM,QAAA,GAAW,OAAO,QAAA,CAAS,QAAA;AAGjC,EAAA,IACI,aAAa,WAAA,IACb,QAAA,KAAa,WAAA,IACb,QAAA,KAAa,aACb,QAAA,CAAS,UAAA,CAAW,UAAU,CAAA,IAC9B,SAAS,UAAA,CAAW,KAAK,CAAA,IACzB,QAAA,CAAS,WAAW,SAAS,CAAA,IAC7B,QAAA,CAAS,UAAA,CAAW,SAAS,CAAA,IAC7B,QAAA,CAAS,UAAA,CAAW,SAAS,KAC7B,QAAA,CAAS,UAAA,CAAW,SAAS,CAAA,IAC7B,SAAS,UAAA,CAAW,SAAS,CAAA,IAC7B,QAAA,CAAS,WAAW,SAAS,CAAA,IAC7B,QAAA,CAAS,UAAA,CAAW,SAAS,CAAA,IAC7B,QAAA,CAAS,UAAA,CAAW,SAAS,KAC7B,QAAA,CAAS,UAAA,CAAW,SAAS,CAAA,IAC7B,SAAS,UAAA,CAAW,SAAS,CAAA,IAC7B,QAAA,CAAS,WAAW,SAAS,CAAA,IAC7B,QAAA,CAAS,UAAA,CAAW,SAAS,CAAA,IAC7B,QAAA,CAAS,UAAA,CAAW,SAAS,KAC7B,QAAA,CAAS,UAAA,CAAW,SAAS,CAAA,IAC7B,SAAS,UAAA,CAAW,SAAS,KAC7B,QAAA,CAAS,UAAA,CAAW,SAAS,CAAA,EAC/B;AACE,IAAA,OAAO,KAAA;AAAA,EACX;AAEA,EAAA,OAAO,MAAA;AACX;AClBA,IAAM,cAAA,uBAAqB,GAAA,EAGzB;AAEF,eAAsB,aAAA,CAClB,SACA,UAAA,EACiD;AAEjD,EAAA,MAAM,aAAA,GAAgB,cAAA,CAAe,GAAA,CAAI,UAAU,CAAA;AACnD,EAAA,IAAI,aAAA,EAAe;AACf,IAAA,OAAO,aAAA;AAAA,EACX;AAGA,EAAA,MAAM,gBAAgB,YAAY;AAC9B,IAAA,IAAI;AACA,MAAA,MAAM,GAAA,GAAM,CAAA,EAAG,OAAA,CAAQ,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,2BAAA,EAA8B,kBAAA,CAAmB,UAAU,CAAC,CAAA,CAAA;AACrG,MAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,QACzB,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA,EAAS,EAAE,MAAA,EAAQ,kBAAA,EAAmB;AAAA,QACtC,WAAA,EAAa;AAAA;AAAA,OAChB,CAAA;AACD,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI,MAAM,IAAI,KAAA,CAAM,CAAA,KAAA,EAAQ,GAAA,CAAI,MAAM,CAAA,CAAE,CAAA;AACjD,MAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,EAAK;AAE7B,MAAA,MAAM,iBAAiB,IAAA,CAAK,aAAA,IAAiB,CAAA,IAAA,EAAO,UAAU,IAAI,QAAA,EAAS;AAC3E,MAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,IAAS,IAAA,CAAK,MAAM,IAAA,EAAK,GAAI,KAAK,KAAA,GAAQ,SAAA;AAE7D,MAAA,OAAO,EAAE,eAAe,KAAA,EAAM;AAAA,IAClC,CAAA,SAAE;AAEE,MAAA,cAAA,CAAe,OAAO,UAAU,CAAA;AAAA,IACpC;AAAA,EACJ,CAAA,GAAG;AAGH,EAAA,cAAA,CAAe,GAAA,CAAI,YAAY,YAAY,CAAA;AAC3C,EAAA,OAAO,YAAA;AACX;AAEA,eAAsB,UAAA,CAClB,SACA,UAAA,EACA,UAAA,EACA,eAAuB,SAAA,EACvB,YAAA,EACA,UAAA,GAAkC,EAAC,EACrC;AACE,EAAA,MAAM,GAAA,GAAM,CAAA,EAAG,OAAA,CAAQ,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,cAAA,EAAiB,kBAAA,CAAmB,UAAU,CAAC,CAAA,CAAA;AACxF,EAAA,MAAM,IAAA,GAAO;AAAA,IACT,eAAe,YAAA,IAAgB,IAAA;AAAA,IAC/B,aAAA,EAAe,YAAA;AAAA,IACf,WAAA,EAAa,UAAA;AAAA,IACb,YAAA,EAAc,CAAA;AAAA,IACd,WAAA,EAAa,OAAA;AAAA,IACb,MAAA,EAAQ,OAAA;AAAA,IACR,aAAa,iBAAA,EAAkB;AAAA;AAAA,IAC/B,UAAA;AAAA,IACA,WAAA,EAAA,iBAAa,IAAI,IAAA,EAAK,EAAE,WAAA;AAAY,GACxC;AACA,EAAA,IAAI;AACA,IAAA,MAAM,MAAM,GAAA,EAAK;AAAA,MACb,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS;AAAA,QACL,MAAA,EAAQ,kBAAA;AAAA,QACR,cAAA,EAAgB;AAAA,OACpB;AAAA,MACA,WAAA,EAAa,SAAA;AAAA;AAAA,MACb,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,IAAI;AAAA,KAC5B,CAAA;AAAA,EACL,CAAA,CAAA,MAAQ;AAAA,EAER;AACJ;AAEO,SAAS,iBACZ,KAAA,EAC+B;AAC/B,EAAA,IAAI,CAAC,KAAA,IAAS,CAAC,KAAA,CAAM,QAAQ,OAAO,MAAA;AACpC,EAAA,MAAM,YAAY,KAAA,CAAM,MAAA;AACxB,EAAA,IAAI,CAAC,WAAW,OAAO,MAAA;AACvB,EAAA,MAAM,aAAa,SAAA,CAAU,OAAA;AAAA,IACzB;AAAA,GACJ;AACA,EAAA,IAAI,CAAC,YAAY,OAAO,MAAA;AACxB,EAAA,MAAM,IAAA,GAA4B;AAAA,IAC9B,YAAY,UAAA,CAAW;AAAA,GAC3B;AACA,EAAA,IAAI,UAAA,CAAW,EAAA,EAAI,IAAA,CAAK,SAAA,GAAY,UAAA,CAAW,EAAA;AAC/C,EAAA,MAAM,IAAA,GAAO,UAAA,CAAW,YAAA,CAAa,wBAAwB,CAAA;AAC7D,EAAA,IAAI,IAAA,OAAW,eAAA,GAAkB,IAAA;AACjC,EAAA,MAAM,IAAA,GAAO,UAAA,CAAW,WAAA,EAAa,IAAA,EAAK;AAC1C,EAAA,IAAI,MAAM,IAAA,CAAK,WAAA,GAAc,IAAA,CAAK,KAAA,CAAM,GAAG,GAAG,CAAA;AAC9C,EAAA,OAAO,IAAA;AACX;AAGA,IAAM,oBAAA,uBAA2B,GAAA,EAG/B;AAEF,eAAsB,8BAAA,CAClB,OAAA,EACA,YAAA,EACA,aAAA,EACyC;AACzC,EAAA,MAAM,QAAA,GAAW,CAAA,EAAG,YAAY,CAAA,CAAA,EAAI,aAAa,CAAA,CAAA;AAGjD,EAAA,MAAM,aAAA,GAAgB,oBAAA,CAAqB,GAAA,CAAI,QAAQ,CAAA;AACvD,EAAA,IAAI,aAAA,EAAe;AACf,IAAA,OAAO,aAAA;AAAA,EACX;AAGA,EAAA,MAAM,gBAAgB,YAAY;AAC9B,IAAA,IAAI;AACA,MAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,CAAA,EAAG,QAAQ,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAC,CAAA,gCAAA,CAAkC,CAAA;AACnF,MAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,gBAAA,EAAkB,YAAY,CAAA;AACnD,MAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,gBAAA,EAAkB,aAAa,CAAA;AAEpD,MAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,CAAI,UAAS,EAAG;AAAA,QACpC,MAAA,EAAQ,KAAA;AAAA,QACR,OAAA,EAAS,EAAE,MAAA,EAAQ,kBAAA,EAAmB;AAAA,QACtC,WAAA,EAAa;AAAA,OAChB,CAAA;AAED,MAAA,IAAI,GAAA,CAAI,WAAW,GAAA,EAAK;AAEpB,QAAA,OAAO,IAAA;AAAA,MACX;AAEA,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACT,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,KAAA,EAAQ,GAAA,CAAI,MAAM,CAAA,CAAE,CAAA;AAAA,MACxC;AAEA,MAAA,MAAM,IAAA,GAAQ,MAAM,GAAA,CAAI,IAAA,EAAK;AAC7B,MAAA,OAAO,IAAA;AAAA,IACX,SAAS,CAAA,EAAG;AACR,MAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,2CAAA,EAA8C,CAAC,CAAA,CAAE,CAAA;AAC9D,MAAA,OAAO,IAAA;AAAA,IACX,CAAA,SAAE;AAEE,MAAA,oBAAA,CAAqB,OAAO,QAAQ,CAAA;AAAA,IACxC;AAAA,EACJ,CAAA,GAAG;AAGH,EAAA,oBAAA,CAAqB,GAAA,CAAI,UAAU,YAAY,CAAA;AAC/C,EAAA,OAAO,YAAA;AACX;AAGA,IAAM,qBAAA,uBAA4B,GAAA,EAAsD;AAGxF,IAAI,OAAO,WAAW,WAAA,EAAa;AAC/B,EAAC,OAAe,aAAA,GAAgBA,uBAAA;AAChC,EAAC,MAAA,CAAe,KAAA,GAAS,MAAA,CAAe,KAAA,IAASA,uBAAA;AACrD;AAEA,eAAsB,oBAAA,CAClB,OAAA,EACA,UAAA,EACA,YAAA,EACA,QAAA,EACwC;AACxC,EAAA,IAAI,CAAC,QAAA,EAAU;AACX,IAAA,OAAO,IAAA;AAAA,EACX;AAEA,EAAA,MAAM,QAAA,GAAW,CAAA,EAAG,UAAU,CAAA,CAAA,EAAI,YAAY,CAAA,CAAA;AAG9C,EAAA,MAAM,YAAA,GAAe,qBAAA,CAAsB,GAAA,CAAI,QAAQ,CAAA;AACvD,EAAA,IAAI,YAAA,EAAc;AACd,IAAA,OAAO,YAAA;AAAA,EACX;AAGA,EAAA,MAAM,eAAe,YAAY;AAC7B,IAAA,IAAI;AAEA,MAAA,MAAM,UAAA,GAAa,GAAG,OAAA,CAAQ,OAAA,CAAQ,OAAO,EAAE,CAAC,aAAa,QAAQ,CAAA,CAAA;AAErE,MAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,UAAA,EAAY;AAAA,QAChC,MAAA,EAAQ,KAAA;AAAA,QACR,OAAA,EAAS,EAAE,MAAA,EAAQ,iBAAA,EAAkB;AAAA,QACrC,WAAA,EAAa;AAAA,OAChB,CAAA;AAED,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACT,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,KAAA,EAAQ,GAAA,CAAI,MAAM,CAAA,CAAE,CAAA;AAAA,MACxC;AAEA,MAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAK5B,MAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AAC/B,QAAC,MAAA,CAAe,KAAA,GAAS,MAAA,CAAe,KAAA,IAASA,uBAAA;AAAA,MACrD;AAGA,MAAA,MAAM,QAAA,GAAW,IAAI,QAAA,CAAS;AAAA;AAAA,gBAAA,EAExB,IAAI;AAAA;AAAA,YAAA,CAET,CAAA;AAED,MAAA,MAAM,SAAS,QAAA,EAAS;AAGxB,MAAA,MAAM,gBAAA,GAAmB,QAAQ,OAAA,IAAW,MAAA;AAE5C,MAAA,IAAI,OAAO,qBAAqB,UAAA,EAAY;AACxC,QAAA,OAAO,gBAAA;AAAA,MACX;AAEA,MAAA,OAAA,CAAQ,IAAA,CAAK,gDAAgD,MAAM,CAAA;AACnE,MAAA,OAAO,IAAA;AAAA,IACX,SAAS,CAAA,EAAG;AACR,MAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,2CAAA,EAA8C,CAAC,CAAA,CAAE,CAAA;AAC9D,MAAA,OAAO,IAAA;AAAA,IACX,CAAA,SAAE;AAEE,MAAA,qBAAA,CAAsB,OAAO,QAAQ,CAAA;AAAA,IACzC;AAAA,EACJ,CAAA,GAAG;AAGH,EAAA,qBAAA,CAAsB,GAAA,CAAI,UAAU,WAAW,CAAA;AAC/C,EAAA,OAAO,WAAA;AACX;;;ACvPA,IAAM,aAAA,uBAAoB,GAAA,EAKvB;AAGH,IAAI,kBAAA,GAAqB,KAAA;AAGzB,IAAM,aAAA,uBAAoB,GAAA,EAAoB;AAC9C,IAAM,WAAA,GAAc,GAAA;AAMpB,SAAS,oBAAoB,OAAA,EAKpB;AAEL,EAAA,MAAM,aAAA,GAAgB,OAAA,CAAQ,OAAA,CAAQ,wBAAwB,CAAA;AAE9D,EAAA,IAAI,CAAC,eAAe,OAAO,IAAA;AAE3B,EAAA,MAAM,UAAA,GAAa,aAAA,CAAc,YAAA,CAAa,sBAAsB,CAAA;AACpE,EAAA,IAAI,CAAC,YAAY,OAAO,IAAA;AAGxB,EAAA,MAAM,QAAA,GAAW,GAAG,UAAU,CAAA,CAAA;AAC9B,EAAA,MAAM,MAAA,GAAS,aAAA,CAAc,GAAA,CAAI,QAAQ,CAAA;AACzC,EAAA,IAAI,QAAQ,OAAO,MAAA;AAGnB,EAAA,MAAM,YAAA,GAAe,aAAA,CAAc,YAAA,CAAa,2BAA2B,CAAA;AAC3E,EAAA,MAAM,YAAA,GAAe,aAAA,CAAc,YAAA,CAAa,2BAA2B,CAAA,IAAK,SAAA;AAChF,EAAA,MAAM,UAAA,GAAa,cAAc,YAAA,CAAa,0BAA0B,KACpD,OAAO,MAAA,KAAW,WAAA,IAAgB,MAAA,CAAe,YAAA,IAClD,4BAAA;AAEnB,EAAA,MAAM,QAAA,GAAW;AAAA,IACb,UAAA;AAAA,IACA,cAAc,YAAA,IAAgB,IAAA;AAAA,IAC9B,YAAA;AAAA,IACA;AAAA,GACJ;AAGA,EAAA,aAAA,CAAc,GAAA,CAAI,UAAU,QAAQ,CAAA;AACpC,EAAA,OAAO,QAAA;AACX;AAMA,SAAS,oBAAoB,KAAA,EAAyB;AAClD,EAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AACrB,EAAA,IAAI,CAAC,MAAA,EAAQ;AAGb,EAAA,MAAM,QAAA,GAAW,oBAAoB,MAAM,CAAA;AAC3C,EAAA,IAAI,CAAC,QAAA,EAAU;AAGf,EAAA,MAAMC,IAAAA,GAAM,KAAK,GAAA,EAAI;AACrB,EAAA,MAAM,SAAA,GAAY,aAAA,CAAc,GAAA,CAAI,QAAA,CAAS,UAAU,CAAA,IAAK,CAAA;AAC5D,EAAA,IAAIA,IAAAA,GAAM,YAAY,WAAA,EAAa;AAC/B,IAAA;AAAA,EACJ;AACA,EAAA,aAAA,CAAc,GAAA,CAAI,QAAA,CAAS,UAAA,EAAYA,IAAG,CAAA;AAG1C,EAAA,MAAM,SAAA,GAAY,iBAAiB,KAAK,CAAA;AAOxC,EAAA,MAAM,iBAAA,GAAoB,OAAO,YAAA,CAAa,mBAAmB,KACvC,MAAA,CAAO,OAAA,CAAQ,qBAAqB,CAAA,KAAM,IAAA;AAEpE,EAAA,MAAM,WAAA,GAAc,cAAc,MAAA,IAAa,iBAAA;AAE/C,EAAA,IAAI,CAAC,WAAA,EAAa;AAoBd,IAAA;AAAA,EACJ;AAGA,EAAA,KAAK,UAAA;AAAA,IACD,QAAA,CAAS,UAAA;AAAA,IACT,QAAA,CAAS,UAAA;AAAA,IACT,OAAA;AAAA,IACA,QAAA,CAAS,YAAA;AAAA,IACT,SAAS,YAAA,IAAgB,MAAA;AAAA,IACzB;AAAA,GACJ;AACJ;AAMO,SAAS,yBAAA,GAAkC;AAC9C,EAAA,IAAI,kBAAA,EAAoB;AACpB,IAAA,OAAA,CAAQ,KAAK,mDAAmD,CAAA;AAChE,IAAA;AAAA,EACJ;AAEA,EAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AAEjC,IAAA;AAAA,EACJ;AAIA,EAAA,QAAA,CAAS,gBAAA,CAAiB,OAAA,EAAS,mBAAA,EAAqB,IAAI,CAAA;AAE5D,EAAA,kBAAA,GAAqB,IAAA;AACrB,EAAA,OAAA,CAAQ,IAAI,oDAAoD,CAAA;AACpE;AAKO,SAAS,4BAAA,GAAqC;AACjD,EAAA,IAAI,CAAC,kBAAA,EAAoB;AAEzB,EAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AACjC,IAAA,QAAA,CAAS,mBAAA,CAAoB,OAAA,EAAS,mBAAA,EAAqB,IAAI,CAAA;AAAA,EACnE;AAEA,EAAA,kBAAA,GAAqB,KAAA;AACrB,EAAA,aAAA,CAAc,KAAA,EAAM;AACpB,EAAA,aAAA,CAAc,KAAA,EAAM;AACxB;AAMO,SAAS,sBAAA,CACZ,YACA,QAAA,EAKI;AACJ,EAAA,MAAM,QAAA,GAAW,aAAA,CAAc,GAAA,CAAI,UAAU,CAAA;AAC7C,EAAA,IAAI,QAAA,EAAU;AACV,IAAA,aAAA,CAAc,IAAI,UAAA,EAAY;AAAA,MAC1B,GAAG,QAAA;AAAA,MACH,GAAG;AAAA,KACN,CAAA;AAAA,EACL;AACJ;AAKO,SAAS,kBAAA,GAA2B;AACvC,EAAA,aAAA,CAAc,KAAA,EAAM;AACxB;;;ACnLA,IAAM,aAAA,GAAgBC,qBAAyC,IAAI,CAAA;AAgC5D,SAAS,cAAA,CAAe;AAAA,EAC3B,UAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA,EAAa,mBAAA;AAAA,EACb,YAAA,EAAc,oBAAA;AAAA,EACd;AACJ,CAAA,EAAwB;AACpB,EAAA,MAAM,YAAA,GAAeC,eAA4B,MAAM;AAEnD,IAAA,MAAM,qBACF,UAAA,IACC,OAAO,0QAAgB,WAAA,IACnB,WAAyB,eAAA,IAC7B,OAAO,eAAe,WAAA,IAClB,UAAA,CAAmB,SAAS,GAAA,EAAK,sBAAA,IACrC,OAAO,MAAA,KAAW,WAAA,IAAe,OAAO,YAAA,IACzC,4BAAA;AAGJ,IAAA,MAAM,WAAA,GAAc,uBAAuB,iBAAA,EAAkB;AAG7D,IAAA,MAAM,uBACF,oBAAA,IACC,OAAO,eAAe,WAAA,IAClB,UAAA,CAAmB,SAAS,GAAA,EAAK,uBAAA,IACrC,OAAO,qQAAA,KAAgB,WAAA,IACnB,SAAoB,EAAK,gBAAA,IAC7B,OAAO,MAAA,KAAW,WAAA,IAAgB,OAAe,aAAA,IAClD,MAAA;AAEJ,IAAA,OAAO;AAAA,MACH,UAAA,EAAY,kBAAA;AAAA,MACZ,WAAA;AAAA,MACA,SAAA;AAAA,MACA,YAAA,EAAc;AAAA,KAClB;AAAA,EACJ,GAAG,CAAC,UAAA,EAAY,SAAA,EAAW,mBAAA,EAAqB,oBAAoB,CAAC,CAAA;AAGrE,EAAAC,gBAAA,CAAU,MAAM;AACZ,IAAA,yBAAA,EAA0B;AAG1B,IAAA,OAAO,MAAM;AACT,MAAA,4BAAA,EAA6B;AAAA,IACjC,CAAA;AAAA,EACJ,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,uBACIJ,wBAAA,aAAA,CAAC,aAAA,CAAc,UAAd,EAAuB,KAAA,EAAO,gBAC1B,QACL,CAAA;AAER;AAEO,SAAS,gBAAA,GAAuC;AACnD,EAAA,MAAM,OAAA,GAAUK,kBAAW,aAAa,CAAA;AACxC,EAAA,IAAI,CAAC,OAAA,EAAS;AACV,IAAA,MAAM,IAAI,KAAA;AAAA,MACN;AAAA,KACJ;AAAA,EACJ;AACA,EAAA,OAAO,OAAA;AACX;ACzGO,SAAS,qBAAqB,KAAA,EAA4B;AAC7D,EAAA,OAAOL,uBAAAA,CAAM,aAAA,CAAc,cAAA,EAAoB,KAAK,CAAA;AACxD;ACwDO,SAAS,gBAAA,GAA2C;AACvD,EAAA,MAAM,EAAE,UAAA,EAAW,GAAI,gBAAA,EAAiB;AAExC,EAAA,MAAM,UAAA,GAAaM,kBAAA;AAAA,IACf,CACI,OACA,OAAA,KAMC;AACD,MAAA,MAAM,IAAA,GAAO,gBAAA,CAAiB,KAAA,IAAS,MAAS,CAAA;AAChD,MAAA,IAAI,CAAC,OAAA,EAAS,KAAA,IAAS,KAAA,IAAS,CAAC,IAAA,EAAM;AACnC,QAAA,OAAO,KAAA;AAAA,MACX;AAEA,MAAA,MAAM,aAAa,OAAA,EAAS,UAAA;AAC5B,MAAA,MAAM,YAAA,GAAe,SAAS,YAAA,IAAgB,SAAA;AAE9C,MAAA,IAAI,CAAC,UAAA,EAAY;AACb,QAAA,OAAA,CAAQ,IAAA;AAAA,UACJ;AAAA,SACJ;AACA,QAAA,OAAO,KAAA;AAAA,MACX;AAEA,MAAA,KAAK,UAAA;AAAA,QACD,UAAA;AAAA,QACA,UAAA;AAAA,QACA,OAAA;AAAA,QACA,YAAA;AAAA,QACA,MAAA;AAAA,QACA,EAAE,GAAG,IAAA,EAAM,GAAG,SAAS,UAAA;AAAW,OACtC;AACA,MAAA,OAAO,IAAA;AAAA,IACX,CAAA;AAAA,IACA,CAAC,UAAU;AAAA,GACf;AAEA,EAAA,MAAM,WAAA,GAAcA,kBAAA;AAAA,IAChB,CACI,UAAA,EACA,UAAA,EACA,eAAuB,SAAA,EACvB,UAAA,GAAkC,EAAC,KAClC;AACD,MAAA,KAAK,UAAA;AAAA,QACD,UAAA;AAAA,QACA,UAAA;AAAA,QACA,UAAA;AAAA,QACA,YAAA;AAAA,QACA,MAAA;AAAA,QACA;AAAA,OACJ;AAAA,IACJ,CAAA;AAAA,IACA,CAAC,UAAU;AAAA,GACf;AAEA,EAAA,MAAM,eAAA,GAAkBA,kBAAA;AAAA,IACpB,CACI,UAAA,EACA,YAAA,GAAuB,SAAA,EACvB,YAAA,KACC;AACD,MAAA,KAAK,UAAA;AAAA,QACD,UAAA;AAAA,QACA,UAAA;AAAA,QACA,OAAA;AAAA,QACA,YAAA;AAAA,QACA;AAAA,OACJ;AAAA,IACJ,CAAA;AAAA,IACA,CAAC,UAAU;AAAA,GACf;AAEA,EAAA,OAAO;AAAA,IACH,UAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACJ;AACJ;;;ACtJA,IAAM,MAAA,GAAS,CAAA,GAAI,EAAA,GAAK,EAAA,GAAK,GAAA;AAQtB,SAAS,QAAQ,CAAA,EAAuB;AAC3C,EAAA,IAAI;AACA,IAAA,MAAM,GAAA,GAAM,YAAA,CAAa,OAAA,CAAQ,CAAC,CAAA;AAClC,IAAA,OAAO,GAAA,GAAM,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA,GAAI,IAAA;AAAA,EACnC,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,IAAA;AAAA,EACX;AACJ;AAEO,SAAS,OAAA,CAAQ,GAAW,CAAA,EAAQ;AACvC,EAAA,IAAI;AACA,IAAA,YAAA,CAAa,OAAA,CAAQ,CAAA,EAAG,IAAA,CAAK,SAAA,CAAU,CAAC,CAAC,CAAA;AAAA,EAC7C,CAAA,CAAA,MAAQ;AAAA,EAAE;AACd;AAEO,SAAS,GAAA,GAAM;AAClB,EAAA,OAAO,KAAK,GAAA,EAAI;AACpB;AAEO,SAAS,MAAM,EAAA,EAAY;AAC9B,EAAA,OAAO,GAAA,KAAQ,EAAA,IAAM,MAAA;AACzB;AAEO,IAAM,GAAA,GAAM,CAAC,UAAA,KAAuB,CAAA,iBAAA,EAAoB,UAAU,CAAA,CAAA;AAClE,IAAM,YAAY,CAAC,UAAA,EAAoB,UAC1C,CAAA,gBAAA,EAAmB,UAAU,IAAI,KAAK,CAAA,CAAA;AAEnC,SAAS,WAAW,UAAA,EAAmC;AAC1D,EAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,GAAA,CAAI,UAAU,CAAC,CAAA;AACjC,EAAA,OAAO,CAAA,IAAK,KAAA,CAAM,CAAA,CAAE,EAAE,IAAI,CAAA,GAAI,IAAA;AAClC;AAEO,SAAS,WAAA,CACZ,UAAA,EACA,aAAA,EACA,KAAA,EACF;AACE,EAAA,OAAA,CAAQ,GAAA,CAAI,UAAU,CAAA,EAAG,EAAE,eAAe,KAAA,EAAO,EAAA,EAAI,GAAA,EAAI,EAAa,CAAA;AAC1E;AAEA,IAAM,SAAA,uBAAgB,GAAA,EAAY;AAE3B,SAAS,eAAA,CAAgB,YAAoB,KAAA,EAAwB;AACxE,EAAA,MAAM,GAAA,GAAM,SAAA,CAAU,UAAA,EAAY,KAAK,CAAA;AACvC,EAAA,IAAI,SAAA,CAAU,GAAA,CAAI,GAAG,CAAA,EAAG,OAAO,IAAA;AAC/B,EAAA,IAAI;AACA,IAAA,MAAM,GAAA,GAAM,YAAA,CAAa,OAAA,CAAQ,GAAG,CAAA;AACpC,IAAA,IAAI,CAAC,KAAK,OAAO,KAAA;AACjB,IAAA,MAAM,EAAA,GAAK,OAAO,GAAG,CAAA;AACrB,IAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,EAAE,CAAA,IAAK,EAAA,IAAM,GAAG,OAAO,KAAA;AAC5C,IAAA,IAAI,GAAA,EAAI,GAAI,EAAA,GAAK,MAAA,EAAQ;AACrB,MAAA,YAAA,CAAa,WAAW,GAAG,CAAA;AAC3B,MAAA,OAAO,KAAA;AAAA,IACX;AACA,IAAA,SAAA,CAAU,IAAI,GAAG,CAAA;AACjB,IAAA,OAAO,IAAA;AAAA,EACX,CAAA,CAAA,MAAQ;AACJ,IAAA,OAAO,KAAA;AAAA,EACX;AACJ;AAEO,SAAS,gBAAA,CAAiB,YAAoB,KAAA,EAAe;AAChE,EAAA,MAAM,GAAA,GAAM,SAAA,CAAU,UAAA,EAAY,KAAK,CAAA;AACvC,EAAA,SAAA,CAAU,IAAI,GAAG,CAAA;AACjB,EAAA,IAAI;AACA,IAAA,YAAA,CAAa,OAAA,CAAQ,GAAA,EAAK,GAAA,EAAI,CAAE,UAAU,CAAA;AAAA,EAC9C,CAAA,CAAA,MAAQ;AAAA,EAAE;AACd;;;AClBO,SAAS,aAAA,CACZ,YACA,OAAA,EACmB;AACnB,EAAA,MAAM,EAAE,UAAA,EAAW,GAAI,gBAAA,EAAiB;AACxC,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIC,gBAGlB,IAAI,CAAA;AACd,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,gBAAS,IAAI,CAAA;AAC/C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,gBAAuB,IAAI,CAAA;AAErD,EAAA,MAAM,mBAAA,GAAsB,SAAS,mBAAA,KAAwB,KAAA;AAG7D,EAAAH,iBAAU,MAAM;AACZ,IAAA,IAAI,KAAA,GAAQ,IAAA;AAEZ,IAAA,MAAM,MAAA,GAAS,WAAW,UAAU,CAAA;AACpC,IAAA,IAAI,MAAA,EAAQ;AACR,MAAA,SAAA,CAAU,EAAE,aAAA,EAAe,MAAA,CAAO,eAAe,KAAA,EAAO,MAAA,CAAO,OAAO,CAAA;AACtE,MAAA,YAAA,CAAa,KAAK,CAAA;AAAA,IACtB,CAAA,MAAO;AACH,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAA,CAAC,YAAY;AACT,QAAA,IAAI;AACA,UAAA,MAAM,EAAE,aAAA,EAAe,KAAA,EAAM,GAAI,MAAM,aAAA;AAAA,YACnC,UAAA;AAAA,YACA;AAAA,WACJ;AACA,UAAA,IAAI,CAAC,KAAA,EAAO;AACZ,UAAA,WAAA,CAAY,UAAA,EAAY,eAAe,KAAK,CAAA;AAC5C,UAAA,SAAA,CAAU,EAAE,aAAA,EAAe,KAAA,EAAO,CAAA;AAClC,UAAA,QAAA,CAAS,IAAI,CAAA;AAAA,QACjB,SAAS,CAAA,EAAG;AACR,UAAA,IAAI,CAAC,KAAA,EAAO;AACZ,UAAA,MAAM,GAAA,GAAM,aAAa,KAAA,GAAQ,CAAA,GAAI,IAAI,KAAA,CAAM,MAAA,CAAO,CAAC,CAAC,CAAA;AACxD,UAAA,QAAA,CAAS,GAAG,CAAA;AACZ,UAAA,SAAA,CAAU;AAAA,YACN,aAAA,EAAe,OAAO,UAAU,CAAA,CAAA;AAAA,YAChC,KAAA,EAAO;AAAA,WACV,CAAA;AAAA,QACL,CAAA,SAAE;AACE,UAAA,IAAI,KAAA,EAAO;AACP,YAAA,YAAA,CAAa,KAAK,CAAA;AAAA,UACtB;AAAA,QACJ;AAAA,MACJ,CAAA,GAAG;AAAA,IACP;AAEA,IAAA,OAAO,MAAM;AACT,MAAA,KAAA,GAAQ,KAAA;AAAA,IACZ,CAAA;AAAA,EACJ,CAAA,EAAG,CAAC,UAAA,EAAY,UAAU,CAAC,CAAA;AAG3B,EAAAA,iBAAU,MAAM;AACZ,IAAA,IAAI,CAAC,mBAAA,IAAuB,CAAC,MAAA,EAAQ;AAErC,IAAA,MAAM,MAAM,MAAA,CAAO,aAAA;AACnB,IAAA,MAAM,GAAA,GAAM,OAAO,KAAA,IAAS,SAAA;AAC5B,IAAA,IAAI,CAAC,GAAA,EAAK;AAGV,IAAA,IAAI,eAAA,CAAgB,UAAA,EAAY,GAAG,CAAA,EAAG;AACtC,IAAA,gBAAA,CAAiB,YAAY,GAAG,CAAA;AAChC,IAAA,KAAK,UAAA,CAAW,UAAA,EAAY,UAAA,EAAY,OAAA,EAAS,KAAK,GAAG,CAAA;AAAA,EAC7D,CAAA,EAAG,CAAC,UAAA,EAAY,MAAA,EAAQ,eAAe,MAAA,EAAQ,KAAA,EAAO,UAAA,EAAY,mBAAmB,CAAC,CAAA;AAEtF,EAAA,MAAM,UAAA,GAAaE,kBAAAA;AAAA,IACf,CAAC,KAAA,KAA8B;AAC3B,MAAY,MAAA,EAAQ;AACpB,MAAA,MAAM,GAAA,GAAM,QAAQ,KAAA,IAAS,SAAA;AAC7B,MAAA,MAAM,IAAA,GAAO,SACN,MAAM;AACL,QAAA,MAAM,YAAY,KAAA,CAAM,MAAA;AACxB,QAAA,IAAI,CAAC,WAAW,OAAO,MAAA;AACvB,QAAA,MAAM,aAAa,SAAA,CAAU,OAAA;AAAA,UACzB;AAAA,SACJ;AACA,QAAA,IAAI,CAAC,YAAY,OAAO,MAAA;AACxB,QAAA,MAAME,KAAAA,GAA4B;AAAA,UAC9B,YAAY,UAAA,CAAW;AAAA,SAC3B;AACA,QAAA,IAAI,UAAA,CAAW,EAAA,EAAIA,KAAAA,CAAK,YAAY,UAAA,CAAW,EAAA;AAC/C,QAAA,MAAM,IAAA,GAAO,UAAA,CAAW,YAAA,CAAa,wBAAwB,CAAA;AAC7D,QAAA,IAAI,IAAA,EAAMA,KAAAA,CAAK,eAAA,GAAkB,IAAA;AACjC,QAAA,MAAM,IAAA,GAAO,UAAA,CAAW,WAAA,EAAa,IAAA,EAAK;AAC1C,QAAA,IAAI,MAAMA,KAAAA,CAAK,cAAc,IAAA,CAAK,KAAA,CAAM,GAAG,GAAG,CAAA;AAC9C,QAAA,OAAOA,KAAAA;AAAA,MACX,IAAG,GACD,MAAA;AAEN,MAAA,KAAK,WAAW,UAAA,EAAY,UAAA,EAAY,OAAA,EAAS,GAAA,EAAK,QAAW,IAAI,CAAA;AAAA,IACzE,CAAA;AAAA,IACA,CAAC,UAAA,EAAY,MAAA,EAAQ,aAAA,EAAe,MAAA,EAAQ,OAAO,UAAU;AAAA,GACjE;AAEA,EAAA,OAAO;AAAA,IACH,YAAA,EAAc,QAAQ,KAAA,IAAS,SAAA;AAAA,IAC/B,YAAA,EAAc,QAAQ,aAAA,IAAiB,IAAA;AAAA,IACvC,SAAA;AAAA,IACA,KAAA;AAAA,IACA;AAAA,GACJ;AACJ;ACjIO,SAAS,cAAA,CACZ,SACA,OAAA,EACgE;AAEhE,EAAA,IAAI,CAAC,OAAA,EAAS;AACV,IAAA,OAAA,CAAQ,MAAM,wDAAwD,CAAA;AACtE,IAAA,QAAQ,CAAC,KAAA,KAAa,IAAA;AAAA,EAC1B;AAEA,EAAA,IAAI,CAAC,OAAA,IAAW,OAAO,OAAA,KAAY,QAAA,EAAU;AACzC,IAAA,OAAA,CAAQ,MAAM,8CAA8C,CAAA;AAC5D,IAAA,OAAO,OAAA;AAAA,EACX;AAEA,EAAA,MAAM,SAAA,GAAY,CAAC,CAAC,OAAA,CAAQ,aAAA;AAC5B,EAAA,MAAM,SAAA,GAAY,CAAC,EAAE,OAAA,CAAQ,cAAc,OAAA,CAAQ,QAAA,CAAA;AAEnD,EAAA,IAAI,CAAC,SAAA,IAAa,CAAC,SAAA,EAAW;AAC1B,IAAA,OAAA,CAAQ,KAAK,4DAA4D,CAAA;AACzE,IAAA,OAAO,OAAA;AAAA,EACX;AAEA,EAAA,MAAM,gBAAA,GAAmB,OAAA;AAEzB,EAAA,SAAS,QAAQ,KAAA,EAAU;AAMvB,IAAA,MAAM,UAAU,gBAAA,EAAiB;AACjC,IAAA,MAAM,UAAA,GAAa,SAAS,UAAA,IAAc,4BAAA;AAC1C,IAAA,MAAM,sBAAsB,OAAA,EAAS,YAAA;AAGrC,IAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAID,gBAGlB,IAAI,CAAA;AACd,IAAA,MAAM,CAAC,aAAA,EAAe,gBAAgB,CAAA,GAAIA,gBAAS,SAAS,CAAA;AAC5D,IAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIA,gBAGlB,IAAI,CAAA;AAGd,IAAA,MAAM,YAAA,GAAe,QAAQ,YAAA,IAAgB,mBAAA;AAC7C,IAAA,MAAM,UAAA,GAAa,SAAA,GAAY,MAAA,EAAQ,UAAA,GAAa,OAAA,CAAQ,UAAA;AAI5D,IAAAH,iBAAU,MAAM;AACZ,MAAA,IAAI,CAAC,SAAA,EAAW;AAChB,MAAA,IAAI,CAAC,YAAA,EAAc;AACf,QAAA,OAAA,CAAQ,KAAK,4DAA4D,CAAA;AACzE,QAAA,gBAAA,CAAiB,KAAK,CAAA;AACtB,QAAA;AAAA,MACJ;AAEA,MAAA,IAAI,KAAA,GAAQ,IAAA;AACZ,MAAA,gBAAA,CAAiB,IAAI,CAAA;AAErB,MAAA,CAAC,YAAY;AACT,QAAA,IAAI;AACA,UAAA,MAAM,kBAAkB,MAAM,8BAAA;AAAA,YAC1B,UAAA;AAAA,YACA,YAAA;AAAA,YACA,OAAA,CAAQ;AAAA,WACZ;AAEA,UAAA,IAAI,CAAC,KAAA,EAAO;AAEZ,UAAA,IAAI,CAAC,eAAA,EAAiB;AAClB,YAAA,SAAA,CAAU,IAAI,CAAA;AACd,YAAA,gBAAA,CAAiB,KAAK,CAAA;AACtB,YAAA;AAAA,UACJ;AAEA,UAAA,MAAM,iBAAA,GAA8D;AAAA,YAChE,OAAA,EAAS;AAAA,WACb;AAEA,UAAA,KAAA,MAAW,CAACK,QAAO,WAAW,CAAA,IAAK,OAAO,OAAA,CAAQ,eAAA,CAAgB,QAAQ,CAAA,EAAG;AACzE,YAAA,IAAIA,WAAU,SAAA,EAAW;AACzB,YAAA,IAAI,aAAa,SAAA,EAAW;AACxB,cAAA,IAAI;AACA,gBAAA,MAAM,cAAc,MAAM,oBAAA;AAAA,kBACtB,UAAA;AAAA,kBACA,eAAA,CAAgB,WAAA;AAAA,kBAChB,WAAA,CAAY,aAAA;AAAA,kBACZ,WAAA,CAAY;AAAA,iBAChB;AACA,gBAAA,IAAI,WAAA,IAAe,OAAO,WAAA,KAAgB,UAAA,IAAc,KAAA,EAAO;AAC3D,kBAAA,iBAAA,CAAkBA,MAAK,CAAA,GAAI,WAAA;AAAA,gBAC/B;AAAA,cACJ,SAAS,CAAA,EAAG;AACR,gBAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,gCAAA,EAAmCA,MAAK,CAAA,CAAA,CAAA,EAAK,CAAC,CAAA;AAAA,cAC/D;AAAA,YACJ;AAAA,UACJ;AAEA,UAAA,IAAI,KAAA,EAAO;AACP,YAAA,SAAA,CAAU;AAAA,cACN,YAAY,eAAA,CAAgB,WAAA;AAAA,cAC5B,QAAA,EAAU;AAAA,aACb,CAAA;AACD,YAAA,gBAAA,CAAiB,KAAK,CAAA;AAAA,UAC1B;AAAA,QACJ,SAAS,CAAA,EAAG;AACR,UAAA,OAAA,CAAQ,IAAA,CAAK,6CAA6C,CAAC,CAAA;AAC3D,UAAA,IAAI,KAAA,EAAO;AACP,YAAA,SAAA,CAAU,IAAI,CAAA;AACd,YAAA,gBAAA,CAAiB,KAAK,CAAA;AAAA,UAC1B;AAAA,QACJ;AAAA,MACJ,CAAA,GAAG;AAEH,MAAA,OAAO,MAAM;AAAE,QAAA,KAAA,GAAQ,KAAA;AAAA,MAAO,CAAA;AAAA,IAClC,GAAG,CAAC,SAAA,EAAW,QAAQ,aAAA,EAAe,YAAA,EAAc,UAAU,CAAC,CAAA;AAG/D,IAAAL,iBAAU,MAAM;AACZ,MAAA,IAAI,CAAC,UAAA,EAAY;AACjB,MAAA,IAAI,aAAa,aAAA,EAAe;AAEhC,MAAA,IAAI,KAAA,GAAQ,IAAA;AACZ,MAAA,MAAM,MAAA,GAAS,WAAW,UAAU,CAAA;AAEpC,MAAA,IAAI,MAAA,EAAQ;AACR,QAAA,SAAA,CAAU;AAAA,UACN,eAAe,MAAA,CAAO,aAAA;AAAA,UACtB,OAAO,MAAA,CAAO;AAAA,SACjB,CAAA;AAAA,MACL,CAAA,MAAO;AACH,QAAA,CAAC,YAAY;AACT,UAAA,IAAI;AACA,YAAA,MAAM,EAAE,eAAe,KAAA,EAAAK,MAAAA,KAAU,MAAM,aAAA,CAAc,YAAY,UAAU,CAAA;AAC3E,YAAA,IAAI,CAAC,KAAA,EAAO;AACZ,YAAA,WAAA,CAAY,UAAA,EAAY,eAAeA,MAAK,CAAA;AAC5C,YAAA,SAAA,CAAU,EAAE,aAAA,EAAe,KAAA,EAAAA,MAAAA,EAAO,CAAA;AAAA,UACtC,SAAS,CAAA,EAAG;AACR,YAAA,IAAI,CAAC,KAAA,EAAO;AACZ,YAAA,SAAA,CAAU;AAAA,cACN,aAAA,EAAe,OAAO,UAAU,CAAA,CAAA;AAAA,cAChC,KAAA,EAAO;AAAA,aACV,CAAA;AAAA,UACL;AAAA,QACJ,CAAA,GAAG;AAAA,MACP;AAEA,MAAA,OAAO,MAAM;AAAE,QAAA,KAAA,GAAQ,KAAA;AAAA,MAAO,CAAA;AAAA,IAClC,GAAG,CAAC,UAAA,EAAY,UAAA,EAAY,SAAA,EAAW,aAAa,CAAC,CAAA;AAGrD,IAAAL,iBAAU,MAAM;AACZ,MAAA,IAAI,CAAC,UAAA,EAAY;AACjB,MAAA,MAAM,GAAA,GAAM,QAAQ,KAAA,IAAS,SAAA;AAC7B,MAAA,IAAI,CAAC,GAAA,IAAO,eAAA,CAAgB,UAAA,EAAY,GAAG,CAAA,EAAG;AAC9C,MAAA,gBAAA,CAAiB,YAAY,GAAG,CAAA;AAChC,MAAA,KAAK,WAAW,UAAA,EAAY,UAAA,EAAY,OAAA,EAAS,GAAA,EAAK,QAAQ,aAAa,CAAA;AAAA,IAC/E,CAAA,EAAG,CAAC,UAAA,EAAY,MAAA,EAAQ,eAAe,MAAA,EAAQ,KAAA,EAAO,UAAU,CAAC,CAAA;AAGjE,IAAA,MAAM,UAAA,GAAaE,kBAAAA;AAAA,MACf,CAAC,OAA2B,IAAA,KAA+B;AACvD,QAAA,IAAI,CAAC,YAAY,OAAO,KAAA;AACxB,QAAA,MAAM,GAAA,GAAM,QAAQ,KAAA,IAAS,SAAA;AAC7B,QAAA,MAAM,IAAA,GAAO,gBAAA,CAAiB,KAAA,IAAS,MAAS,CAAA;AAChD,QAAA,IAAI,CAAC,IAAA,EAAM,KAAA,IAAS,KAAA,IAAS,CAAC,MAAM,OAAO,KAAA;AAC3C,QAAA,KAAK,WAAW,UAAA,EAAY,UAAA,EAAY,OAAA,EAAS,GAAA,EAAK,QAAW,IAAI,CAAA;AACrE,QAAA,OAAO,IAAA;AAAA,MACX,CAAA;AAAA,MACA,CAAC,UAAA,EAAY,MAAA,EAAQ,aAAA,EAAe,MAAA,EAAQ,OAAO,UAAU;AAAA,KACjE;AAOA,IAAA,IAAI,SAAA,KAAc,aAAA,IAAiB,CAAC,MAAA,IAAU,CAAC,UAAA,CAAA,EAAa;AACxD,MAAA,OAAON,uBAAAA,CAAM,aAAA,CAAc,gBAAA,EAAyB,KAAY,CAAA;AAAA,IACpE;AAGA,IAAA,IAAI,CAAC,UAAA,EAAY;AACb,MAAA,OAAOA,uBAAAA,CAAM,aAAA,CAAc,gBAAA,EAAyB,KAAY,CAAA;AAAA,IACpE;AAGA,IAAA,MAAM,QAAA,GAAqD,EAAE,OAAA,EAAS,gBAAA,EAAiB;AAEvF,IAAA,IAAI,SAAA,IAAa,QAAQ,QAAA,EAAU;AAC/B,MAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,MAAA,CAAO,QAAQ,CAAA,EAAG;AACxD,QAAA,IAAI,GAAA,KAAQ,SAAA,IAAa,KAAA,IAAS,OAAO,UAAU,UAAA,EAAY;AAC3D,UAAA,QAAA,CAAS,GAAG,CAAA,GAAI,KAAA;AAAA,QACpB;AAAA,MACJ;AAAA,IACJ,CAAA,MAAA,IAAW,CAAC,SAAA,IAAa,OAAA,CAAQ,QAAA,EAAU;AACvC,MAAA,KAAA,MAAW,CAAC,KAAK,KAAK,CAAA,IAAK,OAAO,OAAA,CAAQ,OAAA,CAAQ,QAAQ,CAAA,EAAG;AACzD,QAAA,IAAI,GAAA,KAAQ,SAAA,IAAa,KAAA,IAAS,OAAO,UAAU,UAAA,EAAY;AAC3D,UAAA,QAAA,CAAS,GAAG,CAAA,GAAI,KAAA;AAAA,QACpB;AAAA,MACJ;AAAA,IACJ;AAGA,IAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,SAAA;AAC/B,IAAA,MAAM,OAAA,GAAU,QAAA,CAAS,KAAK,CAAA,IAAK,SAAS,OAAA,IAAW,gBAAA;AAEvD,IAAA,uBACIA,uBAAAA,CAAA,aAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACG,OAAA,EAAS,CAAC,KAAA,KAAU;AAGhB,UAAA,UAAA,CAAW,KAAK,CAAA;AAAA,QACpB,CAAA;AAAA,QACA,sBAAA,EAAsB,UAAA;AAAA,QACtB,2BAAA,EAA2B,QAAQ,aAAA,IAAiB,EAAA;AAAA,QACpD,2BAAA,EAA2B,KAAA;AAAA,QAC3B,0BAAA,EAA0B;AAAA,OAAA;AAAA,MAEzBA,uBAAAA,CAAM,cAAc,OAAA,EAAS;AAAA,QAC1B,GAAA,EAAK,CAAA,EAAG,UAAU,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAAA,QAC3B,GAAI,KAAA;AAAA,QACJ,MAAA,EAAQ,EAAE,UAAA,EAAY,MAAM,UAAA,CAAW,MAAM,EAAE,KAAA,EAAO,IAAA,EAAM,CAAA;AAAE,OACjE;AAAA,KACL;AAAA,EAER;AAEA,EAAA,OAAA,CAAQ,cAAc,CAAA,eAAA,EAAkB,OAAA,CAAQ,WAAA,IAAe,OAAA,CAAQ,QAAQ,WAAW,CAAA,CAAA,CAAA;AAC1F,EAAA,OAAO,OAAA;AACX","file":"index.js","sourcesContent":["/**\n * Detect if the code is running on localhost (development environment).\n * Returns \"dev\" for localhost, \"prod\" for production.\n */\nexport function detectEnvironment(): \"dev\" | \"prod\" {\n if (typeof window === \"undefined\") {\n return \"prod\"; // Server-side, default to prod\n }\n\n const hostname = window.location.hostname;\n\n // Check for localhost, 127.0.0.1, or local IP addresses\n if (\n hostname === \"localhost\" ||\n hostname === \"127.0.0.1\" ||\n hostname === \"0.0.0.0\" ||\n hostname.startsWith(\"192.168.\") ||\n hostname.startsWith(\"10.\") ||\n hostname.startsWith(\"172.16.\") ||\n hostname.startsWith(\"172.17.\") ||\n hostname.startsWith(\"172.18.\") ||\n hostname.startsWith(\"172.19.\") ||\n hostname.startsWith(\"172.20.\") ||\n hostname.startsWith(\"172.21.\") ||\n hostname.startsWith(\"172.22.\") ||\n hostname.startsWith(\"172.23.\") ||\n hostname.startsWith(\"172.24.\") ||\n hostname.startsWith(\"172.25.\") ||\n hostname.startsWith(\"172.26.\") ||\n hostname.startsWith(\"172.27.\") ||\n hostname.startsWith(\"172.28.\") ||\n hostname.startsWith(\"172.29.\") ||\n hostname.startsWith(\"172.30.\") ||\n hostname.startsWith(\"172.31.\")\n ) {\n return \"dev\";\n }\n\n return \"prod\";\n}\n\n","import React from \"react\";\nimport { detectEnvironment } from \"./environment\";\n\nexport type RetrieveResponse = {\n proposal_id: string;\n experiment_id: string | null;\n label: string | null;\n};\n\nexport type ComponentVariantInfo = {\n experiment_id: string;\n label: string;\n file_path: string | null;\n};\n\nexport type ComponentExperimentConfig = {\n proposal_id: string;\n variants: Record<string, ComponentVariantInfo>;\n};\n\n// Shared promise cache to prevent multiple simultaneous API calls for the same proposal\nconst pendingFetches = new Map<\n string,\n Promise<{ experiment_id: string; label: string }>\n>();\n\nexport async function fetchDecision(\n baseUrl: string,\n proposalId: string\n): Promise<{ experiment_id: string; label: string }> {\n // Check if there's already a pending fetch for this proposal\n const existingFetch = pendingFetches.get(proposalId);\n if (existingFetch) {\n return existingFetch;\n }\n\n // Create new fetch promise\n const fetchPromise = (async () => {\n try {\n const url = `${baseUrl.replace(/\\/$/, \"\")}/retrieve_react_experiment/${encodeURIComponent(proposalId)}`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: { Accept: \"application/json\" },\n credentials: \"include\", // Include cookies for user identification\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const data = (await res.json()) as RetrieveResponse;\n\n const experiment_id = (data.experiment_id || `exp_${proposalId}`).toString();\n const label = data.label && data.label.trim() ? data.label : \"control\";\n\n return { experiment_id, label };\n } finally {\n // Remove from pending cache after completion\n pendingFetches.delete(proposalId);\n }\n })();\n\n // Store the promise so other components can wait for the same call\n pendingFetches.set(proposalId, fetchPromise);\n return fetchPromise;\n}\n\nexport async function sendMetric(\n baseUrl: string,\n proposalId: string,\n metricName: \"visit\" | \"click\" | string,\n variantLabel: string = \"control\",\n experimentId?: string,\n dimensions: Record<string, any> = {}\n) {\n const url = `${baseUrl.replace(/\\/$/, \"\")}/send_metrics/${encodeURIComponent(proposalId)}`;\n const body = {\n experiment_id: experimentId ?? null,\n variant_label: variantLabel,\n metric_name: metricName,\n metric_value: 1,\n metric_unit: \"count\",\n source: \"react\",\n environment: detectEnvironment(), // Include environment (dev or prod)\n dimensions,\n captured_at: new Date().toISOString(),\n };\n try {\n await fetch(url, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n credentials: \"include\", // CRITICAL: Include cookies to distinguish different users\n body: JSON.stringify(body),\n });\n } catch {\n // Silently fail - metrics should not break the app\n }\n}\n\nexport function extractClickMeta(\n event?: { target?: EventTarget | null } | null\n): Record<string, any> | undefined {\n if (!event || !event.target) return undefined;\n const rawTarget = event.target as HTMLElement | null;\n if (!rawTarget) return undefined;\n const actionable = rawTarget.closest(\n \"[data-probat-conversion='true'], button, a, [role='button']\"\n );\n if (!actionable) return undefined;\n const meta: Record<string, any> = {\n target_tag: actionable.tagName,\n };\n if (actionable.id) meta.target_id = actionable.id;\n const attr = actionable.getAttribute(\"data-probat-conversion\");\n if (attr) meta.conversion_attr = attr;\n const text = actionable.textContent?.trim();\n if (text) meta.target_text = text.slice(0, 120);\n return meta;\n}\n\n// Cache for component config fetches\nconst componentConfigCache = new Map<\n string,\n Promise<ComponentExperimentConfig | null>\n>();\n\nexport async function fetchComponentExperimentConfig(\n baseUrl: string,\n repoFullName: string,\n componentPath: string\n): Promise<ComponentExperimentConfig | null> {\n const cacheKey = `${repoFullName}:${componentPath}`;\n\n // Check cache\n const existingFetch = componentConfigCache.get(cacheKey);\n if (existingFetch) {\n return existingFetch;\n }\n\n // Create new fetch promise\n const fetchPromise = (async () => {\n try {\n const url = new URL(`${baseUrl.replace(/\\/$/, \"\")}/get_component_experiment_config`);\n url.searchParams.set(\"repo_full_name\", repoFullName);\n url.searchParams.set(\"component_path\", componentPath);\n\n const res = await fetch(url.toString(), {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n credentials: \"include\",\n });\n\n if (res.status === 404) {\n // No experiments for this component - return null\n return null;\n }\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n const data = (await res.json()) as ComponentExperimentConfig;\n return data;\n } catch (e) {\n console.warn(`[PROBAT] Failed to fetch component config: ${e}`);\n return null;\n } finally {\n // Remove from cache after completion\n componentConfigCache.delete(cacheKey);\n }\n })();\n\n // Store the promise\n componentConfigCache.set(cacheKey, fetchPromise);\n return fetchPromise;\n}\n\n// Cache for variant component loads\nconst variantComponentCache = new Map<string, Promise<React.ComponentType<any> | null>>();\n\n// Make React available globally for variant components\nif (typeof window !== \"undefined\") {\n (window as any).__probatReact = React;\n (window as any).React = (window as any).React || React;\n}\n\nexport async function loadVariantComponent(\n baseUrl: string,\n proposalId: string,\n experimentId: string,\n filePath: string | null\n): Promise<React.ComponentType<any> | null> {\n if (!filePath) {\n return null;\n }\n\n const cacheKey = `${proposalId}:${experimentId}`;\n\n // Check cache\n const existingLoad = variantComponentCache.get(cacheKey);\n if (existingLoad) {\n return existingLoad;\n }\n\n // Create new load promise\n const loadPromise = (async () => {\n try {\n // Fetch the variant code (server compiles TSX/JSX to JS)\n const variantUrl = `${baseUrl.replace(/\\/$/, \"\")}/variants/${filePath}`;\n\n const res = await fetch(variantUrl, {\n method: \"GET\",\n headers: { Accept: \"text/javascript\" },\n credentials: \"include\",\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n const code = await res.text();\n\n // The server returns an IIFE that assigns to __probatVariant\n // Execute the code to get the component\n // First, ensure React is available globally\n if (typeof window !== \"undefined\") {\n (window as any).React = (window as any).React || React;\n }\n\n // Execute the IIFE code\n const evalFunc = new Function(`\n var __probatVariant;\n ${code}\n return __probatVariant;\n `);\n\n const result = evalFunc();\n\n // The result is { default: Component } from esbuild's IIFE output\n const VariantComponent = result?.default || result;\n\n if (typeof VariantComponent === \"function\") {\n return VariantComponent as React.ComponentType<any>;\n }\n\n console.warn(\"[PROBAT] Variant component is not a function\", result);\n return null;\n } catch (e) {\n console.warn(`[PROBAT] Failed to load variant component: ${e}`);\n return null;\n } finally {\n // Remove from cache after completion\n variantComponentCache.delete(cacheKey);\n }\n })();\n\n // Store the promise\n variantComponentCache.set(cacheKey, loadPromise);\n return loadPromise;\n}\n\n","/**\n * Document-level click tracking for Probat experiments\n * \n * This module implements event delegation at the document level to track clicks\n * even when components don't have onClick handlers or when stopPropagation() is called.\n */\n\nimport { sendMetric } from './api';\nimport { extractClickMeta } from './api';\n\n// Cache for proposal metadata to avoid repeated DOM queries\nconst proposalCache = new Map<string, {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n}>();\n\n// Track if listener is already attached\nlet isListenerAttached = false;\n\n// Rate limiting: prevent duplicate rapid clicks\nconst lastClickTime = new Map<string, number>();\nconst DEBOUNCE_MS = 100; // Ignore clicks within 100ms of each other\n\n/**\n * Get proposal metadata from DOM element\n * Looks for the nearest [data-probat-proposal] wrapper\n */\nfunction getProposalMetadata(element: HTMLElement): {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n} | null {\n // Find the nearest probat wrapper\n const probatWrapper = element.closest('[data-probat-proposal]') as HTMLElement | null;\n \n if (!probatWrapper) return null;\n \n const proposalId = probatWrapper.getAttribute('data-probat-proposal');\n if (!proposalId) return null;\n \n // Check cache first\n const cacheKey = `${proposalId}`;\n const cached = proposalCache.get(cacheKey);\n if (cached) return cached;\n \n // Extract metadata from data attributes\n const experimentId = probatWrapper.getAttribute('data-probat-experiment-id');\n const variantLabel = probatWrapper.getAttribute('data-probat-variant-label') || 'control';\n const apiBaseUrl = probatWrapper.getAttribute('data-probat-api-base-url') || \n (typeof window !== 'undefined' && (window as any).__PROBAT_API) ||\n 'https://gushi.onrender.com';\n \n const metadata = {\n proposalId,\n experimentId: experimentId || null,\n variantLabel,\n apiBaseUrl,\n };\n \n // Cache it\n proposalCache.set(cacheKey, metadata);\n return metadata;\n}\n\n/**\n * Handle click event at document level\n * Uses capture phase to catch events before stopPropagation()\n */\nfunction handleDocumentClick(event: MouseEvent): void {\n const target = event.target as HTMLElement | null;\n if (!target) return;\n \n // Get proposal metadata\n const metadata = getProposalMetadata(target);\n if (!metadata) return;\n \n // Rate limiting: prevent duplicate rapid clicks\n const now = Date.now();\n const lastClick = lastClickTime.get(metadata.proposalId) || 0;\n if (now - lastClick < DEBOUNCE_MS) {\n return; // Ignore rapid duplicate clicks\n }\n lastClickTime.set(metadata.proposalId, now);\n \n // Extract click metadata (your existing function)\n const clickMeta = extractClickMeta(event);\n \n // Determine if we should track this click\n // Track if:\n // 1. It's an actionable element (button, link, etc.) - clickMeta exists\n // 2. Element has data-probat-track attribute\n // 3. Parent has data-probat-track attribute\n const hasTrackAttribute = target.hasAttribute('data-probat-track') || \n target.closest('[data-probat-track]') !== null;\n \n const shouldTrack = clickMeta !== undefined || hasTrackAttribute;\n \n if (!shouldTrack) {\n // Optional: Track \"dead clicks\" for UX insights\n // Uncomment the code below if you want to track clicks on non-interactive elements\n /*\n const deadClickMeta = {\n dead_click: true,\n target_tag: target.tagName,\n target_class: target.className || '',\n target_id: target.id || '',\n };\n \n void sendMetric(\n metadata.apiBaseUrl,\n metadata.proposalId,\n 'dead_click',\n metadata.variantLabel,\n metadata.experimentId,\n deadClickMeta\n );\n */\n return;\n }\n \n // Send click metric\n void sendMetric(\n metadata.apiBaseUrl,\n metadata.proposalId,\n 'click',\n metadata.variantLabel,\n metadata.experimentId || undefined,\n clickMeta\n );\n}\n\n/**\n * Initialize document-level click tracking\n * Call this once when your app initializes (typically in ProbatProvider)\n */\nexport function initDocumentClickTracking(): void {\n if (isListenerAttached) {\n console.warn('[PROBAT] Document click listener already attached');\n return;\n }\n \n if (typeof document === 'undefined') {\n // Server-side rendering - skip\n return;\n }\n \n // Use capture phase (true) to catch events before they bubble\n // This ensures we catch clicks even if stopPropagation() is called\n document.addEventListener('click', handleDocumentClick, true);\n \n isListenerAttached = true;\n console.log('[PROBAT] Document-level click tracking initialized');\n}\n\n/**\n * Clean up the listener (useful for testing or cleanup)\n */\nexport function cleanupDocumentClickTracking(): void {\n if (!isListenerAttached) return;\n \n if (typeof document !== 'undefined') {\n document.removeEventListener('click', handleDocumentClick, true);\n }\n \n isListenerAttached = false;\n proposalCache.clear();\n lastClickTime.clear();\n}\n\n/**\n * Update proposal metadata cache (call this when proposal data changes)\n * This is useful if you want to update the cache without waiting for DOM queries\n */\nexport function updateProposalMetadata(\n proposalId: string,\n metadata: {\n experimentId?: string | null;\n variantLabel?: string;\n apiBaseUrl?: string;\n }\n): void {\n const existing = proposalCache.get(proposalId);\n if (existing) {\n proposalCache.set(proposalId, {\n ...existing,\n ...metadata,\n });\n }\n}\n\n/**\n * Clear the proposal cache (useful for testing)\n */\nexport function clearProposalCache(): void {\n proposalCache.clear();\n}\n\n","\"use client\";\n\nimport React, { createContext, useContext, useMemo, useEffect } from \"react\";\nimport { detectEnvironment } from \"../utils/environment\";\nimport { initDocumentClickTracking, cleanupDocumentClickTracking } from \"../utils/documentClickTracker\";\n\ndeclare global {\n interface Window {\n __PROBAT_API?: string;\n }\n}\n\nexport interface ProbatContextValue {\n apiBaseUrl: string;\n environment: \"dev\" | \"prod\";\n clientKey?: string;\n repoFullName?: string; // Repository full name (e.g., \"owner/repo\") for component-based experiments\n}\n\nconst ProbatContext = createContext<ProbatContextValue | null>(null);\n\nexport interface ProbatProviderProps {\n /**\n * The base URL for the Probat API.\n * If not provided, will try to read from:\n * - VITE_PROBAT_API (Vite)\n * - NEXT_PUBLIC_PROBAT_API (Next.js)\n * - window.__PROBAT_API\n * - Default: \"https://gushi.onrender.com\"\n */\n apiBaseUrl?: string;\n /**\n * Client key for identification (optional)\n */\n clientKey?: string;\n /**\n * Explicitly set environment. If not provided, will auto-detect based on hostname.\n * \"dev\" for localhost, \"prod\" for production.\n */\n environment?: \"dev\" | \"prod\";\n /**\n * Repository full name (e.g., \"owner/repo\") for component-based experiments.\n * If not provided, will try to read from:\n * - NEXT_PUBLIC_PROBAT_REPO (Next.js)\n * - VITE_PROBAT_REPO (Vite)\n * - window.__PROBAT_REPO\n */\n repoFullName?: string;\n children: React.ReactNode;\n}\n\nexport function ProbatProvider({\n apiBaseUrl,\n clientKey,\n environment: explicitEnvironment,\n repoFullName: explicitRepoFullName,\n children,\n}: ProbatProviderProps) {\n const contextValue = useMemo<ProbatContextValue>(() => {\n // Determine API base URL\n const resolvedApiBaseUrl =\n apiBaseUrl ||\n (typeof import.meta !== \"undefined\" &&\n (import.meta as any).env?.VITE_PROBAT_API) ||\n (typeof globalThis !== \"undefined\" &&\n (globalThis as any).process?.env?.NEXT_PUBLIC_PROBAT_API) ||\n (typeof window !== \"undefined\" && window.__PROBAT_API) ||\n \"https://gushi.onrender.com\";\n\n // Determine environment\n const environment = explicitEnvironment || detectEnvironment();\n\n // Determine repo full name\n const resolvedRepoFullName =\n explicitRepoFullName ||\n (typeof globalThis !== \"undefined\" &&\n (globalThis as any).process?.env?.NEXT_PUBLIC_PROBAT_REPO) ||\n (typeof import.meta !== \"undefined\" &&\n (import.meta as any).env?.VITE_PROBAT_REPO) ||\n (typeof window !== \"undefined\" && (window as any).__PROBAT_REPO) ||\n undefined;\n\n return {\n apiBaseUrl: resolvedApiBaseUrl,\n environment,\n clientKey,\n repoFullName: resolvedRepoFullName,\n };\n }, [apiBaseUrl, clientKey, explicitEnvironment, explicitRepoFullName]);\n\n // Initialize document-level click tracking when provider mounts\n useEffect(() => {\n initDocumentClickTracking();\n \n // Cleanup on unmount (optional, but good practice)\n return () => {\n cleanupDocumentClickTracking();\n };\n }, []);\n\n return (\n <ProbatContext.Provider value={contextValue}>\n {children}\n </ProbatContext.Provider>\n );\n}\n\nexport function useProbatContext(): ProbatContextValue {\n const context = useContext(ProbatContext);\n if (!context) {\n throw new Error(\n \"useProbatContext must be used within a ProbatProvider. Please wrap your app with <ProbatProvider>.\"\n );\n }\n return context;\n}\n\n","\"use client\";\n\nimport React from \"react\";\nimport { ProbatProvider as BaseProbatProvider } from \"../context/ProbatContext\";\nimport type { ProbatProviderProps } from \"../context/ProbatContext\";\n\n/**\n * ProbatProviderClient - Can be imported directly in Next.js Server Components\n * This is a re-export with \"use client\" directive to ensure it works in Server Components\n */\nexport function ProbatProviderClient(props: ProbatProviderProps) {\n return React.createElement(BaseProbatProvider, props);\n}\n\n// Also export as ProbatProvider for convenience\nexport { ProbatProviderClient as ProbatProvider };\nexport type { ProbatProviderProps };\n\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { sendMetric, extractClickMeta } from \"../utils/api\";\n\nexport interface UseProbatMetricsReturn {\n /**\n * Track a click event\n * @param event - Optional React mouse event (will extract metadata automatically)\n * @param options - Optional configuration\n * @param options.force - Force tracking even if no actionable element is found\n * @param options.proposalId - Override the proposal ID (usually not needed)\n * @param options.variantLabel - Override the variant label (usually not needed)\n * @param options.dimensions - Additional dimensions to include\n */\n trackClick: (\n event?: MouseEvent | null,\n options?: {\n force?: boolean;\n proposalId?: string;\n variantLabel?: string;\n dimensions?: Record<string, any>;\n }\n ) => boolean;\n /**\n * Track a custom metric\n * @param metricName - Name of the metric\n * @param proposalId - Proposal ID\n * @param variantLabel - Variant label (defaults to \"control\")\n * @param dimensions - Additional dimensions\n */\n trackMetric: (\n metricName: string,\n proposalId: string,\n variantLabel?: string,\n dimensions?: Record<string, any>\n ) => void;\n /**\n * Track an impression/view\n * @param proposalId - Proposal ID\n * @param variantLabel - Variant label (defaults to \"control\")\n * @param experimentId - Optional experiment ID\n */\n trackImpression: (\n proposalId: string,\n variantLabel?: string,\n experimentId?: string\n ) => void;\n}\n\n/**\n * Hook for tracking Probat metrics (clicks, impressions, custom metrics)\n *\n * @example\n * ```tsx\n * const { trackClick, trackImpression } = useProbatMetrics();\n *\n * // Track click on button\n * <button onClick={(e) => trackClick(e)}>Click me</button>\n *\n * // Track impression\n * useEffect(() => {\n * trackImpression(proposalId, variantLabel, experimentId);\n * }, [proposalId, variantLabel, experimentId]);\n * ```\n */\nexport function useProbatMetrics(): UseProbatMetricsReturn {\n const { apiBaseUrl } = useProbatContext();\n\n const trackClick = useCallback(\n (\n event?: MouseEvent | null,\n options?: {\n force?: boolean;\n proposalId?: string;\n variantLabel?: string;\n dimensions?: Record<string, any>;\n }\n ) => {\n const meta = extractClickMeta(event ?? undefined);\n if (!options?.force && event && !meta) {\n return false;\n }\n\n const proposalId = options?.proposalId;\n const variantLabel = options?.variantLabel || \"control\";\n\n if (!proposalId) {\n console.warn(\n \"[Probat] trackClick called without proposalId. Provide it in options or use useExperiment hook.\"\n );\n return false;\n }\n\n void sendMetric(\n apiBaseUrl,\n proposalId,\n \"click\",\n variantLabel,\n undefined,\n { ...meta, ...options?.dimensions }\n );\n return true;\n },\n [apiBaseUrl]\n );\n\n const trackMetric = useCallback(\n (\n metricName: string,\n proposalId: string,\n variantLabel: string = \"control\",\n dimensions: Record<string, any> = {}\n ) => {\n void sendMetric(\n apiBaseUrl,\n proposalId,\n metricName,\n variantLabel,\n undefined,\n dimensions\n );\n },\n [apiBaseUrl]\n );\n\n const trackImpression = useCallback(\n (\n proposalId: string,\n variantLabel: string = \"control\",\n experimentId?: string\n ) => {\n void sendMetric(\n apiBaseUrl,\n proposalId,\n \"visit\",\n variantLabel,\n experimentId\n );\n },\n [apiBaseUrl]\n );\n\n return {\n trackClick,\n trackMetric,\n trackImpression,\n };\n}\n\n","const TTL_MS = 6 * 60 * 60 * 1000; // 6 hours\n\nexport type Choice = {\n experiment_id: string;\n label: string;\n ts: number;\n};\n\nexport function safeGet(k: string): any | null {\n try {\n const raw = localStorage.getItem(k);\n return raw ? JSON.parse(raw) : null;\n } catch {\n return null;\n }\n}\n\nexport function safeSet(k: string, v: any) {\n try {\n localStorage.setItem(k, JSON.stringify(v));\n } catch { }\n}\n\nexport function now() {\n return Date.now();\n}\n\nexport function fresh(ts: number) {\n return now() - ts <= TTL_MS;\n}\n\nexport const KEY = (proposalId: string) => `probat_choice_v3:${proposalId}`;\nexport const VISIT_KEY = (proposalId: string, label: string) =>\n `probat_visit_v1:${proposalId}:${label}`;\n\nexport function readChoice(proposalId: string): Choice | null {\n const c = safeGet(KEY(proposalId)) as Choice | null;\n return c && fresh(c.ts) ? c : null;\n}\n\nexport function writeChoice(\n proposalId: string,\n experiment_id: string,\n label: string\n) {\n safeSet(KEY(proposalId), { experiment_id, label, ts: now() } as Choice);\n}\n\nconst visitMemo = new Set<string>();\n\nexport function hasTrackedVisit(proposalId: string, label: string): boolean {\n const key = VISIT_KEY(proposalId, label);\n if (visitMemo.has(key)) return true;\n try {\n const raw = localStorage.getItem(key);\n if (!raw) return false;\n const ts = Number(raw);\n if (!Number.isFinite(ts) || ts <= 0) return false;\n if (now() - ts > TTL_MS) {\n localStorage.removeItem(key);\n return false;\n }\n visitMemo.add(key);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function markTrackedVisit(proposalId: string, label: string) {\n const key = VISIT_KEY(proposalId, label);\n visitMemo.add(key);\n try {\n localStorage.setItem(key, now().toString());\n } catch { }\n}\n\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { fetchDecision } from \"../utils/api\";\nimport {\n readChoice,\n writeChoice,\n hasTrackedVisit,\n markTrackedVisit,\n} from \"../utils/storage\";\nimport { sendMetric } from \"../utils/api\";\n\nexport interface UseExperimentReturn {\n /**\n * The current variant label (e.g., \"control\", \"variant-a\")\n */\n variantLabel: string;\n /**\n * The experiment ID\n */\n experimentId: string | null;\n /**\n * Whether the experiment decision is still loading\n */\n isLoading: boolean;\n /**\n * Any error that occurred while fetching the experiment\n */\n error: Error | null;\n /**\n * Manually track a click for this experiment\n */\n trackClick: (event?: MouseEvent | null) => void;\n}\n\n/**\n * Hook for fetching and applying experiment variants\n *\n * @param proposalId - The proposal ID for the experiment\n * @param options - Optional configuration\n * @param options.autoTrackImpression - Automatically track impression when variant is loaded (default: true)\n *\n * @example\n * ```tsx\n * const { variantLabel, isLoading, trackClick } = useExperiment(\"proposal-id\");\n *\n * if (isLoading) return <div>Loading...</div>;\n *\n * return (\n * <div onClick={trackClick}>\n * {variantLabel === \"control\" ? <ControlComponent /> : <VariantComponent />}\n * </div>\n * );\n * ```\n */\nexport function useExperiment(\n proposalId: string,\n options?: { autoTrackImpression?: boolean }\n): UseExperimentReturn {\n const { apiBaseUrl } = useProbatContext();\n const [choice, setChoice] = useState<{\n experiment_id: string;\n label: string;\n } | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const autoTrackImpression = options?.autoTrackImpression !== false;\n\n // Fetch experiment decision\n useEffect(() => {\n let alive = true;\n\n const cached = readChoice(proposalId);\n if (cached) {\n setChoice({ experiment_id: cached.experiment_id, label: cached.label });\n setIsLoading(false);\n } else {\n setIsLoading(true);\n (async () => {\n try {\n const { experiment_id, label } = await fetchDecision(\n apiBaseUrl,\n proposalId\n );\n if (!alive) return;\n writeChoice(proposalId, experiment_id, label);\n setChoice({ experiment_id, label });\n setError(null);\n } catch (e) {\n if (!alive) return;\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n setChoice({\n experiment_id: `exp_${proposalId}`,\n label: \"control\",\n });\n } finally {\n if (alive) {\n setIsLoading(false);\n }\n }\n })();\n }\n\n return () => {\n alive = false;\n };\n }, [proposalId, apiBaseUrl]);\n\n // Track impression when variant is determined\n useEffect(() => {\n if (!autoTrackImpression || !choice) return;\n\n const exp = choice.experiment_id;\n const lbl = choice.label ?? \"control\";\n if (!lbl) return;\n\n // Only track if we haven't already tracked this visit\n if (hasTrackedVisit(proposalId, lbl)) return;\n markTrackedVisit(proposalId, lbl);\n void sendMetric(apiBaseUrl, proposalId, \"visit\", lbl, exp);\n }, [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl, autoTrackImpression]);\n\n const trackClick = useCallback(\n (event?: MouseEvent | null) => {\n const exp = choice?.experiment_id;\n const lbl = choice?.label ?? \"control\";\n const meta = event\n ? (() => {\n const rawTarget = event.target as HTMLElement | null;\n if (!rawTarget) return undefined;\n const actionable = rawTarget.closest(\n \"[data-probat-conversion='true'], button, a, [role='button']\"\n );\n if (!actionable) return undefined;\n const meta: Record<string, any> = {\n target_tag: actionable.tagName,\n };\n if (actionable.id) meta.target_id = actionable.id;\n const attr = actionable.getAttribute(\"data-probat-conversion\");\n if (attr) meta.conversion_attr = attr;\n const text = actionable.textContent?.trim();\n if (text) meta.target_text = text.slice(0, 120);\n return meta;\n })()\n : undefined;\n\n void sendMetric(apiBaseUrl, proposalId, \"click\", lbl, undefined, meta);\n },\n [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]\n );\n\n return {\n variantLabel: choice?.label ?? \"control\",\n experimentId: choice?.experiment_id ?? null,\n isLoading,\n error,\n trackClick,\n };\n}\n\n","\"use client\";\n\nimport React, { useState, useEffect, useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport {\n fetchDecision,\n fetchComponentExperimentConfig,\n loadVariantComponent,\n sendMetric,\n extractClickMeta,\n} from \"../utils/api\";\nimport {\n readChoice,\n writeChoice,\n hasTrackedVisit,\n markTrackedVisit,\n} from \"../utils/storage\";\n\n// Support both old and new API for backward compatibility\nexport interface WithExperimentOptions {\n // New API: component-based\n componentPath?: string;\n repoFullName?: string;\n\n // Old API: direct proposal/registry (for backward compatibility)\n proposalId?: string;\n registry?: Record<string, React.ComponentType<any>>;\n}\n\n/**\n * Higher-Order Component for wrapping components with experiment variants\n */\nexport function withExperiment<P = any>(\n Control: React.ComponentType<P>,\n options: WithExperimentOptions\n): React.ComponentType<P & { probat?: { trackClick: () => void } }> {\n // Validate inputs at HOC level (not in component)\n if (!Control) {\n console.error(\"[PROBAT] withExperiment: Control component is required\");\n return ((props: P) => null) as any;\n }\n\n if (!options || typeof options !== 'object') {\n console.error(\"[PROBAT] withExperiment: options is required\");\n return Control as any;\n }\n\n const useNewAPI = !!options.componentPath;\n const useOldAPI = !!(options.proposalId && options.registry);\n\n if (!useNewAPI && !useOldAPI) {\n console.warn(\"[PROBAT] withExperiment: Invalid config, returning Control\");\n return Control as any;\n }\n\n const ControlComponent = Control;\n\n function Wrapped(props: P) {\n // ============================================================\n // ALL HOOKS MUST BE AT THE TOP - BEFORE ANY CONDITIONAL RETURNS\n // ============================================================\n\n // 1. Context hook - always called first\n const context = useProbatContext();\n const apiBaseUrl = context?.apiBaseUrl || \"https://gushi.onrender.com\";\n const contextRepoFullName = context?.repoFullName;\n\n // 2. State hooks - always called in same order\n const [config, setConfig] = useState<{\n proposalId: string;\n variants: Record<string, React.ComponentType<any>>;\n } | null>(null);\n const [configLoading, setConfigLoading] = useState(useNewAPI);\n const [choice, setChoice] = useState<{\n experiment_id: string;\n label: string;\n } | null>(null);\n\n // Derived values\n const repoFullName = options.repoFullName || contextRepoFullName;\n const proposalId = useNewAPI ? config?.proposalId : options.proposalId;\n\n // 3. Effect hooks - always called\n // Load component config (new API)\n useEffect(() => {\n if (!useNewAPI) return;\n if (!repoFullName) {\n console.warn(\"[PROBAT] componentPath provided but repoFullName not found\");\n setConfigLoading(false);\n return;\n }\n\n let alive = true;\n setConfigLoading(true);\n\n (async () => {\n try {\n const componentConfig = await fetchComponentExperimentConfig(\n apiBaseUrl,\n repoFullName,\n options.componentPath!\n );\n\n if (!alive) return;\n\n if (!componentConfig) {\n setConfig(null);\n setConfigLoading(false);\n return;\n }\n\n const variantComponents: Record<string, React.ComponentType<any>> = {\n control: ControlComponent,\n };\n\n for (const [label, variantInfo] of Object.entries(componentConfig.variants)) {\n if (label === \"control\") continue;\n if (variantInfo?.file_path) {\n try {\n const VariantComp = await loadVariantComponent(\n apiBaseUrl,\n componentConfig.proposal_id,\n variantInfo.experiment_id,\n variantInfo.file_path\n );\n if (VariantComp && typeof VariantComp === 'function' && alive) {\n variantComponents[label] = VariantComp;\n }\n } catch (e) {\n console.warn(`[PROBAT] Failed to load variant ${label}:`, e);\n }\n }\n }\n\n if (alive) {\n setConfig({\n proposalId: componentConfig.proposal_id,\n variants: variantComponents,\n });\n setConfigLoading(false);\n }\n } catch (e) {\n console.warn(\"[PROBAT] Failed to load component config:\", e);\n if (alive) {\n setConfig(null);\n setConfigLoading(false);\n }\n }\n })();\n\n return () => { alive = false; };\n }, [useNewAPI, options.componentPath, repoFullName, apiBaseUrl]);\n\n // Fetch experiment decision\n useEffect(() => {\n if (!proposalId) return;\n if (useNewAPI && configLoading) return;\n\n let alive = true;\n const cached = readChoice(proposalId);\n\n if (cached) {\n setChoice({\n experiment_id: cached.experiment_id,\n label: cached.label,\n });\n } else {\n (async () => {\n try {\n const { experiment_id, label } = await fetchDecision(apiBaseUrl, proposalId);\n if (!alive) return;\n writeChoice(proposalId, experiment_id, label);\n setChoice({ experiment_id, label });\n } catch (e) {\n if (!alive) return;\n setChoice({\n experiment_id: `exp_${proposalId}`,\n label: \"control\",\n });\n }\n })();\n }\n\n return () => { alive = false; };\n }, [proposalId, apiBaseUrl, useNewAPI, configLoading]);\n\n // Track visit\n useEffect(() => {\n if (!proposalId) return;\n const lbl = choice?.label ?? \"control\";\n if (!lbl || hasTrackedVisit(proposalId, lbl)) return;\n markTrackedVisit(proposalId, lbl);\n void sendMetric(apiBaseUrl, proposalId, \"visit\", lbl, choice?.experiment_id);\n }, [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]);\n\n // 4. Callback hooks - always called\n const trackClick = useCallback(\n (event?: MouseEvent | null, opts?: { force?: boolean }) => {\n if (!proposalId) return false;\n const lbl = choice?.label ?? \"control\";\n const meta = extractClickMeta(event ?? undefined);\n if (!opts?.force && event && !meta) return false;\n void sendMetric(apiBaseUrl, proposalId, \"click\", lbl, undefined, meta);\n return true;\n },\n [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]\n );\n\n // ============================================================\n // NOW WE CAN DO CONDITIONAL RETURNS - AFTER ALL HOOKS\n // ============================================================\n\n // Loading state - return control\n if (useNewAPI && (configLoading || !config || !proposalId)) {\n return React.createElement(ControlComponent as any, props as any);\n }\n\n // No proposalId - return control\n if (!proposalId) {\n return React.createElement(ControlComponent as any, props as any);\n }\n\n // Build registry - always has control\n const registry: Record<string, React.ComponentType<any>> = { control: ControlComponent };\n\n if (useNewAPI && config?.variants) {\n for (const [key, value] of Object.entries(config.variants)) {\n if (key !== 'control' && value && typeof value === 'function') {\n registry[key] = value;\n }\n }\n } else if (!useNewAPI && options.registry) {\n for (const [key, value] of Object.entries(options.registry)) {\n if (key !== 'control' && value && typeof value === 'function') {\n registry[key] = value;\n }\n }\n }\n\n // Select variant\n const label = choice?.label ?? \"control\";\n const Variant = registry[label] || registry.control || ControlComponent;\n\n return (\n <div\n onClick={(event) => {\n // Keep existing onClick for backward compatibility\n // Document-level listener will also catch it (in capture phase)\n trackClick(event);\n }}\n data-probat-proposal={proposalId}\n data-probat-experiment-id={choice?.experiment_id || ''}\n data-probat-variant-label={label}\n data-probat-api-base-url={apiBaseUrl}\n >\n {React.createElement(Variant, {\n key: `${proposalId}:${label}`,\n ...(props as any),\n probat: { trackClick: () => trackClick(null, { force: true }) },\n })}\n </div>\n );\n }\n\n Wrapped.displayName = `withExperiment(${Control.displayName || Control.name || \"Component\"})`;\n return Wrapped as any;\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/environment.ts","../src/utils/api.ts","../src/utils/documentClickTracker.ts","../src/context/ProbatContext.tsx","../src/components/ProbatProviderClient.tsx","../src/hooks/useProbatMetrics.ts","../src/utils/storage.ts","../src/hooks/useExperiment.ts","../src/hoc/withExperiment.tsx"],"names":["React","now","createContext","useMemo","useEffect","useContext","useCallback","useState","meta","label"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Detect if the code is running on localhost (development environment).\n * Returns \"dev\" for localhost, \"prod\" for production.\n */\nexport function detectEnvironment(): \"dev\" | \"prod\" {\n if (typeof window === \"undefined\") {\n return \"prod\"; // Server-side, default to prod\n }\n\n const hostname = window.location.hostname;\n\n // Check for localhost, 127.0.0.1, or local IP addresses\n if (\n hostname === \"localhost\" ||\n hostname === \"127.0.0.1\" ||\n hostname === \"0.0.0.0\" ||\n hostname.startsWith(\"192.168.\") ||\n hostname.startsWith(\"10.\") ||\n hostname.startsWith(\"172.16.\") ||\n hostname.startsWith(\"172.17.\") ||\n hostname.startsWith(\"172.18.\") ||\n hostname.startsWith(\"172.19.\") ||\n hostname.startsWith(\"172.20.\") ||\n hostname.startsWith(\"172.21.\") ||\n hostname.startsWith(\"172.22.\") ||\n hostname.startsWith(\"172.23.\") ||\n hostname.startsWith(\"172.24.\") ||\n hostname.startsWith(\"172.25.\") ||\n hostname.startsWith(\"172.26.\") ||\n hostname.startsWith(\"172.27.\") ||\n hostname.startsWith(\"172.28.\") ||\n hostname.startsWith(\"172.29.\") ||\n hostname.startsWith(\"172.30.\") ||\n hostname.startsWith(\"172.31.\")\n ) {\n return \"dev\";\n }\n\n return \"prod\";\n}\n\n","import React from \"react\";\nimport { detectEnvironment } from \"./environment\";\n\nexport type RetrieveResponse = {\n proposal_id: string;\n experiment_id: string | null;\n label: string | null;\n};\n\nexport type ComponentVariantInfo = {\n experiment_id: string;\n label: string;\n file_path: string | null;\n};\n\nexport type ComponentExperimentConfig = {\n proposal_id: string;\n variants: Record<string, ComponentVariantInfo>;\n};\n\n// Shared promise cache to prevent multiple simultaneous API calls for the same proposal\nconst pendingFetches = new Map<\n string,\n Promise<{ experiment_id: string; label: string }>\n>();\n\nexport async function fetchDecision(\n baseUrl: string,\n proposalId: string\n): Promise<{ experiment_id: string; label: string }> {\n // Check if there's already a pending fetch for this proposal\n const existingFetch = pendingFetches.get(proposalId);\n if (existingFetch) {\n return existingFetch;\n }\n\n // Create new fetch promise\n const fetchPromise = (async () => {\n try {\n const url = `${baseUrl.replace(/\\/$/, \"\")}/retrieve_react_experiment/${encodeURIComponent(proposalId)}`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: { Accept: \"application/json\" },\n credentials: \"include\", // Include cookies for user identification\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const data = (await res.json()) as RetrieveResponse;\n\n const experiment_id = (data.experiment_id || `exp_${proposalId}`).toString();\n const label = data.label && data.label.trim() ? data.label : \"control\";\n\n return { experiment_id, label };\n } finally {\n // Remove from pending cache after completion\n pendingFetches.delete(proposalId);\n }\n })();\n\n // Store the promise so other components can wait for the same call\n pendingFetches.set(proposalId, fetchPromise);\n return fetchPromise;\n}\n\nexport async function sendMetric(\n baseUrl: string,\n proposalId: string,\n metricName: \"visit\" | \"click\" | string,\n variantLabel: string = \"control\",\n experimentId?: string,\n dimensions: Record<string, any> = {}\n) {\n const url = `${baseUrl.replace(/\\/$/, \"\")}/send_metrics/${encodeURIComponent(proposalId)}`;\n const body = {\n experiment_id: experimentId ?? null,\n variant_label: variantLabel,\n metric_name: metricName,\n metric_value: 1,\n metric_unit: \"count\",\n source: \"react\",\n environment: detectEnvironment(), // Include environment (dev or prod)\n dimensions,\n captured_at: new Date().toISOString(),\n };\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n credentials: \"include\", // CRITICAL: Include cookies to distinguish different users\n body: JSON.stringify(body),\n });\n \n // Log in development for debugging\n if (!response.ok) {\n console.warn('[PROBAT] Metric send failed:', {\n status: response.status,\n statusText: response.statusText,\n url,\n body,\n });\n } else {\n console.log('[PROBAT] Metric sent successfully:', {\n metricName,\n proposalId,\n variantLabel,\n });\n }\n } catch (error) {\n // Log error in development, but don't break the app\n console.error('[PROBAT] Error sending metric:', {\n error: error instanceof Error ? error.message : String(error),\n url,\n body,\n });\n }\n}\n\nexport function extractClickMeta(\n event?: { target?: EventTarget | null } | null\n): Record<string, any> | undefined {\n if (!event || !event.target) return undefined;\n const rawTarget = event.target as HTMLElement | null;\n if (!rawTarget) return undefined;\n const actionable = rawTarget.closest(\n \"[data-probat-conversion='true'], button, a, [role='button']\"\n );\n if (!actionable) return undefined;\n const meta: Record<string, any> = {\n target_tag: actionable.tagName,\n };\n if (actionable.id) meta.target_id = actionable.id;\n const attr = actionable.getAttribute(\"data-probat-conversion\");\n if (attr) meta.conversion_attr = attr;\n const text = actionable.textContent?.trim();\n if (text) meta.target_text = text.slice(0, 120);\n return meta;\n}\n\n// Cache for component config fetches\nconst componentConfigCache = new Map<\n string,\n Promise<ComponentExperimentConfig | null>\n>();\n\nexport async function fetchComponentExperimentConfig(\n baseUrl: string,\n repoFullName: string,\n componentPath: string\n): Promise<ComponentExperimentConfig | null> {\n const cacheKey = `${repoFullName}:${componentPath}`;\n\n // Check cache\n const existingFetch = componentConfigCache.get(cacheKey);\n if (existingFetch) {\n return existingFetch;\n }\n\n // Create new fetch promise\n const fetchPromise = (async () => {\n try {\n const url = new URL(`${baseUrl.replace(/\\/$/, \"\")}/get_component_experiment_config`);\n url.searchParams.set(\"repo_full_name\", repoFullName);\n url.searchParams.set(\"component_path\", componentPath);\n\n const res = await fetch(url.toString(), {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n credentials: \"include\",\n });\n\n if (res.status === 404) {\n // No experiments for this component - return null\n return null;\n }\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n const data = (await res.json()) as ComponentExperimentConfig;\n return data;\n } catch (e) {\n console.warn(`[PROBAT] Failed to fetch component config: ${e}`);\n return null;\n } finally {\n // Remove from cache after completion\n componentConfigCache.delete(cacheKey);\n }\n })();\n\n // Store the promise\n componentConfigCache.set(cacheKey, fetchPromise);\n return fetchPromise;\n}\n\n// Cache for variant component loads\nconst variantComponentCache = new Map<string, Promise<React.ComponentType<any> | null>>();\n\n// Make React available globally for variant components\nif (typeof window !== \"undefined\") {\n (window as any).__probatReact = React;\n (window as any).React = (window as any).React || React;\n}\n\nexport async function loadVariantComponent(\n baseUrl: string,\n proposalId: string,\n experimentId: string,\n filePath: string | null\n): Promise<React.ComponentType<any> | null> {\n if (!filePath) {\n return null;\n }\n\n const cacheKey = `${proposalId}:${experimentId}`;\n\n // Check cache\n const existingLoad = variantComponentCache.get(cacheKey);\n if (existingLoad) {\n return existingLoad;\n }\n\n // Create new load promise\n const loadPromise = (async () => {\n try {\n // Fetch the variant code (server compiles TSX/JSX to JS)\n const variantUrl = `${baseUrl.replace(/\\/$/, \"\")}/variants/${filePath}`;\n\n const res = await fetch(variantUrl, {\n method: \"GET\",\n headers: { Accept: \"text/javascript\" },\n credentials: \"include\",\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n const code = await res.text();\n\n // The server returns an IIFE that assigns to __probatVariant\n // Execute the code to get the component\n // First, ensure React is available globally\n if (typeof window !== \"undefined\") {\n (window as any).React = (window as any).React || React;\n }\n\n // Execute the IIFE code\n const evalFunc = new Function(`\n var __probatVariant;\n ${code}\n return __probatVariant;\n `);\n\n const result = evalFunc();\n\n // The result is { default: Component } from esbuild's IIFE output\n const VariantComponent = result?.default || result;\n\n if (typeof VariantComponent === \"function\") {\n return VariantComponent as React.ComponentType<any>;\n }\n\n console.warn(\"[PROBAT] Variant component is not a function\", result);\n return null;\n } catch (e) {\n console.warn(`[PROBAT] Failed to load variant component: ${e}`);\n return null;\n } finally {\n // Remove from cache after completion\n variantComponentCache.delete(cacheKey);\n }\n })();\n\n // Store the promise\n variantComponentCache.set(cacheKey, loadPromise);\n return loadPromise;\n}\n\n","/**\n * Document-level click tracking for Probat experiments\n * \n * This module implements event delegation at the document level to track clicks\n * even when components don't have onClick handlers or when stopPropagation() is called.\n */\n\nimport { sendMetric } from './api';\nimport { extractClickMeta } from './api';\n\n// Cache for proposal metadata to avoid repeated DOM queries\nconst proposalCache = new Map<string, {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n}>();\n\n// Track if listener is already attached\nlet isListenerAttached = false;\n\n// Rate limiting: prevent duplicate rapid clicks\nconst lastClickTime = new Map<string, number>();\nconst DEBOUNCE_MS = 100; // Ignore clicks within 100ms of each other\n\n/**\n * Get proposal metadata from DOM element\n * Looks for the nearest [data-probat-proposal] wrapper\n */\nfunction getProposalMetadata(element: HTMLElement): {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n} | null {\n // Find the nearest probat wrapper\n const probatWrapper = element.closest('[data-probat-proposal]') as HTMLElement | null;\n\n if (!probatWrapper) return null;\n\n const proposalId = probatWrapper.getAttribute('data-probat-proposal');\n if (!proposalId) return null;\n\n // Check cache first\n const cacheKey = `${proposalId}`;\n const cached = proposalCache.get(cacheKey);\n if (cached) return cached;\n\n // Extract metadata from data attributes\n const experimentId = probatWrapper.getAttribute('data-probat-experiment-id');\n const variantLabel = probatWrapper.getAttribute('data-probat-variant-label') || 'control';\n const apiBaseUrl = probatWrapper.getAttribute('data-probat-api-base-url') ||\n (typeof window !== 'undefined' && (window as any).__PROBAT_API) ||\n 'https://gushi.onrender.com';\n\n const metadata = {\n proposalId,\n experimentId: experimentId || null,\n variantLabel,\n apiBaseUrl,\n };\n\n // Cache it\n proposalCache.set(cacheKey, metadata);\n return metadata;\n}\n\n/**\n * Handle click event at document level\n * Uses capture phase to catch events before stopPropagation()\n */\nfunction handleDocumentClick(event: MouseEvent): void {\n const target = event.target as HTMLElement | null;\n if (!target) return;\n\n // Get proposal metadata\n const metadata = getProposalMetadata(target);\n if (!metadata) {\n return; // Click outside probat component\n }\n\n // Rate limiting: prevent duplicate rapid clicks\n const now = Date.now();\n const lastClick = lastClickTime.get(metadata.proposalId) || 0;\n if (now - lastClick < DEBOUNCE_MS) {\n return; // Ignore rapid duplicate clicks\n }\n lastClickTime.set(metadata.proposalId, now);\n\n // Extract click metadata (your existing function)\n const clickMeta = extractClickMeta(event);\n\n // Determine if we should track this click\n // Track if:\n // 1. It's an actionable element (button, link, etc.) - clickMeta exists\n // 2. Element has data-probat-track attribute\n // 3. Parent has data-probat-track attribute\n // 4. ANY click within a probat component (more permissive - track all clicks)\n const hasTrackAttribute = target.hasAttribute('data-probat-track') ||\n target.closest('[data-probat-track]') !== null;\n\n // More permissive: Track ALL clicks within probat components\n // This ensures we capture clicks even if elements don't have explicit tracking attributes\n const shouldTrack = clickMeta !== undefined || hasTrackAttribute || true; // Track all clicks in probat components\n\n if (!shouldTrack) {\n return;\n }\n\n // Build metadata - use clickMeta if available, otherwise create basic metadata\n const finalMeta = clickMeta || {\n target_tag: target.tagName,\n target_class: target.className || '',\n target_id: target.id || '',\n clicked_inside_probat: true, // Flag to indicate this was tracked via document-level listener\n };\n\n // Send click metric\n // For control variant, don't send experiment_id (control might be synthetic)\n // For other variants, send experiment_id if it exists and is valid (not synthetic \"exp_\" prefix)\n const experimentId = metadata.variantLabel === 'control'\n ? undefined\n : (metadata.experimentId && !metadata.experimentId.startsWith('exp_')\n ? metadata.experimentId\n : undefined);\n\n void sendMetric(\n metadata.apiBaseUrl,\n metadata.proposalId,\n 'click',\n metadata.variantLabel,\n experimentId,\n finalMeta\n );\n\n // Debug logging (always log for now to help diagnose)\n console.log('[PROBAT] Click tracked:', {\n proposalId: metadata.proposalId,\n variantLabel: metadata.variantLabel,\n target: target.tagName,\n targetId: target.id || 'none',\n targetClass: target.className || 'none',\n meta: finalMeta,\n });\n\n // Also log to help debug if API call fails\n console.log('[PROBAT] Sending metric to:', `${metadata.apiBaseUrl}/send_metrics/${metadata.proposalId}`);\n}\n\n/**\n * Initialize document-level click tracking\n * Call this once when your app initializes (typically in ProbatProvider)\n */\nexport function initDocumentClickTracking(): void {\n if (isListenerAttached) {\n console.warn('[PROBAT] Document click listener already attached');\n return;\n }\n\n if (typeof document === 'undefined') {\n // Server-side rendering - skip\n return;\n }\n\n // Use capture phase (true) to catch events before they bubble\n // This ensures we catch clicks even if stopPropagation() is called\n document.addEventListener('click', handleDocumentClick, true);\n\n isListenerAttached = true;\n console.log('[PROBAT] Document-level click tracking initialized');\n}\n\n/**\n * Clean up the listener (useful for testing or cleanup)\n */\nexport function cleanupDocumentClickTracking(): void {\n if (!isListenerAttached) return;\n\n if (typeof document !== 'undefined') {\n document.removeEventListener('click', handleDocumentClick, true);\n }\n\n isListenerAttached = false;\n proposalCache.clear();\n lastClickTime.clear();\n}\n\n/**\n * Update proposal metadata cache (call this when proposal data changes)\n * This is useful if you want to update the cache without waiting for DOM queries\n */\nexport function updateProposalMetadata(\n proposalId: string,\n metadata: {\n experimentId?: string | null;\n variantLabel?: string;\n apiBaseUrl?: string;\n }\n): void {\n const existing = proposalCache.get(proposalId);\n if (existing) {\n proposalCache.set(proposalId, {\n ...existing,\n ...metadata,\n });\n }\n}\n\n/**\n * Clear the proposal cache (useful for testing)\n */\nexport function clearProposalCache(): void {\n proposalCache.clear();\n}\n\n","\"use client\";\n\nimport React, { createContext, useContext, useMemo, useEffect } from \"react\";\nimport { detectEnvironment } from \"../utils/environment\";\nimport { initDocumentClickTracking, cleanupDocumentClickTracking } from \"../utils/documentClickTracker\";\n\ndeclare global {\n interface Window {\n __PROBAT_API?: string;\n }\n}\n\nexport interface ProbatContextValue {\n apiBaseUrl: string;\n environment: \"dev\" | \"prod\";\n clientKey?: string;\n repoFullName?: string; // Repository full name (e.g., \"owner/repo\") for component-based experiments\n}\n\nconst ProbatContext = createContext<ProbatContextValue | null>(null);\n\nexport interface ProbatProviderProps {\n /**\n * The base URL for the Probat API.\n * If not provided, will try to read from:\n * - VITE_PROBAT_API (Vite)\n * - NEXT_PUBLIC_PROBAT_API (Next.js)\n * - window.__PROBAT_API\n * - Default: \"https://gushi.onrender.com\"\n */\n apiBaseUrl?: string;\n /**\n * Client key for identification (optional)\n */\n clientKey?: string;\n /**\n * Explicitly set environment. If not provided, will auto-detect based on hostname.\n * \"dev\" for localhost, \"prod\" for production.\n */\n environment?: \"dev\" | \"prod\";\n /**\n * Repository full name (e.g., \"owner/repo\") for component-based experiments.\n * If not provided, will try to read from:\n * - NEXT_PUBLIC_PROBAT_REPO (Next.js)\n * - VITE_PROBAT_REPO (Vite)\n * - window.__PROBAT_REPO\n */\n repoFullName?: string;\n children: React.ReactNode;\n}\n\nexport function ProbatProvider({\n apiBaseUrl,\n clientKey,\n environment: explicitEnvironment,\n repoFullName: explicitRepoFullName,\n children,\n}: ProbatProviderProps) {\n const contextValue = useMemo<ProbatContextValue>(() => {\n // Determine API base URL\n const resolvedApiBaseUrl =\n apiBaseUrl ||\n (typeof import.meta !== \"undefined\" &&\n (import.meta as any).env?.VITE_PROBAT_API) ||\n (typeof globalThis !== \"undefined\" &&\n (globalThis as any).process?.env?.NEXT_PUBLIC_PROBAT_API) ||\n (typeof window !== \"undefined\" && window.__PROBAT_API) ||\n \"https://gushi.onrender.com\";\n\n // Determine environment\n const environment = explicitEnvironment || detectEnvironment();\n\n // Determine repo full name\n const resolvedRepoFullName =\n explicitRepoFullName ||\n (typeof globalThis !== \"undefined\" &&\n (globalThis as any).process?.env?.NEXT_PUBLIC_PROBAT_REPO) ||\n (typeof import.meta !== \"undefined\" &&\n (import.meta as any).env?.VITE_PROBAT_REPO) ||\n (typeof window !== \"undefined\" && (window as any).__PROBAT_REPO) ||\n undefined;\n\n return {\n apiBaseUrl: resolvedApiBaseUrl,\n environment,\n clientKey,\n repoFullName: resolvedRepoFullName,\n };\n }, [apiBaseUrl, clientKey, explicitEnvironment, explicitRepoFullName]);\n\n // Initialize document-level click tracking when provider mounts\n useEffect(() => {\n initDocumentClickTracking();\n \n // Cleanup on unmount (optional, but good practice)\n return () => {\n cleanupDocumentClickTracking();\n };\n }, []);\n\n return (\n <ProbatContext.Provider value={contextValue}>\n {children}\n </ProbatContext.Provider>\n );\n}\n\nexport function useProbatContext(): ProbatContextValue {\n const context = useContext(ProbatContext);\n if (!context) {\n throw new Error(\n \"useProbatContext must be used within a ProbatProvider. Please wrap your app with <ProbatProvider>.\"\n );\n }\n return context;\n}\n\n","\"use client\";\n\nimport React from \"react\";\nimport { ProbatProvider as BaseProbatProvider } from \"../context/ProbatContext\";\nimport type { ProbatProviderProps } from \"../context/ProbatContext\";\n\n/**\n * ProbatProviderClient - Can be imported directly in Next.js Server Components\n * This is a re-export with \"use client\" directive to ensure it works in Server Components\n */\nexport function ProbatProviderClient(props: ProbatProviderProps) {\n return React.createElement(BaseProbatProvider, props);\n}\n\n// Also export as ProbatProvider for convenience\nexport { ProbatProviderClient as ProbatProvider };\nexport type { ProbatProviderProps };\n\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { sendMetric, extractClickMeta } from \"../utils/api\";\n\nexport interface UseProbatMetricsReturn {\n /**\n * Track a click event\n * @param event - Optional React mouse event (will extract metadata automatically)\n * @param options - Optional configuration\n * @param options.force - Force tracking even if no actionable element is found\n * @param options.proposalId - Override the proposal ID (usually not needed)\n * @param options.variantLabel - Override the variant label (usually not needed)\n * @param options.dimensions - Additional dimensions to include\n */\n trackClick: (\n event?: MouseEvent | null,\n options?: {\n force?: boolean;\n proposalId?: string;\n variantLabel?: string;\n dimensions?: Record<string, any>;\n }\n ) => boolean;\n /**\n * Track a custom metric\n * @param metricName - Name of the metric\n * @param proposalId - Proposal ID\n * @param variantLabel - Variant label (defaults to \"control\")\n * @param dimensions - Additional dimensions\n */\n trackMetric: (\n metricName: string,\n proposalId: string,\n variantLabel?: string,\n dimensions?: Record<string, any>\n ) => void;\n /**\n * Track an impression/view\n * @param proposalId - Proposal ID\n * @param variantLabel - Variant label (defaults to \"control\")\n * @param experimentId - Optional experiment ID\n */\n trackImpression: (\n proposalId: string,\n variantLabel?: string,\n experimentId?: string\n ) => void;\n}\n\n/**\n * Hook for tracking Probat metrics (clicks, impressions, custom metrics)\n *\n * @example\n * ```tsx\n * const { trackClick, trackImpression } = useProbatMetrics();\n *\n * // Track click on button\n * <button onClick={(e) => trackClick(e)}>Click me</button>\n *\n * // Track impression\n * useEffect(() => {\n * trackImpression(proposalId, variantLabel, experimentId);\n * }, [proposalId, variantLabel, experimentId]);\n * ```\n */\nexport function useProbatMetrics(): UseProbatMetricsReturn {\n const { apiBaseUrl } = useProbatContext();\n\n const trackClick = useCallback(\n (\n event?: MouseEvent | null,\n options?: {\n force?: boolean;\n proposalId?: string;\n variantLabel?: string;\n dimensions?: Record<string, any>;\n }\n ) => {\n const meta = extractClickMeta(event ?? undefined);\n if (!options?.force && event && !meta) {\n return false;\n }\n\n const proposalId = options?.proposalId;\n const variantLabel = options?.variantLabel || \"control\";\n\n if (!proposalId) {\n console.warn(\n \"[Probat] trackClick called without proposalId. Provide it in options or use useExperiment hook.\"\n );\n return false;\n }\n\n void sendMetric(\n apiBaseUrl,\n proposalId,\n \"click\",\n variantLabel,\n undefined,\n { ...meta, ...options?.dimensions }\n );\n return true;\n },\n [apiBaseUrl]\n );\n\n const trackMetric = useCallback(\n (\n metricName: string,\n proposalId: string,\n variantLabel: string = \"control\",\n dimensions: Record<string, any> = {}\n ) => {\n void sendMetric(\n apiBaseUrl,\n proposalId,\n metricName,\n variantLabel,\n undefined,\n dimensions\n );\n },\n [apiBaseUrl]\n );\n\n const trackImpression = useCallback(\n (\n proposalId: string,\n variantLabel: string = \"control\",\n experimentId?: string\n ) => {\n void sendMetric(\n apiBaseUrl,\n proposalId,\n \"visit\",\n variantLabel,\n experimentId\n );\n },\n [apiBaseUrl]\n );\n\n return {\n trackClick,\n trackMetric,\n trackImpression,\n };\n}\n\n","const TTL_MS = 6 * 60 * 60 * 1000; // 6 hours\n\nexport type Choice = {\n experiment_id: string;\n label: string;\n ts: number;\n};\n\nexport function safeGet(k: string): any | null {\n try {\n const raw = localStorage.getItem(k);\n return raw ? JSON.parse(raw) : null;\n } catch {\n return null;\n }\n}\n\nexport function safeSet(k: string, v: any) {\n try {\n localStorage.setItem(k, JSON.stringify(v));\n } catch { }\n}\n\nexport function now() {\n return Date.now();\n}\n\nexport function fresh(ts: number) {\n return now() - ts <= TTL_MS;\n}\n\nexport const KEY = (proposalId: string) => `probat_choice_v3:${proposalId}`;\nexport const VISIT_KEY = (proposalId: string, label: string) =>\n `probat_visit_v1:${proposalId}:${label}`;\n\nexport function readChoice(proposalId: string): Choice | null {\n const c = safeGet(KEY(proposalId)) as Choice | null;\n return c && fresh(c.ts) ? c : null;\n}\n\nexport function writeChoice(\n proposalId: string,\n experiment_id: string,\n label: string\n) {\n safeSet(KEY(proposalId), { experiment_id, label, ts: now() } as Choice);\n}\n\nconst visitMemo = new Set<string>();\n\nexport function hasTrackedVisit(proposalId: string, label: string): boolean {\n const key = VISIT_KEY(proposalId, label);\n if (visitMemo.has(key)) return true;\n try {\n const raw = localStorage.getItem(key);\n if (!raw) return false;\n const ts = Number(raw);\n if (!Number.isFinite(ts) || ts <= 0) return false;\n if (now() - ts > TTL_MS) {\n localStorage.removeItem(key);\n return false;\n }\n visitMemo.add(key);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function markTrackedVisit(proposalId: string, label: string) {\n const key = VISIT_KEY(proposalId, label);\n visitMemo.add(key);\n try {\n localStorage.setItem(key, now().toString());\n } catch { }\n}\n\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { fetchDecision } from \"../utils/api\";\nimport {\n readChoice,\n writeChoice,\n hasTrackedVisit,\n markTrackedVisit,\n} from \"../utils/storage\";\nimport { sendMetric } from \"../utils/api\";\n\nexport interface UseExperimentReturn {\n /**\n * The current variant label (e.g., \"control\", \"variant-a\")\n */\n variantLabel: string;\n /**\n * The experiment ID\n */\n experimentId: string | null;\n /**\n * Whether the experiment decision is still loading\n */\n isLoading: boolean;\n /**\n * Any error that occurred while fetching the experiment\n */\n error: Error | null;\n /**\n * Manually track a click for this experiment\n */\n trackClick: (event?: MouseEvent | null) => void;\n}\n\n/**\n * Hook for fetching and applying experiment variants\n *\n * @param proposalId - The proposal ID for the experiment\n * @param options - Optional configuration\n * @param options.autoTrackImpression - Automatically track impression when variant is loaded (default: true)\n *\n * @example\n * ```tsx\n * const { variantLabel, isLoading, trackClick } = useExperiment(\"proposal-id\");\n *\n * if (isLoading) return <div>Loading...</div>;\n *\n * return (\n * <div onClick={trackClick}>\n * {variantLabel === \"control\" ? <ControlComponent /> : <VariantComponent />}\n * </div>\n * );\n * ```\n */\nexport function useExperiment(\n proposalId: string,\n options?: { autoTrackImpression?: boolean }\n): UseExperimentReturn {\n const { apiBaseUrl } = useProbatContext();\n const [choice, setChoice] = useState<{\n experiment_id: string;\n label: string;\n } | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const autoTrackImpression = options?.autoTrackImpression !== false;\n\n // Fetch experiment decision\n useEffect(() => {\n let alive = true;\n\n const cached = readChoice(proposalId);\n if (cached) {\n setChoice({ experiment_id: cached.experiment_id, label: cached.label });\n setIsLoading(false);\n } else {\n setIsLoading(true);\n (async () => {\n try {\n const { experiment_id, label } = await fetchDecision(\n apiBaseUrl,\n proposalId\n );\n if (!alive) return;\n writeChoice(proposalId, experiment_id, label);\n setChoice({ experiment_id, label });\n setError(null);\n } catch (e) {\n if (!alive) return;\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n setChoice({\n experiment_id: `exp_${proposalId}`,\n label: \"control\",\n });\n } finally {\n if (alive) {\n setIsLoading(false);\n }\n }\n })();\n }\n\n return () => {\n alive = false;\n };\n }, [proposalId, apiBaseUrl]);\n\n // Track impression when variant is determined\n useEffect(() => {\n if (!autoTrackImpression || !choice) return;\n\n const exp = choice.experiment_id;\n const lbl = choice.label ?? \"control\";\n if (!lbl) return;\n\n // Only track if we haven't already tracked this visit\n if (hasTrackedVisit(proposalId, lbl)) return;\n markTrackedVisit(proposalId, lbl);\n void sendMetric(apiBaseUrl, proposalId, \"visit\", lbl, exp);\n }, [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl, autoTrackImpression]);\n\n const trackClick = useCallback(\n (event?: MouseEvent | null) => {\n const exp = choice?.experiment_id;\n const lbl = choice?.label ?? \"control\";\n const meta = event\n ? (() => {\n const rawTarget = event.target as HTMLElement | null;\n if (!rawTarget) return undefined;\n const actionable = rawTarget.closest(\n \"[data-probat-conversion='true'], button, a, [role='button']\"\n );\n if (!actionable) return undefined;\n const meta: Record<string, any> = {\n target_tag: actionable.tagName,\n };\n if (actionable.id) meta.target_id = actionable.id;\n const attr = actionable.getAttribute(\"data-probat-conversion\");\n if (attr) meta.conversion_attr = attr;\n const text = actionable.textContent?.trim();\n if (text) meta.target_text = text.slice(0, 120);\n return meta;\n })()\n : undefined;\n\n void sendMetric(apiBaseUrl, proposalId, \"click\", lbl, undefined, meta);\n },\n [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]\n );\n\n return {\n variantLabel: choice?.label ?? \"control\",\n experimentId: choice?.experiment_id ?? null,\n isLoading,\n error,\n trackClick,\n };\n}\n\n","\"use client\";\n\nimport React, { useState, useEffect, useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport {\n fetchDecision,\n fetchComponentExperimentConfig,\n loadVariantComponent,\n sendMetric,\n extractClickMeta,\n} from \"../utils/api\";\nimport {\n readChoice,\n writeChoice,\n hasTrackedVisit,\n markTrackedVisit,\n} from \"../utils/storage\";\n\n// Support both old and new API for backward compatibility\nexport interface WithExperimentOptions {\n // New API: component-based\n componentPath?: string;\n repoFullName?: string;\n\n // Old API: direct proposal/registry (for backward compatibility)\n proposalId?: string;\n registry?: Record<string, React.ComponentType<any>>;\n}\n\n/**\n * Higher-Order Component for wrapping components with experiment variants\n */\nexport function withExperiment<P = any>(\n Control: React.ComponentType<P>,\n options: WithExperimentOptions\n): React.ComponentType<P & { probat?: { trackClick: () => void } }> {\n // Validate inputs at HOC level (not in component)\n if (!Control) {\n console.error(\"[PROBAT] withExperiment: Control component is required\");\n return ((props: P) => null) as any;\n }\n\n if (!options || typeof options !== 'object') {\n console.error(\"[PROBAT] withExperiment: options is required\");\n return Control as any;\n }\n\n const useNewAPI = !!options.componentPath;\n const useOldAPI = !!(options.proposalId && options.registry);\n\n if (!useNewAPI && !useOldAPI) {\n console.warn(\"[PROBAT] withExperiment: Invalid config, returning Control\");\n return Control as any;\n }\n\n const ControlComponent = Control;\n\n function Wrapped(props: P) {\n // ============================================================\n // ALL HOOKS MUST BE AT THE TOP - BEFORE ANY CONDITIONAL RETURNS\n // ============================================================\n\n // 1. Context hook - always called first\n const context = useProbatContext();\n const apiBaseUrl = context?.apiBaseUrl || \"https://gushi.onrender.com\";\n const contextRepoFullName = context?.repoFullName;\n\n // 2. State hooks - always called in same order\n const [config, setConfig] = useState<{\n proposalId: string;\n variants: Record<string, React.ComponentType<any>>;\n } | null>(null);\n const [configLoading, setConfigLoading] = useState(useNewAPI);\n const [choice, setChoice] = useState<{\n experiment_id: string;\n label: string;\n } | null>(null);\n\n // Derived values\n const repoFullName = options.repoFullName || contextRepoFullName;\n const proposalId = useNewAPI ? config?.proposalId : options.proposalId;\n\n // 3. Effect hooks - always called\n // Load component config (new API)\n useEffect(() => {\n if (!useNewAPI) return;\n if (!repoFullName) {\n console.warn(\"[PROBAT] componentPath provided but repoFullName not found\");\n setConfigLoading(false);\n return;\n }\n\n let alive = true;\n setConfigLoading(true);\n\n (async () => {\n try {\n const componentConfig = await fetchComponentExperimentConfig(\n apiBaseUrl,\n repoFullName,\n options.componentPath!\n );\n\n if (!alive) return;\n\n if (!componentConfig) {\n setConfig(null);\n setConfigLoading(false);\n return;\n }\n\n const variantComponents: Record<string, React.ComponentType<any>> = {\n control: ControlComponent,\n };\n\n for (const [label, variantInfo] of Object.entries(componentConfig.variants)) {\n if (label === \"control\") continue;\n if (variantInfo?.file_path) {\n try {\n const VariantComp = await loadVariantComponent(\n apiBaseUrl,\n componentConfig.proposal_id,\n variantInfo.experiment_id,\n variantInfo.file_path\n );\n if (VariantComp && typeof VariantComp === 'function' && alive) {\n variantComponents[label] = VariantComp;\n }\n } catch (e) {\n console.warn(`[PROBAT] Failed to load variant ${label}:`, e);\n }\n }\n }\n\n if (alive) {\n setConfig({\n proposalId: componentConfig.proposal_id,\n variants: variantComponents,\n });\n setConfigLoading(false);\n }\n } catch (e) {\n console.warn(\"[PROBAT] Failed to load component config:\", e);\n if (alive) {\n setConfig(null);\n setConfigLoading(false);\n }\n }\n })();\n\n return () => { alive = false; };\n }, [useNewAPI, options.componentPath, repoFullName, apiBaseUrl]);\n\n // Fetch experiment decision\n useEffect(() => {\n if (!proposalId) return;\n if (useNewAPI && configLoading) return;\n\n let alive = true;\n const cached = readChoice(proposalId);\n\n if (cached) {\n setChoice({\n experiment_id: cached.experiment_id,\n label: cached.label,\n });\n } else {\n (async () => {\n try {\n const { experiment_id, label } = await fetchDecision(apiBaseUrl, proposalId);\n if (!alive) return;\n writeChoice(proposalId, experiment_id, label);\n setChoice({ experiment_id, label });\n } catch (e) {\n if (!alive) return;\n setChoice({\n experiment_id: `exp_${proposalId}`,\n label: \"control\",\n });\n }\n })();\n }\n\n return () => { alive = false; };\n }, [proposalId, apiBaseUrl, useNewAPI, configLoading]);\n\n // Track visit\n useEffect(() => {\n if (!proposalId) return;\n const lbl = choice?.label ?? \"control\";\n if (!lbl || hasTrackedVisit(proposalId, lbl)) return;\n markTrackedVisit(proposalId, lbl);\n void sendMetric(apiBaseUrl, proposalId, \"visit\", lbl, choice?.experiment_id);\n }, [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]);\n\n // 4. Callback hooks - always called\n const trackClick = useCallback(\n (event?: MouseEvent | null, opts?: { force?: boolean }) => {\n if (!proposalId) return false;\n const lbl = choice?.label ?? \"control\";\n const meta = extractClickMeta(event ?? undefined);\n if (!opts?.force && event && !meta) return false;\n void sendMetric(apiBaseUrl, proposalId, \"click\", lbl, undefined, meta);\n return true;\n },\n [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]\n );\n\n // ============================================================\n // NOW WE CAN DO CONDITIONAL RETURNS - AFTER ALL HOOKS\n // ============================================================\n\n // Loading state - return control\n if (useNewAPI && (configLoading || !config || !proposalId)) {\n return React.createElement(ControlComponent as any, props as any);\n }\n\n // No proposalId - return control\n if (!proposalId) {\n return React.createElement(ControlComponent as any, props as any);\n }\n\n // Build registry - always has control\n const registry: Record<string, React.ComponentType<any>> = { control: ControlComponent };\n\n if (useNewAPI && config?.variants) {\n for (const [key, value] of Object.entries(config.variants)) {\n if (key !== 'control' && value && typeof value === 'function') {\n registry[key] = value;\n }\n }\n } else if (!useNewAPI && options.registry) {\n for (const [key, value] of Object.entries(options.registry)) {\n if (key !== 'control' && value && typeof value === 'function') {\n registry[key] = value;\n }\n }\n }\n\n // Select variant\n const label = choice?.label ?? \"control\";\n const Variant = registry[label] || registry.control || ControlComponent;\n\n return (\n <div\n onClick={(event) => {\n // Keep existing onClick for backward compatibility\n // Document-level listener will also catch it (in capture phase)\n trackClick(event);\n }}\n data-probat-proposal={proposalId}\n data-probat-experiment-id={choice?.experiment_id || ''}\n data-probat-variant-label={label}\n data-probat-api-base-url={apiBaseUrl}\n >\n {React.createElement(Variant, {\n key: `${proposalId}:${label}`,\n ...(props as any),\n probat: { trackClick: () => trackClick(null, { force: true }) },\n })}\n </div>\n );\n }\n\n Wrapped.displayName = `withExperiment(${Control.displayName || Control.name || \"Component\"})`;\n return Wrapped as any;\n}\n"]}
package/dist/index.mjs CHANGED
@@ -55,7 +55,7 @@ async function sendMetric(baseUrl, proposalId, metricName, variantLabel = "contr
55
55
  captured_at: (/* @__PURE__ */ new Date()).toISOString()
56
56
  };
57
57
  try {
58
- await fetch(url, {
58
+ const response = await fetch(url, {
59
59
  method: "POST",
60
60
  headers: {
61
61
  Accept: "application/json",
@@ -65,7 +65,26 @@ async function sendMetric(baseUrl, proposalId, metricName, variantLabel = "contr
65
65
  // CRITICAL: Include cookies to distinguish different users
66
66
  body: JSON.stringify(body)
67
67
  });
68
- } catch {
68
+ if (!response.ok) {
69
+ console.warn("[PROBAT] Metric send failed:", {
70
+ status: response.status,
71
+ statusText: response.statusText,
72
+ url,
73
+ body
74
+ });
75
+ } else {
76
+ console.log("[PROBAT] Metric sent successfully:", {
77
+ metricName,
78
+ proposalId,
79
+ variantLabel
80
+ });
81
+ }
82
+ } catch (error) {
83
+ console.error("[PROBAT] Error sending metric:", {
84
+ error: error instanceof Error ? error.message : String(error),
85
+ url,
86
+ body
87
+ });
69
88
  }
70
89
  }
71
90
  function extractClickMeta(event) {
@@ -202,7 +221,9 @@ function handleDocumentClick(event) {
202
221
  const target = event.target;
203
222
  if (!target) return;
204
223
  const metadata = getProposalMetadata(target);
205
- if (!metadata) return;
224
+ if (!metadata) {
225
+ return;
226
+ }
206
227
  const now2 = Date.now();
207
228
  const lastClick = lastClickTime.get(metadata.proposalId) || 0;
208
229
  if (now2 - lastClick < DEBOUNCE_MS) {
@@ -210,19 +231,32 @@ function handleDocumentClick(event) {
210
231
  }
211
232
  lastClickTime.set(metadata.proposalId, now2);
212
233
  const clickMeta = extractClickMeta(event);
213
- const hasTrackAttribute = target.hasAttribute("data-probat-track") || target.closest("[data-probat-track]") !== null;
214
- const shouldTrack = clickMeta !== void 0 || hasTrackAttribute;
215
- if (!shouldTrack) {
216
- return;
217
- }
234
+ target.hasAttribute("data-probat-track") || target.closest("[data-probat-track]") !== null;
235
+ const finalMeta = clickMeta || {
236
+ target_tag: target.tagName,
237
+ target_class: target.className || "",
238
+ target_id: target.id || "",
239
+ clicked_inside_probat: true
240
+ // Flag to indicate this was tracked via document-level listener
241
+ };
242
+ const experimentId = metadata.variantLabel === "control" ? void 0 : metadata.experimentId && !metadata.experimentId.startsWith("exp_") ? metadata.experimentId : void 0;
218
243
  void sendMetric(
219
244
  metadata.apiBaseUrl,
220
245
  metadata.proposalId,
221
246
  "click",
222
247
  metadata.variantLabel,
223
- metadata.experimentId || void 0,
224
- clickMeta
248
+ experimentId,
249
+ finalMeta
225
250
  );
251
+ console.log("[PROBAT] Click tracked:", {
252
+ proposalId: metadata.proposalId,
253
+ variantLabel: metadata.variantLabel,
254
+ target: target.tagName,
255
+ targetId: target.id || "none",
256
+ targetClass: target.className || "none",
257
+ meta: finalMeta
258
+ });
259
+ console.log("[PROBAT] Sending metric to:", `${metadata.apiBaseUrl}/send_metrics/${metadata.proposalId}`);
226
260
  }
227
261
  function initDocumentClickTracking() {
228
262
  if (isListenerAttached) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/environment.ts","../src/utils/api.ts","../src/utils/documentClickTracker.ts","../src/context/ProbatContext.tsx","../src/components/ProbatProviderClient.tsx","../src/hooks/useProbatMetrics.ts","../src/utils/storage.ts","../src/hooks/useExperiment.ts","../src/hoc/withExperiment.tsx"],"names":["React","now","useEffect","useCallback","meta","useState","label"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Detect if the code is running on localhost (development environment).\n * Returns \"dev\" for localhost, \"prod\" for production.\n */\nexport function detectEnvironment(): \"dev\" | \"prod\" {\n if (typeof window === \"undefined\") {\n return \"prod\"; // Server-side, default to prod\n }\n\n const hostname = window.location.hostname;\n\n // Check for localhost, 127.0.0.1, or local IP addresses\n if (\n hostname === \"localhost\" ||\n hostname === \"127.0.0.1\" ||\n hostname === \"0.0.0.0\" ||\n hostname.startsWith(\"192.168.\") ||\n hostname.startsWith(\"10.\") ||\n hostname.startsWith(\"172.16.\") ||\n hostname.startsWith(\"172.17.\") ||\n hostname.startsWith(\"172.18.\") ||\n hostname.startsWith(\"172.19.\") ||\n hostname.startsWith(\"172.20.\") ||\n hostname.startsWith(\"172.21.\") ||\n hostname.startsWith(\"172.22.\") ||\n hostname.startsWith(\"172.23.\") ||\n hostname.startsWith(\"172.24.\") ||\n hostname.startsWith(\"172.25.\") ||\n hostname.startsWith(\"172.26.\") ||\n hostname.startsWith(\"172.27.\") ||\n hostname.startsWith(\"172.28.\") ||\n hostname.startsWith(\"172.29.\") ||\n hostname.startsWith(\"172.30.\") ||\n hostname.startsWith(\"172.31.\")\n ) {\n return \"dev\";\n }\n\n return \"prod\";\n}\n\n","import React from \"react\";\nimport { detectEnvironment } from \"./environment\";\n\nexport type RetrieveResponse = {\n proposal_id: string;\n experiment_id: string | null;\n label: string | null;\n};\n\nexport type ComponentVariantInfo = {\n experiment_id: string;\n label: string;\n file_path: string | null;\n};\n\nexport type ComponentExperimentConfig = {\n proposal_id: string;\n variants: Record<string, ComponentVariantInfo>;\n};\n\n// Shared promise cache to prevent multiple simultaneous API calls for the same proposal\nconst pendingFetches = new Map<\n string,\n Promise<{ experiment_id: string; label: string }>\n>();\n\nexport async function fetchDecision(\n baseUrl: string,\n proposalId: string\n): Promise<{ experiment_id: string; label: string }> {\n // Check if there's already a pending fetch for this proposal\n const existingFetch = pendingFetches.get(proposalId);\n if (existingFetch) {\n return existingFetch;\n }\n\n // Create new fetch promise\n const fetchPromise = (async () => {\n try {\n const url = `${baseUrl.replace(/\\/$/, \"\")}/retrieve_react_experiment/${encodeURIComponent(proposalId)}`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: { Accept: \"application/json\" },\n credentials: \"include\", // Include cookies for user identification\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const data = (await res.json()) as RetrieveResponse;\n\n const experiment_id = (data.experiment_id || `exp_${proposalId}`).toString();\n const label = data.label && data.label.trim() ? data.label : \"control\";\n\n return { experiment_id, label };\n } finally {\n // Remove from pending cache after completion\n pendingFetches.delete(proposalId);\n }\n })();\n\n // Store the promise so other components can wait for the same call\n pendingFetches.set(proposalId, fetchPromise);\n return fetchPromise;\n}\n\nexport async function sendMetric(\n baseUrl: string,\n proposalId: string,\n metricName: \"visit\" | \"click\" | string,\n variantLabel: string = \"control\",\n experimentId?: string,\n dimensions: Record<string, any> = {}\n) {\n const url = `${baseUrl.replace(/\\/$/, \"\")}/send_metrics/${encodeURIComponent(proposalId)}`;\n const body = {\n experiment_id: experimentId ?? null,\n variant_label: variantLabel,\n metric_name: metricName,\n metric_value: 1,\n metric_unit: \"count\",\n source: \"react\",\n environment: detectEnvironment(), // Include environment (dev or prod)\n dimensions,\n captured_at: new Date().toISOString(),\n };\n try {\n await fetch(url, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n credentials: \"include\", // CRITICAL: Include cookies to distinguish different users\n body: JSON.stringify(body),\n });\n } catch {\n // Silently fail - metrics should not break the app\n }\n}\n\nexport function extractClickMeta(\n event?: { target?: EventTarget | null } | null\n): Record<string, any> | undefined {\n if (!event || !event.target) return undefined;\n const rawTarget = event.target as HTMLElement | null;\n if (!rawTarget) return undefined;\n const actionable = rawTarget.closest(\n \"[data-probat-conversion='true'], button, a, [role='button']\"\n );\n if (!actionable) return undefined;\n const meta: Record<string, any> = {\n target_tag: actionable.tagName,\n };\n if (actionable.id) meta.target_id = actionable.id;\n const attr = actionable.getAttribute(\"data-probat-conversion\");\n if (attr) meta.conversion_attr = attr;\n const text = actionable.textContent?.trim();\n if (text) meta.target_text = text.slice(0, 120);\n return meta;\n}\n\n// Cache for component config fetches\nconst componentConfigCache = new Map<\n string,\n Promise<ComponentExperimentConfig | null>\n>();\n\nexport async function fetchComponentExperimentConfig(\n baseUrl: string,\n repoFullName: string,\n componentPath: string\n): Promise<ComponentExperimentConfig | null> {\n const cacheKey = `${repoFullName}:${componentPath}`;\n\n // Check cache\n const existingFetch = componentConfigCache.get(cacheKey);\n if (existingFetch) {\n return existingFetch;\n }\n\n // Create new fetch promise\n const fetchPromise = (async () => {\n try {\n const url = new URL(`${baseUrl.replace(/\\/$/, \"\")}/get_component_experiment_config`);\n url.searchParams.set(\"repo_full_name\", repoFullName);\n url.searchParams.set(\"component_path\", componentPath);\n\n const res = await fetch(url.toString(), {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n credentials: \"include\",\n });\n\n if (res.status === 404) {\n // No experiments for this component - return null\n return null;\n }\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n const data = (await res.json()) as ComponentExperimentConfig;\n return data;\n } catch (e) {\n console.warn(`[PROBAT] Failed to fetch component config: ${e}`);\n return null;\n } finally {\n // Remove from cache after completion\n componentConfigCache.delete(cacheKey);\n }\n })();\n\n // Store the promise\n componentConfigCache.set(cacheKey, fetchPromise);\n return fetchPromise;\n}\n\n// Cache for variant component loads\nconst variantComponentCache = new Map<string, Promise<React.ComponentType<any> | null>>();\n\n// Make React available globally for variant components\nif (typeof window !== \"undefined\") {\n (window as any).__probatReact = React;\n (window as any).React = (window as any).React || React;\n}\n\nexport async function loadVariantComponent(\n baseUrl: string,\n proposalId: string,\n experimentId: string,\n filePath: string | null\n): Promise<React.ComponentType<any> | null> {\n if (!filePath) {\n return null;\n }\n\n const cacheKey = `${proposalId}:${experimentId}`;\n\n // Check cache\n const existingLoad = variantComponentCache.get(cacheKey);\n if (existingLoad) {\n return existingLoad;\n }\n\n // Create new load promise\n const loadPromise = (async () => {\n try {\n // Fetch the variant code (server compiles TSX/JSX to JS)\n const variantUrl = `${baseUrl.replace(/\\/$/, \"\")}/variants/${filePath}`;\n\n const res = await fetch(variantUrl, {\n method: \"GET\",\n headers: { Accept: \"text/javascript\" },\n credentials: \"include\",\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n const code = await res.text();\n\n // The server returns an IIFE that assigns to __probatVariant\n // Execute the code to get the component\n // First, ensure React is available globally\n if (typeof window !== \"undefined\") {\n (window as any).React = (window as any).React || React;\n }\n\n // Execute the IIFE code\n const evalFunc = new Function(`\n var __probatVariant;\n ${code}\n return __probatVariant;\n `);\n\n const result = evalFunc();\n\n // The result is { default: Component } from esbuild's IIFE output\n const VariantComponent = result?.default || result;\n\n if (typeof VariantComponent === \"function\") {\n return VariantComponent as React.ComponentType<any>;\n }\n\n console.warn(\"[PROBAT] Variant component is not a function\", result);\n return null;\n } catch (e) {\n console.warn(`[PROBAT] Failed to load variant component: ${e}`);\n return null;\n } finally {\n // Remove from cache after completion\n variantComponentCache.delete(cacheKey);\n }\n })();\n\n // Store the promise\n variantComponentCache.set(cacheKey, loadPromise);\n return loadPromise;\n}\n\n","/**\n * Document-level click tracking for Probat experiments\n * \n * This module implements event delegation at the document level to track clicks\n * even when components don't have onClick handlers or when stopPropagation() is called.\n */\n\nimport { sendMetric } from './api';\nimport { extractClickMeta } from './api';\n\n// Cache for proposal metadata to avoid repeated DOM queries\nconst proposalCache = new Map<string, {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n}>();\n\n// Track if listener is already attached\nlet isListenerAttached = false;\n\n// Rate limiting: prevent duplicate rapid clicks\nconst lastClickTime = new Map<string, number>();\nconst DEBOUNCE_MS = 100; // Ignore clicks within 100ms of each other\n\n/**\n * Get proposal metadata from DOM element\n * Looks for the nearest [data-probat-proposal] wrapper\n */\nfunction getProposalMetadata(element: HTMLElement): {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n} | null {\n // Find the nearest probat wrapper\n const probatWrapper = element.closest('[data-probat-proposal]') as HTMLElement | null;\n \n if (!probatWrapper) return null;\n \n const proposalId = probatWrapper.getAttribute('data-probat-proposal');\n if (!proposalId) return null;\n \n // Check cache first\n const cacheKey = `${proposalId}`;\n const cached = proposalCache.get(cacheKey);\n if (cached) return cached;\n \n // Extract metadata from data attributes\n const experimentId = probatWrapper.getAttribute('data-probat-experiment-id');\n const variantLabel = probatWrapper.getAttribute('data-probat-variant-label') || 'control';\n const apiBaseUrl = probatWrapper.getAttribute('data-probat-api-base-url') || \n (typeof window !== 'undefined' && (window as any).__PROBAT_API) ||\n 'https://gushi.onrender.com';\n \n const metadata = {\n proposalId,\n experimentId: experimentId || null,\n variantLabel,\n apiBaseUrl,\n };\n \n // Cache it\n proposalCache.set(cacheKey, metadata);\n return metadata;\n}\n\n/**\n * Handle click event at document level\n * Uses capture phase to catch events before stopPropagation()\n */\nfunction handleDocumentClick(event: MouseEvent): void {\n const target = event.target as HTMLElement | null;\n if (!target) return;\n \n // Get proposal metadata\n const metadata = getProposalMetadata(target);\n if (!metadata) return;\n \n // Rate limiting: prevent duplicate rapid clicks\n const now = Date.now();\n const lastClick = lastClickTime.get(metadata.proposalId) || 0;\n if (now - lastClick < DEBOUNCE_MS) {\n return; // Ignore rapid duplicate clicks\n }\n lastClickTime.set(metadata.proposalId, now);\n \n // Extract click metadata (your existing function)\n const clickMeta = extractClickMeta(event);\n \n // Determine if we should track this click\n // Track if:\n // 1. It's an actionable element (button, link, etc.) - clickMeta exists\n // 2. Element has data-probat-track attribute\n // 3. Parent has data-probat-track attribute\n const hasTrackAttribute = target.hasAttribute('data-probat-track') || \n target.closest('[data-probat-track]') !== null;\n \n const shouldTrack = clickMeta !== undefined || hasTrackAttribute;\n \n if (!shouldTrack) {\n // Optional: Track \"dead clicks\" for UX insights\n // Uncomment the code below if you want to track clicks on non-interactive elements\n /*\n const deadClickMeta = {\n dead_click: true,\n target_tag: target.tagName,\n target_class: target.className || '',\n target_id: target.id || '',\n };\n \n void sendMetric(\n metadata.apiBaseUrl,\n metadata.proposalId,\n 'dead_click',\n metadata.variantLabel,\n metadata.experimentId,\n deadClickMeta\n );\n */\n return;\n }\n \n // Send click metric\n void sendMetric(\n metadata.apiBaseUrl,\n metadata.proposalId,\n 'click',\n metadata.variantLabel,\n metadata.experimentId || undefined,\n clickMeta\n );\n}\n\n/**\n * Initialize document-level click tracking\n * Call this once when your app initializes (typically in ProbatProvider)\n */\nexport function initDocumentClickTracking(): void {\n if (isListenerAttached) {\n console.warn('[PROBAT] Document click listener already attached');\n return;\n }\n \n if (typeof document === 'undefined') {\n // Server-side rendering - skip\n return;\n }\n \n // Use capture phase (true) to catch events before they bubble\n // This ensures we catch clicks even if stopPropagation() is called\n document.addEventListener('click', handleDocumentClick, true);\n \n isListenerAttached = true;\n console.log('[PROBAT] Document-level click tracking initialized');\n}\n\n/**\n * Clean up the listener (useful for testing or cleanup)\n */\nexport function cleanupDocumentClickTracking(): void {\n if (!isListenerAttached) return;\n \n if (typeof document !== 'undefined') {\n document.removeEventListener('click', handleDocumentClick, true);\n }\n \n isListenerAttached = false;\n proposalCache.clear();\n lastClickTime.clear();\n}\n\n/**\n * Update proposal metadata cache (call this when proposal data changes)\n * This is useful if you want to update the cache without waiting for DOM queries\n */\nexport function updateProposalMetadata(\n proposalId: string,\n metadata: {\n experimentId?: string | null;\n variantLabel?: string;\n apiBaseUrl?: string;\n }\n): void {\n const existing = proposalCache.get(proposalId);\n if (existing) {\n proposalCache.set(proposalId, {\n ...existing,\n ...metadata,\n });\n }\n}\n\n/**\n * Clear the proposal cache (useful for testing)\n */\nexport function clearProposalCache(): void {\n proposalCache.clear();\n}\n\n","\"use client\";\n\nimport React, { createContext, useContext, useMemo, useEffect } from \"react\";\nimport { detectEnvironment } from \"../utils/environment\";\nimport { initDocumentClickTracking, cleanupDocumentClickTracking } from \"../utils/documentClickTracker\";\n\ndeclare global {\n interface Window {\n __PROBAT_API?: string;\n }\n}\n\nexport interface ProbatContextValue {\n apiBaseUrl: string;\n environment: \"dev\" | \"prod\";\n clientKey?: string;\n repoFullName?: string; // Repository full name (e.g., \"owner/repo\") for component-based experiments\n}\n\nconst ProbatContext = createContext<ProbatContextValue | null>(null);\n\nexport interface ProbatProviderProps {\n /**\n * The base URL for the Probat API.\n * If not provided, will try to read from:\n * - VITE_PROBAT_API (Vite)\n * - NEXT_PUBLIC_PROBAT_API (Next.js)\n * - window.__PROBAT_API\n * - Default: \"https://gushi.onrender.com\"\n */\n apiBaseUrl?: string;\n /**\n * Client key for identification (optional)\n */\n clientKey?: string;\n /**\n * Explicitly set environment. If not provided, will auto-detect based on hostname.\n * \"dev\" for localhost, \"prod\" for production.\n */\n environment?: \"dev\" | \"prod\";\n /**\n * Repository full name (e.g., \"owner/repo\") for component-based experiments.\n * If not provided, will try to read from:\n * - NEXT_PUBLIC_PROBAT_REPO (Next.js)\n * - VITE_PROBAT_REPO (Vite)\n * - window.__PROBAT_REPO\n */\n repoFullName?: string;\n children: React.ReactNode;\n}\n\nexport function ProbatProvider({\n apiBaseUrl,\n clientKey,\n environment: explicitEnvironment,\n repoFullName: explicitRepoFullName,\n children,\n}: ProbatProviderProps) {\n const contextValue = useMemo<ProbatContextValue>(() => {\n // Determine API base URL\n const resolvedApiBaseUrl =\n apiBaseUrl ||\n (typeof import.meta !== \"undefined\" &&\n (import.meta as any).env?.VITE_PROBAT_API) ||\n (typeof globalThis !== \"undefined\" &&\n (globalThis as any).process?.env?.NEXT_PUBLIC_PROBAT_API) ||\n (typeof window !== \"undefined\" && window.__PROBAT_API) ||\n \"https://gushi.onrender.com\";\n\n // Determine environment\n const environment = explicitEnvironment || detectEnvironment();\n\n // Determine repo full name\n const resolvedRepoFullName =\n explicitRepoFullName ||\n (typeof globalThis !== \"undefined\" &&\n (globalThis as any).process?.env?.NEXT_PUBLIC_PROBAT_REPO) ||\n (typeof import.meta !== \"undefined\" &&\n (import.meta as any).env?.VITE_PROBAT_REPO) ||\n (typeof window !== \"undefined\" && (window as any).__PROBAT_REPO) ||\n undefined;\n\n return {\n apiBaseUrl: resolvedApiBaseUrl,\n environment,\n clientKey,\n repoFullName: resolvedRepoFullName,\n };\n }, [apiBaseUrl, clientKey, explicitEnvironment, explicitRepoFullName]);\n\n // Initialize document-level click tracking when provider mounts\n useEffect(() => {\n initDocumentClickTracking();\n \n // Cleanup on unmount (optional, but good practice)\n return () => {\n cleanupDocumentClickTracking();\n };\n }, []);\n\n return (\n <ProbatContext.Provider value={contextValue}>\n {children}\n </ProbatContext.Provider>\n );\n}\n\nexport function useProbatContext(): ProbatContextValue {\n const context = useContext(ProbatContext);\n if (!context) {\n throw new Error(\n \"useProbatContext must be used within a ProbatProvider. Please wrap your app with <ProbatProvider>.\"\n );\n }\n return context;\n}\n\n","\"use client\";\n\nimport React from \"react\";\nimport { ProbatProvider as BaseProbatProvider } from \"../context/ProbatContext\";\nimport type { ProbatProviderProps } from \"../context/ProbatContext\";\n\n/**\n * ProbatProviderClient - Can be imported directly in Next.js Server Components\n * This is a re-export with \"use client\" directive to ensure it works in Server Components\n */\nexport function ProbatProviderClient(props: ProbatProviderProps) {\n return React.createElement(BaseProbatProvider, props);\n}\n\n// Also export as ProbatProvider for convenience\nexport { ProbatProviderClient as ProbatProvider };\nexport type { ProbatProviderProps };\n\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { sendMetric, extractClickMeta } from \"../utils/api\";\n\nexport interface UseProbatMetricsReturn {\n /**\n * Track a click event\n * @param event - Optional React mouse event (will extract metadata automatically)\n * @param options - Optional configuration\n * @param options.force - Force tracking even if no actionable element is found\n * @param options.proposalId - Override the proposal ID (usually not needed)\n * @param options.variantLabel - Override the variant label (usually not needed)\n * @param options.dimensions - Additional dimensions to include\n */\n trackClick: (\n event?: MouseEvent | null,\n options?: {\n force?: boolean;\n proposalId?: string;\n variantLabel?: string;\n dimensions?: Record<string, any>;\n }\n ) => boolean;\n /**\n * Track a custom metric\n * @param metricName - Name of the metric\n * @param proposalId - Proposal ID\n * @param variantLabel - Variant label (defaults to \"control\")\n * @param dimensions - Additional dimensions\n */\n trackMetric: (\n metricName: string,\n proposalId: string,\n variantLabel?: string,\n dimensions?: Record<string, any>\n ) => void;\n /**\n * Track an impression/view\n * @param proposalId - Proposal ID\n * @param variantLabel - Variant label (defaults to \"control\")\n * @param experimentId - Optional experiment ID\n */\n trackImpression: (\n proposalId: string,\n variantLabel?: string,\n experimentId?: string\n ) => void;\n}\n\n/**\n * Hook for tracking Probat metrics (clicks, impressions, custom metrics)\n *\n * @example\n * ```tsx\n * const { trackClick, trackImpression } = useProbatMetrics();\n *\n * // Track click on button\n * <button onClick={(e) => trackClick(e)}>Click me</button>\n *\n * // Track impression\n * useEffect(() => {\n * trackImpression(proposalId, variantLabel, experimentId);\n * }, [proposalId, variantLabel, experimentId]);\n * ```\n */\nexport function useProbatMetrics(): UseProbatMetricsReturn {\n const { apiBaseUrl } = useProbatContext();\n\n const trackClick = useCallback(\n (\n event?: MouseEvent | null,\n options?: {\n force?: boolean;\n proposalId?: string;\n variantLabel?: string;\n dimensions?: Record<string, any>;\n }\n ) => {\n const meta = extractClickMeta(event ?? undefined);\n if (!options?.force && event && !meta) {\n return false;\n }\n\n const proposalId = options?.proposalId;\n const variantLabel = options?.variantLabel || \"control\";\n\n if (!proposalId) {\n console.warn(\n \"[Probat] trackClick called without proposalId. Provide it in options or use useExperiment hook.\"\n );\n return false;\n }\n\n void sendMetric(\n apiBaseUrl,\n proposalId,\n \"click\",\n variantLabel,\n undefined,\n { ...meta, ...options?.dimensions }\n );\n return true;\n },\n [apiBaseUrl]\n );\n\n const trackMetric = useCallback(\n (\n metricName: string,\n proposalId: string,\n variantLabel: string = \"control\",\n dimensions: Record<string, any> = {}\n ) => {\n void sendMetric(\n apiBaseUrl,\n proposalId,\n metricName,\n variantLabel,\n undefined,\n dimensions\n );\n },\n [apiBaseUrl]\n );\n\n const trackImpression = useCallback(\n (\n proposalId: string,\n variantLabel: string = \"control\",\n experimentId?: string\n ) => {\n void sendMetric(\n apiBaseUrl,\n proposalId,\n \"visit\",\n variantLabel,\n experimentId\n );\n },\n [apiBaseUrl]\n );\n\n return {\n trackClick,\n trackMetric,\n trackImpression,\n };\n}\n\n","const TTL_MS = 6 * 60 * 60 * 1000; // 6 hours\n\nexport type Choice = {\n experiment_id: string;\n label: string;\n ts: number;\n};\n\nexport function safeGet(k: string): any | null {\n try {\n const raw = localStorage.getItem(k);\n return raw ? JSON.parse(raw) : null;\n } catch {\n return null;\n }\n}\n\nexport function safeSet(k: string, v: any) {\n try {\n localStorage.setItem(k, JSON.stringify(v));\n } catch { }\n}\n\nexport function now() {\n return Date.now();\n}\n\nexport function fresh(ts: number) {\n return now() - ts <= TTL_MS;\n}\n\nexport const KEY = (proposalId: string) => `probat_choice_v3:${proposalId}`;\nexport const VISIT_KEY = (proposalId: string, label: string) =>\n `probat_visit_v1:${proposalId}:${label}`;\n\nexport function readChoice(proposalId: string): Choice | null {\n const c = safeGet(KEY(proposalId)) as Choice | null;\n return c && fresh(c.ts) ? c : null;\n}\n\nexport function writeChoice(\n proposalId: string,\n experiment_id: string,\n label: string\n) {\n safeSet(KEY(proposalId), { experiment_id, label, ts: now() } as Choice);\n}\n\nconst visitMemo = new Set<string>();\n\nexport function hasTrackedVisit(proposalId: string, label: string): boolean {\n const key = VISIT_KEY(proposalId, label);\n if (visitMemo.has(key)) return true;\n try {\n const raw = localStorage.getItem(key);\n if (!raw) return false;\n const ts = Number(raw);\n if (!Number.isFinite(ts) || ts <= 0) return false;\n if (now() - ts > TTL_MS) {\n localStorage.removeItem(key);\n return false;\n }\n visitMemo.add(key);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function markTrackedVisit(proposalId: string, label: string) {\n const key = VISIT_KEY(proposalId, label);\n visitMemo.add(key);\n try {\n localStorage.setItem(key, now().toString());\n } catch { }\n}\n\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { fetchDecision } from \"../utils/api\";\nimport {\n readChoice,\n writeChoice,\n hasTrackedVisit,\n markTrackedVisit,\n} from \"../utils/storage\";\nimport { sendMetric } from \"../utils/api\";\n\nexport interface UseExperimentReturn {\n /**\n * The current variant label (e.g., \"control\", \"variant-a\")\n */\n variantLabel: string;\n /**\n * The experiment ID\n */\n experimentId: string | null;\n /**\n * Whether the experiment decision is still loading\n */\n isLoading: boolean;\n /**\n * Any error that occurred while fetching the experiment\n */\n error: Error | null;\n /**\n * Manually track a click for this experiment\n */\n trackClick: (event?: MouseEvent | null) => void;\n}\n\n/**\n * Hook for fetching and applying experiment variants\n *\n * @param proposalId - The proposal ID for the experiment\n * @param options - Optional configuration\n * @param options.autoTrackImpression - Automatically track impression when variant is loaded (default: true)\n *\n * @example\n * ```tsx\n * const { variantLabel, isLoading, trackClick } = useExperiment(\"proposal-id\");\n *\n * if (isLoading) return <div>Loading...</div>;\n *\n * return (\n * <div onClick={trackClick}>\n * {variantLabel === \"control\" ? <ControlComponent /> : <VariantComponent />}\n * </div>\n * );\n * ```\n */\nexport function useExperiment(\n proposalId: string,\n options?: { autoTrackImpression?: boolean }\n): UseExperimentReturn {\n const { apiBaseUrl } = useProbatContext();\n const [choice, setChoice] = useState<{\n experiment_id: string;\n label: string;\n } | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const autoTrackImpression = options?.autoTrackImpression !== false;\n\n // Fetch experiment decision\n useEffect(() => {\n let alive = true;\n\n const cached = readChoice(proposalId);\n if (cached) {\n setChoice({ experiment_id: cached.experiment_id, label: cached.label });\n setIsLoading(false);\n } else {\n setIsLoading(true);\n (async () => {\n try {\n const { experiment_id, label } = await fetchDecision(\n apiBaseUrl,\n proposalId\n );\n if (!alive) return;\n writeChoice(proposalId, experiment_id, label);\n setChoice({ experiment_id, label });\n setError(null);\n } catch (e) {\n if (!alive) return;\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n setChoice({\n experiment_id: `exp_${proposalId}`,\n label: \"control\",\n });\n } finally {\n if (alive) {\n setIsLoading(false);\n }\n }\n })();\n }\n\n return () => {\n alive = false;\n };\n }, [proposalId, apiBaseUrl]);\n\n // Track impression when variant is determined\n useEffect(() => {\n if (!autoTrackImpression || !choice) return;\n\n const exp = choice.experiment_id;\n const lbl = choice.label ?? \"control\";\n if (!lbl) return;\n\n // Only track if we haven't already tracked this visit\n if (hasTrackedVisit(proposalId, lbl)) return;\n markTrackedVisit(proposalId, lbl);\n void sendMetric(apiBaseUrl, proposalId, \"visit\", lbl, exp);\n }, [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl, autoTrackImpression]);\n\n const trackClick = useCallback(\n (event?: MouseEvent | null) => {\n const exp = choice?.experiment_id;\n const lbl = choice?.label ?? \"control\";\n const meta = event\n ? (() => {\n const rawTarget = event.target as HTMLElement | null;\n if (!rawTarget) return undefined;\n const actionable = rawTarget.closest(\n \"[data-probat-conversion='true'], button, a, [role='button']\"\n );\n if (!actionable) return undefined;\n const meta: Record<string, any> = {\n target_tag: actionable.tagName,\n };\n if (actionable.id) meta.target_id = actionable.id;\n const attr = actionable.getAttribute(\"data-probat-conversion\");\n if (attr) meta.conversion_attr = attr;\n const text = actionable.textContent?.trim();\n if (text) meta.target_text = text.slice(0, 120);\n return meta;\n })()\n : undefined;\n\n void sendMetric(apiBaseUrl, proposalId, \"click\", lbl, undefined, meta);\n },\n [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]\n );\n\n return {\n variantLabel: choice?.label ?? \"control\",\n experimentId: choice?.experiment_id ?? null,\n isLoading,\n error,\n trackClick,\n };\n}\n\n","\"use client\";\n\nimport React, { useState, useEffect, useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport {\n fetchDecision,\n fetchComponentExperimentConfig,\n loadVariantComponent,\n sendMetric,\n extractClickMeta,\n} from \"../utils/api\";\nimport {\n readChoice,\n writeChoice,\n hasTrackedVisit,\n markTrackedVisit,\n} from \"../utils/storage\";\n\n// Support both old and new API for backward compatibility\nexport interface WithExperimentOptions {\n // New API: component-based\n componentPath?: string;\n repoFullName?: string;\n\n // Old API: direct proposal/registry (for backward compatibility)\n proposalId?: string;\n registry?: Record<string, React.ComponentType<any>>;\n}\n\n/**\n * Higher-Order Component for wrapping components with experiment variants\n */\nexport function withExperiment<P = any>(\n Control: React.ComponentType<P>,\n options: WithExperimentOptions\n): React.ComponentType<P & { probat?: { trackClick: () => void } }> {\n // Validate inputs at HOC level (not in component)\n if (!Control) {\n console.error(\"[PROBAT] withExperiment: Control component is required\");\n return ((props: P) => null) as any;\n }\n\n if (!options || typeof options !== 'object') {\n console.error(\"[PROBAT] withExperiment: options is required\");\n return Control as any;\n }\n\n const useNewAPI = !!options.componentPath;\n const useOldAPI = !!(options.proposalId && options.registry);\n\n if (!useNewAPI && !useOldAPI) {\n console.warn(\"[PROBAT] withExperiment: Invalid config, returning Control\");\n return Control as any;\n }\n\n const ControlComponent = Control;\n\n function Wrapped(props: P) {\n // ============================================================\n // ALL HOOKS MUST BE AT THE TOP - BEFORE ANY CONDITIONAL RETURNS\n // ============================================================\n\n // 1. Context hook - always called first\n const context = useProbatContext();\n const apiBaseUrl = context?.apiBaseUrl || \"https://gushi.onrender.com\";\n const contextRepoFullName = context?.repoFullName;\n\n // 2. State hooks - always called in same order\n const [config, setConfig] = useState<{\n proposalId: string;\n variants: Record<string, React.ComponentType<any>>;\n } | null>(null);\n const [configLoading, setConfigLoading] = useState(useNewAPI);\n const [choice, setChoice] = useState<{\n experiment_id: string;\n label: string;\n } | null>(null);\n\n // Derived values\n const repoFullName = options.repoFullName || contextRepoFullName;\n const proposalId = useNewAPI ? config?.proposalId : options.proposalId;\n\n // 3. Effect hooks - always called\n // Load component config (new API)\n useEffect(() => {\n if (!useNewAPI) return;\n if (!repoFullName) {\n console.warn(\"[PROBAT] componentPath provided but repoFullName not found\");\n setConfigLoading(false);\n return;\n }\n\n let alive = true;\n setConfigLoading(true);\n\n (async () => {\n try {\n const componentConfig = await fetchComponentExperimentConfig(\n apiBaseUrl,\n repoFullName,\n options.componentPath!\n );\n\n if (!alive) return;\n\n if (!componentConfig) {\n setConfig(null);\n setConfigLoading(false);\n return;\n }\n\n const variantComponents: Record<string, React.ComponentType<any>> = {\n control: ControlComponent,\n };\n\n for (const [label, variantInfo] of Object.entries(componentConfig.variants)) {\n if (label === \"control\") continue;\n if (variantInfo?.file_path) {\n try {\n const VariantComp = await loadVariantComponent(\n apiBaseUrl,\n componentConfig.proposal_id,\n variantInfo.experiment_id,\n variantInfo.file_path\n );\n if (VariantComp && typeof VariantComp === 'function' && alive) {\n variantComponents[label] = VariantComp;\n }\n } catch (e) {\n console.warn(`[PROBAT] Failed to load variant ${label}:`, e);\n }\n }\n }\n\n if (alive) {\n setConfig({\n proposalId: componentConfig.proposal_id,\n variants: variantComponents,\n });\n setConfigLoading(false);\n }\n } catch (e) {\n console.warn(\"[PROBAT] Failed to load component config:\", e);\n if (alive) {\n setConfig(null);\n setConfigLoading(false);\n }\n }\n })();\n\n return () => { alive = false; };\n }, [useNewAPI, options.componentPath, repoFullName, apiBaseUrl]);\n\n // Fetch experiment decision\n useEffect(() => {\n if (!proposalId) return;\n if (useNewAPI && configLoading) return;\n\n let alive = true;\n const cached = readChoice(proposalId);\n\n if (cached) {\n setChoice({\n experiment_id: cached.experiment_id,\n label: cached.label,\n });\n } else {\n (async () => {\n try {\n const { experiment_id, label } = await fetchDecision(apiBaseUrl, proposalId);\n if (!alive) return;\n writeChoice(proposalId, experiment_id, label);\n setChoice({ experiment_id, label });\n } catch (e) {\n if (!alive) return;\n setChoice({\n experiment_id: `exp_${proposalId}`,\n label: \"control\",\n });\n }\n })();\n }\n\n return () => { alive = false; };\n }, [proposalId, apiBaseUrl, useNewAPI, configLoading]);\n\n // Track visit\n useEffect(() => {\n if (!proposalId) return;\n const lbl = choice?.label ?? \"control\";\n if (!lbl || hasTrackedVisit(proposalId, lbl)) return;\n markTrackedVisit(proposalId, lbl);\n void sendMetric(apiBaseUrl, proposalId, \"visit\", lbl, choice?.experiment_id);\n }, [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]);\n\n // 4. Callback hooks - always called\n const trackClick = useCallback(\n (event?: MouseEvent | null, opts?: { force?: boolean }) => {\n if (!proposalId) return false;\n const lbl = choice?.label ?? \"control\";\n const meta = extractClickMeta(event ?? undefined);\n if (!opts?.force && event && !meta) return false;\n void sendMetric(apiBaseUrl, proposalId, \"click\", lbl, undefined, meta);\n return true;\n },\n [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]\n );\n\n // ============================================================\n // NOW WE CAN DO CONDITIONAL RETURNS - AFTER ALL HOOKS\n // ============================================================\n\n // Loading state - return control\n if (useNewAPI && (configLoading || !config || !proposalId)) {\n return React.createElement(ControlComponent as any, props as any);\n }\n\n // No proposalId - return control\n if (!proposalId) {\n return React.createElement(ControlComponent as any, props as any);\n }\n\n // Build registry - always has control\n const registry: Record<string, React.ComponentType<any>> = { control: ControlComponent };\n\n if (useNewAPI && config?.variants) {\n for (const [key, value] of Object.entries(config.variants)) {\n if (key !== 'control' && value && typeof value === 'function') {\n registry[key] = value;\n }\n }\n } else if (!useNewAPI && options.registry) {\n for (const [key, value] of Object.entries(options.registry)) {\n if (key !== 'control' && value && typeof value === 'function') {\n registry[key] = value;\n }\n }\n }\n\n // Select variant\n const label = choice?.label ?? \"control\";\n const Variant = registry[label] || registry.control || ControlComponent;\n\n return (\n <div\n onClick={(event) => {\n // Keep existing onClick for backward compatibility\n // Document-level listener will also catch it (in capture phase)\n trackClick(event);\n }}\n data-probat-proposal={proposalId}\n data-probat-experiment-id={choice?.experiment_id || ''}\n data-probat-variant-label={label}\n data-probat-api-base-url={apiBaseUrl}\n >\n {React.createElement(Variant, {\n key: `${proposalId}:${label}`,\n ...(props as any),\n probat: { trackClick: () => trackClick(null, { force: true }) },\n })}\n </div>\n );\n }\n\n Wrapped.displayName = `withExperiment(${Control.displayName || Control.name || \"Component\"})`;\n return Wrapped as any;\n}\n"]}
1
+ {"version":3,"sources":["../src/utils/environment.ts","../src/utils/api.ts","../src/utils/documentClickTracker.ts","../src/context/ProbatContext.tsx","../src/components/ProbatProviderClient.tsx","../src/hooks/useProbatMetrics.ts","../src/utils/storage.ts","../src/hooks/useExperiment.ts","../src/hoc/withExperiment.tsx"],"names":["React","now","useEffect","useCallback","meta","useState","label"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Detect if the code is running on localhost (development environment).\n * Returns \"dev\" for localhost, \"prod\" for production.\n */\nexport function detectEnvironment(): \"dev\" | \"prod\" {\n if (typeof window === \"undefined\") {\n return \"prod\"; // Server-side, default to prod\n }\n\n const hostname = window.location.hostname;\n\n // Check for localhost, 127.0.0.1, or local IP addresses\n if (\n hostname === \"localhost\" ||\n hostname === \"127.0.0.1\" ||\n hostname === \"0.0.0.0\" ||\n hostname.startsWith(\"192.168.\") ||\n hostname.startsWith(\"10.\") ||\n hostname.startsWith(\"172.16.\") ||\n hostname.startsWith(\"172.17.\") ||\n hostname.startsWith(\"172.18.\") ||\n hostname.startsWith(\"172.19.\") ||\n hostname.startsWith(\"172.20.\") ||\n hostname.startsWith(\"172.21.\") ||\n hostname.startsWith(\"172.22.\") ||\n hostname.startsWith(\"172.23.\") ||\n hostname.startsWith(\"172.24.\") ||\n hostname.startsWith(\"172.25.\") ||\n hostname.startsWith(\"172.26.\") ||\n hostname.startsWith(\"172.27.\") ||\n hostname.startsWith(\"172.28.\") ||\n hostname.startsWith(\"172.29.\") ||\n hostname.startsWith(\"172.30.\") ||\n hostname.startsWith(\"172.31.\")\n ) {\n return \"dev\";\n }\n\n return \"prod\";\n}\n\n","import React from \"react\";\nimport { detectEnvironment } from \"./environment\";\n\nexport type RetrieveResponse = {\n proposal_id: string;\n experiment_id: string | null;\n label: string | null;\n};\n\nexport type ComponentVariantInfo = {\n experiment_id: string;\n label: string;\n file_path: string | null;\n};\n\nexport type ComponentExperimentConfig = {\n proposal_id: string;\n variants: Record<string, ComponentVariantInfo>;\n};\n\n// Shared promise cache to prevent multiple simultaneous API calls for the same proposal\nconst pendingFetches = new Map<\n string,\n Promise<{ experiment_id: string; label: string }>\n>();\n\nexport async function fetchDecision(\n baseUrl: string,\n proposalId: string\n): Promise<{ experiment_id: string; label: string }> {\n // Check if there's already a pending fetch for this proposal\n const existingFetch = pendingFetches.get(proposalId);\n if (existingFetch) {\n return existingFetch;\n }\n\n // Create new fetch promise\n const fetchPromise = (async () => {\n try {\n const url = `${baseUrl.replace(/\\/$/, \"\")}/retrieve_react_experiment/${encodeURIComponent(proposalId)}`;\n const res = await fetch(url, {\n method: \"POST\",\n headers: { Accept: \"application/json\" },\n credentials: \"include\", // Include cookies for user identification\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const data = (await res.json()) as RetrieveResponse;\n\n const experiment_id = (data.experiment_id || `exp_${proposalId}`).toString();\n const label = data.label && data.label.trim() ? data.label : \"control\";\n\n return { experiment_id, label };\n } finally {\n // Remove from pending cache after completion\n pendingFetches.delete(proposalId);\n }\n })();\n\n // Store the promise so other components can wait for the same call\n pendingFetches.set(proposalId, fetchPromise);\n return fetchPromise;\n}\n\nexport async function sendMetric(\n baseUrl: string,\n proposalId: string,\n metricName: \"visit\" | \"click\" | string,\n variantLabel: string = \"control\",\n experimentId?: string,\n dimensions: Record<string, any> = {}\n) {\n const url = `${baseUrl.replace(/\\/$/, \"\")}/send_metrics/${encodeURIComponent(proposalId)}`;\n const body = {\n experiment_id: experimentId ?? null,\n variant_label: variantLabel,\n metric_name: metricName,\n metric_value: 1,\n metric_unit: \"count\",\n source: \"react\",\n environment: detectEnvironment(), // Include environment (dev or prod)\n dimensions,\n captured_at: new Date().toISOString(),\n };\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n },\n credentials: \"include\", // CRITICAL: Include cookies to distinguish different users\n body: JSON.stringify(body),\n });\n \n // Log in development for debugging\n if (!response.ok) {\n console.warn('[PROBAT] Metric send failed:', {\n status: response.status,\n statusText: response.statusText,\n url,\n body,\n });\n } else {\n console.log('[PROBAT] Metric sent successfully:', {\n metricName,\n proposalId,\n variantLabel,\n });\n }\n } catch (error) {\n // Log error in development, but don't break the app\n console.error('[PROBAT] Error sending metric:', {\n error: error instanceof Error ? error.message : String(error),\n url,\n body,\n });\n }\n}\n\nexport function extractClickMeta(\n event?: { target?: EventTarget | null } | null\n): Record<string, any> | undefined {\n if (!event || !event.target) return undefined;\n const rawTarget = event.target as HTMLElement | null;\n if (!rawTarget) return undefined;\n const actionable = rawTarget.closest(\n \"[data-probat-conversion='true'], button, a, [role='button']\"\n );\n if (!actionable) return undefined;\n const meta: Record<string, any> = {\n target_tag: actionable.tagName,\n };\n if (actionable.id) meta.target_id = actionable.id;\n const attr = actionable.getAttribute(\"data-probat-conversion\");\n if (attr) meta.conversion_attr = attr;\n const text = actionable.textContent?.trim();\n if (text) meta.target_text = text.slice(0, 120);\n return meta;\n}\n\n// Cache for component config fetches\nconst componentConfigCache = new Map<\n string,\n Promise<ComponentExperimentConfig | null>\n>();\n\nexport async function fetchComponentExperimentConfig(\n baseUrl: string,\n repoFullName: string,\n componentPath: string\n): Promise<ComponentExperimentConfig | null> {\n const cacheKey = `${repoFullName}:${componentPath}`;\n\n // Check cache\n const existingFetch = componentConfigCache.get(cacheKey);\n if (existingFetch) {\n return existingFetch;\n }\n\n // Create new fetch promise\n const fetchPromise = (async () => {\n try {\n const url = new URL(`${baseUrl.replace(/\\/$/, \"\")}/get_component_experiment_config`);\n url.searchParams.set(\"repo_full_name\", repoFullName);\n url.searchParams.set(\"component_path\", componentPath);\n\n const res = await fetch(url.toString(), {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n credentials: \"include\",\n });\n\n if (res.status === 404) {\n // No experiments for this component - return null\n return null;\n }\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n const data = (await res.json()) as ComponentExperimentConfig;\n return data;\n } catch (e) {\n console.warn(`[PROBAT] Failed to fetch component config: ${e}`);\n return null;\n } finally {\n // Remove from cache after completion\n componentConfigCache.delete(cacheKey);\n }\n })();\n\n // Store the promise\n componentConfigCache.set(cacheKey, fetchPromise);\n return fetchPromise;\n}\n\n// Cache for variant component loads\nconst variantComponentCache = new Map<string, Promise<React.ComponentType<any> | null>>();\n\n// Make React available globally for variant components\nif (typeof window !== \"undefined\") {\n (window as any).__probatReact = React;\n (window as any).React = (window as any).React || React;\n}\n\nexport async function loadVariantComponent(\n baseUrl: string,\n proposalId: string,\n experimentId: string,\n filePath: string | null\n): Promise<React.ComponentType<any> | null> {\n if (!filePath) {\n return null;\n }\n\n const cacheKey = `${proposalId}:${experimentId}`;\n\n // Check cache\n const existingLoad = variantComponentCache.get(cacheKey);\n if (existingLoad) {\n return existingLoad;\n }\n\n // Create new load promise\n const loadPromise = (async () => {\n try {\n // Fetch the variant code (server compiles TSX/JSX to JS)\n const variantUrl = `${baseUrl.replace(/\\/$/, \"\")}/variants/${filePath}`;\n\n const res = await fetch(variantUrl, {\n method: \"GET\",\n headers: { Accept: \"text/javascript\" },\n credentials: \"include\",\n });\n\n if (!res.ok) {\n throw new Error(`HTTP ${res.status}`);\n }\n\n const code = await res.text();\n\n // The server returns an IIFE that assigns to __probatVariant\n // Execute the code to get the component\n // First, ensure React is available globally\n if (typeof window !== \"undefined\") {\n (window as any).React = (window as any).React || React;\n }\n\n // Execute the IIFE code\n const evalFunc = new Function(`\n var __probatVariant;\n ${code}\n return __probatVariant;\n `);\n\n const result = evalFunc();\n\n // The result is { default: Component } from esbuild's IIFE output\n const VariantComponent = result?.default || result;\n\n if (typeof VariantComponent === \"function\") {\n return VariantComponent as React.ComponentType<any>;\n }\n\n console.warn(\"[PROBAT] Variant component is not a function\", result);\n return null;\n } catch (e) {\n console.warn(`[PROBAT] Failed to load variant component: ${e}`);\n return null;\n } finally {\n // Remove from cache after completion\n variantComponentCache.delete(cacheKey);\n }\n })();\n\n // Store the promise\n variantComponentCache.set(cacheKey, loadPromise);\n return loadPromise;\n}\n\n","/**\n * Document-level click tracking for Probat experiments\n * \n * This module implements event delegation at the document level to track clicks\n * even when components don't have onClick handlers or when stopPropagation() is called.\n */\n\nimport { sendMetric } from './api';\nimport { extractClickMeta } from './api';\n\n// Cache for proposal metadata to avoid repeated DOM queries\nconst proposalCache = new Map<string, {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n}>();\n\n// Track if listener is already attached\nlet isListenerAttached = false;\n\n// Rate limiting: prevent duplicate rapid clicks\nconst lastClickTime = new Map<string, number>();\nconst DEBOUNCE_MS = 100; // Ignore clicks within 100ms of each other\n\n/**\n * Get proposal metadata from DOM element\n * Looks for the nearest [data-probat-proposal] wrapper\n */\nfunction getProposalMetadata(element: HTMLElement): {\n proposalId: string;\n experimentId: string | null;\n variantLabel: string;\n apiBaseUrl: string;\n} | null {\n // Find the nearest probat wrapper\n const probatWrapper = element.closest('[data-probat-proposal]') as HTMLElement | null;\n\n if (!probatWrapper) return null;\n\n const proposalId = probatWrapper.getAttribute('data-probat-proposal');\n if (!proposalId) return null;\n\n // Check cache first\n const cacheKey = `${proposalId}`;\n const cached = proposalCache.get(cacheKey);\n if (cached) return cached;\n\n // Extract metadata from data attributes\n const experimentId = probatWrapper.getAttribute('data-probat-experiment-id');\n const variantLabel = probatWrapper.getAttribute('data-probat-variant-label') || 'control';\n const apiBaseUrl = probatWrapper.getAttribute('data-probat-api-base-url') ||\n (typeof window !== 'undefined' && (window as any).__PROBAT_API) ||\n 'https://gushi.onrender.com';\n\n const metadata = {\n proposalId,\n experimentId: experimentId || null,\n variantLabel,\n apiBaseUrl,\n };\n\n // Cache it\n proposalCache.set(cacheKey, metadata);\n return metadata;\n}\n\n/**\n * Handle click event at document level\n * Uses capture phase to catch events before stopPropagation()\n */\nfunction handleDocumentClick(event: MouseEvent): void {\n const target = event.target as HTMLElement | null;\n if (!target) return;\n\n // Get proposal metadata\n const metadata = getProposalMetadata(target);\n if (!metadata) {\n return; // Click outside probat component\n }\n\n // Rate limiting: prevent duplicate rapid clicks\n const now = Date.now();\n const lastClick = lastClickTime.get(metadata.proposalId) || 0;\n if (now - lastClick < DEBOUNCE_MS) {\n return; // Ignore rapid duplicate clicks\n }\n lastClickTime.set(metadata.proposalId, now);\n\n // Extract click metadata (your existing function)\n const clickMeta = extractClickMeta(event);\n\n // Determine if we should track this click\n // Track if:\n // 1. It's an actionable element (button, link, etc.) - clickMeta exists\n // 2. Element has data-probat-track attribute\n // 3. Parent has data-probat-track attribute\n // 4. ANY click within a probat component (more permissive - track all clicks)\n const hasTrackAttribute = target.hasAttribute('data-probat-track') ||\n target.closest('[data-probat-track]') !== null;\n\n // More permissive: Track ALL clicks within probat components\n // This ensures we capture clicks even if elements don't have explicit tracking attributes\n const shouldTrack = clickMeta !== undefined || hasTrackAttribute || true; // Track all clicks in probat components\n\n if (!shouldTrack) {\n return;\n }\n\n // Build metadata - use clickMeta if available, otherwise create basic metadata\n const finalMeta = clickMeta || {\n target_tag: target.tagName,\n target_class: target.className || '',\n target_id: target.id || '',\n clicked_inside_probat: true, // Flag to indicate this was tracked via document-level listener\n };\n\n // Send click metric\n // For control variant, don't send experiment_id (control might be synthetic)\n // For other variants, send experiment_id if it exists and is valid (not synthetic \"exp_\" prefix)\n const experimentId = metadata.variantLabel === 'control'\n ? undefined\n : (metadata.experimentId && !metadata.experimentId.startsWith('exp_')\n ? metadata.experimentId\n : undefined);\n\n void sendMetric(\n metadata.apiBaseUrl,\n metadata.proposalId,\n 'click',\n metadata.variantLabel,\n experimentId,\n finalMeta\n );\n\n // Debug logging (always log for now to help diagnose)\n console.log('[PROBAT] Click tracked:', {\n proposalId: metadata.proposalId,\n variantLabel: metadata.variantLabel,\n target: target.tagName,\n targetId: target.id || 'none',\n targetClass: target.className || 'none',\n meta: finalMeta,\n });\n\n // Also log to help debug if API call fails\n console.log('[PROBAT] Sending metric to:', `${metadata.apiBaseUrl}/send_metrics/${metadata.proposalId}`);\n}\n\n/**\n * Initialize document-level click tracking\n * Call this once when your app initializes (typically in ProbatProvider)\n */\nexport function initDocumentClickTracking(): void {\n if (isListenerAttached) {\n console.warn('[PROBAT] Document click listener already attached');\n return;\n }\n\n if (typeof document === 'undefined') {\n // Server-side rendering - skip\n return;\n }\n\n // Use capture phase (true) to catch events before they bubble\n // This ensures we catch clicks even if stopPropagation() is called\n document.addEventListener('click', handleDocumentClick, true);\n\n isListenerAttached = true;\n console.log('[PROBAT] Document-level click tracking initialized');\n}\n\n/**\n * Clean up the listener (useful for testing or cleanup)\n */\nexport function cleanupDocumentClickTracking(): void {\n if (!isListenerAttached) return;\n\n if (typeof document !== 'undefined') {\n document.removeEventListener('click', handleDocumentClick, true);\n }\n\n isListenerAttached = false;\n proposalCache.clear();\n lastClickTime.clear();\n}\n\n/**\n * Update proposal metadata cache (call this when proposal data changes)\n * This is useful if you want to update the cache without waiting for DOM queries\n */\nexport function updateProposalMetadata(\n proposalId: string,\n metadata: {\n experimentId?: string | null;\n variantLabel?: string;\n apiBaseUrl?: string;\n }\n): void {\n const existing = proposalCache.get(proposalId);\n if (existing) {\n proposalCache.set(proposalId, {\n ...existing,\n ...metadata,\n });\n }\n}\n\n/**\n * Clear the proposal cache (useful for testing)\n */\nexport function clearProposalCache(): void {\n proposalCache.clear();\n}\n\n","\"use client\";\n\nimport React, { createContext, useContext, useMemo, useEffect } from \"react\";\nimport { detectEnvironment } from \"../utils/environment\";\nimport { initDocumentClickTracking, cleanupDocumentClickTracking } from \"../utils/documentClickTracker\";\n\ndeclare global {\n interface Window {\n __PROBAT_API?: string;\n }\n}\n\nexport interface ProbatContextValue {\n apiBaseUrl: string;\n environment: \"dev\" | \"prod\";\n clientKey?: string;\n repoFullName?: string; // Repository full name (e.g., \"owner/repo\") for component-based experiments\n}\n\nconst ProbatContext = createContext<ProbatContextValue | null>(null);\n\nexport interface ProbatProviderProps {\n /**\n * The base URL for the Probat API.\n * If not provided, will try to read from:\n * - VITE_PROBAT_API (Vite)\n * - NEXT_PUBLIC_PROBAT_API (Next.js)\n * - window.__PROBAT_API\n * - Default: \"https://gushi.onrender.com\"\n */\n apiBaseUrl?: string;\n /**\n * Client key for identification (optional)\n */\n clientKey?: string;\n /**\n * Explicitly set environment. If not provided, will auto-detect based on hostname.\n * \"dev\" for localhost, \"prod\" for production.\n */\n environment?: \"dev\" | \"prod\";\n /**\n * Repository full name (e.g., \"owner/repo\") for component-based experiments.\n * If not provided, will try to read from:\n * - NEXT_PUBLIC_PROBAT_REPO (Next.js)\n * - VITE_PROBAT_REPO (Vite)\n * - window.__PROBAT_REPO\n */\n repoFullName?: string;\n children: React.ReactNode;\n}\n\nexport function ProbatProvider({\n apiBaseUrl,\n clientKey,\n environment: explicitEnvironment,\n repoFullName: explicitRepoFullName,\n children,\n}: ProbatProviderProps) {\n const contextValue = useMemo<ProbatContextValue>(() => {\n // Determine API base URL\n const resolvedApiBaseUrl =\n apiBaseUrl ||\n (typeof import.meta !== \"undefined\" &&\n (import.meta as any).env?.VITE_PROBAT_API) ||\n (typeof globalThis !== \"undefined\" &&\n (globalThis as any).process?.env?.NEXT_PUBLIC_PROBAT_API) ||\n (typeof window !== \"undefined\" && window.__PROBAT_API) ||\n \"https://gushi.onrender.com\";\n\n // Determine environment\n const environment = explicitEnvironment || detectEnvironment();\n\n // Determine repo full name\n const resolvedRepoFullName =\n explicitRepoFullName ||\n (typeof globalThis !== \"undefined\" &&\n (globalThis as any).process?.env?.NEXT_PUBLIC_PROBAT_REPO) ||\n (typeof import.meta !== \"undefined\" &&\n (import.meta as any).env?.VITE_PROBAT_REPO) ||\n (typeof window !== \"undefined\" && (window as any).__PROBAT_REPO) ||\n undefined;\n\n return {\n apiBaseUrl: resolvedApiBaseUrl,\n environment,\n clientKey,\n repoFullName: resolvedRepoFullName,\n };\n }, [apiBaseUrl, clientKey, explicitEnvironment, explicitRepoFullName]);\n\n // Initialize document-level click tracking when provider mounts\n useEffect(() => {\n initDocumentClickTracking();\n \n // Cleanup on unmount (optional, but good practice)\n return () => {\n cleanupDocumentClickTracking();\n };\n }, []);\n\n return (\n <ProbatContext.Provider value={contextValue}>\n {children}\n </ProbatContext.Provider>\n );\n}\n\nexport function useProbatContext(): ProbatContextValue {\n const context = useContext(ProbatContext);\n if (!context) {\n throw new Error(\n \"useProbatContext must be used within a ProbatProvider. Please wrap your app with <ProbatProvider>.\"\n );\n }\n return context;\n}\n\n","\"use client\";\n\nimport React from \"react\";\nimport { ProbatProvider as BaseProbatProvider } from \"../context/ProbatContext\";\nimport type { ProbatProviderProps } from \"../context/ProbatContext\";\n\n/**\n * ProbatProviderClient - Can be imported directly in Next.js Server Components\n * This is a re-export with \"use client\" directive to ensure it works in Server Components\n */\nexport function ProbatProviderClient(props: ProbatProviderProps) {\n return React.createElement(BaseProbatProvider, props);\n}\n\n// Also export as ProbatProvider for convenience\nexport { ProbatProviderClient as ProbatProvider };\nexport type { ProbatProviderProps };\n\n","\"use client\";\n\nimport { useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { sendMetric, extractClickMeta } from \"../utils/api\";\n\nexport interface UseProbatMetricsReturn {\n /**\n * Track a click event\n * @param event - Optional React mouse event (will extract metadata automatically)\n * @param options - Optional configuration\n * @param options.force - Force tracking even if no actionable element is found\n * @param options.proposalId - Override the proposal ID (usually not needed)\n * @param options.variantLabel - Override the variant label (usually not needed)\n * @param options.dimensions - Additional dimensions to include\n */\n trackClick: (\n event?: MouseEvent | null,\n options?: {\n force?: boolean;\n proposalId?: string;\n variantLabel?: string;\n dimensions?: Record<string, any>;\n }\n ) => boolean;\n /**\n * Track a custom metric\n * @param metricName - Name of the metric\n * @param proposalId - Proposal ID\n * @param variantLabel - Variant label (defaults to \"control\")\n * @param dimensions - Additional dimensions\n */\n trackMetric: (\n metricName: string,\n proposalId: string,\n variantLabel?: string,\n dimensions?: Record<string, any>\n ) => void;\n /**\n * Track an impression/view\n * @param proposalId - Proposal ID\n * @param variantLabel - Variant label (defaults to \"control\")\n * @param experimentId - Optional experiment ID\n */\n trackImpression: (\n proposalId: string,\n variantLabel?: string,\n experimentId?: string\n ) => void;\n}\n\n/**\n * Hook for tracking Probat metrics (clicks, impressions, custom metrics)\n *\n * @example\n * ```tsx\n * const { trackClick, trackImpression } = useProbatMetrics();\n *\n * // Track click on button\n * <button onClick={(e) => trackClick(e)}>Click me</button>\n *\n * // Track impression\n * useEffect(() => {\n * trackImpression(proposalId, variantLabel, experimentId);\n * }, [proposalId, variantLabel, experimentId]);\n * ```\n */\nexport function useProbatMetrics(): UseProbatMetricsReturn {\n const { apiBaseUrl } = useProbatContext();\n\n const trackClick = useCallback(\n (\n event?: MouseEvent | null,\n options?: {\n force?: boolean;\n proposalId?: string;\n variantLabel?: string;\n dimensions?: Record<string, any>;\n }\n ) => {\n const meta = extractClickMeta(event ?? undefined);\n if (!options?.force && event && !meta) {\n return false;\n }\n\n const proposalId = options?.proposalId;\n const variantLabel = options?.variantLabel || \"control\";\n\n if (!proposalId) {\n console.warn(\n \"[Probat] trackClick called without proposalId. Provide it in options or use useExperiment hook.\"\n );\n return false;\n }\n\n void sendMetric(\n apiBaseUrl,\n proposalId,\n \"click\",\n variantLabel,\n undefined,\n { ...meta, ...options?.dimensions }\n );\n return true;\n },\n [apiBaseUrl]\n );\n\n const trackMetric = useCallback(\n (\n metricName: string,\n proposalId: string,\n variantLabel: string = \"control\",\n dimensions: Record<string, any> = {}\n ) => {\n void sendMetric(\n apiBaseUrl,\n proposalId,\n metricName,\n variantLabel,\n undefined,\n dimensions\n );\n },\n [apiBaseUrl]\n );\n\n const trackImpression = useCallback(\n (\n proposalId: string,\n variantLabel: string = \"control\",\n experimentId?: string\n ) => {\n void sendMetric(\n apiBaseUrl,\n proposalId,\n \"visit\",\n variantLabel,\n experimentId\n );\n },\n [apiBaseUrl]\n );\n\n return {\n trackClick,\n trackMetric,\n trackImpression,\n };\n}\n\n","const TTL_MS = 6 * 60 * 60 * 1000; // 6 hours\n\nexport type Choice = {\n experiment_id: string;\n label: string;\n ts: number;\n};\n\nexport function safeGet(k: string): any | null {\n try {\n const raw = localStorage.getItem(k);\n return raw ? JSON.parse(raw) : null;\n } catch {\n return null;\n }\n}\n\nexport function safeSet(k: string, v: any) {\n try {\n localStorage.setItem(k, JSON.stringify(v));\n } catch { }\n}\n\nexport function now() {\n return Date.now();\n}\n\nexport function fresh(ts: number) {\n return now() - ts <= TTL_MS;\n}\n\nexport const KEY = (proposalId: string) => `probat_choice_v3:${proposalId}`;\nexport const VISIT_KEY = (proposalId: string, label: string) =>\n `probat_visit_v1:${proposalId}:${label}`;\n\nexport function readChoice(proposalId: string): Choice | null {\n const c = safeGet(KEY(proposalId)) as Choice | null;\n return c && fresh(c.ts) ? c : null;\n}\n\nexport function writeChoice(\n proposalId: string,\n experiment_id: string,\n label: string\n) {\n safeSet(KEY(proposalId), { experiment_id, label, ts: now() } as Choice);\n}\n\nconst visitMemo = new Set<string>();\n\nexport function hasTrackedVisit(proposalId: string, label: string): boolean {\n const key = VISIT_KEY(proposalId, label);\n if (visitMemo.has(key)) return true;\n try {\n const raw = localStorage.getItem(key);\n if (!raw) return false;\n const ts = Number(raw);\n if (!Number.isFinite(ts) || ts <= 0) return false;\n if (now() - ts > TTL_MS) {\n localStorage.removeItem(key);\n return false;\n }\n visitMemo.add(key);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function markTrackedVisit(proposalId: string, label: string) {\n const key = VISIT_KEY(proposalId, label);\n visitMemo.add(key);\n try {\n localStorage.setItem(key, now().toString());\n } catch { }\n}\n\n","\"use client\";\n\nimport { useState, useEffect, useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport { fetchDecision } from \"../utils/api\";\nimport {\n readChoice,\n writeChoice,\n hasTrackedVisit,\n markTrackedVisit,\n} from \"../utils/storage\";\nimport { sendMetric } from \"../utils/api\";\n\nexport interface UseExperimentReturn {\n /**\n * The current variant label (e.g., \"control\", \"variant-a\")\n */\n variantLabel: string;\n /**\n * The experiment ID\n */\n experimentId: string | null;\n /**\n * Whether the experiment decision is still loading\n */\n isLoading: boolean;\n /**\n * Any error that occurred while fetching the experiment\n */\n error: Error | null;\n /**\n * Manually track a click for this experiment\n */\n trackClick: (event?: MouseEvent | null) => void;\n}\n\n/**\n * Hook for fetching and applying experiment variants\n *\n * @param proposalId - The proposal ID for the experiment\n * @param options - Optional configuration\n * @param options.autoTrackImpression - Automatically track impression when variant is loaded (default: true)\n *\n * @example\n * ```tsx\n * const { variantLabel, isLoading, trackClick } = useExperiment(\"proposal-id\");\n *\n * if (isLoading) return <div>Loading...</div>;\n *\n * return (\n * <div onClick={trackClick}>\n * {variantLabel === \"control\" ? <ControlComponent /> : <VariantComponent />}\n * </div>\n * );\n * ```\n */\nexport function useExperiment(\n proposalId: string,\n options?: { autoTrackImpression?: boolean }\n): UseExperimentReturn {\n const { apiBaseUrl } = useProbatContext();\n const [choice, setChoice] = useState<{\n experiment_id: string;\n label: string;\n } | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const autoTrackImpression = options?.autoTrackImpression !== false;\n\n // Fetch experiment decision\n useEffect(() => {\n let alive = true;\n\n const cached = readChoice(proposalId);\n if (cached) {\n setChoice({ experiment_id: cached.experiment_id, label: cached.label });\n setIsLoading(false);\n } else {\n setIsLoading(true);\n (async () => {\n try {\n const { experiment_id, label } = await fetchDecision(\n apiBaseUrl,\n proposalId\n );\n if (!alive) return;\n writeChoice(proposalId, experiment_id, label);\n setChoice({ experiment_id, label });\n setError(null);\n } catch (e) {\n if (!alive) return;\n const err = e instanceof Error ? e : new Error(String(e));\n setError(err);\n setChoice({\n experiment_id: `exp_${proposalId}`,\n label: \"control\",\n });\n } finally {\n if (alive) {\n setIsLoading(false);\n }\n }\n })();\n }\n\n return () => {\n alive = false;\n };\n }, [proposalId, apiBaseUrl]);\n\n // Track impression when variant is determined\n useEffect(() => {\n if (!autoTrackImpression || !choice) return;\n\n const exp = choice.experiment_id;\n const lbl = choice.label ?? \"control\";\n if (!lbl) return;\n\n // Only track if we haven't already tracked this visit\n if (hasTrackedVisit(proposalId, lbl)) return;\n markTrackedVisit(proposalId, lbl);\n void sendMetric(apiBaseUrl, proposalId, \"visit\", lbl, exp);\n }, [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl, autoTrackImpression]);\n\n const trackClick = useCallback(\n (event?: MouseEvent | null) => {\n const exp = choice?.experiment_id;\n const lbl = choice?.label ?? \"control\";\n const meta = event\n ? (() => {\n const rawTarget = event.target as HTMLElement | null;\n if (!rawTarget) return undefined;\n const actionable = rawTarget.closest(\n \"[data-probat-conversion='true'], button, a, [role='button']\"\n );\n if (!actionable) return undefined;\n const meta: Record<string, any> = {\n target_tag: actionable.tagName,\n };\n if (actionable.id) meta.target_id = actionable.id;\n const attr = actionable.getAttribute(\"data-probat-conversion\");\n if (attr) meta.conversion_attr = attr;\n const text = actionable.textContent?.trim();\n if (text) meta.target_text = text.slice(0, 120);\n return meta;\n })()\n : undefined;\n\n void sendMetric(apiBaseUrl, proposalId, \"click\", lbl, undefined, meta);\n },\n [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]\n );\n\n return {\n variantLabel: choice?.label ?? \"control\",\n experimentId: choice?.experiment_id ?? null,\n isLoading,\n error,\n trackClick,\n };\n}\n\n","\"use client\";\n\nimport React, { useState, useEffect, useCallback } from \"react\";\nimport type { MouseEvent } from \"react\";\nimport { useProbatContext } from \"../context/ProbatContext\";\nimport {\n fetchDecision,\n fetchComponentExperimentConfig,\n loadVariantComponent,\n sendMetric,\n extractClickMeta,\n} from \"../utils/api\";\nimport {\n readChoice,\n writeChoice,\n hasTrackedVisit,\n markTrackedVisit,\n} from \"../utils/storage\";\n\n// Support both old and new API for backward compatibility\nexport interface WithExperimentOptions {\n // New API: component-based\n componentPath?: string;\n repoFullName?: string;\n\n // Old API: direct proposal/registry (for backward compatibility)\n proposalId?: string;\n registry?: Record<string, React.ComponentType<any>>;\n}\n\n/**\n * Higher-Order Component for wrapping components with experiment variants\n */\nexport function withExperiment<P = any>(\n Control: React.ComponentType<P>,\n options: WithExperimentOptions\n): React.ComponentType<P & { probat?: { trackClick: () => void } }> {\n // Validate inputs at HOC level (not in component)\n if (!Control) {\n console.error(\"[PROBAT] withExperiment: Control component is required\");\n return ((props: P) => null) as any;\n }\n\n if (!options || typeof options !== 'object') {\n console.error(\"[PROBAT] withExperiment: options is required\");\n return Control as any;\n }\n\n const useNewAPI = !!options.componentPath;\n const useOldAPI = !!(options.proposalId && options.registry);\n\n if (!useNewAPI && !useOldAPI) {\n console.warn(\"[PROBAT] withExperiment: Invalid config, returning Control\");\n return Control as any;\n }\n\n const ControlComponent = Control;\n\n function Wrapped(props: P) {\n // ============================================================\n // ALL HOOKS MUST BE AT THE TOP - BEFORE ANY CONDITIONAL RETURNS\n // ============================================================\n\n // 1. Context hook - always called first\n const context = useProbatContext();\n const apiBaseUrl = context?.apiBaseUrl || \"https://gushi.onrender.com\";\n const contextRepoFullName = context?.repoFullName;\n\n // 2. State hooks - always called in same order\n const [config, setConfig] = useState<{\n proposalId: string;\n variants: Record<string, React.ComponentType<any>>;\n } | null>(null);\n const [configLoading, setConfigLoading] = useState(useNewAPI);\n const [choice, setChoice] = useState<{\n experiment_id: string;\n label: string;\n } | null>(null);\n\n // Derived values\n const repoFullName = options.repoFullName || contextRepoFullName;\n const proposalId = useNewAPI ? config?.proposalId : options.proposalId;\n\n // 3. Effect hooks - always called\n // Load component config (new API)\n useEffect(() => {\n if (!useNewAPI) return;\n if (!repoFullName) {\n console.warn(\"[PROBAT] componentPath provided but repoFullName not found\");\n setConfigLoading(false);\n return;\n }\n\n let alive = true;\n setConfigLoading(true);\n\n (async () => {\n try {\n const componentConfig = await fetchComponentExperimentConfig(\n apiBaseUrl,\n repoFullName,\n options.componentPath!\n );\n\n if (!alive) return;\n\n if (!componentConfig) {\n setConfig(null);\n setConfigLoading(false);\n return;\n }\n\n const variantComponents: Record<string, React.ComponentType<any>> = {\n control: ControlComponent,\n };\n\n for (const [label, variantInfo] of Object.entries(componentConfig.variants)) {\n if (label === \"control\") continue;\n if (variantInfo?.file_path) {\n try {\n const VariantComp = await loadVariantComponent(\n apiBaseUrl,\n componentConfig.proposal_id,\n variantInfo.experiment_id,\n variantInfo.file_path\n );\n if (VariantComp && typeof VariantComp === 'function' && alive) {\n variantComponents[label] = VariantComp;\n }\n } catch (e) {\n console.warn(`[PROBAT] Failed to load variant ${label}:`, e);\n }\n }\n }\n\n if (alive) {\n setConfig({\n proposalId: componentConfig.proposal_id,\n variants: variantComponents,\n });\n setConfigLoading(false);\n }\n } catch (e) {\n console.warn(\"[PROBAT] Failed to load component config:\", e);\n if (alive) {\n setConfig(null);\n setConfigLoading(false);\n }\n }\n })();\n\n return () => { alive = false; };\n }, [useNewAPI, options.componentPath, repoFullName, apiBaseUrl]);\n\n // Fetch experiment decision\n useEffect(() => {\n if (!proposalId) return;\n if (useNewAPI && configLoading) return;\n\n let alive = true;\n const cached = readChoice(proposalId);\n\n if (cached) {\n setChoice({\n experiment_id: cached.experiment_id,\n label: cached.label,\n });\n } else {\n (async () => {\n try {\n const { experiment_id, label } = await fetchDecision(apiBaseUrl, proposalId);\n if (!alive) return;\n writeChoice(proposalId, experiment_id, label);\n setChoice({ experiment_id, label });\n } catch (e) {\n if (!alive) return;\n setChoice({\n experiment_id: `exp_${proposalId}`,\n label: \"control\",\n });\n }\n })();\n }\n\n return () => { alive = false; };\n }, [proposalId, apiBaseUrl, useNewAPI, configLoading]);\n\n // Track visit\n useEffect(() => {\n if (!proposalId) return;\n const lbl = choice?.label ?? \"control\";\n if (!lbl || hasTrackedVisit(proposalId, lbl)) return;\n markTrackedVisit(proposalId, lbl);\n void sendMetric(apiBaseUrl, proposalId, \"visit\", lbl, choice?.experiment_id);\n }, [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]);\n\n // 4. Callback hooks - always called\n const trackClick = useCallback(\n (event?: MouseEvent | null, opts?: { force?: boolean }) => {\n if (!proposalId) return false;\n const lbl = choice?.label ?? \"control\";\n const meta = extractClickMeta(event ?? undefined);\n if (!opts?.force && event && !meta) return false;\n void sendMetric(apiBaseUrl, proposalId, \"click\", lbl, undefined, meta);\n return true;\n },\n [proposalId, choice?.experiment_id, choice?.label, apiBaseUrl]\n );\n\n // ============================================================\n // NOW WE CAN DO CONDITIONAL RETURNS - AFTER ALL HOOKS\n // ============================================================\n\n // Loading state - return control\n if (useNewAPI && (configLoading || !config || !proposalId)) {\n return React.createElement(ControlComponent as any, props as any);\n }\n\n // No proposalId - return control\n if (!proposalId) {\n return React.createElement(ControlComponent as any, props as any);\n }\n\n // Build registry - always has control\n const registry: Record<string, React.ComponentType<any>> = { control: ControlComponent };\n\n if (useNewAPI && config?.variants) {\n for (const [key, value] of Object.entries(config.variants)) {\n if (key !== 'control' && value && typeof value === 'function') {\n registry[key] = value;\n }\n }\n } else if (!useNewAPI && options.registry) {\n for (const [key, value] of Object.entries(options.registry)) {\n if (key !== 'control' && value && typeof value === 'function') {\n registry[key] = value;\n }\n }\n }\n\n // Select variant\n const label = choice?.label ?? \"control\";\n const Variant = registry[label] || registry.control || ControlComponent;\n\n return (\n <div\n onClick={(event) => {\n // Keep existing onClick for backward compatibility\n // Document-level listener will also catch it (in capture phase)\n trackClick(event);\n }}\n data-probat-proposal={proposalId}\n data-probat-experiment-id={choice?.experiment_id || ''}\n data-probat-variant-label={label}\n data-probat-api-base-url={apiBaseUrl}\n >\n {React.createElement(Variant, {\n key: `${proposalId}:${label}`,\n ...(props as any),\n probat: { trackClick: () => trackClick(null, { force: true }) },\n })}\n </div>\n );\n }\n\n Wrapped.displayName = `withExperiment(${Control.displayName || Control.name || \"Component\"})`;\n return Wrapped as any;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@probat/react",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "React library for Probat A/B testing and experimentation",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -42,4 +42,4 @@
42
42
  "tsup": "^8.0.0",
43
43
  "typescript": "^5.0.0"
44
44
  }
45
- }
45
+ }
package/src/utils/api.ts CHANGED
@@ -82,7 +82,7 @@ export async function sendMetric(
82
82
  captured_at: new Date().toISOString(),
83
83
  };
84
84
  try {
85
- await fetch(url, {
85
+ const response = await fetch(url, {
86
86
  method: "POST",
87
87
  headers: {
88
88
  Accept: "application/json",
@@ -91,8 +91,29 @@ export async function sendMetric(
91
91
  credentials: "include", // CRITICAL: Include cookies to distinguish different users
92
92
  body: JSON.stringify(body),
93
93
  });
94
- } catch {
95
- // Silently fail - metrics should not break the app
94
+
95
+ // Log in development for debugging
96
+ if (!response.ok) {
97
+ console.warn('[PROBAT] Metric send failed:', {
98
+ status: response.status,
99
+ statusText: response.statusText,
100
+ url,
101
+ body,
102
+ });
103
+ } else {
104
+ console.log('[PROBAT] Metric sent successfully:', {
105
+ metricName,
106
+ proposalId,
107
+ variantLabel,
108
+ });
109
+ }
110
+ } catch (error) {
111
+ // Log error in development, but don't break the app
112
+ console.error('[PROBAT] Error sending metric:', {
113
+ error: error instanceof Error ? error.message : String(error),
114
+ url,
115
+ body,
116
+ });
96
117
  }
97
118
  }
98
119
 
@@ -35,31 +35,31 @@ function getProposalMetadata(element: HTMLElement): {
35
35
  } | null {
36
36
  // Find the nearest probat wrapper
37
37
  const probatWrapper = element.closest('[data-probat-proposal]') as HTMLElement | null;
38
-
38
+
39
39
  if (!probatWrapper) return null;
40
-
40
+
41
41
  const proposalId = probatWrapper.getAttribute('data-probat-proposal');
42
42
  if (!proposalId) return null;
43
-
43
+
44
44
  // Check cache first
45
45
  const cacheKey = `${proposalId}`;
46
46
  const cached = proposalCache.get(cacheKey);
47
47
  if (cached) return cached;
48
-
48
+
49
49
  // Extract metadata from data attributes
50
50
  const experimentId = probatWrapper.getAttribute('data-probat-experiment-id');
51
51
  const variantLabel = probatWrapper.getAttribute('data-probat-variant-label') || 'control';
52
- const apiBaseUrl = probatWrapper.getAttribute('data-probat-api-base-url') ||
53
- (typeof window !== 'undefined' && (window as any).__PROBAT_API) ||
54
- 'https://gushi.onrender.com';
55
-
52
+ const apiBaseUrl = probatWrapper.getAttribute('data-probat-api-base-url') ||
53
+ (typeof window !== 'undefined' && (window as any).__PROBAT_API) ||
54
+ 'https://gushi.onrender.com';
55
+
56
56
  const metadata = {
57
57
  proposalId,
58
58
  experimentId: experimentId || null,
59
59
  variantLabel,
60
60
  apiBaseUrl,
61
61
  };
62
-
62
+
63
63
  // Cache it
64
64
  proposalCache.set(cacheKey, metadata);
65
65
  return metadata;
@@ -72,11 +72,13 @@ function getProposalMetadata(element: HTMLElement): {
72
72
  function handleDocumentClick(event: MouseEvent): void {
73
73
  const target = event.target as HTMLElement | null;
74
74
  if (!target) return;
75
-
75
+
76
76
  // Get proposal metadata
77
77
  const metadata = getProposalMetadata(target);
78
- if (!metadata) return;
79
-
78
+ if (!metadata) {
79
+ return; // Click outside probat component
80
+ }
81
+
80
82
  // Rate limiting: prevent duplicate rapid clicks
81
83
  const now = Date.now();
82
84
  const lastClick = lastClickTime.get(metadata.proposalId) || 0;
@@ -84,52 +86,65 @@ function handleDocumentClick(event: MouseEvent): void {
84
86
  return; // Ignore rapid duplicate clicks
85
87
  }
86
88
  lastClickTime.set(metadata.proposalId, now);
87
-
89
+
88
90
  // Extract click metadata (your existing function)
89
91
  const clickMeta = extractClickMeta(event);
90
-
92
+
91
93
  // Determine if we should track this click
92
94
  // Track if:
93
95
  // 1. It's an actionable element (button, link, etc.) - clickMeta exists
94
96
  // 2. Element has data-probat-track attribute
95
97
  // 3. Parent has data-probat-track attribute
96
- const hasTrackAttribute = target.hasAttribute('data-probat-track') ||
97
- target.closest('[data-probat-track]') !== null;
98
-
99
- const shouldTrack = clickMeta !== undefined || hasTrackAttribute;
100
-
98
+ // 4. ANY click within a probat component (more permissive - track all clicks)
99
+ const hasTrackAttribute = target.hasAttribute('data-probat-track') ||
100
+ target.closest('[data-probat-track]') !== null;
101
+
102
+ // More permissive: Track ALL clicks within probat components
103
+ // This ensures we capture clicks even if elements don't have explicit tracking attributes
104
+ const shouldTrack = clickMeta !== undefined || hasTrackAttribute || true; // Track all clicks in probat components
105
+
101
106
  if (!shouldTrack) {
102
- // Optional: Track "dead clicks" for UX insights
103
- // Uncomment the code below if you want to track clicks on non-interactive elements
104
- /*
105
- const deadClickMeta = {
106
- dead_click: true,
107
- target_tag: target.tagName,
108
- target_class: target.className || '',
109
- target_id: target.id || '',
110
- };
111
-
112
- void sendMetric(
113
- metadata.apiBaseUrl,
114
- metadata.proposalId,
115
- 'dead_click',
116
- metadata.variantLabel,
117
- metadata.experimentId,
118
- deadClickMeta
119
- );
120
- */
121
107
  return;
122
108
  }
123
-
109
+
110
+ // Build metadata - use clickMeta if available, otherwise create basic metadata
111
+ const finalMeta = clickMeta || {
112
+ target_tag: target.tagName,
113
+ target_class: target.className || '',
114
+ target_id: target.id || '',
115
+ clicked_inside_probat: true, // Flag to indicate this was tracked via document-level listener
116
+ };
117
+
124
118
  // Send click metric
119
+ // For control variant, don't send experiment_id (control might be synthetic)
120
+ // For other variants, send experiment_id if it exists and is valid (not synthetic "exp_" prefix)
121
+ const experimentId = metadata.variantLabel === 'control'
122
+ ? undefined
123
+ : (metadata.experimentId && !metadata.experimentId.startsWith('exp_')
124
+ ? metadata.experimentId
125
+ : undefined);
126
+
125
127
  void sendMetric(
126
128
  metadata.apiBaseUrl,
127
129
  metadata.proposalId,
128
130
  'click',
129
131
  metadata.variantLabel,
130
- metadata.experimentId || undefined,
131
- clickMeta
132
+ experimentId,
133
+ finalMeta
132
134
  );
135
+
136
+ // Debug logging (always log for now to help diagnose)
137
+ console.log('[PROBAT] Click tracked:', {
138
+ proposalId: metadata.proposalId,
139
+ variantLabel: metadata.variantLabel,
140
+ target: target.tagName,
141
+ targetId: target.id || 'none',
142
+ targetClass: target.className || 'none',
143
+ meta: finalMeta,
144
+ });
145
+
146
+ // Also log to help debug if API call fails
147
+ console.log('[PROBAT] Sending metric to:', `${metadata.apiBaseUrl}/send_metrics/${metadata.proposalId}`);
133
148
  }
134
149
 
135
150
  /**
@@ -141,16 +156,16 @@ export function initDocumentClickTracking(): void {
141
156
  console.warn('[PROBAT] Document click listener already attached');
142
157
  return;
143
158
  }
144
-
159
+
145
160
  if (typeof document === 'undefined') {
146
161
  // Server-side rendering - skip
147
162
  return;
148
163
  }
149
-
164
+
150
165
  // Use capture phase (true) to catch events before they bubble
151
166
  // This ensures we catch clicks even if stopPropagation() is called
152
167
  document.addEventListener('click', handleDocumentClick, true);
153
-
168
+
154
169
  isListenerAttached = true;
155
170
  console.log('[PROBAT] Document-level click tracking initialized');
156
171
  }
@@ -160,11 +175,11 @@ export function initDocumentClickTracking(): void {
160
175
  */
161
176
  export function cleanupDocumentClickTracking(): void {
162
177
  if (!isListenerAttached) return;
163
-
178
+
164
179
  if (typeof document !== 'undefined') {
165
180
  document.removeEventListener('click', handleDocumentClick, true);
166
181
  }
167
-
182
+
168
183
  isListenerAttached = false;
169
184
  proposalCache.clear();
170
185
  lastClickTime.clear();