opensteer 0.4.5 → 0.4.7
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/CHANGELOG.md +4 -3
- package/README.md +4 -4
- package/bin/opensteer.mjs +5 -6
- package/dist/{chunk-2NKR4JZ6.js → chunk-PIJI7FBH.js} +1121 -308
- package/dist/cli/server.cjs +1117 -304
- package/dist/cli/server.js +3 -2
- package/dist/index.cjs +1127 -313
- package/dist/index.d.cts +69 -42
- package/dist/index.d.ts +69 -42
- package/dist/index.js +13 -11
- package/package.json +73 -80
package/dist/cli/server.cjs
CHANGED
|
@@ -752,7 +752,7 @@ var BrowserPool = class {
|
|
|
752
752
|
const context = contexts[0];
|
|
753
753
|
const pages = context.pages();
|
|
754
754
|
const page = pages.length > 0 ? pages[0] : await context.newPage();
|
|
755
|
-
return { browser, context, page,
|
|
755
|
+
return { browser, context, page, isExternal: true };
|
|
756
756
|
} catch (error) {
|
|
757
757
|
if (browser) {
|
|
758
758
|
await browser.close().catch(() => void 0);
|
|
@@ -787,7 +787,7 @@ var BrowserPool = class {
|
|
|
787
787
|
context = await browser.newContext(options.context || {});
|
|
788
788
|
page = await context.newPage();
|
|
789
789
|
}
|
|
790
|
-
return { browser, context, page,
|
|
790
|
+
return { browser, context, page, isExternal: false };
|
|
791
791
|
}
|
|
792
792
|
async launchSandbox(options) {
|
|
793
793
|
const browser = await import_playwright.chromium.launch({
|
|
@@ -798,7 +798,7 @@ var BrowserPool = class {
|
|
|
798
798
|
const context = await browser.newContext(options.context || {});
|
|
799
799
|
const page = await context.newPage();
|
|
800
800
|
this.browser = browser;
|
|
801
|
-
return { browser, context, page,
|
|
801
|
+
return { browser, context, page, isExternal: false };
|
|
802
802
|
}
|
|
803
803
|
};
|
|
804
804
|
|
|
@@ -869,28 +869,27 @@ function assertNoLegacyAiConfig(source, config) {
|
|
|
869
869
|
);
|
|
870
870
|
}
|
|
871
871
|
}
|
|
872
|
-
function
|
|
872
|
+
function assertNoLegacyRuntimeConfig(source, config) {
|
|
873
873
|
if (!config || typeof config !== "object") return;
|
|
874
874
|
const configRecord = config;
|
|
875
875
|
if (hasOwn(configRecord, "runtime")) {
|
|
876
876
|
throw new Error(
|
|
877
|
-
`Legacy "runtime" config is no longer supported in ${source}. Use top-level "
|
|
877
|
+
`Legacy "runtime" config is no longer supported in ${source}. Use top-level "cloud" instead.`
|
|
878
878
|
);
|
|
879
879
|
}
|
|
880
|
-
if (hasOwn(configRecord, "
|
|
880
|
+
if (hasOwn(configRecord, "mode")) {
|
|
881
881
|
throw new Error(
|
|
882
|
-
`Top-level "
|
|
882
|
+
`Top-level "mode" config is no longer supported in ${source}. Use "cloud: true" to enable cloud mode.`
|
|
883
883
|
);
|
|
884
884
|
}
|
|
885
|
-
|
|
886
|
-
if (typeof remoteValue === "boolean") {
|
|
885
|
+
if (hasOwn(configRecord, "remote")) {
|
|
887
886
|
throw new Error(
|
|
888
|
-
`
|
|
887
|
+
`Top-level "remote" config is no longer supported in ${source}. Use "cloud" options instead.`
|
|
889
888
|
);
|
|
890
889
|
}
|
|
891
|
-
if (
|
|
890
|
+
if (hasOwn(configRecord, "apiKey")) {
|
|
892
891
|
throw new Error(
|
|
893
|
-
`
|
|
892
|
+
`Top-level "apiKey" config is not supported in ${source}. Use "cloud.apiKey" instead.`
|
|
894
893
|
);
|
|
895
894
|
}
|
|
896
895
|
}
|
|
@@ -936,20 +935,52 @@ function parseNumber(value) {
|
|
|
936
935
|
if (!Number.isFinite(parsed)) return void 0;
|
|
937
936
|
return parsed;
|
|
938
937
|
}
|
|
939
|
-
function
|
|
938
|
+
function parseRuntimeMode(value, source) {
|
|
940
939
|
if (value == null) return void 0;
|
|
941
940
|
if (typeof value !== "string") {
|
|
942
941
|
throw new Error(
|
|
943
|
-
`Invalid ${source} value "${String(value)}". Use "local" or "
|
|
942
|
+
`Invalid ${source} value "${String(value)}". Use "local" or "cloud".`
|
|
944
943
|
);
|
|
945
944
|
}
|
|
946
945
|
const normalized = value.trim().toLowerCase();
|
|
947
946
|
if (!normalized) return void 0;
|
|
948
|
-
if (normalized === "local" || normalized === "
|
|
947
|
+
if (normalized === "local" || normalized === "cloud") {
|
|
949
948
|
return normalized;
|
|
950
949
|
}
|
|
951
950
|
throw new Error(
|
|
952
|
-
`Invalid ${source} value "${value}". Use "local" or "
|
|
951
|
+
`Invalid ${source} value "${value}". Use "local" or "cloud".`
|
|
952
|
+
);
|
|
953
|
+
}
|
|
954
|
+
function parseAuthScheme(value, source) {
|
|
955
|
+
if (value == null) return void 0;
|
|
956
|
+
if (typeof value !== "string") {
|
|
957
|
+
throw new Error(
|
|
958
|
+
`Invalid ${source} value "${String(value)}". Use "api-key" or "bearer".`
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
const normalized = value.trim().toLowerCase();
|
|
962
|
+
if (!normalized) return void 0;
|
|
963
|
+
if (normalized === "api-key" || normalized === "bearer") {
|
|
964
|
+
return normalized;
|
|
965
|
+
}
|
|
966
|
+
throw new Error(
|
|
967
|
+
`Invalid ${source} value "${value}". Use "api-key" or "bearer".`
|
|
968
|
+
);
|
|
969
|
+
}
|
|
970
|
+
function parseCloudAnnounce(value, source) {
|
|
971
|
+
if (value == null) return void 0;
|
|
972
|
+
if (typeof value !== "string") {
|
|
973
|
+
throw new Error(
|
|
974
|
+
`Invalid ${source} value "${String(value)}". Use "always", "off", or "tty".`
|
|
975
|
+
);
|
|
976
|
+
}
|
|
977
|
+
const normalized = value.trim().toLowerCase();
|
|
978
|
+
if (!normalized) return void 0;
|
|
979
|
+
if (normalized === "always" || normalized === "off" || normalized === "tty") {
|
|
980
|
+
return normalized;
|
|
981
|
+
}
|
|
982
|
+
throw new Error(
|
|
983
|
+
`Invalid ${source} value "${value}". Use "always", "off", or "tty".`
|
|
953
984
|
);
|
|
954
985
|
}
|
|
955
986
|
function resolveOpensteerApiKey() {
|
|
@@ -957,29 +988,46 @@ function resolveOpensteerApiKey() {
|
|
|
957
988
|
if (!value) return void 0;
|
|
958
989
|
return value;
|
|
959
990
|
}
|
|
960
|
-
function
|
|
991
|
+
function resolveOpensteerAuthScheme() {
|
|
992
|
+
return parseAuthScheme(
|
|
993
|
+
process.env.OPENSTEER_AUTH_SCHEME,
|
|
994
|
+
"OPENSTEER_AUTH_SCHEME"
|
|
995
|
+
);
|
|
996
|
+
}
|
|
997
|
+
function normalizeCloudOptions(value) {
|
|
961
998
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
962
999
|
return void 0;
|
|
963
1000
|
}
|
|
964
1001
|
return value;
|
|
965
1002
|
}
|
|
966
|
-
function
|
|
967
|
-
|
|
968
|
-
if (
|
|
1003
|
+
function parseCloudEnabled(value, source) {
|
|
1004
|
+
if (value == null) return void 0;
|
|
1005
|
+
if (typeof value === "boolean") return value;
|
|
1006
|
+
if (typeof value === "object" && !Array.isArray(value)) return true;
|
|
1007
|
+
throw new Error(
|
|
1008
|
+
`Invalid ${source} value "${String(value)}". Use true, false, or a cloud options object.`
|
|
1009
|
+
);
|
|
1010
|
+
}
|
|
1011
|
+
function resolveCloudSelection(config) {
|
|
1012
|
+
const configCloud = parseCloudEnabled(config.cloud, "cloud");
|
|
1013
|
+
if (configCloud !== void 0) {
|
|
969
1014
|
return {
|
|
970
|
-
|
|
971
|
-
source: "config.
|
|
1015
|
+
cloud: configCloud,
|
|
1016
|
+
source: "config.cloud"
|
|
972
1017
|
};
|
|
973
1018
|
}
|
|
974
|
-
const envMode =
|
|
1019
|
+
const envMode = parseRuntimeMode(
|
|
1020
|
+
process.env.OPENSTEER_MODE,
|
|
1021
|
+
"OPENSTEER_MODE"
|
|
1022
|
+
);
|
|
975
1023
|
if (envMode) {
|
|
976
1024
|
return {
|
|
977
|
-
|
|
1025
|
+
cloud: envMode === "cloud",
|
|
978
1026
|
source: "env.OPENSTEER_MODE"
|
|
979
1027
|
};
|
|
980
1028
|
}
|
|
981
1029
|
return {
|
|
982
|
-
|
|
1030
|
+
cloud: false,
|
|
983
1031
|
source: "default"
|
|
984
1032
|
};
|
|
985
1033
|
}
|
|
@@ -995,11 +1043,11 @@ function resolveConfig(input = {}) {
|
|
|
995
1043
|
);
|
|
996
1044
|
}
|
|
997
1045
|
assertNoLegacyAiConfig("Opensteer constructor config", input);
|
|
998
|
-
|
|
1046
|
+
assertNoLegacyRuntimeConfig("Opensteer constructor config", input);
|
|
999
1047
|
const rootDir = input.storage?.rootDir ?? DEFAULT_CONFIG.storage.rootDir ?? process.cwd();
|
|
1000
1048
|
const fileConfig = loadConfigFile(rootDir);
|
|
1001
1049
|
assertNoLegacyAiConfig(".opensteer/config.json", fileConfig);
|
|
1002
|
-
|
|
1050
|
+
assertNoLegacyRuntimeConfig(".opensteer/config.json", fileConfig);
|
|
1003
1051
|
const envConfig = {
|
|
1004
1052
|
browser: {
|
|
1005
1053
|
headless: parseBool(process.env.OPENSTEER_HEADLESS),
|
|
@@ -1016,20 +1064,39 @@ function resolveConfig(input = {}) {
|
|
|
1016
1064
|
const mergedWithEnv = mergeDeep(mergedWithFile, envConfig);
|
|
1017
1065
|
const resolved = mergeDeep(mergedWithEnv, input);
|
|
1018
1066
|
const envApiKey = resolveOpensteerApiKey();
|
|
1019
|
-
const
|
|
1020
|
-
const
|
|
1021
|
-
|
|
1067
|
+
const envAuthScheme = resolveOpensteerAuthScheme();
|
|
1068
|
+
const envCloudAnnounce = parseCloudAnnounce(
|
|
1069
|
+
process.env.OPENSTEER_REMOTE_ANNOUNCE,
|
|
1070
|
+
"OPENSTEER_REMOTE_ANNOUNCE"
|
|
1071
|
+
);
|
|
1072
|
+
const inputCloudOptions = normalizeCloudOptions(input.cloud);
|
|
1073
|
+
const inputAuthScheme = parseAuthScheme(
|
|
1074
|
+
inputCloudOptions?.authScheme,
|
|
1075
|
+
"cloud.authScheme"
|
|
1076
|
+
);
|
|
1077
|
+
const inputCloudAnnounce = parseCloudAnnounce(
|
|
1078
|
+
inputCloudOptions?.announce,
|
|
1079
|
+
"cloud.announce"
|
|
1080
|
+
);
|
|
1081
|
+
const inputHasCloudApiKey = Boolean(
|
|
1082
|
+
inputCloudOptions && Object.prototype.hasOwnProperty.call(inputCloudOptions, "apiKey")
|
|
1022
1083
|
);
|
|
1023
|
-
const
|
|
1024
|
-
|
|
1084
|
+
const cloudSelection = resolveCloudSelection({
|
|
1085
|
+
cloud: resolved.cloud
|
|
1025
1086
|
});
|
|
1026
|
-
if (
|
|
1027
|
-
const
|
|
1028
|
-
|
|
1087
|
+
if (cloudSelection.cloud) {
|
|
1088
|
+
const resolvedCloud = normalizeCloudOptions(resolved.cloud) ?? {};
|
|
1089
|
+
const authScheme = inputAuthScheme ?? envAuthScheme ?? parseAuthScheme(resolvedCloud.authScheme, "cloud.authScheme") ?? "api-key";
|
|
1090
|
+
const announce = inputCloudAnnounce ?? envCloudAnnounce ?? parseCloudAnnounce(resolvedCloud.announce, "cloud.announce") ?? "always";
|
|
1091
|
+
resolved.cloud = {
|
|
1092
|
+
...resolvedCloud,
|
|
1093
|
+
authScheme,
|
|
1094
|
+
announce
|
|
1095
|
+
};
|
|
1029
1096
|
}
|
|
1030
|
-
if (envApiKey &&
|
|
1031
|
-
resolved.
|
|
1032
|
-
...
|
|
1097
|
+
if (envApiKey && cloudSelection.cloud && !inputHasCloudApiKey) {
|
|
1098
|
+
resolved.cloud = {
|
|
1099
|
+
...normalizeCloudOptions(resolved.cloud) ?? {},
|
|
1033
1100
|
apiKey: envApiKey
|
|
1034
1101
|
};
|
|
1035
1102
|
}
|
|
@@ -1072,15 +1139,52 @@ function getCallerFilePath() {
|
|
|
1072
1139
|
// src/navigation.ts
|
|
1073
1140
|
var DEFAULT_TIMEOUT = 3e4;
|
|
1074
1141
|
var DEFAULT_SETTLE_MS = 750;
|
|
1142
|
+
var FRAME_EVALUATE_GRACE_MS = 200;
|
|
1143
|
+
var STEALTH_WORLD_NAME = "__opensteer_wait__";
|
|
1144
|
+
var StealthWaitUnavailableError = class extends Error {
|
|
1145
|
+
constructor(cause) {
|
|
1146
|
+
super("Stealth visual wait requires Chromium CDP support.", { cause });
|
|
1147
|
+
this.name = "StealthWaitUnavailableError";
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
function isStealthWaitUnavailableError(error) {
|
|
1151
|
+
return error instanceof StealthWaitUnavailableError;
|
|
1152
|
+
}
|
|
1153
|
+
var FRAME_OWNER_VISIBILITY_FUNCTION = `function() {
|
|
1154
|
+
if (!(this instanceof HTMLElement)) return false;
|
|
1155
|
+
|
|
1156
|
+
var rect = this.getBoundingClientRect();
|
|
1157
|
+
if (rect.width <= 0 || rect.height <= 0) return false;
|
|
1158
|
+
if (
|
|
1159
|
+
rect.bottom <= 0 ||
|
|
1160
|
+
rect.right <= 0 ||
|
|
1161
|
+
rect.top >= window.innerHeight ||
|
|
1162
|
+
rect.left >= window.innerWidth
|
|
1163
|
+
) {
|
|
1164
|
+
return false;
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
var style = window.getComputedStyle(this);
|
|
1168
|
+
if (
|
|
1169
|
+
style.display === 'none' ||
|
|
1170
|
+
style.visibility === 'hidden' ||
|
|
1171
|
+
Number(style.opacity) === 0
|
|
1172
|
+
) {
|
|
1173
|
+
return false;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
return true;
|
|
1177
|
+
}`;
|
|
1075
1178
|
function buildStabilityScript(timeout, settleMs) {
|
|
1076
1179
|
return `new Promise(function(resolve) {
|
|
1077
1180
|
var deadline = Date.now() + ${timeout};
|
|
1078
|
-
var timer = null;
|
|
1079
1181
|
var resolved = false;
|
|
1182
|
+
var timer = null;
|
|
1080
1183
|
var observers = [];
|
|
1081
1184
|
var observedShadowRoots = [];
|
|
1082
1185
|
var fonts = document.fonts;
|
|
1083
1186
|
var fontsReady = !fonts || fonts.status === 'loaded';
|
|
1187
|
+
var lastRelevantMutationAt = Date.now();
|
|
1084
1188
|
|
|
1085
1189
|
function clearObservers() {
|
|
1086
1190
|
for (var i = 0; i < observers.length; i++) {
|
|
@@ -1098,9 +1202,87 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
1098
1202
|
resolve();
|
|
1099
1203
|
}
|
|
1100
1204
|
|
|
1205
|
+
function isElementVisiblyIntersectingViewport(element) {
|
|
1206
|
+
if (!(element instanceof Element)) return false;
|
|
1207
|
+
|
|
1208
|
+
var rect = element.getBoundingClientRect();
|
|
1209
|
+
var inViewport =
|
|
1210
|
+
rect.width > 0 &&
|
|
1211
|
+
rect.height > 0 &&
|
|
1212
|
+
rect.bottom > 0 &&
|
|
1213
|
+
rect.right > 0 &&
|
|
1214
|
+
rect.top < window.innerHeight &&
|
|
1215
|
+
rect.left < window.innerWidth;
|
|
1216
|
+
|
|
1217
|
+
if (!inViewport) return false;
|
|
1218
|
+
|
|
1219
|
+
var style = window.getComputedStyle(element);
|
|
1220
|
+
if (style.visibility === 'hidden' || style.display === 'none') {
|
|
1221
|
+
return false;
|
|
1222
|
+
}
|
|
1223
|
+
if (Number(style.opacity) === 0) {
|
|
1224
|
+
return false;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
return true;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
function resolveRelevantElement(node) {
|
|
1231
|
+
if (!node) return null;
|
|
1232
|
+
if (node instanceof Element) return node;
|
|
1233
|
+
if (typeof ShadowRoot !== 'undefined' && node instanceof ShadowRoot) {
|
|
1234
|
+
return node.host instanceof Element ? node.host : null;
|
|
1235
|
+
}
|
|
1236
|
+
var parentElement = node.parentElement;
|
|
1237
|
+
return parentElement instanceof Element ? parentElement : null;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
function isNodeVisiblyRelevant(node) {
|
|
1241
|
+
var element = resolveRelevantElement(node);
|
|
1242
|
+
if (!element) return false;
|
|
1243
|
+
return isElementVisiblyIntersectingViewport(element);
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
function hasRelevantMutation(records) {
|
|
1247
|
+
for (var i = 0; i < records.length; i++) {
|
|
1248
|
+
var record = records[i];
|
|
1249
|
+
if (isNodeVisiblyRelevant(record.target)) return true;
|
|
1250
|
+
|
|
1251
|
+
var addedNodes = record.addedNodes;
|
|
1252
|
+
for (var j = 0; j < addedNodes.length; j++) {
|
|
1253
|
+
if (isNodeVisiblyRelevant(addedNodes[j])) return true;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
var removedNodes = record.removedNodes;
|
|
1257
|
+
for (var k = 0; k < removedNodes.length; k++) {
|
|
1258
|
+
if (isNodeVisiblyRelevant(removedNodes[k])) return true;
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
return false;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
function scheduleCheck() {
|
|
1266
|
+
if (resolved) return;
|
|
1267
|
+
if (timer) clearTimeout(timer);
|
|
1268
|
+
|
|
1269
|
+
var remaining = deadline - Date.now();
|
|
1270
|
+
if (remaining <= 0) {
|
|
1271
|
+
done();
|
|
1272
|
+
return;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
var checkDelay = Math.min(120, Math.max(16, ${settleMs}));
|
|
1276
|
+
timer = setTimeout(checkNow, checkDelay);
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1101
1279
|
function observeMutations(target) {
|
|
1102
1280
|
if (!target) return;
|
|
1103
|
-
var observer = new MutationObserver(function() {
|
|
1281
|
+
var observer = new MutationObserver(function(records) {
|
|
1282
|
+
if (!hasRelevantMutation(records)) return;
|
|
1283
|
+
lastRelevantMutationAt = Date.now();
|
|
1284
|
+
scheduleCheck();
|
|
1285
|
+
});
|
|
1104
1286
|
observer.observe(target, {
|
|
1105
1287
|
childList: true,
|
|
1106
1288
|
subtree: true,
|
|
@@ -1138,18 +1320,25 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
1138
1320
|
var images = root.querySelectorAll('img');
|
|
1139
1321
|
for (var i = 0; i < images.length; i++) {
|
|
1140
1322
|
var img = images[i];
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
rect.bottom > 0 &&
|
|
1144
|
-
rect.right > 0 &&
|
|
1145
|
-
rect.top < window.innerHeight &&
|
|
1146
|
-
rect.left < window.innerWidth;
|
|
1147
|
-
if (inViewport && !img.complete) return false;
|
|
1323
|
+
if (!isElementVisiblyIntersectingViewport(img)) continue;
|
|
1324
|
+
if (!img.complete) return false;
|
|
1148
1325
|
}
|
|
1149
1326
|
return true;
|
|
1150
1327
|
}
|
|
1151
1328
|
|
|
1152
|
-
function
|
|
1329
|
+
function getAnimationTarget(effect) {
|
|
1330
|
+
if (!effect) return null;
|
|
1331
|
+
var target = effect.target;
|
|
1332
|
+
if (target instanceof Element) return target;
|
|
1333
|
+
|
|
1334
|
+
if (target && target.element instanceof Element) {
|
|
1335
|
+
return target.element;
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
return null;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
function hasRunningVisibleFiniteAnimations() {
|
|
1153
1342
|
if (typeof document.getAnimations !== 'function') return false;
|
|
1154
1343
|
var animations = document.getAnimations();
|
|
1155
1344
|
|
|
@@ -1163,6 +1352,9 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
1163
1352
|
? timing.endTime
|
|
1164
1353
|
: Number.POSITIVE_INFINITY;
|
|
1165
1354
|
if (Number.isFinite(endTime) && endTime > 0) {
|
|
1355
|
+
var target = getAnimationTarget(effect);
|
|
1356
|
+
if (!target) continue;
|
|
1357
|
+
if (!isElementVisiblyIntersectingViewport(target)) continue;
|
|
1166
1358
|
return true;
|
|
1167
1359
|
}
|
|
1168
1360
|
}
|
|
@@ -1173,21 +1365,29 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
1173
1365
|
function isVisuallyReady() {
|
|
1174
1366
|
if (!fontsReady) return false;
|
|
1175
1367
|
if (!checkViewportImages(document)) return false;
|
|
1176
|
-
if (
|
|
1368
|
+
if (hasRunningVisibleFiniteAnimations()) return false;
|
|
1177
1369
|
return true;
|
|
1178
1370
|
}
|
|
1179
1371
|
|
|
1180
|
-
function
|
|
1181
|
-
if (Date.now()
|
|
1182
|
-
|
|
1372
|
+
function checkNow() {
|
|
1373
|
+
if (Date.now() >= deadline) {
|
|
1374
|
+
done();
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1183
1378
|
observeOpenShadowRoots();
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1379
|
+
|
|
1380
|
+
if (!isVisuallyReady()) {
|
|
1381
|
+
scheduleCheck();
|
|
1382
|
+
return;
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
if (Date.now() - lastRelevantMutationAt >= ${settleMs}) {
|
|
1386
|
+
done();
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
scheduleCheck();
|
|
1191
1391
|
}
|
|
1192
1392
|
|
|
1193
1393
|
observeMutations(document.documentElement);
|
|
@@ -1196,67 +1396,266 @@ function buildStabilityScript(timeout, settleMs) {
|
|
|
1196
1396
|
if (fonts && fonts.ready && typeof fonts.ready.then === 'function') {
|
|
1197
1397
|
fonts.ready.then(function() {
|
|
1198
1398
|
fontsReady = true;
|
|
1199
|
-
|
|
1399
|
+
scheduleCheck();
|
|
1400
|
+
}, function() {
|
|
1401
|
+
fontsReady = true;
|
|
1402
|
+
scheduleCheck();
|
|
1200
1403
|
});
|
|
1201
1404
|
}
|
|
1202
1405
|
|
|
1203
1406
|
var safetyTimer = setTimeout(done, ${timeout});
|
|
1204
1407
|
|
|
1205
|
-
|
|
1408
|
+
scheduleCheck();
|
|
1206
1409
|
})`;
|
|
1207
1410
|
}
|
|
1411
|
+
var StealthCdpRuntime = class _StealthCdpRuntime {
|
|
1412
|
+
constructor(session2) {
|
|
1413
|
+
this.session = session2;
|
|
1414
|
+
}
|
|
1415
|
+
contextsByFrame = /* @__PURE__ */ new Map();
|
|
1416
|
+
disposed = false;
|
|
1417
|
+
static async create(page) {
|
|
1418
|
+
let session2;
|
|
1419
|
+
try {
|
|
1420
|
+
session2 = await page.context().newCDPSession(page);
|
|
1421
|
+
} catch (error) {
|
|
1422
|
+
throw new StealthWaitUnavailableError(error);
|
|
1423
|
+
}
|
|
1424
|
+
const runtime = new _StealthCdpRuntime(session2);
|
|
1425
|
+
try {
|
|
1426
|
+
await runtime.initialize();
|
|
1427
|
+
return runtime;
|
|
1428
|
+
} catch (error) {
|
|
1429
|
+
await runtime.dispose();
|
|
1430
|
+
throw new StealthWaitUnavailableError(error);
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
async dispose() {
|
|
1434
|
+
if (this.disposed) return;
|
|
1435
|
+
this.disposed = true;
|
|
1436
|
+
this.contextsByFrame.clear();
|
|
1437
|
+
await this.session.detach().catch(() => void 0);
|
|
1438
|
+
}
|
|
1439
|
+
async waitForMainFrameVisualStability(options) {
|
|
1440
|
+
const timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
1441
|
+
const settleMs = options.settleMs ?? DEFAULT_SETTLE_MS;
|
|
1442
|
+
if (timeout <= 0) return;
|
|
1443
|
+
const frameRecords = await this.getFrameRecords();
|
|
1444
|
+
const mainFrame = frameRecords[0];
|
|
1445
|
+
if (!mainFrame) return;
|
|
1446
|
+
await this.waitForFrameVisualStability(mainFrame.frameId, timeout, settleMs);
|
|
1447
|
+
}
|
|
1448
|
+
async collectVisibleFrameIds() {
|
|
1449
|
+
const frameRecords = await this.getFrameRecords();
|
|
1450
|
+
if (frameRecords.length === 0) return [];
|
|
1451
|
+
const visibleFrameIds = [];
|
|
1452
|
+
for (const frameRecord of frameRecords) {
|
|
1453
|
+
if (!frameRecord.parentFrameId) {
|
|
1454
|
+
visibleFrameIds.push(frameRecord.frameId);
|
|
1455
|
+
continue;
|
|
1456
|
+
}
|
|
1457
|
+
try {
|
|
1458
|
+
const parentContextId = await this.ensureFrameContextId(
|
|
1459
|
+
frameRecord.parentFrameId
|
|
1460
|
+
);
|
|
1461
|
+
const visible = await this.isFrameOwnerVisible(
|
|
1462
|
+
frameRecord.frameId,
|
|
1463
|
+
parentContextId
|
|
1464
|
+
);
|
|
1465
|
+
if (visible) {
|
|
1466
|
+
visibleFrameIds.push(frameRecord.frameId);
|
|
1467
|
+
}
|
|
1468
|
+
} catch (error) {
|
|
1469
|
+
if (isIgnorableFrameError(error)) continue;
|
|
1470
|
+
throw error;
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
return visibleFrameIds;
|
|
1474
|
+
}
|
|
1475
|
+
async waitForFrameVisualStability(frameId, timeout, settleMs) {
|
|
1476
|
+
if (timeout <= 0) return;
|
|
1477
|
+
const script = buildStabilityScript(timeout, settleMs);
|
|
1478
|
+
let contextId = await this.ensureFrameContextId(frameId);
|
|
1479
|
+
try {
|
|
1480
|
+
await this.evaluateWithGuard(contextId, script, timeout);
|
|
1481
|
+
} catch (error) {
|
|
1482
|
+
if (!isMissingExecutionContextError(error)) {
|
|
1483
|
+
throw error;
|
|
1484
|
+
}
|
|
1485
|
+
this.contextsByFrame.delete(frameId);
|
|
1486
|
+
contextId = await this.ensureFrameContextId(frameId);
|
|
1487
|
+
await this.evaluateWithGuard(contextId, script, timeout);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
async initialize() {
|
|
1491
|
+
await this.session.send("Page.enable");
|
|
1492
|
+
await this.session.send("Runtime.enable");
|
|
1493
|
+
await this.session.send("DOM.enable");
|
|
1494
|
+
}
|
|
1495
|
+
async getFrameRecords() {
|
|
1496
|
+
const treeResult = await this.session.send("Page.getFrameTree");
|
|
1497
|
+
const records = [];
|
|
1498
|
+
walkFrameTree(treeResult.frameTree, null, records);
|
|
1499
|
+
return records;
|
|
1500
|
+
}
|
|
1501
|
+
async ensureFrameContextId(frameId) {
|
|
1502
|
+
const cached = this.contextsByFrame.get(frameId);
|
|
1503
|
+
if (cached != null) {
|
|
1504
|
+
return cached;
|
|
1505
|
+
}
|
|
1506
|
+
const world = await this.session.send("Page.createIsolatedWorld", {
|
|
1507
|
+
frameId,
|
|
1508
|
+
worldName: STEALTH_WORLD_NAME
|
|
1509
|
+
});
|
|
1510
|
+
this.contextsByFrame.set(frameId, world.executionContextId);
|
|
1511
|
+
return world.executionContextId;
|
|
1512
|
+
}
|
|
1513
|
+
async evaluateWithGuard(contextId, script, timeout) {
|
|
1514
|
+
const evaluationPromise = this.evaluateScript(contextId, script);
|
|
1515
|
+
const settledPromise = evaluationPromise.then(
|
|
1516
|
+
() => ({ kind: "resolved" }),
|
|
1517
|
+
(error) => ({ kind: "rejected", error })
|
|
1518
|
+
);
|
|
1519
|
+
const timeoutPromise = sleep(
|
|
1520
|
+
timeout + FRAME_EVALUATE_GRACE_MS
|
|
1521
|
+
).then(() => ({ kind: "timeout" }));
|
|
1522
|
+
const result = await Promise.race([
|
|
1523
|
+
settledPromise,
|
|
1524
|
+
timeoutPromise
|
|
1525
|
+
]);
|
|
1526
|
+
if (result.kind === "rejected") {
|
|
1527
|
+
throw result.error;
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
async evaluateScript(contextId, expression) {
|
|
1531
|
+
const result = await this.session.send("Runtime.evaluate", {
|
|
1532
|
+
contextId,
|
|
1533
|
+
expression,
|
|
1534
|
+
awaitPromise: true,
|
|
1535
|
+
returnByValue: true
|
|
1536
|
+
});
|
|
1537
|
+
if (result.exceptionDetails) {
|
|
1538
|
+
throw new Error(formatCdpException(result.exceptionDetails));
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
async isFrameOwnerVisible(frameId, parentContextId) {
|
|
1542
|
+
const owner = await this.session.send("DOM.getFrameOwner", {
|
|
1543
|
+
frameId
|
|
1544
|
+
});
|
|
1545
|
+
const resolveParams = {
|
|
1546
|
+
executionContextId: parentContextId
|
|
1547
|
+
};
|
|
1548
|
+
if (typeof owner.backendNodeId === "number") {
|
|
1549
|
+
resolveParams.backendNodeId = owner.backendNodeId;
|
|
1550
|
+
} else if (typeof owner.nodeId === "number") {
|
|
1551
|
+
resolveParams.nodeId = owner.nodeId;
|
|
1552
|
+
} else {
|
|
1553
|
+
return false;
|
|
1554
|
+
}
|
|
1555
|
+
const resolved = await this.session.send(
|
|
1556
|
+
"DOM.resolveNode",
|
|
1557
|
+
resolveParams
|
|
1558
|
+
);
|
|
1559
|
+
const objectId = resolved.object?.objectId;
|
|
1560
|
+
if (!objectId) return false;
|
|
1561
|
+
try {
|
|
1562
|
+
const callResult = await this.session.send("Runtime.callFunctionOn", {
|
|
1563
|
+
objectId,
|
|
1564
|
+
functionDeclaration: FRAME_OWNER_VISIBILITY_FUNCTION,
|
|
1565
|
+
returnByValue: true
|
|
1566
|
+
});
|
|
1567
|
+
if (callResult.exceptionDetails) {
|
|
1568
|
+
throw new Error(formatCdpException(callResult.exceptionDetails));
|
|
1569
|
+
}
|
|
1570
|
+
return callResult.result.value === true;
|
|
1571
|
+
} finally {
|
|
1572
|
+
await this.releaseObject(objectId);
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
async releaseObject(objectId) {
|
|
1576
|
+
await this.session.send("Runtime.releaseObject", {
|
|
1577
|
+
objectId
|
|
1578
|
+
}).catch(() => void 0);
|
|
1579
|
+
}
|
|
1580
|
+
};
|
|
1208
1581
|
async function waitForVisualStability(page, options = {}) {
|
|
1209
|
-
const
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
}
|
|
1582
|
+
const runtime = await StealthCdpRuntime.create(page);
|
|
1583
|
+
try {
|
|
1584
|
+
await runtime.waitForMainFrameVisualStability(options);
|
|
1585
|
+
} finally {
|
|
1586
|
+
await runtime.dispose();
|
|
1587
|
+
}
|
|
1215
1588
|
}
|
|
1216
1589
|
async function waitForVisualStabilityAcrossFrames(page, options = {}) {
|
|
1217
1590
|
const timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
1218
1591
|
const settleMs = options.settleMs ?? DEFAULT_SETTLE_MS;
|
|
1592
|
+
if (timeout <= 0) return;
|
|
1219
1593
|
const deadline = Date.now() + timeout;
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1594
|
+
const runtime = await StealthCdpRuntime.create(page);
|
|
1595
|
+
try {
|
|
1596
|
+
while (true) {
|
|
1597
|
+
const remaining = Math.max(0, deadline - Date.now());
|
|
1598
|
+
if (remaining === 0) return;
|
|
1599
|
+
const frameIds = await runtime.collectVisibleFrameIds();
|
|
1600
|
+
if (frameIds.length === 0) return;
|
|
1601
|
+
await Promise.all(
|
|
1602
|
+
frameIds.map(async (frameId) => {
|
|
1603
|
+
try {
|
|
1604
|
+
await runtime.waitForFrameVisualStability(
|
|
1605
|
+
frameId,
|
|
1606
|
+
remaining,
|
|
1607
|
+
settleMs
|
|
1608
|
+
);
|
|
1609
|
+
} catch (error) {
|
|
1610
|
+
if (isIgnorableFrameError(error)) return;
|
|
1611
|
+
throw error;
|
|
1612
|
+
}
|
|
1613
|
+
})
|
|
1614
|
+
);
|
|
1615
|
+
const currentFrameIds = await runtime.collectVisibleFrameIds();
|
|
1616
|
+
if (sameFrameIds(frameIds, currentFrameIds)) {
|
|
1617
|
+
return;
|
|
1618
|
+
}
|
|
1240
1619
|
}
|
|
1620
|
+
} finally {
|
|
1621
|
+
await runtime.dispose();
|
|
1241
1622
|
}
|
|
1242
1623
|
}
|
|
1243
|
-
|
|
1244
|
-
const
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1624
|
+
function walkFrameTree(node, parentFrameId, records) {
|
|
1625
|
+
const frameId = node.frame?.id;
|
|
1626
|
+
if (!frameId) return;
|
|
1627
|
+
records.push({
|
|
1628
|
+
frameId,
|
|
1629
|
+
parentFrameId
|
|
1630
|
+
});
|
|
1631
|
+
for (const child of node.childFrames ?? []) {
|
|
1632
|
+
walkFrameTree(child, frameId, records);
|
|
1633
|
+
}
|
|
1248
1634
|
}
|
|
1249
|
-
function
|
|
1635
|
+
function sameFrameIds(before, after) {
|
|
1250
1636
|
if (before.length !== after.length) return false;
|
|
1251
|
-
for (const
|
|
1252
|
-
if (!after.includes(
|
|
1637
|
+
for (const frameId of before) {
|
|
1638
|
+
if (!after.includes(frameId)) return false;
|
|
1253
1639
|
}
|
|
1254
1640
|
return true;
|
|
1255
1641
|
}
|
|
1642
|
+
function formatCdpException(details) {
|
|
1643
|
+
return details.exception?.description || details.text || "CDP runtime evaluation failed.";
|
|
1644
|
+
}
|
|
1645
|
+
function isMissingExecutionContextError(error) {
|
|
1646
|
+
if (!(error instanceof Error)) return false;
|
|
1647
|
+
const message = error.message;
|
|
1648
|
+
return message.includes("Cannot find context with specified id") || message.includes("Cannot find execution context");
|
|
1649
|
+
}
|
|
1256
1650
|
function isIgnorableFrameError(error) {
|
|
1257
1651
|
if (!(error instanceof Error)) return false;
|
|
1258
1652
|
const message = error.message;
|
|
1259
|
-
return message.includes("Frame was detached") || message.includes("Execution context was destroyed") || message.includes("Target page, context or browser has been closed");
|
|
1653
|
+
return message.includes("Frame was detached") || message.includes("Execution context was destroyed") || message.includes("Target page, context or browser has been closed") || message.includes("Cannot find context with specified id") || message.includes("Cannot find execution context") || message.includes("No frame for given id found");
|
|
1654
|
+
}
|
|
1655
|
+
function sleep(ms) {
|
|
1656
|
+
return new Promise((resolve) => {
|
|
1657
|
+
setTimeout(resolve, ms);
|
|
1658
|
+
});
|
|
1260
1659
|
}
|
|
1261
1660
|
|
|
1262
1661
|
// src/storage/local.ts
|
|
@@ -2157,6 +2556,66 @@ var OS_BOUNDARY_ATTR = "data-os-boundary";
|
|
|
2157
2556
|
var OS_UNAVAILABLE_ATTR = "data-os-unavailable";
|
|
2158
2557
|
var OS_IFRAME_BOUNDARY_TAG = "os-iframe-root";
|
|
2159
2558
|
var OS_SHADOW_BOUNDARY_TAG = "os-shadow-root";
|
|
2559
|
+
function decodeSerializedNodeTableEntry(nodeTable, rawIndex, label) {
|
|
2560
|
+
if (typeof rawIndex !== "number" || !Number.isInteger(rawIndex) || rawIndex < 0 || rawIndex >= nodeTable.length) {
|
|
2561
|
+
throw new Error(
|
|
2562
|
+
`Invalid serialized path node index at "${label}": expected a valid table index.`
|
|
2563
|
+
);
|
|
2564
|
+
}
|
|
2565
|
+
const node = nodeTable[rawIndex];
|
|
2566
|
+
if (!node || typeof node !== "object") {
|
|
2567
|
+
throw new Error(
|
|
2568
|
+
`Invalid serialized path node at "${label}": table entry is missing.`
|
|
2569
|
+
);
|
|
2570
|
+
}
|
|
2571
|
+
return node;
|
|
2572
|
+
}
|
|
2573
|
+
function decodeSerializedDomPath(nodeTable, rawPath, label) {
|
|
2574
|
+
if (!Array.isArray(rawPath)) {
|
|
2575
|
+
throw new Error(
|
|
2576
|
+
`Invalid serialized path at "${label}": expected an array of node indexes.`
|
|
2577
|
+
);
|
|
2578
|
+
}
|
|
2579
|
+
return rawPath.map(
|
|
2580
|
+
(value, index) => decodeSerializedNodeTableEntry(nodeTable, value, `${label}[${index}]`)
|
|
2581
|
+
);
|
|
2582
|
+
}
|
|
2583
|
+
function decodeSerializedElementPath(nodeTable, rawPath, label) {
|
|
2584
|
+
if (!rawPath || typeof rawPath !== "object") {
|
|
2585
|
+
throw new Error(
|
|
2586
|
+
`Invalid serialized element path at "${label}": expected an object.`
|
|
2587
|
+
);
|
|
2588
|
+
}
|
|
2589
|
+
if (rawPath.context !== void 0 && !Array.isArray(rawPath.context)) {
|
|
2590
|
+
throw new Error(
|
|
2591
|
+
`Invalid serialized context at "${label}.context": expected an array.`
|
|
2592
|
+
);
|
|
2593
|
+
}
|
|
2594
|
+
const contextRaw = Array.isArray(rawPath.context) ? rawPath.context : [];
|
|
2595
|
+
const context = contextRaw.map((hop, hopIndex) => {
|
|
2596
|
+
if (!hop || typeof hop !== "object" || hop.kind !== "shadow") {
|
|
2597
|
+
throw new Error(
|
|
2598
|
+
`Invalid serialized context hop at "${label}.context[${hopIndex}]": expected a shadow hop.`
|
|
2599
|
+
);
|
|
2600
|
+
}
|
|
2601
|
+
return {
|
|
2602
|
+
kind: "shadow",
|
|
2603
|
+
host: decodeSerializedDomPath(
|
|
2604
|
+
nodeTable,
|
|
2605
|
+
hop.host,
|
|
2606
|
+
`${label}.context[${hopIndex}].host`
|
|
2607
|
+
)
|
|
2608
|
+
};
|
|
2609
|
+
});
|
|
2610
|
+
return {
|
|
2611
|
+
context,
|
|
2612
|
+
nodes: decodeSerializedDomPath(
|
|
2613
|
+
nodeTable,
|
|
2614
|
+
rawPath.nodes,
|
|
2615
|
+
`${label}.nodes`
|
|
2616
|
+
)
|
|
2617
|
+
};
|
|
2618
|
+
}
|
|
2160
2619
|
async function serializePageHTML(page, _options = {}) {
|
|
2161
2620
|
return serializeFrameRecursive(page.mainFrame(), [], "f0");
|
|
2162
2621
|
}
|
|
@@ -2213,6 +2672,8 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
2213
2672
|
(Array.isArray(deferredMatchAttrKeys) ? deferredMatchAttrKeys : []).map((key) => String(key))
|
|
2214
2673
|
);
|
|
2215
2674
|
let counter = 1;
|
|
2675
|
+
const nodeTable = [];
|
|
2676
|
+
const nodeTableIndexByKey = /* @__PURE__ */ new Map();
|
|
2216
2677
|
const entries = [];
|
|
2217
2678
|
const helpers = {
|
|
2218
2679
|
nextToken() {
|
|
@@ -2414,6 +2875,47 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
2414
2875
|
nodes: target
|
|
2415
2876
|
};
|
|
2416
2877
|
},
|
|
2878
|
+
buildPathNodeKey(node) {
|
|
2879
|
+
const attrs = Object.entries(node.attrs || {}).sort(
|
|
2880
|
+
([a], [b]) => a.localeCompare(b)
|
|
2881
|
+
);
|
|
2882
|
+
const match = (node.match || []).map(
|
|
2883
|
+
(clause) => clause.kind === "attr" ? [
|
|
2884
|
+
"attr",
|
|
2885
|
+
clause.key,
|
|
2886
|
+
clause.op || "exact",
|
|
2887
|
+
clause.value ?? null
|
|
2888
|
+
] : ["position", clause.axis]
|
|
2889
|
+
);
|
|
2890
|
+
return JSON.stringify([
|
|
2891
|
+
node.tag,
|
|
2892
|
+
node.position.nthChild,
|
|
2893
|
+
node.position.nthOfType,
|
|
2894
|
+
attrs,
|
|
2895
|
+
match
|
|
2896
|
+
]);
|
|
2897
|
+
},
|
|
2898
|
+
internPathNode(node) {
|
|
2899
|
+
const key = helpers.buildPathNodeKey(node);
|
|
2900
|
+
const existing = nodeTableIndexByKey.get(key);
|
|
2901
|
+
if (existing != null) return existing;
|
|
2902
|
+
const index = nodeTable.length;
|
|
2903
|
+
nodeTable.push(node);
|
|
2904
|
+
nodeTableIndexByKey.set(key, index);
|
|
2905
|
+
return index;
|
|
2906
|
+
},
|
|
2907
|
+
packDomPath(path5) {
|
|
2908
|
+
return path5.map((node) => helpers.internPathNode(node));
|
|
2909
|
+
},
|
|
2910
|
+
packElementPath(path5) {
|
|
2911
|
+
return {
|
|
2912
|
+
context: (path5.context || []).map((hop) => ({
|
|
2913
|
+
kind: "shadow",
|
|
2914
|
+
host: helpers.packDomPath(hop.host)
|
|
2915
|
+
})),
|
|
2916
|
+
nodes: helpers.packDomPath(path5.nodes)
|
|
2917
|
+
};
|
|
2918
|
+
},
|
|
2417
2919
|
ensureNodeId(el) {
|
|
2418
2920
|
const next = `${frameKey2}_${counter++}`;
|
|
2419
2921
|
el.setAttribute(nodeAttr, next);
|
|
@@ -2443,9 +2945,12 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
2443
2945
|
serializeElement(el) {
|
|
2444
2946
|
const nodeId = helpers.ensureNodeId(el);
|
|
2445
2947
|
const instanceToken = helpers.setInstanceToken(el);
|
|
2948
|
+
const packedPath = helpers.packElementPath(
|
|
2949
|
+
helpers.buildElementPath(el)
|
|
2950
|
+
);
|
|
2446
2951
|
entries.push({
|
|
2447
2952
|
nodeId,
|
|
2448
|
-
path:
|
|
2953
|
+
path: packedPath,
|
|
2449
2954
|
instanceToken
|
|
2450
2955
|
});
|
|
2451
2956
|
const tag = el.tagName.toLowerCase();
|
|
@@ -2473,11 +2978,12 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
2473
2978
|
win[frameTokenKey] = frameToken;
|
|
2474
2979
|
const root = document.documentElement;
|
|
2475
2980
|
if (!root) {
|
|
2476
|
-
return { html: "", frameToken, entries };
|
|
2981
|
+
return { html: "", frameToken, nodeTable, entries };
|
|
2477
2982
|
}
|
|
2478
2983
|
return {
|
|
2479
2984
|
html: helpers.serializeElement(root),
|
|
2480
2985
|
frameToken,
|
|
2986
|
+
nodeTable,
|
|
2481
2987
|
entries
|
|
2482
2988
|
};
|
|
2483
2989
|
},
|
|
@@ -2495,13 +3001,18 @@ async function serializeFrameRecursive(frame, baseContext, frameKey) {
|
|
|
2495
3001
|
);
|
|
2496
3002
|
const nodePaths = /* @__PURE__ */ new Map();
|
|
2497
3003
|
const nodeMeta = /* @__PURE__ */ new Map();
|
|
2498
|
-
for (const entry of frameSnapshot.entries) {
|
|
3004
|
+
for (const [index, entry] of frameSnapshot.entries.entries()) {
|
|
3005
|
+
const path5 = decodeSerializedElementPath(
|
|
3006
|
+
frameSnapshot.nodeTable,
|
|
3007
|
+
entry.path,
|
|
3008
|
+
`entries[${index}].path`
|
|
3009
|
+
);
|
|
2499
3010
|
nodePaths.set(entry.nodeId, {
|
|
2500
3011
|
context: [
|
|
2501
3012
|
...baseContext,
|
|
2502
|
-
...
|
|
3013
|
+
...path5.context || []
|
|
2503
3014
|
],
|
|
2504
|
-
nodes:
|
|
3015
|
+
nodes: path5.nodes
|
|
2505
3016
|
});
|
|
2506
3017
|
nodeMeta.set(entry.nodeId, {
|
|
2507
3018
|
frameToken: frameSnapshot.frameToken,
|
|
@@ -4895,7 +5406,7 @@ async function performInput(page, path5, options) {
|
|
|
4895
5406
|
await resolved.element.type(options.text);
|
|
4896
5407
|
}
|
|
4897
5408
|
if (options.pressEnter) {
|
|
4898
|
-
await resolved.element.press("Enter");
|
|
5409
|
+
await resolved.element.press("Enter", { noWaitAfter: true });
|
|
4899
5410
|
}
|
|
4900
5411
|
return {
|
|
4901
5412
|
ok: true,
|
|
@@ -5561,7 +6072,26 @@ var ACTION_WAIT_PROFILES = {
|
|
|
5561
6072
|
type: ROBUST_PROFILE
|
|
5562
6073
|
};
|
|
5563
6074
|
var NETWORK_POLL_MS = 50;
|
|
5564
|
-
var
|
|
6075
|
+
var NETWORK_RELAX_AFTER_MS = 1800;
|
|
6076
|
+
var RELAXED_ALLOWED_PENDING = 2;
|
|
6077
|
+
var HEAVY_VISUAL_REQUEST_WINDOW_MS = 5e3;
|
|
6078
|
+
var TRACKED_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
6079
|
+
"document",
|
|
6080
|
+
"fetch",
|
|
6081
|
+
"xhr",
|
|
6082
|
+
"stylesheet",
|
|
6083
|
+
"image",
|
|
6084
|
+
"font",
|
|
6085
|
+
"media"
|
|
6086
|
+
]);
|
|
6087
|
+
var HEAVY_RESOURCE_TYPES = /* @__PURE__ */ new Set(["document", "fetch", "xhr"]);
|
|
6088
|
+
var HEAVY_VISUAL_RESOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
6089
|
+
"stylesheet",
|
|
6090
|
+
"image",
|
|
6091
|
+
"font",
|
|
6092
|
+
"media"
|
|
6093
|
+
]);
|
|
6094
|
+
var IGNORED_RESOURCE_TYPES = /* @__PURE__ */ new Set(["websocket", "eventsource", "manifest"]);
|
|
5565
6095
|
var NOOP_SESSION = {
|
|
5566
6096
|
async wait() {
|
|
5567
6097
|
},
|
|
@@ -5571,7 +6101,7 @@ var NOOP_SESSION = {
|
|
|
5571
6101
|
function createPostActionWaitSession(page, action, override) {
|
|
5572
6102
|
const profile = resolveActionWaitProfile(action, override);
|
|
5573
6103
|
if (!profile.enabled) return NOOP_SESSION;
|
|
5574
|
-
const tracker = profile.includeNetwork ? new
|
|
6104
|
+
const tracker = profile.includeNetwork ? new AdaptiveNetworkTracker(page) : null;
|
|
5575
6105
|
tracker?.start();
|
|
5576
6106
|
let settled = false;
|
|
5577
6107
|
return {
|
|
@@ -5579,19 +6109,32 @@ function createPostActionWaitSession(page, action, override) {
|
|
|
5579
6109
|
if (settled) return;
|
|
5580
6110
|
settled = true;
|
|
5581
6111
|
const deadline = Date.now() + profile.timeout;
|
|
5582
|
-
const
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
6112
|
+
const visualTimeout = profile.includeNetwork ? Math.min(
|
|
6113
|
+
profile.timeout,
|
|
6114
|
+
resolveNetworkBackedVisualTimeout(profile.settleMs)
|
|
6115
|
+
) : profile.timeout;
|
|
5586
6116
|
try {
|
|
5587
|
-
|
|
5588
|
-
waitForVisualStabilityAcrossFrames(page, {
|
|
5589
|
-
timeout:
|
|
6117
|
+
try {
|
|
6118
|
+
await waitForVisualStabilityAcrossFrames(page, {
|
|
6119
|
+
timeout: visualTimeout,
|
|
5590
6120
|
settleMs: profile.settleMs
|
|
5591
|
-
})
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
6121
|
+
});
|
|
6122
|
+
} catch (error) {
|
|
6123
|
+
if (isStealthWaitUnavailableError(error)) {
|
|
6124
|
+
throw error;
|
|
6125
|
+
}
|
|
6126
|
+
} finally {
|
|
6127
|
+
tracker?.freezeCollection();
|
|
6128
|
+
}
|
|
6129
|
+
if (tracker) {
|
|
6130
|
+
try {
|
|
6131
|
+
await tracker.waitForQuiet({
|
|
6132
|
+
deadline,
|
|
6133
|
+
quietMs: profile.networkQuietMs
|
|
6134
|
+
});
|
|
6135
|
+
} catch {
|
|
6136
|
+
}
|
|
6137
|
+
}
|
|
5595
6138
|
} finally {
|
|
5596
6139
|
tracker?.stop();
|
|
5597
6140
|
}
|
|
@@ -5631,53 +6174,70 @@ function normalizeMs(value, fallback) {
|
|
|
5631
6174
|
}
|
|
5632
6175
|
return Math.max(0, Math.floor(value));
|
|
5633
6176
|
}
|
|
5634
|
-
|
|
6177
|
+
function resolveNetworkBackedVisualTimeout(settleMs) {
|
|
6178
|
+
const derived = settleMs * 3 + 300;
|
|
6179
|
+
return Math.max(1200, Math.min(2500, derived));
|
|
6180
|
+
}
|
|
6181
|
+
var AdaptiveNetworkTracker = class {
|
|
5635
6182
|
constructor(page) {
|
|
5636
6183
|
this.page = page;
|
|
5637
6184
|
}
|
|
5638
|
-
pending = /* @__PURE__ */ new
|
|
6185
|
+
pending = /* @__PURE__ */ new Map();
|
|
5639
6186
|
started = false;
|
|
6187
|
+
collecting = false;
|
|
6188
|
+
startedAt = 0;
|
|
5640
6189
|
idleSince = Date.now();
|
|
5641
6190
|
start() {
|
|
5642
6191
|
if (this.started) return;
|
|
5643
6192
|
this.started = true;
|
|
6193
|
+
this.collecting = true;
|
|
6194
|
+
this.startedAt = Date.now();
|
|
6195
|
+
this.idleSince = this.startedAt;
|
|
5644
6196
|
this.page.on("request", this.handleRequestStarted);
|
|
5645
6197
|
this.page.on("requestfinished", this.handleRequestFinished);
|
|
5646
6198
|
this.page.on("requestfailed", this.handleRequestFinished);
|
|
5647
6199
|
}
|
|
6200
|
+
freezeCollection() {
|
|
6201
|
+
if (!this.started) return;
|
|
6202
|
+
this.collecting = false;
|
|
6203
|
+
}
|
|
5648
6204
|
stop() {
|
|
5649
6205
|
if (!this.started) return;
|
|
5650
6206
|
this.started = false;
|
|
6207
|
+
this.collecting = false;
|
|
5651
6208
|
this.page.off("request", this.handleRequestStarted);
|
|
5652
6209
|
this.page.off("requestfinished", this.handleRequestFinished);
|
|
5653
6210
|
this.page.off("requestfailed", this.handleRequestFinished);
|
|
5654
6211
|
this.pending.clear();
|
|
6212
|
+
this.startedAt = 0;
|
|
5655
6213
|
this.idleSince = Date.now();
|
|
5656
6214
|
}
|
|
5657
6215
|
async waitForQuiet(options) {
|
|
5658
6216
|
const quietMs = Math.max(0, options.quietMs);
|
|
5659
6217
|
if (quietMs === 0) return;
|
|
5660
6218
|
while (Date.now() < options.deadline) {
|
|
5661
|
-
|
|
6219
|
+
const now = Date.now();
|
|
6220
|
+
const allowedPending = this.resolveAllowedPending(now);
|
|
6221
|
+
if (this.pending.size <= allowedPending) {
|
|
5662
6222
|
if (this.idleSince === 0) {
|
|
5663
|
-
this.idleSince =
|
|
6223
|
+
this.idleSince = now;
|
|
5664
6224
|
}
|
|
5665
|
-
const idleFor =
|
|
6225
|
+
const idleFor = now - this.idleSince;
|
|
5666
6226
|
if (idleFor >= quietMs) {
|
|
5667
6227
|
return;
|
|
5668
6228
|
}
|
|
5669
6229
|
} else {
|
|
5670
6230
|
this.idleSince = 0;
|
|
5671
6231
|
}
|
|
5672
|
-
const remaining = Math.max(1, options.deadline -
|
|
5673
|
-
await
|
|
6232
|
+
const remaining = Math.max(1, options.deadline - now);
|
|
6233
|
+
await sleep2(Math.min(NETWORK_POLL_MS, remaining));
|
|
5674
6234
|
}
|
|
5675
6235
|
}
|
|
5676
6236
|
handleRequestStarted = (request) => {
|
|
5677
|
-
if (!this.started) return;
|
|
5678
|
-
const
|
|
5679
|
-
if (
|
|
5680
|
-
this.pending.
|
|
6237
|
+
if (!this.started || !this.collecting) return;
|
|
6238
|
+
const trackedRequest = this.classifyRequest(request);
|
|
6239
|
+
if (!trackedRequest) return;
|
|
6240
|
+
this.pending.set(request, trackedRequest);
|
|
5681
6241
|
this.idleSince = 0;
|
|
5682
6242
|
};
|
|
5683
6243
|
handleRequestFinished = (request) => {
|
|
@@ -5687,8 +6247,35 @@ var ScopedNetworkTracker = class {
|
|
|
5687
6247
|
this.idleSince = Date.now();
|
|
5688
6248
|
}
|
|
5689
6249
|
};
|
|
6250
|
+
classifyRequest(request) {
|
|
6251
|
+
const resourceType = request.resourceType().toLowerCase();
|
|
6252
|
+
if (IGNORED_RESOURCE_TYPES.has(resourceType)) return null;
|
|
6253
|
+
if (!TRACKED_RESOURCE_TYPES.has(resourceType)) return null;
|
|
6254
|
+
const frame = request.frame();
|
|
6255
|
+
if (!frame || frame !== this.page.mainFrame()) return null;
|
|
6256
|
+
return {
|
|
6257
|
+
resourceType,
|
|
6258
|
+
startedAt: Date.now()
|
|
6259
|
+
};
|
|
6260
|
+
}
|
|
6261
|
+
resolveAllowedPending(now) {
|
|
6262
|
+
const relaxed = now - this.startedAt >= NETWORK_RELAX_AFTER_MS ? RELAXED_ALLOWED_PENDING : 0;
|
|
6263
|
+
if (this.hasHeavyPending(now)) return 0;
|
|
6264
|
+
return relaxed;
|
|
6265
|
+
}
|
|
6266
|
+
hasHeavyPending(now) {
|
|
6267
|
+
for (const trackedRequest of this.pending.values()) {
|
|
6268
|
+
if (HEAVY_RESOURCE_TYPES.has(trackedRequest.resourceType)) {
|
|
6269
|
+
return true;
|
|
6270
|
+
}
|
|
6271
|
+
if (HEAVY_VISUAL_RESOURCE_TYPES.has(trackedRequest.resourceType) && now - trackedRequest.startedAt < HEAVY_VISUAL_REQUEST_WINDOW_MS) {
|
|
6272
|
+
return true;
|
|
6273
|
+
}
|
|
6274
|
+
}
|
|
6275
|
+
return false;
|
|
6276
|
+
}
|
|
5690
6277
|
};
|
|
5691
|
-
async function
|
|
6278
|
+
async function sleep2(ms) {
|
|
5692
6279
|
await new Promise((resolve) => {
|
|
5693
6280
|
setTimeout(resolve, ms);
|
|
5694
6281
|
});
|
|
@@ -6806,36 +7393,39 @@ function clonePersistedExtractNode(node) {
|
|
|
6806
7393
|
return JSON.parse(JSON.stringify(node));
|
|
6807
7394
|
}
|
|
6808
7395
|
|
|
6809
|
-
// src/
|
|
7396
|
+
// src/cloud/contracts.ts
|
|
7397
|
+
var cloudSessionContractVersion = "v3";
|
|
7398
|
+
|
|
7399
|
+
// src/cloud/action-ws-client.ts
|
|
6810
7400
|
var import_ws2 = __toESM(require("ws"), 1);
|
|
6811
7401
|
|
|
6812
|
-
// src/
|
|
6813
|
-
var
|
|
7402
|
+
// src/cloud/errors.ts
|
|
7403
|
+
var OpensteerCloudError = class extends Error {
|
|
6814
7404
|
code;
|
|
6815
7405
|
status;
|
|
6816
7406
|
details;
|
|
6817
7407
|
constructor(code, message, status, details) {
|
|
6818
7408
|
super(message);
|
|
6819
|
-
this.name = "
|
|
7409
|
+
this.name = "OpensteerCloudError";
|
|
6820
7410
|
this.code = code;
|
|
6821
7411
|
this.status = status;
|
|
6822
7412
|
this.details = details;
|
|
6823
7413
|
}
|
|
6824
7414
|
};
|
|
6825
|
-
function
|
|
6826
|
-
return new
|
|
6827
|
-
"
|
|
6828
|
-
message || `${method} is not supported in
|
|
7415
|
+
function cloudUnsupportedMethodError(method, message) {
|
|
7416
|
+
return new OpensteerCloudError(
|
|
7417
|
+
"CLOUD_UNSUPPORTED_METHOD",
|
|
7418
|
+
message || `${method} is not supported in cloud mode.`
|
|
6829
7419
|
);
|
|
6830
7420
|
}
|
|
6831
|
-
function
|
|
6832
|
-
return new
|
|
6833
|
-
"
|
|
6834
|
-
"
|
|
7421
|
+
function cloudNotLaunchedError() {
|
|
7422
|
+
return new OpensteerCloudError(
|
|
7423
|
+
"CLOUD_SESSION_NOT_FOUND",
|
|
7424
|
+
"Cloud session is not connected. Call launch() first."
|
|
6835
7425
|
);
|
|
6836
7426
|
}
|
|
6837
7427
|
|
|
6838
|
-
// src/
|
|
7428
|
+
// src/cloud/action-ws-client.ts
|
|
6839
7429
|
var ActionWsClient = class _ActionWsClient {
|
|
6840
7430
|
ws;
|
|
6841
7431
|
sessionId;
|
|
@@ -6852,18 +7442,18 @@ var ActionWsClient = class _ActionWsClient {
|
|
|
6852
7442
|
});
|
|
6853
7443
|
ws.on("error", (error) => {
|
|
6854
7444
|
this.rejectAll(
|
|
6855
|
-
new
|
|
6856
|
-
"
|
|
6857
|
-
`
|
|
7445
|
+
new OpensteerCloudError(
|
|
7446
|
+
"CLOUD_TRANSPORT_ERROR",
|
|
7447
|
+
`Cloud action websocket error: ${error.message}`
|
|
6858
7448
|
)
|
|
6859
7449
|
);
|
|
6860
7450
|
});
|
|
6861
7451
|
ws.on("close", () => {
|
|
6862
7452
|
this.closed = true;
|
|
6863
7453
|
this.rejectAll(
|
|
6864
|
-
new
|
|
6865
|
-
"
|
|
6866
|
-
"
|
|
7454
|
+
new OpensteerCloudError(
|
|
7455
|
+
"CLOUD_SESSION_CLOSED",
|
|
7456
|
+
"Cloud action websocket closed."
|
|
6867
7457
|
)
|
|
6868
7458
|
);
|
|
6869
7459
|
});
|
|
@@ -6875,8 +7465,8 @@ var ActionWsClient = class _ActionWsClient {
|
|
|
6875
7465
|
ws.once("open", () => resolve());
|
|
6876
7466
|
ws.once("error", (error) => {
|
|
6877
7467
|
reject(
|
|
6878
|
-
new
|
|
6879
|
-
"
|
|
7468
|
+
new OpensteerCloudError(
|
|
7469
|
+
"CLOUD_TRANSPORT_ERROR",
|
|
6880
7470
|
`Failed to connect action websocket: ${error.message}`
|
|
6881
7471
|
)
|
|
6882
7472
|
);
|
|
@@ -6886,9 +7476,9 @@ var ActionWsClient = class _ActionWsClient {
|
|
|
6886
7476
|
}
|
|
6887
7477
|
async request(method, args) {
|
|
6888
7478
|
if (this.closed || this.ws.readyState !== import_ws2.default.OPEN) {
|
|
6889
|
-
throw new
|
|
6890
|
-
"
|
|
6891
|
-
"
|
|
7479
|
+
throw new OpensteerCloudError(
|
|
7480
|
+
"CLOUD_SESSION_CLOSED",
|
|
7481
|
+
"Cloud action websocket is closed."
|
|
6892
7482
|
);
|
|
6893
7483
|
}
|
|
6894
7484
|
const id = this.nextRequestId;
|
|
@@ -6907,8 +7497,8 @@ var ActionWsClient = class _ActionWsClient {
|
|
|
6907
7497
|
this.ws.send(JSON.stringify(payload));
|
|
6908
7498
|
} catch (error) {
|
|
6909
7499
|
this.pending.delete(id);
|
|
6910
|
-
const message = error instanceof Error ? error.message : "Failed to send
|
|
6911
|
-
throw new
|
|
7500
|
+
const message = error instanceof Error ? error.message : "Failed to send cloud action request.";
|
|
7501
|
+
throw new OpensteerCloudError("CLOUD_TRANSPORT_ERROR", message);
|
|
6912
7502
|
}
|
|
6913
7503
|
return await resultPromise;
|
|
6914
7504
|
}
|
|
@@ -6926,9 +7516,9 @@ var ActionWsClient = class _ActionWsClient {
|
|
|
6926
7516
|
parsed = JSON.parse(rawDataToUtf8(raw));
|
|
6927
7517
|
} catch {
|
|
6928
7518
|
this.rejectAll(
|
|
6929
|
-
new
|
|
6930
|
-
"
|
|
6931
|
-
"Invalid
|
|
7519
|
+
new OpensteerCloudError(
|
|
7520
|
+
"CLOUD_TRANSPORT_ERROR",
|
|
7521
|
+
"Invalid cloud action response payload."
|
|
6932
7522
|
)
|
|
6933
7523
|
);
|
|
6934
7524
|
return;
|
|
@@ -6941,7 +7531,7 @@ var ActionWsClient = class _ActionWsClient {
|
|
|
6941
7531
|
return;
|
|
6942
7532
|
}
|
|
6943
7533
|
pending.reject(
|
|
6944
|
-
new
|
|
7534
|
+
new OpensteerCloudError(
|
|
6945
7535
|
parsed.code,
|
|
6946
7536
|
parsed.error,
|
|
6947
7537
|
void 0,
|
|
@@ -6969,7 +7559,7 @@ function withTokenQuery(wsUrl, token) {
|
|
|
6969
7559
|
return url.toString();
|
|
6970
7560
|
}
|
|
6971
7561
|
|
|
6972
|
-
// src/
|
|
7562
|
+
// src/cloud/local-cache-sync.ts
|
|
6973
7563
|
var import_fs3 = __toESM(require("fs"), 1);
|
|
6974
7564
|
var import_path5 = __toESM(require("path"), 1);
|
|
6975
7565
|
function collectLocalSelectorCacheEntries(storage) {
|
|
@@ -7093,24 +7683,24 @@ function dedupeNewest(entries) {
|
|
|
7093
7683
|
return [...byKey.values()];
|
|
7094
7684
|
}
|
|
7095
7685
|
|
|
7096
|
-
// src/
|
|
7686
|
+
// src/cloud/cdp-client.ts
|
|
7097
7687
|
var import_playwright2 = require("playwright");
|
|
7098
|
-
var
|
|
7688
|
+
var CloudCdpClient = class {
|
|
7099
7689
|
async connect(args) {
|
|
7100
7690
|
const endpoint = withTokenQuery2(args.wsUrl, args.token);
|
|
7101
7691
|
let browser;
|
|
7102
7692
|
try {
|
|
7103
7693
|
browser = await import_playwright2.chromium.connectOverCDP(endpoint);
|
|
7104
7694
|
} catch (error) {
|
|
7105
|
-
const message = error instanceof Error ? error.message : "Failed to connect to
|
|
7106
|
-
throw new
|
|
7695
|
+
const message = error instanceof Error ? error.message : "Failed to connect to cloud CDP endpoint.";
|
|
7696
|
+
throw new OpensteerCloudError("CLOUD_TRANSPORT_ERROR", message);
|
|
7107
7697
|
}
|
|
7108
7698
|
const context = browser.contexts()[0];
|
|
7109
7699
|
if (!context) {
|
|
7110
7700
|
await browser.close();
|
|
7111
|
-
throw new
|
|
7112
|
-
"
|
|
7113
|
-
"
|
|
7701
|
+
throw new OpensteerCloudError(
|
|
7702
|
+
"CLOUD_INTERNAL",
|
|
7703
|
+
"Cloud browser returned no context."
|
|
7114
7704
|
);
|
|
7115
7705
|
}
|
|
7116
7706
|
const page = context.pages()[0] || await context.newPage();
|
|
@@ -7123,34 +7713,46 @@ function withTokenQuery2(wsUrl, token) {
|
|
|
7123
7713
|
return url.toString();
|
|
7124
7714
|
}
|
|
7125
7715
|
|
|
7126
|
-
// src/
|
|
7716
|
+
// src/cloud/session-client.ts
|
|
7127
7717
|
var CACHE_IMPORT_BATCH_SIZE = 200;
|
|
7128
|
-
var
|
|
7718
|
+
var CloudSessionClient = class {
|
|
7129
7719
|
baseUrl;
|
|
7130
7720
|
key;
|
|
7131
|
-
|
|
7721
|
+
authScheme;
|
|
7722
|
+
constructor(baseUrl, key, authScheme = "api-key") {
|
|
7132
7723
|
this.baseUrl = normalizeBaseUrl(baseUrl);
|
|
7133
7724
|
this.key = key;
|
|
7725
|
+
this.authScheme = authScheme;
|
|
7134
7726
|
}
|
|
7135
7727
|
async create(request) {
|
|
7136
7728
|
const response = await fetch(`${this.baseUrl}/sessions`, {
|
|
7137
7729
|
method: "POST",
|
|
7138
7730
|
headers: {
|
|
7139
7731
|
"content-type": "application/json",
|
|
7140
|
-
|
|
7732
|
+
...this.authHeaders()
|
|
7141
7733
|
},
|
|
7142
7734
|
body: JSON.stringify(request)
|
|
7143
7735
|
});
|
|
7144
7736
|
if (!response.ok) {
|
|
7145
7737
|
throw await parseHttpError(response);
|
|
7146
7738
|
}
|
|
7147
|
-
|
|
7739
|
+
let body;
|
|
7740
|
+
try {
|
|
7741
|
+
body = await response.json();
|
|
7742
|
+
} catch {
|
|
7743
|
+
throw new OpensteerCloudError(
|
|
7744
|
+
"CLOUD_CONTRACT_MISMATCH",
|
|
7745
|
+
"Invalid cloud session create response: expected a JSON object.",
|
|
7746
|
+
response.status
|
|
7747
|
+
);
|
|
7748
|
+
}
|
|
7749
|
+
return parseCreateResponse(body, response.status);
|
|
7148
7750
|
}
|
|
7149
7751
|
async close(sessionId) {
|
|
7150
7752
|
const response = await fetch(`${this.baseUrl}/sessions/${sessionId}`, {
|
|
7151
7753
|
method: "DELETE",
|
|
7152
7754
|
headers: {
|
|
7153
|
-
|
|
7755
|
+
...this.authHeaders()
|
|
7154
7756
|
}
|
|
7155
7757
|
});
|
|
7156
7758
|
if (response.status === 204) {
|
|
@@ -7180,7 +7782,7 @@ var RemoteSessionClient = class {
|
|
|
7180
7782
|
method: "POST",
|
|
7181
7783
|
headers: {
|
|
7182
7784
|
"content-type": "application/json",
|
|
7183
|
-
|
|
7785
|
+
...this.authHeaders()
|
|
7184
7786
|
},
|
|
7185
7787
|
body: JSON.stringify({ entries })
|
|
7186
7788
|
});
|
|
@@ -7189,10 +7791,148 @@ var RemoteSessionClient = class {
|
|
|
7189
7791
|
}
|
|
7190
7792
|
return await response.json();
|
|
7191
7793
|
}
|
|
7794
|
+
authHeaders() {
|
|
7795
|
+
if (this.authScheme === "bearer") {
|
|
7796
|
+
return {
|
|
7797
|
+
authorization: `Bearer ${this.key}`
|
|
7798
|
+
};
|
|
7799
|
+
}
|
|
7800
|
+
return {
|
|
7801
|
+
"x-api-key": this.key
|
|
7802
|
+
};
|
|
7803
|
+
}
|
|
7192
7804
|
};
|
|
7193
7805
|
function normalizeBaseUrl(baseUrl) {
|
|
7194
7806
|
return baseUrl.replace(/\/+$/, "");
|
|
7195
7807
|
}
|
|
7808
|
+
function parseCreateResponse(body, status) {
|
|
7809
|
+
const root = requireObject(
|
|
7810
|
+
body,
|
|
7811
|
+
"Invalid cloud session create response: expected a JSON object.",
|
|
7812
|
+
status
|
|
7813
|
+
);
|
|
7814
|
+
const sessionId = requireString(root, "sessionId", status);
|
|
7815
|
+
const actionWsUrl = requireString(root, "actionWsUrl", status);
|
|
7816
|
+
const cdpWsUrl = requireString(root, "cdpWsUrl", status);
|
|
7817
|
+
const actionToken = requireString(root, "actionToken", status);
|
|
7818
|
+
const cdpToken = requireString(root, "cdpToken", status);
|
|
7819
|
+
const cloudSessionUrl = requireString(root, "cloudSessionUrl", status);
|
|
7820
|
+
const cloudSessionRoot = requireObject(
|
|
7821
|
+
root.cloudSession,
|
|
7822
|
+
"Invalid cloud session create response: cloudSession must be an object.",
|
|
7823
|
+
status
|
|
7824
|
+
);
|
|
7825
|
+
const cloudSession = {
|
|
7826
|
+
sessionId: requireString(cloudSessionRoot, "sessionId", status, "cloudSession"),
|
|
7827
|
+
workspaceId: requireString(
|
|
7828
|
+
cloudSessionRoot,
|
|
7829
|
+
"workspaceId",
|
|
7830
|
+
status,
|
|
7831
|
+
"cloudSession"
|
|
7832
|
+
),
|
|
7833
|
+
state: requireString(cloudSessionRoot, "state", status, "cloudSession"),
|
|
7834
|
+
createdAt: requireNumber(cloudSessionRoot, "createdAt", status, "cloudSession"),
|
|
7835
|
+
sourceType: requireSourceType(cloudSessionRoot, "sourceType", status, "cloudSession"),
|
|
7836
|
+
sourceRef: optionalString(cloudSessionRoot, "sourceRef", status, "cloudSession"),
|
|
7837
|
+
label: optionalString(cloudSessionRoot, "label", status, "cloudSession")
|
|
7838
|
+
};
|
|
7839
|
+
const expiresAt = optionalNumber(root, "expiresAt", status);
|
|
7840
|
+
return {
|
|
7841
|
+
sessionId,
|
|
7842
|
+
actionWsUrl,
|
|
7843
|
+
cdpWsUrl,
|
|
7844
|
+
actionToken,
|
|
7845
|
+
cdpToken,
|
|
7846
|
+
expiresAt,
|
|
7847
|
+
cloudSessionUrl,
|
|
7848
|
+
cloudSession
|
|
7849
|
+
};
|
|
7850
|
+
}
|
|
7851
|
+
function requireObject(value, message, status) {
|
|
7852
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
7853
|
+
throw new OpensteerCloudError("CLOUD_CONTRACT_MISMATCH", message, status);
|
|
7854
|
+
}
|
|
7855
|
+
return value;
|
|
7856
|
+
}
|
|
7857
|
+
function requireString(source, field, status, parent) {
|
|
7858
|
+
const value = source[field];
|
|
7859
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
7860
|
+
throw new OpensteerCloudError(
|
|
7861
|
+
"CLOUD_CONTRACT_MISMATCH",
|
|
7862
|
+
`Invalid cloud session create response: ${formatFieldPath(
|
|
7863
|
+
field,
|
|
7864
|
+
parent
|
|
7865
|
+
)} must be a non-empty string.`,
|
|
7866
|
+
status
|
|
7867
|
+
);
|
|
7868
|
+
}
|
|
7869
|
+
return value;
|
|
7870
|
+
}
|
|
7871
|
+
function requireNumber(source, field, status, parent) {
|
|
7872
|
+
const value = source[field];
|
|
7873
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
7874
|
+
throw new OpensteerCloudError(
|
|
7875
|
+
"CLOUD_CONTRACT_MISMATCH",
|
|
7876
|
+
`Invalid cloud session create response: ${formatFieldPath(
|
|
7877
|
+
field,
|
|
7878
|
+
parent
|
|
7879
|
+
)} must be a finite number.`,
|
|
7880
|
+
status
|
|
7881
|
+
);
|
|
7882
|
+
}
|
|
7883
|
+
return value;
|
|
7884
|
+
}
|
|
7885
|
+
function optionalString(source, field, status, parent) {
|
|
7886
|
+
const value = source[field];
|
|
7887
|
+
if (value == null) {
|
|
7888
|
+
return void 0;
|
|
7889
|
+
}
|
|
7890
|
+
if (typeof value !== "string") {
|
|
7891
|
+
throw new OpensteerCloudError(
|
|
7892
|
+
"CLOUD_CONTRACT_MISMATCH",
|
|
7893
|
+
`Invalid cloud session create response: ${formatFieldPath(
|
|
7894
|
+
field,
|
|
7895
|
+
parent
|
|
7896
|
+
)} must be a string when present.`,
|
|
7897
|
+
status
|
|
7898
|
+
);
|
|
7899
|
+
}
|
|
7900
|
+
return value;
|
|
7901
|
+
}
|
|
7902
|
+
function optionalNumber(source, field, status, parent) {
|
|
7903
|
+
const value = source[field];
|
|
7904
|
+
if (value == null) {
|
|
7905
|
+
return void 0;
|
|
7906
|
+
}
|
|
7907
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
7908
|
+
throw new OpensteerCloudError(
|
|
7909
|
+
"CLOUD_CONTRACT_MISMATCH",
|
|
7910
|
+
`Invalid cloud session create response: ${formatFieldPath(
|
|
7911
|
+
field,
|
|
7912
|
+
parent
|
|
7913
|
+
)} must be a finite number when present.`,
|
|
7914
|
+
status
|
|
7915
|
+
);
|
|
7916
|
+
}
|
|
7917
|
+
return value;
|
|
7918
|
+
}
|
|
7919
|
+
function requireSourceType(source, field, status, parent) {
|
|
7920
|
+
const value = source[field];
|
|
7921
|
+
if (value === "agent-thread" || value === "agent-run" || value === "local-cloud" || value === "manual") {
|
|
7922
|
+
return value;
|
|
7923
|
+
}
|
|
7924
|
+
throw new OpensteerCloudError(
|
|
7925
|
+
"CLOUD_CONTRACT_MISMATCH",
|
|
7926
|
+
`Invalid cloud session create response: ${formatFieldPath(
|
|
7927
|
+
field,
|
|
7928
|
+
parent
|
|
7929
|
+
)} must be one of "agent-thread", "agent-run", "local-cloud", or "manual".`,
|
|
7930
|
+
status
|
|
7931
|
+
);
|
|
7932
|
+
}
|
|
7933
|
+
function formatFieldPath(field, parent) {
|
|
7934
|
+
return parent ? `"${parent}.${field}"` : `"${field}"`;
|
|
7935
|
+
}
|
|
7196
7936
|
function zeroImportResponse() {
|
|
7197
7937
|
return {
|
|
7198
7938
|
imported: 0,
|
|
@@ -7216,33 +7956,46 @@ async function parseHttpError(response) {
|
|
|
7216
7956
|
} catch {
|
|
7217
7957
|
body = null;
|
|
7218
7958
|
}
|
|
7219
|
-
const code = typeof body?.code === "string" ?
|
|
7220
|
-
const message = typeof body?.error === "string" ? body.error : `
|
|
7221
|
-
return new
|
|
7959
|
+
const code = typeof body?.code === "string" ? toCloudErrorCode(body.code) : "CLOUD_TRANSPORT_ERROR";
|
|
7960
|
+
const message = typeof body?.error === "string" ? body.error : `Cloud request failed with status ${response.status}.`;
|
|
7961
|
+
return new OpensteerCloudError(code, message, response.status, body?.details);
|
|
7222
7962
|
}
|
|
7223
|
-
function
|
|
7224
|
-
if (code === "
|
|
7963
|
+
function toCloudErrorCode(code) {
|
|
7964
|
+
if (code === "CLOUD_AUTH_FAILED" || code === "CLOUD_SESSION_NOT_FOUND" || code === "CLOUD_SESSION_CLOSED" || code === "CLOUD_UNSUPPORTED_METHOD" || code === "CLOUD_INVALID_REQUEST" || code === "CLOUD_MODEL_NOT_ALLOWED" || code === "CLOUD_ACTION_FAILED" || code === "CLOUD_INTERNAL" || code === "CLOUD_CAPACITY_EXHAUSTED" || code === "CLOUD_RUNTIME_UNAVAILABLE" || code === "CLOUD_RUNTIME_MISMATCH" || code === "CLOUD_SESSION_STALE" || code === "CLOUD_CONTRACT_MISMATCH" || code === "CLOUD_CONTROL_PLANE_ERROR") {
|
|
7225
7965
|
return code;
|
|
7226
7966
|
}
|
|
7227
|
-
return "
|
|
7967
|
+
return "CLOUD_TRANSPORT_ERROR";
|
|
7228
7968
|
}
|
|
7229
7969
|
|
|
7230
|
-
// src/
|
|
7231
|
-
var
|
|
7232
|
-
|
|
7970
|
+
// src/cloud/runtime.ts
|
|
7971
|
+
var DEFAULT_CLOUD_BASE_URL = "https://remote.opensteer.com";
|
|
7972
|
+
var DEFAULT_CLOUD_APP_URL = "https://opensteer.com";
|
|
7973
|
+
function createCloudRuntimeState(key, baseUrl = resolveCloudBaseUrl(), authScheme = "api-key", appUrl = resolveCloudAppUrl()) {
|
|
7233
7974
|
return {
|
|
7234
|
-
sessionClient: new
|
|
7235
|
-
cdpClient: new
|
|
7975
|
+
sessionClient: new CloudSessionClient(baseUrl, key, authScheme),
|
|
7976
|
+
cdpClient: new CloudCdpClient(),
|
|
7977
|
+
appUrl: normalizeCloudAppUrl(appUrl),
|
|
7236
7978
|
actionClient: null,
|
|
7237
|
-
sessionId: null
|
|
7979
|
+
sessionId: null,
|
|
7980
|
+
localRunId: null,
|
|
7981
|
+
cloudSessionUrl: null
|
|
7238
7982
|
};
|
|
7239
7983
|
}
|
|
7240
|
-
function
|
|
7984
|
+
function resolveCloudBaseUrl() {
|
|
7241
7985
|
const value = process.env.OPENSTEER_BASE_URL?.trim();
|
|
7242
|
-
if (!value) return
|
|
7986
|
+
if (!value) return DEFAULT_CLOUD_BASE_URL;
|
|
7987
|
+
return value.replace(/\/+$/, "");
|
|
7988
|
+
}
|
|
7989
|
+
function resolveCloudAppUrl() {
|
|
7990
|
+
const value = process.env.OPENSTEER_APP_URL?.trim();
|
|
7991
|
+
if (!value) return DEFAULT_CLOUD_APP_URL;
|
|
7992
|
+
return normalizeCloudAppUrl(value);
|
|
7993
|
+
}
|
|
7994
|
+
function normalizeCloudAppUrl(value) {
|
|
7995
|
+
if (!value) return null;
|
|
7243
7996
|
return value.replace(/\/+$/, "");
|
|
7244
7997
|
}
|
|
7245
|
-
function
|
|
7998
|
+
function readCloudActionDescription(payload) {
|
|
7246
7999
|
const description = payload.description;
|
|
7247
8000
|
if (typeof description !== "string") return void 0;
|
|
7248
8001
|
const normalized = description.trim();
|
|
@@ -7250,7 +8003,7 @@ function readRemoteActionDescription(payload) {
|
|
|
7250
8003
|
}
|
|
7251
8004
|
|
|
7252
8005
|
// src/opensteer.ts
|
|
7253
|
-
var
|
|
8006
|
+
var CLOUD_INTERACTION_METHODS = /* @__PURE__ */ new Set([
|
|
7254
8007
|
"click",
|
|
7255
8008
|
"dblclick",
|
|
7256
8009
|
"rightclick",
|
|
@@ -7267,7 +8020,7 @@ var Opensteer = class _Opensteer {
|
|
|
7267
8020
|
namespace;
|
|
7268
8021
|
storage;
|
|
7269
8022
|
pool;
|
|
7270
|
-
|
|
8023
|
+
cloud;
|
|
7271
8024
|
browser = null;
|
|
7272
8025
|
pageRef = null;
|
|
7273
8026
|
contextRef = null;
|
|
@@ -7275,8 +8028,8 @@ var Opensteer = class _Opensteer {
|
|
|
7275
8028
|
snapshotCache = null;
|
|
7276
8029
|
constructor(config = {}) {
|
|
7277
8030
|
const resolved = resolveConfig(config);
|
|
7278
|
-
const
|
|
7279
|
-
|
|
8031
|
+
const cloudSelection = resolveCloudSelection({
|
|
8032
|
+
cloud: resolved.cloud
|
|
7280
8033
|
});
|
|
7281
8034
|
const model = resolved.model;
|
|
7282
8035
|
this.config = resolved;
|
|
@@ -7286,20 +8039,22 @@ var Opensteer = class _Opensteer {
|
|
|
7286
8039
|
this.namespace = resolveNamespace(resolved, rootDir);
|
|
7287
8040
|
this.storage = new LocalSelectorStorage(rootDir, this.namespace);
|
|
7288
8041
|
this.pool = new BrowserPool(resolved.browser || {});
|
|
7289
|
-
if (
|
|
7290
|
-
const
|
|
7291
|
-
const apiKey =
|
|
8042
|
+
if (cloudSelection.cloud) {
|
|
8043
|
+
const cloudConfig = resolved.cloud && typeof resolved.cloud === "object" ? resolved.cloud : void 0;
|
|
8044
|
+
const apiKey = cloudConfig?.apiKey?.trim();
|
|
7292
8045
|
if (!apiKey) {
|
|
7293
8046
|
throw new Error(
|
|
7294
|
-
"
|
|
8047
|
+
"Cloud mode requires a non-empty API key via cloud.apiKey or OPENSTEER_API_KEY."
|
|
7295
8048
|
);
|
|
7296
8049
|
}
|
|
7297
|
-
this.
|
|
8050
|
+
this.cloud = createCloudRuntimeState(
|
|
7298
8051
|
apiKey,
|
|
7299
|
-
|
|
8052
|
+
cloudConfig?.baseUrl,
|
|
8053
|
+
cloudConfig?.authScheme,
|
|
8054
|
+
cloudConfig?.appUrl
|
|
7300
8055
|
);
|
|
7301
8056
|
} else {
|
|
7302
|
-
this.
|
|
8057
|
+
this.cloud = null;
|
|
7303
8058
|
}
|
|
7304
8059
|
}
|
|
7305
8060
|
createLazyResolveCallback(model) {
|
|
@@ -7337,32 +8092,32 @@ var Opensteer = class _Opensteer {
|
|
|
7337
8092
|
};
|
|
7338
8093
|
return extract;
|
|
7339
8094
|
}
|
|
7340
|
-
async
|
|
7341
|
-
const result = await this.
|
|
8095
|
+
async invokeCloudActionAndResetCache(method, args) {
|
|
8096
|
+
const result = await this.invokeCloudAction(method, args);
|
|
7342
8097
|
this.snapshotCache = null;
|
|
7343
8098
|
return result;
|
|
7344
8099
|
}
|
|
7345
|
-
async
|
|
7346
|
-
const actionClient = this.
|
|
7347
|
-
const sessionId = this.
|
|
8100
|
+
async invokeCloudAction(method, args) {
|
|
8101
|
+
const actionClient = this.cloud?.actionClient;
|
|
8102
|
+
const sessionId = this.cloud?.sessionId;
|
|
7348
8103
|
if (!actionClient || !sessionId) {
|
|
7349
|
-
throw
|
|
8104
|
+
throw cloudNotLaunchedError();
|
|
7350
8105
|
}
|
|
7351
8106
|
const payload = args && typeof args === "object" ? args : {};
|
|
7352
8107
|
try {
|
|
7353
8108
|
return await actionClient.request(method, payload);
|
|
7354
8109
|
} catch (err) {
|
|
7355
|
-
if (err instanceof
|
|
8110
|
+
if (err instanceof OpensteerCloudError && err.code === "CLOUD_ACTION_FAILED" && CLOUD_INTERACTION_METHODS.has(method)) {
|
|
7356
8111
|
const detailsRecord = err.details && typeof err.details === "object" ? err.details : null;
|
|
7357
|
-
const
|
|
8112
|
+
const cloudFailure = normalizeActionFailure(
|
|
7358
8113
|
detailsRecord?.actionFailure
|
|
7359
8114
|
);
|
|
7360
|
-
const failure =
|
|
8115
|
+
const failure = cloudFailure || classifyActionFailure({
|
|
7361
8116
|
action: method,
|
|
7362
8117
|
error: err,
|
|
7363
8118
|
fallbackMessage: defaultActionFailureMessage(method)
|
|
7364
8119
|
});
|
|
7365
|
-
const description =
|
|
8120
|
+
const description = readCloudActionDescription(payload);
|
|
7366
8121
|
throw this.buildActionError(
|
|
7367
8122
|
method,
|
|
7368
8123
|
description,
|
|
@@ -7403,8 +8158,36 @@ var Opensteer = class _Opensteer {
|
|
|
7403
8158
|
}
|
|
7404
8159
|
return this.contextRef;
|
|
7405
8160
|
}
|
|
7406
|
-
|
|
7407
|
-
return this.
|
|
8161
|
+
getCloudSessionId() {
|
|
8162
|
+
return this.cloud?.sessionId ?? null;
|
|
8163
|
+
}
|
|
8164
|
+
getCloudSessionUrl() {
|
|
8165
|
+
return this.cloud?.cloudSessionUrl ?? null;
|
|
8166
|
+
}
|
|
8167
|
+
announceCloudSession(args) {
|
|
8168
|
+
if (!this.shouldAnnounceCloudSession()) {
|
|
8169
|
+
return;
|
|
8170
|
+
}
|
|
8171
|
+
const fields = [
|
|
8172
|
+
`sessionId=${args.sessionId}`,
|
|
8173
|
+
`workspaceId=${args.workspaceId}`
|
|
8174
|
+
];
|
|
8175
|
+
if (args.cloudSessionUrl) {
|
|
8176
|
+
fields.push(`url=${args.cloudSessionUrl}`);
|
|
8177
|
+
}
|
|
8178
|
+
process.stderr.write(`[opensteer] cloud session ready ${fields.join(" ")}
|
|
8179
|
+
`);
|
|
8180
|
+
}
|
|
8181
|
+
shouldAnnounceCloudSession() {
|
|
8182
|
+
const cloudConfig = this.config.cloud && typeof this.config.cloud === "object" ? this.config.cloud : null;
|
|
8183
|
+
const announce = cloudConfig?.announce ?? "always";
|
|
8184
|
+
if (announce === "off") {
|
|
8185
|
+
return false;
|
|
8186
|
+
}
|
|
8187
|
+
if (announce === "tty") {
|
|
8188
|
+
return Boolean(process.stderr.isTTY);
|
|
8189
|
+
}
|
|
8190
|
+
return true;
|
|
7408
8191
|
}
|
|
7409
8192
|
async launch(options = {}) {
|
|
7410
8193
|
if (this.pageRef && !this.ownsBrowser) {
|
|
@@ -7415,22 +8198,29 @@ var Opensteer = class _Opensteer {
|
|
|
7415
8198
|
if (this.pageRef && this.ownsBrowser) {
|
|
7416
8199
|
return;
|
|
7417
8200
|
}
|
|
7418
|
-
if (this.
|
|
8201
|
+
if (this.cloud) {
|
|
7419
8202
|
let actionClient = null;
|
|
7420
8203
|
let browser = null;
|
|
7421
8204
|
let sessionId = null;
|
|
8205
|
+
let localRunId = null;
|
|
7422
8206
|
try {
|
|
7423
8207
|
try {
|
|
7424
|
-
await this.
|
|
8208
|
+
await this.syncLocalSelectorCacheToCloud();
|
|
7425
8209
|
} catch (error) {
|
|
7426
8210
|
if (this.config.debug) {
|
|
7427
8211
|
const message = error instanceof Error ? error.message : String(error);
|
|
7428
8212
|
console.warn(
|
|
7429
|
-
`[opensteer]
|
|
8213
|
+
`[opensteer] cloud selector cache sync failed: ${message}`
|
|
7430
8214
|
);
|
|
7431
8215
|
}
|
|
7432
8216
|
}
|
|
7433
|
-
|
|
8217
|
+
localRunId = this.cloud.localRunId || buildLocalRunId(this.namespace);
|
|
8218
|
+
this.cloud.localRunId = localRunId;
|
|
8219
|
+
const session3 = await this.cloud.sessionClient.create({
|
|
8220
|
+
cloudSessionContractVersion,
|
|
8221
|
+
sourceType: "local-cloud",
|
|
8222
|
+
clientSessionHint: this.namespace,
|
|
8223
|
+
localRunId,
|
|
7434
8224
|
name: this.namespace,
|
|
7435
8225
|
model: this.config.model,
|
|
7436
8226
|
launchContext: options.context || void 0
|
|
@@ -7441,7 +8231,7 @@ var Opensteer = class _Opensteer {
|
|
|
7441
8231
|
token: session3.actionToken,
|
|
7442
8232
|
sessionId: session3.sessionId
|
|
7443
8233
|
});
|
|
7444
|
-
const cdpConnection = await this.
|
|
8234
|
+
const cdpConnection = await this.cloud.cdpClient.connect({
|
|
7445
8235
|
wsUrl: session3.cdpWsUrl,
|
|
7446
8236
|
token: session3.cdpToken
|
|
7447
8237
|
});
|
|
@@ -7451,8 +8241,17 @@ var Opensteer = class _Opensteer {
|
|
|
7451
8241
|
this.pageRef = cdpConnection.page;
|
|
7452
8242
|
this.ownsBrowser = true;
|
|
7453
8243
|
this.snapshotCache = null;
|
|
7454
|
-
this.
|
|
7455
|
-
this.
|
|
8244
|
+
this.cloud.actionClient = actionClient;
|
|
8245
|
+
this.cloud.sessionId = sessionId;
|
|
8246
|
+
this.cloud.cloudSessionUrl = buildCloudSessionUrl(
|
|
8247
|
+
this.cloud.appUrl,
|
|
8248
|
+
session3.cloudSession.sessionId
|
|
8249
|
+
);
|
|
8250
|
+
this.announceCloudSession({
|
|
8251
|
+
sessionId: session3.sessionId,
|
|
8252
|
+
workspaceId: session3.cloudSession.workspaceId,
|
|
8253
|
+
cloudSessionUrl: this.cloud.cloudSessionUrl
|
|
8254
|
+
});
|
|
7456
8255
|
return;
|
|
7457
8256
|
} catch (error) {
|
|
7458
8257
|
if (actionClient) {
|
|
@@ -7462,8 +8261,9 @@ var Opensteer = class _Opensteer {
|
|
|
7462
8261
|
await browser.close().catch(() => void 0);
|
|
7463
8262
|
}
|
|
7464
8263
|
if (sessionId) {
|
|
7465
|
-
await this.
|
|
8264
|
+
await this.cloud.sessionClient.close(sessionId).catch(() => void 0);
|
|
7466
8265
|
}
|
|
8266
|
+
this.cloud.cloudSessionUrl = null;
|
|
7467
8267
|
throw error;
|
|
7468
8268
|
}
|
|
7469
8269
|
}
|
|
@@ -7481,13 +8281,13 @@ var Opensteer = class _Opensteer {
|
|
|
7481
8281
|
}
|
|
7482
8282
|
static from(page, config = {}) {
|
|
7483
8283
|
const resolvedConfig = resolveConfig(config);
|
|
7484
|
-
const
|
|
7485
|
-
|
|
8284
|
+
const cloudSelection = resolveCloudSelection({
|
|
8285
|
+
cloud: resolvedConfig.cloud
|
|
7486
8286
|
});
|
|
7487
|
-
if (
|
|
7488
|
-
throw
|
|
8287
|
+
if (cloudSelection.cloud) {
|
|
8288
|
+
throw cloudUnsupportedMethodError(
|
|
7489
8289
|
"Opensteer.from(page)",
|
|
7490
|
-
"Opensteer.from(page) is not supported in
|
|
8290
|
+
"Opensteer.from(page) is not supported in cloud mode."
|
|
7491
8291
|
);
|
|
7492
8292
|
}
|
|
7493
8293
|
const instance2 = new _Opensteer(config);
|
|
@@ -7500,12 +8300,14 @@ var Opensteer = class _Opensteer {
|
|
|
7500
8300
|
}
|
|
7501
8301
|
async close() {
|
|
7502
8302
|
this.snapshotCache = null;
|
|
7503
|
-
if (this.
|
|
7504
|
-
const actionClient = this.
|
|
7505
|
-
const sessionId = this.
|
|
8303
|
+
if (this.cloud) {
|
|
8304
|
+
const actionClient = this.cloud.actionClient;
|
|
8305
|
+
const sessionId = this.cloud.sessionId;
|
|
7506
8306
|
const browser = this.browser;
|
|
7507
|
-
this.
|
|
7508
|
-
this.
|
|
8307
|
+
this.cloud.actionClient = null;
|
|
8308
|
+
this.cloud.sessionId = null;
|
|
8309
|
+
this.cloud.localRunId = null;
|
|
8310
|
+
this.cloud.cloudSessionUrl = null;
|
|
7509
8311
|
this.browser = null;
|
|
7510
8312
|
this.pageRef = null;
|
|
7511
8313
|
this.contextRef = null;
|
|
@@ -7517,7 +8319,7 @@ var Opensteer = class _Opensteer {
|
|
|
7517
8319
|
await browser.close().catch(() => void 0);
|
|
7518
8320
|
}
|
|
7519
8321
|
if (sessionId) {
|
|
7520
|
-
await this.
|
|
8322
|
+
await this.cloud.sessionClient.close(sessionId).catch(() => void 0);
|
|
7521
8323
|
}
|
|
7522
8324
|
return;
|
|
7523
8325
|
}
|
|
@@ -7529,17 +8331,17 @@ var Opensteer = class _Opensteer {
|
|
|
7529
8331
|
this.contextRef = null;
|
|
7530
8332
|
this.ownsBrowser = false;
|
|
7531
8333
|
}
|
|
7532
|
-
async
|
|
7533
|
-
if (!this.
|
|
8334
|
+
async syncLocalSelectorCacheToCloud() {
|
|
8335
|
+
if (!this.cloud) return;
|
|
7534
8336
|
const entries = collectLocalSelectorCacheEntries(this.storage);
|
|
7535
8337
|
if (!entries.length) return;
|
|
7536
|
-
await this.
|
|
8338
|
+
await this.cloud.sessionClient.importSelectorCache({
|
|
7537
8339
|
entries
|
|
7538
8340
|
});
|
|
7539
8341
|
}
|
|
7540
8342
|
async goto(url, options) {
|
|
7541
|
-
if (this.
|
|
7542
|
-
await this.
|
|
8343
|
+
if (this.cloud) {
|
|
8344
|
+
await this.invokeCloudActionAndResetCache("goto", { url, options });
|
|
7543
8345
|
return;
|
|
7544
8346
|
}
|
|
7545
8347
|
const { waitUntil = "domcontentloaded", ...rest } = options ?? {};
|
|
@@ -7548,8 +8350,8 @@ var Opensteer = class _Opensteer {
|
|
|
7548
8350
|
this.snapshotCache = null;
|
|
7549
8351
|
}
|
|
7550
8352
|
async snapshot(options = {}) {
|
|
7551
|
-
if (this.
|
|
7552
|
-
return await this.
|
|
8353
|
+
if (this.cloud) {
|
|
8354
|
+
return await this.invokeCloudActionAndResetCache("snapshot", {
|
|
7553
8355
|
options
|
|
7554
8356
|
});
|
|
7555
8357
|
}
|
|
@@ -7558,8 +8360,8 @@ var Opensteer = class _Opensteer {
|
|
|
7558
8360
|
return prepared.cleanedHtml;
|
|
7559
8361
|
}
|
|
7560
8362
|
async state() {
|
|
7561
|
-
if (this.
|
|
7562
|
-
return await this.
|
|
8363
|
+
if (this.cloud) {
|
|
8364
|
+
return await this.invokeCloudAction("state", {});
|
|
7563
8365
|
}
|
|
7564
8366
|
const html = await this.snapshot({ mode: "action" });
|
|
7565
8367
|
return {
|
|
@@ -7569,8 +8371,8 @@ var Opensteer = class _Opensteer {
|
|
|
7569
8371
|
};
|
|
7570
8372
|
}
|
|
7571
8373
|
async screenshot(options = {}) {
|
|
7572
|
-
if (this.
|
|
7573
|
-
const b64 = await this.
|
|
8374
|
+
if (this.cloud) {
|
|
8375
|
+
const b64 = await this.invokeCloudAction(
|
|
7574
8376
|
"screenshot",
|
|
7575
8377
|
options
|
|
7576
8378
|
);
|
|
@@ -7584,8 +8386,8 @@ var Opensteer = class _Opensteer {
|
|
|
7584
8386
|
});
|
|
7585
8387
|
}
|
|
7586
8388
|
async click(options) {
|
|
7587
|
-
if (this.
|
|
7588
|
-
return await this.
|
|
8389
|
+
if (this.cloud) {
|
|
8390
|
+
return await this.invokeCloudActionAndResetCache(
|
|
7589
8391
|
"click",
|
|
7590
8392
|
options
|
|
7591
8393
|
);
|
|
@@ -7597,8 +8399,8 @@ var Opensteer = class _Opensteer {
|
|
|
7597
8399
|
});
|
|
7598
8400
|
}
|
|
7599
8401
|
async dblclick(options) {
|
|
7600
|
-
if (this.
|
|
7601
|
-
return await this.
|
|
8402
|
+
if (this.cloud) {
|
|
8403
|
+
return await this.invokeCloudActionAndResetCache(
|
|
7602
8404
|
"dblclick",
|
|
7603
8405
|
options
|
|
7604
8406
|
);
|
|
@@ -7610,8 +8412,8 @@ var Opensteer = class _Opensteer {
|
|
|
7610
8412
|
});
|
|
7611
8413
|
}
|
|
7612
8414
|
async rightclick(options) {
|
|
7613
|
-
if (this.
|
|
7614
|
-
return await this.
|
|
8415
|
+
if (this.cloud) {
|
|
8416
|
+
return await this.invokeCloudActionAndResetCache(
|
|
7615
8417
|
"rightclick",
|
|
7616
8418
|
options
|
|
7617
8419
|
);
|
|
@@ -7623,8 +8425,8 @@ var Opensteer = class _Opensteer {
|
|
|
7623
8425
|
});
|
|
7624
8426
|
}
|
|
7625
8427
|
async hover(options) {
|
|
7626
|
-
if (this.
|
|
7627
|
-
return await this.
|
|
8428
|
+
if (this.cloud) {
|
|
8429
|
+
return await this.invokeCloudActionAndResetCache(
|
|
7628
8430
|
"hover",
|
|
7629
8431
|
options
|
|
7630
8432
|
);
|
|
@@ -7722,8 +8524,8 @@ var Opensteer = class _Opensteer {
|
|
|
7722
8524
|
);
|
|
7723
8525
|
}
|
|
7724
8526
|
async input(options) {
|
|
7725
|
-
if (this.
|
|
7726
|
-
return await this.
|
|
8527
|
+
if (this.cloud) {
|
|
8528
|
+
return await this.invokeCloudActionAndResetCache(
|
|
7727
8529
|
"input",
|
|
7728
8530
|
options
|
|
7729
8531
|
);
|
|
@@ -7752,7 +8554,7 @@ var Opensteer = class _Opensteer {
|
|
|
7752
8554
|
await handle.type(options.text);
|
|
7753
8555
|
}
|
|
7754
8556
|
if (options.pressEnter) {
|
|
7755
|
-
await handle.press("Enter");
|
|
8557
|
+
await handle.press("Enter", { noWaitAfter: true });
|
|
7756
8558
|
}
|
|
7757
8559
|
});
|
|
7758
8560
|
} catch (err) {
|
|
@@ -7825,8 +8627,8 @@ var Opensteer = class _Opensteer {
|
|
|
7825
8627
|
);
|
|
7826
8628
|
}
|
|
7827
8629
|
async select(options) {
|
|
7828
|
-
if (this.
|
|
7829
|
-
return await this.
|
|
8630
|
+
if (this.cloud) {
|
|
8631
|
+
return await this.invokeCloudActionAndResetCache(
|
|
7830
8632
|
"select",
|
|
7831
8633
|
options
|
|
7832
8634
|
);
|
|
@@ -7935,8 +8737,8 @@ var Opensteer = class _Opensteer {
|
|
|
7935
8737
|
);
|
|
7936
8738
|
}
|
|
7937
8739
|
async scroll(options = {}) {
|
|
7938
|
-
if (this.
|
|
7939
|
-
return await this.
|
|
8740
|
+
if (this.cloud) {
|
|
8741
|
+
return await this.invokeCloudActionAndResetCache(
|
|
7940
8742
|
"scroll",
|
|
7941
8743
|
options
|
|
7942
8744
|
);
|
|
@@ -8037,14 +8839,14 @@ var Opensteer = class _Opensteer {
|
|
|
8037
8839
|
}
|
|
8038
8840
|
// --- Tab Management ---
|
|
8039
8841
|
async tabs() {
|
|
8040
|
-
if (this.
|
|
8041
|
-
return await this.
|
|
8842
|
+
if (this.cloud) {
|
|
8843
|
+
return await this.invokeCloudAction("tabs", {});
|
|
8042
8844
|
}
|
|
8043
8845
|
return listTabs(this.context, this.page);
|
|
8044
8846
|
}
|
|
8045
8847
|
async newTab(url) {
|
|
8046
|
-
if (this.
|
|
8047
|
-
return await this.
|
|
8848
|
+
if (this.cloud) {
|
|
8849
|
+
return await this.invokeCloudActionAndResetCache("newTab", {
|
|
8048
8850
|
url
|
|
8049
8851
|
});
|
|
8050
8852
|
}
|
|
@@ -8054,8 +8856,8 @@ var Opensteer = class _Opensteer {
|
|
|
8054
8856
|
return info;
|
|
8055
8857
|
}
|
|
8056
8858
|
async switchTab(index) {
|
|
8057
|
-
if (this.
|
|
8058
|
-
await this.
|
|
8859
|
+
if (this.cloud) {
|
|
8860
|
+
await this.invokeCloudActionAndResetCache("switchTab", { index });
|
|
8059
8861
|
return;
|
|
8060
8862
|
}
|
|
8061
8863
|
const page = await switchTab(this.context, index);
|
|
@@ -8063,8 +8865,8 @@ var Opensteer = class _Opensteer {
|
|
|
8063
8865
|
this.snapshotCache = null;
|
|
8064
8866
|
}
|
|
8065
8867
|
async closeTab(index) {
|
|
8066
|
-
if (this.
|
|
8067
|
-
await this.
|
|
8868
|
+
if (this.cloud) {
|
|
8869
|
+
await this.invokeCloudActionAndResetCache("closeTab", { index });
|
|
8068
8870
|
return;
|
|
8069
8871
|
}
|
|
8070
8872
|
const newPage = await closeTab(this.context, this.page, index);
|
|
@@ -8075,8 +8877,8 @@ var Opensteer = class _Opensteer {
|
|
|
8075
8877
|
}
|
|
8076
8878
|
// --- Cookie Management ---
|
|
8077
8879
|
async getCookies(url) {
|
|
8078
|
-
if (this.
|
|
8079
|
-
return await this.
|
|
8880
|
+
if (this.cloud) {
|
|
8881
|
+
return await this.invokeCloudAction(
|
|
8080
8882
|
"getCookies",
|
|
8081
8883
|
{ url }
|
|
8082
8884
|
);
|
|
@@ -8084,41 +8886,41 @@ var Opensteer = class _Opensteer {
|
|
|
8084
8886
|
return getCookies(this.context, url);
|
|
8085
8887
|
}
|
|
8086
8888
|
async setCookie(cookie) {
|
|
8087
|
-
if (this.
|
|
8088
|
-
await this.
|
|
8889
|
+
if (this.cloud) {
|
|
8890
|
+
await this.invokeCloudAction("setCookie", cookie);
|
|
8089
8891
|
return;
|
|
8090
8892
|
}
|
|
8091
8893
|
return setCookie(this.context, cookie);
|
|
8092
8894
|
}
|
|
8093
8895
|
async clearCookies() {
|
|
8094
|
-
if (this.
|
|
8095
|
-
await this.
|
|
8896
|
+
if (this.cloud) {
|
|
8897
|
+
await this.invokeCloudAction("clearCookies", {});
|
|
8096
8898
|
return;
|
|
8097
8899
|
}
|
|
8098
8900
|
return clearCookies(this.context);
|
|
8099
8901
|
}
|
|
8100
8902
|
async exportCookies(filePath, url) {
|
|
8101
|
-
if (this.
|
|
8102
|
-
throw
|
|
8903
|
+
if (this.cloud) {
|
|
8904
|
+
throw cloudUnsupportedMethodError(
|
|
8103
8905
|
"exportCookies",
|
|
8104
|
-
"exportCookies() is not supported in
|
|
8906
|
+
"exportCookies() is not supported in cloud mode because it depends on local filesystem paths."
|
|
8105
8907
|
);
|
|
8106
8908
|
}
|
|
8107
8909
|
return exportCookies(this.context, filePath, url);
|
|
8108
8910
|
}
|
|
8109
8911
|
async importCookies(filePath) {
|
|
8110
|
-
if (this.
|
|
8111
|
-
throw
|
|
8912
|
+
if (this.cloud) {
|
|
8913
|
+
throw cloudUnsupportedMethodError(
|
|
8112
8914
|
"importCookies",
|
|
8113
|
-
"importCookies() is not supported in
|
|
8915
|
+
"importCookies() is not supported in cloud mode because it depends on local filesystem paths."
|
|
8114
8916
|
);
|
|
8115
8917
|
}
|
|
8116
8918
|
return importCookies(this.context, filePath);
|
|
8117
8919
|
}
|
|
8118
8920
|
// --- Keyboard Input ---
|
|
8119
8921
|
async pressKey(key) {
|
|
8120
|
-
if (this.
|
|
8121
|
-
await this.
|
|
8922
|
+
if (this.cloud) {
|
|
8923
|
+
await this.invokeCloudActionAndResetCache("pressKey", { key });
|
|
8122
8924
|
return;
|
|
8123
8925
|
}
|
|
8124
8926
|
await this.runWithPostActionWait("pressKey", void 0, async () => {
|
|
@@ -8127,8 +8929,8 @@ var Opensteer = class _Opensteer {
|
|
|
8127
8929
|
this.snapshotCache = null;
|
|
8128
8930
|
}
|
|
8129
8931
|
async type(text) {
|
|
8130
|
-
if (this.
|
|
8131
|
-
await this.
|
|
8932
|
+
if (this.cloud) {
|
|
8933
|
+
await this.invokeCloudActionAndResetCache("type", { text });
|
|
8132
8934
|
return;
|
|
8133
8935
|
}
|
|
8134
8936
|
await this.runWithPostActionWait("type", void 0, async () => {
|
|
@@ -8138,8 +8940,8 @@ var Opensteer = class _Opensteer {
|
|
|
8138
8940
|
}
|
|
8139
8941
|
// --- Element Info ---
|
|
8140
8942
|
async getElementText(options) {
|
|
8141
|
-
if (this.
|
|
8142
|
-
return await this.
|
|
8943
|
+
if (this.cloud) {
|
|
8944
|
+
return await this.invokeCloudAction("getElementText", options);
|
|
8143
8945
|
}
|
|
8144
8946
|
return this.executeElementInfoAction(
|
|
8145
8947
|
"getElementText",
|
|
@@ -8152,8 +8954,8 @@ var Opensteer = class _Opensteer {
|
|
|
8152
8954
|
);
|
|
8153
8955
|
}
|
|
8154
8956
|
async getElementValue(options) {
|
|
8155
|
-
if (this.
|
|
8156
|
-
return await this.
|
|
8957
|
+
if (this.cloud) {
|
|
8958
|
+
return await this.invokeCloudAction(
|
|
8157
8959
|
"getElementValue",
|
|
8158
8960
|
options
|
|
8159
8961
|
);
|
|
@@ -8168,8 +8970,8 @@ var Opensteer = class _Opensteer {
|
|
|
8168
8970
|
);
|
|
8169
8971
|
}
|
|
8170
8972
|
async getElementAttributes(options) {
|
|
8171
|
-
if (this.
|
|
8172
|
-
return await this.
|
|
8973
|
+
if (this.cloud) {
|
|
8974
|
+
return await this.invokeCloudAction(
|
|
8173
8975
|
"getElementAttributes",
|
|
8174
8976
|
options
|
|
8175
8977
|
);
|
|
@@ -8190,8 +8992,8 @@ var Opensteer = class _Opensteer {
|
|
|
8190
8992
|
);
|
|
8191
8993
|
}
|
|
8192
8994
|
async getElementBoundingBox(options) {
|
|
8193
|
-
if (this.
|
|
8194
|
-
return await this.
|
|
8995
|
+
if (this.cloud) {
|
|
8996
|
+
return await this.invokeCloudAction(
|
|
8195
8997
|
"getElementBoundingBox",
|
|
8196
8998
|
options
|
|
8197
8999
|
);
|
|
@@ -8206,14 +9008,14 @@ var Opensteer = class _Opensteer {
|
|
|
8206
9008
|
);
|
|
8207
9009
|
}
|
|
8208
9010
|
async getHtml(selector) {
|
|
8209
|
-
if (this.
|
|
8210
|
-
return await this.
|
|
9011
|
+
if (this.cloud) {
|
|
9012
|
+
return await this.invokeCloudAction("getHtml", { selector });
|
|
8211
9013
|
}
|
|
8212
9014
|
return getPageHtml(this.page, selector);
|
|
8213
9015
|
}
|
|
8214
9016
|
async getTitle() {
|
|
8215
|
-
if (this.
|
|
8216
|
-
return await this.
|
|
9017
|
+
if (this.cloud) {
|
|
9018
|
+
return await this.invokeCloudAction("getTitle", {});
|
|
8217
9019
|
}
|
|
8218
9020
|
return getPageTitle(this.page);
|
|
8219
9021
|
}
|
|
@@ -8251,10 +9053,10 @@ var Opensteer = class _Opensteer {
|
|
|
8251
9053
|
}
|
|
8252
9054
|
// --- File Upload ---
|
|
8253
9055
|
async uploadFile(options) {
|
|
8254
|
-
if (this.
|
|
8255
|
-
throw
|
|
9056
|
+
if (this.cloud) {
|
|
9057
|
+
throw cloudUnsupportedMethodError(
|
|
8256
9058
|
"uploadFile",
|
|
8257
|
-
"uploadFile() is not supported in
|
|
9059
|
+
"uploadFile() is not supported in cloud mode because file paths must be accessible on the cloud runtime."
|
|
8258
9060
|
);
|
|
8259
9061
|
}
|
|
8260
9062
|
const storageKey = this.resolveStorageKey(options.description);
|
|
@@ -8356,15 +9158,15 @@ var Opensteer = class _Opensteer {
|
|
|
8356
9158
|
}
|
|
8357
9159
|
// --- Wait for Text ---
|
|
8358
9160
|
async waitForText(text, options) {
|
|
8359
|
-
if (this.
|
|
8360
|
-
await this.
|
|
9161
|
+
if (this.cloud) {
|
|
9162
|
+
await this.invokeCloudAction("waitForText", { text, options });
|
|
8361
9163
|
return;
|
|
8362
9164
|
}
|
|
8363
9165
|
await this.page.getByText(text).first().waitFor({ timeout: options?.timeout ?? 3e4 });
|
|
8364
9166
|
}
|
|
8365
9167
|
async extract(options) {
|
|
8366
|
-
if (this.
|
|
8367
|
-
return await this.
|
|
9168
|
+
if (this.cloud) {
|
|
9169
|
+
return await this.invokeCloudAction("extract", options);
|
|
8368
9170
|
}
|
|
8369
9171
|
const storageKey = this.resolveStorageKey(options.description);
|
|
8370
9172
|
const schemaHash = options.schema ? computeSchemaHash(options.schema) : null;
|
|
@@ -8416,8 +9218,8 @@ var Opensteer = class _Opensteer {
|
|
|
8416
9218
|
return inflateDataPathObject(data);
|
|
8417
9219
|
}
|
|
8418
9220
|
async extractFromPlan(options) {
|
|
8419
|
-
if (this.
|
|
8420
|
-
return await this.
|
|
9221
|
+
if (this.cloud) {
|
|
9222
|
+
return await this.invokeCloudAction(
|
|
8421
9223
|
"extractFromPlan",
|
|
8422
9224
|
options
|
|
8423
9225
|
);
|
|
@@ -8466,10 +9268,10 @@ var Opensteer = class _Opensteer {
|
|
|
8466
9268
|
return this.storage;
|
|
8467
9269
|
}
|
|
8468
9270
|
clearCache() {
|
|
8469
|
-
if (this.
|
|
9271
|
+
if (this.cloud) {
|
|
8470
9272
|
this.snapshotCache = null;
|
|
8471
|
-
if (!this.
|
|
8472
|
-
void this.
|
|
9273
|
+
if (!this.cloud.actionClient) return;
|
|
9274
|
+
void this.invokeCloudAction("clearCache", {});
|
|
8473
9275
|
return;
|
|
8474
9276
|
}
|
|
8475
9277
|
this.storage.clearNamespace();
|
|
@@ -9497,6 +10299,16 @@ function getScrollDelta2(options) {
|
|
|
9497
10299
|
return { x: 0, y: absoluteAmount };
|
|
9498
10300
|
}
|
|
9499
10301
|
}
|
|
10302
|
+
function buildLocalRunId(namespace) {
|
|
10303
|
+
const normalized = namespace.trim() || "default";
|
|
10304
|
+
return `${normalized}-${Date.now().toString(36)}-${(0, import_crypto2.randomUUID)().slice(0, 8)}`;
|
|
10305
|
+
}
|
|
10306
|
+
function buildCloudSessionUrl(appUrl, sessionId) {
|
|
10307
|
+
if (!appUrl) {
|
|
10308
|
+
return null;
|
|
10309
|
+
}
|
|
10310
|
+
return `${appUrl}/browser/${encodeURIComponent(sessionId)}`;
|
|
10311
|
+
}
|
|
9500
10312
|
|
|
9501
10313
|
// src/cli/paths.ts
|
|
9502
10314
|
var import_os2 = require("os");
|
|
@@ -9898,7 +10710,8 @@ async function handleRequest(request, socket) {
|
|
|
9898
10710
|
url: instance.page.url(),
|
|
9899
10711
|
session,
|
|
9900
10712
|
name: activeNamespace,
|
|
9901
|
-
|
|
10713
|
+
cloudSessionId: instance.getCloudSessionId() ?? void 0,
|
|
10714
|
+
cloudSessionUrl: instance.getCloudSessionUrl() ?? void 0
|
|
9902
10715
|
}
|
|
9903
10716
|
});
|
|
9904
10717
|
} catch (err) {
|