donobu 5.27.0 → 5.27.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.
@@ -21,6 +21,7 @@ export * from './lib/test/fixtures/browserState';
21
21
  export * from './lib/test/fixtures/gptClients';
22
22
  export * from './lib/test/testExtension';
23
23
  export * from './lib/test/utils/donobuTestStack';
24
+ export { AdminApiController } from './managers/AdminApiController';
24
25
  export { DonobuFlow } from './managers/DonobuFlow';
25
26
  export { distillAllowedEnvVariableNames, DonobuFlowsManager, prepareToolCallsForRerun, } from './managers/DonobuFlowsManager';
26
27
  export { type DonobuStack, setupDonobuStack } from './managers/DonobuStack';
package/dist/esm/main.js CHANGED
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.TargetRuntimePluginRegistry = exports.PersistencePluginRegistry = exports.createDefaultToolRegistry = exports.ToolManager = exports.PluginLoader = exports.InteractionVisualizer = exports.setupDonobuStack = exports.prepareToolCallsForRerun = exports.DonobuFlowsManager = exports.distillAllowedEnvVariableNames = exports.DonobuFlow = exports.env = exports.runGenerateSiteTests = exports.VercelAiGptClient = exports.OpenAiGptClient = exports.GptClientPluginRegistry = exports.GptClient = exports.GoogleGenerativeAiGptClient = exports.fixAssertFields = exports.DonobuGptClient = exports.AnthropicGptClient = void 0;
17
+ exports.TargetRuntimePluginRegistry = exports.PersistencePluginRegistry = exports.createDefaultToolRegistry = exports.ToolManager = exports.PluginLoader = exports.InteractionVisualizer = exports.setupDonobuStack = exports.prepareToolCallsForRerun = exports.DonobuFlowsManager = exports.distillAllowedEnvVariableNames = exports.DonobuFlow = exports.AdminApiController = exports.env = exports.runGenerateSiteTests = exports.VercelAiGptClient = exports.OpenAiGptClient = exports.GptClientPluginRegistry = exports.GptClient = exports.GoogleGenerativeAiGptClient = exports.fixAssertFields = exports.DonobuGptClient = exports.AnthropicGptClient = void 0;
18
18
  exports.startDonobuServer = startDonobuServer;
19
19
  const commander_1 = require("commander");
20
20
  const v4_1 = require("zod/v4");
@@ -56,6 +56,8 @@ __exportStar(require("./lib/test/fixtures/browserState"), exports);
56
56
  __exportStar(require("./lib/test/fixtures/gptClients"), exports);
57
57
  __exportStar(require("./lib/test/testExtension"), exports);
58
58
  __exportStar(require("./lib/test/utils/donobuTestStack"), exports);
59
+ var AdminApiController_2 = require("./managers/AdminApiController");
60
+ Object.defineProperty(exports, "AdminApiController", { enumerable: true, get: function () { return AdminApiController_2.AdminApiController; } });
59
61
  var DonobuFlow_1 = require("./managers/DonobuFlow");
60
62
  Object.defineProperty(exports, "DonobuFlow", { enumerable: true, get: function () { return DonobuFlow_1.DonobuFlow; } });
61
63
  var DonobuFlowsManager_1 = require("./managers/DonobuFlowsManager");
@@ -107,8 +107,27 @@ export declare class DonobuFlow {
107
107
  private onUnexpectedException;
108
108
  /**
109
109
  * This method is called when a flow is complete (i.e. when {@link DonobuFlow.run} should return).
110
+ *
111
+ * Browser session state and the final metadata write are committed by
112
+ * whichever code path produced the terminal state (transitionState for
113
+ * tool-driven completion; the on*Failure handlers for failure paths) —
114
+ * by the time we reach onComplete those have already happened.
110
115
  */
111
116
  private onComplete;
117
+ /**
118
+ * Persists the current browser session state if the flow's config has
119
+ * `persistState` enabled. Must be called BEFORE every site that commits
120
+ * a terminal `state` to persistence — otherwise a frontend that polls
121
+ * for the flow's state can observe "complete" between the metadata
122
+ * write and the session-state upload, fire an eager browser-state
123
+ * fetch (e.g. FlowDeveloperTools auto-loads on terminal), and 404 until
124
+ * the upload finishes.
125
+ *
126
+ * The browser context typically survives all-pages-closed (the read
127
+ * goes against the context, not a specific page), so this is also
128
+ * safe to call from the failure handlers like onTargetClosed.
129
+ */
130
+ private persistTerminalSessionStateIfNeeded;
112
131
  /**
113
132
  * Attempt to POST a JSON body containing given flow ID to the given
114
133
  * ${@link callbackUrl} if the URL is non-null. Note that there is no retying
@@ -218,6 +218,7 @@ class DonobuFlow {
218
218
  this.metadata.state = 'FAILED';
219
219
  Logger_1.appLogger.error(result.reason);
220
220
  this.metadata.result = { failed: result.reason };
221
+ await this.persistTerminalSessionStateIfNeeded();
221
222
  await this.persistence.setFlowMetadata(this.metadata);
222
223
  }
223
224
  }
@@ -232,6 +233,7 @@ class DonobuFlow {
232
233
  failed: `Stopped flow due to the ${this.gptClient?.config.type} GPT platform throwing an internal error!`,
233
234
  context: error.message,
234
235
  };
236
+ await this.persistTerminalSessionStateIfNeeded();
235
237
  await this.persistence.setFlowMetadata(this.metadata);
236
238
  }
237
239
  /**
@@ -247,6 +249,7 @@ class DonobuFlow {
247
249
  : `Your ${platform} API quota has been exhausted. Please check your account's billing and usage limits; this may happen if there is a lack of funds in the account`;
248
250
  Logger_1.appLogger.error(failedMessage, error);
249
251
  this.metadata.result = { failed: failedMessage };
252
+ await this.persistTerminalSessionStateIfNeeded();
250
253
  await this.persistence.setFlowMetadata(this.metadata);
251
254
  }
252
255
  /**
@@ -341,18 +344,38 @@ class DonobuFlow {
341
344
  this.metadata.result = {
342
345
  failed: 'Internal error 🙈',
343
346
  };
347
+ await this.persistTerminalSessionStateIfNeeded();
344
348
  await this.persistence.setFlowMetadata(this.metadata);
345
349
  }
346
350
  /**
347
351
  * This method is called when a flow is complete (i.e. when {@link DonobuFlow.run} should return).
352
+ *
353
+ * Browser session state and the final metadata write are committed by
354
+ * whichever code path produced the terminal state (transitionState for
355
+ * tool-driven completion; the on*Failure handlers for failure paths) —
356
+ * by the time we reach onComplete those have already happened.
348
357
  */
349
358
  async onComplete() {
350
- await this.persistence.setFlowMetadata(this.metadata);
359
+ DonobuFlow.invokeFlowFinishedCallback(this.metadata.callbackUrl, this.metadata.id);
360
+ this.controlPanel.close();
361
+ }
362
+ /**
363
+ * Persists the current browser session state if the flow's config has
364
+ * `persistState` enabled. Must be called BEFORE every site that commits
365
+ * a terminal `state` to persistence — otherwise a frontend that polls
366
+ * for the flow's state can observe "complete" between the metadata
367
+ * write and the session-state upload, fire an eager browser-state
368
+ * fetch (e.g. FlowDeveloperTools auto-loads on terminal), and 404 until
369
+ * the upload finishes.
370
+ *
371
+ * The browser context typically survives all-pages-closed (the read
372
+ * goes against the context, not a specific page), so this is also
373
+ * safe to call from the failure handlers like onTargetClosed.
374
+ */
375
+ async persistTerminalSessionStateIfNeeded() {
351
376
  if (this.metadata.web?.browser?.persistState) {
352
377
  await this.targetInspector.persistSessionState(this.persistence, this.metadata.id);
353
378
  }
354
- DonobuFlow.invokeFlowFinishedCallback(this.metadata.callbackUrl, this.metadata.id);
355
- this.controlPanel.close();
356
379
  }
357
380
  /**
358
381
  * Attempt to POST a JSON body containing given flow ID to the given
@@ -623,8 +646,14 @@ Message: ${dialog.message()}`;
623
646
  // the result object before the final state is set. If we did not do
624
647
  // this, then someone polling for a flow's state may see the flow
625
648
  // finished but still see a null result.
649
+ //
650
+ // The same rationale applies to the browser session state: an eager
651
+ // fetch from the frontend (e.g. FlowDeveloperTools auto-loads on
652
+ // terminal state) would otherwise race the upload that onComplete
653
+ // performs and 404 until the user manually refreshed.
626
654
  if ((0, FlowMetadata_1.isComplete)(nextState)) {
627
655
  this.metadata.result = await this.createResultJson(nextState);
656
+ await this.persistTerminalSessionStateIfNeeded();
628
657
  }
629
658
  const lastState = this.metadata.state;
630
659
  this.metadata.state = nextState;
package/dist/main.d.ts CHANGED
@@ -21,6 +21,7 @@ export * from './lib/test/fixtures/browserState';
21
21
  export * from './lib/test/fixtures/gptClients';
22
22
  export * from './lib/test/testExtension';
23
23
  export * from './lib/test/utils/donobuTestStack';
24
+ export { AdminApiController } from './managers/AdminApiController';
24
25
  export { DonobuFlow } from './managers/DonobuFlow';
25
26
  export { distillAllowedEnvVariableNames, DonobuFlowsManager, prepareToolCallsForRerun, } from './managers/DonobuFlowsManager';
26
27
  export { type DonobuStack, setupDonobuStack } from './managers/DonobuStack';
package/dist/main.js CHANGED
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.TargetRuntimePluginRegistry = exports.PersistencePluginRegistry = exports.createDefaultToolRegistry = exports.ToolManager = exports.PluginLoader = exports.InteractionVisualizer = exports.setupDonobuStack = exports.prepareToolCallsForRerun = exports.DonobuFlowsManager = exports.distillAllowedEnvVariableNames = exports.DonobuFlow = exports.env = exports.runGenerateSiteTests = exports.VercelAiGptClient = exports.OpenAiGptClient = exports.GptClientPluginRegistry = exports.GptClient = exports.GoogleGenerativeAiGptClient = exports.fixAssertFields = exports.DonobuGptClient = exports.AnthropicGptClient = void 0;
17
+ exports.TargetRuntimePluginRegistry = exports.PersistencePluginRegistry = exports.createDefaultToolRegistry = exports.ToolManager = exports.PluginLoader = exports.InteractionVisualizer = exports.setupDonobuStack = exports.prepareToolCallsForRerun = exports.DonobuFlowsManager = exports.distillAllowedEnvVariableNames = exports.DonobuFlow = exports.AdminApiController = exports.env = exports.runGenerateSiteTests = exports.VercelAiGptClient = exports.OpenAiGptClient = exports.GptClientPluginRegistry = exports.GptClient = exports.GoogleGenerativeAiGptClient = exports.fixAssertFields = exports.DonobuGptClient = exports.AnthropicGptClient = void 0;
18
18
  exports.startDonobuServer = startDonobuServer;
19
19
  const commander_1 = require("commander");
20
20
  const v4_1 = require("zod/v4");
@@ -56,6 +56,8 @@ __exportStar(require("./lib/test/fixtures/browserState"), exports);
56
56
  __exportStar(require("./lib/test/fixtures/gptClients"), exports);
57
57
  __exportStar(require("./lib/test/testExtension"), exports);
58
58
  __exportStar(require("./lib/test/utils/donobuTestStack"), exports);
59
+ var AdminApiController_2 = require("./managers/AdminApiController");
60
+ Object.defineProperty(exports, "AdminApiController", { enumerable: true, get: function () { return AdminApiController_2.AdminApiController; } });
59
61
  var DonobuFlow_1 = require("./managers/DonobuFlow");
60
62
  Object.defineProperty(exports, "DonobuFlow", { enumerable: true, get: function () { return DonobuFlow_1.DonobuFlow; } });
61
63
  var DonobuFlowsManager_1 = require("./managers/DonobuFlowsManager");
@@ -107,8 +107,27 @@ export declare class DonobuFlow {
107
107
  private onUnexpectedException;
108
108
  /**
109
109
  * This method is called when a flow is complete (i.e. when {@link DonobuFlow.run} should return).
110
+ *
111
+ * Browser session state and the final metadata write are committed by
112
+ * whichever code path produced the terminal state (transitionState for
113
+ * tool-driven completion; the on*Failure handlers for failure paths) —
114
+ * by the time we reach onComplete those have already happened.
110
115
  */
111
116
  private onComplete;
117
+ /**
118
+ * Persists the current browser session state if the flow's config has
119
+ * `persistState` enabled. Must be called BEFORE every site that commits
120
+ * a terminal `state` to persistence — otherwise a frontend that polls
121
+ * for the flow's state can observe "complete" between the metadata
122
+ * write and the session-state upload, fire an eager browser-state
123
+ * fetch (e.g. FlowDeveloperTools auto-loads on terminal), and 404 until
124
+ * the upload finishes.
125
+ *
126
+ * The browser context typically survives all-pages-closed (the read
127
+ * goes against the context, not a specific page), so this is also
128
+ * safe to call from the failure handlers like onTargetClosed.
129
+ */
130
+ private persistTerminalSessionStateIfNeeded;
112
131
  /**
113
132
  * Attempt to POST a JSON body containing given flow ID to the given
114
133
  * ${@link callbackUrl} if the URL is non-null. Note that there is no retying
@@ -218,6 +218,7 @@ class DonobuFlow {
218
218
  this.metadata.state = 'FAILED';
219
219
  Logger_1.appLogger.error(result.reason);
220
220
  this.metadata.result = { failed: result.reason };
221
+ await this.persistTerminalSessionStateIfNeeded();
221
222
  await this.persistence.setFlowMetadata(this.metadata);
222
223
  }
223
224
  }
@@ -232,6 +233,7 @@ class DonobuFlow {
232
233
  failed: `Stopped flow due to the ${this.gptClient?.config.type} GPT platform throwing an internal error!`,
233
234
  context: error.message,
234
235
  };
236
+ await this.persistTerminalSessionStateIfNeeded();
235
237
  await this.persistence.setFlowMetadata(this.metadata);
236
238
  }
237
239
  /**
@@ -247,6 +249,7 @@ class DonobuFlow {
247
249
  : `Your ${platform} API quota has been exhausted. Please check your account's billing and usage limits; this may happen if there is a lack of funds in the account`;
248
250
  Logger_1.appLogger.error(failedMessage, error);
249
251
  this.metadata.result = { failed: failedMessage };
252
+ await this.persistTerminalSessionStateIfNeeded();
250
253
  await this.persistence.setFlowMetadata(this.metadata);
251
254
  }
252
255
  /**
@@ -341,18 +344,38 @@ class DonobuFlow {
341
344
  this.metadata.result = {
342
345
  failed: 'Internal error 🙈',
343
346
  };
347
+ await this.persistTerminalSessionStateIfNeeded();
344
348
  await this.persistence.setFlowMetadata(this.metadata);
345
349
  }
346
350
  /**
347
351
  * This method is called when a flow is complete (i.e. when {@link DonobuFlow.run} should return).
352
+ *
353
+ * Browser session state and the final metadata write are committed by
354
+ * whichever code path produced the terminal state (transitionState for
355
+ * tool-driven completion; the on*Failure handlers for failure paths) —
356
+ * by the time we reach onComplete those have already happened.
348
357
  */
349
358
  async onComplete() {
350
- await this.persistence.setFlowMetadata(this.metadata);
359
+ DonobuFlow.invokeFlowFinishedCallback(this.metadata.callbackUrl, this.metadata.id);
360
+ this.controlPanel.close();
361
+ }
362
+ /**
363
+ * Persists the current browser session state if the flow's config has
364
+ * `persistState` enabled. Must be called BEFORE every site that commits
365
+ * a terminal `state` to persistence — otherwise a frontend that polls
366
+ * for the flow's state can observe "complete" between the metadata
367
+ * write and the session-state upload, fire an eager browser-state
368
+ * fetch (e.g. FlowDeveloperTools auto-loads on terminal), and 404 until
369
+ * the upload finishes.
370
+ *
371
+ * The browser context typically survives all-pages-closed (the read
372
+ * goes against the context, not a specific page), so this is also
373
+ * safe to call from the failure handlers like onTargetClosed.
374
+ */
375
+ async persistTerminalSessionStateIfNeeded() {
351
376
  if (this.metadata.web?.browser?.persistState) {
352
377
  await this.targetInspector.persistSessionState(this.persistence, this.metadata.id);
353
378
  }
354
- DonobuFlow.invokeFlowFinishedCallback(this.metadata.callbackUrl, this.metadata.id);
355
- this.controlPanel.close();
356
379
  }
357
380
  /**
358
381
  * Attempt to POST a JSON body containing given flow ID to the given
@@ -623,8 +646,14 @@ Message: ${dialog.message()}`;
623
646
  // the result object before the final state is set. If we did not do
624
647
  // this, then someone polling for a flow's state may see the flow
625
648
  // finished but still see a null result.
649
+ //
650
+ // The same rationale applies to the browser session state: an eager
651
+ // fetch from the frontend (e.g. FlowDeveloperTools auto-loads on
652
+ // terminal state) would otherwise race the upload that onComplete
653
+ // performs and 404 until the user manually refreshed.
626
654
  if ((0, FlowMetadata_1.isComplete)(nextState)) {
627
655
  this.metadata.result = await this.createResultJson(nextState);
656
+ await this.persistTerminalSessionStateIfNeeded();
628
657
  }
629
658
  const lastState = this.metadata.state;
630
659
  this.metadata.state = nextState;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "donobu",
3
- "version": "5.27.0",
3
+ "version": "5.27.2",
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",