@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 +13 -1
- package/dist/index.js +339 -85
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
-
|
|
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(
|
|
5069
|
-
|
|
5070
|
-
|
|
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(
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
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(
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
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(
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
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(
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
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(
|
|
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(
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
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(
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
5221
|
-
|
|
5222
|
-
(
|
|
5223
|
-
|
|
5224
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
6601
|
-
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6605
|
-
|
|
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
|
-
|
|
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
|
-
|
|
6819
|
+
setPendingExposureQueue
|
|
6616
6820
|
]);
|
|
6617
6821
|
useEffect2(() => {
|
|
6618
|
-
if (
|
|
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(
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
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?.({ ...
|
|
6845
|
+
testExposureCallback?.({ ...activeTestInfo, exposureTime });
|
|
6846
|
+
setPendingExposureQueue?.(/* @__PURE__ */ new Map());
|
|
6641
6847
|
setTimeout(() => {
|
|
6642
6848
|
revalidator?.revalidate();
|
|
6643
6849
|
}, 750);
|
|
6644
6850
|
}
|
|
6645
6851
|
}, [
|
|
6646
|
-
|
|
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
|
-
|
|
6905
|
+
var PackTestRoute = ({
|
|
6906
|
+
impressionSelector
|
|
6907
|
+
} = {}) => {
|
|
6908
|
+
usePackLoaderData(impressionSelector);
|
|
6655
6909
|
return null;
|
|
6656
6910
|
};
|
|
6657
6911
|
|