playwright-core 1.58.0-alpha-2025-12-18 → 1.58.0-alpha-2025-12-19

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/browsers.json CHANGED
@@ -31,14 +31,14 @@
31
31
  },
32
32
  {
33
33
  "name": "firefox",
34
- "revision": "1504",
34
+ "revision": "1507",
35
35
  "installByDefault": true,
36
36
  "browserVersion": "145.0.2",
37
37
  "title": "Firefox"
38
38
  },
39
39
  {
40
40
  "name": "firefox-beta",
41
- "revision": "1499",
41
+ "revision": "1502",
42
42
  "installByDefault": false,
43
43
  "browserVersion": "146.0b8",
44
44
  "title": "Firefox Beta"
@@ -169,7 +169,8 @@ class BrowserType extends import_channelOwner.ChannelOwner {
169
169
  endpointURL,
170
170
  headers,
171
171
  slowMo: params.slowMo,
172
- timeout: new import_timeoutSettings.TimeoutSettings(this._platform).timeout(params)
172
+ timeout: new import_timeoutSettings.TimeoutSettings(this._platform).timeout(params),
173
+ isLocal: params.isLocal
173
174
  });
174
175
  const browser = import_browser.Browser.from(result.browser);
175
176
  browser._connectToBrowserType(this, {}, params.logger);
@@ -609,10 +609,10 @@ import_validatorPrimitives.scheme.BrowserTypeLaunchPersistentContextParams = (0,
609
609
  selectorEngines: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("SelectorEngine"))),
610
610
  testIdAttributeName: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
611
611
  agent: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tObject)({
612
- provider: import_validatorPrimitives.tString,
613
- model: import_validatorPrimitives.tString,
612
+ provider: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
613
+ model: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
614
614
  cacheFile: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
615
- cacheMode: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tEnum)(["ignore", "force", "update", "auto"])),
615
+ cacheOutFile: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
616
616
  secrets: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("NameValue"))),
617
617
  maxTurns: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tInt),
618
618
  maxTokens: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tInt)
@@ -628,7 +628,8 @@ import_validatorPrimitives.scheme.BrowserTypeConnectOverCDPParams = (0, import_v
628
628
  endpointURL: import_validatorPrimitives.tString,
629
629
  headers: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("NameValue"))),
630
630
  slowMo: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tFloat),
631
- timeout: import_validatorPrimitives.tFloat
631
+ timeout: import_validatorPrimitives.tFloat,
632
+ isLocal: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tBoolean)
632
633
  });
633
634
  import_validatorPrimitives.scheme.BrowserTypeConnectOverCDPResult = (0, import_validatorPrimitives.tObject)({
634
635
  browser: (0, import_validatorPrimitives.tChannel)(["Browser"]),
@@ -710,10 +711,10 @@ import_validatorPrimitives.scheme.BrowserNewContextParams = (0, import_validator
710
711
  selectorEngines: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("SelectorEngine"))),
711
712
  testIdAttributeName: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
712
713
  agent: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tObject)({
713
- provider: import_validatorPrimitives.tString,
714
- model: import_validatorPrimitives.tString,
714
+ provider: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
715
+ model: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
715
716
  cacheFile: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
716
- cacheMode: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tEnum)(["ignore", "force", "update", "auto"])),
717
+ cacheOutFile: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
717
718
  secrets: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("NameValue"))),
718
719
  maxTurns: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tInt),
719
720
  maxTokens: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tInt)
@@ -790,10 +791,10 @@ import_validatorPrimitives.scheme.BrowserNewContextForReuseParams = (0, import_v
790
791
  selectorEngines: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("SelectorEngine"))),
791
792
  testIdAttributeName: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
792
793
  agent: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tObject)({
793
- provider: import_validatorPrimitives.tString,
794
- model: import_validatorPrimitives.tString,
794
+ provider: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
795
+ model: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
795
796
  cacheFile: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
796
- cacheMode: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tEnum)(["ignore", "force", "update", "auto"])),
797
+ cacheOutFile: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
797
798
  secrets: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("NameValue"))),
798
799
  maxTurns: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tInt),
799
800
  maxTokens: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tInt)
@@ -915,10 +916,10 @@ import_validatorPrimitives.scheme.BrowserContextInitializer = (0, import_validat
915
916
  selectorEngines: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("SelectorEngine"))),
916
917
  testIdAttributeName: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
917
918
  agent: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tObject)({
918
- provider: import_validatorPrimitives.tString,
919
- model: import_validatorPrimitives.tString,
919
+ provider: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
920
+ model: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
920
921
  cacheFile: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
921
- cacheMode: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tEnum)(["ignore", "force", "update", "auto"])),
922
+ cacheOutFile: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
922
923
  secrets: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("NameValue"))),
923
924
  maxTurns: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tInt),
924
925
  maxTokens: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tInt)
@@ -2843,10 +2844,10 @@ import_validatorPrimitives.scheme.AndroidDeviceLaunchBrowserParams = (0, import_
2843
2844
  selectorEngines: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("SelectorEngine"))),
2844
2845
  testIdAttributeName: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
2845
2846
  agent: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tObject)({
2846
- provider: import_validatorPrimitives.tString,
2847
- model: import_validatorPrimitives.tString,
2847
+ provider: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
2848
+ model: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
2848
2849
  cacheFile: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
2849
- cacheMode: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tEnum)(["ignore", "force", "update", "auto"])),
2850
+ cacheOutFile: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tString),
2850
2851
  secrets: (0, import_validatorPrimitives.tOptional)((0, import_validatorPrimitives.tArray)((0, import_validatorPrimitives.tType)("NameValue"))),
2851
2852
  maxTurns: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tInt),
2852
2853
  maxTokens: (0, import_validatorPrimitives.tOptional)(import_validatorPrimitives.tInt)
@@ -61,8 +61,8 @@ ${options.query}`;
61
61
  async function perform(progress, context, userTask, resultSchema, options = {}) {
62
62
  const { page } = context;
63
63
  const browserContext = page.browserContext;
64
- if (!browserContext._options.agent)
65
- throw new Error(`page.perform() and page.extract() require the agent to be set on the browser context`);
64
+ if (!browserContext._options.agent?.provider || !browserContext._options.agent?.model)
65
+ throw new Error(`This action requires the agent provider and model to be set on the browser context`);
66
66
  const { full } = await page.snapshotForAI(progress);
67
67
  const { tools, callTool } = (0, import_backend.toolsForLoop)(context);
68
68
  page.emit(import_page.Page.Events.AgentTurn, { role: "user", message: userTask });
@@ -121,44 +121,49 @@ ${full}
121
121
  }
122
122
  };
123
123
  }
124
- const allCaches = /* @__PURE__ */ new Map();
125
124
  async function cachedPerform(progress, context, options) {
126
- if (!context.options?.cacheFile || context.options.cacheMode === "ignore" || context.options.cacheMode === "update")
125
+ if (!context.options?.cacheFile)
127
126
  return false;
128
- const cache = await cachedActions(context.options.cacheFile);
127
+ const cache = await cachedActions(context, context.options?.cacheFile);
129
128
  const cacheKey = (options.key ?? options.task).trim();
130
- const entry = cache[cacheKey];
131
- if (!entry) {
132
- if (context.options.cacheMode === "force")
133
- throw new Error(`No cached actions for key "${cacheKey}", but cache mode is set to "force"`);
129
+ const entry = cache.actions[cacheKey];
130
+ if (!entry)
134
131
  return false;
135
- }
136
132
  for (const action of entry.actions)
137
133
  await (0, import_actionRunner.runAction)(progress, "run", context.page, action, context.options.secrets ?? []);
138
134
  return true;
139
135
  }
140
136
  async function updateCache(context, options) {
141
137
  const cacheFile = context.options?.cacheFile;
142
- if (!cacheFile)
143
- return;
144
- const cache = await cachedActions(cacheFile);
138
+ const cacheOutFile = context.options?.cacheOutFile;
139
+ const cache = cacheFile ? await cachedActions(context, cacheFile) : { actions: {}, newActions: {} };
145
140
  const cacheKey = (options.key ?? options.task).trim();
146
- cache[cacheKey] = {
141
+ const newEntry = {
147
142
  timestamp: Date.now(),
148
143
  actions: context.actions
149
144
  };
150
- const entries = Object.entries(cache);
151
- entries.sort((e1, e2) => e1[0].localeCompare(e2[0]));
152
- await import_fs.default.promises.writeFile(cacheFile, JSON.stringify(Object.fromEntries(entries), void 0, 2));
145
+ cache.actions[cacheKey] = newEntry;
146
+ cache.newActions[cacheKey] = newEntry;
147
+ if (cacheOutFile) {
148
+ const entries = Object.entries(cache.newActions);
149
+ entries.sort((e1, e2) => e1[0].localeCompare(e2[0]));
150
+ await import_fs.default.promises.writeFile(cacheOutFile, JSON.stringify(Object.fromEntries(entries), void 0, 2));
151
+ } else if (cacheFile) {
152
+ const entries = Object.entries(cache.actions);
153
+ entries.sort((e1, e2) => e1[0].localeCompare(e2[0]));
154
+ await import_fs.default.promises.writeFile(cacheFile, JSON.stringify(Object.fromEntries(entries), void 0, 2));
155
+ }
153
156
  }
154
- async function cachedActions(cacheFile) {
155
- let cache = allCaches.get(cacheFile);
157
+ async function cachedActions(context, cacheFile) {
158
+ let cache = context[agentCacheSymbol];
156
159
  if (!cache) {
157
- cache = await import_fs.default.promises.readFile(cacheFile, "utf-8").then((text) => JSON.parse(text)).catch(() => ({}));
158
- allCaches.set(cacheFile, cache);
160
+ const actions = await import_fs.default.promises.readFile(cacheFile, "utf-8").then((text) => JSON.parse(text)).catch(() => ({}));
161
+ cache = { actions, newActions: {} };
162
+ context[agentCacheSymbol] = cache;
159
163
  }
160
164
  return cache;
161
165
  }
166
+ const agentCacheSymbol = Symbol("agentCache");
162
167
  // Annotate the CommonJS export names for ESM import in node:
163
168
  0 && (module.exports = {
164
169
  pageExtract,
@@ -114,7 +114,8 @@ class Chromium extends import_browserType.BrowserType {
114
114
  };
115
115
  (0, import_browserContext.validateBrowserContextOptions)(persistent, browserOptions);
116
116
  const browser = await progress.race(import_crBrowser.CRBrowser.connect(this.attribution.playwright, chromeTransport, browserOptions));
117
- browser._isCollocatedWithServer = false;
117
+ if (!options.isLocal)
118
+ browser._isCollocatedWithServer = false;
118
119
  browser.on(import_browser.Browser.Events.Disconnected, doCleanup);
119
120
  return browser;
120
121
  } catch (error) {
@@ -709,8 +709,7 @@ class FrameSession {
709
709
  }
710
710
  _onScreencastFrame(payload) {
711
711
  this._page.screencast.throttleFrameAck(() => {
712
- this._client.send("Page.screencastFrameAck", { sessionId: payload.sessionId }).catch(() => {
713
- });
712
+ this._client._sendMayFail("Page.screencastFrameAck", { sessionId: payload.sessionId });
714
713
  });
715
714
  const buffer = Buffer.from(payload.data, "base64");
716
715
  this._page.emit(import_page.Page.Events.ScreencastFrame, {
@@ -54,7 +54,6 @@ class FFBrowser extends import_browser.Browser {
54
54
  this.session.on("Browser.detachedFromTarget", this._onDetachedFromTarget.bind(this));
55
55
  this.session.on("Browser.downloadCreated", this._onDownloadCreated.bind(this));
56
56
  this.session.on("Browser.downloadFinished", this._onDownloadFinished.bind(this));
57
- this.session.on("Browser.videoRecordingFinished", this._onVideoRecordingFinished.bind(this));
58
57
  }
59
58
  static async connect(parent, transport, options) {
60
59
  const connection = new import_ffConnection.FFConnection(transport, options.protocolLogger, options.browserLogsCollector);
@@ -141,9 +140,6 @@ class FFBrowser extends import_browser.Browser {
141
140
  const error = payload.canceled ? "canceled" : payload.error;
142
141
  this._downloadFinished(payload.uuid, error);
143
142
  }
144
- _onVideoRecordingFinished(payload) {
145
- this._takeVideo(payload.screencastId)?.reportFinished();
146
- }
147
143
  _onDisconnect() {
148
144
  for (const video of this._idToVideo.values())
149
145
  video.artifact.reportFinished(new import_errors.TargetClosedError(this.closeReason()));
@@ -199,15 +195,13 @@ class FFBrowserContext extends import_browserContext.BrowserContext {
199
195
  promises.push(this.doUpdateOffline());
200
196
  promises.push(this.doUpdateDefaultEmulatedMedia());
201
197
  if (this._options.recordVideo) {
202
- promises.push(this._ensureVideosPath().then(() => {
203
- return this._browser.session.send("Browser.setVideoRecordingOptions", {
204
- // validateBrowserContextOptions ensures correct video size.
205
- options: {
206
- ...this._options.recordVideo.size,
207
- dir: this._options.recordVideo.dir
208
- },
209
- browserContextId: this._browserContextId
210
- });
198
+ promises.push(this._browser.session.send("Browser.setScreencastOptions", {
199
+ // validateBrowserContextOptions ensures correct video size.
200
+ options: {
201
+ ...this._options.recordVideo.size,
202
+ quality: 90
203
+ },
204
+ browserContextId: this._browserContextId
211
205
  }));
212
206
  }
213
207
  const proxy = this._options.proxyOverride || this._options.proxy;
@@ -379,12 +373,8 @@ class FFBrowserContext extends import_browserContext.BrowserContext {
379
373
  }
380
374
  async doClose(reason) {
381
375
  if (!this._browserContextId) {
382
- if (this._options.recordVideo) {
383
- await this._browser.session.send("Browser.setVideoRecordingOptions", {
384
- options: void 0,
385
- browserContextId: this._browserContextId
386
- });
387
- }
376
+ if (this._options.recordVideo)
377
+ await Promise.all(this._ffPages().map((ffPage) => ffPage._page.screencast.stopVideoRecording()));
388
378
  await this._browser.close({ reason });
389
379
  } else {
390
380
  await this._browser.session.send("Browser.removeBrowserContext", { browserContextId: this._browserContextId });
@@ -41,9 +41,9 @@ var import_ffConnection = require("./ffConnection");
41
41
  var import_ffExecutionContext = require("./ffExecutionContext");
42
42
  var import_ffInput = require("./ffInput");
43
43
  var import_ffNetworkManager = require("./ffNetworkManager");
44
- var import_debugLogger = require("../utils/debugLogger");
45
44
  var import_stackTrace = require("../../utils/isomorphic/stackTrace");
46
45
  var import_errors = require("../errors");
46
+ var import_debugLogger = require("../utils/debugLogger");
47
47
  const UTILITY_WORLD_NAME = "__playwright_utility_world__";
48
48
  class FFPage {
49
49
  constructor(session, browserContext, opener) {
@@ -83,13 +83,16 @@ class FFPage {
83
83
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.workerDestroyed", this._onWorkerDestroyed.bind(this)),
84
84
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.dispatchMessageFromWorker", this._onDispatchMessageFromWorker.bind(this)),
85
85
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.crashed", this._onCrashed.bind(this)),
86
- import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.videoRecordingStarted", this._onVideoRecordingStarted.bind(this)),
87
86
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.webSocketCreated", this._onWebSocketCreated.bind(this)),
88
87
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.webSocketClosed", this._onWebSocketClosed.bind(this)),
89
88
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.webSocketFrameReceived", this._onWebSocketFrameReceived.bind(this)),
90
89
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.webSocketFrameSent", this._onWebSocketFrameSent.bind(this)),
91
90
  import_eventsHelper.eventsHelper.addEventListener(this._session, "Page.screencastFrame", this._onScreencastFrame.bind(this))
92
91
  ];
92
+ const screencast = this._page.screencast;
93
+ const videoOptions = screencast.launchVideoRecorder();
94
+ if (videoOptions)
95
+ screencast.startVideoRecording(videoOptions).catch((e) => import_debugLogger.debugLogger.log("error", e));
93
96
  this._session.once("Page.ready", () => {
94
97
  if (this._reportedAsNew)
95
98
  return;
@@ -272,9 +275,6 @@ class FFPage {
272
275
  this._session.markAsCrashed();
273
276
  this._page._didCrash();
274
277
  }
275
- _onVideoRecordingStarted(event) {
276
- this._browserContext._browser._videoStarted(this._browserContext, event.screencastId, event.file, this._page.waitForInitializedOrError());
277
- }
278
278
  didClose() {
279
279
  this._markAsError(new import_errors.TargetClosedError(this._page.closeReason()));
280
280
  this._session.dispose();
@@ -418,18 +418,14 @@ class FFPage {
418
418
  });
419
419
  }
420
420
  async startScreencast(options) {
421
- const { screencastId } = await this._session.send("Page.startScreencast", options);
422
- this._screencastId = screencastId;
421
+ await this._session.send("Page.startScreencast", options);
423
422
  }
424
423
  async stopScreencast() {
425
- await this._session.send("Page.stopScreencast");
424
+ await this._session.sendMayFail("Page.stopScreencast");
426
425
  }
427
426
  _onScreencastFrame(event) {
428
- if (!this._screencastId)
429
- return;
430
- const screencastId = this._screencastId;
431
427
  this._page.screencast.throttleFrameAck(() => {
432
- this._session.send("Page.screencastFrameAck", { screencastId }).catch((e) => import_debugLogger.debugLogger.log("error", e));
428
+ this._session.sendMayFail("Page.screencastFrameAck");
433
429
  });
434
430
  const buffer = Buffer.from(event.data, "base64");
435
431
  this._page.emit(import_page2.Page.Events.ScreencastFrame, {
@@ -145,68 +145,78 @@ const EXECUTABLE_PATHS = {
145
145
  "win-x64": ["PrintDeps.exe"]
146
146
  }
147
147
  };
148
+ function cftUrl(suffix) {
149
+ return ({ browserVersion }) => {
150
+ return {
151
+ path: `${browserVersion}/${suffix}`,
152
+ mirrors: [
153
+ "https://cdn.playwright.dev/chrome-for-testing-public"
154
+ ]
155
+ };
156
+ };
157
+ }
148
158
  const DOWNLOAD_PATHS = {
149
159
  "chromium": {
150
160
  "<unknown>": void 0,
151
161
  "ubuntu18.04-x64": void 0,
152
- "ubuntu20.04-x64": "builds/chromium/%s/chromium-linux.zip",
153
- "ubuntu22.04-x64": "builds/chromium/%s/chromium-linux.zip",
154
- "ubuntu24.04-x64": "builds/chromium/%s/chromium-linux.zip",
162
+ "ubuntu20.04-x64": cftUrl("linux64/chrome-linux64.zip"),
163
+ "ubuntu22.04-x64": cftUrl("linux64/chrome-linux64.zip"),
164
+ "ubuntu24.04-x64": cftUrl("linux64/chrome-linux64.zip"),
155
165
  "ubuntu18.04-arm64": void 0,
156
166
  "ubuntu20.04-arm64": "builds/chromium/%s/chromium-linux-arm64.zip",
157
167
  "ubuntu22.04-arm64": "builds/chromium/%s/chromium-linux-arm64.zip",
158
168
  "ubuntu24.04-arm64": "builds/chromium/%s/chromium-linux-arm64.zip",
159
- "debian11-x64": "builds/chromium/%s/chromium-linux.zip",
169
+ "debian11-x64": cftUrl("linux64/chrome-linux64.zip"),
160
170
  "debian11-arm64": "builds/chromium/%s/chromium-linux-arm64.zip",
161
- "debian12-x64": "builds/chromium/%s/chromium-linux.zip",
171
+ "debian12-x64": cftUrl("linux64/chrome-linux64.zip"),
162
172
  "debian12-arm64": "builds/chromium/%s/chromium-linux-arm64.zip",
163
- "debian13-x64": "builds/chromium/%s/chromium-linux.zip",
173
+ "debian13-x64": cftUrl("linux64/chrome-linux64.zip"),
164
174
  "debian13-arm64": "builds/chromium/%s/chromium-linux-arm64.zip",
165
- "mac10.13": "builds/chromium/%s/chromium-mac.zip",
166
- "mac10.14": "builds/chromium/%s/chromium-mac.zip",
167
- "mac10.15": "builds/chromium/%s/chromium-mac.zip",
168
- "mac11": "builds/chromium/%s/chromium-mac.zip",
169
- "mac11-arm64": "builds/chromium/%s/chromium-mac-arm64.zip",
170
- "mac12": "builds/chromium/%s/chromium-mac.zip",
171
- "mac12-arm64": "builds/chromium/%s/chromium-mac-arm64.zip",
172
- "mac13": "builds/chromium/%s/chromium-mac.zip",
173
- "mac13-arm64": "builds/chromium/%s/chromium-mac-arm64.zip",
174
- "mac14": "builds/chromium/%s/chromium-mac.zip",
175
- "mac14-arm64": "builds/chromium/%s/chromium-mac-arm64.zip",
176
- "mac15": "builds/chromium/%s/chromium-mac.zip",
177
- "mac15-arm64": "builds/chromium/%s/chromium-mac-arm64.zip",
178
- "win64": "builds/chromium/%s/chromium-win64.zip"
175
+ "mac10.13": cftUrl("mac-x64/chrome-mac-x64.zip"),
176
+ "mac10.14": cftUrl("mac-x64/chrome-mac-x64.zip"),
177
+ "mac10.15": cftUrl("mac-x64/chrome-mac-x64.zip"),
178
+ "mac11": cftUrl("mac-x64/chrome-mac-x64.zip"),
179
+ "mac11-arm64": cftUrl("mac-arm64/chrome-mac-arm64.zip"),
180
+ "mac12": cftUrl("mac-x64/chrome-mac-x64.zip"),
181
+ "mac12-arm64": cftUrl("mac-arm64/chrome-mac-arm64.zip"),
182
+ "mac13": cftUrl("mac-x64/chrome-mac-x64.zip"),
183
+ "mac13-arm64": cftUrl("mac-arm64/chrome-mac-arm64.zip"),
184
+ "mac14": cftUrl("mac-x64/chrome-mac-x64.zip"),
185
+ "mac14-arm64": cftUrl("mac-arm64/chrome-mac-arm64.zip"),
186
+ "mac15": cftUrl("mac-x64/chrome-mac-x64.zip"),
187
+ "mac15-arm64": cftUrl("mac-arm64/chrome-mac-arm64.zip"),
188
+ "win64": cftUrl("win64/chrome-win64.zip")
179
189
  },
180
190
  "chromium-headless-shell": {
181
191
  "<unknown>": void 0,
182
192
  "ubuntu18.04-x64": void 0,
183
- "ubuntu20.04-x64": "builds/chromium/%s/chromium-headless-shell-linux.zip",
184
- "ubuntu22.04-x64": "builds/chromium/%s/chromium-headless-shell-linux.zip",
185
- "ubuntu24.04-x64": "builds/chromium/%s/chromium-headless-shell-linux.zip",
193
+ "ubuntu20.04-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"),
194
+ "ubuntu22.04-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"),
195
+ "ubuntu24.04-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"),
186
196
  "ubuntu18.04-arm64": void 0,
187
197
  "ubuntu20.04-arm64": "builds/chromium/%s/chromium-headless-shell-linux-arm64.zip",
188
198
  "ubuntu22.04-arm64": "builds/chromium/%s/chromium-headless-shell-linux-arm64.zip",
189
199
  "ubuntu24.04-arm64": "builds/chromium/%s/chromium-headless-shell-linux-arm64.zip",
190
- "debian11-x64": "builds/chromium/%s/chromium-headless-shell-linux.zip",
200
+ "debian11-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"),
191
201
  "debian11-arm64": "builds/chromium/%s/chromium-headless-shell-linux-arm64.zip",
192
- "debian12-x64": "builds/chromium/%s/chromium-headless-shell-linux.zip",
202
+ "debian12-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"),
193
203
  "debian12-arm64": "builds/chromium/%s/chromium-headless-shell-linux-arm64.zip",
194
- "debian13-x64": "builds/chromium/%s/chromium-headless-shell-linux.zip",
204
+ "debian13-x64": cftUrl("linux64/chrome-headless-shell-linux64.zip"),
195
205
  "debian13-arm64": "builds/chromium/%s/chromium-headless-shell-linux-arm64.zip",
196
206
  "mac10.13": void 0,
197
207
  "mac10.14": void 0,
198
208
  "mac10.15": void 0,
199
- "mac11": "builds/chromium/%s/chromium-headless-shell-mac.zip",
200
- "mac11-arm64": "builds/chromium/%s/chromium-headless-shell-mac-arm64.zip",
201
- "mac12": "builds/chromium/%s/chromium-headless-shell-mac.zip",
202
- "mac12-arm64": "builds/chromium/%s/chromium-headless-shell-mac-arm64.zip",
203
- "mac13": "builds/chromium/%s/chromium-headless-shell-mac.zip",
204
- "mac13-arm64": "builds/chromium/%s/chromium-headless-shell-mac-arm64.zip",
205
- "mac14": "builds/chromium/%s/chromium-headless-shell-mac.zip",
206
- "mac14-arm64": "builds/chromium/%s/chromium-headless-shell-mac-arm64.zip",
207
- "mac15": "builds/chromium/%s/chromium-headless-shell-mac.zip",
208
- "mac15-arm64": "builds/chromium/%s/chromium-headless-shell-mac-arm64.zip",
209
- "win64": "builds/chromium/%s/chromium-headless-shell-win64.zip"
209
+ "mac11": cftUrl("mac-x64/chrome-headless-shell-mac-x64.zip"),
210
+ "mac11-arm64": cftUrl("mac-arm64/chrome-headless-shell-mac-arm64.zip"),
211
+ "mac12": cftUrl("mac-x64/chrome-headless-shell-mac-x64.zip"),
212
+ "mac12-arm64": cftUrl("mac-arm64/chrome-headless-shell-mac-arm64.zip"),
213
+ "mac13": cftUrl("mac-x64/chrome-headless-shell-mac-x64.zip"),
214
+ "mac13-arm64": cftUrl("mac-arm64/chrome-headless-shell-mac-arm64.zip"),
215
+ "mac14": cftUrl("mac-x64/chrome-headless-shell-mac-x64.zip"),
216
+ "mac14-arm64": cftUrl("mac-arm64/chrome-headless-shell-mac-arm64.zip"),
217
+ "mac15": cftUrl("mac-x64/chrome-headless-shell-mac-x64.zip"),
218
+ "mac15-arm64": cftUrl("mac-arm64/chrome-headless-shell-mac-arm64.zip"),
219
+ "win64": cftUrl("win64/chrome-headless-shell-win64.zip")
210
220
  },
211
221
  "chromium-tip-of-tree": {
212
222
  "<unknown>": void 0,
@@ -1124,8 +1134,16 @@ Run "${buildPlaywrightCLICommand(sdkLanguage, "install " + name)}"` : "";
1124
1134
  const downloadPathTemplate = paths[import_hostPlatform.hostPlatform] || paths["<unknown>"];
1125
1135
  if (!downloadPathTemplate)
1126
1136
  return [];
1127
- const downloadPath = util.format(downloadPathTemplate, descriptor.revision);
1128
- let downloadURLs = PLAYWRIGHT_CDN_MIRRORS.map((mirror) => `${mirror}/${downloadPath}`);
1137
+ let downloadPath;
1138
+ let mirrors;
1139
+ if (typeof downloadPathTemplate === "function") {
1140
+ const result = downloadPathTemplate(descriptor);
1141
+ downloadPath = result.path;
1142
+ mirrors = result.mirrors;
1143
+ } else {
1144
+ downloadPath = util.format(downloadPathTemplate, descriptor.revision);
1145
+ mirrors = PLAYWRIGHT_CDN_MIRRORS;
1146
+ }
1129
1147
  let downloadHostEnv;
1130
1148
  if (descriptor.name.startsWith("chromium"))
1131
1149
  downloadHostEnv = "PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST";
@@ -1135,8 +1153,8 @@ Run "${buildPlaywrightCLICommand(sdkLanguage, "install " + name)}"` : "";
1135
1153
  downloadHostEnv = "PLAYWRIGHT_WEBKIT_DOWNLOAD_HOST";
1136
1154
  const customHostOverride = downloadHostEnv && (0, import_utils.getFromENV)(downloadHostEnv) || (0, import_utils.getFromENV)("PLAYWRIGHT_DOWNLOAD_HOST");
1137
1155
  if (customHostOverride)
1138
- downloadURLs = [`${customHostOverride}/${downloadPath}`];
1139
- return downloadURLs;
1156
+ mirrors = [customHostOverride];
1157
+ return mirrors.map((mirror) => `${mirror}/${downloadPath}`);
1140
1158
  }
1141
1159
  async _downloadExecutable(descriptor, executablePath) {
1142
1160
  const downloadURLs = this._downloadURLs(descriptor);
@@ -49,7 +49,6 @@ var import_wkInput = require("./wkInput");
49
49
  var import_wkInterceptableRequest = require("./wkInterceptableRequest");
50
50
  var import_wkProvisionalPage = require("./wkProvisionalPage");
51
51
  var import_wkWorkers = require("./wkWorkers");
52
- var import_debugLogger = require("../utils/debugLogger");
53
52
  var import_webkit = require("./webkit");
54
53
  const UTILITY_WORLD_NAME = "__playwright_utility_world__";
55
54
  class WKPage {
@@ -836,7 +835,7 @@ class WKPage {
836
835
  _onScreencastFrame(event) {
837
836
  const generation = this._screencastGeneration;
838
837
  this._page.screencast.throttleFrameAck(() => {
839
- this._pageProxySession.send("Screencast.screencastFrameAck", { generation }).catch((e) => import_debugLogger.debugLogger.log("error", e));
838
+ this._pageProxySession.sendMayFail("Screencast.screencastFrameAck", { generation });
840
839
  });
841
840
  const buffer = Buffer.from(event.data, "base64");
842
841
  this._page.emit(import_page.Page.Events.ScreencastFrame, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playwright-core",
3
- "version": "1.58.0-alpha-2025-12-18",
3
+ "version": "1.58.0-alpha-2025-12-19",
4
4
  "description": "A high-level API to automate web browsers",
5
5
  "repository": {
6
6
  "type": "git",
package/types/types.d.ts CHANGED
@@ -22046,6 +22046,12 @@ export interface ConnectOverCDPOptions {
22046
22046
  */
22047
22047
  headers?: { [key: string]: string; };
22048
22048
 
22049
+ /**
22050
+ * Tells Playwright that it runs on the same host as the CDP server. It will enable certain optimizations that rely
22051
+ * upon the file system being the same between Playwright and the Browser.
22052
+ */
22053
+ isLocal?: boolean;
22054
+
22049
22055
  /**
22050
22056
  * Logger sink for Playwright logging. Optional.
22051
22057
  * @deprecated The logs received by the logger are incomplete. Please use tracing instead.
@@ -22226,14 +22232,14 @@ export interface BrowserContextOptions {
22226
22232
  */
22227
22233
  agent?: {
22228
22234
  /**
22229
- * LLM provider to use.
22235
+ * LLM provider to use. Required in non-cache mode.
22230
22236
  */
22231
- provider: string;
22237
+ provider?: string;
22232
22238
 
22233
22239
  /**
22234
- * Model identifier within provider.
22240
+ * Model identifier within the provider. Required in non-cache mode.
22235
22241
  */
22236
- model: string;
22242
+ model?: string;
22237
22243
 
22238
22244
  /**
22239
22245
  * Cache file to use/generate code for performed actions into. Cache is not used if not specified (default).
@@ -22241,9 +22247,9 @@ export interface BrowserContextOptions {
22241
22247
  cacheFile?: string;
22242
22248
 
22243
22249
  /**
22244
- * Cache control, defaults to 'auto'.
22250
+ * When specified, generated entries are written into the `cacheOutFile` instead of updating the `cacheFile`.
22245
22251
  */
22246
- cacheMode?: "force"|"ignore"|"update"|"auto";
22252
+ cacheOutFile?: string;
22247
22253
 
22248
22254
  /**
22249
22255
  * Secrets to hide from the LLM.