@ricsam/isolate 0.1.12 → 0.1.14

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 (86) hide show
  1. package/README.md +15 -0
  2. package/dist/cjs/bridge/legacy-adapters.cjs +3 -2
  3. package/dist/cjs/bridge/legacy-adapters.cjs.map +3 -3
  4. package/dist/cjs/bridge/runtime-bindings.cjs +9 -7
  5. package/dist/cjs/bridge/runtime-bindings.cjs.map +3 -3
  6. package/dist/cjs/bridge/sandbox-isolate.cjs +58 -2
  7. package/dist/cjs/bridge/sandbox-isolate.cjs.map +3 -3
  8. package/dist/cjs/host/create-isolate-host.cjs +7 -2
  9. package/dist/cjs/host/create-isolate-host.cjs.map +3 -3
  10. package/dist/cjs/host/nested-host-controller.cjs +36 -4
  11. package/dist/cjs/host/nested-host-controller.cjs.map +3 -3
  12. package/dist/cjs/internal/client/connection.cjs +12 -10
  13. package/dist/cjs/internal/client/connection.cjs.map +3 -3
  14. package/dist/cjs/internal/console/index.cjs +18 -14
  15. package/dist/cjs/internal/console/index.cjs.map +3 -3
  16. package/dist/cjs/internal/daemon/connection.cjs +11 -12
  17. package/dist/cjs/internal/daemon/connection.cjs.map +3 -3
  18. package/dist/cjs/internal/event-callback.cjs +70 -0
  19. package/dist/cjs/internal/event-callback.cjs.map +10 -0
  20. package/dist/cjs/internal/playwright/handler.cjs +3 -4
  21. package/dist/cjs/internal/playwright/handler.cjs.map +3 -3
  22. package/dist/cjs/internal/playwright/index.cjs +58 -64
  23. package/dist/cjs/internal/playwright/index.cjs.map +3 -3
  24. package/dist/cjs/internal/protocol/types.cjs.map +2 -2
  25. package/dist/cjs/internal/runtime/index.cjs +8 -13
  26. package/dist/cjs/internal/runtime/index.cjs.map +3 -3
  27. package/dist/cjs/internal/test-environment/index.cjs +3 -2
  28. package/dist/cjs/internal/test-environment/index.cjs.map +3 -3
  29. package/dist/cjs/internal/typecheck/isolate-types.cjs +50 -1
  30. package/dist/cjs/internal/typecheck/isolate-types.cjs.map +3 -3
  31. package/dist/cjs/package.json +1 -1
  32. package/dist/cjs/playwright.cjs.map +2 -2
  33. package/dist/cjs/runtime/namespaced-runtime.cjs +4 -1
  34. package/dist/cjs/runtime/namespaced-runtime.cjs.map +3 -3
  35. package/dist/cjs/runtime/test-event-subscriptions.cjs +73 -0
  36. package/dist/cjs/runtime/test-event-subscriptions.cjs.map +10 -0
  37. package/dist/cjs/runtime/test-runtime.cjs +26 -3
  38. package/dist/cjs/runtime/test-runtime.cjs.map +3 -3
  39. package/dist/mjs/bridge/legacy-adapters.mjs +3 -2
  40. package/dist/mjs/bridge/legacy-adapters.mjs.map +3 -3
  41. package/dist/mjs/bridge/runtime-bindings.mjs +9 -7
  42. package/dist/mjs/bridge/runtime-bindings.mjs.map +3 -3
  43. package/dist/mjs/bridge/sandbox-isolate.mjs +58 -2
  44. package/dist/mjs/bridge/sandbox-isolate.mjs.map +3 -3
  45. package/dist/mjs/host/create-isolate-host.mjs +7 -2
  46. package/dist/mjs/host/create-isolate-host.mjs.map +3 -3
  47. package/dist/mjs/host/nested-host-controller.mjs +36 -4
  48. package/dist/mjs/host/nested-host-controller.mjs.map +3 -3
  49. package/dist/mjs/internal/client/connection.mjs +12 -10
  50. package/dist/mjs/internal/client/connection.mjs.map +3 -3
  51. package/dist/mjs/internal/console/index.mjs +18 -14
  52. package/dist/mjs/internal/console/index.mjs.map +3 -3
  53. package/dist/mjs/internal/daemon/connection.mjs +11 -12
  54. package/dist/mjs/internal/daemon/connection.mjs.map +3 -3
  55. package/dist/mjs/internal/event-callback.mjs +30 -0
  56. package/dist/mjs/internal/event-callback.mjs.map +10 -0
  57. package/dist/mjs/internal/playwright/handler.mjs +3 -4
  58. package/dist/mjs/internal/playwright/handler.mjs.map +3 -3
  59. package/dist/mjs/internal/playwright/index.mjs +58 -64
  60. package/dist/mjs/internal/playwright/index.mjs.map +3 -3
  61. package/dist/mjs/internal/protocol/types.mjs.map +2 -2
  62. package/dist/mjs/internal/runtime/index.mjs +8 -13
  63. package/dist/mjs/internal/runtime/index.mjs.map +3 -3
  64. package/dist/mjs/internal/test-environment/index.mjs +3 -2
  65. package/dist/mjs/internal/test-environment/index.mjs.map +3 -3
  66. package/dist/mjs/internal/typecheck/isolate-types.mjs +50 -1
  67. package/dist/mjs/internal/typecheck/isolate-types.mjs.map +3 -3
  68. package/dist/mjs/package.json +1 -1
  69. package/dist/mjs/playwright.mjs.map +2 -2
  70. package/dist/mjs/runtime/namespaced-runtime.mjs +4 -1
  71. package/dist/mjs/runtime/namespaced-runtime.mjs.map +3 -3
  72. package/dist/mjs/runtime/test-event-subscriptions.mjs +33 -0
  73. package/dist/mjs/runtime/test-event-subscriptions.mjs.map +10 -0
  74. package/dist/mjs/runtime/test-runtime.mjs +26 -3
  75. package/dist/mjs/runtime/test-runtime.mjs.map +3 -3
  76. package/dist/types/internal/console/index.d.ts +2 -1
  77. package/dist/types/internal/event-callback.d.ts +1 -0
  78. package/dist/types/internal/protocol/types.d.ts +4 -3
  79. package/dist/types/internal/runtime/index.d.ts +0 -6
  80. package/dist/types/internal/test-environment/index.d.ts +1 -1
  81. package/dist/types/internal/typecheck/isolate-types.d.ts +2 -2
  82. package/dist/types/playwright.d.ts +1 -0
  83. package/dist/types/runtime/namespaced-runtime.d.ts +3 -1
  84. package/dist/types/runtime/test-event-subscriptions.d.ts +12 -0
  85. package/dist/types/types.d.ts +12 -0
  86. package/package.json +1 -1
@@ -1,7 +1,11 @@
1
1
  // src/internal/console/index.ts
2
2
  import ivm from "@ricsam/isolated-vm";
3
+ import { invokeBestEffortEventHandler } from "../event-callback.mjs";
3
4
  async function setupConsole(context, options) {
4
5
  const opts = options ?? {};
6
+ const emitEntry = (entry) => {
7
+ invokeBestEffortEventHandler("console.onEntry", opts.onEntry, entry);
8
+ };
5
9
  const timers = new Map;
6
10
  const counters = new Map;
7
11
  let groupDepth = 0;
@@ -9,7 +13,7 @@ async function setupConsole(context, options) {
9
13
  const logLevels = ["log", "warn", "error", "debug", "info"];
10
14
  for (const level of logLevels) {
11
15
  global.setSync(`__console_${level}`, new ivm.Callback((stdout) => {
12
- opts.onEntry?.({
16
+ emitEntry({
13
17
  type: "output",
14
18
  level,
15
19
  stdout,
@@ -18,21 +22,21 @@ async function setupConsole(context, options) {
18
22
  }));
19
23
  }
20
24
  global.setSync("__console_dir", new ivm.Callback((stdout) => {
21
- opts.onEntry?.({
25
+ emitEntry({
22
26
  type: "dir",
23
27
  stdout,
24
28
  groupDepth
25
29
  });
26
30
  }));
27
31
  global.setSync("__console_table", new ivm.Callback((stdout) => {
28
- opts.onEntry?.({
32
+ emitEntry({
29
33
  type: "table",
30
34
  stdout,
31
35
  groupDepth
32
36
  });
33
37
  }));
34
38
  global.setSync("__console_trace", new ivm.Callback((stdout, stack) => {
35
- opts.onEntry?.({
39
+ emitEntry({
36
40
  type: "trace",
37
41
  stdout,
38
42
  stack,
@@ -49,7 +53,7 @@ async function setupConsole(context, options) {
49
53
  if (start !== undefined) {
50
54
  const duration = performance.now() - start;
51
55
  timers.delete(l);
52
- opts.onEntry?.({
56
+ emitEntry({
53
57
  type: "time",
54
58
  label: l,
55
59
  duration,
@@ -62,7 +66,7 @@ async function setupConsole(context, options) {
62
66
  const start = timers.get(l);
63
67
  if (start !== undefined) {
64
68
  const actualDuration = performance.now() - start;
65
- opts.onEntry?.({
69
+ emitEntry({
66
70
  type: "timeLog",
67
71
  label: l,
68
72
  duration: actualDuration,
@@ -75,7 +79,7 @@ async function setupConsole(context, options) {
75
79
  const l = label ?? "default";
76
80
  const count = (counters.get(l) ?? 0) + 1;
77
81
  counters.set(l, count);
78
- opts.onEntry?.({
82
+ emitEntry({
79
83
  type: "count",
80
84
  label: l,
81
85
  count,
@@ -85,7 +89,7 @@ async function setupConsole(context, options) {
85
89
  global.setSync("__console_countReset", new ivm.Callback((label) => {
86
90
  const l = label ?? "default";
87
91
  counters.delete(l);
88
- opts.onEntry?.({
92
+ emitEntry({
89
93
  type: "countReset",
90
94
  label: l,
91
95
  groupDepth
@@ -93,7 +97,7 @@ async function setupConsole(context, options) {
93
97
  }));
94
98
  global.setSync("__console_group", new ivm.Callback((label) => {
95
99
  const l = label ?? "default";
96
- opts.onEntry?.({
100
+ emitEntry({
97
101
  type: "group",
98
102
  label: l,
99
103
  collapsed: false,
@@ -103,7 +107,7 @@ async function setupConsole(context, options) {
103
107
  }));
104
108
  global.setSync("__console_groupCollapsed", new ivm.Callback((label) => {
105
109
  const l = label ?? "default";
106
- opts.onEntry?.({
110
+ emitEntry({
107
111
  type: "group",
108
112
  label: l,
109
113
  collapsed: true,
@@ -115,16 +119,16 @@ async function setupConsole(context, options) {
115
119
  if (groupDepth > 0) {
116
120
  groupDepth--;
117
121
  }
118
- opts.onEntry?.({
122
+ emitEntry({
119
123
  type: "groupEnd",
120
124
  groupDepth
121
125
  });
122
126
  }));
123
127
  global.setSync("__console_clear", new ivm.Callback(() => {
124
- opts.onEntry?.({ type: "clear" });
128
+ emitEntry({ type: "clear" });
125
129
  }));
126
130
  global.setSync("__console_assert", new ivm.Callback((stdout) => {
127
- opts.onEntry?.({
131
+ emitEntry({
128
132
  type: "assert",
129
133
  stdout,
130
134
  groupDepth
@@ -439,4 +443,4 @@ export {
439
443
  setupConsole
440
444
  };
441
445
 
442
- //# debugId=ACA86F3A29BC75EB64756E2164756E21
446
+ //# debugId=AA2C38BED96F591564756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/internal/console/index.ts"],
4
4
  "sourcesContent": [
5
- "import ivm from \"@ricsam/isolated-vm\";\n\n/**\n * Console entry types for structured console output.\n * Each entry type captures the specific data needed to render like DevTools.\n * Output is pre-formatted as stdout strings (like Node.js console) inside the sandbox.\n */\nexport type ConsoleEntry =\n | {\n type: \"output\";\n level: \"log\" | \"warn\" | \"error\" | \"info\" | \"debug\";\n stdout: string;\n groupDepth: number;\n }\n | {\n /** Browser console output (from Playwright page, not sandbox) */\n type: \"browserOutput\";\n level: string;\n stdout: string;\n location?: {\n url?: string;\n lineNumber?: number;\n columnNumber?: number;\n };\n timestamp: number;\n }\n | { type: \"dir\"; stdout: string; groupDepth: number }\n | { type: \"table\"; stdout: string; groupDepth: number }\n | { type: \"time\"; label: string; duration: number; groupDepth: number }\n | {\n type: \"timeLog\";\n label: string;\n duration: number;\n stdout: string;\n groupDepth: number;\n }\n | { type: \"count\"; label: string; count: number; groupDepth: number }\n | { type: \"countReset\"; label: string; groupDepth: number }\n | { type: \"assert\"; stdout: string; groupDepth: number }\n | {\n type: \"group\";\n label: string;\n collapsed: boolean;\n groupDepth: number;\n }\n | { type: \"groupEnd\"; groupDepth: number }\n | { type: \"clear\" }\n | { type: \"trace\"; stdout: string; stack: string; groupDepth: number };\n\n/**\n * Console options with a single structured callback.\n */\nexport interface ConsoleOptions {\n /**\n * Callback invoked for each console operation.\n * Receives a structured entry with all data needed to render the output.\n */\n onEntry?: (entry: ConsoleEntry) => void;\n}\n\n/**\n * Console handle for accessing internal state.\n */\nexport interface ConsoleHandle {\n dispose(): void;\n reset(): void;\n getTimers(): Map<string, number>;\n getCounters(): Map<string, number>;\n getGroupDepth(): number;\n}\n\n\n/**\n * Setup console API in an isolated-vm context\n *\n * Injects console.log, console.warn, console.error, console.info, console.debug,\n * console.trace, console.dir, console.table, console.time, console.timeEnd,\n * console.timeLog, console.count, console.countReset, console.group,\n * console.groupCollapsed, console.groupEnd, console.clear, console.assert\n *\n * @example\n * const handle = await setupConsole(context, {\n * onEntry: (entry) => {\n * if (entry.type === 'output') {\n * console.log(`[${entry.level}]`, ...entry.args);\n * }\n * }\n * });\n */\nexport async function setupConsole(\n context: ivm.Context,\n options?: ConsoleOptions\n): Promise<ConsoleHandle> {\n const opts = options ?? {};\n\n // State management\n const timers = new Map<string, number>();\n const counters = new Map<string, number>();\n let groupDepth = 0;\n\n const global = context.global;\n\n // Log-level methods (output type)\n const logLevels = [\"log\", \"warn\", \"error\", \"debug\", \"info\"] as const;\n\n for (const level of logLevels) {\n global.setSync(\n `__console_${level}`,\n new ivm.Callback((stdout: string) => {\n opts.onEntry?.({\n type: \"output\",\n level,\n stdout,\n groupDepth,\n });\n })\n );\n }\n\n // dir method\n global.setSync(\n \"__console_dir\",\n new ivm.Callback((stdout: string) => {\n opts.onEntry?.({\n type: \"dir\",\n stdout,\n groupDepth,\n });\n })\n );\n\n // table method\n global.setSync(\n \"__console_table\",\n new ivm.Callback((stdout: string) => {\n opts.onEntry?.({\n type: \"table\",\n stdout,\n groupDepth,\n });\n })\n );\n\n // trace method (includes stack)\n global.setSync(\n \"__console_trace\",\n new ivm.Callback((stdout: string, stack: string) => {\n opts.onEntry?.({\n type: \"trace\",\n stdout,\n stack,\n groupDepth,\n });\n })\n );\n\n // Timing methods\n global.setSync(\n \"__console_time\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n timers.set(l, performance.now());\n })\n );\n\n global.setSync(\n \"__console_timeEnd\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n const start = timers.get(l);\n if (start !== undefined) {\n const duration = performance.now() - start;\n timers.delete(l);\n opts.onEntry?.({\n type: \"time\",\n label: l,\n duration,\n groupDepth,\n });\n }\n })\n );\n\n global.setSync(\n \"__console_timeLog\",\n new ivm.Callback((label: string, duration: number, stdout: string) => {\n const l = label ?? \"default\";\n const start = timers.get(l);\n if (start !== undefined) {\n const actualDuration = performance.now() - start;\n opts.onEntry?.({\n type: \"timeLog\",\n label: l,\n duration: actualDuration,\n stdout,\n groupDepth,\n });\n }\n })\n );\n\n // Counting methods\n global.setSync(\n \"__console_count\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n const count = (counters.get(l) ?? 0) + 1;\n counters.set(l, count);\n opts.onEntry?.({\n type: \"count\",\n label: l,\n count,\n groupDepth,\n });\n })\n );\n\n global.setSync(\n \"__console_countReset\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n counters.delete(l);\n opts.onEntry?.({\n type: \"countReset\",\n label: l,\n groupDepth,\n });\n })\n );\n\n // Grouping methods\n global.setSync(\n \"__console_group\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n opts.onEntry?.({\n type: \"group\",\n label: l,\n collapsed: false,\n groupDepth,\n });\n groupDepth++;\n })\n );\n\n global.setSync(\n \"__console_groupCollapsed\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n opts.onEntry?.({\n type: \"group\",\n label: l,\n collapsed: true,\n groupDepth,\n });\n groupDepth++;\n })\n );\n\n global.setSync(\n \"__console_groupEnd\",\n new ivm.Callback(() => {\n if (groupDepth > 0) {\n groupDepth--;\n }\n opts.onEntry?.({\n type: \"groupEnd\",\n groupDepth,\n });\n })\n );\n\n // Other methods\n global.setSync(\n \"__console_clear\",\n new ivm.Callback(() => {\n opts.onEntry?.({ type: \"clear\" });\n })\n );\n\n global.setSync(\n \"__console_assert\",\n new ivm.Callback((stdout: string) => {\n opts.onEntry?.({\n type: \"assert\",\n stdout,\n groupDepth,\n });\n })\n );\n\n // Inject console object with Node.js-style formatting\n context.evalSync(`\n // Format a single value for console output (Node.js style)\n function __formatForConsole(value, options = {}) {\n const { depth = 2, currentDepth = 0, seen = new WeakSet(), inObject = false } = options;\n\n // Handle null/undefined\n if (value === null) return 'null';\n if (value === undefined) return 'undefined';\n\n // Handle primitives\n const type = typeof value;\n if (type === 'string') {\n // Strings: quoted when inside objects/arrays, raw when top-level console.log arg\n return inObject ? \"'\" + value.replace(/'/g, \"\\\\\\\\'\") + \"'\" : value;\n }\n if (type === 'number' || type === 'boolean') {\n return String(value);\n }\n if (type === 'bigint') {\n return value.toString() + 'n';\n }\n if (type === 'symbol') {\n return value.toString();\n }\n if (type === 'function') {\n const name = value.name || '(anonymous)';\n return '[Function: ' + name + ']';\n }\n\n // Handle objects\n if (type === 'object') {\n // Handle circular references BEFORE depth check (Node.js behavior)\n if (seen.has(value)) {\n return '[Circular]';\n }\n seen.add(value);\n\n // Check depth limit\n if (currentDepth >= depth) {\n if (Array.isArray(value)) return '[Array]';\n return '[Object]';\n }\n\n const nextOptions = { depth, currentDepth: currentDepth + 1, seen, inObject: true };\n\n // Handle Error objects\n if (value instanceof Error) {\n let result = value.name + ': ' + value.message;\n if (value.stack) {\n // Get stack lines after the first line (which is the error message)\n const stackLines = value.stack.split('\\\\n').slice(1);\n if (stackLines.length > 0) {\n result += '\\\\n' + stackLines.join('\\\\n');\n }\n }\n return result;\n }\n\n // Handle Response objects\n if (typeof Response !== 'undefined' && value instanceof Response) {\n return 'Response { status: ' + value.status + ', statusText: ' + __formatForConsole(value.statusText, nextOptions) + ', url: ' + __formatForConsole(value.url, nextOptions) + ' }';\n }\n\n // Handle Request objects\n if (typeof Request !== 'undefined' && value instanceof Request) {\n return 'Request { method: ' + __formatForConsole(value.method, nextOptions) + ', url: ' + __formatForConsole(value.url, nextOptions) + ' }';\n }\n\n // Handle Headers objects\n if (typeof Headers !== 'undefined' && value instanceof Headers) {\n const entries = [];\n value.forEach((v, k) => {\n entries.push(__formatForConsole(k, nextOptions) + ' => ' + __formatForConsole(v, nextOptions));\n });\n return 'Headers { ' + entries.join(', ') + ' }';\n }\n\n // Handle URLSearchParams objects\n if (typeof URLSearchParams !== 'undefined' && value instanceof URLSearchParams) {\n const entries = [];\n for (const [k, v] of value) {\n entries.push(__formatForConsole(k, nextOptions) + ' => ' + __formatForConsole(v, nextOptions));\n }\n return entries.length === 0\n ? 'URLSearchParams {}'\n : 'URLSearchParams { ' + entries.join(', ') + ' }';\n }\n\n // Handle URL objects\n if (typeof URL !== 'undefined' && value instanceof URL) {\n const entries = [\n 'href: ' + __formatForConsole(value.href, nextOptions),\n 'origin: ' + __formatForConsole(value.origin, nextOptions),\n 'protocol: ' + __formatForConsole(value.protocol, nextOptions),\n 'username: ' + __formatForConsole(value.username, nextOptions),\n 'password: ' + __formatForConsole(value.password, nextOptions),\n 'host: ' + __formatForConsole(value.host, nextOptions),\n 'hostname: ' + __formatForConsole(value.hostname, nextOptions),\n 'port: ' + __formatForConsole(value.port, nextOptions),\n 'pathname: ' + __formatForConsole(value.pathname, nextOptions),\n 'search: ' + __formatForConsole(value.search, nextOptions),\n 'searchParams: ' + __formatForConsole(value.searchParams, nextOptions),\n 'hash: ' + __formatForConsole(value.hash, nextOptions),\n ];\n return 'URL { ' + entries.join(', ') + ' }';\n }\n\n // Handle Date objects\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n // Handle RegExp\n if (value instanceof RegExp) {\n return value.toString();\n }\n\n // Handle Map\n if (value instanceof Map) {\n const entries = [];\n value.forEach((v, k) => {\n entries.push(__formatForConsole(k, nextOptions) + ' => ' + __formatForConsole(v, nextOptions));\n });\n return 'Map(' + value.size + ') { ' + entries.join(', ') + ' }';\n }\n\n // Handle Set\n if (value instanceof Set) {\n const entries = [];\n value.forEach((v) => {\n entries.push(__formatForConsole(v, nextOptions));\n });\n return 'Set(' + value.size + ') { ' + entries.join(', ') + ' }';\n }\n\n // Handle ArrayBuffer and TypedArrays\n if (value instanceof ArrayBuffer) {\n return 'ArrayBuffer { byteLength: ' + value.byteLength + ' }';\n }\n if (ArrayBuffer.isView(value) && !(value instanceof DataView)) {\n const typedArray = value;\n const name = typedArray.constructor.name;\n const length = typedArray.length;\n if (length <= 10) {\n const items = Array.from(typedArray).map(v => __formatForConsole(v, nextOptions));\n return name + '(' + length + ') [ ' + items.join(', ') + ' ]';\n }\n return name + '(' + length + ') [ ... ]';\n }\n\n // Handle Promise\n if (value instanceof Promise) {\n return 'Promise { <pending> }';\n }\n\n // Handle arrays\n if (Array.isArray(value)) {\n if (value.length === 0) return '[]';\n const items = value.map(item => __formatForConsole(item, nextOptions));\n return '[ ' + items.join(', ') + ' ]';\n }\n\n // Handle plain objects\n const keys = Object.keys(value);\n if (keys.length === 0) return '{}';\n const entries = keys.map(key => {\n const formattedKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? key : __formatForConsole(key, nextOptions);\n return formattedKey + ': ' + __formatForConsole(value[key], nextOptions);\n });\n return '{ ' + entries.join(', ') + ' }';\n }\n\n return String(value);\n }\n\n // Format multiple args with space separation (like console.log)\n function __formatArgs(args) {\n return args.map((arg, i) => __formatForConsole(arg, { inObject: false })).join(' ');\n }\n\n // Format data for console.table - creates ASCII table\n function __formatTable(data, columns) {\n if (data === null || data === undefined) {\n return __formatForConsole(data);\n }\n\n // Convert to array of objects\n let rows = [];\n let headers = new Set();\n\n if (Array.isArray(data)) {\n rows = data.map((item, index) => {\n if (item !== null && typeof item === 'object' && !Array.isArray(item)) {\n Object.keys(item).forEach(k => headers.add(k));\n return { __index: index, ...item };\n }\n return { __index: index, Values: item };\n });\n headers.add('Values');\n } else if (typeof data === 'object') {\n Object.keys(data).forEach(key => {\n const item = data[key];\n if (item !== null && typeof item === 'object' && !Array.isArray(item)) {\n Object.keys(item).forEach(k => headers.add(k));\n rows.push({ __index: key, ...item });\n } else {\n rows.push({ __index: key, Values: item });\n headers.add('Values');\n }\n });\n } else {\n return __formatForConsole(data);\n }\n\n // Filter headers by columns if provided\n let headerList = ['(index)', ...headers];\n headerList = headerList.filter(h => h !== '__index');\n if (columns && Array.isArray(columns)) {\n headerList = ['(index)', ...columns.filter(c => headers.has(c))];\n }\n\n // Calculate column widths\n const colWidths = {};\n headerList.forEach(h => {\n colWidths[h] = h === '(index)' ? 7 : h.length;\n });\n rows.forEach(row => {\n headerList.forEach(h => {\n const key = h === '(index)' ? '__index' : h;\n const val = row[key];\n const formatted = val !== undefined ? __formatForConsole(val, { depth: 1, inObject: true }) : '';\n colWidths[h] = Math.max(colWidths[h], formatted.length);\n });\n });\n\n // Build table\n const sep = '+' + headerList.map(h => '-'.repeat(colWidths[h] + 2)).join('+') + '+';\n const headerRow = '|' + headerList.map(h => ' ' + h.padEnd(colWidths[h]) + ' ').join('|') + '|';\n\n const dataRows = rows.map(row => {\n return '|' + headerList.map(h => {\n const key = h === '(index)' ? '__index' : h;\n const val = row[key];\n const formatted = val !== undefined ? __formatForConsole(val, { depth: 1, inObject: true }) : '';\n return ' ' + formatted.padEnd(colWidths[h]) + ' ';\n }).join('|') + '|';\n });\n\n return [sep, headerRow, sep, ...dataRows, sep].join('\\\\n');\n }\n\n globalThis.console = {\n log: (...args) => __console_log(__formatArgs(args)),\n warn: (...args) => __console_warn(__formatArgs(args)),\n error: (...args) => __console_error(__formatArgs(args)),\n debug: (...args) => __console_debug(__formatArgs(args)),\n info: (...args) => __console_info(__formatArgs(args)),\n trace: (...args) => {\n const err = new Error();\n const stack = err.stack || '';\n // Remove the first two lines (Error and the trace call itself)\n const stackLines = stack.split('\\\\n').slice(2).join('\\\\n');\n __console_trace(__formatArgs(args), 'Trace' + (args.length > 0 ? ': ' + __formatArgs(args) : '') + '\\\\n' + stackLines);\n },\n dir: (value, options) => __console_dir(__formatForConsole(value, { depth: options?.depth ?? 2, inObject: true })),\n table: (data, columns) => __console_table(__formatTable(data, columns)),\n time: __console_time,\n timeEnd: __console_timeEnd,\n timeLog: (label, ...args) => __console_timeLog(label ?? 'default', 0, __formatArgs(args)),\n count: __console_count,\n countReset: __console_countReset,\n group: __console_group,\n groupCollapsed: __console_groupCollapsed,\n groupEnd: __console_groupEnd,\n clear: __console_clear,\n assert: (condition, ...args) => {\n if (!condition) {\n const msg = args.length > 0 ? __formatArgs(args) : 'console.assert';\n __console_assert('Assertion failed: ' + msg);\n }\n },\n };\n `);\n\n return {\n dispose() {\n timers.clear();\n counters.clear();\n groupDepth = 0;\n },\n reset() {\n timers.clear();\n counters.clear();\n groupDepth = 0;\n },\n getTimers() {\n return new Map(timers);\n },\n getCounters() {\n return new Map(counters);\n },\n getGroupDepth() {\n return groupDepth;\n },\n };\n}\n"
5
+ "import ivm from \"@ricsam/isolated-vm\";\nimport { invokeBestEffortEventHandler } from \"../event-callback.mjs\";\n\n/**\n * Console entry types for structured console output.\n * Each entry type captures the specific data needed to render like DevTools.\n * Output is pre-formatted as stdout strings (like Node.js console) inside the sandbox.\n */\nexport type ConsoleEntry =\n | {\n type: \"output\";\n level: \"log\" | \"warn\" | \"error\" | \"info\" | \"debug\";\n stdout: string;\n groupDepth: number;\n }\n | {\n /** Browser console output (from Playwright page, not sandbox) */\n type: \"browserOutput\";\n level: string;\n stdout: string;\n location?: {\n url?: string;\n lineNumber?: number;\n columnNumber?: number;\n };\n timestamp: number;\n }\n | { type: \"dir\"; stdout: string; groupDepth: number }\n | { type: \"table\"; stdout: string; groupDepth: number }\n | { type: \"time\"; label: string; duration: number; groupDepth: number }\n | {\n type: \"timeLog\";\n label: string;\n duration: number;\n stdout: string;\n groupDepth: number;\n }\n | { type: \"count\"; label: string; count: number; groupDepth: number }\n | { type: \"countReset\"; label: string; groupDepth: number }\n | { type: \"assert\"; stdout: string; groupDepth: number }\n | {\n type: \"group\";\n label: string;\n collapsed: boolean;\n groupDepth: number;\n }\n | { type: \"groupEnd\"; groupDepth: number }\n | { type: \"clear\" }\n | { type: \"trace\"; stdout: string; stack: string; groupDepth: number };\n\n/**\n * Console options with a single structured callback.\n */\nexport interface ConsoleOptions {\n /**\n * Sync-only, best-effort callback invoked for each console operation.\n * Receives a structured entry with all data needed to render the output.\n * Returned promises are ignored.\n */\n onEntry?: (entry: ConsoleEntry) => void;\n}\n\n/**\n * Console handle for accessing internal state.\n */\nexport interface ConsoleHandle {\n dispose(): void;\n reset(): void;\n getTimers(): Map<string, number>;\n getCounters(): Map<string, number>;\n getGroupDepth(): number;\n}\n\n\n/**\n * Setup console API in an isolated-vm context\n *\n * Injects console.log, console.warn, console.error, console.info, console.debug,\n * console.trace, console.dir, console.table, console.time, console.timeEnd,\n * console.timeLog, console.count, console.countReset, console.group,\n * console.groupCollapsed, console.groupEnd, console.clear, console.assert\n *\n * @example\n * const handle = await setupConsole(context, {\n * onEntry: (entry) => {\n * if (entry.type === 'output') {\n * console.log(`[${entry.level}]`, ...entry.args);\n * }\n * }\n * });\n */\nexport async function setupConsole(\n context: ivm.Context,\n options?: ConsoleOptions\n): Promise<ConsoleHandle> {\n const opts = options ?? {};\n const emitEntry = (entry: ConsoleEntry): void => {\n invokeBestEffortEventHandler(\"console.onEntry\", opts.onEntry, entry);\n };\n\n // State management\n const timers = new Map<string, number>();\n const counters = new Map<string, number>();\n let groupDepth = 0;\n\n const global = context.global;\n\n // Log-level methods (output type)\n const logLevels = [\"log\", \"warn\", \"error\", \"debug\", \"info\"] as const;\n\n for (const level of logLevels) {\n global.setSync(\n `__console_${level}`,\n new ivm.Callback((stdout: string) => {\n emitEntry({\n type: \"output\",\n level,\n stdout,\n groupDepth,\n });\n })\n );\n }\n\n // dir method\n global.setSync(\n \"__console_dir\",\n new ivm.Callback((stdout: string) => {\n emitEntry({\n type: \"dir\",\n stdout,\n groupDepth,\n });\n })\n );\n\n // table method\n global.setSync(\n \"__console_table\",\n new ivm.Callback((stdout: string) => {\n emitEntry({\n type: \"table\",\n stdout,\n groupDepth,\n });\n })\n );\n\n // trace method (includes stack)\n global.setSync(\n \"__console_trace\",\n new ivm.Callback((stdout: string, stack: string) => {\n emitEntry({\n type: \"trace\",\n stdout,\n stack,\n groupDepth,\n });\n })\n );\n\n // Timing methods\n global.setSync(\n \"__console_time\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n timers.set(l, performance.now());\n })\n );\n\n global.setSync(\n \"__console_timeEnd\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n const start = timers.get(l);\n if (start !== undefined) {\n const duration = performance.now() - start;\n timers.delete(l);\n emitEntry({\n type: \"time\",\n label: l,\n duration,\n groupDepth,\n });\n }\n })\n );\n\n global.setSync(\n \"__console_timeLog\",\n new ivm.Callback((label: string, duration: number, stdout: string) => {\n const l = label ?? \"default\";\n const start = timers.get(l);\n if (start !== undefined) {\n const actualDuration = performance.now() - start;\n emitEntry({\n type: \"timeLog\",\n label: l,\n duration: actualDuration,\n stdout,\n groupDepth,\n });\n }\n })\n );\n\n // Counting methods\n global.setSync(\n \"__console_count\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n const count = (counters.get(l) ?? 0) + 1;\n counters.set(l, count);\n emitEntry({\n type: \"count\",\n label: l,\n count,\n groupDepth,\n });\n })\n );\n\n global.setSync(\n \"__console_countReset\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n counters.delete(l);\n emitEntry({\n type: \"countReset\",\n label: l,\n groupDepth,\n });\n })\n );\n\n // Grouping methods\n global.setSync(\n \"__console_group\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n emitEntry({\n type: \"group\",\n label: l,\n collapsed: false,\n groupDepth,\n });\n groupDepth++;\n })\n );\n\n global.setSync(\n \"__console_groupCollapsed\",\n new ivm.Callback((label?: string) => {\n const l = label ?? \"default\";\n emitEntry({\n type: \"group\",\n label: l,\n collapsed: true,\n groupDepth,\n });\n groupDepth++;\n })\n );\n\n global.setSync(\n \"__console_groupEnd\",\n new ivm.Callback(() => {\n if (groupDepth > 0) {\n groupDepth--;\n }\n emitEntry({\n type: \"groupEnd\",\n groupDepth,\n });\n })\n );\n\n // Other methods\n global.setSync(\n \"__console_clear\",\n new ivm.Callback(() => {\n emitEntry({ type: \"clear\" });\n })\n );\n\n global.setSync(\n \"__console_assert\",\n new ivm.Callback((stdout: string) => {\n emitEntry({\n type: \"assert\",\n stdout,\n groupDepth,\n });\n })\n );\n\n // Inject console object with Node.js-style formatting\n context.evalSync(`\n // Format a single value for console output (Node.js style)\n function __formatForConsole(value, options = {}) {\n const { depth = 2, currentDepth = 0, seen = new WeakSet(), inObject = false } = options;\n\n // Handle null/undefined\n if (value === null) return 'null';\n if (value === undefined) return 'undefined';\n\n // Handle primitives\n const type = typeof value;\n if (type === 'string') {\n // Strings: quoted when inside objects/arrays, raw when top-level console.log arg\n return inObject ? \"'\" + value.replace(/'/g, \"\\\\\\\\'\") + \"'\" : value;\n }\n if (type === 'number' || type === 'boolean') {\n return String(value);\n }\n if (type === 'bigint') {\n return value.toString() + 'n';\n }\n if (type === 'symbol') {\n return value.toString();\n }\n if (type === 'function') {\n const name = value.name || '(anonymous)';\n return '[Function: ' + name + ']';\n }\n\n // Handle objects\n if (type === 'object') {\n // Handle circular references BEFORE depth check (Node.js behavior)\n if (seen.has(value)) {\n return '[Circular]';\n }\n seen.add(value);\n\n // Check depth limit\n if (currentDepth >= depth) {\n if (Array.isArray(value)) return '[Array]';\n return '[Object]';\n }\n\n const nextOptions = { depth, currentDepth: currentDepth + 1, seen, inObject: true };\n\n // Handle Error objects\n if (value instanceof Error) {\n let result = value.name + ': ' + value.message;\n if (value.stack) {\n // Get stack lines after the first line (which is the error message)\n const stackLines = value.stack.split('\\\\n').slice(1);\n if (stackLines.length > 0) {\n result += '\\\\n' + stackLines.join('\\\\n');\n }\n }\n return result;\n }\n\n // Handle Response objects\n if (typeof Response !== 'undefined' && value instanceof Response) {\n return 'Response { status: ' + value.status + ', statusText: ' + __formatForConsole(value.statusText, nextOptions) + ', url: ' + __formatForConsole(value.url, nextOptions) + ' }';\n }\n\n // Handle Request objects\n if (typeof Request !== 'undefined' && value instanceof Request) {\n return 'Request { method: ' + __formatForConsole(value.method, nextOptions) + ', url: ' + __formatForConsole(value.url, nextOptions) + ' }';\n }\n\n // Handle Headers objects\n if (typeof Headers !== 'undefined' && value instanceof Headers) {\n const entries = [];\n value.forEach((v, k) => {\n entries.push(__formatForConsole(k, nextOptions) + ' => ' + __formatForConsole(v, nextOptions));\n });\n return 'Headers { ' + entries.join(', ') + ' }';\n }\n\n // Handle URLSearchParams objects\n if (typeof URLSearchParams !== 'undefined' && value instanceof URLSearchParams) {\n const entries = [];\n for (const [k, v] of value) {\n entries.push(__formatForConsole(k, nextOptions) + ' => ' + __formatForConsole(v, nextOptions));\n }\n return entries.length === 0\n ? 'URLSearchParams {}'\n : 'URLSearchParams { ' + entries.join(', ') + ' }';\n }\n\n // Handle URL objects\n if (typeof URL !== 'undefined' && value instanceof URL) {\n const entries = [\n 'href: ' + __formatForConsole(value.href, nextOptions),\n 'origin: ' + __formatForConsole(value.origin, nextOptions),\n 'protocol: ' + __formatForConsole(value.protocol, nextOptions),\n 'username: ' + __formatForConsole(value.username, nextOptions),\n 'password: ' + __formatForConsole(value.password, nextOptions),\n 'host: ' + __formatForConsole(value.host, nextOptions),\n 'hostname: ' + __formatForConsole(value.hostname, nextOptions),\n 'port: ' + __formatForConsole(value.port, nextOptions),\n 'pathname: ' + __formatForConsole(value.pathname, nextOptions),\n 'search: ' + __formatForConsole(value.search, nextOptions),\n 'searchParams: ' + __formatForConsole(value.searchParams, nextOptions),\n 'hash: ' + __formatForConsole(value.hash, nextOptions),\n ];\n return 'URL { ' + entries.join(', ') + ' }';\n }\n\n // Handle Date objects\n if (value instanceof Date) {\n return value.toISOString();\n }\n\n // Handle RegExp\n if (value instanceof RegExp) {\n return value.toString();\n }\n\n // Handle Map\n if (value instanceof Map) {\n const entries = [];\n value.forEach((v, k) => {\n entries.push(__formatForConsole(k, nextOptions) + ' => ' + __formatForConsole(v, nextOptions));\n });\n return 'Map(' + value.size + ') { ' + entries.join(', ') + ' }';\n }\n\n // Handle Set\n if (value instanceof Set) {\n const entries = [];\n value.forEach((v) => {\n entries.push(__formatForConsole(v, nextOptions));\n });\n return 'Set(' + value.size + ') { ' + entries.join(', ') + ' }';\n }\n\n // Handle ArrayBuffer and TypedArrays\n if (value instanceof ArrayBuffer) {\n return 'ArrayBuffer { byteLength: ' + value.byteLength + ' }';\n }\n if (ArrayBuffer.isView(value) && !(value instanceof DataView)) {\n const typedArray = value;\n const name = typedArray.constructor.name;\n const length = typedArray.length;\n if (length <= 10) {\n const items = Array.from(typedArray).map(v => __formatForConsole(v, nextOptions));\n return name + '(' + length + ') [ ' + items.join(', ') + ' ]';\n }\n return name + '(' + length + ') [ ... ]';\n }\n\n // Handle Promise\n if (value instanceof Promise) {\n return 'Promise { <pending> }';\n }\n\n // Handle arrays\n if (Array.isArray(value)) {\n if (value.length === 0) return '[]';\n const items = value.map(item => __formatForConsole(item, nextOptions));\n return '[ ' + items.join(', ') + ' ]';\n }\n\n // Handle plain objects\n const keys = Object.keys(value);\n if (keys.length === 0) return '{}';\n const entries = keys.map(key => {\n const formattedKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? key : __formatForConsole(key, nextOptions);\n return formattedKey + ': ' + __formatForConsole(value[key], nextOptions);\n });\n return '{ ' + entries.join(', ') + ' }';\n }\n\n return String(value);\n }\n\n // Format multiple args with space separation (like console.log)\n function __formatArgs(args) {\n return args.map((arg, i) => __formatForConsole(arg, { inObject: false })).join(' ');\n }\n\n // Format data for console.table - creates ASCII table\n function __formatTable(data, columns) {\n if (data === null || data === undefined) {\n return __formatForConsole(data);\n }\n\n // Convert to array of objects\n let rows = [];\n let headers = new Set();\n\n if (Array.isArray(data)) {\n rows = data.map((item, index) => {\n if (item !== null && typeof item === 'object' && !Array.isArray(item)) {\n Object.keys(item).forEach(k => headers.add(k));\n return { __index: index, ...item };\n }\n return { __index: index, Values: item };\n });\n headers.add('Values');\n } else if (typeof data === 'object') {\n Object.keys(data).forEach(key => {\n const item = data[key];\n if (item !== null && typeof item === 'object' && !Array.isArray(item)) {\n Object.keys(item).forEach(k => headers.add(k));\n rows.push({ __index: key, ...item });\n } else {\n rows.push({ __index: key, Values: item });\n headers.add('Values');\n }\n });\n } else {\n return __formatForConsole(data);\n }\n\n // Filter headers by columns if provided\n let headerList = ['(index)', ...headers];\n headerList = headerList.filter(h => h !== '__index');\n if (columns && Array.isArray(columns)) {\n headerList = ['(index)', ...columns.filter(c => headers.has(c))];\n }\n\n // Calculate column widths\n const colWidths = {};\n headerList.forEach(h => {\n colWidths[h] = h === '(index)' ? 7 : h.length;\n });\n rows.forEach(row => {\n headerList.forEach(h => {\n const key = h === '(index)' ? '__index' : h;\n const val = row[key];\n const formatted = val !== undefined ? __formatForConsole(val, { depth: 1, inObject: true }) : '';\n colWidths[h] = Math.max(colWidths[h], formatted.length);\n });\n });\n\n // Build table\n const sep = '+' + headerList.map(h => '-'.repeat(colWidths[h] + 2)).join('+') + '+';\n const headerRow = '|' + headerList.map(h => ' ' + h.padEnd(colWidths[h]) + ' ').join('|') + '|';\n\n const dataRows = rows.map(row => {\n return '|' + headerList.map(h => {\n const key = h === '(index)' ? '__index' : h;\n const val = row[key];\n const formatted = val !== undefined ? __formatForConsole(val, { depth: 1, inObject: true }) : '';\n return ' ' + formatted.padEnd(colWidths[h]) + ' ';\n }).join('|') + '|';\n });\n\n return [sep, headerRow, sep, ...dataRows, sep].join('\\\\n');\n }\n\n globalThis.console = {\n log: (...args) => __console_log(__formatArgs(args)),\n warn: (...args) => __console_warn(__formatArgs(args)),\n error: (...args) => __console_error(__formatArgs(args)),\n debug: (...args) => __console_debug(__formatArgs(args)),\n info: (...args) => __console_info(__formatArgs(args)),\n trace: (...args) => {\n const err = new Error();\n const stack = err.stack || '';\n // Remove the first two lines (Error and the trace call itself)\n const stackLines = stack.split('\\\\n').slice(2).join('\\\\n');\n __console_trace(__formatArgs(args), 'Trace' + (args.length > 0 ? ': ' + __formatArgs(args) : '') + '\\\\n' + stackLines);\n },\n dir: (value, options) => __console_dir(__formatForConsole(value, { depth: options?.depth ?? 2, inObject: true })),\n table: (data, columns) => __console_table(__formatTable(data, columns)),\n time: __console_time,\n timeEnd: __console_timeEnd,\n timeLog: (label, ...args) => __console_timeLog(label ?? 'default', 0, __formatArgs(args)),\n count: __console_count,\n countReset: __console_countReset,\n group: __console_group,\n groupCollapsed: __console_groupCollapsed,\n groupEnd: __console_groupEnd,\n clear: __console_clear,\n assert: (condition, ...args) => {\n if (!condition) {\n const msg = args.length > 0 ? __formatArgs(args) : 'console.assert';\n __console_assert('Assertion failed: ' + msg);\n }\n },\n };\n `);\n\n return {\n dispose() {\n timers.clear();\n counters.clear();\n groupDepth = 0;\n },\n reset() {\n timers.clear();\n counters.clear();\n groupDepth = 0;\n },\n getTimers() {\n return new Map(timers);\n },\n getCounters() {\n return new Map(counters);\n },\n getGroupDepth() {\n return groupDepth;\n },\n };\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "ACA86F3A29BC75EB64756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "AA2C38BED96F591564756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -29,6 +29,11 @@ var NULL_BODY_STATUSES = new Set([101, 103, 204, 205, 304]);
29
29
  var DEFAULT_CALLBACK_TIMEOUT_MS = 120000;
30
30
  var FETCH_CALLBACK_TIMEOUT_MS = 35000;
31
31
  var requestContextStorage = new AsyncLocalStorage;
32
+ function invokeBestEffortClientEventCallback(connection, callbackId, args, label, options) {
33
+ invokeClientCallback(connection, callbackId, args, options).catch((error) => {
34
+ console.error(`[isolate-daemon] ${label} delivery failed.`, error);
35
+ });
36
+ }
32
37
  function createAbortError(reason = "The operation was aborted") {
33
38
  if (typeof DOMException !== "undefined") {
34
39
  return new DOMException(reason, "AbortError");
@@ -401,7 +406,6 @@ function softDeleteRuntime(instance, state, reason) {
401
406
  instance.callbacks.clear();
402
407
  instance.runtime.timers.clearAll();
403
408
  instance.runtime.console.reset();
404
- instance.runtime.pendingCallbacks.length = 0;
405
409
  instance.returnedCallbacks?.clear();
406
410
  instance.returnedPromises?.clear();
407
411
  instance.returnedIterators?.clear();
@@ -870,8 +874,7 @@ async function handleCreateRuntime(message, connection, state) {
870
874
  if (!conn || callbackId === undefined) {
871
875
  return;
872
876
  }
873
- const promise = invokeClientCallback(conn, callbackId, [JSON.stringify(event)], { signal: getCurrentHostSignal(instance) }).catch(() => {});
874
- instance.runtime?.pendingCallbacks?.push(promise);
877
+ invokeBestEffortClientEventCallback(conn, callbackId, [JSON.stringify(event)], "testEnvironment.onEvent", { signal: getCurrentHostSignal(instance) });
875
878
  } : undefined,
876
879
  testTimeout: testEnvOptions?.testTimeout
877
880
  };
@@ -904,14 +907,11 @@ async function handleCreateRuntime(message, connection, state) {
904
907
  return;
905
908
  }
906
909
  if (event.type === "browserConsoleLog" && callbackContext.playwright.onBrowserConsoleLogCallbackId !== undefined) {
907
- const promise = invokeClientCallback(conn, callbackContext.playwright.onBrowserConsoleLogCallbackId, [{ level: event.level, stdout: event.stdout, timestamp: event.timestamp }], { signal: getCurrentHostSignal(instance) }).catch(() => {});
908
- instance.runtime?.pendingCallbacks?.push(promise);
910
+ invokeBestEffortClientEventCallback(conn, callbackContext.playwright.onBrowserConsoleLogCallbackId, [{ level: event.level, stdout: event.stdout, timestamp: event.timestamp }], "playwright.onBrowserConsoleLog", { signal: getCurrentHostSignal(instance) });
909
911
  } else if (event.type === "networkRequest" && callbackContext.playwright.onNetworkRequestCallbackId !== undefined) {
910
- const promise = invokeClientCallback(conn, callbackContext.playwright.onNetworkRequestCallbackId, [event], { signal: getCurrentHostSignal(instance) }).catch(() => {});
911
- instance.runtime?.pendingCallbacks?.push(promise);
912
+ invokeBestEffortClientEventCallback(conn, callbackContext.playwright.onNetworkRequestCallbackId, [event], "playwright.onNetworkRequest", { signal: getCurrentHostSignal(instance) });
912
913
  } else if (event.type === "networkResponse" && callbackContext.playwright.onNetworkResponseCallbackId !== undefined) {
913
- const promise = invokeClientCallback(conn, callbackContext.playwright.onNetworkResponseCallbackId, [event], { signal: getCurrentHostSignal(instance) }).catch(() => {});
914
- instance.runtime?.pendingCallbacks?.push(promise);
914
+ invokeBestEffortClientEventCallback(conn, callbackContext.playwright.onNetworkResponseCallbackId, [event], "playwright.onNetworkResponse", { signal: getCurrentHostSignal(instance) });
915
915
  }
916
916
  }
917
917
  };
@@ -926,8 +926,7 @@ async function handleCreateRuntime(message, connection, state) {
926
926
  const callbackId = callbackContext.consoleOnEntry;
927
927
  if (!conn || callbackId === undefined)
928
928
  return;
929
- const promise = invokeClientCallback(conn, callbackId, [entry]).catch(() => {});
930
- runtime.pendingCallbacks.push(promise);
929
+ invokeBestEffortClientEventCallback(conn, callbackId, [entry], "console.onEntry");
931
930
  }
932
931
  },
933
932
  fetch: async (url, init) => {
@@ -2230,4 +2229,4 @@ export {
2230
2229
  handleConnection
2231
2230
  };
2232
2231
 
2233
- //# debugId=B375B10E50F2EE8464756E2164756E21
2232
+ //# debugId=5633592E119EA72364756E2164756E21