donobu 5.18.2 → 5.18.3

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.
@@ -25,6 +25,7 @@ const BrowserUtils_1 = require("../../utils/BrowserUtils");
25
25
  const FlowLogBuffer_1 = require("../../utils/FlowLogBuffer");
26
26
  const Logger_1 = require("../../utils/Logger");
27
27
  const MiscUtils_1 = require("../../utils/MiscUtils");
28
+ const PageLogListeners_1 = require("../../utils/PageLogListeners");
28
29
  const cacheLocator_1 = require("../ai/cache/cacheLocator");
29
30
  const extendPage_1 = require("../page/extendPage");
30
31
  const tbd_1 = require("../page/tbd");
@@ -101,6 +102,11 @@ exports.test = test_1.test.extend({
101
102
  });
102
103
  extendedPage._dnb.donobuFlowMetadata.name = getSanitizedTestName(testInfo);
103
104
  extendedPage._dnb.donobuFlowMetadata.overallObjective = overallObjective;
105
+ // Register browser console and network listeners so that logs from these
106
+ // sources are captured into the flow's logBuffer. In Studio-launched flows
107
+ // this is done by WebTargetInspector.initialize(), but that method is not
108
+ // called during test runs, so we wire the listeners up here directly.
109
+ (0, PageLogListeners_1.registerPageLogListeners)(page);
104
110
  // Bind the Playwright-provided `use` callback to an async resource so that
105
111
  // any microtasks scheduled inside the test body keep the flow logging
106
112
  // context. Without this, Playwright may re-use earlier async resources that
@@ -6,6 +6,7 @@ const SetDonobuAnnotations_1 = require("../bindings/SetDonobuAnnotations");
6
6
  const PageClosedException_1 = require("../exceptions/PageClosedException");
7
7
  const BrowserUtils_1 = require("../utils/BrowserUtils");
8
8
  const Logger_1 = require("../utils/Logger");
9
+ const PageLogListeners_1 = require("../utils/PageLogListeners");
9
10
  const PlaywrightUtils_1 = require("../utils/PlaywrightUtils");
10
11
  const PageInspector_1 = require("./PageInspector");
11
12
  /**
@@ -185,81 +186,7 @@ The active (i.e. in focus) tab is ${this._target.current.url()}`;
185
186
  /* ------------------------------------------------------------------ */
186
187
  handleNewPage(page, callbacks) {
187
188
  this._target.current = page;
188
- page.on('console', (msg) => {
189
- const { url, lineNumber, columnNumber } = msg.location();
190
- const hasSourceLocation = lineNumber !== 0 || columnNumber !== 0;
191
- const meta = url
192
- ? hasSourceLocation
193
- ? { url, lineNumber, columnNumber }
194
- : { url }
195
- : undefined;
196
- switch (msg.type()) {
197
- case 'error':
198
- Logger_1.browserLogger.error(msg.text(), meta);
199
- break;
200
- case 'warning':
201
- Logger_1.browserLogger.warn(msg.text(), meta);
202
- break;
203
- case 'debug':
204
- Logger_1.browserLogger.debug(msg.text(), meta);
205
- break;
206
- default:
207
- Logger_1.browserLogger.info(msg.text(), meta);
208
- break;
209
- }
210
- });
211
- page.on('pageerror', (error) => {
212
- Logger_1.browserLogger.error(error.message, {
213
- stack: error.stack,
214
- url: page.url(),
215
- });
216
- });
217
- // Fallback timing: track request start times keyed by the Request object
218
- // itself (via WeakMap) so concurrent requests to the same URL don't collide.
219
- // Prefer Playwright's native timing API when it has data.
220
- const requestStartTimes = new WeakMap();
221
- page.on('request', (request) => {
222
- requestStartTimes.set(request, Date.now());
223
- });
224
- const getDuration = (request) => {
225
- const timing = request.timing();
226
- if (timing.responseEnd >= 0) {
227
- return Math.round(timing.responseEnd);
228
- }
229
- const startTime = requestStartTimes.get(request);
230
- return startTime !== undefined ? Date.now() - startTime : undefined;
231
- };
232
- page.on('response', (response) => {
233
- const request = response.request();
234
- const status = response.status();
235
- const duration = getDuration(request);
236
- const meta = {
237
- method: request.method(),
238
- url: request.url(),
239
- status,
240
- duration,
241
- resourceType: request.resourceType(),
242
- };
243
- if (status >= 500) {
244
- Logger_1.networkLogger.error(request.url(), meta);
245
- }
246
- else if (status >= 400) {
247
- Logger_1.networkLogger.warn(request.url(), meta);
248
- }
249
- else {
250
- Logger_1.networkLogger.info(request.url(), meta);
251
- }
252
- });
253
- page.on('requestfailed', (request) => {
254
- const duration = getDuration(request);
255
- Logger_1.networkLogger.error(`${request.url()} FAILED: ${request.failure()?.errorText}`, {
256
- method: request.method(),
257
- url: request.url(),
258
- resourceType: request.resourceType(),
259
- failureReason: request.failure()?.errorText,
260
- duration,
261
- });
262
- });
189
+ (0, PageLogListeners_1.registerPageLogListeners)(page);
263
190
  if (callbacks.metadata.runMode !== 'INSTRUCT') {
264
191
  page.on('domcontentloaded', async () => {
265
192
  await this._interactionVisualizer.showMouse(page);
@@ -0,0 +1,15 @@
1
+ import type { Page } from 'playwright';
2
+ /**
3
+ * Registers Playwright page event listeners that route browser console messages
4
+ * and network request/response data to the {@link browserLogger} and
5
+ * {@link networkLogger} Winston loggers. These loggers include a
6
+ * {@link FlowLogBufferTransport} that captures entries into the per-flow
7
+ * log buffer (when one is available via AsyncLocalStorage or the process-local
8
+ * fallback).
9
+ *
10
+ * This function is called from both {@link WebTargetInspector.handleNewPage}
11
+ * (Studio-launched flows) and the Playwright test extension fixture, ensuring
12
+ * identical logging behaviour across both runtime contexts.
13
+ */
14
+ export declare function registerPageLogListeners(page: Page): void;
15
+ //# sourceMappingURL=PageLogListeners.d.ts.map
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerPageLogListeners = registerPageLogListeners;
4
+ const Logger_1 = require("./Logger");
5
+ /**
6
+ * Registers Playwright page event listeners that route browser console messages
7
+ * and network request/response data to the {@link browserLogger} and
8
+ * {@link networkLogger} Winston loggers. These loggers include a
9
+ * {@link FlowLogBufferTransport} that captures entries into the per-flow
10
+ * log buffer (when one is available via AsyncLocalStorage or the process-local
11
+ * fallback).
12
+ *
13
+ * This function is called from both {@link WebTargetInspector.handleNewPage}
14
+ * (Studio-launched flows) and the Playwright test extension fixture, ensuring
15
+ * identical logging behaviour across both runtime contexts.
16
+ */
17
+ function registerPageLogListeners(page) {
18
+ page.on('console', (msg) => {
19
+ const { url, lineNumber, columnNumber } = msg.location();
20
+ const hasSourceLocation = lineNumber !== 0 || columnNumber !== 0;
21
+ const meta = url
22
+ ? hasSourceLocation
23
+ ? { url, lineNumber, columnNumber }
24
+ : { url }
25
+ : undefined;
26
+ switch (msg.type()) {
27
+ case 'error':
28
+ Logger_1.browserLogger.error(msg.text(), meta);
29
+ break;
30
+ case 'warning':
31
+ Logger_1.browserLogger.warn(msg.text(), meta);
32
+ break;
33
+ case 'debug':
34
+ Logger_1.browserLogger.debug(msg.text(), meta);
35
+ break;
36
+ default:
37
+ Logger_1.browserLogger.info(msg.text(), meta);
38
+ break;
39
+ }
40
+ });
41
+ page.on('pageerror', (error) => {
42
+ Logger_1.browserLogger.error(error.message, {
43
+ stack: error.stack,
44
+ url: page.url(),
45
+ });
46
+ });
47
+ // Fallback timing: track request start times keyed by the Request object
48
+ // itself (via WeakMap) so concurrent requests to the same URL don't collide.
49
+ // Prefer Playwright's native timing API when it has data.
50
+ const requestStartTimes = new WeakMap();
51
+ page.on('request', (request) => {
52
+ requestStartTimes.set(request, Date.now());
53
+ });
54
+ const getDuration = (request) => {
55
+ const timing = request.timing();
56
+ if (timing.responseEnd >= 0) {
57
+ return Math.round(timing.responseEnd);
58
+ }
59
+ const startTime = requestStartTimes.get(request);
60
+ return startTime !== undefined ? Date.now() - startTime : undefined;
61
+ };
62
+ page.on('response', (response) => {
63
+ const request = response.request();
64
+ const status = response.status();
65
+ const duration = getDuration(request);
66
+ const meta = {
67
+ method: request.method(),
68
+ url: request.url(),
69
+ status,
70
+ duration,
71
+ resourceType: request.resourceType(),
72
+ };
73
+ if (status >= 500) {
74
+ Logger_1.networkLogger.error(request.url(), meta);
75
+ }
76
+ else if (status >= 400) {
77
+ Logger_1.networkLogger.warn(request.url(), meta);
78
+ }
79
+ else {
80
+ Logger_1.networkLogger.info(request.url(), meta);
81
+ }
82
+ });
83
+ page.on('requestfailed', (request) => {
84
+ const duration = getDuration(request);
85
+ Logger_1.networkLogger.error(`${request.url()} FAILED: ${request.failure()?.errorText}`, {
86
+ method: request.method(),
87
+ url: request.url(),
88
+ resourceType: request.resourceType(),
89
+ failureReason: request.failure()?.errorText,
90
+ duration,
91
+ });
92
+ });
93
+ }
94
+ //# sourceMappingURL=PageLogListeners.js.map
@@ -25,6 +25,7 @@ const BrowserUtils_1 = require("../../utils/BrowserUtils");
25
25
  const FlowLogBuffer_1 = require("../../utils/FlowLogBuffer");
26
26
  const Logger_1 = require("../../utils/Logger");
27
27
  const MiscUtils_1 = require("../../utils/MiscUtils");
28
+ const PageLogListeners_1 = require("../../utils/PageLogListeners");
28
29
  const cacheLocator_1 = require("../ai/cache/cacheLocator");
29
30
  const extendPage_1 = require("../page/extendPage");
30
31
  const tbd_1 = require("../page/tbd");
@@ -101,6 +102,11 @@ exports.test = test_1.test.extend({
101
102
  });
102
103
  extendedPage._dnb.donobuFlowMetadata.name = getSanitizedTestName(testInfo);
103
104
  extendedPage._dnb.donobuFlowMetadata.overallObjective = overallObjective;
105
+ // Register browser console and network listeners so that logs from these
106
+ // sources are captured into the flow's logBuffer. In Studio-launched flows
107
+ // this is done by WebTargetInspector.initialize(), but that method is not
108
+ // called during test runs, so we wire the listeners up here directly.
109
+ (0, PageLogListeners_1.registerPageLogListeners)(page);
104
110
  // Bind the Playwright-provided `use` callback to an async resource so that
105
111
  // any microtasks scheduled inside the test body keep the flow logging
106
112
  // context. Without this, Playwright may re-use earlier async resources that
@@ -6,6 +6,7 @@ const SetDonobuAnnotations_1 = require("../bindings/SetDonobuAnnotations");
6
6
  const PageClosedException_1 = require("../exceptions/PageClosedException");
7
7
  const BrowserUtils_1 = require("../utils/BrowserUtils");
8
8
  const Logger_1 = require("../utils/Logger");
9
+ const PageLogListeners_1 = require("../utils/PageLogListeners");
9
10
  const PlaywrightUtils_1 = require("../utils/PlaywrightUtils");
10
11
  const PageInspector_1 = require("./PageInspector");
11
12
  /**
@@ -185,81 +186,7 @@ The active (i.e. in focus) tab is ${this._target.current.url()}`;
185
186
  /* ------------------------------------------------------------------ */
186
187
  handleNewPage(page, callbacks) {
187
188
  this._target.current = page;
188
- page.on('console', (msg) => {
189
- const { url, lineNumber, columnNumber } = msg.location();
190
- const hasSourceLocation = lineNumber !== 0 || columnNumber !== 0;
191
- const meta = url
192
- ? hasSourceLocation
193
- ? { url, lineNumber, columnNumber }
194
- : { url }
195
- : undefined;
196
- switch (msg.type()) {
197
- case 'error':
198
- Logger_1.browserLogger.error(msg.text(), meta);
199
- break;
200
- case 'warning':
201
- Logger_1.browserLogger.warn(msg.text(), meta);
202
- break;
203
- case 'debug':
204
- Logger_1.browserLogger.debug(msg.text(), meta);
205
- break;
206
- default:
207
- Logger_1.browserLogger.info(msg.text(), meta);
208
- break;
209
- }
210
- });
211
- page.on('pageerror', (error) => {
212
- Logger_1.browserLogger.error(error.message, {
213
- stack: error.stack,
214
- url: page.url(),
215
- });
216
- });
217
- // Fallback timing: track request start times keyed by the Request object
218
- // itself (via WeakMap) so concurrent requests to the same URL don't collide.
219
- // Prefer Playwright's native timing API when it has data.
220
- const requestStartTimes = new WeakMap();
221
- page.on('request', (request) => {
222
- requestStartTimes.set(request, Date.now());
223
- });
224
- const getDuration = (request) => {
225
- const timing = request.timing();
226
- if (timing.responseEnd >= 0) {
227
- return Math.round(timing.responseEnd);
228
- }
229
- const startTime = requestStartTimes.get(request);
230
- return startTime !== undefined ? Date.now() - startTime : undefined;
231
- };
232
- page.on('response', (response) => {
233
- const request = response.request();
234
- const status = response.status();
235
- const duration = getDuration(request);
236
- const meta = {
237
- method: request.method(),
238
- url: request.url(),
239
- status,
240
- duration,
241
- resourceType: request.resourceType(),
242
- };
243
- if (status >= 500) {
244
- Logger_1.networkLogger.error(request.url(), meta);
245
- }
246
- else if (status >= 400) {
247
- Logger_1.networkLogger.warn(request.url(), meta);
248
- }
249
- else {
250
- Logger_1.networkLogger.info(request.url(), meta);
251
- }
252
- });
253
- page.on('requestfailed', (request) => {
254
- const duration = getDuration(request);
255
- Logger_1.networkLogger.error(`${request.url()} FAILED: ${request.failure()?.errorText}`, {
256
- method: request.method(),
257
- url: request.url(),
258
- resourceType: request.resourceType(),
259
- failureReason: request.failure()?.errorText,
260
- duration,
261
- });
262
- });
189
+ (0, PageLogListeners_1.registerPageLogListeners)(page);
263
190
  if (callbacks.metadata.runMode !== 'INSTRUCT') {
264
191
  page.on('domcontentloaded', async () => {
265
192
  await this._interactionVisualizer.showMouse(page);
@@ -0,0 +1,15 @@
1
+ import type { Page } from 'playwright';
2
+ /**
3
+ * Registers Playwright page event listeners that route browser console messages
4
+ * and network request/response data to the {@link browserLogger} and
5
+ * {@link networkLogger} Winston loggers. These loggers include a
6
+ * {@link FlowLogBufferTransport} that captures entries into the per-flow
7
+ * log buffer (when one is available via AsyncLocalStorage or the process-local
8
+ * fallback).
9
+ *
10
+ * This function is called from both {@link WebTargetInspector.handleNewPage}
11
+ * (Studio-launched flows) and the Playwright test extension fixture, ensuring
12
+ * identical logging behaviour across both runtime contexts.
13
+ */
14
+ export declare function registerPageLogListeners(page: Page): void;
15
+ //# sourceMappingURL=PageLogListeners.d.ts.map
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerPageLogListeners = registerPageLogListeners;
4
+ const Logger_1 = require("./Logger");
5
+ /**
6
+ * Registers Playwright page event listeners that route browser console messages
7
+ * and network request/response data to the {@link browserLogger} and
8
+ * {@link networkLogger} Winston loggers. These loggers include a
9
+ * {@link FlowLogBufferTransport} that captures entries into the per-flow
10
+ * log buffer (when one is available via AsyncLocalStorage or the process-local
11
+ * fallback).
12
+ *
13
+ * This function is called from both {@link WebTargetInspector.handleNewPage}
14
+ * (Studio-launched flows) and the Playwright test extension fixture, ensuring
15
+ * identical logging behaviour across both runtime contexts.
16
+ */
17
+ function registerPageLogListeners(page) {
18
+ page.on('console', (msg) => {
19
+ const { url, lineNumber, columnNumber } = msg.location();
20
+ const hasSourceLocation = lineNumber !== 0 || columnNumber !== 0;
21
+ const meta = url
22
+ ? hasSourceLocation
23
+ ? { url, lineNumber, columnNumber }
24
+ : { url }
25
+ : undefined;
26
+ switch (msg.type()) {
27
+ case 'error':
28
+ Logger_1.browserLogger.error(msg.text(), meta);
29
+ break;
30
+ case 'warning':
31
+ Logger_1.browserLogger.warn(msg.text(), meta);
32
+ break;
33
+ case 'debug':
34
+ Logger_1.browserLogger.debug(msg.text(), meta);
35
+ break;
36
+ default:
37
+ Logger_1.browserLogger.info(msg.text(), meta);
38
+ break;
39
+ }
40
+ });
41
+ page.on('pageerror', (error) => {
42
+ Logger_1.browserLogger.error(error.message, {
43
+ stack: error.stack,
44
+ url: page.url(),
45
+ });
46
+ });
47
+ // Fallback timing: track request start times keyed by the Request object
48
+ // itself (via WeakMap) so concurrent requests to the same URL don't collide.
49
+ // Prefer Playwright's native timing API when it has data.
50
+ const requestStartTimes = new WeakMap();
51
+ page.on('request', (request) => {
52
+ requestStartTimes.set(request, Date.now());
53
+ });
54
+ const getDuration = (request) => {
55
+ const timing = request.timing();
56
+ if (timing.responseEnd >= 0) {
57
+ return Math.round(timing.responseEnd);
58
+ }
59
+ const startTime = requestStartTimes.get(request);
60
+ return startTime !== undefined ? Date.now() - startTime : undefined;
61
+ };
62
+ page.on('response', (response) => {
63
+ const request = response.request();
64
+ const status = response.status();
65
+ const duration = getDuration(request);
66
+ const meta = {
67
+ method: request.method(),
68
+ url: request.url(),
69
+ status,
70
+ duration,
71
+ resourceType: request.resourceType(),
72
+ };
73
+ if (status >= 500) {
74
+ Logger_1.networkLogger.error(request.url(), meta);
75
+ }
76
+ else if (status >= 400) {
77
+ Logger_1.networkLogger.warn(request.url(), meta);
78
+ }
79
+ else {
80
+ Logger_1.networkLogger.info(request.url(), meta);
81
+ }
82
+ });
83
+ page.on('requestfailed', (request) => {
84
+ const duration = getDuration(request);
85
+ Logger_1.networkLogger.error(`${request.url()} FAILED: ${request.failure()?.errorText}`, {
86
+ method: request.method(),
87
+ url: request.url(),
88
+ resourceType: request.resourceType(),
89
+ failureReason: request.failure()?.errorText,
90
+ duration,
91
+ });
92
+ });
93
+ }
94
+ //# sourceMappingURL=PageLogListeners.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "donobu",
3
- "version": "5.18.2",
3
+ "version": "5.18.3",
4
4
  "description": "Create browser automations with an LLM agent and replay them as Playwright scripts.",
5
5
  "main": "dist/main.js",
6
6
  "module": "dist/esm/main.js",