patchright-core 1.57.0 → 1.58.2

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.
Files changed (148) hide show
  1. package/ThirdPartyNotices.txt +3223 -308
  2. package/browsers.json +21 -22
  3. package/lib/cli/program.js +4 -5
  4. package/lib/client/api.js +3 -0
  5. package/lib/client/browser.js +3 -5
  6. package/lib/client/browserContext.js +40 -4
  7. package/lib/client/browserType.js +4 -3
  8. package/lib/client/connection.js +4 -0
  9. package/lib/client/elementHandle.js +3 -0
  10. package/lib/client/events.js +3 -0
  11. package/lib/client/fetch.js +3 -4
  12. package/lib/client/frame.js +10 -1
  13. package/lib/client/locator.js +8 -0
  14. package/lib/client/network.js +5 -1
  15. package/lib/client/page.js +29 -1
  16. package/lib/client/pageAgent.js +64 -0
  17. package/lib/client/platform.js +3 -0
  18. package/lib/client/tracing.js +1 -1
  19. package/lib/generated/injectedScriptSource.js +1 -1
  20. package/lib/generated/pollingRecorderSource.js +1 -1
  21. package/lib/mcpBundle.js +84 -0
  22. package/lib/mcpBundleImpl/index.js +147 -0
  23. package/lib/protocol/serializers.js +5 -0
  24. package/lib/protocol/validator.js +88 -4
  25. package/lib/remote/playwrightServer.js +1 -2
  26. package/lib/server/agent/actionRunner.js +335 -0
  27. package/lib/server/agent/actions.js +128 -0
  28. package/lib/server/agent/codegen.js +111 -0
  29. package/lib/server/agent/context.js +150 -0
  30. package/lib/server/agent/expectTools.js +156 -0
  31. package/lib/server/agent/pageAgent.js +204 -0
  32. package/lib/server/agent/performTools.js +262 -0
  33. package/lib/server/agent/tool.js +109 -0
  34. package/lib/server/artifact.js +1 -1
  35. package/lib/server/bidi/bidiBrowser.js +56 -12
  36. package/lib/server/bidi/bidiChromium.js +8 -12
  37. package/lib/server/bidi/bidiConnection.js +1 -0
  38. package/lib/server/bidi/bidiDeserializer.js +116 -0
  39. package/lib/server/bidi/bidiExecutionContext.js +75 -29
  40. package/lib/server/bidi/bidiFirefox.js +6 -8
  41. package/lib/server/bidi/bidiNetworkManager.js +1 -1
  42. package/lib/server/bidi/bidiPage.js +39 -28
  43. package/lib/server/bidi/third_party/bidiProtocolCore.js +1 -0
  44. package/lib/server/browserContext.js +34 -26
  45. package/lib/server/browserType.js +12 -4
  46. package/lib/server/chromium/chromium.js +14 -20
  47. package/lib/server/chromium/chromiumSwitches.js +2 -2
  48. package/lib/server/chromium/crBrowser.js +22 -12
  49. package/lib/server/chromium/crConnection.js +0 -5
  50. package/lib/server/chromium/crCoverage.js +13 -1
  51. package/lib/server/chromium/crDevTools.js +0 -2
  52. package/lib/server/chromium/crNetworkManager.js +92 -12
  53. package/lib/server/chromium/crPage.js +62 -116
  54. package/lib/server/codegen/javascript.js +6 -29
  55. package/lib/server/deviceDescriptorsSource.json +56 -56
  56. package/lib/server/dispatchers/browserContextDispatcher.js +3 -2
  57. package/lib/server/dispatchers/dispatcher.js +6 -13
  58. package/lib/server/dispatchers/frameDispatcher.js +1 -1
  59. package/lib/server/dispatchers/jsHandleDispatcher.js +2 -2
  60. package/lib/server/dispatchers/pageAgentDispatcher.js +96 -0
  61. package/lib/server/dispatchers/pageDispatcher.js +4 -0
  62. package/lib/server/dom.js +12 -3
  63. package/lib/server/electron/electron.js +5 -2
  64. package/lib/server/firefox/ffBrowser.js +10 -20
  65. package/lib/server/firefox/ffConnection.js +0 -5
  66. package/lib/server/firefox/ffNetworkManager.js +2 -2
  67. package/lib/server/firefox/ffPage.js +15 -18
  68. package/lib/server/firefox/firefox.js +6 -8
  69. package/lib/server/frameSelectors.js +16 -4
  70. package/lib/server/frames.js +251 -86
  71. package/lib/server/instrumentation.js +3 -0
  72. package/lib/server/javascript.js +8 -4
  73. package/lib/server/launchApp.js +2 -1
  74. package/lib/server/network.js +50 -12
  75. package/lib/server/page.js +61 -91
  76. package/lib/server/progress.js +26 -6
  77. package/lib/server/recorder/recorderApp.js +79 -100
  78. package/lib/server/registry/browserFetcher.js +6 -4
  79. package/lib/server/registry/index.js +172 -149
  80. package/lib/server/registry/oopDownloadBrowserMain.js +3 -0
  81. package/lib/server/screencast.js +190 -0
  82. package/lib/server/screenshotter.js +6 -0
  83. package/lib/server/trace/recorder/snapshotter.js +17 -8
  84. package/lib/server/trace/recorder/snapshotterInjected.js +30 -72
  85. package/lib/server/trace/recorder/tracing.js +29 -21
  86. package/lib/server/trace/viewer/traceParser.js +72 -0
  87. package/lib/server/trace/viewer/traceViewer.js +21 -17
  88. package/lib/server/utils/expectUtils.js +87 -2
  89. package/lib/server/utils/hostPlatform.js +15 -0
  90. package/lib/server/utils/httpServer.js +5 -20
  91. package/lib/server/utils/network.js +37 -28
  92. package/lib/server/utils/nodePlatform.js +6 -0
  93. package/lib/server/{chromium/videoRecorder.js → videoRecorder.js} +22 -13
  94. package/lib/server/webkit/webkit.js +4 -6
  95. package/lib/server/webkit/wkBrowser.js +2 -6
  96. package/lib/server/webkit/wkConnection.js +1 -6
  97. package/lib/server/webkit/wkInterceptableRequest.js +29 -1
  98. package/lib/server/webkit/wkPage.js +75 -46
  99. package/lib/utils/isomorphic/ariaSnapshot.js +60 -2
  100. package/lib/utils/isomorphic/lruCache.js +51 -0
  101. package/lib/utils/isomorphic/protocolMetainfo.js +9 -1
  102. package/lib/utils/isomorphic/stringUtils.js +49 -0
  103. package/lib/utils/isomorphic/trace/entries.js +16 -0
  104. package/lib/utils/isomorphic/trace/snapshotRenderer.js +499 -0
  105. package/lib/utils/isomorphic/trace/snapshotServer.js +120 -0
  106. package/lib/utils/isomorphic/trace/snapshotStorage.js +89 -0
  107. package/lib/utils/isomorphic/trace/traceLoader.js +131 -0
  108. package/lib/utils/isomorphic/trace/traceModel.js +365 -0
  109. package/lib/utils/isomorphic/trace/traceModernizer.js +400 -0
  110. package/lib/utils/isomorphic/trace/versions/traceV3.js +16 -0
  111. package/lib/utils/isomorphic/trace/versions/traceV4.js +16 -0
  112. package/lib/utils/isomorphic/trace/versions/traceV5.js +16 -0
  113. package/lib/utils/isomorphic/trace/versions/traceV6.js +16 -0
  114. package/lib/utils/isomorphic/trace/versions/traceV7.js +16 -0
  115. package/lib/utils/isomorphic/trace/versions/traceV8.js +16 -0
  116. package/lib/utils/isomorphic/yaml.js +84 -0
  117. package/lib/utils.js +2 -0
  118. package/lib/utilsBundle.js +2 -5
  119. package/lib/utilsBundleImpl/index.js +165 -165
  120. package/lib/vite/htmlReport/index.html +21 -21
  121. package/lib/vite/recorder/assets/codeMirrorModule-CFUTFUO7.js +32 -0
  122. package/lib/vite/{traceViewer/codeMirrorModule.C3UTv-Ge.css → recorder/assets/codeMirrorModule-DYBRYzYX.css} +1 -1
  123. package/lib/vite/recorder/assets/{index-Ri0uHF7I.css → index-BSjZa4pk.css} +1 -1
  124. package/lib/vite/recorder/assets/index-CVkBxsGf.js +193 -0
  125. package/lib/vite/recorder/index.html +2 -2
  126. package/lib/vite/traceViewer/assets/codeMirrorModule-BVA4h_ZY.js +32 -0
  127. package/lib/vite/traceViewer/assets/defaultSettingsView-CjfmcdOz.js +266 -0
  128. package/lib/vite/{recorder/assets/codeMirrorModule-C3UTv-Ge.css → traceViewer/codeMirrorModule.DYBRYzYX.css} +1 -1
  129. package/lib/vite/traceViewer/defaultSettingsView.7ch9cixO.css +1 -0
  130. package/lib/vite/traceViewer/index.BVu7tZDe.css +1 -0
  131. package/lib/vite/traceViewer/index.BtyWtaE-.js +2 -0
  132. package/lib/vite/traceViewer/index.html +4 -4
  133. package/lib/vite/traceViewer/sw.bundle.js +5 -3
  134. package/lib/vite/traceViewer/uiMode.fyrXARf2.js +5 -0
  135. package/lib/vite/traceViewer/uiMode.html +3 -3
  136. package/package.json +2 -1
  137. package/types/protocol.d.ts +738 -159
  138. package/types/types.d.ts +25 -38
  139. package/lib/server/bidi/third_party/bidiDeserializer.js +0 -98
  140. package/lib/server/trace/test/inMemorySnapshotter.js +0 -87
  141. package/lib/vite/recorder/assets/codeMirrorModule-CBbSe-ZI.js +0 -25
  142. package/lib/vite/recorder/assets/index-CpZVd2nA.js +0 -193
  143. package/lib/vite/traceViewer/assets/codeMirrorModule-DHz0wP2C.js +0 -25
  144. package/lib/vite/traceViewer/assets/defaultSettingsView-WsZP88O6.js +0 -266
  145. package/lib/vite/traceViewer/defaultSettingsView.ConWv5KN.css +0 -1
  146. package/lib/vite/traceViewer/index.C4Y3Aw8n.css +0 -1
  147. package/lib/vite/traceViewer/index.C8xAeo93.js +0 -2
  148. package/lib/vite/traceViewer/uiMode.BltraIJB.js +0 -5
@@ -53,6 +53,7 @@ class RecorderApp {
53
53
  this._recorderSources = [];
54
54
  this._page = page;
55
55
  this._recorder = recorder;
56
+ this._frontend = createRecorderFrontend(page);
56
57
  this.wsEndpointForTest = wsEndpointForTest;
57
58
  this._languageGeneratorOptions = {
58
59
  browserName: params.browserName,
@@ -64,6 +65,10 @@ class RecorderApp {
64
65
  this._throttledOutputFile = params.outputFile ? new import_throttledFile.ThrottledFile(params.outputFile) : null;
65
66
  this._primaryGeneratorId = process.env.TEST_INSPECTOR_LANGUAGE || params.language || determinePrimaryGeneratorId(params.sdkLanguage);
66
67
  this._selectedGeneratorId = this._primaryGeneratorId;
68
+ for (const languageGenerator of (0, import_languages.languageSet)()) {
69
+ if (languageGenerator.id === this._primaryGeneratorId)
70
+ this._recorder.setLanguage(languageGenerator.highlighter);
71
+ }
67
72
  }
68
73
  async _init(inspectedContext) {
69
74
  await (0, import_launchApp.syncLocalStorageWithSettings)(this._page, "recorder");
@@ -89,7 +94,7 @@ class RecorderApp {
89
94
  });
90
95
  });
91
96
  });
92
- await this._page.exposeBinding(progress, "dispatch", false, (_, data) => this._handleUIEvent(data));
97
+ await this._createDispatcher(progress);
93
98
  this._page.once("close", () => {
94
99
  this._recorder.close();
95
100
  this._page.browserContext.close({ reason: "Recorder window closed" }).catch(() => {
@@ -100,59 +105,56 @@ class RecorderApp {
100
105
  });
101
106
  const url = this._recorder.url();
102
107
  if (url)
103
- this._onPageNavigated(url);
104
- this._onModeChanged(this._recorder.mode());
105
- this._onPausedStateChanged(this._recorder.paused());
108
+ this._frontend.pageNavigated({ url });
109
+ this._frontend.modeChanged({ mode: this._recorder.mode() });
110
+ this._frontend.pauseStateChanged({ paused: this._recorder.paused() });
106
111
  this._updateActions("reveal");
107
112
  this._onUserSourcesChanged(this._recorder.userSources(), this._recorder.pausedSourceId());
108
- this._onCallLogsUpdated(this._recorder.callLog());
113
+ this._frontend.callLogsUpdated({ callLogs: this._recorder.callLog() });
109
114
  this._wireListeners(this._recorder);
110
115
  }
111
- _handleUIEvent(data) {
112
- if (data.event === "clear") {
113
- this._actions = [];
114
- this._updateActions("reveal");
115
- this._recorder.clear();
116
- return;
117
- }
118
- if (data.event === "fileChanged") {
119
- const source = [...this._recorderSources, ...this._userSources].find((s) => s.id === data.params.fileId);
120
- if (source) {
121
- if (source.isRecorded)
122
- this._selectedGeneratorId = source.id;
123
- this._recorder.setLanguage(source.language);
116
+ async _createDispatcher(progress) {
117
+ const dispatcher = {
118
+ clear: async () => {
119
+ this._actions = [];
120
+ this._updateActions("reveal");
121
+ this._recorder.clear();
122
+ },
123
+ fileChanged: async (params) => {
124
+ const source = [...this._recorderSources, ...this._userSources].find((s) => s.id === params.fileId);
125
+ if (source) {
126
+ if (source.isRecorded)
127
+ this._selectedGeneratorId = source.id;
128
+ this._recorder.setLanguage(source.language);
129
+ }
130
+ },
131
+ setAutoExpect: async (params) => {
132
+ this._languageGeneratorOptions.generateAutoExpect = params.autoExpect;
133
+ this._updateActions();
134
+ },
135
+ setMode: async (params) => {
136
+ this._recorder.setMode(params.mode);
137
+ },
138
+ resume: async () => {
139
+ this._recorder.resume();
140
+ },
141
+ pause: async () => {
142
+ this._recorder.pause();
143
+ },
144
+ step: async () => {
145
+ this._recorder.step();
146
+ },
147
+ highlightRequested: async (params) => {
148
+ if (params.selector)
149
+ this._recorder.setHighlightedSelector(params.selector);
150
+ if (params.ariaTemplate)
151
+ this._recorder.setHighlightedAriaTemplate(params.ariaTemplate);
124
152
  }
125
- return;
126
- }
127
- if (data.event === "setAutoExpect") {
128
- this._languageGeneratorOptions.generateAutoExpect = data.params.autoExpect;
129
- this._updateActions();
130
- return;
131
- }
132
- if (data.event === "setMode") {
133
- this._recorder.setMode(data.params.mode);
134
- return;
135
- }
136
- if (data.event === "resume") {
137
- this._recorder.resume();
138
- return;
139
- }
140
- if (data.event === "pause") {
141
- this._recorder.pause();
142
- return;
143
- }
144
- if (data.event === "step") {
145
- this._recorder.step();
146
- return;
147
- }
148
- if (data.event === "highlightRequested") {
149
- if (data.params.selector)
150
- this._recorder.setHighlightedSelector(data.params.selector);
151
- if (data.params.ariaTemplate)
152
- this._recorder.setHighlightedAriaTemplate(data.params.ariaTemplate);
153
- return;
154
- }
155
- throw new Error(`Unknown event: ${data.event}`);
153
+ };
154
+ await this._page.exposeBinding(progress, "sendCommand", false, async (_, data) => {
155
+ const { method, params } = data;
156
+ return await dispatcher[method].call(dispatcher, params);
157
+ });
156
158
  }
157
159
  static async show(context, params) {
158
160
  if (process.env.PW_CODEGEN_NO_INSPECTOR)
@@ -220,25 +222,29 @@ class RecorderApp {
220
222
  this._onSignalAdded(signal);
221
223
  });
222
224
  recorder.on(import_recorder.RecorderEvent.PageNavigated, (url) => {
223
- this._onPageNavigated(url);
225
+ this._frontend.pageNavigated({ url });
224
226
  });
225
227
  recorder.on(import_recorder.RecorderEvent.ContextClosed, () => {
226
- this._onContextClosed();
228
+ this._throttledOutputFile?.flush();
229
+ this._page.browserContext.close({ reason: "Recorder window closed" }).catch(() => {
230
+ });
227
231
  });
228
232
  recorder.on(import_recorder.RecorderEvent.ModeChanged, (mode) => {
229
- this._onModeChanged(mode);
233
+ this._frontend.modeChanged({ mode });
230
234
  });
231
235
  recorder.on(import_recorder.RecorderEvent.PausedStateChanged, (paused) => {
232
- this._onPausedStateChanged(paused);
236
+ this._frontend.pauseStateChanged({ paused });
233
237
  });
234
238
  recorder.on(import_recorder.RecorderEvent.UserSourcesChanged, (sources, pausedSourceId) => {
235
239
  this._onUserSourcesChanged(sources, pausedSourceId);
236
240
  });
237
241
  recorder.on(import_recorder.RecorderEvent.ElementPicked, (elementInfo, userGesture) => {
238
- this._onElementPicked(elementInfo, userGesture);
242
+ if (userGesture)
243
+ this._page.bringToFront();
244
+ this._frontend.elementPicked({ elementInfo, userGesture });
239
245
  });
240
246
  recorder.on(import_recorder.RecorderEvent.CallLogsUpdated, (callLogs) => {
241
- this._onCallLogsUpdated(callLogs);
247
+ this._frontend.callLogsUpdated({ callLogs });
242
248
  });
243
249
  }
244
250
  _onActionAdded(action) {
@@ -251,29 +257,6 @@ class RecorderApp {
251
257
  lastAction.action.signals.push(signal.signal);
252
258
  this._updateActions();
253
259
  }
254
- _onPageNavigated(url) {
255
- this._page.mainFrame().evaluateExpression((({ url: url2 }) => {
256
- window.playwrightSetPageURL(url2);
257
- }).toString(), { isFunction: true }, { url }).catch(() => {
258
- });
259
- }
260
- _onContextClosed() {
261
- this._throttledOutputFile?.flush();
262
- this._page.browserContext.close({ reason: "Recorder window closed" }).catch(() => {
263
- });
264
- }
265
- _onModeChanged(mode) {
266
- this._page.mainFrame().evaluateExpression(((mode2) => {
267
- window.playwrightSetMode(mode2);
268
- }).toString(), { isFunction: true }, mode).catch(() => {
269
- });
270
- }
271
- _onPausedStateChanged(paused) {
272
- this._page.mainFrame().evaluateExpression(((paused2) => {
273
- window.playwrightSetPaused(paused2);
274
- }).toString(), { isFunction: true }, paused).catch(() => {
275
- });
276
- }
277
260
  _onUserSourcesChanged(sources, pausedSourceId) {
278
261
  if (!sources.length && !this._userSources.length)
279
262
  return;
@@ -281,34 +264,14 @@ class RecorderApp {
281
264
  this._pushAllSources();
282
265
  this._revealSource(pausedSourceId);
283
266
  }
284
- _onElementPicked(elementInfo, userGesture) {
285
- if (userGesture)
286
- this._page.bringToFront();
287
- this._page.mainFrame().evaluateExpression(((param) => {
288
- window.playwrightElementPicked(param.elementInfo, param.userGesture);
289
- }).toString(), { isFunction: true }, { elementInfo, userGesture }).catch(() => {
290
- });
291
- }
292
- _onCallLogsUpdated(callLogs) {
293
- this._page.mainFrame().evaluateExpression(((callLogs2) => {
294
- window.playwrightUpdateLogs(callLogs2);
295
- }).toString(), { isFunction: true }, callLogs).catch(() => {
296
- });
297
- }
298
267
  _pushAllSources() {
299
268
  const sources = [...this._userSources, ...this._recorderSources];
300
- this._page.mainFrame().evaluateExpression((({ sources: sources2 }) => {
301
- window.playwrightSetSources(sources2);
302
- }).toString(), { isFunction: true }, { sources }).catch(() => {
303
- });
269
+ this._frontend.sourcesUpdated({ sources });
304
270
  }
305
271
  _revealSource(sourceId) {
306
272
  if (!sourceId)
307
273
  return;
308
- this._page.mainFrame().evaluateExpression((({ sourceId: sourceId2 }) => {
309
- window.playwrightSelectSource(sourceId2);
310
- }).toString(), { isFunction: true }, { sourceId }).catch(() => {
311
- });
274
+ this._frontend.sourceRevealRequested({ sourceId });
312
275
  }
313
276
  _updateActions(reveal) {
314
277
  const recorderSources = [];
@@ -372,6 +335,8 @@ class ProgrammaticRecorderApp {
372
335
  });
373
336
  recorder.on(import_recorder.RecorderEvent.SignalAdded, (signal) => {
374
337
  const page = findPageByGuid(inspectedContext, signal.frame.pageGuid);
338
+ if (!page)
339
+ return;
375
340
  inspectedContext.emit(import_browserContext.BrowserContext.Events.RecorderEvent, { event: "signalAdded", data: signal, page, code: "" });
376
341
  });
377
342
  }
@@ -379,6 +344,20 @@ class ProgrammaticRecorderApp {
379
344
  function findPageByGuid(context, guid) {
380
345
  return context.pages().find((p) => p.guid === guid);
381
346
  }
347
+ function createRecorderFrontend(page) {
348
+ return new Proxy({}, {
349
+ get: (_target, prop) => {
350
+ if (typeof prop !== "string")
351
+ return void 0;
352
+ return (params) => {
353
+ page.mainFrame().evaluateExpression(((event) => {
354
+ window.dispatch(event);
355
+ }).toString(), { isFunction: true }, { method: prop, params }).catch(() => {
356
+ });
357
+ };
358
+ }
359
+ });
360
+ }
382
361
  const recorderAppSymbol = Symbol("recorderApp");
383
362
  // Annotate the CommonJS export names for ESM import in node:
384
363
  0 && (module.exports = {
@@ -42,10 +42,13 @@ var import_userAgent = require("../utils/userAgent");
42
42
  var import_utilsBundle = require("../../utilsBundle");
43
43
  var import_fileUtils = require("../utils/fileUtils");
44
44
  var import__ = require(".");
45
- async function downloadBrowserWithProgressBar(title, browserDirectory, executablePath, downloadURLs, downloadFileName, downloadSocketTimeout) {
45
+ async function downloadBrowserWithProgressBar(title, browserDirectory, executablePath, downloadURLs, downloadFileName, downloadSocketTimeout, force) {
46
46
  if (await (0, import_fileUtils.existsAsync)((0, import__.browserDirectoryToMarkerFilePath)(browserDirectory))) {
47
47
  import_debugLogger.debugLogger.log("install", `${title} is already downloaded.`);
48
- return false;
48
+ if (force)
49
+ import_debugLogger.debugLogger.log("install", `force-downloading ${title}.`);
50
+ else
51
+ return;
49
52
  }
50
53
  const uniqueTempDir = await import_fs.default.promises.mkdtemp(import_path.default.join(import_os.default.tmpdir(), "playwright-download-"));
51
54
  const zipPath = import_path.default.join(uniqueTempDir, downloadFileName);
@@ -63,7 +66,7 @@ async function downloadBrowserWithProgressBar(title, browserDirectory, executabl
63
66
  if (await (0, import_fileUtils.existsAsync)(zipPath))
64
67
  await import_fs.default.promises.unlink(zipPath);
65
68
  if (await (0, import_fileUtils.existsAsync)(browserDirectory))
66
- await import_fs.default.promises.rmdir(browserDirectory, { recursive: true });
69
+ await (0, import_fileUtils.removeFolders)([browserDirectory]);
67
70
  const errorMessage = error?.message || "";
68
71
  import_debugLogger.debugLogger.log("install", `attempt #${attempt} - ERROR: ${errorMessage}`);
69
72
  if (attempt >= retryCount)
@@ -77,7 +80,6 @@ async function downloadBrowserWithProgressBar(title, browserDirectory, executabl
77
80
  await (0, import_fileUtils.removeFolders)([uniqueTempDir]);
78
81
  }
79
82
  logPolitely(`${title} downloaded to ${browserDirectory}`);
80
- return true;
81
83
  }
82
84
  function downloadBrowserWithProgressBarOutOfProcess(title, browserDirectory, url, zipPath, executablePath, socketTimeout) {
83
85
  const cp = childProcess.fork(import_path.default.join(__dirname, "oopDownloadBrowserMain.js"));