stagehand 4.4.0a0.dev1673__tar.gz → 4.4.0a0.dev1676__tar.gz
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.
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/PKG-INFO +1 -1
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/pyproject.toml +1 -1
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_extension/manifest.json +2 -1
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_extension/service-worker.js +262 -230
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_generated/protocol_version.py +1 -1
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/README.md +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/__init__.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_extension/blank.html +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_extension/content-script.js +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_extension/offscreen/service-worker-heartbeat.html +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_extension/offscreen/service-worker-heartbeat.js +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_extension/wake-service-worker.html +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_extension/wake-service-worker.js +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_generated/__init__.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_generated/input_types.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_generated/models.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_sdk_identity.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_validation.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/browser.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/browser_clipboard.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/browser_context.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/browserbase_connection.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/browserbase_rpc.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/browserbase_services.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/browserbase_session.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/browserbase_transport.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/cdp_client.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/client_models.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/client_types.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/extension_assets.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/file_upload.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/locator.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/page.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/py.typed +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/response.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/rpc_client.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/stagehand.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/timeouts.py +0 -0
- {stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/webmcp.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: stagehand
|
|
3
|
-
Version: 4.4.0a0.
|
|
3
|
+
Version: 4.4.0a0.dev1676
|
|
4
4
|
Summary: Browserbase's SDK for building browser agents
|
|
5
5
|
Keywords: ai,agent,ai-agent,browser,browser-agent,browser-automation,computer-use,headless,playwright,cdp,llm,automation,web-scraping,testing
|
|
6
6
|
Author: Browserbase
|
{stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_extension/service-worker.js
RENAMED
|
@@ -9206,7 +9206,7 @@ function isRecord$2(value) {
|
|
|
9206
9206
|
}
|
|
9207
9207
|
var package_default$1 = {
|
|
9208
9208
|
name: "@browserbasehq/stagehand-protocol",
|
|
9209
|
-
version: "3.1.1-alpha-
|
|
9209
|
+
version: "3.1.1-alpha-c82e6170c29ab6fb17c4a10e44812bd29507e7d4",
|
|
9210
9210
|
"private": true,
|
|
9211
9211
|
type: "module",
|
|
9212
9212
|
exports: {
|
|
@@ -18454,18 +18454,6 @@ async function waitForDomNetworkQuiet(frame, logger, timeout, progress) {
|
|
|
18454
18454
|
if (remainingBudget === 0) return;
|
|
18455
18455
|
await progress.run("enabling network events", () => client.send("Network.enable").catch(() => {}));
|
|
18456
18456
|
await progress.run("enabling page events", () => client.send("Page.enable").catch(() => {}));
|
|
18457
|
-
await progress.run("attaching to frames", () => client.send("Target.setAutoAttach", {
|
|
18458
|
-
autoAttach: true,
|
|
18459
|
-
waitForDebuggerOnStart: false,
|
|
18460
|
-
flatten: true,
|
|
18461
|
-
filter: [{
|
|
18462
|
-
type: "worker",
|
|
18463
|
-
exclude: true
|
|
18464
|
-
}, {
|
|
18465
|
-
type: "shared_worker",
|
|
18466
|
-
exclude: true
|
|
18467
|
-
}]
|
|
18468
|
-
}).catch(() => {}));
|
|
18469
18457
|
progress.throwIfStopped();
|
|
18470
18458
|
await new Promise((resolve) => {
|
|
18471
18459
|
const inflight = /* @__PURE__ */ new Set();
|
|
@@ -66131,7 +66119,7 @@ var WebTracerProvider = class extends BasicTracerProvider {
|
|
|
66131
66119
|
};
|
|
66132
66120
|
var package_default = {
|
|
66133
66121
|
name: "@browserbasehq/stagehand-extension",
|
|
66134
|
-
version: "1.3.0-alpha-
|
|
66122
|
+
version: "1.3.0-alpha-c82e6170c29ab6fb17c4a10e44812bd29507e7d4",
|
|
66135
66123
|
"private": true,
|
|
66136
66124
|
type: "module",
|
|
66137
66125
|
scripts: {
|
|
@@ -70124,6 +70112,7 @@ var StagehandRuntime = class {
|
|
|
70124
70112
|
this.state = createStore()(() => StagehandRuntimeStateSchema.parse({ status: "idle" }));
|
|
70125
70113
|
this.pagesById = /* @__PURE__ */ new Map();
|
|
70126
70114
|
this.pageEventSubscriptions = /* @__PURE__ */ new Map();
|
|
70115
|
+
this.pendingBrowserSessionCleanup = /* @__PURE__ */ new Map();
|
|
70127
70116
|
this.browserConnectionGeneration = 0;
|
|
70128
70117
|
this.initializationInProgress = false;
|
|
70129
70118
|
this.lifecycleTail = Promise.resolve();
|
|
@@ -70134,39 +70123,49 @@ var StagehandRuntime = class {
|
|
|
70134
70123
|
async replaceBrowserConnection(params, bootstrapLogger) {
|
|
70135
70124
|
const { cdpUrl } = params;
|
|
70136
70125
|
const generation = ++this.browserConnectionGeneration;
|
|
70137
|
-
|
|
70126
|
+
if (this.browserSession && !this.pendingBrowserSessionCleanup.has(this.browserSession)) this.pendingBrowserSessionCleanup.set(this.browserSession, void 0);
|
|
70138
70127
|
this.browserSession = void 0;
|
|
70139
70128
|
this.browserSessionCdpUrl = void 0;
|
|
70140
70129
|
this.disposeAllPageEventSubscriptions();
|
|
70141
70130
|
this.pagesById.clear();
|
|
70142
70131
|
this.responseHandles.clear();
|
|
70143
|
-
await
|
|
70144
|
-
|
|
70145
|
-
|
|
70146
|
-
|
|
70147
|
-
|
|
70148
|
-
|
|
70149
|
-
}
|
|
70150
|
-
this.browserSession = session;
|
|
70151
|
-
this.browserSessionCdpUrl = cdpUrl;
|
|
70152
|
-
} catch (error) {
|
|
70153
|
-
if (generation === this.browserConnectionGeneration) {
|
|
70154
|
-
await this.browserSession?.close();
|
|
70155
|
-
this.browserSession = void 0;
|
|
70156
|
-
}
|
|
70157
|
-
throw error;
|
|
70132
|
+
await this.runPendingSessionCleanup();
|
|
70133
|
+
if (generation !== this.browserConnectionGeneration) throw new Error("Stagehand browser connection was dropped while connecting");
|
|
70134
|
+
const session = await this.adapters.browserSessionFactory(cdpUrl, this.logger, bootstrapLogger);
|
|
70135
|
+
if (generation !== this.browserConnectionGeneration) {
|
|
70136
|
+
await this.cleanupSession(session);
|
|
70137
|
+
throw new Error("Stagehand browser connection was dropped while connecting");
|
|
70158
70138
|
}
|
|
70139
|
+
this.browserSession = session;
|
|
70140
|
+
this.browserSessionCdpUrl = cdpUrl;
|
|
70159
70141
|
}
|
|
70160
70142
|
/**
|
|
70161
70143
|
* Closes the runtime's own browser connection immediately, outside the lifecycle
|
|
70162
70144
|
* queue: a lost client must not wait behind lifecycle work that needs that client.
|
|
70163
70145
|
*/
|
|
70164
|
-
async
|
|
70146
|
+
async disconnectBrowser() {
|
|
70165
70147
|
this.browserConnectionGeneration += 1;
|
|
70166
|
-
|
|
70148
|
+
if (this.browserSession && !this.pendingBrowserSessionCleanup.has(this.browserSession)) this.pendingBrowserSessionCleanup.set(this.browserSession, void 0);
|
|
70167
70149
|
this.browserSession = void 0;
|
|
70168
70150
|
this.browserSessionCdpUrl = void 0;
|
|
70169
|
-
await
|
|
70151
|
+
await this.runPendingSessionCleanup();
|
|
70152
|
+
}
|
|
70153
|
+
cleanupSession(session) {
|
|
70154
|
+
const pending = this.pendingBrowserSessionCleanup.get(session);
|
|
70155
|
+
if (pending) return pending;
|
|
70156
|
+
const closing = Promise.resolve().then(() => session.close()).then(() => {
|
|
70157
|
+
this.pendingBrowserSessionCleanup.delete(session);
|
|
70158
|
+
}, (error) => {
|
|
70159
|
+
this.pendingBrowserSessionCleanup.set(session, void 0);
|
|
70160
|
+
throw error;
|
|
70161
|
+
});
|
|
70162
|
+
this.pendingBrowserSessionCleanup.set(session, closing);
|
|
70163
|
+
return closing;
|
|
70164
|
+
}
|
|
70165
|
+
async runPendingSessionCleanup() {
|
|
70166
|
+
const errors = (await Promise.allSettled(Array.from(this.pendingBrowserSessionCleanup.keys(), (session) => this.cleanupSession(session)))).flatMap((result) => result.status === "rejected" ? [result.reason] : []);
|
|
70167
|
+
if (errors.length === 1) throw errors[0];
|
|
70168
|
+
if (errors.length > 1) throw new AggregateError(errors, "Browser session cleanup failed");
|
|
70170
70169
|
}
|
|
70171
70170
|
async ensureBrowserConnection(cdpUrl) {
|
|
70172
70171
|
if (!this.browserSession?.connected || this.browserSessionCdpUrl !== cdpUrl) await this.replaceBrowserConnection({ cdpUrl });
|
|
@@ -70582,11 +70581,9 @@ var StagehandRuntime = class {
|
|
|
70582
70581
|
}
|
|
70583
70582
|
async close() {
|
|
70584
70583
|
await this.enqueueLifecycle(async () => {
|
|
70585
|
-
const session = this.browserSession;
|
|
70586
|
-
this.browserSession = void 0;
|
|
70587
|
-
this.browserSessionCdpUrl = void 0;
|
|
70588
70584
|
this.clearStagehandInstance();
|
|
70589
|
-
await
|
|
70585
|
+
await this.disconnectBrowser();
|
|
70586
|
+
if (!this.stagehandInstanceDisposal) this.stagehandInstanceClosing = false;
|
|
70590
70587
|
});
|
|
70591
70588
|
}
|
|
70592
70589
|
async disposeStagehandInstance() {
|
|
@@ -70595,10 +70592,13 @@ var StagehandRuntime = class {
|
|
|
70595
70592
|
const disposal = this.enqueueLifecycle(async () => {
|
|
70596
70593
|
this.disposeAllPageEventSubscriptions();
|
|
70597
70594
|
await this.waitForStagehandInstanceRequests();
|
|
70595
|
+
const session = this.browserSession;
|
|
70596
|
+
if (session?.getDomainPolicy()) await session.setDomainPolicy(null);
|
|
70597
|
+
await this.runPendingSessionCleanup();
|
|
70598
70598
|
this.clearStagehandInstance();
|
|
70599
|
+
this.stagehandInstanceClosing = false;
|
|
70599
70600
|
});
|
|
70600
70601
|
this.stagehandInstanceDisposal = disposal.finally(() => {
|
|
70601
|
-
this.stagehandInstanceClosing = false;
|
|
70602
70602
|
this.stagehandInstanceDisposal = void 0;
|
|
70603
70603
|
});
|
|
70604
70604
|
return await this.stagehandInstanceDisposal;
|
|
@@ -71042,7 +71042,6 @@ function cookieMatchesFilter(cookie, options) {
|
|
|
71042
71042
|
//#endregion
|
|
71043
71043
|
//#region understudy/domainPolicy.ts
|
|
71044
71044
|
var DOMAIN_LABEL_RE = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
71045
|
-
var HTTP_SCHEMES = ["http", "https"];
|
|
71046
71045
|
function canonicalizeHostname(hostname) {
|
|
71047
71046
|
return hostname.toLowerCase().replace(/\.+$/, "");
|
|
71048
71047
|
}
|
|
@@ -71095,30 +71094,6 @@ function getDomainPatterns(policy, key) {
|
|
|
71095
71094
|
function patternHost(rule) {
|
|
71096
71095
|
return rule.type === "wildcard" ? `*.${rule.hostname}` : rule.hostname;
|
|
71097
71096
|
}
|
|
71098
|
-
function fetchPatternHosts(rule) {
|
|
71099
|
-
const host = patternHost(rule);
|
|
71100
|
-
return [host, `${host}.`];
|
|
71101
|
-
}
|
|
71102
|
-
function toBlocklistFetchPatterns(rules) {
|
|
71103
|
-
const patterns = [];
|
|
71104
|
-
for (const rule of rules) for (const host of fetchPatternHosts(rule)) for (const scheme of HTTP_SCHEMES) {
|
|
71105
|
-
patterns.push({
|
|
71106
|
-
urlPattern: `${scheme}://${host}/*`,
|
|
71107
|
-
requestStage: "Request"
|
|
71108
|
-
});
|
|
71109
|
-
patterns.push({
|
|
71110
|
-
urlPattern: `${scheme}://${host}:*/*`,
|
|
71111
|
-
requestStage: "Request"
|
|
71112
|
-
});
|
|
71113
|
-
}
|
|
71114
|
-
return patterns;
|
|
71115
|
-
}
|
|
71116
|
-
function toAllowlistFetchPatterns() {
|
|
71117
|
-
return HTTP_SCHEMES.map((scheme) => ({
|
|
71118
|
-
urlPattern: `${scheme}://*/*`,
|
|
71119
|
-
requestStage: "Request"
|
|
71120
|
-
}));
|
|
71121
|
-
}
|
|
71122
71097
|
function normalizeDomainPolicy(policy) {
|
|
71123
71098
|
const allowedDomains = getDomainPatterns(policy, "allowedDomains");
|
|
71124
71099
|
const blockedDomains = getDomainPatterns(policy, "blockedDomains");
|
|
@@ -71129,8 +71104,7 @@ function normalizeDomainPolicy(policy) {
|
|
|
71129
71104
|
allowedDomains: allowedDomainRules.map(patternHost),
|
|
71130
71105
|
blockedDomains: blockedDomainRules.map(patternHost),
|
|
71131
71106
|
allowedDomainRules,
|
|
71132
|
-
blockedDomainRules
|
|
71133
|
-
fetchPatterns: allowedDomainRules.length ? toAllowlistFetchPatterns() : toBlocklistFetchPatterns(blockedDomainRules)
|
|
71107
|
+
blockedDomainRules
|
|
71134
71108
|
};
|
|
71135
71109
|
}
|
|
71136
71110
|
function hostnameFromHttpUrl(url) {
|
|
@@ -71162,6 +71136,53 @@ function getDomainPolicyDecision(url, policy) {
|
|
|
71162
71136
|
};
|
|
71163
71137
|
return { action: "continue" };
|
|
71164
71138
|
}
|
|
71139
|
+
/**
|
|
71140
|
+
* Compile a normalized policy into browser-wide DNR session rules without installing them.
|
|
71141
|
+
* IDs are deterministic within this rule set; the installer must own their namespace.
|
|
71142
|
+
* Chrome rule limits and regex support must be checked by the installer before activation.
|
|
71143
|
+
*/
|
|
71144
|
+
function toDomainPolicyDnrRules(policy) {
|
|
71145
|
+
if (!policy) return [];
|
|
71146
|
+
const rules = [];
|
|
71147
|
+
const addRule = (type, priority, regexFilter) => {
|
|
71148
|
+
rules.push({
|
|
71149
|
+
id: rules.length + 1,
|
|
71150
|
+
priority,
|
|
71151
|
+
action: { type },
|
|
71152
|
+
condition: {
|
|
71153
|
+
regexFilter,
|
|
71154
|
+
isUrlFilterCaseSensitive: false,
|
|
71155
|
+
resourceTypes: [
|
|
71156
|
+
"main_frame",
|
|
71157
|
+
"sub_frame",
|
|
71158
|
+
"stylesheet",
|
|
71159
|
+
"script",
|
|
71160
|
+
"image",
|
|
71161
|
+
"font",
|
|
71162
|
+
"object",
|
|
71163
|
+
"xmlhttprequest",
|
|
71164
|
+
"ping",
|
|
71165
|
+
"csp_report",
|
|
71166
|
+
"media",
|
|
71167
|
+
"websocket",
|
|
71168
|
+
"webtransport",
|
|
71169
|
+
"webbundle",
|
|
71170
|
+
"other"
|
|
71171
|
+
]
|
|
71172
|
+
}
|
|
71173
|
+
});
|
|
71174
|
+
};
|
|
71175
|
+
if (policy.allowedDomainRules.length) {
|
|
71176
|
+
addRule("block", 1, "^https?://");
|
|
71177
|
+
for (const rule of policy.allowedDomainRules) addRule("allow", 2, domainRuleDnrRegex(rule));
|
|
71178
|
+
}
|
|
71179
|
+
for (const rule of policy.blockedDomainRules) addRule("block", 3, domainRuleDnrRegex(rule));
|
|
71180
|
+
return rules;
|
|
71181
|
+
}
|
|
71182
|
+
function domainRuleDnrRegex(rule) {
|
|
71183
|
+
const hostname = rule.hostname.replace(/\./g, "\\.");
|
|
71184
|
+
return `^https?://([^/?#@]*@)?${rule.type === "wildcard" ? "[^/?#@:]*\\." : ""}${hostname}\\.*(:[0-9]+)?(/|$)`;
|
|
71185
|
+
}
|
|
71165
71186
|
var RequestSchema = discriminatedUnion("action", [strictObject({
|
|
71166
71187
|
action: literal("attach"),
|
|
71167
71188
|
targetId: string().min(1),
|
|
@@ -71293,7 +71314,7 @@ var DEFAULT_ACTIVE_PAGE_TIMEOUT_MS = 3e3;
|
|
|
71293
71314
|
* so Page can record the correct owner at event time.
|
|
71294
71315
|
*/
|
|
71295
71316
|
var BrowserContext = class BrowserContext {
|
|
71296
|
-
constructor(conn, logger, chromeTabs, env = "LOCAL", localBrowserLaunchOptions = null, blankPageUrl = "about:blank", fallbackLocatorScriptSource = null) {
|
|
71317
|
+
constructor(conn, logger, chromeTabs, env = "LOCAL", localBrowserLaunchOptions = null, blankPageUrl = "about:blank", fallbackLocatorScriptSource = null, domainPolicyRules) {
|
|
71297
71318
|
this.conn = conn;
|
|
71298
71319
|
this.logger = logger;
|
|
71299
71320
|
this.chromeTabs = chromeTabs;
|
|
@@ -71301,8 +71322,8 @@ var BrowserContext = class BrowserContext {
|
|
|
71301
71322
|
this.localBrowserLaunchOptions = localBrowserLaunchOptions;
|
|
71302
71323
|
this.blankPageUrl = blankPageUrl;
|
|
71303
71324
|
this.fallbackLocatorScriptSource = fallbackLocatorScriptSource;
|
|
71325
|
+
this.domainPolicyRules = domainPolicyRules;
|
|
71304
71326
|
this._targetSessionListeners = /* @__PURE__ */ new Set();
|
|
71305
|
-
this._domainPolicySessionListeners = /* @__PURE__ */ new Map();
|
|
71306
71327
|
this._sessionInit = /* @__PURE__ */ new Set();
|
|
71307
71328
|
this.pagesByTarget = /* @__PURE__ */ new Map();
|
|
71308
71329
|
this.mainFrameToTarget = /* @__PURE__ */ new Map();
|
|
@@ -71322,6 +71343,8 @@ var BrowserContext = class BrowserContext {
|
|
|
71322
71343
|
this.initScripts = [];
|
|
71323
71344
|
this.extraHttpHeaders = null;
|
|
71324
71345
|
this.domainPolicy = null;
|
|
71346
|
+
this.domainPolicyTail = Promise.resolve();
|
|
71347
|
+
this.closing = false;
|
|
71325
71348
|
}
|
|
71326
71349
|
get connected() {
|
|
71327
71350
|
return this.conn.connected;
|
|
@@ -71350,13 +71373,22 @@ var BrowserContext = class BrowserContext {
|
|
|
71350
71373
|
static async create(wsUrl, opts) {
|
|
71351
71374
|
const connectTask = async () => {
|
|
71352
71375
|
const conn = await CdpConnection.connect(wsUrl, opts.websocketFactory, opts.logger);
|
|
71353
|
-
const ctx = new BrowserContext(conn, opts.logger, opts.chromeTabs, opts?.env ?? "LOCAL", opts?.localBrowserLaunchOptions ?? null, opts.blankPageUrl, opts.fallbackLocatorScriptSource);
|
|
71376
|
+
const ctx = new BrowserContext(conn, opts.logger, opts.chromeTabs, opts?.env ?? "LOCAL", opts?.localBrowserLaunchOptions ?? null, opts.blankPageUrl, opts.fallbackLocatorScriptSource, opts.domainPolicyRules);
|
|
71354
71377
|
const bootstrap = async () => {
|
|
71355
71378
|
await ctx.bootstrap();
|
|
71356
71379
|
if (!ctx.hasTopLevelPage()) await ctx.newPage();
|
|
71357
71380
|
};
|
|
71358
|
-
|
|
71359
|
-
|
|
71381
|
+
try {
|
|
71382
|
+
if (opts.bootstrapLogger) await conn.runWithTelemetryContext(Symbol("browser.bootstrap"), opts.bootstrapLogger, bootstrap);
|
|
71383
|
+
else await bootstrap();
|
|
71384
|
+
} catch (error) {
|
|
71385
|
+
try {
|
|
71386
|
+
await ctx.close();
|
|
71387
|
+
} catch (cleanupError) {
|
|
71388
|
+
throw new AggregateError([error, cleanupError], "Browser context initialization and cleanup failed");
|
|
71389
|
+
}
|
|
71390
|
+
throw error;
|
|
71391
|
+
}
|
|
71360
71392
|
return ctx;
|
|
71361
71393
|
};
|
|
71362
71394
|
return await connectTask();
|
|
@@ -71456,96 +71488,16 @@ var BrowserContext = class BrowserContext {
|
|
|
71456
71488
|
}
|
|
71457
71489
|
async setDomainPolicy(policy) {
|
|
71458
71490
|
const nextPolicy = normalizeDomainPolicy(policy);
|
|
71459
|
-
this.
|
|
71460
|
-
const
|
|
71461
|
-
|
|
71462
|
-
|
|
71463
|
-
if (
|
|
71464
|
-
|
|
71465
|
-
|
|
71466
|
-
const failures = (await Promise.allSettled(sessions.map(async (session) => {
|
|
71467
|
-
if (!nextPolicy) {
|
|
71468
|
-
try {
|
|
71469
|
-
await session.send("Fetch.disable");
|
|
71470
|
-
this.uninstallDomainPolicyHandler(session);
|
|
71471
|
-
} catch (error) {
|
|
71472
|
-
throw {
|
|
71473
|
-
action: "disable",
|
|
71474
|
-
error
|
|
71475
|
-
};
|
|
71476
|
-
}
|
|
71477
|
-
return;
|
|
71478
|
-
}
|
|
71479
|
-
this.installDomainPolicyHandler(session);
|
|
71480
|
-
try {
|
|
71481
|
-
await session.send("Fetch.enable", { patterns: nextPolicy.fetchPatterns });
|
|
71482
|
-
} catch (error) {
|
|
71483
|
-
throw {
|
|
71484
|
-
action: "enable",
|
|
71485
|
-
error
|
|
71486
|
-
};
|
|
71487
|
-
}
|
|
71488
|
-
}))).map((result, index) => ({
|
|
71489
|
-
result,
|
|
71490
|
-
session: sessions[index]
|
|
71491
|
-
})).filter((entry) => entry.result.status === "rejected").map((entry) => {
|
|
71492
|
-
const failure = entry.result.reason;
|
|
71493
|
-
if (failure?.action === "enable") this.uninstallDomainPolicyHandler(entry.session);
|
|
71494
|
-
const reason = failure?.error ?? entry.result.reason;
|
|
71495
|
-
return {
|
|
71496
|
-
reason,
|
|
71497
|
-
sessionId: entry.session.id ?? "unknown",
|
|
71498
|
-
message: reason instanceof Error ? reason.message : String(reason)
|
|
71499
|
-
};
|
|
71491
|
+
if (this.closing) throw new Error("Browser context is closing");
|
|
71492
|
+
const rules = this.domainPolicyRules;
|
|
71493
|
+
if (!rules) throw new Error("Domain policy DNR enforcement is unavailable");
|
|
71494
|
+
const update = this.domainPolicyTail.then(async () => {
|
|
71495
|
+
if (this.closing) throw new Error("Browser context is closing");
|
|
71496
|
+
await rules.replace(nextPolicy);
|
|
71497
|
+
this.domainPolicy = nextPolicy;
|
|
71500
71498
|
});
|
|
71501
|
-
|
|
71502
|
-
|
|
71503
|
-
category: "ctx",
|
|
71504
|
-
failures: failures.map(({ sessionId, message }) => ({
|
|
71505
|
-
sessionId,
|
|
71506
|
-
message
|
|
71507
|
-
}))
|
|
71508
|
-
});
|
|
71509
|
-
throw failures[0].reason;
|
|
71510
|
-
}
|
|
71511
|
-
}
|
|
71512
|
-
installDomainPolicyHandler(session) {
|
|
71513
|
-
const sessionId = session.id;
|
|
71514
|
-
if (!sessionId) return;
|
|
71515
|
-
if (this._domainPolicySessionListeners.has(sessionId)) return;
|
|
71516
|
-
const handler = (evt) => {
|
|
71517
|
-
this.handleDomainPolicyRequestPaused(session, evt);
|
|
71518
|
-
};
|
|
71519
|
-
this._domainPolicySessionListeners.set(sessionId, handler);
|
|
71520
|
-
session.on("Fetch.requestPaused", handler);
|
|
71521
|
-
}
|
|
71522
|
-
uninstallDomainPolicyHandler(session) {
|
|
71523
|
-
const sessionId = session.id;
|
|
71524
|
-
if (!sessionId) return;
|
|
71525
|
-
const handler = this._domainPolicySessionListeners.get(sessionId);
|
|
71526
|
-
if (!handler) return;
|
|
71527
|
-
session.off("Fetch.requestPaused", handler);
|
|
71528
|
-
this._domainPolicySessionListeners.delete(sessionId);
|
|
71529
|
-
}
|
|
71530
|
-
async handleDomainPolicyRequestPaused(session, evt) {
|
|
71531
|
-
const decision = getDomainPolicyDecision(evt.request.url, this.domainPolicy);
|
|
71532
|
-
if (decision.action === "continue") {
|
|
71533
|
-
await session.send("Fetch.continueRequest", { requestId: evt.requestId }).catch(() => {});
|
|
71534
|
-
return;
|
|
71535
|
-
}
|
|
71536
|
-
let hostname = "";
|
|
71537
|
-
try {
|
|
71538
|
-
hostname = new URL(evt.request.url).hostname.toLowerCase();
|
|
71539
|
-
} catch {}
|
|
71540
|
-
this.logger.debug("Blocked request by domain policy", {
|
|
71541
|
-
category: "network",
|
|
71542
|
-
hostname,
|
|
71543
|
-
ruleType: decision.reason
|
|
71544
|
-
});
|
|
71545
|
-
await session.send("Fetch.failRequest", {
|
|
71546
|
-
requestId: evt.requestId,
|
|
71547
|
-
errorReason: "BlockedByClient"
|
|
71548
|
-
}).catch(() => {});
|
|
71499
|
+
this.domainPolicyTail = update.catch(() => void 0);
|
|
71500
|
+
await update;
|
|
71549
71501
|
}
|
|
71550
71502
|
get clipboard() {
|
|
71551
71503
|
return this._clipboard ??= new ContextClipboard({
|
|
@@ -71629,23 +71581,42 @@ var BrowserContext = class BrowserContext {
|
|
|
71629
71581
|
/**
|
|
71630
71582
|
* Close CDP and clear all mappings. Best-effort cleanup.
|
|
71631
71583
|
*/
|
|
71632
|
-
|
|
71633
|
-
|
|
71634
|
-
this.
|
|
71635
|
-
|
|
71636
|
-
|
|
71637
|
-
|
|
71638
|
-
|
|
71639
|
-
|
|
71640
|
-
|
|
71641
|
-
|
|
71642
|
-
|
|
71643
|
-
|
|
71644
|
-
|
|
71645
|
-
|
|
71646
|
-
|
|
71647
|
-
|
|
71648
|
-
|
|
71584
|
+
close() {
|
|
71585
|
+
if (this.closePromise) return this.closePromise;
|
|
71586
|
+
this.closing = true;
|
|
71587
|
+
const closing = Promise.resolve().then(async () => {
|
|
71588
|
+
try {
|
|
71589
|
+
await this.conn.close();
|
|
71590
|
+
} finally {
|
|
71591
|
+
await this.domainPolicyTail;
|
|
71592
|
+
try {
|
|
71593
|
+
await this.domainPolicyRules?.close();
|
|
71594
|
+
this.domainPolicy = null;
|
|
71595
|
+
} finally {
|
|
71596
|
+
this.pagesByTarget.clear();
|
|
71597
|
+
this.mainFrameToTarget.clear();
|
|
71598
|
+
this.sessionOwnerPage.clear();
|
|
71599
|
+
this.frameOwnerPage.clear();
|
|
71600
|
+
this.pendingOopifByMainFrame.clear();
|
|
71601
|
+
this.pendingOopifParentByMainFrame.clear();
|
|
71602
|
+
this.adoptedOopifSessionByFrame.clear();
|
|
71603
|
+
this.createdAtByTarget.clear();
|
|
71604
|
+
this.typeByTarget.clear();
|
|
71605
|
+
this.pendingCreatedTargetUrl.clear();
|
|
71606
|
+
this.pageCreationFailures.clear();
|
|
71607
|
+
this.pendingInitialTopLevelTargets.clear();
|
|
71608
|
+
this.pendingNewPageTargets.clear();
|
|
71609
|
+
this.domainPolicyClosingTargets.clear();
|
|
71610
|
+
this.domainPolicyClosePromises.clear();
|
|
71611
|
+
this._sessionInit.clear();
|
|
71612
|
+
}
|
|
71613
|
+
}
|
|
71614
|
+
});
|
|
71615
|
+
this.closePromise = closing.catch((error) => {
|
|
71616
|
+
this.closePromise = void 0;
|
|
71617
|
+
throw error;
|
|
71618
|
+
});
|
|
71619
|
+
return this.closePromise;
|
|
71649
71620
|
}
|
|
71650
71621
|
/**
|
|
71651
71622
|
* Bootstrap target lifecycle:
|
|
@@ -71724,20 +71695,6 @@ var BrowserContext = class BrowserContext {
|
|
|
71724
71695
|
response: session.send(method, params).then(() => true).catch(() => false)
|
|
71725
71696
|
};
|
|
71726
71697
|
};
|
|
71727
|
-
const queueFetchEnablePreResume = (params) => {
|
|
71728
|
-
let error;
|
|
71729
|
-
return {
|
|
71730
|
-
dispatched: this.conn.waitForSessionDispatch(sessionId, "Fetch.enable").then(() => true).catch((err) => {
|
|
71731
|
-
error = err;
|
|
71732
|
-
return false;
|
|
71733
|
-
}),
|
|
71734
|
-
response: session.send("Fetch.enable", params).then(() => true).catch((err) => {
|
|
71735
|
-
error = err;
|
|
71736
|
-
return false;
|
|
71737
|
-
}),
|
|
71738
|
-
getError: () => error
|
|
71739
|
-
};
|
|
71740
|
-
};
|
|
71741
71698
|
const initScriptOps = [];
|
|
71742
71699
|
const corePreResumeOps = [
|
|
71743
71700
|
queuePreResume("Page.enable"),
|
|
@@ -71754,11 +71711,6 @@ var BrowserContext = class BrowserContext {
|
|
|
71754
71711
|
headerPreResumeOps.push(queuePreResume("Network.enable"));
|
|
71755
71712
|
headerPreResumeOps.push(queuePreResume("Network.setExtraHTTPHeaders", { headers }));
|
|
71756
71713
|
}
|
|
71757
|
-
const fetchPreResumeOps = [];
|
|
71758
|
-
if (this.domainPolicy) {
|
|
71759
|
-
this.installDomainPolicyHandler(session);
|
|
71760
|
-
fetchPreResumeOps.push(queueFetchEnablePreResume({ patterns: this.domainPolicy.fetchPatterns }));
|
|
71761
|
-
}
|
|
71762
71714
|
if (this.initScripts.length) for (const source of this.initScripts) initScriptOps.push(queuePreResume("Page.addScriptToEvaluateOnNewDocument", {
|
|
71763
71715
|
source,
|
|
71764
71716
|
runImmediately: true
|
|
@@ -71766,15 +71718,13 @@ var BrowserContext = class BrowserContext {
|
|
|
71766
71718
|
const preResumeDispatched = (await Promise.all([
|
|
71767
71719
|
...corePreResumeOps.map((op) => op.dispatched),
|
|
71768
71720
|
...headerPreResumeOps.map((op) => op.dispatched),
|
|
71769
|
-
...fetchPreResumeOps.map((op) => op.dispatched),
|
|
71770
71721
|
...initScriptOps.map((op) => op.dispatched)
|
|
71771
71722
|
])).every(Boolean);
|
|
71772
71723
|
const resumeOp = queuePreResume("Runtime.runIfWaitingForDebugger");
|
|
71773
71724
|
const [resumedDispatched, resumedOk] = await Promise.all([resumeOp.dispatched, resumeOp.response]);
|
|
71774
|
-
const [coreResults, headerResults,
|
|
71725
|
+
const [coreResults, headerResults, initScriptResults] = await Promise.all([
|
|
71775
71726
|
Promise.all(corePreResumeOps.map((op) => op.response)),
|
|
71776
71727
|
Promise.all(headerPreResumeOps.map((op) => op.response)),
|
|
71777
|
-
Promise.all(fetchPreResumeOps.map((op) => op.response)),
|
|
71778
71728
|
Promise.all(initScriptOps.map((op) => op.response))
|
|
71779
71729
|
]);
|
|
71780
71730
|
if (!preResumeDispatched || !resumedDispatched || !resumedOk) {
|
|
@@ -71792,23 +71742,6 @@ var BrowserContext = class BrowserContext {
|
|
|
71792
71742
|
return;
|
|
71793
71743
|
}
|
|
71794
71744
|
resumed = true;
|
|
71795
|
-
if (fetchPreResumeOps.length > 0 && !fetchResults.every(Boolean)) {
|
|
71796
|
-
this.uninstallDomainPolicyHandler(session);
|
|
71797
|
-
const fetchError = fetchPreResumeOps.map((op) => op.getError()).find((error) => error !== void 0);
|
|
71798
|
-
const fetchErrorMessage = fetchError ? fetchError instanceof Error ? fetchError.message : String(fetchError) : "Fetch.enable failed during target attach";
|
|
71799
|
-
const policyFailureMessage = "Fetch.enable failed during target attach; closing target because Stagehand cannot guarantee domain policy enforcement";
|
|
71800
|
-
this.recordPageCreationFailure(info.targetId, fetchError instanceof Error ? fetchError : /* @__PURE__ */ new Error(`${policyFailureMessage}: ${fetchErrorMessage}`), policyFailureMessage);
|
|
71801
|
-
this.logger.error("Closing target because domain policy could not be guaranteed", {
|
|
71802
|
-
category: "ctx",
|
|
71803
|
-
targetId: String(info.targetId),
|
|
71804
|
-
targetType: String(info.type),
|
|
71805
|
-
targetUrl: String(info.url ?? ""),
|
|
71806
|
-
sessionId,
|
|
71807
|
-
cdpError: fetchErrorMessage
|
|
71808
|
-
});
|
|
71809
|
-
await this.conn.send("Target.closeTarget", { targetId: info.targetId }).catch(() => {});
|
|
71810
|
-
return;
|
|
71811
|
-
}
|
|
71812
71745
|
const scriptsInstalled = coreResults.every(Boolean) && initScriptResults.every(Boolean);
|
|
71813
71746
|
try {
|
|
71814
71747
|
session.send("Page.setLifecycleEventsEnabled", { enabled: true }).catch(() => {});
|
|
@@ -71935,7 +71868,7 @@ var BrowserContext = class BrowserContext {
|
|
|
71935
71868
|
if (existingClose) return source === "attached" ? await existingClose : true;
|
|
71936
71869
|
const decision = getDomainPolicyDecision(info.url ?? "", this.domainPolicy);
|
|
71937
71870
|
if (decision.action === "continue") return false;
|
|
71938
|
-
this.logger.debug("
|
|
71871
|
+
this.logger.debug("Closing popup targeting a disallowed domain", {
|
|
71939
71872
|
category: "network",
|
|
71940
71873
|
targetId: String(info.targetId),
|
|
71941
71874
|
targetUrl: String(info.url ?? ""),
|
|
@@ -71986,9 +71919,6 @@ var BrowserContext = class BrowserContext {
|
|
|
71986
71919
|
for (const [fid, sid] of Array.from(this.pendingOopifByMainFrame.entries())) if (sid === sessionId) this.removePendingOopif(fid);
|
|
71987
71920
|
for (const [fid, sid] of Array.from(this.adoptedOopifSessionByFrame.entries())) if (sid === sessionId) this.adoptedOopifSessionByFrame.delete(fid);
|
|
71988
71921
|
this._targetSessionListeners.delete(sessionId);
|
|
71989
|
-
const session = this.conn.getSession(sessionId);
|
|
71990
|
-
if (session) this.uninstallDomainPolicyHandler(session);
|
|
71991
|
-
else this._domainPolicySessionListeners.delete(sessionId);
|
|
71992
71922
|
this._sessionInit.delete(sessionId);
|
|
71993
71923
|
}
|
|
71994
71924
|
/**
|
|
@@ -72122,6 +72052,95 @@ var BrowserContext = class BrowserContext {
|
|
|
72122
72052
|
}
|
|
72123
72053
|
};
|
|
72124
72054
|
//#endregion
|
|
72055
|
+
//#region understudy/domainPolicyDnr.ts
|
|
72056
|
+
var DOMAIN_POLICY_RULE_ID_START = 1e6;
|
|
72057
|
+
var DOMAIN_POLICY_RULE_ID_END = 101e4;
|
|
72058
|
+
function isDomainPolicyRule(rule) {
|
|
72059
|
+
return rule.id >= 1e6 && rule.id < DOMAIN_POLICY_RULE_ID_END;
|
|
72060
|
+
}
|
|
72061
|
+
/** One manager per extension, with one active browser session at a time. */
|
|
72062
|
+
var DomainPolicyDnrManager = class {
|
|
72063
|
+
constructor(api, extensionId) {
|
|
72064
|
+
this.api = api;
|
|
72065
|
+
this.extensionId = extensionId;
|
|
72066
|
+
this.tail = Promise.resolve();
|
|
72067
|
+
}
|
|
72068
|
+
openSession() {
|
|
72069
|
+
return this.enqueue(async () => {
|
|
72070
|
+
await this.replaceRules([]);
|
|
72071
|
+
const owner = Symbol("domain-policy");
|
|
72072
|
+
this.owner = owner;
|
|
72073
|
+
return {
|
|
72074
|
+
replace: (policy) => {
|
|
72075
|
+
const rules = this.compile(policy);
|
|
72076
|
+
return this.enqueue(async () => {
|
|
72077
|
+
if (this.owner !== owner) throw new Error("Domain policy session is no longer active");
|
|
72078
|
+
await this.replaceRules(rules);
|
|
72079
|
+
});
|
|
72080
|
+
},
|
|
72081
|
+
close: () => this.enqueue(async () => {
|
|
72082
|
+
if (this.owner !== owner) return;
|
|
72083
|
+
await this.replaceRules([]);
|
|
72084
|
+
this.owner = void 0;
|
|
72085
|
+
})
|
|
72086
|
+
};
|
|
72087
|
+
});
|
|
72088
|
+
}
|
|
72089
|
+
compile(policy) {
|
|
72090
|
+
const rules = toDomainPolicyDnrRules(policy).map((rule) => ({
|
|
72091
|
+
...rule,
|
|
72092
|
+
id: DOMAIN_POLICY_RULE_ID_START + rule.id
|
|
72093
|
+
}));
|
|
72094
|
+
if (!rules.length) return rules;
|
|
72095
|
+
rules.unshift({
|
|
72096
|
+
id: DOMAIN_POLICY_RULE_ID_START,
|
|
72097
|
+
priority: 4,
|
|
72098
|
+
action: { type: "allow" },
|
|
72099
|
+
condition: {
|
|
72100
|
+
regexFilter: "^https?://",
|
|
72101
|
+
isUrlFilterCaseSensitive: false,
|
|
72102
|
+
excludedResourceTypes: [],
|
|
72103
|
+
initiatorDomains: [this.extensionId],
|
|
72104
|
+
tabIds: [-1]
|
|
72105
|
+
}
|
|
72106
|
+
});
|
|
72107
|
+
return rules;
|
|
72108
|
+
}
|
|
72109
|
+
async replaceRules(rules) {
|
|
72110
|
+
const existing = await this.api.getSessionRules();
|
|
72111
|
+
const owned = existing.filter(isDomainPolicyRule);
|
|
72112
|
+
const unrelated = existing.filter((rule) => !isDomainPolicyRule(rule));
|
|
72113
|
+
if (rules.length) {
|
|
72114
|
+
if (rules.some((rule) => !isDomainPolicyRule(rule)) || unrelated.length + rules.length > this.api.MAX_NUMBER_OF_SESSION_RULES) throw new Error("Domain policy exceeds Chrome's session rule limit");
|
|
72115
|
+
if ([...unrelated, ...rules].filter((rule) => rule.condition.regexFilter !== void 0).length > this.api.MAX_NUMBER_OF_REGEX_RULES) throw new Error("Domain policy exceeds Chrome's regex rule limit");
|
|
72116
|
+
const regexes = /* @__PURE__ */ new Map();
|
|
72117
|
+
for (const { condition } of rules) {
|
|
72118
|
+
if (condition.regexFilter === void 0) continue;
|
|
72119
|
+
const options = {
|
|
72120
|
+
regex: condition.regexFilter,
|
|
72121
|
+
isCaseSensitive: condition.isUrlFilterCaseSensitive ?? false,
|
|
72122
|
+
requireCapturing: false
|
|
72123
|
+
};
|
|
72124
|
+
regexes.set(JSON.stringify(options), options);
|
|
72125
|
+
}
|
|
72126
|
+
await Promise.all(Array.from(regexes.values(), async (options) => {
|
|
72127
|
+
const result = await this.api.isRegexSupported(options);
|
|
72128
|
+
if (!result.isSupported) throw new Error("Chrome does not support a domain policy regex: " + (result.reason ?? "unknown reason"));
|
|
72129
|
+
}));
|
|
72130
|
+
}
|
|
72131
|
+
if (!owned.length && !rules.length) return;
|
|
72132
|
+
await this.api.updateSessionRules({
|
|
72133
|
+
removeRuleIds: owned.map((rule) => rule.id),
|
|
72134
|
+
addRules: rules
|
|
72135
|
+
});
|
|
72136
|
+
}
|
|
72137
|
+
enqueue(work) {
|
|
72138
|
+
const result = this.tail.then(work, work);
|
|
72139
|
+
this.tail = result.catch(() => void 0);
|
|
72140
|
+
return result;
|
|
72141
|
+
}
|
|
72142
|
+
};
|
|
72143
|
+
//#endregion
|
|
72125
72144
|
//#region version.ts
|
|
72126
72145
|
var STAGEHAND_RUNTIME_VERSION = package_default.version;
|
|
72127
72146
|
//#endregion
|
|
@@ -72129,18 +72148,31 @@ var STAGEHAND_RUNTIME_VERSION = package_default.version;
|
|
|
72129
72148
|
function startStagehandServiceWorker(scope = globalThis, runtime) {
|
|
72130
72149
|
const chromeRuntimeClient = new ChromeRuntimeClient(scope, STAGEHAND_SEND_TO_HOST_BINDING);
|
|
72131
72150
|
let rpcClient;
|
|
72151
|
+
let domainPolicyManager;
|
|
72132
72152
|
const activeRuntime = runtime ?? createStagehandRuntime({
|
|
72133
72153
|
browserSessionFactory: async (cdpUrl, logger, bootstrapLogger) => {
|
|
72134
|
-
|
|
72135
|
-
|
|
72136
|
-
|
|
72137
|
-
|
|
72138
|
-
|
|
72139
|
-
|
|
72140
|
-
|
|
72141
|
-
|
|
72142
|
-
|
|
72143
|
-
|
|
72154
|
+
domainPolicyManager ??= new DomainPolicyDnrManager(chrome.declarativeNetRequest, chrome.runtime.id);
|
|
72155
|
+
const domainPolicyRules = await domainPolicyManager.openSession();
|
|
72156
|
+
try {
|
|
72157
|
+
const locatorRuntimeResponse = await fetch(chrome.runtime.getURL("content-script.js"));
|
|
72158
|
+
if (!locatorRuntimeResponse.ok) throw new Error(`Failed to load Stagehand locator runtime: ${locatorRuntimeResponse.status}`);
|
|
72159
|
+
return await BrowserContext.create(cdpUrl, {
|
|
72160
|
+
websocketFactory: browserWebSocketFactory,
|
|
72161
|
+
logger,
|
|
72162
|
+
blankPageUrl: chrome.runtime.getURL("blank.html"),
|
|
72163
|
+
fallbackLocatorScriptSource: await locatorRuntimeResponse.text(),
|
|
72164
|
+
chromeTabs: new ChromeTabTargetAdapter(chrome),
|
|
72165
|
+
bootstrapLogger,
|
|
72166
|
+
domainPolicyRules
|
|
72167
|
+
});
|
|
72168
|
+
} catch (error) {
|
|
72169
|
+
try {
|
|
72170
|
+
await domainPolicyRules.close();
|
|
72171
|
+
} catch (cleanupError) {
|
|
72172
|
+
throw new AggregateError([error, cleanupError], "Browser session initialization and domain policy cleanup failed");
|
|
72173
|
+
}
|
|
72174
|
+
throw error;
|
|
72175
|
+
}
|
|
72144
72176
|
},
|
|
72145
72177
|
emitLog: (log) => {
|
|
72146
72178
|
rpcClient?.notify(StagehandNotifications.log, log).catch((error) => {
|
|
@@ -72175,7 +72207,7 @@ function startStagehandServiceWorker(scope = globalThis, runtime) {
|
|
|
72175
72207
|
return session.conn;
|
|
72176
72208
|
},
|
|
72177
72209
|
rejectClientCallbacks: () => rpcClient?.releaseClient(),
|
|
72178
|
-
closeConnection: () => activeRuntime.
|
|
72210
|
+
closeConnection: () => activeRuntime.disconnectBrowser(),
|
|
72179
72211
|
disposeClient: () => activeRuntime.disposeStagehandInstance(),
|
|
72180
72212
|
onError: (error) => {
|
|
72181
72213
|
console.error("Stagehand client lifecycle cleanup failed", error);
|
{stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_generated/protocol_version.py
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
"""Generated from packages/protocol/package.json. Do not edit."""
|
|
2
2
|
|
|
3
3
|
PROTOCOL_SEMVER_PATTERN = '^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\\+([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?$'
|
|
4
|
-
STAGEHAND_PROTOCOL_VERSION = '3.1.1-alpha-
|
|
4
|
+
STAGEHAND_PROTOCOL_VERSION = '3.1.1-alpha-c82e6170c29ab6fb17c4a10e44812bd29507e7d4'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_extension/content-script.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_generated/__init__.py
RENAMED
|
File without changes
|
{stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/_generated/input_types.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/browserbase_connection.py
RENAMED
|
File without changes
|
|
File without changes
|
{stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/browserbase_services.py
RENAMED
|
File without changes
|
{stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/browserbase_session.py
RENAMED
|
File without changes
|
{stagehand-4.4.0a0.dev1673 → stagehand-4.4.0a0.dev1676}/src/stagehand/browserbase_transport.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|