@pack/hydrogen 3.1.0 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -26,10 +26,14 @@ interface TestInput {
26
26
  interface Test$1 {
27
27
  id: string;
28
28
  handle: string;
29
+ impressionTrigger?: string;
29
30
  testVariant: {
30
31
  id: string;
31
32
  handle: string;
32
33
  };
34
+ impression?: {
35
+ sectionIds?: string[];
36
+ };
33
37
  }
34
38
 
35
39
  declare class PackTestSession {
@@ -177,15 +181,23 @@ declare function action({ request, context }: ActionFunctionArgs): Promise<Respo
177
181
  */
178
182
  declare function loader({ request, context }: LoaderFunctionArgs): Promise<Response>;
179
183
 
180
- declare const PackTestRoute: () => null;
184
+ type PackTestImpressionSelector = string | string[] | ((packTestInfo: Test$1) => string | string[] | undefined);
185
+ type PackTestRouteProps = {
186
+ impressionSelector?: PackTestImpressionSelector;
187
+ };
188
+ declare const PackTestRoute: ({ impressionSelector, }?: PackTestRouteProps) => null;
181
189
 
182
190
  interface Test {
183
191
  id: string;
184
192
  handle: string;
193
+ impressionTrigger?: string;
185
194
  testVariant: {
186
195
  id: string;
187
196
  handle: string;
188
197
  };
198
+ impression?: {
199
+ sectionIds?: string[];
200
+ };
189
201
  }
190
202
  interface TestExposureCallbackArg extends Test {
191
203
  exposureTime: number;
package/dist/index.js CHANGED
@@ -5027,6 +5027,10 @@ var cookie2 = __toESM(require_cookie(), 1);
5027
5027
  var import_json_rules_engine = __toESM(require_dist(), 1);
5028
5028
  var import_debug2 = __toESM(require_browser(), 1);
5029
5029
  var debug2 = (0, import_debug2.default)("pack:ab-testing:local-resolver");
5030
+ function getImpressionSectionIds(testVariant) {
5031
+ const sectionIds = testVariant?.sectionTestVariants?.map((variant) => variant?.section?.id).filter((id) => Boolean(id)) || [];
5032
+ return [...new Set(sectionIds)];
5033
+ }
5030
5034
  var LocalTestResolver = class {
5031
5035
  testRules = [];
5032
5036
  constructor() {
@@ -5065,62 +5069,86 @@ var LocalTestResolver = class {
5065
5069
  * Evaluate test rules and assign a variant
5066
5070
  */
5067
5071
  async assignTest(attributes, _sessionId) {
5068
- debug2("[Pack Test LocalResolver] Starting test assignment:", JSON.stringify({
5069
- totalRules: this.testRules.length,
5070
- attributes
5071
- }));
5072
+ debug2(
5073
+ "[Pack Test LocalResolver] Starting test assignment:",
5074
+ JSON.stringify({
5075
+ totalRules: this.testRules.length,
5076
+ attributes
5077
+ })
5078
+ );
5072
5079
  if (!this.testRules.length) {
5073
5080
  debug2("[Pack Test LocalResolver] No test rules available");
5074
5081
  return null;
5075
5082
  }
5076
5083
  const eligibleTests = await this.evaluateRules(this.testRules, attributes);
5077
- debug2("[Pack Test LocalResolver] Rule evaluation result:", JSON.stringify({
5078
- totalTests: this.testRules.length,
5079
- eligibleTests: eligibleTests.length,
5080
- eligibleTestIds: eligibleTests.map((t) => ({ id: t.id, handle: t.handle }))
5081
- }));
5084
+ debug2(
5085
+ "[Pack Test LocalResolver] Rule evaluation result:",
5086
+ JSON.stringify({
5087
+ totalTests: this.testRules.length,
5088
+ eligibleTests: eligibleTests.length,
5089
+ eligibleTestIds: eligibleTests.map((t) => ({
5090
+ id: t.id,
5091
+ handle: t.handle
5092
+ }))
5093
+ })
5094
+ );
5082
5095
  if (!eligibleTests.length) {
5083
5096
  debug2("[Pack Test LocalResolver] No eligible tests found");
5084
5097
  return null;
5085
5098
  }
5086
5099
  const randomTestIndex = this.getRandomNumber(eligibleTests.length - 1);
5087
5100
  const selectedTest = eligibleTests[randomTestIndex];
5088
- debug2("[Pack Test LocalResolver] Selected test:", JSON.stringify({
5089
- testId: selectedTest.id,
5090
- testHandle: selectedTest.handle,
5091
- randomIndex: randomTestIndex,
5092
- totalEligible: eligibleTests.length
5093
- }));
5101
+ debug2(
5102
+ "[Pack Test LocalResolver] Selected test:",
5103
+ JSON.stringify({
5104
+ testId: selectedTest.id,
5105
+ testHandle: selectedTest.handle,
5106
+ randomIndex: randomTestIndex,
5107
+ totalEligible: eligibleTests.length
5108
+ })
5109
+ );
5094
5110
  const randomPercentage = this.getRandomNumber(100, 1);
5095
5111
  let accumulatedPercentage = 0;
5096
- debug2("[Pack Test LocalResolver] Starting variant assignment:", JSON.stringify({
5097
- randomPercentage,
5098
- variants: selectedTest.testVariants.map((v) => ({
5099
- id: v.id,
5100
- handle: v.handle,
5101
- trafficPercentage: v.trafficPercentage
5102
- }))
5103
- }));
5112
+ debug2(
5113
+ "[Pack Test LocalResolver] Starting variant assignment:",
5114
+ JSON.stringify({
5115
+ randomPercentage,
5116
+ variants: selectedTest.testVariants.map((v) => ({
5117
+ id: v.id,
5118
+ handle: v.handle,
5119
+ trafficPercentage: v.trafficPercentage
5120
+ }))
5121
+ })
5122
+ );
5104
5123
  for (const variant of selectedTest.testVariants) {
5105
5124
  accumulatedPercentage += variant.trafficPercentage * 100;
5106
- debug2("[Pack Test LocalResolver] Checking variant:", JSON.stringify({
5107
- variantId: variant.id,
5108
- variantHandle: variant.handle,
5109
- trafficPercentage: variant.trafficPercentage,
5110
- accumulatedPercentage,
5111
- randomPercentage,
5112
- isSelected: accumulatedPercentage >= randomPercentage
5113
- }));
5125
+ debug2(
5126
+ "[Pack Test LocalResolver] Checking variant:",
5127
+ JSON.stringify({
5128
+ variantId: variant.id,
5129
+ variantHandle: variant.handle,
5130
+ trafficPercentage: variant.trafficPercentage,
5131
+ accumulatedPercentage,
5132
+ randomPercentage,
5133
+ isSelected: accumulatedPercentage >= randomPercentage
5134
+ })
5135
+ );
5114
5136
  if (accumulatedPercentage >= randomPercentage) {
5137
+ const impressionSectionIds = getImpressionSectionIds(variant);
5115
5138
  const result = {
5116
5139
  id: selectedTest.id,
5117
5140
  handle: selectedTest.handle,
5141
+ impressionTrigger: selectedTest.impressionTrigger,
5118
5142
  testVariant: {
5119
5143
  id: variant.id,
5120
5144
  handle: variant.handle
5121
- }
5145
+ },
5146
+ impression: impressionSectionIds.length > 0 ? { sectionIds: impressionSectionIds } : void 0
5122
5147
  };
5123
- debug2("[Pack Test LocalResolver] Variant selected:", JSON.stringify(result));
5148
+ debug2(
5149
+ "[Pack Test LocalResolver] Variant selected:",
5150
+ JSON.stringify(result)
5151
+ );
5124
5152
  return result;
5125
5153
  }
5126
5154
  }
@@ -5131,26 +5159,34 @@ var LocalTestResolver = class {
5131
5159
  * Evaluate rules using json-rules-engine (same as tests-service)
5132
5160
  */
5133
5161
  async evaluateRules(tests, attributes) {
5134
- debug2("[Pack Test LocalResolver] Starting rule evaluation:", JSON.stringify({
5135
- totalTests: tests.length,
5136
- attributes,
5137
- isClientSide: typeof window !== "undefined"
5138
- }));
5162
+ debug2(
5163
+ "[Pack Test LocalResolver] Starting rule evaluation:",
5164
+ JSON.stringify({
5165
+ totalTests: tests.length,
5166
+ attributes,
5167
+ isClientSide: typeof window !== "undefined"
5168
+ })
5169
+ );
5139
5170
  if (typeof window !== "undefined") {
5140
5171
  debug2("[Pack Test LocalResolver] Client side - returning all tests");
5141
5172
  return tests;
5142
5173
  }
5143
5174
  const engineResultsPromises = tests.map((test, index) => {
5144
5175
  const { rules } = test;
5145
- debug2(`[Pack Test LocalResolver] Processing test ${index}:`, JSON.stringify({
5146
- testId: test.id,
5147
- testHandle: test.handle,
5148
- rulesCount: rules?.length || 0,
5149
- rules
5150
- }));
5176
+ debug2(
5177
+ `[Pack Test LocalResolver] Processing test ${index}:`,
5178
+ JSON.stringify({
5179
+ testId: test.id,
5180
+ testHandle: test.handle,
5181
+ rulesCount: rules?.length || 0,
5182
+ rules
5183
+ })
5184
+ );
5151
5185
  if (rules && Array.isArray(rules)) {
5152
5186
  if (rules.length === 0) {
5153
- debug2(`[Pack Test LocalResolver] Test ${test.handle} has no rules - targeting all`);
5187
+ debug2(
5188
+ `[Pack Test LocalResolver] Test ${test.handle} has no rules - targeting all`
5189
+ );
5154
5190
  return Promise.resolve({
5155
5191
  events: [{ type: "targeted" }]
5156
5192
  });
@@ -5162,7 +5198,10 @@ var LocalTestResolver = class {
5162
5198
  operator: rule.operator,
5163
5199
  value: rule.value
5164
5200
  }));
5165
- debug2(`[Pack Test LocalResolver] Test ${test.handle} engine conditions:`, JSON.stringify(engineConditionalProperties));
5201
+ debug2(
5202
+ `[Pack Test LocalResolver] Test ${test.handle} engine conditions:`,
5203
+ JSON.stringify(engineConditionalProperties)
5204
+ );
5166
5205
  const engineRules = [
5167
5206
  new import_json_rules_engine.Rule({
5168
5207
  conditions: {
@@ -5209,29 +5248,46 @@ var LocalTestResolver = class {
5209
5248
  (factValue) => !factValue
5210
5249
  );
5211
5250
  const result = engine.run(attributes);
5212
- debug2(`[Pack Test LocalResolver] Engine result for test ${test.handle}:`, JSON.stringify(result));
5251
+ debug2(
5252
+ `[Pack Test LocalResolver] Engine result for test ${test.handle}:`,
5253
+ JSON.stringify(result)
5254
+ );
5213
5255
  return result;
5214
5256
  }
5215
5257
  }
5216
- debug2(`[Pack Test LocalResolver] Test ${test.handle} has invalid rules`);
5258
+ debug2(
5259
+ `[Pack Test LocalResolver] Test ${test.handle} has invalid rules`
5260
+ );
5217
5261
  return void 0;
5218
5262
  });
5219
5263
  const engineResults = await Promise.all(engineResultsPromises);
5220
- debug2("[Pack Test LocalResolver] All engine results:", JSON.stringify(engineResults));
5221
- const eligibleTests = tests.filter(
5222
- (test, index) => {
5223
- const hasTargetedEvent = !!engineResults?.[index]?.events.find((event) => event.type === "targeted");
5224
- debug2(`[Pack Test LocalResolver] Test ${test.handle} eligibility:`, JSON.stringify({
5264
+ debug2(
5265
+ "[Pack Test LocalResolver] All engine results:",
5266
+ JSON.stringify(engineResults)
5267
+ );
5268
+ const eligibleTests = tests.filter((test, index) => {
5269
+ const hasTargetedEvent = !!engineResults?.[index]?.events.find(
5270
+ (event) => event.type === "targeted"
5271
+ );
5272
+ debug2(
5273
+ `[Pack Test LocalResolver] Test ${test.handle} eligibility:`,
5274
+ JSON.stringify({
5225
5275
  hasTargetedEvent,
5226
5276
  events: engineResults?.[index]?.events
5227
- }));
5228
- return hasTargetedEvent;
5229
- }
5277
+ })
5278
+ );
5279
+ return hasTargetedEvent;
5280
+ });
5281
+ debug2(
5282
+ "[Pack Test LocalResolver] Final eligible tests:",
5283
+ JSON.stringify({
5284
+ eligibleCount: eligibleTests.length,
5285
+ eligibleTests: eligibleTests.map((t) => ({
5286
+ id: t.id,
5287
+ handle: t.handle
5288
+ }))
5289
+ })
5230
5290
  );
5231
- debug2("[Pack Test LocalResolver] Final eligible tests:", JSON.stringify({
5232
- eligibleCount: eligibleTests.length,
5233
- eligibleTests: eligibleTests.map((t) => ({ id: t.id, handle: t.handle }))
5234
- }));
5235
5291
  return eligibleTests;
5236
5292
  }
5237
5293
  /**
@@ -5274,16 +5330,26 @@ var QUERY_TESTS_BY_RULES = `#graphql
5274
5330
  operator
5275
5331
  value
5276
5332
  }
5333
+ impressionTrigger
5277
5334
  testVariants {
5278
5335
  id
5279
5336
  handle
5280
5337
  trafficPercentage
5338
+ sectionTestVariants {
5339
+ section {
5340
+ id
5341
+ }
5342
+ }
5281
5343
  }
5282
5344
  }
5283
5345
  }
5284
5346
  }
5285
5347
  }
5286
5348
  `;
5349
+ function getImpressionSectionIds2(testVariant) {
5350
+ const sectionIds = testVariant?.sectionTestVariants?.map((variant) => variant?.section?.id).filter((id) => Boolean(id)) || [];
5351
+ return [...new Set(sectionIds)];
5352
+ }
5287
5353
  var localTestResolver = new LocalTestResolver();
5288
5354
  function generateTestRulesCacheKey(storeId, contentEnvironment) {
5289
5355
  return `pack-tests:${storeId}:${contentEnvironment || "default"}`;
@@ -5497,13 +5563,16 @@ async function packClientFetchTestByRules(packClient, testTargetAudienceAttribut
5497
5563
  (v) => v.id === currentTestData.testVariant.id
5498
5564
  );
5499
5565
  if (currentVariant) {
5566
+ const impressionSectionIds = getImpressionSectionIds2(currentVariant);
5500
5567
  const refreshedTest = {
5501
5568
  id: freshTestData.id,
5502
5569
  handle: freshTestData.handle,
5570
+ impressionTrigger: freshTestData.impressionTrigger,
5503
5571
  testVariant: {
5504
5572
  id: currentVariant.id,
5505
5573
  handle: currentVariant.handle
5506
5574
  },
5575
+ impression: impressionSectionIds.length > 0 ? { sectionIds: impressionSectionIds } : void 0,
5507
5576
  isFirstExposure: void 0
5508
5577
  };
5509
5578
  const { isFirstExposure: isFirstExposure2, ...testDataWithoutFlag2 } = refreshedTest;
@@ -5551,13 +5620,16 @@ async function packClientFetchTestByRules(packClient, testTargetAudienceAttribut
5551
5620
  (v) => v.id === exposedTest.testVariant?.id
5552
5621
  );
5553
5622
  if (exposedVariant) {
5623
+ const impressionSectionIds = getImpressionSectionIds2(exposedVariant);
5554
5624
  const result2 = {
5555
5625
  id: freshTestData.id,
5556
5626
  handle: freshTestData.handle,
5627
+ impressionTrigger: freshTestData.impressionTrigger,
5557
5628
  testVariant: {
5558
5629
  id: exposedVariant.id,
5559
5630
  handle: exposedVariant.handle
5560
5631
  },
5632
+ impression: impressionSectionIds.length > 0 ? { sectionIds: impressionSectionIds } : void 0,
5561
5633
  isFirstExposure: void 0
5562
5634
  };
5563
5635
  const { isFirstExposure: isFirstExposure2, ...testDataWithoutFlag2 } = result2;
@@ -6572,8 +6644,35 @@ var PackTestContext = createContext({});
6572
6644
  var usePackTestContext = () => useContext(PackTestContext);
6573
6645
 
6574
6646
  // src/tests/pack-test-route.ts
6575
- var usePackLoaderData = () => {
6647
+ function getImpressionSectionSelectors(packTestInfo) {
6648
+ const sectionIds = packTestInfo.impression?.sectionIds || [];
6649
+ return [...new Set(sectionIds)].map(
6650
+ (sectionId) => `section[data-comp-id="${sectionId}"]`
6651
+ );
6652
+ }
6653
+ function getImpressionSelectors(packTestInfo, impressionSelector) {
6654
+ if (!impressionSelector) {
6655
+ return getImpressionSectionSelectors(packTestInfo);
6656
+ }
6657
+ const resolvedSelector = typeof impressionSelector === "function" ? impressionSelector(packTestInfo) : impressionSelector;
6658
+ if (!resolvedSelector) {
6659
+ return getImpressionSectionSelectors(packTestInfo);
6660
+ }
6661
+ return Array.isArray(resolvedSelector) ? resolvedSelector : [resolvedSelector];
6662
+ }
6663
+ function serializeExposedTestCookieValue(packTestInfo) {
6664
+ return JSON.stringify({
6665
+ id: packTestInfo.id,
6666
+ handle: packTestInfo.handle,
6667
+ testVariant: {
6668
+ id: packTestInfo.testVariant.id,
6669
+ handle: packTestInfo.testVariant.handle
6670
+ }
6671
+ });
6672
+ }
6673
+ var usePackLoaderData = (impressionSelector) => {
6576
6674
  const [exposedTestInfo, setExposedTestInfo] = useState();
6675
+ const [triggeredExposure, setTriggeredExposure] = useState();
6577
6676
  let packTestInfo;
6578
6677
  let packIsPreviewMode;
6579
6678
  let revalidator;
@@ -6597,61 +6696,216 @@ var usePackLoaderData = () => {
6597
6696
  } = usePackTestContext();
6598
6697
  const exposedTestCookieString = api.get("exposedTest");
6599
6698
  useEffect2(() => {
6600
- if (packTestInfo && !packIsPreviewMode && !hasUserConsent2 && exposedTestCookieString && exposedTestInfo) {
6601
- setPendingExposureQueue?.((prev) => {
6602
- const newQueue = new Map(prev);
6603
- newQueue.set(packTestInfo.id, {
6604
- packTestInfo,
6605
- exposureTime: Date.now()
6699
+ if (packTestInfo?.id !== triggeredExposure?.packTestInfo.id) {
6700
+ setTriggeredExposure(void 0);
6701
+ return;
6702
+ }
6703
+ if (packTestInfo?.testVariant?.id !== triggeredExposure?.packTestInfo.testVariant.id) {
6704
+ setTriggeredExposure(void 0);
6705
+ }
6706
+ }, [triggeredExposure, packTestInfo]);
6707
+ useEffect2(() => {
6708
+ if (!packTestInfo || !!packIsPreviewMode || !!exposedTestCookieString || !!exposedTestInfo) {
6709
+ return;
6710
+ }
6711
+ if (triggeredExposure?.packTestInfo.id === packTestInfo.id && triggeredExposure.packTestInfo.testVariant.id === packTestInfo.testVariant.id) {
6712
+ return;
6713
+ }
6714
+ if (packTestInfo.impressionTrigger !== "ON_ELEMENT_VIEW" || typeof window === "undefined" || typeof IntersectionObserver === "undefined") {
6715
+ setTriggeredExposure({
6716
+ packTestInfo,
6717
+ exposureTime: Date.now()
6718
+ });
6719
+ return;
6720
+ }
6721
+ const impressionSectionSelectors = getImpressionSelectors(
6722
+ packTestInfo,
6723
+ impressionSelector
6724
+ );
6725
+ if (impressionSectionSelectors.length === 0) {
6726
+ console.warn(
6727
+ `[Pack Test] Test "${packTestInfo.id}" uses ON_ELEMENT_VIEW but has no selectors to observe. Impression will not be tracked.`
6728
+ );
6729
+ return;
6730
+ }
6731
+ let isTriggered = false;
6732
+ const observedElements = /* @__PURE__ */ new Set();
6733
+ let observer;
6734
+ let mutationObserver;
6735
+ let observerTimeoutId;
6736
+ const cleanup = () => {
6737
+ observer?.disconnect();
6738
+ mutationObserver?.disconnect();
6739
+ if (observerTimeoutId) {
6740
+ clearTimeout(observerTimeoutId);
6741
+ }
6742
+ };
6743
+ const triggerImpression = () => {
6744
+ if (isTriggered) return;
6745
+ isTriggered = true;
6746
+ cleanup();
6747
+ setTriggeredExposure({
6748
+ packTestInfo,
6749
+ exposureTime: Date.now()
6750
+ });
6751
+ };
6752
+ const observeMatchingElements = () => {
6753
+ if (!observer || isTriggered) return;
6754
+ impressionSectionSelectors.forEach((selector) => {
6755
+ document.querySelectorAll(selector).forEach((element) => {
6756
+ if (observedElements.has(element)) return;
6757
+ observedElements.add(element);
6758
+ observer?.observe(element);
6606
6759
  });
6607
- return newQueue;
6608
6760
  });
6761
+ if (observedElements.size > 0) {
6762
+ mutationObserver?.disconnect();
6763
+ mutationObserver = void 0;
6764
+ if (observerTimeoutId) {
6765
+ clearTimeout(observerTimeoutId);
6766
+ observerTimeoutId = void 0;
6767
+ }
6768
+ }
6769
+ };
6770
+ observer = new IntersectionObserver(
6771
+ (entries) => {
6772
+ if (entries.some((entry) => entry.isIntersecting)) {
6773
+ triggerImpression();
6774
+ }
6775
+ },
6776
+ { threshold: 0.1 }
6777
+ );
6778
+ observeMatchingElements();
6779
+ if (!isTriggered && observedElements.size === 0 && typeof MutationObserver !== "undefined") {
6780
+ mutationObserver = new MutationObserver(() => {
6781
+ observeMatchingElements();
6782
+ });
6783
+ mutationObserver.observe(document.body, {
6784
+ childList: true,
6785
+ subtree: true
6786
+ });
6787
+ observerTimeoutId = setTimeout(() => {
6788
+ if (!isTriggered && observedElements.size === 0) {
6789
+ console.warn(
6790
+ `[Pack Test] Impression target not found within 30s for test "${packTestInfo.id}". Stopping observer.`
6791
+ );
6792
+ cleanup();
6793
+ }
6794
+ }, 3e4);
6609
6795
  }
6796
+ return cleanup;
6610
6797
  }, [
6611
- hasUserConsent2,
6798
+ triggeredExposure,
6799
+ exposedTestCookieString,
6800
+ exposedTestInfo,
6801
+ packIsPreviewMode,
6612
6802
  packTestInfo,
6803
+ impressionSelector
6804
+ ]);
6805
+ useEffect2(() => {
6806
+ if (triggeredExposure && !packIsPreviewMode && !hasUserConsent2 && !exposedTestCookieString) {
6807
+ setPendingExposureQueue?.((prev) => {
6808
+ if (prev.has(triggeredExposure.packTestInfo.id)) return prev;
6809
+ const nextQueue = new Map(prev);
6810
+ nextQueue.set(triggeredExposure.packTestInfo.id, triggeredExposure);
6811
+ return nextQueue;
6812
+ });
6813
+ }
6814
+ }, [
6815
+ triggeredExposure,
6816
+ hasUserConsent2,
6613
6817
  packIsPreviewMode,
6614
6818
  exposedTestCookieString,
6615
- exposedTestInfo
6819
+ setPendingExposureQueue
6616
6820
  ]);
6617
6821
  useEffect2(() => {
6618
- if (packTestInfo && hasUserConsent2 && !exposedTestCookieString && !packIsPreviewMode && !exposedTestInfo) {
6822
+ if (triggeredExposure && hasUserConsent2 && !exposedTestCookieString && !packIsPreviewMode && !exposedTestInfo) {
6823
+ const { packTestInfo: activeTestInfo, exposureTime } = triggeredExposure;
6619
6824
  const expires = /* @__PURE__ */ new Date();
6620
6825
  expires.setHours(expires.getHours() + 24);
6621
- api.set("exposedTest", JSON.stringify(packTestInfo), {
6622
- expires
6623
- });
6624
- setExposedTestInfo(packTestInfo);
6826
+ api.set(
6827
+ "exposedTest",
6828
+ serializeExposedTestCookieValue(activeTestInfo),
6829
+ {
6830
+ expires
6831
+ }
6832
+ );
6833
+ setExposedTestInfo(activeTestInfo);
6625
6834
  pendingExposureQueue?.forEach((data, key) => {
6835
+ if (key === activeTestInfo.id) return;
6626
6836
  try {
6627
6837
  testExposureCallback?.({
6628
6838
  ...data.packTestInfo,
6629
6839
  exposureTime: data.exposureTime
6630
6840
  });
6631
- setPendingExposureQueue?.((prev) => {
6632
- const newQueue = new Map(prev);
6633
- newQueue.delete(key);
6634
- return newQueue;
6635
- });
6636
6841
  } catch (error) {
6637
6842
  console.error("Failed to call testExposure after consent:", error);
6638
6843
  }
6639
6844
  });
6640
- testExposureCallback?.({ ...packTestInfo, exposureTime: Date.now() });
6845
+ testExposureCallback?.({ ...activeTestInfo, exposureTime });
6846
+ setPendingExposureQueue?.(/* @__PURE__ */ new Map());
6641
6847
  setTimeout(() => {
6642
6848
  revalidator?.revalidate();
6643
6849
  }, 750);
6644
6850
  }
6645
6851
  }, [
6646
- packTestInfo,
6852
+ triggeredExposure,
6853
+ exposedTestCookieString,
6854
+ pendingExposureQueue,
6647
6855
  testExposureCallback,
6648
6856
  exposedTestInfo,
6649
6857
  hasUserConsent2,
6650
- packIsPreviewMode
6858
+ packIsPreviewMode,
6859
+ setPendingExposureQueue
6860
+ ]);
6861
+ useEffect2(() => {
6862
+ if (!!triggeredExposure || !hasUserConsent2 || !!packIsPreviewMode || !pendingExposureQueue?.size || !!exposedTestCookieString) {
6863
+ return;
6864
+ }
6865
+ let firstQueuedTest;
6866
+ pendingExposureQueue.forEach((data) => {
6867
+ if (!firstQueuedTest) {
6868
+ firstQueuedTest = data.packTestInfo;
6869
+ }
6870
+ try {
6871
+ testExposureCallback?.({
6872
+ ...data.packTestInfo,
6873
+ exposureTime: data.exposureTime
6874
+ });
6875
+ } catch (error) {
6876
+ console.error(
6877
+ "Failed to call queued testExposure after consent:",
6878
+ error
6879
+ );
6880
+ }
6881
+ });
6882
+ if (firstQueuedTest) {
6883
+ const expires = /* @__PURE__ */ new Date();
6884
+ expires.setHours(expires.getHours() + 24);
6885
+ api.set(
6886
+ "exposedTest",
6887
+ serializeExposedTestCookieValue(firstQueuedTest),
6888
+ {
6889
+ expires
6890
+ }
6891
+ );
6892
+ setExposedTestInfo(firstQueuedTest);
6893
+ }
6894
+ setPendingExposureQueue?.(/* @__PURE__ */ new Map());
6895
+ }, [
6896
+ triggeredExposure,
6897
+ exposedTestCookieString,
6898
+ hasUserConsent2,
6899
+ packIsPreviewMode,
6900
+ pendingExposureQueue,
6901
+ setPendingExposureQueue,
6902
+ testExposureCallback
6651
6903
  ]);
6652
6904
  };
6653
- var PackTestRoute = () => {
6654
- usePackLoaderData();
6905
+ var PackTestRoute = ({
6906
+ impressionSelector
6907
+ } = {}) => {
6908
+ usePackLoaderData(impressionSelector);
6655
6909
  return null;
6656
6910
  };
6657
6911