@browserbasehq/orca 3.6.0-gemini-cua → 3.7.0-preview.1

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 (85) hide show
  1. package/dist/cjs/lib/v3/agent/AgentClient.d.ts +2 -2
  2. package/dist/cjs/lib/v3/agent/AgentClient.js.map +1 -1
  3. package/dist/cjs/lib/v3/agent/AnthropicCUAClient.d.ts +4 -3
  4. package/dist/cjs/lib/v3/agent/AnthropicCUAClient.js +11 -9
  5. package/dist/cjs/lib/v3/agent/AnthropicCUAClient.js.map +1 -1
  6. package/dist/cjs/lib/v3/agent/GoogleCUAClient.d.ts +12 -3
  7. package/dist/cjs/lib/v3/agent/GoogleCUAClient.js +107 -22
  8. package/dist/cjs/lib/v3/agent/GoogleCUAClient.js.map +1 -1
  9. package/dist/cjs/lib/v3/agent/MicrosoftCUAClient.d.ts +2 -2
  10. package/dist/cjs/lib/v3/agent/MicrosoftCUAClient.js +2 -2
  11. package/dist/cjs/lib/v3/agent/MicrosoftCUAClient.js.map +1 -1
  12. package/dist/cjs/lib/v3/agent/OpenAICUAClient.d.ts +6 -3
  13. package/dist/cjs/lib/v3/agent/OpenAICUAClient.js +13 -7
  14. package/dist/cjs/lib/v3/agent/OpenAICUAClient.js.map +1 -1
  15. package/dist/cjs/lib/v3/agent/utils/handleDoneToolCall.d.ts +1 -0
  16. package/dist/cjs/lib/v3/agent/utils/handleDoneToolCall.js +40 -2
  17. package/dist/cjs/lib/v3/agent/utils/handleDoneToolCall.js.map +1 -1
  18. package/dist/cjs/lib/v3/handlers/v3AgentHandler.js +30 -7
  19. package/dist/cjs/lib/v3/handlers/v3AgentHandler.js.map +1 -1
  20. package/dist/cjs/lib/v3/handlers/v3CuaAgentHandler.js +32 -18
  21. package/dist/cjs/lib/v3/handlers/v3CuaAgentHandler.js.map +1 -1
  22. package/dist/cjs/lib/v3/index.d.ts +1 -0
  23. package/dist/cjs/lib/v3/llm/LLMProvider.d.ts +2 -2
  24. package/dist/cjs/lib/v3/llm/LLMProvider.js.map +1 -1
  25. package/dist/cjs/lib/v3/types/public/agent.d.ts +9 -0
  26. package/dist/cjs/lib/v3/types/public/agent.js.map +1 -1
  27. package/dist/cjs/lib/v3/types/public/context.d.ts +7 -0
  28. package/dist/cjs/lib/v3/types/public/context.js.map +1 -1
  29. package/dist/cjs/lib/v3/types/public/sdkErrors.d.ts +4 -0
  30. package/dist/cjs/lib/v3/types/public/sdkErrors.js +9 -1
  31. package/dist/cjs/lib/v3/types/public/sdkErrors.js.map +1 -1
  32. package/dist/cjs/lib/v3/understudy/cdp.d.ts +2 -0
  33. package/dist/cjs/lib/v3/understudy/cdp.js +26 -12
  34. package/dist/cjs/lib/v3/understudy/cdp.js.map +1 -1
  35. package/dist/cjs/lib/v3/understudy/context.d.ts +13 -1
  36. package/dist/cjs/lib/v3/understudy/context.js +284 -1
  37. package/dist/cjs/lib/v3/understudy/context.js.map +1 -1
  38. package/dist/cjs/lib/v3/understudy/domainPolicy.d.ts +25 -0
  39. package/dist/cjs/lib/v3/understudy/domainPolicy.js +162 -0
  40. package/dist/cjs/lib/v3/understudy/domainPolicy.js.map +1 -0
  41. package/dist/cjs/lib/v3/v3.js +4 -1
  42. package/dist/cjs/lib/v3/v3.js.map +1 -1
  43. package/dist/esm/lib/v3/agent/AgentClient.d.ts +2 -2
  44. package/dist/esm/lib/v3/agent/AgentClient.js.map +1 -1
  45. package/dist/esm/lib/v3/agent/AnthropicCUAClient.d.ts +4 -3
  46. package/dist/esm/lib/v3/agent/AnthropicCUAClient.js +11 -9
  47. package/dist/esm/lib/v3/agent/AnthropicCUAClient.js.map +1 -1
  48. package/dist/esm/lib/v3/agent/GoogleCUAClient.d.ts +12 -3
  49. package/dist/esm/lib/v3/agent/GoogleCUAClient.js +107 -22
  50. package/dist/esm/lib/v3/agent/GoogleCUAClient.js.map +1 -1
  51. package/dist/esm/lib/v3/agent/MicrosoftCUAClient.d.ts +2 -2
  52. package/dist/esm/lib/v3/agent/MicrosoftCUAClient.js +2 -2
  53. package/dist/esm/lib/v3/agent/MicrosoftCUAClient.js.map +1 -1
  54. package/dist/esm/lib/v3/agent/OpenAICUAClient.d.ts +6 -3
  55. package/dist/esm/lib/v3/agent/OpenAICUAClient.js +13 -7
  56. package/dist/esm/lib/v3/agent/OpenAICUAClient.js.map +1 -1
  57. package/dist/esm/lib/v3/agent/utils/handleDoneToolCall.d.ts +1 -0
  58. package/dist/esm/lib/v3/agent/utils/handleDoneToolCall.js +39 -2
  59. package/dist/esm/lib/v3/agent/utils/handleDoneToolCall.js.map +1 -1
  60. package/dist/esm/lib/v3/handlers/v3AgentHandler.js +30 -7
  61. package/dist/esm/lib/v3/handlers/v3AgentHandler.js.map +1 -1
  62. package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.js +32 -18
  63. package/dist/esm/lib/v3/handlers/v3CuaAgentHandler.js.map +1 -1
  64. package/dist/esm/lib/v3/index.d.ts +1 -0
  65. package/dist/esm/lib/v3/llm/LLMProvider.d.ts +2 -2
  66. package/dist/esm/lib/v3/llm/LLMProvider.js.map +1 -1
  67. package/dist/esm/lib/v3/types/public/agent.d.ts +9 -0
  68. package/dist/esm/lib/v3/types/public/agent.js.map +1 -1
  69. package/dist/esm/lib/v3/types/public/context.d.ts +7 -0
  70. package/dist/esm/lib/v3/types/public/context.js.map +1 -1
  71. package/dist/esm/lib/v3/types/public/sdkErrors.d.ts +4 -0
  72. package/dist/esm/lib/v3/types/public/sdkErrors.js +7 -0
  73. package/dist/esm/lib/v3/types/public/sdkErrors.js.map +1 -1
  74. package/dist/esm/lib/v3/understudy/cdp.d.ts +2 -0
  75. package/dist/esm/lib/v3/understudy/cdp.js +26 -12
  76. package/dist/esm/lib/v3/understudy/cdp.js.map +1 -1
  77. package/dist/esm/lib/v3/understudy/context.d.ts +13 -1
  78. package/dist/esm/lib/v3/understudy/context.js +285 -2
  79. package/dist/esm/lib/v3/understudy/context.js.map +1 -1
  80. package/dist/esm/lib/v3/understudy/domainPolicy.d.ts +25 -0
  81. package/dist/esm/lib/v3/understudy/domainPolicy.js +158 -0
  82. package/dist/esm/lib/v3/understudy/domainPolicy.js.map +1 -0
  83. package/dist/esm/lib/v3/v3.js +4 -1
  84. package/dist/esm/lib/v3/v3.js.map +1 -1
  85. package/package.json +3 -3
@@ -6,9 +6,14 @@ import { v3ScriptContent } from "../dom/build/scriptV3Content.js";
6
6
  import { executionContexts } from "./executionContextRegistry.js";
7
7
  import { normalizeInitScriptSource } from "./initScripts.js";
8
8
  import { ContextClipboard } from "./clipboard.js";
9
- import { TimeoutError, CookieSetError, PageNotFoundError, StagehandSetExtraHTTPHeadersError, } from "../types/public/sdkErrors.js";
9
+ import { TimeoutError, CookieSetError, PageNotFoundError, StagehandSetExtraHTTPHeadersError, StagehandSetDomainPolicyError, } from "../types/public/sdkErrors.js";
10
10
  import { getEnvTimeoutMs, withTimeout } from "../timeoutConfig.js";
11
11
  import { filterCookies, normalizeCookieParams, cookieMatchesFilter, toCdpCookieParam, } from "./cookies.js";
12
+ import { getDomainPolicyDecision, normalizeDomainPolicy, } from "./domainPolicy.js";
13
+ function isMissingTargetError(error) {
14
+ const message = error instanceof Error ? error.message : String(error);
15
+ return /No target with given id found/i.test(message);
16
+ }
12
17
  /**
13
18
  * Returns true when the target's URL points to a document with a real,
14
19
  * pierceable HTML DOM. We allowlist the small set of schemes that carry
@@ -79,6 +84,7 @@ export class V3Context {
79
84
  // Timestamp for most recent popup/open signal
80
85
  _lastPopupSignalAt = 0;
81
86
  _targetSessionListeners = new Set();
87
+ _domainPolicySessionListeners = new Map();
82
88
  _sessionInit = new Set();
83
89
  pagesByTarget = new Map();
84
90
  mainFrameToTarget = new Map();
@@ -89,8 +95,17 @@ export class V3Context {
89
95
  typeByTarget = new Map();
90
96
  _pageOrder = [];
91
97
  pendingCreatedTargetUrl = new Map();
98
+ pageCreationFailures = new Map();
99
+ // Popup close attempts can race targetCreated, targetInfoChanged, and attached.
100
+ // In-flight promises let attach wait for a close result before deciding whether
101
+ // to skip normal setup. Successful closes stay deduped for the context lifetime
102
+ // because Chrome can emit late targetInfoChanged events after targetDestroyed.
103
+ // Failed closes are not retained so attach can continue and future events may retry.
104
+ domainPolicyClosingTargets = new Set();
105
+ domainPolicyClosePromises = new Map();
92
106
  initScripts = [];
93
107
  extraHttpHeaders = null;
108
+ domainPolicy = null;
94
109
  _clipboard;
95
110
  installTargetSessionListeners(session) {
96
111
  const sessionId = session.id;
@@ -329,6 +344,120 @@ export class V3Context {
329
344
  throw new StagehandSetExtraHTTPHeadersError(failures);
330
345
  }
331
346
  }
347
+ getDomainPolicy() {
348
+ if (!this.domainPolicy)
349
+ return null;
350
+ return {
351
+ ...(this.domainPolicy.allowedDomains.length
352
+ ? { allowedDomains: [...this.domainPolicy.allowedDomains] }
353
+ : {}),
354
+ ...(this.domainPolicy.blockedDomains.length
355
+ ? { blockedDomains: [...this.domainPolicy.blockedDomains] }
356
+ : {}),
357
+ };
358
+ }
359
+ async setDomainPolicy(policy) {
360
+ const nextPolicy = normalizeDomainPolicy(policy);
361
+ this.domainPolicy = nextPolicy;
362
+ const sessions = [];
363
+ for (const sessionId of this._sessionInit) {
364
+ const session = this.conn.getSession(sessionId);
365
+ if (session)
366
+ sessions.push(session);
367
+ }
368
+ if (!sessions.length)
369
+ return;
370
+ const results = await Promise.allSettled(sessions.map(async (session) => {
371
+ if (!nextPolicy) {
372
+ try {
373
+ await session.send("Fetch.disable");
374
+ this.uninstallDomainPolicyHandler(session);
375
+ }
376
+ catch (error) {
377
+ throw { action: "disable", error };
378
+ }
379
+ return;
380
+ }
381
+ this.installDomainPolicyHandler(session);
382
+ try {
383
+ await session.send("Fetch.enable", {
384
+ patterns: nextPolicy.fetchPatterns,
385
+ });
386
+ }
387
+ catch (error) {
388
+ throw { action: "enable", error };
389
+ }
390
+ }));
391
+ const failures = results
392
+ .map((result, index) => ({ result, session: sessions[index] }))
393
+ .filter((entry) => entry.result.status === "rejected")
394
+ .map((entry) => {
395
+ const failure = entry.result.reason;
396
+ if (failure?.action === "enable") {
397
+ this.uninstallDomainPolicyHandler(entry.session);
398
+ }
399
+ const reason = failure?.error ?? entry.result.reason;
400
+ const sid = entry.session.id ?? "unknown";
401
+ const message = reason instanceof Error ? reason.message : String(reason);
402
+ return `session=${sid} error=${message}`;
403
+ });
404
+ if (failures.length) {
405
+ throw new StagehandSetDomainPolicyError(failures);
406
+ }
407
+ }
408
+ installDomainPolicyHandler(session) {
409
+ const sessionId = session.id;
410
+ if (!sessionId)
411
+ return;
412
+ if (this._domainPolicySessionListeners.has(sessionId))
413
+ return;
414
+ const handler = (evt) => {
415
+ void this.handleDomainPolicyRequestPaused(session, evt);
416
+ };
417
+ this._domainPolicySessionListeners.set(sessionId, handler);
418
+ session.on("Fetch.requestPaused", handler);
419
+ }
420
+ uninstallDomainPolicyHandler(session) {
421
+ const sessionId = session.id;
422
+ if (!sessionId)
423
+ return;
424
+ const handler = this._domainPolicySessionListeners.get(sessionId);
425
+ if (!handler)
426
+ return;
427
+ session.off("Fetch.requestPaused", handler);
428
+ this._domainPolicySessionListeners.delete(sessionId);
429
+ }
430
+ async handleDomainPolicyRequestPaused(session, evt) {
431
+ const decision = getDomainPolicyDecision(evt.request.url, this.domainPolicy);
432
+ if (decision.action === "continue") {
433
+ await session
434
+ .send("Fetch.continueRequest", { requestId: evt.requestId })
435
+ .catch(() => { });
436
+ return;
437
+ }
438
+ let hostname = "";
439
+ try {
440
+ hostname = new URL(evt.request.url).hostname.toLowerCase();
441
+ }
442
+ catch {
443
+ // ignore malformed URLs for logging
444
+ }
445
+ v3Logger({
446
+ category: "network",
447
+ message: "Blocked request by domain policy",
448
+ level: 2,
449
+ auxiliary: {
450
+ hostname: { value: hostname, type: "string" },
451
+ ruleType: { value: decision.reason, type: "string" },
452
+ },
453
+ });
454
+ await session
455
+ .send("Fetch.failRequest", {
456
+ requestId: evt.requestId,
457
+ errorReason: "BlockedByClient",
458
+ })
459
+ .catch(() => { });
460
+ }
332
461
  get clipboard() {
333
462
  return (this._clipboard ??= new ContextClipboard({
334
463
  context: this,
@@ -397,6 +526,12 @@ export class V3Context {
397
526
  await this.conn.send("Target.activateTarget", { targetId }).catch(() => { });
398
527
  const deadline = Date.now() + 5000;
399
528
  while (Date.now() < deadline) {
529
+ const failure = this.pageCreationFailures.get(targetId);
530
+ if (failure) {
531
+ this.pageCreationFailures.delete(targetId);
532
+ this.pendingCreatedTargetUrl.delete(targetId);
533
+ throw failure;
534
+ }
400
535
  const page = this.pagesByTarget.get(targetId);
401
536
  if (page) {
402
537
  // we created at about:blank; navigate only after attach so init scripts run
@@ -412,6 +547,7 @@ export class V3Context {
412
547
  }
413
548
  await new Promise((r) => setTimeout(r, 25));
414
549
  }
550
+ this.pendingCreatedTargetUrl.delete(targetId);
415
551
  throw new TimeoutError(`newPage: target not attached (${targetId})`, 5000);
416
552
  }
417
553
  /**
@@ -427,6 +563,9 @@ export class V3Context {
427
563
  this.createdAtByTarget.clear();
428
564
  this.typeByTarget.clear();
429
565
  this.pendingCreatedTargetUrl.clear();
566
+ this.pageCreationFailures.clear();
567
+ this.domainPolicyClosingTargets.clear();
568
+ this.domainPolicyClosePromises.clear();
430
569
  }
431
570
  /**
432
571
  * Bootstrap target lifecycle:
@@ -453,8 +592,12 @@ export class V3Context {
453
592
  const ti = info;
454
593
  if (info.type === "page" && (ti?.openerId || ti?.openerFrameId)) {
455
594
  this._notePopupSignal();
595
+ void this.closePopupIfBlockedByDomainPolicy(info, "targetCreated");
456
596
  }
457
597
  });
598
+ this.conn.on("Target.targetInfoChanged", (evt) => {
599
+ void this.closePopupIfBlockedByDomainPolicy(evt.targetInfo, "targetInfoChanged");
600
+ });
458
601
  // Only enable auto-attach after listeners are ready so replayed targets are captured.
459
602
  await this.conn.enableAutoAttach();
460
603
  const targets = await this.conn.getTargets();
@@ -482,6 +625,9 @@ export class V3Context {
482
625
  * - Resume the target only after listeners are wired.
483
626
  */
484
627
  async onAttachedToTarget(info, sessionId) {
628
+ if (await this.closePopupIfBlockedByDomainPolicy(info, "attached")) {
629
+ return;
630
+ }
485
631
  // Skip non-web targets (workers, chrome extensions, background pages, etc.).
486
632
  // They still need to be resumed so we don't leave them paused by
487
633
  // waitForDebuggerOnStart, but injecting the piercer into these targets
@@ -533,6 +679,24 @@ export class V3Context {
533
679
  .catch(() => false);
534
680
  return { dispatched, response };
535
681
  };
682
+ const queueFetchEnablePreResume = (params) => {
683
+ let error;
684
+ const dispatched = this.conn
685
+ .waitForSessionDispatch(sessionId, "Fetch.enable")
686
+ .then(() => true)
687
+ .catch((err) => {
688
+ error = err;
689
+ return false;
690
+ });
691
+ const response = session
692
+ .send("Fetch.enable", params)
693
+ .then(() => true)
694
+ .catch((err) => {
695
+ error = err;
696
+ return false;
697
+ });
698
+ return { dispatched, response, getError: () => error };
699
+ };
536
700
  const initScriptOps = [];
537
701
  // Pre-resume ordering matters:
538
702
  // - enable domains;
@@ -554,6 +718,13 @@ export class V3Context {
554
718
  headerPreResumeOps.push(queuePreResume("Network.enable"));
555
719
  headerPreResumeOps.push(queuePreResume("Network.setExtraHTTPHeaders", { headers }));
556
720
  }
721
+ const fetchPreResumeOps = [];
722
+ if (this.domainPolicy) {
723
+ this.installDomainPolicyHandler(session);
724
+ fetchPreResumeOps.push(queueFetchEnablePreResume({
725
+ patterns: this.domainPolicy.fetchPatterns,
726
+ }));
727
+ }
557
728
  // Send init scripts only after auto-attach has been queued.
558
729
  if (this.initScripts.length) {
559
730
  for (const source of this.initScripts) {
@@ -572,6 +743,7 @@ export class V3Context {
572
743
  const preResumeDispatched = (await Promise.all([
573
744
  ...corePreResumeOps.map((op) => op.dispatched),
574
745
  ...headerPreResumeOps.map((op) => op.dispatched),
746
+ ...fetchPreResumeOps.map((op) => op.dispatched),
575
747
  ...initScriptOps.map((op) => op.dispatched),
576
748
  piercerPreloadOp.dispatched,
577
749
  ])).every(Boolean);
@@ -581,9 +753,10 @@ export class V3Context {
581
753
  resumeOp.dispatched,
582
754
  resumeOp.response,
583
755
  ]);
584
- const [coreResults, headerResults, initScriptResults, piercerPreRegistered,] = await Promise.all([
756
+ const [coreResults, headerResults, fetchResults, initScriptResults, piercerPreRegistered,] = await Promise.all([
585
757
  Promise.all(corePreResumeOps.map((op) => op.response)),
586
758
  Promise.all(headerPreResumeOps.map((op) => op.response)),
759
+ Promise.all(fetchPreResumeOps.map((op) => op.response)),
587
760
  Promise.all(initScriptOps.map((op) => op.response)),
588
761
  piercerPreloadOp.response,
589
762
  ]);
@@ -616,6 +789,40 @@ export class V3Context {
616
789
  return;
617
790
  }
618
791
  resumed = true;
792
+ if (fetchPreResumeOps.length > 0 && !fetchResults.every(Boolean)) {
793
+ this.uninstallDomainPolicyHandler(session);
794
+ const fetchError = fetchPreResumeOps
795
+ .map((op) => op.getError())
796
+ .find((error) => error !== undefined);
797
+ const fetchErrorMessage = fetchError
798
+ ? fetchError instanceof Error
799
+ ? fetchError.message
800
+ : String(fetchError)
801
+ : "Fetch.enable failed during target attach";
802
+ const policyFailureMessage = "Fetch.enable failed during target attach; closing target because " +
803
+ "Stagehand cannot guarantee domain policy enforcement";
804
+ if (this.pendingCreatedTargetUrl.has(info.targetId)) {
805
+ this.pageCreationFailures.set(info.targetId, new StagehandSetDomainPolicyError([
806
+ `session=${sessionId} target=${info.targetId} error=${policyFailureMessage} cdpError=${fetchErrorMessage}`,
807
+ ]));
808
+ }
809
+ v3Logger({
810
+ category: "ctx",
811
+ message: "Closing target because domain policy could not be guaranteed",
812
+ level: 0,
813
+ auxiliary: {
814
+ targetId: { value: String(info.targetId), type: "string" },
815
+ targetType: { value: String(info.type), type: "string" },
816
+ targetUrl: { value: String(info.url ?? ""), type: "string" },
817
+ sessionId: { value: sessionId, type: "string" },
818
+ cdpError: { value: fetchErrorMessage, type: "string" },
819
+ },
820
+ });
821
+ await this.conn
822
+ .send("Target.closeTarget", { targetId: info.targetId })
823
+ .catch(() => { });
824
+ return;
825
+ }
619
826
  const scriptsInstalled = coreResults.every(Boolean) && initScriptResults.every(Boolean);
620
827
  try {
621
828
  // Best-effort lifecycle events; do not block top-level page registration
@@ -731,6 +938,74 @@ export class V3Context {
731
938
  await resume();
732
939
  }
733
940
  }
941
+ async closePopupIfBlockedByDomainPolicy(info, source) {
942
+ if (!this.domainPolicy || !isTopLevelPage(info))
943
+ return false;
944
+ if (!info.openerId && !info.openerFrameId)
945
+ return false;
946
+ if (this.domainPolicyClosingTargets.has(info.targetId))
947
+ return true;
948
+ const existingClose = this.domainPolicyClosePromises.get(info.targetId);
949
+ if (existingClose) {
950
+ return source === "attached" ? await existingClose : true;
951
+ }
952
+ const decision = getDomainPolicyDecision(info.url ?? "", this.domainPolicy);
953
+ if (decision.action === "continue")
954
+ return false;
955
+ v3Logger({
956
+ category: "network",
957
+ message: "Popup reached a disallowed domain before it could be intercepted; closing it",
958
+ level: 2,
959
+ auxiliary: {
960
+ targetId: { value: String(info.targetId), type: "string" },
961
+ targetUrl: { value: String(info.url ?? ""), type: "string" },
962
+ openerId: { value: String(info.openerId ?? ""), type: "string" },
963
+ openerFrameId: {
964
+ value: String(info.openerFrameId ?? ""),
965
+ type: "string",
966
+ },
967
+ ruleType: { value: decision.reason, type: "string" },
968
+ source: { value: source, type: "string" },
969
+ },
970
+ });
971
+ const closePromise = this.closeTargetAfterDomainPolicyViolation(info, {
972
+ failureMessage: "Failed to close popup after it reached a disallowed domain",
973
+ }).then((closed) => {
974
+ this.domainPolicyClosePromises.delete(info.targetId);
975
+ if (closed) {
976
+ this.domainPolicyClosingTargets.add(info.targetId);
977
+ }
978
+ return closed;
979
+ });
980
+ this.domainPolicyClosePromises.set(info.targetId, closePromise);
981
+ return await closePromise;
982
+ }
983
+ async closeTargetAfterDomainPolicyViolation(info, opts) {
984
+ try {
985
+ await this.conn.send("Target.closeTarget", { targetId: info.targetId });
986
+ return true;
987
+ }
988
+ catch (error) {
989
+ if (isMissingTargetError(error)) {
990
+ return true;
991
+ }
992
+ v3Logger({
993
+ category: "network",
994
+ message: opts.failureMessage,
995
+ level: 0,
996
+ auxiliary: {
997
+ targetId: { value: String(info.targetId), type: "string" },
998
+ targetType: { value: String(info.type), type: "string" },
999
+ targetUrl: { value: String(info.url ?? ""), type: "string" },
1000
+ error: {
1001
+ value: error instanceof Error ? error.message : String(error),
1002
+ type: "string",
1003
+ },
1004
+ },
1005
+ });
1006
+ return false;
1007
+ }
1008
+ }
734
1009
  /**
735
1010
  * Detach handler:
736
1011
  * - Remove child session ownership and prune its subtree.
@@ -751,6 +1026,13 @@ export class V3Context {
751
1026
  this.pendingOopifByMainFrame.delete(fid);
752
1027
  }
753
1028
  this._targetSessionListeners.delete(sessionId);
1029
+ const session = this.conn.getSession(sessionId);
1030
+ if (session) {
1031
+ this.uninstallDomainPolicyHandler(session);
1032
+ }
1033
+ else {
1034
+ this._domainPolicySessionListeners.delete(sessionId);
1035
+ }
754
1036
  this._sessionInit.delete(sessionId);
755
1037
  this._piercerInstalled.delete(sessionId);
756
1038
  }
@@ -761,6 +1043,7 @@ export class V3Context {
761
1043
  const page = this.pagesByTarget.get(targetId);
762
1044
  if (!page)
763
1045
  return;
1046
+ this.pageCreationFailures.delete(targetId);
764
1047
  const mainId = page.mainFrameId();
765
1048
  this.mainFrameToTarget.delete(mainId);
766
1049
  this.frameOwnerPage.delete(mainId);