@skrillex1224/playwright-toolkit 2.1.183 → 2.1.184

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/browser.js CHANGED
@@ -1317,6 +1317,636 @@ var ByPass = {
1317
1317
  resolveRouteByProxy
1318
1318
  };
1319
1319
 
1320
+ // src/runtime-env.js
1321
+ var BROWSER_PROFILE_SCHEMA_VERSION = 1;
1322
+ var rememberedRuntimeState = null;
1323
+ var isPlainObject = (value) => value && typeof value === "object" && !Array.isArray(value);
1324
+ var deepClone = (value) => {
1325
+ if (value == null) return value;
1326
+ try {
1327
+ return JSON.parse(JSON.stringify(value));
1328
+ } catch {
1329
+ return value;
1330
+ }
1331
+ };
1332
+ var tryParseJSON = (value) => {
1333
+ if (value == null) return null;
1334
+ if (typeof value === "object") return value;
1335
+ const raw = String(value || "").trim();
1336
+ if (!raw) return null;
1337
+ try {
1338
+ return JSON.parse(raw);
1339
+ } catch {
1340
+ return null;
1341
+ }
1342
+ };
1343
+ var normalizeLocalStorage = (value) => {
1344
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
1345
+ return Object.entries(source).reduce((acc, [key, item]) => {
1346
+ const safeKey = String(key || "").trim();
1347
+ const safeValue = String(item != null ? item : "").trim();
1348
+ if (!safeKey || !safeValue || safeValue === "<nil>") return acc;
1349
+ acc[safeKey] = safeValue;
1350
+ return acc;
1351
+ }, {});
1352
+ };
1353
+ var normalizeSessionStorage = (value) => {
1354
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
1355
+ return Object.entries(source).reduce((acc, [key, item]) => {
1356
+ const safeKey = String(key || "").trim();
1357
+ const safeValue = String(item != null ? item : "").trim();
1358
+ if (!safeKey || !safeValue || safeValue === "<nil>") return acc;
1359
+ acc[safeKey] = safeValue;
1360
+ return acc;
1361
+ }, {});
1362
+ };
1363
+ var normalizeAuth = (value) => {
1364
+ const source = value && typeof value === "object" && !Array.isArray(value) ? value : {};
1365
+ return Object.entries(source).reduce((acc, [key, item]) => {
1366
+ const safeKey = String(key || "").trim();
1367
+ const safeValue = String(item != null ? item : "").trim();
1368
+ if (!safeKey || !safeValue || safeValue === "<nil>") return acc;
1369
+ acc[safeKey] = safeValue;
1370
+ return acc;
1371
+ }, {});
1372
+ };
1373
+ var normalizeCookies = (value) => {
1374
+ if (!Array.isArray(value)) return [];
1375
+ return value.map((item) => {
1376
+ var _a;
1377
+ const raw = item && typeof item === "object" ? item : {};
1378
+ const name = String(raw.name || "").trim();
1379
+ const cookieValue = String((_a = raw.value) != null ? _a : "").trim();
1380
+ if (!name || !cookieValue || cookieValue === "<nil>") return null;
1381
+ const domain = String(raw.domain || "").trim();
1382
+ const path = String(raw.path || "").trim() || "/";
1383
+ const sameSiteRaw = String(raw.sameSite || "").trim();
1384
+ return {
1385
+ ...raw,
1386
+ name,
1387
+ value: cookieValue,
1388
+ domain,
1389
+ path,
1390
+ ...sameSiteRaw ? { sameSite: sameSiteRaw } : {}
1391
+ };
1392
+ }).filter(Boolean);
1393
+ };
1394
+ var buildCookieMap = (cookies) => cookies.reduce((acc, item) => {
1395
+ acc[item.name] = item.value;
1396
+ return acc;
1397
+ }, {});
1398
+ var normalizeHttpUrl = (value) => {
1399
+ const raw = String(value || "").trim();
1400
+ if (!raw) return "";
1401
+ try {
1402
+ const parsed = new URL(raw);
1403
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return "";
1404
+ parsed.hash = "";
1405
+ return parsed.toString();
1406
+ } catch {
1407
+ return "";
1408
+ }
1409
+ };
1410
+ var uniqueStrings = (value) => {
1411
+ const list = Array.isArray(value) ? value : [];
1412
+ const seen = /* @__PURE__ */ new Set();
1413
+ const result = [];
1414
+ list.forEach((item) => {
1415
+ const normalized = String(item || "").trim();
1416
+ if (!normalized || seen.has(normalized)) return;
1417
+ seen.add(normalized);
1418
+ result.push(normalized);
1419
+ });
1420
+ return result;
1421
+ };
1422
+ var normalizeHttpUrlList = (value) => uniqueStrings(
1423
+ (Array.isArray(value) ? value : [value]).map((item) => normalizeHttpUrl(item)).filter(Boolean)
1424
+ );
1425
+ var normalizeCookieDomain = (value) => String(value || "").trim().replace(/^\./, "").toLowerCase();
1426
+ var normalizeCookiePath = (value) => {
1427
+ const raw = String(value || "").trim();
1428
+ if (!raw) return "/";
1429
+ return raw.startsWith("/") ? raw : `/${raw}`;
1430
+ };
1431
+ var doesCookieMatchUrl = (cookie, url) => {
1432
+ if (!cookie || !url) return false;
1433
+ try {
1434
+ const parsed = new URL(url);
1435
+ const host = String(parsed.hostname || "").trim().toLowerCase();
1436
+ const pathname = String(parsed.pathname || "/").trim() || "/";
1437
+ const cookieDomain = normalizeCookieDomain(cookie.domain);
1438
+ const cookiePath = normalizeCookiePath(cookie.path);
1439
+ if (!host || !cookieDomain) return false;
1440
+ const domainMatched = host === cookieDomain || host.endsWith(`.${cookieDomain}`);
1441
+ if (!domainMatched) return false;
1442
+ if (cookie.secure && parsed.protocol !== "https:") return false;
1443
+ return pathname.startsWith(cookiePath);
1444
+ } catch {
1445
+ return false;
1446
+ }
1447
+ };
1448
+ var normalizeRawSnapshot = (value = {}) => {
1449
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
1450
+ const source = isPlainObject(value) ? value : {};
1451
+ const pageUrl = normalizeHttpUrl((_a = source.page_url) != null ? _a : source.pageUrl);
1452
+ const frameUrls = normalizeHttpUrlList((_b = source.frame_urls) != null ? _b : source.frameUrls);
1453
+ const resourceUrls = normalizeHttpUrlList((_c = source.resource_urls) != null ? _c : source.resourceUrls);
1454
+ const browserProfileObservedSource = (_i = (_h = (_f = (_d = source.browser_profile_observed) != null ? _d : source.browserProfileObserved) != null ? _f : (_e = source.browser_profile) == null ? void 0 : _e.observed) != null ? _h : (_g = source.browserProfile) == null ? void 0 : _g.observed) != null ? _i : source.browserProfile;
1455
+ return {
1456
+ page_url: pageUrl,
1457
+ frame_urls: frameUrls,
1458
+ resource_urls: resourceUrls,
1459
+ cookies: Array.isArray(source.cookies) ? deepClone(source.cookies) : [],
1460
+ local_storage: normalizeLocalStorage((_j = source.local_storage) != null ? _j : source.localStorage),
1461
+ session_storage: normalizeSessionStorage((_k = source.session_storage) != null ? _k : source.sessionStorage),
1462
+ browser_profile_observed: normalizeObservedBrowserProfile(browserProfileObservedSource),
1463
+ auth: normalizeAuth(source.auth)
1464
+ };
1465
+ };
1466
+ var collectCookieUrlsFromSnapshot = (snapshot = {}) => {
1467
+ const normalized = normalizeRawSnapshot(snapshot);
1468
+ return uniqueStrings([
1469
+ normalized.page_url,
1470
+ ...normalized.frame_urls,
1471
+ ...normalized.resource_urls
1472
+ ].filter(Boolean));
1473
+ };
1474
+ var filterCookiesBySnapshot = (cookies = [], snapshot = {}) => {
1475
+ const normalizedCookies = normalizeCookies(cookies);
1476
+ const cookieUrls = collectCookieUrlsFromSnapshot(snapshot);
1477
+ if (cookieUrls.length === 0) {
1478
+ return normalizedCookies;
1479
+ }
1480
+ return normalizedCookies.filter((cookie) => cookieUrls.some((url) => doesCookieMatchUrl(cookie, url)));
1481
+ };
1482
+ var buildEnvPayloadFromSnapshot = (snapshot = {}, options = {}) => {
1483
+ var _a, _b, _c, _d, _e;
1484
+ const normalized = normalizeRawSnapshot(snapshot);
1485
+ const cookies = filterCookiesBySnapshot((snapshot == null ? void 0 : snapshot.cookies) || normalized.cookies, normalized);
1486
+ const localStorage = normalized.local_storage;
1487
+ const sessionStorage = normalized.session_storage;
1488
+ const auth = normalizeAuth((_a = options.auth) != null ? _a : normalized.auth);
1489
+ const browserProfileCore = normalizeBrowserProfileCore(
1490
+ (_e = (_c = options.browserProfileCore) != null ? _c : (_b = snapshot == null ? void 0 : snapshot.browser_profile) == null ? void 0 : _b.core) != null ? _e : (_d = snapshot == null ? void 0 : snapshot.browserProfile) == null ? void 0 : _d.core
1491
+ );
1492
+ const browserProfile = buildBrowserProfilePayload(browserProfileCore, normalized.browser_profile_observed);
1493
+ const payload = {
1494
+ ...cookies.length > 0 ? { cookies } : {},
1495
+ ...Object.keys(localStorage).length > 0 ? { local_storage: localStorage } : {},
1496
+ ...Object.keys(sessionStorage).length > 0 ? { session_storage: sessionStorage } : {},
1497
+ ...Object.keys(auth).length > 0 ? { auth } : {},
1498
+ ...Object.keys(browserProfile).length > 0 ? { browser_profile: browserProfile } : {}
1499
+ };
1500
+ return Object.keys(payload).length > 0 ? payload : null;
1501
+ };
1502
+ var captureRawSnapshotFromPage = async (page) => {
1503
+ const frameUrls = typeof (page == null ? void 0 : page.frames) === "function" ? page.frames().map((frame) => {
1504
+ try {
1505
+ return frame.url();
1506
+ } catch {
1507
+ return "";
1508
+ }
1509
+ }) : [];
1510
+ const snapshot = await page.evaluate(() => {
1511
+ const localStorage = {};
1512
+ const sessionStorage = {};
1513
+ const resourceUrls = [];
1514
+ const frameUrls2 = [];
1515
+ try {
1516
+ for (let i = 0; i < window.localStorage.length; i += 1) {
1517
+ const key = window.localStorage.key(i);
1518
+ if (!key) continue;
1519
+ const value = window.localStorage.getItem(key);
1520
+ if (value !== null) localStorage[key] = value;
1521
+ }
1522
+ } catch {
1523
+ }
1524
+ try {
1525
+ for (let i = 0; i < window.sessionStorage.length; i += 1) {
1526
+ const key = window.sessionStorage.key(i);
1527
+ if (!key) continue;
1528
+ const value = window.sessionStorage.getItem(key);
1529
+ if (value !== null) sessionStorage[key] = value;
1530
+ }
1531
+ } catch {
1532
+ }
1533
+ try {
1534
+ const perfEntries = performance.getEntriesByType("resource") || [];
1535
+ perfEntries.forEach((entry) => {
1536
+ const name = String((entry == null ? void 0 : entry.name) || "").trim();
1537
+ if (name) resourceUrls.push(name);
1538
+ });
1539
+ } catch {
1540
+ }
1541
+ try {
1542
+ document.querySelectorAll("iframe,frame").forEach((node) => {
1543
+ const src = String((node == null ? void 0 : node.src) || "").trim();
1544
+ if (src) frameUrls2.push(src);
1545
+ });
1546
+ } catch {
1547
+ }
1548
+ const nav = window.navigator || {};
1549
+ const screen = window.screen || {};
1550
+ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || "";
1551
+ return {
1552
+ page_url: window.location.href || "",
1553
+ frame_urls: frameUrls2,
1554
+ resource_urls: resourceUrls,
1555
+ local_storage: localStorage,
1556
+ session_storage: sessionStorage,
1557
+ browser_profile_observed: {
1558
+ user_agent: nav.userAgent || "",
1559
+ platform: nav.platform || "",
1560
+ language: nav.language || "",
1561
+ languages: Array.isArray(nav.languages) ? nav.languages : [],
1562
+ hardware_concurrency: Number(nav.hardwareConcurrency || 0),
1563
+ device_memory: Number(nav.deviceMemory || 0),
1564
+ timezone,
1565
+ viewport: {
1566
+ width: Number(window.innerWidth || 0),
1567
+ height: Number(window.innerHeight || 0)
1568
+ },
1569
+ screen: {
1570
+ width: Number(screen.width || 0),
1571
+ height: Number(screen.height || 0),
1572
+ avail_width: Number(screen.availWidth || 0),
1573
+ avail_height: Number(screen.availHeight || 0),
1574
+ color_depth: Number(screen.colorDepth || 0),
1575
+ pixel_depth: Number(screen.pixelDepth || 0)
1576
+ }
1577
+ }
1578
+ };
1579
+ });
1580
+ return normalizeRawSnapshot({
1581
+ ...snapshot,
1582
+ frame_urls: [...frameUrls, ...(snapshot == null ? void 0 : snapshot.frame_urls) || []]
1583
+ });
1584
+ };
1585
+ var normalizeObservedBrowserProfile = (value) => {
1586
+ const source = isPlainObject(value) ? value : {};
1587
+ const profile = {};
1588
+ const stringFields = {
1589
+ user_agent: source.user_agent,
1590
+ platform: source.platform,
1591
+ language: source.language,
1592
+ timezone: source.timezone
1593
+ };
1594
+ Object.entries(stringFields).forEach(([key, item]) => {
1595
+ const safeValue = String(item || "").trim();
1596
+ if (safeValue) {
1597
+ profile[key] = safeValue;
1598
+ }
1599
+ });
1600
+ if (Array.isArray(source.languages)) {
1601
+ const languages = source.languages.map((item) => String(item || "").trim()).filter(Boolean);
1602
+ if (languages.length > 0) {
1603
+ profile.languages = languages;
1604
+ }
1605
+ }
1606
+ const numericFields = {
1607
+ hardware_concurrency: Number(source.hardware_concurrency || 0),
1608
+ device_memory: Number(source.device_memory || 0)
1609
+ };
1610
+ Object.entries(numericFields).forEach(([key, item]) => {
1611
+ if (Number.isFinite(item) && item > 0) {
1612
+ profile[key] = item;
1613
+ }
1614
+ });
1615
+ if (isPlainObject(source.viewport)) {
1616
+ const width = Number(source.viewport.width || 0);
1617
+ const height = Number(source.viewport.height || 0);
1618
+ if (width > 0 && height > 0) {
1619
+ profile.viewport = { width, height };
1620
+ }
1621
+ }
1622
+ if (isPlainObject(source.screen)) {
1623
+ const screenProfile = {};
1624
+ const screenFields = {
1625
+ width: Number(source.screen.width || 0),
1626
+ height: Number(source.screen.height || 0),
1627
+ avail_width: Number(source.screen.avail_width || 0),
1628
+ avail_height: Number(source.screen.avail_height || 0),
1629
+ color_depth: Number(source.screen.color_depth || 0),
1630
+ pixel_depth: Number(source.screen.pixel_depth || 0)
1631
+ };
1632
+ Object.entries(screenFields).forEach(([key, item]) => {
1633
+ if (Number.isFinite(item) && item > 0) {
1634
+ screenProfile[key] = item;
1635
+ }
1636
+ });
1637
+ if (Object.keys(screenProfile).length > 0) {
1638
+ profile.screen = screenProfile;
1639
+ }
1640
+ }
1641
+ return profile;
1642
+ };
1643
+ var normalizeBrowserProfileCore = (value) => {
1644
+ const source = isPlainObject(value) ? value : {};
1645
+ const profile = {};
1646
+ if (isPlainObject(source.fingerprint) && Object.keys(source.fingerprint).length > 0) {
1647
+ profile.fingerprint = deepClone(source.fingerprint);
1648
+ }
1649
+ const timezoneId = String(source.timezone_id || "").trim();
1650
+ if (timezoneId) {
1651
+ profile.timezone_id = timezoneId;
1652
+ }
1653
+ const locale = String(source.locale || "").trim();
1654
+ if (locale) {
1655
+ profile.locale = locale;
1656
+ }
1657
+ const profileKey = String(source.profile_key || "").trim();
1658
+ if (profileKey) {
1659
+ profile.profile_key = profileKey;
1660
+ }
1661
+ const browserMajorVersion = Number(source.browser_major_version || 0);
1662
+ if (Number.isFinite(browserMajorVersion) && browserMajorVersion > 0) {
1663
+ profile.browser_major_version = browserMajorVersion;
1664
+ }
1665
+ const schemaVersion = Number(source.schema_version || 0);
1666
+ if (Number.isFinite(schemaVersion) && schemaVersion > 0) {
1667
+ profile.schema_version = schemaVersion;
1668
+ } else if (Object.keys(profile).length > 0) {
1669
+ profile.schema_version = BROWSER_PROFILE_SCHEMA_VERSION;
1670
+ }
1671
+ return profile;
1672
+ };
1673
+ var buildBrowserProfilePayload = (core = {}, observed = {}) => {
1674
+ const payload = {};
1675
+ if (isPlainObject(core) && Object.keys(core).length > 0) {
1676
+ payload.core = core;
1677
+ }
1678
+ if (isPlainObject(observed) && Object.keys(observed).length > 0) {
1679
+ payload.observed = observed;
1680
+ }
1681
+ return payload;
1682
+ };
1683
+ var mergePlainObject = (target = {}, source = {}) => {
1684
+ const next = isPlainObject(target) ? deepClone(target) : {};
1685
+ if (!isPlainObject(source)) return next;
1686
+ Object.entries(source).forEach(([key, value]) => {
1687
+ if (!key) return;
1688
+ if (isPlainObject(value) && isPlainObject(next[key])) {
1689
+ next[key] = mergePlainObject(next[key], value);
1690
+ return;
1691
+ }
1692
+ next[key] = deepClone(value);
1693
+ });
1694
+ return next;
1695
+ };
1696
+ var mergeBrowserProfilePayload = (target = {}, source = {}) => {
1697
+ const current = isPlainObject(target) ? target : {};
1698
+ const incoming = isPlainObject(source) ? source : {};
1699
+ const currentCore = normalizeBrowserProfileCore(current.core);
1700
+ const incomingCore = normalizeBrowserProfileCore(incoming.core);
1701
+ const currentObserved = normalizeObservedBrowserProfile(current.observed);
1702
+ const incomingObserved = normalizeObservedBrowserProfile(incoming.observed);
1703
+ let mergedCore = currentCore;
1704
+ if (Object.keys(mergedCore).length === 0 && Object.keys(incomingCore).length > 0) {
1705
+ mergedCore = incomingCore;
1706
+ } else if (Object.keys(incomingCore).length > 0) {
1707
+ const currentVersion = Number(currentCore.browser_major_version || 0);
1708
+ const incomingVersion = Number(incomingCore.browser_major_version || 0);
1709
+ if (currentVersion > 0 && incomingVersion > 0 && currentVersion !== incomingVersion) {
1710
+ mergedCore = incomingCore;
1711
+ }
1712
+ }
1713
+ const mergedObserved = mergePlainObject(currentObserved, incomingObserved);
1714
+ return buildBrowserProfilePayload(mergedCore, mergedObserved);
1715
+ };
1716
+ var mergeEnvPatchObjects = (...patches) => {
1717
+ const merged = {};
1718
+ patches.forEach((patch) => {
1719
+ if (!isPlainObject(patch)) return;
1720
+ Object.entries(patch).forEach(([key, value]) => {
1721
+ if (!key) return;
1722
+ if (key === "browser_profile") {
1723
+ const browserProfile = mergeBrowserProfilePayload(merged.browser_profile, value);
1724
+ if (Object.keys(browserProfile).length > 0) {
1725
+ merged.browser_profile = browserProfile;
1726
+ }
1727
+ return;
1728
+ }
1729
+ if (isPlainObject(value) && isPlainObject(merged[key])) {
1730
+ merged[key] = mergePlainObject(merged[key], value);
1731
+ return;
1732
+ }
1733
+ merged[key] = deepClone(value);
1734
+ });
1735
+ });
1736
+ return Object.keys(merged).length > 0 ? merged : null;
1737
+ };
1738
+ var normalizeBrowserProfile = (value) => {
1739
+ const source = isPlainObject(value) ? value : {};
1740
+ const coreSource = isPlainObject(source.core) ? source.core : {};
1741
+ const observedSource = isPlainObject(source.observed) ? source.observed : {};
1742
+ const core = normalizeBrowserProfileCore(coreSource);
1743
+ const observed = normalizeObservedBrowserProfile(observedSource);
1744
+ return {
1745
+ core,
1746
+ observed,
1747
+ payload: buildBrowserProfilePayload(core, observed)
1748
+ };
1749
+ };
1750
+ var rememberRuntimeState = (state) => {
1751
+ rememberedRuntimeState = deepClone(state);
1752
+ return rememberedRuntimeState;
1753
+ };
1754
+ var normalizeRuntimeState = (source = {}, actor = "") => {
1755
+ if (source && typeof source === "object" && source.runtime && typeof source.runtime === "object" && !Array.isArray(source.runtime) && Object.prototype.hasOwnProperty.call(source, "browserProfileCore")) {
1756
+ return source;
1757
+ }
1758
+ return RuntimeEnv.parseInput(source, actor);
1759
+ };
1760
+ var RuntimeEnv = {
1761
+ tryParseJSON,
1762
+ normalizeCookies,
1763
+ normalizeLocalStorage,
1764
+ normalizeSessionStorage,
1765
+ normalizeAuth,
1766
+ normalizeBrowserProfileCore,
1767
+ normalizeObservedBrowserProfile,
1768
+ normalizeSnapshot(snapshot = {}) {
1769
+ return normalizeRawSnapshot(snapshot);
1770
+ },
1771
+ collectCookieUrls(snapshot = {}) {
1772
+ return collectCookieUrlsFromSnapshot(snapshot);
1773
+ },
1774
+ buildRuntimeEnvFromSnapshot(snapshot = {}, options = {}) {
1775
+ return buildEnvPayloadFromSnapshot(snapshot, options);
1776
+ },
1777
+ buildEnvPatchFromSnapshot(snapshot = {}, options = {}) {
1778
+ return buildEnvPayloadFromSnapshot(snapshot, options);
1779
+ },
1780
+ mergeEnvPatches(...patches) {
1781
+ return mergeEnvPatchObjects(...patches);
1782
+ },
1783
+ // parseInput 把 Actor 输入里的 runtime 字段标准化成 toolkit 内部统一结构。
1784
+ // 后续 visitor 只和这个 state 交互,不再自己拼 token/cookie 逻辑。
1785
+ parseInput(input = {}, actor = "") {
1786
+ const runtime = tryParseJSON(input == null ? void 0 : input.runtime) || {};
1787
+ const resolvedActor = String(actor || (input == null ? void 0 : input.actor) || "").trim();
1788
+ const cookies = normalizeCookies(runtime == null ? void 0 : runtime.cookies);
1789
+ const cookieMap = buildCookieMap(cookies);
1790
+ const localStorage = normalizeLocalStorage(runtime == null ? void 0 : runtime.local_storage);
1791
+ const sessionStorage = normalizeSessionStorage(runtime == null ? void 0 : runtime.session_storage);
1792
+ const auth = normalizeAuth(runtime == null ? void 0 : runtime.auth);
1793
+ const browserProfile = normalizeBrowserProfile(runtime == null ? void 0 : runtime.browser_profile);
1794
+ const envId = String((input == null ? void 0 : input.env_id) || "").trim();
1795
+ const normalizedRuntime = {
1796
+ ...runtime,
1797
+ ...cookies.length > 0 ? { cookies } : {},
1798
+ ...Object.keys(localStorage).length > 0 ? { local_storage: localStorage } : {},
1799
+ ...Object.keys(sessionStorage).length > 0 ? { session_storage: sessionStorage } : {},
1800
+ ...Object.keys(auth).length > 0 ? { auth } : {}
1801
+ };
1802
+ if (Object.keys(browserProfile.payload).length > 0) {
1803
+ normalizedRuntime.browser_profile = browserProfile.payload;
1804
+ } else {
1805
+ delete normalizedRuntime.browser_profile;
1806
+ }
1807
+ const state = {
1808
+ actor: resolvedActor,
1809
+ runtime: normalizedRuntime,
1810
+ envId,
1811
+ auth,
1812
+ cookies,
1813
+ cookieMap,
1814
+ localStorage,
1815
+ sessionStorage,
1816
+ browserProfile: browserProfile.payload,
1817
+ browserProfileCore: browserProfile.core,
1818
+ browserProfileObserved: browserProfile.observed
1819
+ };
1820
+ rememberRuntimeState(state);
1821
+ return state;
1822
+ },
1823
+ // buildEnvPatch 只构造允许回写到后端 env 的字段集合。
1824
+ buildEnvPatch(source = {}, actor = "") {
1825
+ const state = normalizeRuntimeState(source, actor);
1826
+ const browserProfile = buildBrowserProfilePayload(state.browserProfileCore, state.browserProfileObserved);
1827
+ const envPatch = {
1828
+ ...Object.keys(state.auth || {}).length > 0 ? { auth: state.auth } : {},
1829
+ ...Array.isArray(state.cookies) && state.cookies.length > 0 ? { cookies: state.cookies } : {},
1830
+ ...Object.keys(state.localStorage || {}).length > 0 ? { local_storage: state.localStorage } : {},
1831
+ ...Object.keys(state.sessionStorage || {}).length > 0 ? { session_storage: state.sessionStorage } : {},
1832
+ ...Object.keys(browserProfile).length > 0 ? { browser_profile: browserProfile } : {}
1833
+ };
1834
+ return Object.keys(envPatch).length > 0 ? envPatch : null;
1835
+ },
1836
+ // hasLoginState 用来区分“必须鉴权的平台”和“可匿名运行的平台”。
1837
+ hasLoginState(source = {}, actor = "") {
1838
+ const state = normalizeRuntimeState(source, actor);
1839
+ return Array.isArray(state.cookies) && state.cookies.length > 0 || Object.keys(state.localStorage || {}).length > 0 || Object.keys(state.sessionStorage || {}).length > 0 || Object.keys(state.auth || {}).length > 0;
1840
+ },
1841
+ getAuthValue(source = {}, key = "", actor = "") {
1842
+ var _a, _b;
1843
+ const state = normalizeRuntimeState(source, actor);
1844
+ const safeKey = String(key || "").trim();
1845
+ if (!safeKey) return "";
1846
+ return String((_b = (_a = state.auth) == null ? void 0 : _a[safeKey]) != null ? _b : "").trim();
1847
+ },
1848
+ rememberState(source = {}) {
1849
+ const state = normalizeRuntimeState(source);
1850
+ rememberRuntimeState(state);
1851
+ return RuntimeEnv.peekRememberedState();
1852
+ },
1853
+ peekRememberedState() {
1854
+ return rememberedRuntimeState ? deepClone(rememberedRuntimeState) : null;
1855
+ },
1856
+ getBrowserProfileCore(source = {}, actor = "") {
1857
+ const state = normalizeRuntimeState(source, actor);
1858
+ return deepClone(state.browserProfileCore || {});
1859
+ },
1860
+ setBrowserProfileCore(source = {}, core = {}, actor = "") {
1861
+ const state = normalizeRuntimeState(source, actor);
1862
+ const normalizedCore = normalizeBrowserProfileCore(core);
1863
+ state.browserProfileCore = normalizedCore;
1864
+ state.browserProfile = buildBrowserProfilePayload(normalizedCore, state.browserProfileObserved);
1865
+ if (Object.keys(state.browserProfile).length > 0) {
1866
+ state.runtime.browser_profile = state.browserProfile;
1867
+ } else {
1868
+ delete state.runtime.browser_profile;
1869
+ }
1870
+ rememberRuntimeState(state);
1871
+ return state;
1872
+ },
1873
+ // applyToPage 只负责把登录态相关字段注入页面:
1874
+ // cookies / localStorage / sessionStorage。
1875
+ // 指纹、时区、UA、viewport 的回放发生在 launch.js 启动阶段,不在这里做。
1876
+ async applyToPage(page, source = {}, options = {}) {
1877
+ if (!page) return;
1878
+ const state = normalizeRuntimeState(source, (options == null ? void 0 : options.actor) || "");
1879
+ const localStorage = state.localStorage || {};
1880
+ const sessionStorage = state.sessionStorage || {};
1881
+ const cookies = (state.cookies || []).map((cookie) => {
1882
+ const normalized = { ...cookie };
1883
+ if (!normalized.path) {
1884
+ normalized.path = "/";
1885
+ }
1886
+ if (!normalized.domain) {
1887
+ return null;
1888
+ }
1889
+ return normalized;
1890
+ }).filter(Boolean);
1891
+ if (cookies.length > 0) {
1892
+ await page.context().addCookies(cookies);
1893
+ }
1894
+ if (Object.keys(localStorage).length > 0) {
1895
+ await page.addInitScript((payload) => {
1896
+ try {
1897
+ Object.entries(payload || {}).forEach(([key, value]) => {
1898
+ if (!key) return;
1899
+ window.localStorage.setItem(key, String(value != null ? value : ""));
1900
+ });
1901
+ } catch (error) {
1902
+ }
1903
+ }, localStorage);
1904
+ }
1905
+ if (Object.keys(sessionStorage).length > 0) {
1906
+ await page.addInitScript((payload) => {
1907
+ try {
1908
+ Object.entries(payload || {}).forEach(([key, value]) => {
1909
+ if (!key) return;
1910
+ window.sessionStorage.setItem(key, String(value != null ? value : ""));
1911
+ });
1912
+ } catch (error) {
1913
+ }
1914
+ }, sessionStorage);
1915
+ }
1916
+ },
1917
+ // captureEnvPatch 在任务结束时采集最新环境快照,用于 pushSuccess / pushFailed 自动回写。
1918
+ async captureEnvPatch(page, source = {}, options = {}) {
1919
+ const state = normalizeRuntimeState(source, (options == null ? void 0 : options.actor) || "");
1920
+ const baseline = RuntimeEnv.buildEnvPatch(state) || {};
1921
+ if (!page || typeof page.evaluate !== "function" || typeof page.context !== "function") {
1922
+ return Object.keys(baseline).length > 0 ? baseline : null;
1923
+ }
1924
+ try {
1925
+ const rawSnapshot = await captureRawSnapshotFromPage(page);
1926
+ const cookieUrls = collectCookieUrlsFromSnapshot(rawSnapshot);
1927
+ let cookies = [];
1928
+ try {
1929
+ cookies = cookieUrls.length > 0 ? await page.context().cookies(cookieUrls) : await page.context().cookies();
1930
+ } catch {
1931
+ cookies = [];
1932
+ }
1933
+ const capturedPatch = RuntimeEnv.buildEnvPatchFromSnapshot(
1934
+ {
1935
+ ...rawSnapshot,
1936
+ cookies
1937
+ },
1938
+ {
1939
+ auth: state.auth,
1940
+ browserProfileCore: state.browserProfileCore
1941
+ }
1942
+ );
1943
+ return RuntimeEnv.mergeEnvPatches(baseline, capturedPatch);
1944
+ } catch {
1945
+ }
1946
+ return Object.keys(baseline).length > 0 ? baseline : null;
1947
+ }
1948
+ };
1949
+
1320
1950
  // entrys/browser.js
1321
1951
  var usePlaywrightToolKit = () => {
1322
1952
  return {
@@ -1324,6 +1954,7 @@ var usePlaywrightToolKit = () => {
1324
1954
  Display,
1325
1955
  ByPass,
1326
1956
  Constants: constants_exports,
1957
+ RuntimeEnv,
1327
1958
  $Internals: {
1328
1959
  LOG_TEMPLATES,
1329
1960
  stripAnsi