opensteer 0.6.6 → 0.6.8
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-profile-client-CGXc0-P9.d.cts +228 -0
- package/dist/browser-profile-client-DHLzMf-K.d.ts +228 -0
- package/dist/{chunk-H27BERRF.js → chunk-C6AJL5XU.js} +7828 -7641
- package/dist/{chunk-KPPOTU3D.js → chunk-LTREUXLO.js} +140 -12
- package/dist/{chunk-6B6LOYU3.js → chunk-O4HVMKX2.js} +1 -1
- package/dist/{chunk-54KNQTOL.js → chunk-UQYVMJOZ.js} +27 -12
- package/dist/cli/auth.cjs +108 -11
- package/dist/cli/auth.d.cts +1 -1
- package/dist/cli/auth.d.ts +1 -1
- package/dist/cli/auth.js +2 -2
- package/dist/cli/profile.cjs +472 -186
- package/dist/cli/profile.d.cts +2 -2
- package/dist/cli/profile.d.ts +2 -2
- package/dist/cli/profile.js +4 -4
- package/dist/cli/server.cjs +453 -167
- package/dist/cli/server.js +2 -2
- package/dist/index.cjs +482 -165
- package/dist/index.d.cts +48 -5
- package/dist/index.d.ts +48 -5
- package/dist/index.js +34 -5
- package/dist/{types-BWItZPl_.d.cts → types-Cr10igF3.d.cts} +1 -1
- package/dist/{types-BWItZPl_.d.ts → types-Cr10igF3.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/browser-profile-client-D6PuRefA.d.cts +0 -168
- package/dist/browser-profile-client-OUHaODro.d.ts +0 -168
package/dist/cli/profile.cjs
CHANGED
|
@@ -425,7 +425,7 @@ __export(profile_exports, {
|
|
|
425
425
|
});
|
|
426
426
|
module.exports = __toCommonJS(profile_exports);
|
|
427
427
|
var import_node_path4 = __toESM(require("path"), 1);
|
|
428
|
-
var
|
|
428
|
+
var import_promises5 = require("readline/promises");
|
|
429
429
|
|
|
430
430
|
// src/config.ts
|
|
431
431
|
var import_fs = __toESM(require("fs"), 1);
|
|
@@ -1324,11 +1324,8 @@ var import_crypto = require("crypto");
|
|
|
1324
1324
|
|
|
1325
1325
|
// src/browser/pool.ts
|
|
1326
1326
|
var import_node_child_process = require("child_process");
|
|
1327
|
-
var
|
|
1328
|
-
var import_promises = require("fs/promises");
|
|
1327
|
+
var import_promises2 = require("fs/promises");
|
|
1329
1328
|
var import_node_net = require("net");
|
|
1330
|
-
var import_node_os = require("os");
|
|
1331
|
-
var import_node_path = require("path");
|
|
1332
1329
|
var import_playwright = require("playwright");
|
|
1333
1330
|
|
|
1334
1331
|
// src/browser/cdp-proxy.ts
|
|
@@ -1821,18 +1818,282 @@ function listLocalChromeProfiles(userDataDir = detectChromePaths().defaultUserDa
|
|
|
1821
1818
|
}
|
|
1822
1819
|
}
|
|
1823
1820
|
|
|
1821
|
+
// src/browser/persistent-profile.ts
|
|
1822
|
+
var import_node_crypto = require("crypto");
|
|
1823
|
+
var import_node_fs = require("fs");
|
|
1824
|
+
var import_promises = require("fs/promises");
|
|
1825
|
+
var import_node_os = require("os");
|
|
1826
|
+
var import_node_path = require("path");
|
|
1827
|
+
var OPENSTEER_META_FILE = ".opensteer-meta.json";
|
|
1828
|
+
var PROCESS_STARTED_AT_MS = Math.floor(Date.now() - process.uptime() * 1e3);
|
|
1829
|
+
var PROCESS_START_TIME_TOLERANCE_MS = 1e3;
|
|
1830
|
+
var CHROME_SINGLETON_ENTRIES = /* @__PURE__ */ new Set([
|
|
1831
|
+
"SingletonCookie",
|
|
1832
|
+
"SingletonLock",
|
|
1833
|
+
"SingletonSocket",
|
|
1834
|
+
"DevToolsActivePort",
|
|
1835
|
+
"lockfile"
|
|
1836
|
+
]);
|
|
1837
|
+
var COPY_SKIP_ENTRIES = /* @__PURE__ */ new Set([
|
|
1838
|
+
...CHROME_SINGLETON_ENTRIES,
|
|
1839
|
+
OPENSTEER_META_FILE
|
|
1840
|
+
]);
|
|
1841
|
+
var SKIPPED_ROOT_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
1842
|
+
"Crash Reports",
|
|
1843
|
+
"Crashpad",
|
|
1844
|
+
"BrowserMetrics",
|
|
1845
|
+
"GrShaderCache",
|
|
1846
|
+
"ShaderCache",
|
|
1847
|
+
"GraphiteDawnCache",
|
|
1848
|
+
"component_crx_cache",
|
|
1849
|
+
"Crowd Deny",
|
|
1850
|
+
"hyphen-data",
|
|
1851
|
+
"OnDeviceHeadSuggestModel",
|
|
1852
|
+
"OptimizationGuidePredictionModels",
|
|
1853
|
+
"Segmentation Platform",
|
|
1854
|
+
"SmartCardDeviceNames",
|
|
1855
|
+
"WidevineCdm",
|
|
1856
|
+
"pnacl"
|
|
1857
|
+
]);
|
|
1858
|
+
async function getOrCreatePersistentProfile(sourceUserDataDir, profileDirectory, profilesRootDir = defaultPersistentProfilesRootDir()) {
|
|
1859
|
+
const resolvedSourceUserDataDir = expandHome(sourceUserDataDir);
|
|
1860
|
+
const targetUserDataDir = (0, import_node_path.join)(
|
|
1861
|
+
expandHome(profilesRootDir),
|
|
1862
|
+
buildPersistentProfileKey(resolvedSourceUserDataDir, profileDirectory)
|
|
1863
|
+
);
|
|
1864
|
+
const sourceProfileDir = (0, import_node_path.join)(resolvedSourceUserDataDir, profileDirectory);
|
|
1865
|
+
const metadata = buildPersistentProfileMetadata(
|
|
1866
|
+
resolvedSourceUserDataDir,
|
|
1867
|
+
profileDirectory
|
|
1868
|
+
);
|
|
1869
|
+
await (0, import_promises.mkdir)((0, import_node_path.dirname)(targetUserDataDir), { recursive: true });
|
|
1870
|
+
await cleanOrphanedTempDirs(
|
|
1871
|
+
(0, import_node_path.dirname)(targetUserDataDir),
|
|
1872
|
+
(0, import_node_path.basename)(targetUserDataDir)
|
|
1873
|
+
);
|
|
1874
|
+
if (!(0, import_node_fs.existsSync)(sourceProfileDir)) {
|
|
1875
|
+
throw new Error(
|
|
1876
|
+
`Chrome profile "${profileDirectory}" was not found in "${resolvedSourceUserDataDir}".`
|
|
1877
|
+
);
|
|
1878
|
+
}
|
|
1879
|
+
const created = await createPersistentProfileClone(
|
|
1880
|
+
resolvedSourceUserDataDir,
|
|
1881
|
+
sourceProfileDir,
|
|
1882
|
+
targetUserDataDir,
|
|
1883
|
+
profileDirectory,
|
|
1884
|
+
metadata
|
|
1885
|
+
);
|
|
1886
|
+
await ensurePersistentProfileMetadata(targetUserDataDir, metadata);
|
|
1887
|
+
return {
|
|
1888
|
+
created,
|
|
1889
|
+
userDataDir: targetUserDataDir
|
|
1890
|
+
};
|
|
1891
|
+
}
|
|
1892
|
+
async function clearPersistentProfileSingletons(userDataDir) {
|
|
1893
|
+
await Promise.all(
|
|
1894
|
+
[...CHROME_SINGLETON_ENTRIES].map(
|
|
1895
|
+
(entry) => (0, import_promises.rm)((0, import_node_path.join)(userDataDir, entry), {
|
|
1896
|
+
force: true,
|
|
1897
|
+
recursive: true
|
|
1898
|
+
}).catch(() => void 0)
|
|
1899
|
+
)
|
|
1900
|
+
);
|
|
1901
|
+
}
|
|
1902
|
+
function buildPersistentProfileKey(sourceUserDataDir, profileDirectory) {
|
|
1903
|
+
const hash = (0, import_node_crypto.createHash)("sha256").update(`${sourceUserDataDir}\0${profileDirectory}`).digest("hex").slice(0, 16);
|
|
1904
|
+
const sourceLabel = sanitizePathSegment((0, import_node_path.basename)(sourceUserDataDir) || "user-data");
|
|
1905
|
+
const profileLabel = sanitizePathSegment(profileDirectory || "Default");
|
|
1906
|
+
return `${sourceLabel}-${profileLabel}-${hash}`;
|
|
1907
|
+
}
|
|
1908
|
+
function defaultPersistentProfilesRootDir() {
|
|
1909
|
+
return (0, import_node_path.join)((0, import_node_os.homedir)(), ".opensteer", "real-browser-profiles");
|
|
1910
|
+
}
|
|
1911
|
+
function sanitizePathSegment(value) {
|
|
1912
|
+
const sanitized = value.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/-+/g, "-");
|
|
1913
|
+
return sanitized.replace(/^-|-$/g, "") || "profile";
|
|
1914
|
+
}
|
|
1915
|
+
function isProfileDirectory(userDataDir, entry) {
|
|
1916
|
+
return (0, import_node_fs.existsSync)((0, import_node_path.join)(userDataDir, entry, "Preferences"));
|
|
1917
|
+
}
|
|
1918
|
+
async function copyRootLevelEntries(sourceUserDataDir, targetUserDataDir, targetProfileDirectory) {
|
|
1919
|
+
let entries;
|
|
1920
|
+
try {
|
|
1921
|
+
entries = await (0, import_promises.readdir)(sourceUserDataDir);
|
|
1922
|
+
} catch {
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
1925
|
+
const copyTasks = [];
|
|
1926
|
+
for (const entry of entries) {
|
|
1927
|
+
if (COPY_SKIP_ENTRIES.has(entry)) continue;
|
|
1928
|
+
if (entry === targetProfileDirectory) continue;
|
|
1929
|
+
const sourcePath = (0, import_node_path.join)(sourceUserDataDir, entry);
|
|
1930
|
+
const targetPath = (0, import_node_path.join)(targetUserDataDir, entry);
|
|
1931
|
+
if ((0, import_node_fs.existsSync)(targetPath)) continue;
|
|
1932
|
+
let entryStat;
|
|
1933
|
+
try {
|
|
1934
|
+
entryStat = await (0, import_promises.stat)(sourcePath);
|
|
1935
|
+
} catch {
|
|
1936
|
+
continue;
|
|
1937
|
+
}
|
|
1938
|
+
if (entryStat.isFile()) {
|
|
1939
|
+
copyTasks.push((0, import_promises.copyFile)(sourcePath, targetPath).catch(() => void 0));
|
|
1940
|
+
} else if (entryStat.isDirectory()) {
|
|
1941
|
+
if (isProfileDirectory(sourceUserDataDir, entry)) continue;
|
|
1942
|
+
if (SKIPPED_ROOT_DIRECTORIES.has(entry)) continue;
|
|
1943
|
+
copyTasks.push(
|
|
1944
|
+
(0, import_promises.cp)(sourcePath, targetPath, { recursive: true }).catch(
|
|
1945
|
+
() => void 0
|
|
1946
|
+
)
|
|
1947
|
+
);
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
await Promise.all(copyTasks);
|
|
1951
|
+
}
|
|
1952
|
+
async function writePersistentProfileMetadata(userDataDir, metadata) {
|
|
1953
|
+
await (0, import_promises.writeFile)(
|
|
1954
|
+
(0, import_node_path.join)(userDataDir, OPENSTEER_META_FILE),
|
|
1955
|
+
JSON.stringify(metadata, null, 2)
|
|
1956
|
+
);
|
|
1957
|
+
}
|
|
1958
|
+
function buildPersistentProfileMetadata(sourceUserDataDir, profileDirectory) {
|
|
1959
|
+
return {
|
|
1960
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1961
|
+
profileDirectory,
|
|
1962
|
+
source: sourceUserDataDir
|
|
1963
|
+
};
|
|
1964
|
+
}
|
|
1965
|
+
async function createPersistentProfileClone(sourceUserDataDir, sourceProfileDir, targetUserDataDir, profileDirectory, metadata) {
|
|
1966
|
+
if ((0, import_node_fs.existsSync)(targetUserDataDir)) {
|
|
1967
|
+
return false;
|
|
1968
|
+
}
|
|
1969
|
+
const tempUserDataDir = await (0, import_promises.mkdtemp)(
|
|
1970
|
+
buildPersistentProfileTempDirPrefix(targetUserDataDir)
|
|
1971
|
+
);
|
|
1972
|
+
let published = false;
|
|
1973
|
+
try {
|
|
1974
|
+
await (0, import_promises.cp)(sourceProfileDir, (0, import_node_path.join)(tempUserDataDir, profileDirectory), {
|
|
1975
|
+
recursive: true
|
|
1976
|
+
});
|
|
1977
|
+
await copyRootLevelEntries(
|
|
1978
|
+
sourceUserDataDir,
|
|
1979
|
+
tempUserDataDir,
|
|
1980
|
+
profileDirectory
|
|
1981
|
+
);
|
|
1982
|
+
await writePersistentProfileMetadata(tempUserDataDir, metadata);
|
|
1983
|
+
try {
|
|
1984
|
+
await (0, import_promises.rename)(tempUserDataDir, targetUserDataDir);
|
|
1985
|
+
} catch (error) {
|
|
1986
|
+
if (wasProfilePublishedByAnotherProcess(error, targetUserDataDir)) {
|
|
1987
|
+
return false;
|
|
1988
|
+
}
|
|
1989
|
+
throw error;
|
|
1990
|
+
}
|
|
1991
|
+
published = true;
|
|
1992
|
+
return true;
|
|
1993
|
+
} finally {
|
|
1994
|
+
if (!published) {
|
|
1995
|
+
await (0, import_promises.rm)(tempUserDataDir, {
|
|
1996
|
+
recursive: true,
|
|
1997
|
+
force: true
|
|
1998
|
+
}).catch(() => void 0);
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
async function ensurePersistentProfileMetadata(userDataDir, metadata) {
|
|
2003
|
+
if ((0, import_node_fs.existsSync)((0, import_node_path.join)(userDataDir, OPENSTEER_META_FILE))) {
|
|
2004
|
+
return;
|
|
2005
|
+
}
|
|
2006
|
+
await writePersistentProfileMetadata(userDataDir, metadata);
|
|
2007
|
+
}
|
|
2008
|
+
function wasProfilePublishedByAnotherProcess(error, targetUserDataDir) {
|
|
2009
|
+
const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : void 0;
|
|
2010
|
+
return (0, import_node_fs.existsSync)(targetUserDataDir) && (code === "EEXIST" || code === "ENOTEMPTY" || code === "EPERM");
|
|
2011
|
+
}
|
|
2012
|
+
function buildPersistentProfileTempDirPrefix(targetUserDataDir) {
|
|
2013
|
+
return (0, import_node_path.join)(
|
|
2014
|
+
(0, import_node_path.dirname)(targetUserDataDir),
|
|
2015
|
+
`${(0, import_node_path.basename)(targetUserDataDir)}-tmp-${process.pid}-${PROCESS_STARTED_AT_MS}-`
|
|
2016
|
+
);
|
|
2017
|
+
}
|
|
2018
|
+
async function cleanOrphanedTempDirs(profilesDir, targetBaseName) {
|
|
2019
|
+
let entries;
|
|
2020
|
+
try {
|
|
2021
|
+
entries = await (0, import_promises.readdir)(profilesDir, {
|
|
2022
|
+
encoding: "utf8",
|
|
2023
|
+
withFileTypes: true
|
|
2024
|
+
});
|
|
2025
|
+
} catch {
|
|
2026
|
+
return;
|
|
2027
|
+
}
|
|
2028
|
+
const tempDirPrefix = `${targetBaseName}-tmp-`;
|
|
2029
|
+
await Promise.all(
|
|
2030
|
+
entries.map(async (entry) => {
|
|
2031
|
+
if (!entry.isDirectory() || !entry.name.startsWith(tempDirPrefix)) {
|
|
2032
|
+
return;
|
|
2033
|
+
}
|
|
2034
|
+
if (isTempDirOwnedByLiveProcess(entry.name, tempDirPrefix)) {
|
|
2035
|
+
return;
|
|
2036
|
+
}
|
|
2037
|
+
await (0, import_promises.rm)((0, import_node_path.join)(profilesDir, entry.name), {
|
|
2038
|
+
recursive: true,
|
|
2039
|
+
force: true
|
|
2040
|
+
}).catch(() => void 0);
|
|
2041
|
+
})
|
|
2042
|
+
);
|
|
2043
|
+
}
|
|
2044
|
+
function isTempDirOwnedByLiveProcess(tempDirName, tempDirPrefix) {
|
|
2045
|
+
const owner = parseTempDirOwner(tempDirName, tempDirPrefix);
|
|
2046
|
+
if (!owner) {
|
|
2047
|
+
return false;
|
|
2048
|
+
}
|
|
2049
|
+
if (owner.pid === process.pid && Math.abs(owner.processStartedAtMs - PROCESS_STARTED_AT_MS) <= PROCESS_START_TIME_TOLERANCE_MS) {
|
|
2050
|
+
return true;
|
|
2051
|
+
}
|
|
2052
|
+
return isProcessRunning(owner.pid);
|
|
2053
|
+
}
|
|
2054
|
+
function parseTempDirOwner(tempDirName, tempDirPrefix) {
|
|
2055
|
+
const remainder = tempDirName.slice(tempDirPrefix.length);
|
|
2056
|
+
const firstDashIndex = remainder.indexOf("-");
|
|
2057
|
+
const secondDashIndex = firstDashIndex === -1 ? -1 : remainder.indexOf("-", firstDashIndex + 1);
|
|
2058
|
+
if (firstDashIndex === -1 || secondDashIndex === -1) {
|
|
2059
|
+
return null;
|
|
2060
|
+
}
|
|
2061
|
+
const pid = Number.parseInt(remainder.slice(0, firstDashIndex), 10);
|
|
2062
|
+
const processStartedAtMs = Number.parseInt(
|
|
2063
|
+
remainder.slice(firstDashIndex + 1, secondDashIndex),
|
|
2064
|
+
10
|
|
2065
|
+
);
|
|
2066
|
+
if (!Number.isInteger(pid) || pid <= 0) {
|
|
2067
|
+
return null;
|
|
2068
|
+
}
|
|
2069
|
+
if (!Number.isInteger(processStartedAtMs) || processStartedAtMs <= 0) {
|
|
2070
|
+
return null;
|
|
2071
|
+
}
|
|
2072
|
+
return { pid, processStartedAtMs };
|
|
2073
|
+
}
|
|
2074
|
+
function isProcessRunning(pid) {
|
|
2075
|
+
try {
|
|
2076
|
+
process.kill(pid, 0);
|
|
2077
|
+
return true;
|
|
2078
|
+
} catch (error) {
|
|
2079
|
+
const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : void 0;
|
|
2080
|
+
return code !== "ESRCH";
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
|
|
1824
2084
|
// src/browser/pool.ts
|
|
1825
2085
|
var BrowserPool = class {
|
|
1826
2086
|
browser = null;
|
|
1827
2087
|
cdpProxy = null;
|
|
1828
2088
|
launchedProcess = null;
|
|
1829
|
-
|
|
2089
|
+
managedUserDataDir = null;
|
|
2090
|
+
persistentProfile = false;
|
|
1830
2091
|
defaults;
|
|
1831
2092
|
constructor(defaults = {}) {
|
|
1832
2093
|
this.defaults = defaults;
|
|
1833
2094
|
}
|
|
1834
2095
|
async launch(options = {}) {
|
|
1835
|
-
if (this.browser || this.cdpProxy || this.launchedProcess || this.
|
|
2096
|
+
if (this.browser || this.cdpProxy || this.launchedProcess || this.managedUserDataDir) {
|
|
1836
2097
|
await this.close();
|
|
1837
2098
|
}
|
|
1838
2099
|
const mode = options.mode ?? this.defaults.mode ?? "chromium";
|
|
@@ -1882,11 +2143,13 @@ var BrowserPool = class {
|
|
|
1882
2143
|
const browser = this.browser;
|
|
1883
2144
|
const cdpProxy = this.cdpProxy;
|
|
1884
2145
|
const launchedProcess = this.launchedProcess;
|
|
1885
|
-
const
|
|
2146
|
+
const managedUserDataDir = this.managedUserDataDir;
|
|
2147
|
+
const persistentProfile = this.persistentProfile;
|
|
1886
2148
|
this.browser = null;
|
|
1887
2149
|
this.cdpProxy = null;
|
|
1888
2150
|
this.launchedProcess = null;
|
|
1889
|
-
this.
|
|
2151
|
+
this.managedUserDataDir = null;
|
|
2152
|
+
this.persistentProfile = false;
|
|
1890
2153
|
try {
|
|
1891
2154
|
if (browser) {
|
|
1892
2155
|
await browser.close().catch(() => void 0);
|
|
@@ -1894,8 +2157,8 @@ var BrowserPool = class {
|
|
|
1894
2157
|
} finally {
|
|
1895
2158
|
cdpProxy?.close();
|
|
1896
2159
|
await killProcessTree(launchedProcess);
|
|
1897
|
-
if (
|
|
1898
|
-
await (0,
|
|
2160
|
+
if (managedUserDataDir && !persistentProfile) {
|
|
2161
|
+
await (0, import_promises2.rm)(managedUserDataDir, {
|
|
1899
2162
|
recursive: true,
|
|
1900
2163
|
force: true
|
|
1901
2164
|
}).catch(() => void 0);
|
|
@@ -1944,10 +2207,11 @@ var BrowserPool = class {
|
|
|
1944
2207
|
options.userDataDir ?? chromePaths.defaultUserDataDir
|
|
1945
2208
|
);
|
|
1946
2209
|
const profileDirectory = options.profileDirectory ?? "Default";
|
|
1947
|
-
const
|
|
2210
|
+
const persistentProfile = await getOrCreatePersistentProfile(
|
|
1948
2211
|
sourceUserDataDir,
|
|
1949
2212
|
profileDirectory
|
|
1950
2213
|
);
|
|
2214
|
+
await clearPersistentProfileSingletons(persistentProfile.userDataDir);
|
|
1951
2215
|
const debugPort = await reserveDebugPort();
|
|
1952
2216
|
const headless = resolveLaunchHeadless(
|
|
1953
2217
|
"real",
|
|
@@ -1955,7 +2219,7 @@ var BrowserPool = class {
|
|
|
1955
2219
|
this.defaults.headless
|
|
1956
2220
|
);
|
|
1957
2221
|
const launchArgs = buildRealBrowserLaunchArgs({
|
|
1958
|
-
userDataDir:
|
|
2222
|
+
userDataDir: persistentProfile.userDataDir,
|
|
1959
2223
|
profileDirectory,
|
|
1960
2224
|
debugPort,
|
|
1961
2225
|
headless
|
|
@@ -1975,24 +2239,22 @@ var BrowserPool = class {
|
|
|
1975
2239
|
timeout: options.timeout ?? 3e4
|
|
1976
2240
|
});
|
|
1977
2241
|
const { context, page } = await createOwnedBrowserContextAndPage(
|
|
1978
|
-
browser
|
|
1979
|
-
{
|
|
1980
|
-
headless,
|
|
1981
|
-
initialUrl: options.initialUrl,
|
|
1982
|
-
timeoutMs: options.timeout ?? 3e4
|
|
1983
|
-
}
|
|
2242
|
+
browser
|
|
1984
2243
|
);
|
|
2244
|
+
if (options.initialUrl) {
|
|
2245
|
+
await page.goto(options.initialUrl, {
|
|
2246
|
+
waitUntil: "domcontentloaded",
|
|
2247
|
+
timeout: options.timeout ?? 3e4
|
|
2248
|
+
});
|
|
2249
|
+
}
|
|
1985
2250
|
this.browser = browser;
|
|
1986
2251
|
this.launchedProcess = processHandle;
|
|
1987
|
-
this.
|
|
2252
|
+
this.managedUserDataDir = persistentProfile.userDataDir;
|
|
2253
|
+
this.persistentProfile = true;
|
|
1988
2254
|
return { browser, context, page, isExternal: false };
|
|
1989
2255
|
} catch (error) {
|
|
1990
2256
|
await browser?.close().catch(() => void 0);
|
|
1991
2257
|
await killProcessTree(processHandle);
|
|
1992
|
-
await (0, import_promises.rm)(tempUserDataDir, {
|
|
1993
|
-
recursive: true,
|
|
1994
|
-
force: true
|
|
1995
|
-
}).catch(() => void 0);
|
|
1996
2258
|
throw error;
|
|
1997
2259
|
}
|
|
1998
2260
|
}
|
|
@@ -2015,8 +2277,7 @@ var BrowserPool = class {
|
|
|
2015
2277
|
};
|
|
2016
2278
|
async function pickBrowserContextAndPage(browser) {
|
|
2017
2279
|
const context = getPrimaryBrowserContext(browser);
|
|
2018
|
-
const
|
|
2019
|
-
const page = pages.find((candidate) => isInspectablePageUrl2(candidate.url())) || pages[0] || await context.newPage();
|
|
2280
|
+
const page = await getAttachedPageOrCreate(context);
|
|
2020
2281
|
return { context, page };
|
|
2021
2282
|
}
|
|
2022
2283
|
function resolveLaunchHeadless(mode, requestedHeadless, defaultHeadless) {
|
|
@@ -2028,77 +2289,31 @@ function resolveLaunchHeadless(mode, requestedHeadless, defaultHeadless) {
|
|
|
2028
2289
|
}
|
|
2029
2290
|
return mode === "real";
|
|
2030
2291
|
}
|
|
2031
|
-
async function createOwnedBrowserContextAndPage(browser
|
|
2292
|
+
async function createOwnedBrowserContextAndPage(browser) {
|
|
2032
2293
|
const context = getPrimaryBrowserContext(browser);
|
|
2033
|
-
const page = await
|
|
2294
|
+
const page = await getExistingPageOrCreate(context);
|
|
2034
2295
|
return { context, page };
|
|
2035
2296
|
}
|
|
2036
|
-
async function
|
|
2037
|
-
const
|
|
2038
|
-
const
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
newWindow: !options.headless
|
|
2044
|
-
});
|
|
2045
|
-
await browserSession.send("Target.activateTarget", { targetId }).catch(() => void 0);
|
|
2046
|
-
const page = await waitForOwnedBrowserPage(context, {
|
|
2047
|
-
existingPages,
|
|
2048
|
-
targetUrl,
|
|
2049
|
-
timeoutMs: options.timeoutMs
|
|
2050
|
-
});
|
|
2051
|
-
if (targetUrl !== "about:blank") {
|
|
2052
|
-
await page.waitForLoadState("domcontentloaded", {
|
|
2053
|
-
timeout: options.timeoutMs
|
|
2054
|
-
});
|
|
2055
|
-
}
|
|
2056
|
-
await closeDisposableStartupTargets(browserSession, targetId);
|
|
2057
|
-
return page;
|
|
2058
|
-
} finally {
|
|
2059
|
-
await browserSession.detach().catch(() => void 0);
|
|
2060
|
-
}
|
|
2061
|
-
}
|
|
2062
|
-
async function closeDisposableStartupTargets(browserSession, preservedTargetId) {
|
|
2063
|
-
const response = await browserSession.send("Target.getTargets").catch(() => null);
|
|
2064
|
-
if (!response) {
|
|
2065
|
-
return;
|
|
2297
|
+
async function getAttachedPageOrCreate(context) {
|
|
2298
|
+
const pages = context.pages();
|
|
2299
|
+
const inspectablePage = pages.find(
|
|
2300
|
+
(candidate) => isInspectablePageUrl2(safePageUrl(candidate))
|
|
2301
|
+
);
|
|
2302
|
+
if (inspectablePage) {
|
|
2303
|
+
return inspectablePage;
|
|
2066
2304
|
}
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
}
|
|
2071
|
-
await browserSession.send("Target.closeTarget", { targetId: targetInfo.targetId }).catch(() => void 0);
|
|
2305
|
+
const attachedPage = pages[0];
|
|
2306
|
+
if (attachedPage) {
|
|
2307
|
+
return attachedPage;
|
|
2072
2308
|
}
|
|
2309
|
+
return await context.newPage();
|
|
2073
2310
|
}
|
|
2074
|
-
async function
|
|
2075
|
-
const
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
for (const candidate of context.pages()) {
|
|
2079
|
-
if (options.existingPages.has(candidate)) {
|
|
2080
|
-
continue;
|
|
2081
|
-
}
|
|
2082
|
-
const url = candidate.url();
|
|
2083
|
-
if (!isInspectablePageUrl2(url)) {
|
|
2084
|
-
continue;
|
|
2085
|
-
}
|
|
2086
|
-
fallbackPage ??= candidate;
|
|
2087
|
-
if (options.targetUrl === "about:blank") {
|
|
2088
|
-
return candidate;
|
|
2089
|
-
}
|
|
2090
|
-
if (pageLooselyMatchesUrl(url, options.targetUrl)) {
|
|
2091
|
-
return candidate;
|
|
2092
|
-
}
|
|
2093
|
-
}
|
|
2094
|
-
await sleep(100);
|
|
2095
|
-
}
|
|
2096
|
-
if (fallbackPage) {
|
|
2097
|
-
return fallbackPage;
|
|
2311
|
+
async function getExistingPageOrCreate(context) {
|
|
2312
|
+
const existingPage = context.pages()[0];
|
|
2313
|
+
if (existingPage) {
|
|
2314
|
+
return existingPage;
|
|
2098
2315
|
}
|
|
2099
|
-
|
|
2100
|
-
`Chrome created a target for ${options.targetUrl}, but Playwright did not expose the page in time.`
|
|
2101
|
-
);
|
|
2316
|
+
return await context.newPage();
|
|
2102
2317
|
}
|
|
2103
2318
|
function getPrimaryBrowserContext(browser) {
|
|
2104
2319
|
const contexts = browser.contexts();
|
|
@@ -2112,19 +2327,11 @@ function getPrimaryBrowserContext(browser) {
|
|
|
2112
2327
|
function isInspectablePageUrl2(url) {
|
|
2113
2328
|
return url === "about:blank" || url.startsWith("http://") || url.startsWith("https://");
|
|
2114
2329
|
}
|
|
2115
|
-
function
|
|
2116
|
-
return url === "about:blank" || url === "chrome://newtab/" || url === "chrome://new-tab-page/";
|
|
2117
|
-
}
|
|
2118
|
-
function pageLooselyMatchesUrl(currentUrl, initialUrl) {
|
|
2330
|
+
function safePageUrl(page) {
|
|
2119
2331
|
try {
|
|
2120
|
-
|
|
2121
|
-
const requested = new URL(initialUrl);
|
|
2122
|
-
if (current.href === requested.href) {
|
|
2123
|
-
return true;
|
|
2124
|
-
}
|
|
2125
|
-
return current.hostname === requested.hostname && current.pathname === requested.pathname;
|
|
2332
|
+
return page.url();
|
|
2126
2333
|
} catch {
|
|
2127
|
-
return
|
|
2334
|
+
return "";
|
|
2128
2335
|
}
|
|
2129
2336
|
}
|
|
2130
2337
|
function normalizeDiscoveryUrl(cdpUrl) {
|
|
@@ -2204,38 +2411,12 @@ async function reserveDebugPort() {
|
|
|
2204
2411
|
});
|
|
2205
2412
|
});
|
|
2206
2413
|
}
|
|
2207
|
-
async function cloneProfileToTempDir(userDataDir, profileDirectory) {
|
|
2208
|
-
const resolvedUserDataDir = expandHome(userDataDir);
|
|
2209
|
-
const tempUserDataDir = await (0, import_promises.mkdtemp)(
|
|
2210
|
-
(0, import_node_path.join)((0, import_node_os.tmpdir)(), "opensteer-real-browser-")
|
|
2211
|
-
);
|
|
2212
|
-
const sourceProfileDir = (0, import_node_path.join)(resolvedUserDataDir, profileDirectory);
|
|
2213
|
-
const targetProfileDir = (0, import_node_path.join)(tempUserDataDir, profileDirectory);
|
|
2214
|
-
if ((0, import_node_fs.existsSync)(sourceProfileDir)) {
|
|
2215
|
-
await (0, import_promises.cp)(sourceProfileDir, targetProfileDir, {
|
|
2216
|
-
recursive: true
|
|
2217
|
-
});
|
|
2218
|
-
} else {
|
|
2219
|
-
await (0, import_promises.mkdir)(targetProfileDir, {
|
|
2220
|
-
recursive: true
|
|
2221
|
-
});
|
|
2222
|
-
}
|
|
2223
|
-
const localStatePath = (0, import_node_path.join)(resolvedUserDataDir, "Local State");
|
|
2224
|
-
if ((0, import_node_fs.existsSync)(localStatePath)) {
|
|
2225
|
-
await (0, import_promises.copyFile)(localStatePath, (0, import_node_path.join)(tempUserDataDir, "Local State"));
|
|
2226
|
-
}
|
|
2227
|
-
return tempUserDataDir;
|
|
2228
|
-
}
|
|
2229
2414
|
function buildRealBrowserLaunchArgs(options) {
|
|
2230
2415
|
const args = [
|
|
2231
2416
|
`--user-data-dir=${options.userDataDir}`,
|
|
2232
2417
|
`--profile-directory=${options.profileDirectory}`,
|
|
2233
2418
|
`--remote-debugging-port=${options.debugPort}`,
|
|
2234
|
-
"--
|
|
2235
|
-
"--no-default-browser-check",
|
|
2236
|
-
"--disable-background-networking",
|
|
2237
|
-
"--disable-sync",
|
|
2238
|
-
"--disable-popup-blocking"
|
|
2419
|
+
"--disable-blink-features=AutomationControlled"
|
|
2239
2420
|
];
|
|
2240
2421
|
if (options.headless) {
|
|
2241
2422
|
args.push("--headless=new");
|
|
@@ -7053,7 +7234,7 @@ async function closeTab(context, activePage, index) {
|
|
|
7053
7234
|
}
|
|
7054
7235
|
|
|
7055
7236
|
// src/actions/cookies.ts
|
|
7056
|
-
var
|
|
7237
|
+
var import_promises3 = require("fs/promises");
|
|
7057
7238
|
async function getCookies(context, url) {
|
|
7058
7239
|
return context.cookies(url ? [url] : void 0);
|
|
7059
7240
|
}
|
|
@@ -7065,10 +7246,10 @@ async function clearCookies(context) {
|
|
|
7065
7246
|
}
|
|
7066
7247
|
async function exportCookies(context, filePath, url) {
|
|
7067
7248
|
const cookies = await context.cookies(url ? [url] : void 0);
|
|
7068
|
-
await (0,
|
|
7249
|
+
await (0, import_promises3.writeFile)(filePath, JSON.stringify(cookies, null, 2), "utf-8");
|
|
7069
7250
|
}
|
|
7070
7251
|
async function importCookies(context, filePath) {
|
|
7071
|
-
const raw = await (0,
|
|
7252
|
+
const raw = await (0, import_promises3.readFile)(filePath, "utf-8");
|
|
7072
7253
|
const cookies = JSON.parse(raw);
|
|
7073
7254
|
await context.addCookies(cookies);
|
|
7074
7255
|
}
|
|
@@ -7819,31 +8000,31 @@ function buildVariantDescriptorFromCluster(descriptors) {
|
|
|
7819
8000
|
const keyStats = /* @__PURE__ */ new Map();
|
|
7820
8001
|
for (const descriptor of descriptors) {
|
|
7821
8002
|
for (const field of descriptor.fields) {
|
|
7822
|
-
const
|
|
8003
|
+
const stat2 = keyStats.get(field.path) || {
|
|
7823
8004
|
indices: /* @__PURE__ */ new Set(),
|
|
7824
8005
|
pathNodes: [],
|
|
7825
8006
|
attributes: [],
|
|
7826
8007
|
sources: []
|
|
7827
8008
|
};
|
|
7828
|
-
|
|
8009
|
+
stat2.indices.add(descriptor.index);
|
|
7829
8010
|
if (isPersistedValueNode(field.node)) {
|
|
7830
|
-
|
|
7831
|
-
|
|
8011
|
+
stat2.pathNodes.push(field.node.$path);
|
|
8012
|
+
stat2.attributes.push(field.node.attribute);
|
|
7832
8013
|
} else if (isPersistedSourceNode(field.node)) {
|
|
7833
|
-
|
|
8014
|
+
stat2.sources.push("current_url");
|
|
7834
8015
|
}
|
|
7835
|
-
keyStats.set(field.path,
|
|
8016
|
+
keyStats.set(field.path, stat2);
|
|
7836
8017
|
}
|
|
7837
8018
|
}
|
|
7838
8019
|
const mergedFields = [];
|
|
7839
|
-
for (const [fieldPath,
|
|
7840
|
-
if (
|
|
7841
|
-
if (
|
|
8020
|
+
for (const [fieldPath, stat2] of keyStats) {
|
|
8021
|
+
if (stat2.indices.size < threshold) continue;
|
|
8022
|
+
if (stat2.pathNodes.length >= threshold) {
|
|
7842
8023
|
let mergedFieldPath = null;
|
|
7843
|
-
if (
|
|
7844
|
-
mergedFieldPath = sanitizeElementPath(
|
|
8024
|
+
if (stat2.pathNodes.length === 1) {
|
|
8025
|
+
mergedFieldPath = sanitizeElementPath(stat2.pathNodes[0]);
|
|
7845
8026
|
} else {
|
|
7846
|
-
mergedFieldPath = mergeElementPathsByMajority(
|
|
8027
|
+
mergedFieldPath = mergeElementPathsByMajority(stat2.pathNodes);
|
|
7847
8028
|
}
|
|
7848
8029
|
if (!mergedFieldPath) continue;
|
|
7849
8030
|
if (clusterSize === 1) {
|
|
@@ -7856,17 +8037,17 @@ function buildVariantDescriptorFromCluster(descriptors) {
|
|
|
7856
8037
|
mergedFieldPath,
|
|
7857
8038
|
"field"
|
|
7858
8039
|
);
|
|
7859
|
-
const attrThreshold =
|
|
8040
|
+
const attrThreshold = stat2.pathNodes.length === 1 ? 1 : majorityThreshold(stat2.pathNodes.length);
|
|
7860
8041
|
mergedFields.push({
|
|
7861
8042
|
path: fieldPath,
|
|
7862
8043
|
node: createValueNode({
|
|
7863
8044
|
elementPath: mergedFieldPath,
|
|
7864
|
-
attribute: pickModeString(
|
|
8045
|
+
attribute: pickModeString(stat2.attributes, attrThreshold)
|
|
7865
8046
|
})
|
|
7866
8047
|
});
|
|
7867
8048
|
continue;
|
|
7868
8049
|
}
|
|
7869
|
-
const dominantSource = pickModeString(
|
|
8050
|
+
const dominantSource = pickModeString(stat2.sources, threshold);
|
|
7870
8051
|
if (dominantSource === "current_url") {
|
|
7871
8052
|
mergedFields.push({
|
|
7872
8053
|
path: fieldPath,
|
|
@@ -8735,7 +8916,96 @@ function stripPositionClauses2(path7) {
|
|
|
8735
8916
|
}
|
|
8736
8917
|
|
|
8737
8918
|
// src/cloud/contracts.ts
|
|
8919
|
+
var cloudActionMethods = [
|
|
8920
|
+
"goto",
|
|
8921
|
+
"snapshot",
|
|
8922
|
+
"screenshot",
|
|
8923
|
+
"state",
|
|
8924
|
+
"click",
|
|
8925
|
+
"dblclick",
|
|
8926
|
+
"rightclick",
|
|
8927
|
+
"hover",
|
|
8928
|
+
"input",
|
|
8929
|
+
"select",
|
|
8930
|
+
"scroll",
|
|
8931
|
+
"tabs",
|
|
8932
|
+
"newTab",
|
|
8933
|
+
"switchTab",
|
|
8934
|
+
"closeTab",
|
|
8935
|
+
"getCookies",
|
|
8936
|
+
"setCookie",
|
|
8937
|
+
"clearCookies",
|
|
8938
|
+
"pressKey",
|
|
8939
|
+
"type",
|
|
8940
|
+
"getElementText",
|
|
8941
|
+
"getElementValue",
|
|
8942
|
+
"getElementAttributes",
|
|
8943
|
+
"getElementBoundingBox",
|
|
8944
|
+
"getHtml",
|
|
8945
|
+
"getTitle",
|
|
8946
|
+
"uploadFile",
|
|
8947
|
+
"exportCookies",
|
|
8948
|
+
"importCookies",
|
|
8949
|
+
"waitForText",
|
|
8950
|
+
"extract",
|
|
8951
|
+
"extractFromPlan",
|
|
8952
|
+
"clearCache"
|
|
8953
|
+
];
|
|
8954
|
+
var cloudErrorCodes = [
|
|
8955
|
+
"CLOUD_AUTH_FAILED",
|
|
8956
|
+
"CLOUD_SESSION_NOT_FOUND",
|
|
8957
|
+
"CLOUD_SESSION_CLOSED",
|
|
8958
|
+
"CLOUD_UNSUPPORTED_METHOD",
|
|
8959
|
+
"CLOUD_INVALID_REQUEST",
|
|
8960
|
+
"CLOUD_MODEL_NOT_ALLOWED",
|
|
8961
|
+
"CLOUD_ACTION_FAILED",
|
|
8962
|
+
"CLOUD_CAPACITY_EXHAUSTED",
|
|
8963
|
+
"CLOUD_RUNTIME_UNAVAILABLE",
|
|
8964
|
+
"CLOUD_RUNTIME_MISMATCH",
|
|
8965
|
+
"CLOUD_SESSION_STALE",
|
|
8966
|
+
"CLOUD_CONTROL_PLANE_ERROR",
|
|
8967
|
+
"CLOUD_CONTRACT_MISMATCH",
|
|
8968
|
+
"CLOUD_PROXY_UNAVAILABLE",
|
|
8969
|
+
"CLOUD_PROXY_REQUIRED",
|
|
8970
|
+
"CLOUD_BILLING_LIMIT_REACHED",
|
|
8971
|
+
"CLOUD_RATE_LIMITED",
|
|
8972
|
+
"CLOUD_BROWSER_PROFILE_NOT_FOUND",
|
|
8973
|
+
"CLOUD_BROWSER_PROFILE_BUSY",
|
|
8974
|
+
"CLOUD_BROWSER_PROFILE_DISABLED",
|
|
8975
|
+
"CLOUD_BROWSER_PROFILE_PROXY_UNAVAILABLE",
|
|
8976
|
+
"CLOUD_BROWSER_PROFILE_SYNC_FAILED",
|
|
8977
|
+
"CLOUD_INTERNAL"
|
|
8978
|
+
];
|
|
8979
|
+
var cloudSessionStatuses = [
|
|
8980
|
+
"provisioning",
|
|
8981
|
+
"active",
|
|
8982
|
+
"closing",
|
|
8983
|
+
"closed",
|
|
8984
|
+
"failed"
|
|
8985
|
+
];
|
|
8738
8986
|
var cloudSessionContractVersion = "v3";
|
|
8987
|
+
var cloudSessionSourceTypes = [
|
|
8988
|
+
"agent-thread",
|
|
8989
|
+
"agent-run",
|
|
8990
|
+
"project-agent-run",
|
|
8991
|
+
"local-cloud",
|
|
8992
|
+
"manual"
|
|
8993
|
+
];
|
|
8994
|
+
var cloudActionMethodSet = new Set(cloudActionMethods);
|
|
8995
|
+
var cloudErrorCodeSet = new Set(cloudErrorCodes);
|
|
8996
|
+
var cloudSessionSourceTypeSet = new Set(
|
|
8997
|
+
cloudSessionSourceTypes
|
|
8998
|
+
);
|
|
8999
|
+
var cloudSessionStatusSet = new Set(cloudSessionStatuses);
|
|
9000
|
+
function isCloudErrorCode(value) {
|
|
9001
|
+
return typeof value === "string" && cloudErrorCodeSet.has(value);
|
|
9002
|
+
}
|
|
9003
|
+
function isCloudSessionSourceType(value) {
|
|
9004
|
+
return typeof value === "string" && cloudSessionSourceTypeSet.has(value);
|
|
9005
|
+
}
|
|
9006
|
+
function isCloudSessionStatus(value) {
|
|
9007
|
+
return typeof value === "string" && cloudSessionStatusSet.has(value);
|
|
9008
|
+
}
|
|
8739
9009
|
|
|
8740
9010
|
// src/cloud/action-ws-client.ts
|
|
8741
9011
|
var import_ws2 = __toESM(require("ws"), 1);
|
|
@@ -8766,6 +9036,13 @@ function cloudNotLaunchedError() {
|
|
|
8766
9036
|
);
|
|
8767
9037
|
}
|
|
8768
9038
|
|
|
9039
|
+
// src/cloud/ws-url.ts
|
|
9040
|
+
function withTokenQuery(wsUrl, token) {
|
|
9041
|
+
const url = new URL(wsUrl);
|
|
9042
|
+
url.searchParams.set("token", token);
|
|
9043
|
+
return url.toString();
|
|
9044
|
+
}
|
|
9045
|
+
|
|
8769
9046
|
// src/cloud/action-ws-client.ts
|
|
8770
9047
|
var ActionWsClient = class _ActionWsClient {
|
|
8771
9048
|
ws;
|
|
@@ -8894,11 +9171,6 @@ function rawDataToUtf8(raw) {
|
|
|
8894
9171
|
if (Array.isArray(raw)) return Buffer.concat(raw).toString("utf8");
|
|
8895
9172
|
return raw.toString("utf8");
|
|
8896
9173
|
}
|
|
8897
|
-
function withTokenQuery(wsUrl, token) {
|
|
8898
|
-
const url = new URL(wsUrl);
|
|
8899
|
-
url.searchParams.set("token", token);
|
|
8900
|
-
return url.toString();
|
|
8901
|
-
}
|
|
8902
9174
|
|
|
8903
9175
|
// src/cloud/local-cache-sync.ts
|
|
8904
9176
|
var import_fs4 = __toESM(require("fs"), 1);
|
|
@@ -9038,7 +9310,7 @@ function dedupeNewest(entries) {
|
|
|
9038
9310
|
var import_playwright2 = require("playwright");
|
|
9039
9311
|
var CloudCdpClient = class {
|
|
9040
9312
|
async connect(args) {
|
|
9041
|
-
const endpoint =
|
|
9313
|
+
const endpoint = withTokenQuery(args.wsUrl, args.token);
|
|
9042
9314
|
let browser;
|
|
9043
9315
|
try {
|
|
9044
9316
|
browser = await import_playwright2.chromium.connectOverCDP(endpoint);
|
|
@@ -9067,7 +9339,7 @@ function selectPreferredContextPage(browser, contexts) {
|
|
|
9067
9339
|
let aboutBlankCandidate = null;
|
|
9068
9340
|
for (const context of contexts) {
|
|
9069
9341
|
for (const page of context.pages()) {
|
|
9070
|
-
const url =
|
|
9342
|
+
const url = safePageUrl2(page);
|
|
9071
9343
|
if (!isInternalOrEmptyUrl(url)) {
|
|
9072
9344
|
return { browser, context, page };
|
|
9073
9345
|
}
|
|
@@ -9078,7 +9350,7 @@ function selectPreferredContextPage(browser, contexts) {
|
|
|
9078
9350
|
}
|
|
9079
9351
|
return aboutBlankCandidate;
|
|
9080
9352
|
}
|
|
9081
|
-
function
|
|
9353
|
+
function safePageUrl2(page) {
|
|
9082
9354
|
try {
|
|
9083
9355
|
return page.url();
|
|
9084
9356
|
} catch {
|
|
@@ -9090,11 +9362,6 @@ function isInternalOrEmptyUrl(url) {
|
|
|
9090
9362
|
if (url === "about:blank") return true;
|
|
9091
9363
|
return url.startsWith("chrome://") || url.startsWith("devtools://") || url.startsWith("edge://");
|
|
9092
9364
|
}
|
|
9093
|
-
function withTokenQuery2(wsUrl, token) {
|
|
9094
|
-
const url = new URL(wsUrl);
|
|
9095
|
-
url.searchParams.set("token", token);
|
|
9096
|
-
return url.toString();
|
|
9097
|
-
}
|
|
9098
9365
|
|
|
9099
9366
|
// src/utils/strip-trailing-slashes.ts
|
|
9100
9367
|
function stripTrailingSlashes(value) {
|
|
@@ -9131,10 +9398,7 @@ async function parseCloudHttpError(response) {
|
|
|
9131
9398
|
return new OpensteerCloudError(code, message, response.status, body?.details);
|
|
9132
9399
|
}
|
|
9133
9400
|
function toCloudErrorCode(code) {
|
|
9134
|
-
|
|
9135
|
-
return code;
|
|
9136
|
-
}
|
|
9137
|
-
return "CLOUD_TRANSPORT_ERROR";
|
|
9401
|
+
return isCloudErrorCode(code) ? code : "CLOUD_TRANSPORT_ERROR";
|
|
9138
9402
|
}
|
|
9139
9403
|
|
|
9140
9404
|
// src/cloud/session-client.ts
|
|
@@ -9241,7 +9505,12 @@ function parseCreateResponse(body, status) {
|
|
|
9241
9505
|
status,
|
|
9242
9506
|
"cloudSession"
|
|
9243
9507
|
),
|
|
9244
|
-
state:
|
|
9508
|
+
state: requireSessionStatus(
|
|
9509
|
+
cloudSessionRoot,
|
|
9510
|
+
"state",
|
|
9511
|
+
status,
|
|
9512
|
+
"cloudSession"
|
|
9513
|
+
),
|
|
9245
9514
|
createdAt: requireNumber(cloudSessionRoot, "createdAt", status, "cloudSession"),
|
|
9246
9515
|
sourceType: requireSourceType(cloudSessionRoot, "sourceType", status, "cloudSession"),
|
|
9247
9516
|
sourceRef: optionalString(cloudSessionRoot, "sourceRef", status, "cloudSession"),
|
|
@@ -9329,7 +9598,7 @@ function optionalNumber(source, field, status, parent) {
|
|
|
9329
9598
|
}
|
|
9330
9599
|
function requireSourceType(source, field, status, parent) {
|
|
9331
9600
|
const value = source[field];
|
|
9332
|
-
if (value
|
|
9601
|
+
if (isCloudSessionSourceType(value)) {
|
|
9333
9602
|
return value;
|
|
9334
9603
|
}
|
|
9335
9604
|
throw new OpensteerCloudError(
|
|
@@ -9337,13 +9606,30 @@ function requireSourceType(source, field, status, parent) {
|
|
|
9337
9606
|
`Invalid cloud session create response: ${formatFieldPath(
|
|
9338
9607
|
field,
|
|
9339
9608
|
parent
|
|
9340
|
-
)} must be one of
|
|
9609
|
+
)} must be one of ${formatAllowedValues(cloudSessionSourceTypes)}.`,
|
|
9610
|
+
status
|
|
9611
|
+
);
|
|
9612
|
+
}
|
|
9613
|
+
function requireSessionStatus(source, field, status, parent) {
|
|
9614
|
+
const value = source[field];
|
|
9615
|
+
if (isCloudSessionStatus(value)) {
|
|
9616
|
+
return value;
|
|
9617
|
+
}
|
|
9618
|
+
throw new OpensteerCloudError(
|
|
9619
|
+
"CLOUD_CONTRACT_MISMATCH",
|
|
9620
|
+
`Invalid cloud session create response: ${formatFieldPath(
|
|
9621
|
+
field,
|
|
9622
|
+
parent
|
|
9623
|
+
)} must be one of ${formatAllowedValues(cloudSessionStatuses)}.`,
|
|
9341
9624
|
status
|
|
9342
9625
|
);
|
|
9343
9626
|
}
|
|
9344
9627
|
function formatFieldPath(field, parent) {
|
|
9345
9628
|
return parent ? `"${parent}.${field}"` : `"${field}"`;
|
|
9346
9629
|
}
|
|
9630
|
+
function formatAllowedValues(values) {
|
|
9631
|
+
return values.map((value) => `"${value}"`).join(", ");
|
|
9632
|
+
}
|
|
9347
9633
|
function zeroImportResponse() {
|
|
9348
9634
|
return {
|
|
9349
9635
|
imported: 0,
|
|
@@ -14498,8 +14784,8 @@ function buildLocalRunId(namespace) {
|
|
|
14498
14784
|
// src/browser/chromium-profile.ts
|
|
14499
14785
|
var import_node_util = require("util");
|
|
14500
14786
|
var import_node_child_process3 = require("child_process");
|
|
14501
|
-
var
|
|
14502
|
-
var
|
|
14787
|
+
var import_node_crypto2 = require("crypto");
|
|
14788
|
+
var import_promises4 = require("fs/promises");
|
|
14503
14789
|
var import_node_fs2 = require("fs");
|
|
14504
14790
|
var import_node_path2 = require("path");
|
|
14505
14791
|
var import_node_os2 = require("os");
|
|
@@ -14724,7 +15010,7 @@ function resolveCookieDbPath(profileDir) {
|
|
|
14724
15010
|
return null;
|
|
14725
15011
|
}
|
|
14726
15012
|
async function selectProfileDirFromUserDataDir(userDataDir) {
|
|
14727
|
-
const entries = await (0,
|
|
15013
|
+
const entries = await (0, import_promises4.readdir)(userDataDir, {
|
|
14728
15014
|
withFileTypes: true
|
|
14729
15015
|
}).catch(() => []);
|
|
14730
15016
|
const candidates = entries.filter((entry) => entry.isDirectory()).map((entry) => (0, import_node_path2.join)(userDataDir, entry.name)).filter((entryPath) => resolveCookieDbPath(entryPath));
|
|
@@ -14811,20 +15097,20 @@ function detectChromiumBrand(location) {
|
|
|
14811
15097
|
return DEFAULT_CHROMIUM_BRAND;
|
|
14812
15098
|
}
|
|
14813
15099
|
async function createSqliteSnapshot(dbPath) {
|
|
14814
|
-
const snapshotDir = await (0,
|
|
15100
|
+
const snapshotDir = await (0, import_promises4.mkdtemp)((0, import_node_path2.join)((0, import_node_os2.tmpdir)(), "opensteer-cookie-db-"));
|
|
14815
15101
|
const snapshotPath = (0, import_node_path2.join)(snapshotDir, "Cookies");
|
|
14816
|
-
await (0,
|
|
15102
|
+
await (0, import_promises4.copyFile)(dbPath, snapshotPath);
|
|
14817
15103
|
for (const suffix of ["-wal", "-shm", "-journal"]) {
|
|
14818
15104
|
const source = `${dbPath}${suffix}`;
|
|
14819
15105
|
if (!(0, import_node_fs2.existsSync)(source)) {
|
|
14820
15106
|
continue;
|
|
14821
15107
|
}
|
|
14822
|
-
await (0,
|
|
15108
|
+
await (0, import_promises4.copyFile)(source, `${snapshotPath}${suffix}`);
|
|
14823
15109
|
}
|
|
14824
15110
|
return {
|
|
14825
15111
|
snapshotPath,
|
|
14826
15112
|
cleanup: async () => {
|
|
14827
|
-
await (0,
|
|
15113
|
+
await (0, import_promises4.rm)(snapshotDir, { recursive: true, force: true });
|
|
14828
15114
|
}
|
|
14829
15115
|
};
|
|
14830
15116
|
}
|
|
@@ -14870,7 +15156,7 @@ function stripDomainHashPrefix(buffer, hostKey) {
|
|
|
14870
15156
|
if (buffer.length < 32) {
|
|
14871
15157
|
return buffer;
|
|
14872
15158
|
}
|
|
14873
|
-
const domainHash = (0,
|
|
15159
|
+
const domainHash = (0, import_node_crypto2.createHash)("sha256").update(hostKey, "utf8").digest();
|
|
14874
15160
|
if (buffer.subarray(0, 32).equals(domainHash)) {
|
|
14875
15161
|
return buffer.subarray(32);
|
|
14876
15162
|
}
|
|
@@ -14879,7 +15165,7 @@ function stripDomainHashPrefix(buffer, hostKey) {
|
|
|
14879
15165
|
function decryptChromiumAes128CbcValue(encryptedValue, key, hostKey) {
|
|
14880
15166
|
const ciphertext = encryptedValue.length > 3 && encryptedValue[0] === 118 && encryptedValue[1] === 49 && (encryptedValue[2] === 48 || encryptedValue[2] === 49) ? encryptedValue.subarray(3) : encryptedValue;
|
|
14881
15167
|
const iv = Buffer.alloc(AES_BLOCK_BYTES, " ");
|
|
14882
|
-
const decipher = (0,
|
|
15168
|
+
const decipher = (0, import_node_crypto2.createDecipheriv)("aes-128-cbc", key, iv);
|
|
14883
15169
|
const plaintext = Buffer.concat([
|
|
14884
15170
|
decipher.update(ciphertext),
|
|
14885
15171
|
decipher.final()
|
|
@@ -14892,7 +15178,7 @@ function decryptChromiumAes256GcmValue(encryptedValue, key) {
|
|
|
14892
15178
|
const nonce = encryptedValue.subarray(3, 15);
|
|
14893
15179
|
const ciphertext = encryptedValue.subarray(15, encryptedValue.length - 16);
|
|
14894
15180
|
const authTag = encryptedValue.subarray(encryptedValue.length - 16);
|
|
14895
|
-
const decipher = (0,
|
|
15181
|
+
const decipher = (0, import_node_crypto2.createDecipheriv)("aes-256-gcm", key, nonce);
|
|
14896
15182
|
decipher.setAuthTag(authTag);
|
|
14897
15183
|
return Buffer.concat([
|
|
14898
15184
|
decipher.update(ciphertext),
|
|
@@ -14929,7 +15215,7 @@ async function buildChromiumDecryptor(location) {
|
|
|
14929
15215
|
`Unable to read ${brand.macService} from macOS Keychain.`
|
|
14930
15216
|
);
|
|
14931
15217
|
}
|
|
14932
|
-
const key = (0,
|
|
15218
|
+
const key = (0, import_node_crypto2.pbkdf2Sync)(password, KEY_SALT, MAC_KEY_ITERATIONS, KEY_LENGTH, "sha1");
|
|
14933
15219
|
return async (row) => decryptChromiumAes128CbcValue(
|
|
14934
15220
|
Buffer.from(row.encrypted_value || "", "hex"),
|
|
14935
15221
|
key,
|
|
@@ -14940,7 +15226,7 @@ async function buildChromiumDecryptor(location) {
|
|
|
14940
15226
|
const brand = detectChromiumBrand(location);
|
|
14941
15227
|
const keychainStore = createKeychainStore();
|
|
14942
15228
|
const password = keychainStore?.get(brand.macService, brand.macAccount) ?? brand.linuxApplications.map((application) => keychainStore?.get(application, application) ?? null).find(Boolean) ?? null;
|
|
14943
|
-
const key = (0,
|
|
15229
|
+
const key = (0, import_node_crypto2.pbkdf2Sync)(
|
|
14944
15230
|
password || "peanuts",
|
|
14945
15231
|
KEY_SALT,
|
|
14946
15232
|
LINUX_KEY_ITERATIONS,
|
|
@@ -14960,7 +15246,7 @@ async function buildChromiumDecryptor(location) {
|
|
|
14960
15246
|
);
|
|
14961
15247
|
}
|
|
14962
15248
|
const localState = JSON.parse(
|
|
14963
|
-
await (0,
|
|
15249
|
+
await (0, import_promises4.readFile)(location.localStatePath, "utf8")
|
|
14964
15250
|
);
|
|
14965
15251
|
const encryptedKeyBase64 = localState.os_crypt?.encrypted_key;
|
|
14966
15252
|
if (!encryptedKeyBase64) {
|
|
@@ -15054,18 +15340,18 @@ async function loadCookiesFromSqlite(location) {
|
|
|
15054
15340
|
}
|
|
15055
15341
|
}
|
|
15056
15342
|
async function loadCookiesFromBrowserSnapshot(location, options) {
|
|
15057
|
-
const snapshotRootDir = await (0,
|
|
15343
|
+
const snapshotRootDir = await (0, import_promises4.mkdtemp)((0, import_node_path2.join)((0, import_node_os2.tmpdir)(), "opensteer-profile-"));
|
|
15058
15344
|
const snapshotProfileDir = (0, import_node_path2.join)(
|
|
15059
15345
|
snapshotRootDir,
|
|
15060
15346
|
(0, import_node_path2.basename)(location.profileDir)
|
|
15061
15347
|
);
|
|
15062
15348
|
let context = null;
|
|
15063
15349
|
try {
|
|
15064
|
-
await (0,
|
|
15350
|
+
await (0, import_promises4.cp)(location.profileDir, snapshotProfileDir, {
|
|
15065
15351
|
recursive: true
|
|
15066
15352
|
});
|
|
15067
15353
|
if (location.localStatePath) {
|
|
15068
|
-
await (0,
|
|
15354
|
+
await (0, import_promises4.copyFile)(location.localStatePath, (0, import_node_path2.join)(snapshotRootDir, "Local State"));
|
|
15069
15355
|
}
|
|
15070
15356
|
const brand = detectChromiumBrand(location);
|
|
15071
15357
|
const args = [`--profile-directory=${(0, import_node_path2.basename)(snapshotProfileDir)}`];
|
|
@@ -15078,7 +15364,7 @@ async function loadCookiesFromBrowserSnapshot(location, options) {
|
|
|
15078
15364
|
return await context.cookies();
|
|
15079
15365
|
} finally {
|
|
15080
15366
|
await context?.close().catch(() => void 0);
|
|
15081
|
-
await (0,
|
|
15367
|
+
await (0, import_promises4.rm)(snapshotRootDir, { recursive: true, force: true });
|
|
15082
15368
|
}
|
|
15083
15369
|
}
|
|
15084
15370
|
function isMissingSqliteBinary(error) {
|
|
@@ -15321,7 +15607,7 @@ function toResolvedCloudCredential(source, credential) {
|
|
|
15321
15607
|
}
|
|
15322
15608
|
|
|
15323
15609
|
// src/auth/machine-credential-store.ts
|
|
15324
|
-
var
|
|
15610
|
+
var import_node_crypto3 = require("crypto");
|
|
15325
15611
|
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
15326
15612
|
var import_node_os3 = __toESM(require("os"), 1);
|
|
15327
15613
|
var import_node_path3 = __toESM(require("path"), 1);
|
|
@@ -15469,7 +15755,7 @@ function createMachineCredentialStore(options = {}) {
|
|
|
15469
15755
|
}
|
|
15470
15756
|
function resolveCredentialSlot(authDir, target) {
|
|
15471
15757
|
const normalizedBaseUrl = normalizeCredentialUrl(target.baseUrl);
|
|
15472
|
-
const storageKey = (0,
|
|
15758
|
+
const storageKey = (0, import_node_crypto3.createHash)("sha256").update(normalizedBaseUrl).digest("hex").slice(0, 24);
|
|
15473
15759
|
return {
|
|
15474
15760
|
keychainAccount: `${KEYCHAIN_ACCOUNT_PREFIX}${storageKey}`,
|
|
15475
15761
|
metadataPath: import_node_path3.default.join(authDir, `cli-login.${storageKey}.json`),
|
|
@@ -16394,7 +16680,7 @@ function createDefaultDeps() {
|
|
|
16394
16680
|
loadLocalProfileCookies: (profileDir, options) => loadCookiesFromLocalProfileDir(profileDir, options),
|
|
16395
16681
|
isInteractive: () => Boolean(process.stdin.isTTY && process.stdout.isTTY),
|
|
16396
16682
|
confirm: async (message) => {
|
|
16397
|
-
const rl = (0,
|
|
16683
|
+
const rl = (0, import_promises5.createInterface)({
|
|
16398
16684
|
input: process.stdin,
|
|
16399
16685
|
output: process.stderr
|
|
16400
16686
|
});
|