@pack/hydrogen 3.1.1-beta.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 +351 -149
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4356,7 +4356,7 @@ var require_dist = __commonJS({
|
|
|
4356
4356
|
}
|
|
4357
4357
|
});
|
|
4358
4358
|
|
|
4359
|
-
//
|
|
4359
|
+
// ../packlytics/dist/utils/get-packlytics-id.js
|
|
4360
4360
|
function sha256(ascii) {
|
|
4361
4361
|
function rightRotate(value, amount) {
|
|
4362
4362
|
return value >>> amount | value << 32 - amount;
|
|
@@ -4471,7 +4471,7 @@ var parseAcceptLanguage = function parseAcceptLanguage2(languageHeaderValue, opt
|
|
|
4471
4471
|
});
|
|
4472
4472
|
};
|
|
4473
4473
|
|
|
4474
|
-
//
|
|
4474
|
+
// ../packlytics/dist/utils/get-headers.js
|
|
4475
4475
|
function getHeaders(requestOrHeaders) {
|
|
4476
4476
|
if (requestOrHeaders instanceof Request) {
|
|
4477
4477
|
return requestOrHeaders.headers;
|
|
@@ -4479,7 +4479,7 @@ function getHeaders(requestOrHeaders) {
|
|
|
4479
4479
|
return requestOrHeaders;
|
|
4480
4480
|
}
|
|
4481
4481
|
|
|
4482
|
-
//
|
|
4482
|
+
// ../packlytics/dist/utils/get-client-locales.js
|
|
4483
4483
|
function getClientLocales(requestOrHeaders) {
|
|
4484
4484
|
let headers = getHeaders(requestOrHeaders);
|
|
4485
4485
|
let acceptLanguage = headers.get("Accept-Language");
|
|
@@ -4494,7 +4494,7 @@ function getClientLocales(requestOrHeaders) {
|
|
|
4494
4494
|
return locales;
|
|
4495
4495
|
}
|
|
4496
4496
|
|
|
4497
|
-
//
|
|
4497
|
+
// ../packlytics/dist/utils/sanatize-payload.js
|
|
4498
4498
|
var sanitizePayload = (data) => {
|
|
4499
4499
|
let dataStr = JSON.stringify(data);
|
|
4500
4500
|
const sensitiveFields = [
|
|
@@ -4525,7 +4525,7 @@ var sanitizePayload = (data) => {
|
|
|
4525
4525
|
return dataStr;
|
|
4526
4526
|
};
|
|
4527
4527
|
|
|
4528
|
-
//
|
|
4528
|
+
// ../packlytics/dist/utils/send-event.js
|
|
4529
4529
|
var metadata = null;
|
|
4530
4530
|
var getPacklyticsMetadata = async () => {
|
|
4531
4531
|
if (metadata)
|
|
@@ -4583,14 +4583,14 @@ var sendEvent = (storefrontId, sessionId) => {
|
|
|
4583
4583
|
};
|
|
4584
4584
|
};
|
|
4585
4585
|
|
|
4586
|
-
//
|
|
4586
|
+
// ../packlytics/dist/utils/page-hit.js
|
|
4587
4587
|
var trackPageHit = (storefrontId, sessionId) => {
|
|
4588
4588
|
return (eventPayload = {}) => {
|
|
4589
4589
|
return sendEvent(storefrontId, sessionId)("page_hit", eventPayload);
|
|
4590
4590
|
};
|
|
4591
4591
|
};
|
|
4592
4592
|
|
|
4593
|
-
//
|
|
4593
|
+
// ../packlytics/dist/utils/get-client-device.js
|
|
4594
4594
|
var import_ua_parser_js = __toESM(require_ua_parser());
|
|
4595
4595
|
function getDevice(userAgent) {
|
|
4596
4596
|
const userAgentData = (0, import_ua_parser_js.default)(userAgent);
|
|
@@ -4608,16 +4608,16 @@ function getDevice(userAgent) {
|
|
|
4608
4608
|
};
|
|
4609
4609
|
}
|
|
4610
4610
|
|
|
4611
|
-
//
|
|
4611
|
+
// ../packlytics/dist/packlytics.js
|
|
4612
4612
|
import { getStorefrontHeaders } from "@shopify/hydrogen/oxygen";
|
|
4613
4613
|
|
|
4614
|
-
//
|
|
4614
|
+
// ../packlytics/dist/utils/get-client-location.js
|
|
4615
4615
|
function getClientLocation(locale) {
|
|
4616
4616
|
const localeSplit = locale.split("-");
|
|
4617
4617
|
return localeSplit.length > 1 ? localeSplit[1].toLowerCase() : "";
|
|
4618
4618
|
}
|
|
4619
4619
|
|
|
4620
|
-
//
|
|
4620
|
+
// ../packlytics/dist/packlytics.js
|
|
4621
4621
|
async function sendEvent2(request, session, params) {
|
|
4622
4622
|
if (process.env.NODE_ENV === "development") {
|
|
4623
4623
|
return;
|
|
@@ -4691,7 +4691,6 @@ var PACK_COOKIE_ID = "__pack";
|
|
|
4691
4691
|
var PACK_USER_CONSENT_COOKIE_ID = "__pack_user_consent";
|
|
4692
4692
|
var PACK_TEST_COOKIE_ID = "__pack_test";
|
|
4693
4693
|
var PACK_COOKIE_MAX_AGE = 60 * 60 * 24 * 360;
|
|
4694
|
-
var PACK_TEST_CACHE_CHECK_URL = "https://test-cache-check-production.packdigital.workers.dev/tests-updated-at";
|
|
4695
4694
|
|
|
4696
4695
|
// src/session/usePackCookies.ts
|
|
4697
4696
|
function usePackCookies(options) {
|
|
@@ -5028,6 +5027,10 @@ var cookie2 = __toESM(require_cookie(), 1);
|
|
|
5028
5027
|
var import_json_rules_engine = __toESM(require_dist(), 1);
|
|
5029
5028
|
var import_debug2 = __toESM(require_browser(), 1);
|
|
5030
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
|
+
}
|
|
5031
5034
|
var LocalTestResolver = class {
|
|
5032
5035
|
testRules = [];
|
|
5033
5036
|
constructor() {
|
|
@@ -5066,62 +5069,86 @@ var LocalTestResolver = class {
|
|
|
5066
5069
|
* Evaluate test rules and assign a variant
|
|
5067
5070
|
*/
|
|
5068
5071
|
async assignTest(attributes, _sessionId) {
|
|
5069
|
-
debug2(
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5072
|
+
debug2(
|
|
5073
|
+
"[Pack Test LocalResolver] Starting test assignment:",
|
|
5074
|
+
JSON.stringify({
|
|
5075
|
+
totalRules: this.testRules.length,
|
|
5076
|
+
attributes
|
|
5077
|
+
})
|
|
5078
|
+
);
|
|
5073
5079
|
if (!this.testRules.length) {
|
|
5074
5080
|
debug2("[Pack Test LocalResolver] No test rules available");
|
|
5075
5081
|
return null;
|
|
5076
5082
|
}
|
|
5077
5083
|
const eligibleTests = await this.evaluateRules(this.testRules, attributes);
|
|
5078
|
-
debug2(
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
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
|
+
);
|
|
5083
5095
|
if (!eligibleTests.length) {
|
|
5084
5096
|
debug2("[Pack Test LocalResolver] No eligible tests found");
|
|
5085
5097
|
return null;
|
|
5086
5098
|
}
|
|
5087
5099
|
const randomTestIndex = this.getRandomNumber(eligibleTests.length - 1);
|
|
5088
5100
|
const selectedTest = eligibleTests[randomTestIndex];
|
|
5089
|
-
debug2(
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
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
|
+
);
|
|
5095
5110
|
const randomPercentage = this.getRandomNumber(100, 1);
|
|
5096
5111
|
let accumulatedPercentage = 0;
|
|
5097
|
-
debug2(
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
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
|
+
);
|
|
5105
5123
|
for (const variant of selectedTest.testVariants) {
|
|
5106
5124
|
accumulatedPercentage += variant.trafficPercentage * 100;
|
|
5107
|
-
debug2(
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
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
|
+
);
|
|
5115
5136
|
if (accumulatedPercentage >= randomPercentage) {
|
|
5137
|
+
const impressionSectionIds = getImpressionSectionIds(variant);
|
|
5116
5138
|
const result = {
|
|
5117
5139
|
id: selectedTest.id,
|
|
5118
5140
|
handle: selectedTest.handle,
|
|
5141
|
+
impressionTrigger: selectedTest.impressionTrigger,
|
|
5119
5142
|
testVariant: {
|
|
5120
5143
|
id: variant.id,
|
|
5121
5144
|
handle: variant.handle
|
|
5122
|
-
}
|
|
5145
|
+
},
|
|
5146
|
+
impression: impressionSectionIds.length > 0 ? { sectionIds: impressionSectionIds } : void 0
|
|
5123
5147
|
};
|
|
5124
|
-
debug2(
|
|
5148
|
+
debug2(
|
|
5149
|
+
"[Pack Test LocalResolver] Variant selected:",
|
|
5150
|
+
JSON.stringify(result)
|
|
5151
|
+
);
|
|
5125
5152
|
return result;
|
|
5126
5153
|
}
|
|
5127
5154
|
}
|
|
@@ -5132,26 +5159,34 @@ var LocalTestResolver = class {
|
|
|
5132
5159
|
* Evaluate rules using json-rules-engine (same as tests-service)
|
|
5133
5160
|
*/
|
|
5134
5161
|
async evaluateRules(tests, attributes) {
|
|
5135
|
-
debug2(
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
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
|
+
);
|
|
5140
5170
|
if (typeof window !== "undefined") {
|
|
5141
5171
|
debug2("[Pack Test LocalResolver] Client side - returning all tests");
|
|
5142
5172
|
return tests;
|
|
5143
5173
|
}
|
|
5144
5174
|
const engineResultsPromises = tests.map((test, index) => {
|
|
5145
5175
|
const { rules } = test;
|
|
5146
|
-
debug2(
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
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
|
+
);
|
|
5152
5185
|
if (rules && Array.isArray(rules)) {
|
|
5153
5186
|
if (rules.length === 0) {
|
|
5154
|
-
debug2(
|
|
5187
|
+
debug2(
|
|
5188
|
+
`[Pack Test LocalResolver] Test ${test.handle} has no rules - targeting all`
|
|
5189
|
+
);
|
|
5155
5190
|
return Promise.resolve({
|
|
5156
5191
|
events: [{ type: "targeted" }]
|
|
5157
5192
|
});
|
|
@@ -5163,7 +5198,10 @@ var LocalTestResolver = class {
|
|
|
5163
5198
|
operator: rule.operator,
|
|
5164
5199
|
value: rule.value
|
|
5165
5200
|
}));
|
|
5166
|
-
debug2(
|
|
5201
|
+
debug2(
|
|
5202
|
+
`[Pack Test LocalResolver] Test ${test.handle} engine conditions:`,
|
|
5203
|
+
JSON.stringify(engineConditionalProperties)
|
|
5204
|
+
);
|
|
5167
5205
|
const engineRules = [
|
|
5168
5206
|
new import_json_rules_engine.Rule({
|
|
5169
5207
|
conditions: {
|
|
@@ -5210,29 +5248,46 @@ var LocalTestResolver = class {
|
|
|
5210
5248
|
(factValue) => !factValue
|
|
5211
5249
|
);
|
|
5212
5250
|
const result = engine.run(attributes);
|
|
5213
|
-
debug2(
|
|
5251
|
+
debug2(
|
|
5252
|
+
`[Pack Test LocalResolver] Engine result for test ${test.handle}:`,
|
|
5253
|
+
JSON.stringify(result)
|
|
5254
|
+
);
|
|
5214
5255
|
return result;
|
|
5215
5256
|
}
|
|
5216
5257
|
}
|
|
5217
|
-
debug2(
|
|
5258
|
+
debug2(
|
|
5259
|
+
`[Pack Test LocalResolver] Test ${test.handle} has invalid rules`
|
|
5260
|
+
);
|
|
5218
5261
|
return void 0;
|
|
5219
5262
|
});
|
|
5220
5263
|
const engineResults = await Promise.all(engineResultsPromises);
|
|
5221
|
-
debug2(
|
|
5222
|
-
|
|
5223
|
-
(
|
|
5224
|
-
|
|
5225
|
-
|
|
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({
|
|
5226
5275
|
hasTargetedEvent,
|
|
5227
5276
|
events: engineResults?.[index]?.events
|
|
5228
|
-
})
|
|
5229
|
-
|
|
5230
|
-
|
|
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
|
+
})
|
|
5231
5290
|
);
|
|
5232
|
-
debug2("[Pack Test LocalResolver] Final eligible tests:", JSON.stringify({
|
|
5233
|
-
eligibleCount: eligibleTests.length,
|
|
5234
|
-
eligibleTests: eligibleTests.map((t) => ({ id: t.id, handle: t.handle }))
|
|
5235
|
-
}));
|
|
5236
5291
|
return eligibleTests;
|
|
5237
5292
|
}
|
|
5238
5293
|
/**
|
|
@@ -5275,16 +5330,26 @@ var QUERY_TESTS_BY_RULES = `#graphql
|
|
|
5275
5330
|
operator
|
|
5276
5331
|
value
|
|
5277
5332
|
}
|
|
5333
|
+
impressionTrigger
|
|
5278
5334
|
testVariants {
|
|
5279
5335
|
id
|
|
5280
5336
|
handle
|
|
5281
5337
|
trafficPercentage
|
|
5338
|
+
sectionTestVariants {
|
|
5339
|
+
section {
|
|
5340
|
+
id
|
|
5341
|
+
}
|
|
5342
|
+
}
|
|
5282
5343
|
}
|
|
5283
5344
|
}
|
|
5284
5345
|
}
|
|
5285
5346
|
}
|
|
5286
5347
|
}
|
|
5287
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
|
+
}
|
|
5288
5353
|
var localTestResolver = new LocalTestResolver();
|
|
5289
5354
|
function generateTestRulesCacheKey(storeId, contentEnvironment) {
|
|
5290
5355
|
return `pack-tests:${storeId}:${contentEnvironment || "default"}`;
|
|
@@ -5316,7 +5381,7 @@ async function fetchTestRulesShared(packClient, withCache, token) {
|
|
|
5316
5381
|
async ({
|
|
5317
5382
|
addDebugData
|
|
5318
5383
|
}) => {
|
|
5319
|
-
const URL2 =
|
|
5384
|
+
const URL2 = "https://test-cache-check-production.packdigital.workers.dev/tests-updated-at";
|
|
5320
5385
|
const resp2 = await fetch(URL2, {
|
|
5321
5386
|
headers: {
|
|
5322
5387
|
Authorization: `Bearer ${token}`
|
|
@@ -5498,13 +5563,16 @@ async function packClientFetchTestByRules(packClient, testTargetAudienceAttribut
|
|
|
5498
5563
|
(v) => v.id === currentTestData.testVariant.id
|
|
5499
5564
|
);
|
|
5500
5565
|
if (currentVariant) {
|
|
5566
|
+
const impressionSectionIds = getImpressionSectionIds2(currentVariant);
|
|
5501
5567
|
const refreshedTest = {
|
|
5502
5568
|
id: freshTestData.id,
|
|
5503
5569
|
handle: freshTestData.handle,
|
|
5570
|
+
impressionTrigger: freshTestData.impressionTrigger,
|
|
5504
5571
|
testVariant: {
|
|
5505
5572
|
id: currentVariant.id,
|
|
5506
5573
|
handle: currentVariant.handle
|
|
5507
5574
|
},
|
|
5575
|
+
impression: impressionSectionIds.length > 0 ? { sectionIds: impressionSectionIds } : void 0,
|
|
5508
5576
|
isFirstExposure: void 0
|
|
5509
5577
|
};
|
|
5510
5578
|
const { isFirstExposure: isFirstExposure2, ...testDataWithoutFlag2 } = refreshedTest;
|
|
@@ -5552,13 +5620,16 @@ async function packClientFetchTestByRules(packClient, testTargetAudienceAttribut
|
|
|
5552
5620
|
(v) => v.id === exposedTest.testVariant?.id
|
|
5553
5621
|
);
|
|
5554
5622
|
if (exposedVariant) {
|
|
5623
|
+
const impressionSectionIds = getImpressionSectionIds2(exposedVariant);
|
|
5555
5624
|
const result2 = {
|
|
5556
5625
|
id: freshTestData.id,
|
|
5557
5626
|
handle: freshTestData.handle,
|
|
5627
|
+
impressionTrigger: freshTestData.impressionTrigger,
|
|
5558
5628
|
testVariant: {
|
|
5559
5629
|
id: exposedVariant.id,
|
|
5560
5630
|
handle: exposedVariant.handle
|
|
5561
5631
|
},
|
|
5632
|
+
impression: impressionSectionIds.length > 0 ? { sectionIds: impressionSectionIds } : void 0,
|
|
5562
5633
|
isFirstExposure: void 0
|
|
5563
5634
|
};
|
|
5564
5635
|
const { isFirstExposure: isFirstExposure2, ...testDataWithoutFlag2 } = result2;
|
|
@@ -6045,45 +6116,8 @@ async function getCacheKey(withCache, query, token, options) {
|
|
|
6045
6116
|
debug4(`Error getting cache key: ${err}`);
|
|
6046
6117
|
console.error(err);
|
|
6047
6118
|
}
|
|
6048
|
-
|
|
6049
|
-
const hasTestHeaders = options?.headers && (options.headers["X-Pack-Test-Id"] || options.headers["X-Pack-Test-Handle"] || options.headers["X-Pack-Test-Variant-Id"] || options.headers["X-Pack-Test-Variant-Handle"]);
|
|
6050
|
-
if (hasTestHeaders) {
|
|
6051
|
-
try {
|
|
6052
|
-
const resp = await withCache.run(
|
|
6053
|
-
{
|
|
6054
|
-
cacheKey: ["pack:tests:updatedAt"],
|
|
6055
|
-
cacheStrategy: CacheCustom({
|
|
6056
|
-
maxAge: 15,
|
|
6057
|
-
staleWhileRevalidate: 15
|
|
6058
|
-
}),
|
|
6059
|
-
shouldCacheResult: (value) => value !== null
|
|
6060
|
-
},
|
|
6061
|
-
async ({
|
|
6062
|
-
addDebugData
|
|
6063
|
-
}) => {
|
|
6064
|
-
const URL2 = PACK_TEST_CACHE_CHECK_URL;
|
|
6065
|
-
const resp2 = await fetch(URL2, {
|
|
6066
|
-
headers: { Authorization: `Bearer ${token}` }
|
|
6067
|
-
});
|
|
6068
|
-
addDebugData?.({
|
|
6069
|
-
displayName: "Pack Test Cache Check (content key)",
|
|
6070
|
-
response: resp2
|
|
6071
|
-
});
|
|
6072
|
-
if (resp2.status !== 200) return null;
|
|
6073
|
-
return resp2.json();
|
|
6074
|
-
}
|
|
6075
|
-
);
|
|
6076
|
-
testsUpdatedAt = resp?.testsUpdatedAt;
|
|
6077
|
-
} catch (err) {
|
|
6078
|
-
debug4(`Error getting testsUpdatedAt for cache key: ${err}`);
|
|
6079
|
-
}
|
|
6080
|
-
}
|
|
6081
|
-
if (publishedAt && testsUpdatedAt) {
|
|
6082
|
-
return `${queryHash}:${publishedAt}:${testsUpdatedAt}`;
|
|
6083
|
-
} else if (publishedAt) {
|
|
6119
|
+
if (publishedAt) {
|
|
6084
6120
|
return `${queryHash}:${publishedAt}`;
|
|
6085
|
-
} else if (testsUpdatedAt) {
|
|
6086
|
-
return `${queryHash}:${testsUpdatedAt}`;
|
|
6087
6121
|
}
|
|
6088
6122
|
return queryHash;
|
|
6089
6123
|
}
|
|
@@ -6337,20 +6371,6 @@ function createPackClient(options) {
|
|
|
6337
6371
|
testInfoForRequest,
|
|
6338
6372
|
testFromQueryParams: testFromQueryParams || test
|
|
6339
6373
|
});
|
|
6340
|
-
if (testFromQueryParams) {
|
|
6341
|
-
try {
|
|
6342
|
-
const result = await packClient.fetch(query, {
|
|
6343
|
-
variables: queryVariables,
|
|
6344
|
-
headers
|
|
6345
|
-
});
|
|
6346
|
-
return {
|
|
6347
|
-
...result,
|
|
6348
|
-
packTestInfo: testInfoForLoader
|
|
6349
|
-
};
|
|
6350
|
-
} catch (error) {
|
|
6351
|
-
return { error, data: null };
|
|
6352
|
-
}
|
|
6353
|
-
}
|
|
6354
6374
|
if (previewEnabled) {
|
|
6355
6375
|
try {
|
|
6356
6376
|
const result = await packClient.fetch(query, {
|
|
@@ -6624,8 +6644,35 @@ var PackTestContext = createContext({});
|
|
|
6624
6644
|
var usePackTestContext = () => useContext(PackTestContext);
|
|
6625
6645
|
|
|
6626
6646
|
// src/tests/pack-test-route.ts
|
|
6627
|
-
|
|
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) => {
|
|
6628
6674
|
const [exposedTestInfo, setExposedTestInfo] = useState();
|
|
6675
|
+
const [triggeredExposure, setTriggeredExposure] = useState();
|
|
6629
6676
|
let packTestInfo;
|
|
6630
6677
|
let packIsPreviewMode;
|
|
6631
6678
|
let revalidator;
|
|
@@ -6649,61 +6696,216 @@ var usePackLoaderData = () => {
|
|
|
6649
6696
|
} = usePackTestContext();
|
|
6650
6697
|
const exposedTestCookieString = api.get("exposedTest");
|
|
6651
6698
|
useEffect2(() => {
|
|
6652
|
-
if (packTestInfo
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
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);
|
|
6658
6759
|
});
|
|
6659
|
-
return newQueue;
|
|
6660
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);
|
|
6661
6795
|
}
|
|
6796
|
+
return cleanup;
|
|
6662
6797
|
}, [
|
|
6663
|
-
|
|
6798
|
+
triggeredExposure,
|
|
6799
|
+
exposedTestCookieString,
|
|
6800
|
+
exposedTestInfo,
|
|
6801
|
+
packIsPreviewMode,
|
|
6664
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,
|
|
6665
6817
|
packIsPreviewMode,
|
|
6666
6818
|
exposedTestCookieString,
|
|
6667
|
-
|
|
6819
|
+
setPendingExposureQueue
|
|
6668
6820
|
]);
|
|
6669
6821
|
useEffect2(() => {
|
|
6670
|
-
if (
|
|
6822
|
+
if (triggeredExposure && hasUserConsent2 && !exposedTestCookieString && !packIsPreviewMode && !exposedTestInfo) {
|
|
6823
|
+
const { packTestInfo: activeTestInfo, exposureTime } = triggeredExposure;
|
|
6671
6824
|
const expires = /* @__PURE__ */ new Date();
|
|
6672
6825
|
expires.setHours(expires.getHours() + 24);
|
|
6673
|
-
api.set(
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6826
|
+
api.set(
|
|
6827
|
+
"exposedTest",
|
|
6828
|
+
serializeExposedTestCookieValue(activeTestInfo),
|
|
6829
|
+
{
|
|
6830
|
+
expires
|
|
6831
|
+
}
|
|
6832
|
+
);
|
|
6833
|
+
setExposedTestInfo(activeTestInfo);
|
|
6677
6834
|
pendingExposureQueue?.forEach((data, key) => {
|
|
6835
|
+
if (key === activeTestInfo.id) return;
|
|
6678
6836
|
try {
|
|
6679
6837
|
testExposureCallback?.({
|
|
6680
6838
|
...data.packTestInfo,
|
|
6681
6839
|
exposureTime: data.exposureTime
|
|
6682
6840
|
});
|
|
6683
|
-
setPendingExposureQueue?.((prev) => {
|
|
6684
|
-
const newQueue = new Map(prev);
|
|
6685
|
-
newQueue.delete(key);
|
|
6686
|
-
return newQueue;
|
|
6687
|
-
});
|
|
6688
6841
|
} catch (error) {
|
|
6689
6842
|
console.error("Failed to call testExposure after consent:", error);
|
|
6690
6843
|
}
|
|
6691
6844
|
});
|
|
6692
|
-
testExposureCallback?.({ ...
|
|
6845
|
+
testExposureCallback?.({ ...activeTestInfo, exposureTime });
|
|
6846
|
+
setPendingExposureQueue?.(/* @__PURE__ */ new Map());
|
|
6693
6847
|
setTimeout(() => {
|
|
6694
6848
|
revalidator?.revalidate();
|
|
6695
6849
|
}, 750);
|
|
6696
6850
|
}
|
|
6697
6851
|
}, [
|
|
6698
|
-
|
|
6852
|
+
triggeredExposure,
|
|
6853
|
+
exposedTestCookieString,
|
|
6854
|
+
pendingExposureQueue,
|
|
6699
6855
|
testExposureCallback,
|
|
6700
6856
|
exposedTestInfo,
|
|
6701
6857
|
hasUserConsent2,
|
|
6702
|
-
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
|
|
6703
6903
|
]);
|
|
6704
6904
|
};
|
|
6705
|
-
var PackTestRoute = (
|
|
6706
|
-
|
|
6905
|
+
var PackTestRoute = ({
|
|
6906
|
+
impressionSelector
|
|
6907
|
+
} = {}) => {
|
|
6908
|
+
usePackLoaderData(impressionSelector);
|
|
6707
6909
|
return null;
|
|
6708
6910
|
};
|
|
6709
6911
|
|