@pack/hydrogen 3.1.1-beta.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -1
- package/dist/index.d.ts +18 -1
- package/dist/index.js +382 -155
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -4356,7 +4356,10 @@ var require_dist = __commonJS({
|
|
|
4356
4356
|
}
|
|
4357
4357
|
});
|
|
4358
4358
|
|
|
4359
|
-
//
|
|
4359
|
+
// src/handle-request.ts
|
|
4360
|
+
import { sendServerErrorEvent } from "@pack/errors";
|
|
4361
|
+
|
|
4362
|
+
// ../packlytics/dist/utils/get-packlytics-id.js
|
|
4360
4363
|
function sha256(ascii) {
|
|
4361
4364
|
function rightRotate(value, amount) {
|
|
4362
4365
|
return value >>> amount | value << 32 - amount;
|
|
@@ -4471,7 +4474,7 @@ var parseAcceptLanguage = function parseAcceptLanguage2(languageHeaderValue, opt
|
|
|
4471
4474
|
});
|
|
4472
4475
|
};
|
|
4473
4476
|
|
|
4474
|
-
//
|
|
4477
|
+
// ../packlytics/dist/utils/get-headers.js
|
|
4475
4478
|
function getHeaders(requestOrHeaders) {
|
|
4476
4479
|
if (requestOrHeaders instanceof Request) {
|
|
4477
4480
|
return requestOrHeaders.headers;
|
|
@@ -4479,7 +4482,7 @@ function getHeaders(requestOrHeaders) {
|
|
|
4479
4482
|
return requestOrHeaders;
|
|
4480
4483
|
}
|
|
4481
4484
|
|
|
4482
|
-
//
|
|
4485
|
+
// ../packlytics/dist/utils/get-client-locales.js
|
|
4483
4486
|
function getClientLocales(requestOrHeaders) {
|
|
4484
4487
|
let headers = getHeaders(requestOrHeaders);
|
|
4485
4488
|
let acceptLanguage = headers.get("Accept-Language");
|
|
@@ -4494,7 +4497,7 @@ function getClientLocales(requestOrHeaders) {
|
|
|
4494
4497
|
return locales;
|
|
4495
4498
|
}
|
|
4496
4499
|
|
|
4497
|
-
//
|
|
4500
|
+
// ../packlytics/dist/utils/sanatize-payload.js
|
|
4498
4501
|
var sanitizePayload = (data) => {
|
|
4499
4502
|
let dataStr = JSON.stringify(data);
|
|
4500
4503
|
const sensitiveFields = [
|
|
@@ -4525,7 +4528,7 @@ var sanitizePayload = (data) => {
|
|
|
4525
4528
|
return dataStr;
|
|
4526
4529
|
};
|
|
4527
4530
|
|
|
4528
|
-
//
|
|
4531
|
+
// ../packlytics/dist/utils/send-event.js
|
|
4529
4532
|
var metadata = null;
|
|
4530
4533
|
var getPacklyticsMetadata = async () => {
|
|
4531
4534
|
if (metadata)
|
|
@@ -4583,14 +4586,14 @@ var sendEvent = (storefrontId, sessionId) => {
|
|
|
4583
4586
|
};
|
|
4584
4587
|
};
|
|
4585
4588
|
|
|
4586
|
-
//
|
|
4589
|
+
// ../packlytics/dist/utils/page-hit.js
|
|
4587
4590
|
var trackPageHit = (storefrontId, sessionId) => {
|
|
4588
4591
|
return (eventPayload = {}) => {
|
|
4589
4592
|
return sendEvent(storefrontId, sessionId)("page_hit", eventPayload);
|
|
4590
4593
|
};
|
|
4591
4594
|
};
|
|
4592
4595
|
|
|
4593
|
-
//
|
|
4596
|
+
// ../packlytics/dist/utils/get-client-device.js
|
|
4594
4597
|
var import_ua_parser_js = __toESM(require_ua_parser());
|
|
4595
4598
|
function getDevice(userAgent) {
|
|
4596
4599
|
const userAgentData = (0, import_ua_parser_js.default)(userAgent);
|
|
@@ -4608,16 +4611,16 @@ function getDevice(userAgent) {
|
|
|
4608
4611
|
};
|
|
4609
4612
|
}
|
|
4610
4613
|
|
|
4611
|
-
//
|
|
4614
|
+
// ../packlytics/dist/packlytics.js
|
|
4612
4615
|
import { getStorefrontHeaders } from "@shopify/hydrogen/oxygen";
|
|
4613
4616
|
|
|
4614
|
-
//
|
|
4617
|
+
// ../packlytics/dist/utils/get-client-location.js
|
|
4615
4618
|
function getClientLocation(locale) {
|
|
4616
4619
|
const localeSplit = locale.split("-");
|
|
4617
4620
|
return localeSplit.length > 1 ? localeSplit[1].toLowerCase() : "";
|
|
4618
4621
|
}
|
|
4619
4622
|
|
|
4620
|
-
//
|
|
4623
|
+
// ../packlytics/dist/packlytics.js
|
|
4621
4624
|
async function sendEvent2(request, session, params) {
|
|
4622
4625
|
if (process.env.NODE_ENV === "development") {
|
|
4623
4626
|
return;
|
|
@@ -4668,11 +4671,28 @@ async function packlytics(pack, request, next) {
|
|
|
4668
4671
|
}
|
|
4669
4672
|
|
|
4670
4673
|
// src/handle-request.ts
|
|
4674
|
+
function getServerStatusError(request, status) {
|
|
4675
|
+
let pathname = request.url;
|
|
4676
|
+
try {
|
|
4677
|
+
pathname = new URL(request.url).pathname;
|
|
4678
|
+
} catch {
|
|
4679
|
+
}
|
|
4680
|
+
return new Error(`HTTP ${status} response for ${request.method} ${pathname}`);
|
|
4681
|
+
}
|
|
4671
4682
|
async function handleRequest(pack, request, handleRequest2) {
|
|
4672
4683
|
const packHandleResponse = await pack.handleRequest(request);
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4684
|
+
let response;
|
|
4685
|
+
try {
|
|
4686
|
+
response = await packlytics(pack, request, () => {
|
|
4687
|
+
return handleRequest2(request);
|
|
4688
|
+
});
|
|
4689
|
+
} catch (error) {
|
|
4690
|
+
sendServerErrorEvent(error, request, pack);
|
|
4691
|
+
throw error;
|
|
4692
|
+
}
|
|
4693
|
+
if (response.status >= 500 && !request.signal.aborted) {
|
|
4694
|
+
sendServerErrorEvent(getServerStatusError(request, response.status), request, pack);
|
|
4695
|
+
}
|
|
4676
4696
|
packHandleResponse(response);
|
|
4677
4697
|
response.headers.append("powered-by", "Shopify, Hydrogen + Pack Digital");
|
|
4678
4698
|
response.headers.append("Set-Cookie", await pack.session.commit());
|
|
@@ -4691,7 +4711,6 @@ var PACK_COOKIE_ID = "__pack";
|
|
|
4691
4711
|
var PACK_USER_CONSENT_COOKIE_ID = "__pack_user_consent";
|
|
4692
4712
|
var PACK_TEST_COOKIE_ID = "__pack_test";
|
|
4693
4713
|
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
4714
|
|
|
4696
4715
|
// src/session/usePackCookies.ts
|
|
4697
4716
|
function usePackCookies(options) {
|
|
@@ -5028,6 +5047,10 @@ var cookie2 = __toESM(require_cookie(), 1);
|
|
|
5028
5047
|
var import_json_rules_engine = __toESM(require_dist(), 1);
|
|
5029
5048
|
var import_debug2 = __toESM(require_browser(), 1);
|
|
5030
5049
|
var debug2 = (0, import_debug2.default)("pack:ab-testing:local-resolver");
|
|
5050
|
+
function getImpressionSectionIds(testVariant) {
|
|
5051
|
+
const sectionIds = testVariant?.sectionTestVariants?.map((variant) => variant?.section?.id).filter((id) => Boolean(id)) || [];
|
|
5052
|
+
return [...new Set(sectionIds)];
|
|
5053
|
+
}
|
|
5031
5054
|
var LocalTestResolver = class {
|
|
5032
5055
|
testRules = [];
|
|
5033
5056
|
constructor() {
|
|
@@ -5066,62 +5089,86 @@ var LocalTestResolver = class {
|
|
|
5066
5089
|
* Evaluate test rules and assign a variant
|
|
5067
5090
|
*/
|
|
5068
5091
|
async assignTest(attributes, _sessionId) {
|
|
5069
|
-
debug2(
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5092
|
+
debug2(
|
|
5093
|
+
"[Pack Test LocalResolver] Starting test assignment:",
|
|
5094
|
+
JSON.stringify({
|
|
5095
|
+
totalRules: this.testRules.length,
|
|
5096
|
+
attributes
|
|
5097
|
+
})
|
|
5098
|
+
);
|
|
5073
5099
|
if (!this.testRules.length) {
|
|
5074
5100
|
debug2("[Pack Test LocalResolver] No test rules available");
|
|
5075
5101
|
return null;
|
|
5076
5102
|
}
|
|
5077
5103
|
const eligibleTests = await this.evaluateRules(this.testRules, attributes);
|
|
5078
|
-
debug2(
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5104
|
+
debug2(
|
|
5105
|
+
"[Pack Test LocalResolver] Rule evaluation result:",
|
|
5106
|
+
JSON.stringify({
|
|
5107
|
+
totalTests: this.testRules.length,
|
|
5108
|
+
eligibleTests: eligibleTests.length,
|
|
5109
|
+
eligibleTestIds: eligibleTests.map((t) => ({
|
|
5110
|
+
id: t.id,
|
|
5111
|
+
handle: t.handle
|
|
5112
|
+
}))
|
|
5113
|
+
})
|
|
5114
|
+
);
|
|
5083
5115
|
if (!eligibleTests.length) {
|
|
5084
5116
|
debug2("[Pack Test LocalResolver] No eligible tests found");
|
|
5085
5117
|
return null;
|
|
5086
5118
|
}
|
|
5087
5119
|
const randomTestIndex = this.getRandomNumber(eligibleTests.length - 1);
|
|
5088
5120
|
const selectedTest = eligibleTests[randomTestIndex];
|
|
5089
|
-
debug2(
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5121
|
+
debug2(
|
|
5122
|
+
"[Pack Test LocalResolver] Selected test:",
|
|
5123
|
+
JSON.stringify({
|
|
5124
|
+
testId: selectedTest.id,
|
|
5125
|
+
testHandle: selectedTest.handle,
|
|
5126
|
+
randomIndex: randomTestIndex,
|
|
5127
|
+
totalEligible: eligibleTests.length
|
|
5128
|
+
})
|
|
5129
|
+
);
|
|
5095
5130
|
const randomPercentage = this.getRandomNumber(100, 1);
|
|
5096
5131
|
let accumulatedPercentage = 0;
|
|
5097
|
-
debug2(
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5132
|
+
debug2(
|
|
5133
|
+
"[Pack Test LocalResolver] Starting variant assignment:",
|
|
5134
|
+
JSON.stringify({
|
|
5135
|
+
randomPercentage,
|
|
5136
|
+
variants: selectedTest.testVariants.map((v) => ({
|
|
5137
|
+
id: v.id,
|
|
5138
|
+
handle: v.handle,
|
|
5139
|
+
trafficPercentage: v.trafficPercentage
|
|
5140
|
+
}))
|
|
5141
|
+
})
|
|
5142
|
+
);
|
|
5105
5143
|
for (const variant of selectedTest.testVariants) {
|
|
5106
5144
|
accumulatedPercentage += variant.trafficPercentage * 100;
|
|
5107
|
-
debug2(
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5145
|
+
debug2(
|
|
5146
|
+
"[Pack Test LocalResolver] Checking variant:",
|
|
5147
|
+
JSON.stringify({
|
|
5148
|
+
variantId: variant.id,
|
|
5149
|
+
variantHandle: variant.handle,
|
|
5150
|
+
trafficPercentage: variant.trafficPercentage,
|
|
5151
|
+
accumulatedPercentage,
|
|
5152
|
+
randomPercentage,
|
|
5153
|
+
isSelected: accumulatedPercentage >= randomPercentage
|
|
5154
|
+
})
|
|
5155
|
+
);
|
|
5115
5156
|
if (accumulatedPercentage >= randomPercentage) {
|
|
5157
|
+
const impressionSectionIds = getImpressionSectionIds(variant);
|
|
5116
5158
|
const result = {
|
|
5117
5159
|
id: selectedTest.id,
|
|
5118
5160
|
handle: selectedTest.handle,
|
|
5161
|
+
impressionTrigger: selectedTest.impressionTrigger,
|
|
5119
5162
|
testVariant: {
|
|
5120
5163
|
id: variant.id,
|
|
5121
5164
|
handle: variant.handle
|
|
5122
|
-
}
|
|
5165
|
+
},
|
|
5166
|
+
impression: impressionSectionIds.length > 0 ? { sectionIds: impressionSectionIds } : void 0
|
|
5123
5167
|
};
|
|
5124
|
-
debug2(
|
|
5168
|
+
debug2(
|
|
5169
|
+
"[Pack Test LocalResolver] Variant selected:",
|
|
5170
|
+
JSON.stringify(result)
|
|
5171
|
+
);
|
|
5125
5172
|
return result;
|
|
5126
5173
|
}
|
|
5127
5174
|
}
|
|
@@ -5132,26 +5179,34 @@ var LocalTestResolver = class {
|
|
|
5132
5179
|
* Evaluate rules using json-rules-engine (same as tests-service)
|
|
5133
5180
|
*/
|
|
5134
5181
|
async evaluateRules(tests, attributes) {
|
|
5135
|
-
debug2(
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5182
|
+
debug2(
|
|
5183
|
+
"[Pack Test LocalResolver] Starting rule evaluation:",
|
|
5184
|
+
JSON.stringify({
|
|
5185
|
+
totalTests: tests.length,
|
|
5186
|
+
attributes,
|
|
5187
|
+
isClientSide: typeof window !== "undefined"
|
|
5188
|
+
})
|
|
5189
|
+
);
|
|
5140
5190
|
if (typeof window !== "undefined") {
|
|
5141
5191
|
debug2("[Pack Test LocalResolver] Client side - returning all tests");
|
|
5142
5192
|
return tests;
|
|
5143
5193
|
}
|
|
5144
5194
|
const engineResultsPromises = tests.map((test, index) => {
|
|
5145
5195
|
const { rules } = test;
|
|
5146
|
-
debug2(
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
|
|
5196
|
+
debug2(
|
|
5197
|
+
`[Pack Test LocalResolver] Processing test ${index}:`,
|
|
5198
|
+
JSON.stringify({
|
|
5199
|
+
testId: test.id,
|
|
5200
|
+
testHandle: test.handle,
|
|
5201
|
+
rulesCount: rules?.length || 0,
|
|
5202
|
+
rules
|
|
5203
|
+
})
|
|
5204
|
+
);
|
|
5152
5205
|
if (rules && Array.isArray(rules)) {
|
|
5153
5206
|
if (rules.length === 0) {
|
|
5154
|
-
debug2(
|
|
5207
|
+
debug2(
|
|
5208
|
+
`[Pack Test LocalResolver] Test ${test.handle} has no rules - targeting all`
|
|
5209
|
+
);
|
|
5155
5210
|
return Promise.resolve({
|
|
5156
5211
|
events: [{ type: "targeted" }]
|
|
5157
5212
|
});
|
|
@@ -5163,7 +5218,10 @@ var LocalTestResolver = class {
|
|
|
5163
5218
|
operator: rule.operator,
|
|
5164
5219
|
value: rule.value
|
|
5165
5220
|
}));
|
|
5166
|
-
debug2(
|
|
5221
|
+
debug2(
|
|
5222
|
+
`[Pack Test LocalResolver] Test ${test.handle} engine conditions:`,
|
|
5223
|
+
JSON.stringify(engineConditionalProperties)
|
|
5224
|
+
);
|
|
5167
5225
|
const engineRules = [
|
|
5168
5226
|
new import_json_rules_engine.Rule({
|
|
5169
5227
|
conditions: {
|
|
@@ -5210,29 +5268,46 @@ var LocalTestResolver = class {
|
|
|
5210
5268
|
(factValue) => !factValue
|
|
5211
5269
|
);
|
|
5212
5270
|
const result = engine.run(attributes);
|
|
5213
|
-
debug2(
|
|
5271
|
+
debug2(
|
|
5272
|
+
`[Pack Test LocalResolver] Engine result for test ${test.handle}:`,
|
|
5273
|
+
JSON.stringify(result)
|
|
5274
|
+
);
|
|
5214
5275
|
return result;
|
|
5215
5276
|
}
|
|
5216
5277
|
}
|
|
5217
|
-
debug2(
|
|
5278
|
+
debug2(
|
|
5279
|
+
`[Pack Test LocalResolver] Test ${test.handle} has invalid rules`
|
|
5280
|
+
);
|
|
5218
5281
|
return void 0;
|
|
5219
5282
|
});
|
|
5220
5283
|
const engineResults = await Promise.all(engineResultsPromises);
|
|
5221
|
-
debug2(
|
|
5222
|
-
|
|
5223
|
-
(
|
|
5224
|
-
|
|
5225
|
-
|
|
5284
|
+
debug2(
|
|
5285
|
+
"[Pack Test LocalResolver] All engine results:",
|
|
5286
|
+
JSON.stringify(engineResults)
|
|
5287
|
+
);
|
|
5288
|
+
const eligibleTests = tests.filter((test, index) => {
|
|
5289
|
+
const hasTargetedEvent = !!engineResults?.[index]?.events.find(
|
|
5290
|
+
(event) => event.type === "targeted"
|
|
5291
|
+
);
|
|
5292
|
+
debug2(
|
|
5293
|
+
`[Pack Test LocalResolver] Test ${test.handle} eligibility:`,
|
|
5294
|
+
JSON.stringify({
|
|
5226
5295
|
hasTargetedEvent,
|
|
5227
5296
|
events: engineResults?.[index]?.events
|
|
5228
|
-
})
|
|
5229
|
-
|
|
5230
|
-
|
|
5297
|
+
})
|
|
5298
|
+
);
|
|
5299
|
+
return hasTargetedEvent;
|
|
5300
|
+
});
|
|
5301
|
+
debug2(
|
|
5302
|
+
"[Pack Test LocalResolver] Final eligible tests:",
|
|
5303
|
+
JSON.stringify({
|
|
5304
|
+
eligibleCount: eligibleTests.length,
|
|
5305
|
+
eligibleTests: eligibleTests.map((t) => ({
|
|
5306
|
+
id: t.id,
|
|
5307
|
+
handle: t.handle
|
|
5308
|
+
}))
|
|
5309
|
+
})
|
|
5231
5310
|
);
|
|
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
5311
|
return eligibleTests;
|
|
5237
5312
|
}
|
|
5238
5313
|
/**
|
|
@@ -5275,16 +5350,26 @@ var QUERY_TESTS_BY_RULES = `#graphql
|
|
|
5275
5350
|
operator
|
|
5276
5351
|
value
|
|
5277
5352
|
}
|
|
5353
|
+
impressionTrigger
|
|
5278
5354
|
testVariants {
|
|
5279
5355
|
id
|
|
5280
5356
|
handle
|
|
5281
5357
|
trafficPercentage
|
|
5358
|
+
sectionTestVariants {
|
|
5359
|
+
section {
|
|
5360
|
+
id
|
|
5361
|
+
}
|
|
5362
|
+
}
|
|
5282
5363
|
}
|
|
5283
5364
|
}
|
|
5284
5365
|
}
|
|
5285
5366
|
}
|
|
5286
5367
|
}
|
|
5287
5368
|
`;
|
|
5369
|
+
function getImpressionSectionIds2(testVariant) {
|
|
5370
|
+
const sectionIds = testVariant?.sectionTestVariants?.map((variant) => variant?.section?.id).filter((id) => Boolean(id)) || [];
|
|
5371
|
+
return [...new Set(sectionIds)];
|
|
5372
|
+
}
|
|
5288
5373
|
var localTestResolver = new LocalTestResolver();
|
|
5289
5374
|
function generateTestRulesCacheKey(storeId, contentEnvironment) {
|
|
5290
5375
|
return `pack-tests:${storeId}:${contentEnvironment || "default"}`;
|
|
@@ -5316,7 +5401,7 @@ async function fetchTestRulesShared(packClient, withCache, token) {
|
|
|
5316
5401
|
async ({
|
|
5317
5402
|
addDebugData
|
|
5318
5403
|
}) => {
|
|
5319
|
-
const URL2 =
|
|
5404
|
+
const URL2 = "https://test-cache-check-production.packdigital.workers.dev/tests-updated-at";
|
|
5320
5405
|
const resp2 = await fetch(URL2, {
|
|
5321
5406
|
headers: {
|
|
5322
5407
|
Authorization: `Bearer ${token}`
|
|
@@ -5498,13 +5583,16 @@ async function packClientFetchTestByRules(packClient, testTargetAudienceAttribut
|
|
|
5498
5583
|
(v) => v.id === currentTestData.testVariant.id
|
|
5499
5584
|
);
|
|
5500
5585
|
if (currentVariant) {
|
|
5586
|
+
const impressionSectionIds = getImpressionSectionIds2(currentVariant);
|
|
5501
5587
|
const refreshedTest = {
|
|
5502
5588
|
id: freshTestData.id,
|
|
5503
5589
|
handle: freshTestData.handle,
|
|
5590
|
+
impressionTrigger: freshTestData.impressionTrigger,
|
|
5504
5591
|
testVariant: {
|
|
5505
5592
|
id: currentVariant.id,
|
|
5506
5593
|
handle: currentVariant.handle
|
|
5507
5594
|
},
|
|
5595
|
+
impression: impressionSectionIds.length > 0 ? { sectionIds: impressionSectionIds } : void 0,
|
|
5508
5596
|
isFirstExposure: void 0
|
|
5509
5597
|
};
|
|
5510
5598
|
const { isFirstExposure: isFirstExposure2, ...testDataWithoutFlag2 } = refreshedTest;
|
|
@@ -5552,13 +5640,16 @@ async function packClientFetchTestByRules(packClient, testTargetAudienceAttribut
|
|
|
5552
5640
|
(v) => v.id === exposedTest.testVariant?.id
|
|
5553
5641
|
);
|
|
5554
5642
|
if (exposedVariant) {
|
|
5643
|
+
const impressionSectionIds = getImpressionSectionIds2(exposedVariant);
|
|
5555
5644
|
const result2 = {
|
|
5556
5645
|
id: freshTestData.id,
|
|
5557
5646
|
handle: freshTestData.handle,
|
|
5647
|
+
impressionTrigger: freshTestData.impressionTrigger,
|
|
5558
5648
|
testVariant: {
|
|
5559
5649
|
id: exposedVariant.id,
|
|
5560
5650
|
handle: exposedVariant.handle
|
|
5561
5651
|
},
|
|
5652
|
+
impression: impressionSectionIds.length > 0 ? { sectionIds: impressionSectionIds } : void 0,
|
|
5562
5653
|
isFirstExposure: void 0
|
|
5563
5654
|
};
|
|
5564
5655
|
const { isFirstExposure: isFirstExposure2, ...testDataWithoutFlag2 } = result2;
|
|
@@ -6045,45 +6136,8 @@ async function getCacheKey(withCache, query, token, options) {
|
|
|
6045
6136
|
debug4(`Error getting cache key: ${err}`);
|
|
6046
6137
|
console.error(err);
|
|
6047
6138
|
}
|
|
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) {
|
|
6139
|
+
if (publishedAt) {
|
|
6084
6140
|
return `${queryHash}:${publishedAt}`;
|
|
6085
|
-
} else if (testsUpdatedAt) {
|
|
6086
|
-
return `${queryHash}:${testsUpdatedAt}`;
|
|
6087
6141
|
}
|
|
6088
6142
|
return queryHash;
|
|
6089
6143
|
}
|
|
@@ -6126,6 +6180,7 @@ function createPackClient(options) {
|
|
|
6126
6180
|
token,
|
|
6127
6181
|
apiUrl,
|
|
6128
6182
|
defaultThemeData,
|
|
6183
|
+
errorTracking,
|
|
6129
6184
|
i18n,
|
|
6130
6185
|
request
|
|
6131
6186
|
} = options;
|
|
@@ -6200,7 +6255,8 @@ function createPackClient(options) {
|
|
|
6200
6255
|
previewEnabled
|
|
6201
6256
|
),
|
|
6202
6257
|
packIsPreviewMode: previewEnabled,
|
|
6203
|
-
packCustomizerMeta: session.get("customizerMeta")
|
|
6258
|
+
packCustomizerMeta: session.get("customizerMeta"),
|
|
6259
|
+
packErrorTracking: errorTracking
|
|
6204
6260
|
};
|
|
6205
6261
|
},
|
|
6206
6262
|
isPreviewModeEnabled: () => previewEnabled,
|
|
@@ -6215,6 +6271,7 @@ function createPackClient(options) {
|
|
|
6215
6271
|
return { data, error: null };
|
|
6216
6272
|
},
|
|
6217
6273
|
session,
|
|
6274
|
+
errorTracking,
|
|
6218
6275
|
testSession
|
|
6219
6276
|
};
|
|
6220
6277
|
}
|
|
@@ -6264,7 +6321,8 @@ function createPackClient(options) {
|
|
|
6264
6321
|
previewEnabled
|
|
6265
6322
|
),
|
|
6266
6323
|
packIsPreviewMode: previewEnabled,
|
|
6267
|
-
packCustomizerMeta: session.get("customizerMeta")
|
|
6324
|
+
packCustomizerMeta: session.get("customizerMeta"),
|
|
6325
|
+
packErrorTracking: errorTracking
|
|
6268
6326
|
};
|
|
6269
6327
|
},
|
|
6270
6328
|
handleRequest: handleRequest2,
|
|
@@ -6329,7 +6387,7 @@ function createPackClient(options) {
|
|
|
6329
6387
|
}
|
|
6330
6388
|
}
|
|
6331
6389
|
if (testInfoForRequest?.isFirstExposure) {
|
|
6332
|
-
const { isFirstExposure, ...testInfo } = testInfoForRequest;
|
|
6390
|
+
const { isFirstExposure: _isFirstExposure, ...testInfo } = testInfoForRequest;
|
|
6333
6391
|
testInfoForLoader = testInfo;
|
|
6334
6392
|
}
|
|
6335
6393
|
headers = setTestHeaders(headers, {
|
|
@@ -6337,20 +6395,6 @@ function createPackClient(options) {
|
|
|
6337
6395
|
testInfoForRequest,
|
|
6338
6396
|
testFromQueryParams: testFromQueryParams || test
|
|
6339
6397
|
});
|
|
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
6398
|
if (previewEnabled) {
|
|
6355
6399
|
try {
|
|
6356
6400
|
const result = await packClient.fetch(query, {
|
|
@@ -6405,6 +6449,7 @@ function createPackClient(options) {
|
|
|
6405
6449
|
}
|
|
6406
6450
|
},
|
|
6407
6451
|
session,
|
|
6452
|
+
errorTracking,
|
|
6408
6453
|
testSession
|
|
6409
6454
|
};
|
|
6410
6455
|
}
|
|
@@ -6624,8 +6669,35 @@ var PackTestContext = createContext({});
|
|
|
6624
6669
|
var usePackTestContext = () => useContext(PackTestContext);
|
|
6625
6670
|
|
|
6626
6671
|
// src/tests/pack-test-route.ts
|
|
6627
|
-
|
|
6672
|
+
function getImpressionSectionSelectors(packTestInfo) {
|
|
6673
|
+
const sectionIds = packTestInfo.impression?.sectionIds || [];
|
|
6674
|
+
return [...new Set(sectionIds)].map(
|
|
6675
|
+
(sectionId) => `section[data-comp-id="${sectionId}"]`
|
|
6676
|
+
);
|
|
6677
|
+
}
|
|
6678
|
+
function getImpressionSelectors(packTestInfo, impressionSelector) {
|
|
6679
|
+
if (!impressionSelector) {
|
|
6680
|
+
return getImpressionSectionSelectors(packTestInfo);
|
|
6681
|
+
}
|
|
6682
|
+
const resolvedSelector = typeof impressionSelector === "function" ? impressionSelector(packTestInfo) : impressionSelector;
|
|
6683
|
+
if (!resolvedSelector) {
|
|
6684
|
+
return getImpressionSectionSelectors(packTestInfo);
|
|
6685
|
+
}
|
|
6686
|
+
return Array.isArray(resolvedSelector) ? resolvedSelector : [resolvedSelector];
|
|
6687
|
+
}
|
|
6688
|
+
function serializeExposedTestCookieValue(packTestInfo) {
|
|
6689
|
+
return JSON.stringify({
|
|
6690
|
+
id: packTestInfo.id,
|
|
6691
|
+
handle: packTestInfo.handle,
|
|
6692
|
+
testVariant: {
|
|
6693
|
+
id: packTestInfo.testVariant.id,
|
|
6694
|
+
handle: packTestInfo.testVariant.handle
|
|
6695
|
+
}
|
|
6696
|
+
});
|
|
6697
|
+
}
|
|
6698
|
+
var usePackLoaderData = (impressionSelector) => {
|
|
6628
6699
|
const [exposedTestInfo, setExposedTestInfo] = useState();
|
|
6700
|
+
const [triggeredExposure, setTriggeredExposure] = useState();
|
|
6629
6701
|
let packTestInfo;
|
|
6630
6702
|
let packIsPreviewMode;
|
|
6631
6703
|
let revalidator;
|
|
@@ -6649,61 +6721,216 @@ var usePackLoaderData = () => {
|
|
|
6649
6721
|
} = usePackTestContext();
|
|
6650
6722
|
const exposedTestCookieString = api.get("exposedTest");
|
|
6651
6723
|
useEffect2(() => {
|
|
6652
|
-
if (packTestInfo
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6724
|
+
if (packTestInfo?.id !== triggeredExposure?.packTestInfo.id) {
|
|
6725
|
+
setTriggeredExposure(void 0);
|
|
6726
|
+
return;
|
|
6727
|
+
}
|
|
6728
|
+
if (packTestInfo?.testVariant?.id !== triggeredExposure?.packTestInfo.testVariant.id) {
|
|
6729
|
+
setTriggeredExposure(void 0);
|
|
6730
|
+
}
|
|
6731
|
+
}, [triggeredExposure, packTestInfo]);
|
|
6732
|
+
useEffect2(() => {
|
|
6733
|
+
if (!packTestInfo || !!packIsPreviewMode || !!exposedTestCookieString || !!exposedTestInfo) {
|
|
6734
|
+
return;
|
|
6735
|
+
}
|
|
6736
|
+
if (triggeredExposure?.packTestInfo.id === packTestInfo.id && triggeredExposure.packTestInfo.testVariant.id === packTestInfo.testVariant.id) {
|
|
6737
|
+
return;
|
|
6738
|
+
}
|
|
6739
|
+
if (packTestInfo.impressionTrigger !== "ON_ELEMENT_VIEW" || typeof window === "undefined" || typeof IntersectionObserver === "undefined") {
|
|
6740
|
+
setTriggeredExposure({
|
|
6741
|
+
packTestInfo,
|
|
6742
|
+
exposureTime: Date.now()
|
|
6743
|
+
});
|
|
6744
|
+
return;
|
|
6745
|
+
}
|
|
6746
|
+
const impressionSectionSelectors = getImpressionSelectors(
|
|
6747
|
+
packTestInfo,
|
|
6748
|
+
impressionSelector
|
|
6749
|
+
);
|
|
6750
|
+
if (impressionSectionSelectors.length === 0) {
|
|
6751
|
+
console.warn(
|
|
6752
|
+
`[Pack Test] Test "${packTestInfo.id}" uses ON_ELEMENT_VIEW but has no selectors to observe. Impression will not be tracked.`
|
|
6753
|
+
);
|
|
6754
|
+
return;
|
|
6755
|
+
}
|
|
6756
|
+
let isTriggered = false;
|
|
6757
|
+
const observedElements = /* @__PURE__ */ new Set();
|
|
6758
|
+
let observer;
|
|
6759
|
+
let mutationObserver;
|
|
6760
|
+
let observerTimeoutId;
|
|
6761
|
+
const cleanup = () => {
|
|
6762
|
+
observer?.disconnect();
|
|
6763
|
+
mutationObserver?.disconnect();
|
|
6764
|
+
if (observerTimeoutId) {
|
|
6765
|
+
clearTimeout(observerTimeoutId);
|
|
6766
|
+
}
|
|
6767
|
+
};
|
|
6768
|
+
const triggerImpression = () => {
|
|
6769
|
+
if (isTriggered) return;
|
|
6770
|
+
isTriggered = true;
|
|
6771
|
+
cleanup();
|
|
6772
|
+
setTriggeredExposure({
|
|
6773
|
+
packTestInfo,
|
|
6774
|
+
exposureTime: Date.now()
|
|
6775
|
+
});
|
|
6776
|
+
};
|
|
6777
|
+
const observeMatchingElements = () => {
|
|
6778
|
+
if (!observer || isTriggered) return;
|
|
6779
|
+
impressionSectionSelectors.forEach((selector) => {
|
|
6780
|
+
document.querySelectorAll(selector).forEach((element) => {
|
|
6781
|
+
if (observedElements.has(element)) return;
|
|
6782
|
+
observedElements.add(element);
|
|
6783
|
+
observer?.observe(element);
|
|
6658
6784
|
});
|
|
6659
|
-
return newQueue;
|
|
6660
6785
|
});
|
|
6786
|
+
if (observedElements.size > 0) {
|
|
6787
|
+
mutationObserver?.disconnect();
|
|
6788
|
+
mutationObserver = void 0;
|
|
6789
|
+
if (observerTimeoutId) {
|
|
6790
|
+
clearTimeout(observerTimeoutId);
|
|
6791
|
+
observerTimeoutId = void 0;
|
|
6792
|
+
}
|
|
6793
|
+
}
|
|
6794
|
+
};
|
|
6795
|
+
observer = new IntersectionObserver(
|
|
6796
|
+
(entries) => {
|
|
6797
|
+
if (entries.some((entry) => entry.isIntersecting)) {
|
|
6798
|
+
triggerImpression();
|
|
6799
|
+
}
|
|
6800
|
+
},
|
|
6801
|
+
{ threshold: 0.1 }
|
|
6802
|
+
);
|
|
6803
|
+
observeMatchingElements();
|
|
6804
|
+
if (!isTriggered && observedElements.size === 0 && typeof MutationObserver !== "undefined") {
|
|
6805
|
+
mutationObserver = new MutationObserver(() => {
|
|
6806
|
+
observeMatchingElements();
|
|
6807
|
+
});
|
|
6808
|
+
mutationObserver.observe(document.body, {
|
|
6809
|
+
childList: true,
|
|
6810
|
+
subtree: true
|
|
6811
|
+
});
|
|
6812
|
+
observerTimeoutId = setTimeout(() => {
|
|
6813
|
+
if (!isTriggered && observedElements.size === 0) {
|
|
6814
|
+
console.warn(
|
|
6815
|
+
`[Pack Test] Impression target not found within 30s for test "${packTestInfo.id}". Stopping observer.`
|
|
6816
|
+
);
|
|
6817
|
+
cleanup();
|
|
6818
|
+
}
|
|
6819
|
+
}, 3e4);
|
|
6661
6820
|
}
|
|
6821
|
+
return cleanup;
|
|
6662
6822
|
}, [
|
|
6663
|
-
|
|
6823
|
+
triggeredExposure,
|
|
6824
|
+
exposedTestCookieString,
|
|
6825
|
+
exposedTestInfo,
|
|
6826
|
+
packIsPreviewMode,
|
|
6664
6827
|
packTestInfo,
|
|
6828
|
+
impressionSelector
|
|
6829
|
+
]);
|
|
6830
|
+
useEffect2(() => {
|
|
6831
|
+
if (triggeredExposure && !packIsPreviewMode && !hasUserConsent2 && !exposedTestCookieString) {
|
|
6832
|
+
setPendingExposureQueue?.((prev) => {
|
|
6833
|
+
if (prev.has(triggeredExposure.packTestInfo.id)) return prev;
|
|
6834
|
+
const nextQueue = new Map(prev);
|
|
6835
|
+
nextQueue.set(triggeredExposure.packTestInfo.id, triggeredExposure);
|
|
6836
|
+
return nextQueue;
|
|
6837
|
+
});
|
|
6838
|
+
}
|
|
6839
|
+
}, [
|
|
6840
|
+
triggeredExposure,
|
|
6841
|
+
hasUserConsent2,
|
|
6665
6842
|
packIsPreviewMode,
|
|
6666
6843
|
exposedTestCookieString,
|
|
6667
|
-
|
|
6844
|
+
setPendingExposureQueue
|
|
6668
6845
|
]);
|
|
6669
6846
|
useEffect2(() => {
|
|
6670
|
-
if (
|
|
6847
|
+
if (triggeredExposure && hasUserConsent2 && !exposedTestCookieString && !packIsPreviewMode && !exposedTestInfo) {
|
|
6848
|
+
const { packTestInfo: activeTestInfo, exposureTime } = triggeredExposure;
|
|
6671
6849
|
const expires = /* @__PURE__ */ new Date();
|
|
6672
6850
|
expires.setHours(expires.getHours() + 24);
|
|
6673
|
-
api.set(
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6851
|
+
api.set(
|
|
6852
|
+
"exposedTest",
|
|
6853
|
+
serializeExposedTestCookieValue(activeTestInfo),
|
|
6854
|
+
{
|
|
6855
|
+
expires
|
|
6856
|
+
}
|
|
6857
|
+
);
|
|
6858
|
+
setExposedTestInfo(activeTestInfo);
|
|
6677
6859
|
pendingExposureQueue?.forEach((data, key) => {
|
|
6860
|
+
if (key === activeTestInfo.id) return;
|
|
6678
6861
|
try {
|
|
6679
6862
|
testExposureCallback?.({
|
|
6680
6863
|
...data.packTestInfo,
|
|
6681
6864
|
exposureTime: data.exposureTime
|
|
6682
6865
|
});
|
|
6683
|
-
setPendingExposureQueue?.((prev) => {
|
|
6684
|
-
const newQueue = new Map(prev);
|
|
6685
|
-
newQueue.delete(key);
|
|
6686
|
-
return newQueue;
|
|
6687
|
-
});
|
|
6688
6866
|
} catch (error) {
|
|
6689
6867
|
console.error("Failed to call testExposure after consent:", error);
|
|
6690
6868
|
}
|
|
6691
6869
|
});
|
|
6692
|
-
testExposureCallback?.({ ...
|
|
6870
|
+
testExposureCallback?.({ ...activeTestInfo, exposureTime });
|
|
6871
|
+
setPendingExposureQueue?.(/* @__PURE__ */ new Map());
|
|
6693
6872
|
setTimeout(() => {
|
|
6694
6873
|
revalidator?.revalidate();
|
|
6695
6874
|
}, 750);
|
|
6696
6875
|
}
|
|
6697
6876
|
}, [
|
|
6698
|
-
|
|
6877
|
+
triggeredExposure,
|
|
6878
|
+
exposedTestCookieString,
|
|
6879
|
+
pendingExposureQueue,
|
|
6699
6880
|
testExposureCallback,
|
|
6700
6881
|
exposedTestInfo,
|
|
6701
6882
|
hasUserConsent2,
|
|
6702
|
-
packIsPreviewMode
|
|
6883
|
+
packIsPreviewMode,
|
|
6884
|
+
setPendingExposureQueue
|
|
6885
|
+
]);
|
|
6886
|
+
useEffect2(() => {
|
|
6887
|
+
if (!!triggeredExposure || !hasUserConsent2 || !!packIsPreviewMode || !pendingExposureQueue?.size || !!exposedTestCookieString) {
|
|
6888
|
+
return;
|
|
6889
|
+
}
|
|
6890
|
+
let firstQueuedTest;
|
|
6891
|
+
pendingExposureQueue.forEach((data) => {
|
|
6892
|
+
if (!firstQueuedTest) {
|
|
6893
|
+
firstQueuedTest = data.packTestInfo;
|
|
6894
|
+
}
|
|
6895
|
+
try {
|
|
6896
|
+
testExposureCallback?.({
|
|
6897
|
+
...data.packTestInfo,
|
|
6898
|
+
exposureTime: data.exposureTime
|
|
6899
|
+
});
|
|
6900
|
+
} catch (error) {
|
|
6901
|
+
console.error(
|
|
6902
|
+
"Failed to call queued testExposure after consent:",
|
|
6903
|
+
error
|
|
6904
|
+
);
|
|
6905
|
+
}
|
|
6906
|
+
});
|
|
6907
|
+
if (firstQueuedTest) {
|
|
6908
|
+
const expires = /* @__PURE__ */ new Date();
|
|
6909
|
+
expires.setHours(expires.getHours() + 24);
|
|
6910
|
+
api.set(
|
|
6911
|
+
"exposedTest",
|
|
6912
|
+
serializeExposedTestCookieValue(firstQueuedTest),
|
|
6913
|
+
{
|
|
6914
|
+
expires
|
|
6915
|
+
}
|
|
6916
|
+
);
|
|
6917
|
+
setExposedTestInfo(firstQueuedTest);
|
|
6918
|
+
}
|
|
6919
|
+
setPendingExposureQueue?.(/* @__PURE__ */ new Map());
|
|
6920
|
+
}, [
|
|
6921
|
+
triggeredExposure,
|
|
6922
|
+
exposedTestCookieString,
|
|
6923
|
+
hasUserConsent2,
|
|
6924
|
+
packIsPreviewMode,
|
|
6925
|
+
pendingExposureQueue,
|
|
6926
|
+
setPendingExposureQueue,
|
|
6927
|
+
testExposureCallback
|
|
6703
6928
|
]);
|
|
6704
6929
|
};
|
|
6705
|
-
var PackTestRoute = (
|
|
6706
|
-
|
|
6930
|
+
var PackTestRoute = ({
|
|
6931
|
+
impressionSelector
|
|
6932
|
+
} = {}) => {
|
|
6933
|
+
usePackLoaderData(impressionSelector);
|
|
6707
6934
|
return null;
|
|
6708
6935
|
};
|
|
6709
6936
|
|