@pack/hydrogen 3.2.8 → 3.3.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/dist/index.js CHANGED
@@ -32,6 +32,172 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
32
32
  ));
33
33
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
34
34
 
35
+ // node_modules/cookie/index.js
36
+ var require_cookie = __commonJS({
37
+ "node_modules/cookie/index.js"(exports) {
38
+ "use strict";
39
+ exports.parse = parse3;
40
+ exports.serialize = serialize3;
41
+ var __toString = Object.prototype.toString;
42
+ var __hasOwnProperty = Object.prototype.hasOwnProperty;
43
+ var cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
44
+ var cookieValueRegExp = /^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/;
45
+ var domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;
46
+ var pathValueRegExp = /^[\u0020-\u003A\u003D-\u007E]*$/;
47
+ function parse3(str, opt) {
48
+ if (typeof str !== "string") {
49
+ throw new TypeError("argument str must be a string");
50
+ }
51
+ var obj = {};
52
+ var len = str.length;
53
+ if (len < 2) return obj;
54
+ var dec = opt && opt.decode || decode;
55
+ var index = 0;
56
+ var eqIdx = 0;
57
+ var endIdx = 0;
58
+ do {
59
+ eqIdx = str.indexOf("=", index);
60
+ if (eqIdx === -1) break;
61
+ endIdx = str.indexOf(";", index);
62
+ if (endIdx === -1) {
63
+ endIdx = len;
64
+ } else if (eqIdx > endIdx) {
65
+ index = str.lastIndexOf(";", eqIdx - 1) + 1;
66
+ continue;
67
+ }
68
+ var keyStartIdx = startIndex(str, index, eqIdx);
69
+ var keyEndIdx = endIndex(str, eqIdx, keyStartIdx);
70
+ var key = str.slice(keyStartIdx, keyEndIdx);
71
+ if (!__hasOwnProperty.call(obj, key)) {
72
+ var valStartIdx = startIndex(str, eqIdx + 1, endIdx);
73
+ var valEndIdx = endIndex(str, endIdx, valStartIdx);
74
+ if (str.charCodeAt(valStartIdx) === 34 && str.charCodeAt(valEndIdx - 1) === 34) {
75
+ valStartIdx++;
76
+ valEndIdx--;
77
+ }
78
+ var val = str.slice(valStartIdx, valEndIdx);
79
+ obj[key] = tryDecode(val, dec);
80
+ }
81
+ index = endIdx + 1;
82
+ } while (index < len);
83
+ return obj;
84
+ }
85
+ function startIndex(str, index, max) {
86
+ do {
87
+ var code = str.charCodeAt(index);
88
+ if (code !== 32 && code !== 9) return index;
89
+ } while (++index < max);
90
+ return max;
91
+ }
92
+ function endIndex(str, index, min) {
93
+ while (index > min) {
94
+ var code = str.charCodeAt(--index);
95
+ if (code !== 32 && code !== 9) return index + 1;
96
+ }
97
+ return min;
98
+ }
99
+ function serialize3(name, val, opt) {
100
+ var enc = opt && opt.encode || encodeURIComponent;
101
+ if (typeof enc !== "function") {
102
+ throw new TypeError("option encode is invalid");
103
+ }
104
+ if (!cookieNameRegExp.test(name)) {
105
+ throw new TypeError("argument name is invalid");
106
+ }
107
+ var value = enc(val);
108
+ if (!cookieValueRegExp.test(value)) {
109
+ throw new TypeError("argument val is invalid");
110
+ }
111
+ var str = name + "=" + value;
112
+ if (!opt) return str;
113
+ if (null != opt.maxAge) {
114
+ var maxAge = Math.floor(opt.maxAge);
115
+ if (!isFinite(maxAge)) {
116
+ throw new TypeError("option maxAge is invalid");
117
+ }
118
+ str += "; Max-Age=" + maxAge;
119
+ }
120
+ if (opt.domain) {
121
+ if (!domainValueRegExp.test(opt.domain)) {
122
+ throw new TypeError("option domain is invalid");
123
+ }
124
+ str += "; Domain=" + opt.domain;
125
+ }
126
+ if (opt.path) {
127
+ if (!pathValueRegExp.test(opt.path)) {
128
+ throw new TypeError("option path is invalid");
129
+ }
130
+ str += "; Path=" + opt.path;
131
+ }
132
+ if (opt.expires) {
133
+ var expires = opt.expires;
134
+ if (!isDate(expires) || isNaN(expires.valueOf())) {
135
+ throw new TypeError("option expires is invalid");
136
+ }
137
+ str += "; Expires=" + expires.toUTCString();
138
+ }
139
+ if (opt.httpOnly) {
140
+ str += "; HttpOnly";
141
+ }
142
+ if (opt.secure) {
143
+ str += "; Secure";
144
+ }
145
+ if (opt.partitioned) {
146
+ str += "; Partitioned";
147
+ }
148
+ if (opt.priority) {
149
+ var priority = typeof opt.priority === "string" ? opt.priority.toLowerCase() : opt.priority;
150
+ switch (priority) {
151
+ case "low":
152
+ str += "; Priority=Low";
153
+ break;
154
+ case "medium":
155
+ str += "; Priority=Medium";
156
+ break;
157
+ case "high":
158
+ str += "; Priority=High";
159
+ break;
160
+ default:
161
+ throw new TypeError("option priority is invalid");
162
+ }
163
+ }
164
+ if (opt.sameSite) {
165
+ var sameSite = typeof opt.sameSite === "string" ? opt.sameSite.toLowerCase() : opt.sameSite;
166
+ switch (sameSite) {
167
+ case true:
168
+ str += "; SameSite=Strict";
169
+ break;
170
+ case "lax":
171
+ str += "; SameSite=Lax";
172
+ break;
173
+ case "strict":
174
+ str += "; SameSite=Strict";
175
+ break;
176
+ case "none":
177
+ str += "; SameSite=None";
178
+ break;
179
+ default:
180
+ throw new TypeError("option sameSite is invalid");
181
+ }
182
+ }
183
+ return str;
184
+ }
185
+ function decode(str) {
186
+ return str.indexOf("%") !== -1 ? decodeURIComponent(str) : str;
187
+ }
188
+ function isDate(val) {
189
+ return __toString.call(val) === "[object Date]";
190
+ }
191
+ function tryDecode(str, decode2) {
192
+ try {
193
+ return decode2(str);
194
+ } catch (e) {
195
+ return str;
196
+ }
197
+ }
198
+ }
199
+ });
200
+
35
201
  // ../../node_modules/ua-parser-js/src/ua-parser.js
36
202
  var require_ua_parser = __commonJS({
37
203
  "../../node_modules/ua-parser-js/src/ua-parser.js"(exports, module) {
@@ -1283,203 +1449,37 @@ var require_ua_parser = __commonJS({
1283
1449
  UAParser.BROWSER = enumerize([NAME, VERSION, MAJOR]);
1284
1450
  UAParser.CPU = enumerize([ARCHITECTURE]);
1285
1451
  UAParser.DEVICE = enumerize([MODEL, VENDOR, TYPE, CONSOLE, MOBILE, SMARTTV, TABLET, WEARABLE, EMBEDDED]);
1286
- UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]);
1287
- if (typeof exports !== UNDEF_TYPE) {
1288
- if (typeof module !== UNDEF_TYPE && module.exports) {
1289
- exports = module.exports = UAParser;
1290
- }
1291
- exports.UAParser = UAParser;
1292
- } else {
1293
- if (typeof define === FUNC_TYPE && define.amd) {
1294
- define(function() {
1295
- return UAParser;
1296
- });
1297
- } else if (typeof window2 !== UNDEF_TYPE) {
1298
- window2.UAParser = UAParser;
1299
- }
1300
- }
1301
- var $ = typeof window2 !== UNDEF_TYPE && (window2.jQuery || window2.Zepto);
1302
- if ($ && !$.ua) {
1303
- var parser2 = new UAParser();
1304
- $.ua = parser2.getResult();
1305
- $.ua.get = function() {
1306
- return parser2.getUA();
1307
- };
1308
- $.ua.set = function(ua) {
1309
- parser2.setUA(ua);
1310
- var result = parser2.getResult();
1311
- for (var prop in result) {
1312
- $.ua[prop] = result[prop];
1313
- }
1314
- };
1315
- }
1316
- })(typeof window === "object" ? window : exports);
1317
- }
1318
- });
1319
-
1320
- // node_modules/cookie/index.js
1321
- var require_cookie = __commonJS({
1322
- "node_modules/cookie/index.js"(exports) {
1323
- "use strict";
1324
- exports.parse = parse2;
1325
- exports.serialize = serialize3;
1326
- var __toString = Object.prototype.toString;
1327
- var __hasOwnProperty = Object.prototype.hasOwnProperty;
1328
- var cookieNameRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
1329
- var cookieValueRegExp = /^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/;
1330
- var domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;
1331
- var pathValueRegExp = /^[\u0020-\u003A\u003D-\u007E]*$/;
1332
- function parse2(str, opt) {
1333
- if (typeof str !== "string") {
1334
- throw new TypeError("argument str must be a string");
1335
- }
1336
- var obj = {};
1337
- var len = str.length;
1338
- if (len < 2) return obj;
1339
- var dec = opt && opt.decode || decode;
1340
- var index = 0;
1341
- var eqIdx = 0;
1342
- var endIdx = 0;
1343
- do {
1344
- eqIdx = str.indexOf("=", index);
1345
- if (eqIdx === -1) break;
1346
- endIdx = str.indexOf(";", index);
1347
- if (endIdx === -1) {
1348
- endIdx = len;
1349
- } else if (eqIdx > endIdx) {
1350
- index = str.lastIndexOf(";", eqIdx - 1) + 1;
1351
- continue;
1352
- }
1353
- var keyStartIdx = startIndex(str, index, eqIdx);
1354
- var keyEndIdx = endIndex(str, eqIdx, keyStartIdx);
1355
- var key = str.slice(keyStartIdx, keyEndIdx);
1356
- if (!__hasOwnProperty.call(obj, key)) {
1357
- var valStartIdx = startIndex(str, eqIdx + 1, endIdx);
1358
- var valEndIdx = endIndex(str, endIdx, valStartIdx);
1359
- if (str.charCodeAt(valStartIdx) === 34 && str.charCodeAt(valEndIdx - 1) === 34) {
1360
- valStartIdx++;
1361
- valEndIdx--;
1362
- }
1363
- var val = str.slice(valStartIdx, valEndIdx);
1364
- obj[key] = tryDecode(val, dec);
1365
- }
1366
- index = endIdx + 1;
1367
- } while (index < len);
1368
- return obj;
1369
- }
1370
- function startIndex(str, index, max) {
1371
- do {
1372
- var code = str.charCodeAt(index);
1373
- if (code !== 32 && code !== 9) return index;
1374
- } while (++index < max);
1375
- return max;
1376
- }
1377
- function endIndex(str, index, min) {
1378
- while (index > min) {
1379
- var code = str.charCodeAt(--index);
1380
- if (code !== 32 && code !== 9) return index + 1;
1381
- }
1382
- return min;
1383
- }
1384
- function serialize3(name, val, opt) {
1385
- var enc = opt && opt.encode || encodeURIComponent;
1386
- if (typeof enc !== "function") {
1387
- throw new TypeError("option encode is invalid");
1388
- }
1389
- if (!cookieNameRegExp.test(name)) {
1390
- throw new TypeError("argument name is invalid");
1391
- }
1392
- var value = enc(val);
1393
- if (!cookieValueRegExp.test(value)) {
1394
- throw new TypeError("argument val is invalid");
1395
- }
1396
- var str = name + "=" + value;
1397
- if (!opt) return str;
1398
- if (null != opt.maxAge) {
1399
- var maxAge = Math.floor(opt.maxAge);
1400
- if (!isFinite(maxAge)) {
1401
- throw new TypeError("option maxAge is invalid");
1402
- }
1403
- str += "; Max-Age=" + maxAge;
1404
- }
1405
- if (opt.domain) {
1406
- if (!domainValueRegExp.test(opt.domain)) {
1407
- throw new TypeError("option domain is invalid");
1408
- }
1409
- str += "; Domain=" + opt.domain;
1410
- }
1411
- if (opt.path) {
1412
- if (!pathValueRegExp.test(opt.path)) {
1413
- throw new TypeError("option path is invalid");
1414
- }
1415
- str += "; Path=" + opt.path;
1416
- }
1417
- if (opt.expires) {
1418
- var expires = opt.expires;
1419
- if (!isDate(expires) || isNaN(expires.valueOf())) {
1420
- throw new TypeError("option expires is invalid");
1421
- }
1422
- str += "; Expires=" + expires.toUTCString();
1423
- }
1424
- if (opt.httpOnly) {
1425
- str += "; HttpOnly";
1426
- }
1427
- if (opt.secure) {
1428
- str += "; Secure";
1429
- }
1430
- if (opt.partitioned) {
1431
- str += "; Partitioned";
1432
- }
1433
- if (opt.priority) {
1434
- var priority = typeof opt.priority === "string" ? opt.priority.toLowerCase() : opt.priority;
1435
- switch (priority) {
1436
- case "low":
1437
- str += "; Priority=Low";
1438
- break;
1439
- case "medium":
1440
- str += "; Priority=Medium";
1441
- break;
1442
- case "high":
1443
- str += "; Priority=High";
1444
- break;
1445
- default:
1446
- throw new TypeError("option priority is invalid");
1452
+ UAParser.ENGINE = UAParser.OS = enumerize([NAME, VERSION]);
1453
+ if (typeof exports !== UNDEF_TYPE) {
1454
+ if (typeof module !== UNDEF_TYPE && module.exports) {
1455
+ exports = module.exports = UAParser;
1447
1456
  }
1448
- }
1449
- if (opt.sameSite) {
1450
- var sameSite = typeof opt.sameSite === "string" ? opt.sameSite.toLowerCase() : opt.sameSite;
1451
- switch (sameSite) {
1452
- case true:
1453
- str += "; SameSite=Strict";
1454
- break;
1455
- case "lax":
1456
- str += "; SameSite=Lax";
1457
- break;
1458
- case "strict":
1459
- str += "; SameSite=Strict";
1460
- break;
1461
- case "none":
1462
- str += "; SameSite=None";
1463
- break;
1464
- default:
1465
- throw new TypeError("option sameSite is invalid");
1457
+ exports.UAParser = UAParser;
1458
+ } else {
1459
+ if (typeof define === FUNC_TYPE && define.amd) {
1460
+ define(function() {
1461
+ return UAParser;
1462
+ });
1463
+ } else if (typeof window2 !== UNDEF_TYPE) {
1464
+ window2.UAParser = UAParser;
1466
1465
  }
1467
1466
  }
1468
- return str;
1469
- }
1470
- function decode(str) {
1471
- return str.indexOf("%") !== -1 ? decodeURIComponent(str) : str;
1472
- }
1473
- function isDate(val) {
1474
- return __toString.call(val) === "[object Date]";
1475
- }
1476
- function tryDecode(str, decode2) {
1477
- try {
1478
- return decode2(str);
1479
- } catch (e) {
1480
- return str;
1467
+ var $ = typeof window2 !== UNDEF_TYPE && (window2.jQuery || window2.Zepto);
1468
+ if ($ && !$.ua) {
1469
+ var parser2 = new UAParser();
1470
+ $.ua = parser2.getResult();
1471
+ $.ua.get = function() {
1472
+ return parser2.getUA();
1473
+ };
1474
+ $.ua.set = function(ua) {
1475
+ parser2.setUA(ua);
1476
+ var result = parser2.getResult();
1477
+ for (var prop in result) {
1478
+ $.ua[prop] = result[prop];
1479
+ }
1480
+ };
1481
1481
  }
1482
- }
1482
+ })(typeof window === "object" ? window : exports);
1483
1483
  }
1484
1484
  });
1485
1485
 
@@ -1497,7 +1497,7 @@ var require_ms = __commonJS({
1497
1497
  options = options || {};
1498
1498
  var type = typeof val;
1499
1499
  if (type === "string" && val.length > 0) {
1500
- return parse2(val);
1500
+ return parse3(val);
1501
1501
  } else if (type === "number" && isFinite(val)) {
1502
1502
  return options.long ? fmtLong(val) : fmtShort(val);
1503
1503
  }
@@ -1505,7 +1505,7 @@ var require_ms = __commonJS({
1505
1505
  "val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
1506
1506
  );
1507
1507
  };
1508
- function parse2(str) {
1508
+ function parse3(str) {
1509
1509
  str = String(str);
1510
1510
  if (str.length > 100) {
1511
1511
  return;
@@ -4356,6 +4356,9 @@ var require_dist = __commonJS({
4356
4356
  }
4357
4357
  });
4358
4358
 
4359
+ // src/handle-request.ts
4360
+ var import_cookie2 = __toESM(require_cookie(), 1);
4361
+
4359
4362
  // ../packlytics/dist/utils/get-packlytics-id.js
4360
4363
  function sha256(ascii) {
4361
4364
  function rightRotate(value, amount) {
@@ -4667,64 +4670,23 @@ async function packlytics(pack, request, next) {
4667
4670
  return next();
4668
4671
  }
4669
4672
 
4670
- // src/handle-request.ts
4671
- async function handleRequest(pack, request, handleRequest2) {
4672
- const packHandleResponse = await pack.handleRequest(request);
4673
- let response;
4674
- response = await packlytics(pack, request, () => {
4675
- return handleRequest2(request);
4676
- });
4677
- packHandleResponse(response);
4678
- response.headers.append("powered-by", "Shopify, Hydrogen + Pack Digital");
4679
- response.headers.append("Set-Cookie", await pack.session.commit());
4680
- if (pack.testSession && pack.testSession.hasChanges()) {
4681
- response.headers.append("Set-Cookie", await pack.testSession.commit());
4682
- }
4683
- return response;
4684
- }
4685
-
4686
- // src/session/usePackCookies.ts
4687
- var import_cookie = __toESM(require_cookie(), 1);
4688
- import { useEffect } from "react";
4689
-
4690
4673
  // src/constants.ts
4691
4674
  var PACK_COOKIE_ID = "__pack";
4692
4675
  var PACK_USER_CONSENT_COOKIE_ID = "__pack_user_consent";
4693
4676
  var PACK_TEST_COOKIE_ID = "__pack_test";
4694
4677
  var PACK_COOKIE_MAX_AGE = 60 * 60 * 24 * 360;
4695
-
4696
- // src/session/usePackCookies.ts
4697
- function usePackCookies(options) {
4698
- const { hasUserConsent: hasUserConsent2 = true, domain = "" } = options || {};
4699
- useEffect(() => {
4700
- setCookie(
4701
- PACK_USER_CONSENT_COOKIE_ID,
4702
- hasUserConsent2 ? "true" : "false",
4703
- PACK_COOKIE_MAX_AGE,
4704
- domain
4705
- );
4706
- }, [hasUserConsent2]);
4707
- }
4708
- function setCookie(name, value, maxage, domain) {
4709
- document.cookie = (0, import_cookie.serialize)(name, value, {
4710
- maxAge: maxage,
4711
- domain,
4712
- sameSite: "lax",
4713
- path: "/"
4714
- });
4715
- }
4716
-
4717
- // src/session/session.ts
4718
- import {
4719
- createCookie,
4720
- createCookieSessionStorage
4721
- } from "react-router";
4678
+ var PACK_SESSION_COOKIE_ID = "__pack_s";
4679
+ var PACK_SESSION_MAX_AGE = 30 * 60;
4722
4680
 
4723
4681
  // src/session/cookies-utils.tsx
4724
- var import_cookie2 = __toESM(require_cookie(), 1);
4682
+ var import_cookie = __toESM(require_cookie(), 1);
4725
4683
  var tokenHash = "xxxx-4xxx-xxxx-xxxxxxxxxxxx";
4684
+ function isSafari(userAgent) {
4685
+ if (!userAgent) return false;
4686
+ return /Safari\//.test(userAgent) && !/Chrome\//.test(userAgent) && !/Chromium\//.test(userAgent) && !/Edg\//.test(userAgent) && !/Firefox\//.test(userAgent);
4687
+ }
4726
4688
  function hasUserConsent(request) {
4727
- const cookies = import_cookie2.default.parse(request.headers.get("Cookie"));
4689
+ const cookies = import_cookie.default.parse(request.headers.get("Cookie") || "");
4728
4690
  return cookies[PACK_USER_CONSENT_COOKIE_ID] ? cookies[PACK_USER_CONSENT_COOKIE_ID] === "true" : true;
4729
4691
  }
4730
4692
  function buildRandomUUID() {
@@ -4762,11 +4724,72 @@ function hexTime() {
4762
4724
  return output?.substring(0, 8).padStart(8, "0");
4763
4725
  }
4764
4726
 
4765
- // src/session/session.ts
4766
- function isSafari(userAgent) {
4767
- if (!userAgent) return false;
4768
- return /Safari\//.test(userAgent) && !/Chrome\//.test(userAgent) && !/Chromium\//.test(userAgent) && !/Edg\//.test(userAgent) && !/Firefox\//.test(userAgent);
4727
+ // src/audiences/visitor-recency.ts
4728
+ var PRIOR_VISIT_COOKIES = [
4729
+ PACK_COOKIE_ID,
4730
+ PACK_TEST_COOKIE_ID,
4731
+ "_ga",
4732
+ "_shopify_y"
4733
+ ];
4734
+ function sessionVerdict(incoming) {
4735
+ const stored = incoming[PACK_SESSION_COOKIE_ID];
4736
+ if (stored === "r" || stored === "n") return stored;
4737
+ return PRIOR_VISIT_COOKIES.some((name) => incoming[name]) ? "r" : "n";
4738
+ }
4739
+ function sessionMarkerSetCookie(verdict, omitSecure) {
4740
+ return `${PACK_SESSION_COOKIE_ID}=${verdict}; Path=/; Max-Age=${PACK_SESSION_MAX_AGE}; SameSite=None${omitSecure ? "" : "; Secure"}`;
4741
+ }
4742
+
4743
+ // src/handle-request.ts
4744
+ async function handleRequest(pack, request, handleRequest2) {
4745
+ const packHandleResponse = await pack.handleRequest(request);
4746
+ let response;
4747
+ response = await packlytics(pack, request, () => {
4748
+ return handleRequest2(request);
4749
+ });
4750
+ packHandleResponse(response);
4751
+ response.headers.append("powered-by", "Shopify, Hydrogen + Pack Digital");
4752
+ response.headers.append("Set-Cookie", await pack.session.commit());
4753
+ const incoming = import_cookie2.default.parse(request.headers.get("Cookie") || "");
4754
+ const omitSecure = isSafari(request.headers.get("User-Agent")) && process.env.NODE_ENV === "development";
4755
+ response.headers.append(
4756
+ "Set-Cookie",
4757
+ sessionMarkerSetCookie(sessionVerdict(incoming), omitSecure)
4758
+ );
4759
+ if (pack.testSession && pack.testSession.hasChanges()) {
4760
+ response.headers.append("Set-Cookie", await pack.testSession.commit());
4761
+ }
4762
+ return response;
4763
+ }
4764
+
4765
+ // src/session/usePackCookies.ts
4766
+ var import_cookie3 = __toESM(require_cookie(), 1);
4767
+ import { useEffect } from "react";
4768
+ function usePackCookies(options) {
4769
+ const { hasUserConsent: hasUserConsent2 = true, domain = "" } = options || {};
4770
+ useEffect(() => {
4771
+ setCookie(
4772
+ PACK_USER_CONSENT_COOKIE_ID,
4773
+ hasUserConsent2 ? "true" : "false",
4774
+ PACK_COOKIE_MAX_AGE,
4775
+ domain
4776
+ );
4777
+ }, [hasUserConsent2]);
4778
+ }
4779
+ function setCookie(name, value, maxage, domain) {
4780
+ document.cookie = (0, import_cookie3.serialize)(name, value, {
4781
+ maxAge: maxage,
4782
+ domain,
4783
+ sameSite: "lax",
4784
+ path: "/"
4785
+ });
4769
4786
  }
4787
+
4788
+ // src/session/session.ts
4789
+ import {
4790
+ createCookie,
4791
+ createCookieSessionStorage
4792
+ } from "react-router";
4770
4793
  var PackSession = class {
4771
4794
  id;
4772
4795
  secret;
@@ -4823,10 +4846,6 @@ import {
4823
4846
  } from "react-router";
4824
4847
  var import_debug = __toESM(require_browser(), 1);
4825
4848
  var debug = (0, import_debug.default)("pack:ab-testing:test-session");
4826
- function isSafari2(userAgent) {
4827
- if (!userAgent) return false;
4828
- return /Safari\//.test(userAgent) && !/Chrome\//.test(userAgent) && !/Chromium\//.test(userAgent) && !/Edg\//.test(userAgent) && !/Firefox\//.test(userAgent);
4829
- }
4830
4849
  var PackTestSession = class {
4831
4850
  id;
4832
4851
  #session;
@@ -4852,7 +4871,7 @@ var PackTestSession = class {
4852
4871
  });
4853
4872
  const storage = createCookieSessionStorage2({
4854
4873
  cookie: createCookie2(PACK_TEST_COOKIE_ID, {
4855
- secure: isSafari2(userAgent) && process.env.NODE_ENV === "development" ? false : true,
4874
+ secure: isSafari(userAgent) && process.env.NODE_ENV === "development" ? false : true,
4856
4875
  secrets,
4857
4876
  sameSite: "lax",
4858
4877
  maxAge: PACK_COOKIE_MAX_AGE,
@@ -5017,12 +5036,12 @@ var PackTestSession = class {
5017
5036
  };
5018
5037
 
5019
5038
  // src/create-pack-client.ts
5020
- var cookie3 = __toESM(require_cookie(), 1);
5039
+ var cookie5 = __toESM(require_cookie(), 1);
5021
5040
  import { PackClient } from "@pack/client";
5022
5041
  import { CacheCustom, createWithCache } from "@shopify/hydrogen";
5023
5042
 
5024
5043
  // src/tests/test.ts
5025
- var cookie2 = __toESM(require_cookie(), 1);
5044
+ var cookie4 = __toESM(require_cookie(), 1);
5026
5045
 
5027
5046
  // src/tests/local-test-resolver.ts
5028
5047
  var import_json_rules_engine = __toESM(require_dist(), 1);
@@ -5045,6 +5064,364 @@ function getImpressionSectionIdsForVariant(test, testVariant) {
5045
5064
  return [...new Set(fallbackSectionIds)];
5046
5065
  }
5047
5066
 
5067
+ // src/audiences/identity-bundle.ts
5068
+ var cookie3 = __toESM(require_cookie(), 1);
5069
+ function detectDeviceType(userAgent) {
5070
+ const ua = userAgent.toLowerCase();
5071
+ if (/ipad|tablet|(android(?!.*mobile))/.test(ua)) return "tablet";
5072
+ if (/mobi|iphone|android|ipod|phone/.test(ua)) return "mobile";
5073
+ return "desktop";
5074
+ }
5075
+ function extractGa4ClientId(cookies) {
5076
+ const ga = cookies["_ga"];
5077
+ if (!ga) return void 0;
5078
+ const parts = ga.split(".");
5079
+ return parts.length >= 4 ? parts.slice(-2).join(".") : void 0;
5080
+ }
5081
+ function firstHeader(request, ...names) {
5082
+ for (const name of names) {
5083
+ const value = request.headers.get(name);
5084
+ if (value) return value;
5085
+ }
5086
+ return void 0;
5087
+ }
5088
+ function buildIdentityBundle(request, options = {}) {
5089
+ const parsedCookies = cookie3.parse(request.headers.get("cookie") || "");
5090
+ const cookies = {};
5091
+ for (const [name, value] of Object.entries(parsedCookies)) {
5092
+ if (typeof value === "string") cookies[name] = value;
5093
+ }
5094
+ const userAgent = request.headers.get("user-agent") || void 0;
5095
+ const consentCookie = cookies[PACK_USER_CONSENT_COOKIE_ID];
5096
+ const hasConsent = consentCookie ? consentCookie === "true" : true;
5097
+ const requestUrl = new URL(request.url);
5098
+ const query = {};
5099
+ requestUrl.searchParams.forEach((value, key) => {
5100
+ query[key] = value;
5101
+ });
5102
+ return {
5103
+ shopifyCustomerId: options.shopifyCustomerId,
5104
+ // Only GA4 is populated today; other provider ids are filled in by the
5105
+ // condition tasks that own them (see the type declaration).
5106
+ ga4ClientId: extractGa4ClientId(cookies),
5107
+ cookies,
5108
+ hasConsent,
5109
+ userAgent,
5110
+ deviceType: userAgent ? detectDeviceType(userAgent) : "desktop",
5111
+ geo: {
5112
+ country: firstHeader(
5113
+ request,
5114
+ "oxygen-buyer-country",
5115
+ "cf-ipcountry",
5116
+ "x-vercel-ip-country"
5117
+ ),
5118
+ region: firstHeader(
5119
+ request,
5120
+ "oxygen-buyer-province",
5121
+ "cf-region-code",
5122
+ "x-vercel-ip-country-region"
5123
+ )
5124
+ },
5125
+ url: {
5126
+ path: requestUrl.pathname,
5127
+ query,
5128
+ // Public host — prefer the forwarded host over the received one so
5129
+ // self-referral detection works behind a proxy / preview domain, where
5130
+ // request.url carries the internal host (e.g. *.vercel.app) while the
5131
+ // browser typed the storefront domain. x-forwarded-host may be a comma
5132
+ // list and may carry a port.
5133
+ host: (firstHeader(request, "x-forwarded-host", "host") ?? requestUrl.hostname).split(",")[0].trim().split(":")[0].toLowerCase()
5134
+ },
5135
+ referrer: request.headers.get("referer") || void 0
5136
+ };
5137
+ }
5138
+
5139
+ // src/audiences/safe-regex.ts
5140
+ var MAX_REGEX_PATTERN_LENGTH = 200;
5141
+ var MAX_REGEX_INPUT_LENGTH = 4096;
5142
+ function safeRegexMatch(pattern, input) {
5143
+ if (!pattern || input === void 0) return false;
5144
+ if (pattern.length > MAX_REGEX_PATTERN_LENGTH || input.length > MAX_REGEX_INPUT_LENGTH) {
5145
+ return false;
5146
+ }
5147
+ try {
5148
+ return new RegExp(pattern).test(input);
5149
+ } catch {
5150
+ return false;
5151
+ }
5152
+ }
5153
+
5154
+ // src/audiences/conditions/cookie.ts
5155
+ function evaluateCookie(config, identity) {
5156
+ const name = config?.name;
5157
+ const op = config?.op;
5158
+ if (!name || !op) return false;
5159
+ if (config?.requireConsent && !identity.hasConsent) return false;
5160
+ const value = identity.cookies?.[name];
5161
+ const target = config?.value ?? "";
5162
+ switch (op) {
5163
+ case "exists":
5164
+ return value !== void 0 && value !== "";
5165
+ case "equals":
5166
+ return value === target;
5167
+ case "contains":
5168
+ return value !== void 0 && value.includes(target);
5169
+ case "starts_with":
5170
+ return value !== void 0 && value.startsWith(target);
5171
+ case "ends_with":
5172
+ return value !== void 0 && value.endsWith(target);
5173
+ case "matches_regex":
5174
+ return safeRegexMatch(target, value);
5175
+ default:
5176
+ return false;
5177
+ }
5178
+ }
5179
+
5180
+ // src/audiences/conditions/builtin.ts
5181
+ var PAID_MEDIUM = /^(.*cp.*|ppc|retargeting|paid.*)$/;
5182
+ var DISPLAY_MEDIUM = ["display", "banner", "expandable", "interstitial", "cpm"];
5183
+ var SOCIAL_MEDIUM = ["social", "social-network", "social-media", "sm", "social network", "social media"];
5184
+ var ORGANIC_VIDEO_MEDIUM = /^.*video.*$/;
5185
+ var EMAIL_MEDIUM = /^(email|e-mail|e_mail|e mail)$/;
5186
+ var REFERRAL_MEDIUM = ["referral", "app", "link"];
5187
+ var SEARCH_SOURCES = [
5188
+ "google",
5189
+ "bing",
5190
+ "yahoo",
5191
+ "duckduckgo",
5192
+ "baidu",
5193
+ "yandex",
5194
+ "ecosia",
5195
+ "ask.",
5196
+ "aol.",
5197
+ "naver",
5198
+ "daum",
5199
+ "brave",
5200
+ "startpage",
5201
+ "qwant",
5202
+ "sogou",
5203
+ "seznam"
5204
+ ];
5205
+ var SOCIAL_SOURCES = [
5206
+ "facebook",
5207
+ "fb.",
5208
+ "instagram",
5209
+ "tiktok",
5210
+ "pinterest",
5211
+ "pin.it",
5212
+ "linkedin",
5213
+ "lnkd.in",
5214
+ "reddit",
5215
+ "snapchat",
5216
+ "twitter",
5217
+ "x.com",
5218
+ "t.co",
5219
+ "tumblr",
5220
+ "threads",
5221
+ "whatsapp",
5222
+ "wechat",
5223
+ "weibo",
5224
+ "vk.",
5225
+ "quora"
5226
+ ];
5227
+ function hostFromReferrer(referrer) {
5228
+ if (!referrer) return "";
5229
+ try {
5230
+ return new URL(referrer).hostname.toLowerCase();
5231
+ } catch {
5232
+ return "";
5233
+ }
5234
+ }
5235
+ var parseList = (value) => (value ?? "").split(",").map((s) => s.trim()).filter(Boolean);
5236
+ function matchGeo(code, op, value) {
5237
+ if (!code) return false;
5238
+ const c = code.toUpperCase();
5239
+ const list = parseList(value).map((s) => s.toUpperCase());
5240
+ switch (op) {
5241
+ case "equals":
5242
+ return c === (value ?? "").trim().toUpperCase();
5243
+ case "in_list":
5244
+ return list.includes(c);
5245
+ case "not_in_list":
5246
+ return list.length > 0 && !list.includes(c);
5247
+ default:
5248
+ return false;
5249
+ }
5250
+ }
5251
+ function classifyReferrerSource(query, referrer, currentHost) {
5252
+ const medium = (query?.["utm_medium"] ?? "").toLowerCase();
5253
+ const source = (query?.["utm_source"] ?? "").toLowerCase();
5254
+ const stripWww = (h) => h.replace(/^www\./, "");
5255
+ let host = hostFromReferrer(referrer);
5256
+ if (host && currentHost) {
5257
+ const a = stripWww(host);
5258
+ const b = stripWww(currentHost.toLowerCase());
5259
+ if (a === b || a.endsWith("." + b) || b.endsWith("." + a)) host = "";
5260
+ }
5261
+ const bareHost = stripWww(host);
5262
+ const bareKey = (k) => k.endsWith(".") ? k.slice(0, -1) : k;
5263
+ const hostInList = (list) => !!bareHost && list.some((k) => {
5264
+ const key = bareKey(k);
5265
+ return key.includes(".") ? bareHost === key || bareHost.endsWith("." + key) : bareHost.split(".").includes(key);
5266
+ });
5267
+ const sourceInList = (list) => {
5268
+ if (!source) return false;
5269
+ const tokens = source.split(/[.\-_ ]/);
5270
+ return list.some((k) => {
5271
+ const key = bareKey(k);
5272
+ return key.includes(".") ? source === key || source.endsWith("." + key) : tokens.includes(key);
5273
+ });
5274
+ };
5275
+ const inCategory = (list) => sourceInList(list) || hostInList(list);
5276
+ if (PAID_MEDIUM.test(medium) || DISPLAY_MEDIUM.includes(medium)) return "paid";
5277
+ if (SOCIAL_MEDIUM.includes(medium) || inCategory(SOCIAL_SOURCES)) return "social";
5278
+ if (medium === "organic" || ORGANIC_VIDEO_MEDIUM.test(medium) || inCategory(SEARCH_SOURCES)) return "organic";
5279
+ if (EMAIL_MEDIUM.test(medium) || EMAIL_MEDIUM.test(source)) return "email";
5280
+ if (medium === "affiliate" || REFERRAL_MEDIUM.includes(medium) || host || medium || source)
5281
+ return "referral";
5282
+ return "direct";
5283
+ }
5284
+ var BUILTINS = {
5285
+ // Logged in vs. guest — Shopify customer session presence.
5286
+ auth_status: (config, identity) => {
5287
+ const loggedIn = !!identity.shopifyCustomerId;
5288
+ if (config?.value === "logged_in") return loggedIn;
5289
+ if (config?.value === "anonymous") return !loggedIn;
5290
+ return false;
5291
+ },
5292
+ // Device type from the User-Agent; unknown falls back to desktop.
5293
+ device: (config, identity) => (identity.deviceType ?? "desktop") === config?.value,
5294
+ // New vs. returning. The persistent prior-visit cookies say the visitor has
5295
+ // been here at some point, not whether THIS session is their first. The
5296
+ // rolling __pack_s marker carries that verdict ("r"/"n"), decided once at
5297
+ // session start in handle-request (see sessionVerdict in ../visitor-recency).
5298
+ // Mirror that writer's tri-state: "r"/"n" are authoritative; anything else (a
5299
+ // new session with no marker, or a tampered value) falls back to prior visits.
5300
+ // Missing signal → new.
5301
+ //
5302
+ // Consent note: this is the only built-in that reads cookies, and it does NOT
5303
+ // enforce a consent gate. _ga / _shopify_y only exist when analytics consent
5304
+ // was given, but Pack's own __pack / __pack_s are written on every response
5305
+ // regardless of consent (see handle-request), so a visitor who declined can
5306
+ // still be classified from them. Whether that is acceptable is a system-wide
5307
+ // consent-posture decision for the resolver/identity layer — flagged, not
5308
+ // enforced.
5309
+ visitor_recency: (config, identity) => {
5310
+ const cookies = identity.cookies ?? {};
5311
+ const priorVisit = PRIOR_VISIT_COOKIES.some((name) => !!cookies[name]);
5312
+ const session = cookies[PACK_SESSION_COOKIE_ID];
5313
+ const returning = session === "r" ? true : session === "n" ? false : priorVisit;
5314
+ if (config?.value === "returning") return returning;
5315
+ if (config?.value === "new") return !returning;
5316
+ return false;
5317
+ },
5318
+ // Country / region from the CDN geo signal; missing → no match.
5319
+ geo_country: (config, identity) => matchGeo(identity.geo?.country, config?.op, config?.value),
5320
+ geo_region: (config, identity) => matchGeo(identity.geo?.region, config?.op, config?.value),
5321
+ // Traffic source from utm_medium, then Referer host; else direct.
5322
+ referrer_source: (config, identity) => classifyReferrerSource(
5323
+ identity.url?.query,
5324
+ identity.referrer,
5325
+ identity.url?.host
5326
+ ) === config?.value,
5327
+ // A specific UTM parameter on the current URL.
5328
+ utm_param: (config, identity) => {
5329
+ if (!config?.param) return false;
5330
+ const name = config.param.replace(/^utm_/, "");
5331
+ const v = identity.url?.query?.[`utm_${name}`]?.toLowerCase();
5332
+ switch (config?.op) {
5333
+ case "exists":
5334
+ return v !== void 0 && v !== "";
5335
+ case "equals":
5336
+ return v !== void 0 && v === config?.value?.toLowerCase();
5337
+ case "in_list":
5338
+ return v !== void 0 && parseList(config?.value).map((s) => s.toLowerCase()).includes(v);
5339
+ default:
5340
+ return false;
5341
+ }
5342
+ }
5343
+ };
5344
+ function evaluateBuiltin(config, identity) {
5345
+ const evaluator = config?.key ? BUILTINS[config.key] : void 0;
5346
+ return evaluator ? evaluator(config ?? {}, identity) : false;
5347
+ }
5348
+
5349
+ // src/audiences/condition-registry.ts
5350
+ var evaluators = /* @__PURE__ */ new Map();
5351
+ function registerConditionEvaluator(type, evaluate) {
5352
+ if (evaluators.has(type)) {
5353
+ throw new Error(`Condition evaluator "${type}" is already registered.`);
5354
+ }
5355
+ evaluators.set(type, evaluate);
5356
+ }
5357
+ function getConditionEvaluator(type) {
5358
+ return evaluators.get(type);
5359
+ }
5360
+ function isConditionRegistered(type) {
5361
+ return evaluators.has(type);
5362
+ }
5363
+ registerConditionEvaluator("cookie", evaluateCookie);
5364
+ registerConditionEvaluator("builtin", evaluateBuiltin);
5365
+
5366
+ // src/audiences/audience-resolver.ts
5367
+ function isEmptyRules(rules) {
5368
+ return rules == null || typeof rules === "object" && !Array.isArray(rules) && Object.keys(rules).length === 0;
5369
+ }
5370
+ function isGroupNode(node) {
5371
+ return !!node && typeof node === "object" && typeof node.op === "string";
5372
+ }
5373
+ async function resolveRulesTree(rules, identity) {
5374
+ const matchedConditions = [];
5375
+ if (isEmptyRules(rules)) {
5376
+ return { matches: true, matchedConditions };
5377
+ }
5378
+ const matches = await evaluateNode(rules, identity, matchedConditions);
5379
+ return { matches, matchedConditions: matches ? matchedConditions : [] };
5380
+ }
5381
+ async function evaluateNode(node, identity, matched) {
5382
+ if (isGroupNode(node)) {
5383
+ const { op, children } = node;
5384
+ if (op === "AND") {
5385
+ for (const child of children) {
5386
+ if (!await evaluateNode(child, identity, matched)) return false;
5387
+ }
5388
+ return true;
5389
+ }
5390
+ if (op === "OR") {
5391
+ for (const child of children) {
5392
+ if (await evaluateNode(child, identity, matched)) return true;
5393
+ }
5394
+ return false;
5395
+ }
5396
+ if (!children?.length) return false;
5397
+ for (const child of children) {
5398
+ if (await evaluateNode(child, identity, matched)) return false;
5399
+ }
5400
+ return true;
5401
+ }
5402
+ return evaluateLeaf(node, identity, matched);
5403
+ }
5404
+ async function evaluateLeaf(leaf, identity, matched) {
5405
+ const evaluate = getConditionEvaluator(leaf.type);
5406
+ if (!evaluate) return false;
5407
+ let result;
5408
+ try {
5409
+ result = await evaluate(leaf.config ?? {}, identity);
5410
+ } catch {
5411
+ result = false;
5412
+ }
5413
+ if (leaf.negate) result = !result;
5414
+ if (result) {
5415
+ matched.push({
5416
+ type: leaf.type,
5417
+ provider: leaf.provider ?? null,
5418
+ config: leaf.config ?? null,
5419
+ negate: leaf.negate ?? null
5420
+ });
5421
+ }
5422
+ return result;
5423
+ }
5424
+
5048
5425
  // src/tests/local-test-resolver.ts
5049
5426
  var debug2 = (0, import_debug2.default)("pack:ab-testing:local-resolver");
5050
5427
  var LocalTestResolver = class {
@@ -5084,7 +5461,7 @@ var LocalTestResolver = class {
5084
5461
  /**
5085
5462
  * Evaluate test rules and assign a variant
5086
5463
  */
5087
- async assignTest(attributes, _sessionId) {
5464
+ async assignTest(attributes, _sessionId, identity) {
5088
5465
  debug2(
5089
5466
  "[Pack Test LocalResolver] Starting test assignment:",
5090
5467
  JSON.stringify({
@@ -5096,7 +5473,11 @@ var LocalTestResolver = class {
5096
5473
  debug2("[Pack Test LocalResolver] No test rules available");
5097
5474
  return null;
5098
5475
  }
5099
- const eligibleTests = await this.evaluateRules(this.testRules, attributes);
5476
+ const eligibleTests = await this.evaluateRules(
5477
+ this.testRules,
5478
+ attributes,
5479
+ identity
5480
+ );
5100
5481
  debug2(
5101
5482
  "[Pack Test LocalResolver] Rule evaluation result:",
5102
5483
  JSON.stringify({
@@ -5177,7 +5558,7 @@ var LocalTestResolver = class {
5177
5558
  /**
5178
5559
  * Evaluate rules using json-rules-engine (same as tests-service)
5179
5560
  */
5180
- async evaluateRules(tests, attributes) {
5561
+ async evaluateRules(tests, attributes, identity) {
5181
5562
  debug2(
5182
5563
  "[Pack Test LocalResolver] Starting rule evaluation:",
5183
5564
  JSON.stringify({
@@ -5298,7 +5679,7 @@ var LocalTestResolver = class {
5298
5679
  return hasTargetedEvent;
5299
5680
  });
5300
5681
  debug2(
5301
- "[Pack Test LocalResolver] Final eligible tests:",
5682
+ "[Pack Test LocalResolver] Inline-eligible tests:",
5302
5683
  JSON.stringify({
5303
5684
  eligibleCount: eligibleTests.length,
5304
5685
  eligibleTests: eligibleTests.map((t) => ({
@@ -5307,7 +5688,47 @@ var LocalTestResolver = class {
5307
5688
  }))
5308
5689
  })
5309
5690
  );
5310
- return eligibleTests;
5691
+ return this.applyAudienceGating(eligibleTests, identity);
5692
+ }
5693
+ /**
5694
+ * Audience gating (XOR with inline rules): a test attached to an audience is
5695
+ * only eligible when the visitor matches the pinned audience snapshot. Tests
5696
+ * without an audience pass through unchanged. Fails closed (excludes the test)
5697
+ * when the audience can't be evaluated — no identity, or an evaluator error —
5698
+ * so audience-targeted tests never leak to unintended traffic.
5699
+ */
5700
+ async applyAudienceGating(eligibleTests, identity) {
5701
+ const hasAudience = eligibleTests.some(
5702
+ (test) => test.experimentAudience?.pinnedRules
5703
+ );
5704
+ if (!hasAudience) return eligibleTests;
5705
+ const gated = await Promise.all(
5706
+ eligibleTests.map(async (test) => {
5707
+ const pinnedRules = test.experimentAudience?.pinnedRules;
5708
+ if (!pinnedRules) return test;
5709
+ if (!identity) {
5710
+ debug2(
5711
+ `[Pack Test LocalResolver] Test ${test.handle} has an audience but no identity \u2014 excluding`
5712
+ );
5713
+ return null;
5714
+ }
5715
+ try {
5716
+ const { matches } = await resolveRulesTree(pinnedRules, identity);
5717
+ debug2(
5718
+ `[Pack Test LocalResolver] Test ${test.handle} audience match:`,
5719
+ JSON.stringify({ matches })
5720
+ );
5721
+ return matches ? test : null;
5722
+ } catch (err) {
5723
+ debug2(
5724
+ `[Pack Test LocalResolver] Test ${test.handle} audience eval error \u2014 excluding:`,
5725
+ String(err)
5726
+ );
5727
+ return null;
5728
+ }
5729
+ })
5730
+ );
5731
+ return gated.filter((test) => test !== null);
5311
5732
  }
5312
5733
  /**
5313
5734
  * Resolve test and variant IDs from their handles
@@ -5350,6 +5771,10 @@ var QUERY_TESTS_BY_RULES = `#graphql
5350
5771
  value
5351
5772
  }
5352
5773
  impressionTrigger
5774
+ experimentAudience {
5775
+ pinnedVersion
5776
+ pinnedRules
5777
+ }
5353
5778
  testVariants {
5354
5779
  id
5355
5780
  handle
@@ -5688,9 +6113,11 @@ async function packClientFetchTestByRules(packClient, testTargetAudienceAttribut
5688
6113
  }
5689
6114
  const sessionId = packClient.storeId;
5690
6115
  debug3("[Pack Test] Assigning test with session ID:", sessionId);
6116
+ const identity = buildIdentityBundle(request);
5691
6117
  const assignedTest = await localTestResolver.assignTest(
5692
6118
  testTargetAudienceAttributes || {},
5693
- sessionId
6119
+ sessionId,
6120
+ identity
5694
6121
  );
5695
6122
  debug3(
5696
6123
  "[Pack Test] Test assignment result:",
@@ -5781,7 +6208,7 @@ async function getTestInfo({
5781
6208
  isExpired: testSessionExpireAt ? new Date(testSessionExpireAt) < /* @__PURE__ */ new Date() : false
5782
6209
  })
5783
6210
  );
5784
- const exposedTestCookieString = cookie2.parse(
6211
+ const exposedTestCookieString = cookie4.parse(
5785
6212
  request.headers.get("cookie") || ""
5786
6213
  )?.exposedTest;
5787
6214
  debug3(
@@ -6232,7 +6659,7 @@ function createPackClient(options) {
6232
6659
  if (hasExposedTestCookie) {
6233
6660
  response.headers.append(
6234
6661
  "Set-Cookie",
6235
- cookie3.serialize("exposedTest", "", {
6662
+ cookie5.serialize("exposedTest", "", {
6236
6663
  maxAge: 0,
6237
6664
  expires: /* @__PURE__ */ new Date(0),
6238
6665
  path: "/"
@@ -6994,10 +7421,15 @@ export {
6994
7421
  PackTestProvider,
6995
7422
  PackTestRoute,
6996
7423
  PackTestSession,
7424
+ buildIdentityBundle,
6997
7425
  createPackClient,
7426
+ getConditionEvaluator,
6998
7427
  handleRequest,
7428
+ isConditionRegistered,
6999
7429
  action as previewModeAction,
7000
7430
  loader as previewModeLoader,
7431
+ registerConditionEvaluator,
7432
+ resolveRulesTree,
7001
7433
  useAbTest,
7002
7434
  useAbTestHandle,
7003
7435
  useAbTestId,