donobu
Version:
Create browser automations with an LLM agent and replay them as Playwright scripts.
149 lines • 5.72 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.FlowsPersistenceVolatile = void 0;
const FlowNotFoundException_1 = require("../exceptions/FlowNotFoundException");
/**
* A volatile (in-memory) implementation of FlowsPersistence.
*/
class FlowsPersistenceVolatile {
constructor() {
this.flows = new Map();
this.screenshots = new Map();
this.toolCalls = new Map();
this.videos = new Map();
this.files = new Map();
this.browserStates = new Map();
}
async saveMetadata(flowMetadata) {
this.flows.set(flowMetadata.id, { ...flowMetadata });
}
async getMetadataByFlowId(flowId) {
const metadata = this.flows.get(flowId);
if (!metadata) {
throw FlowNotFoundException_1.FlowNotFoundException.forId(flowId);
}
return { ...metadata };
}
async getMetadataByFlowName(flowName) {
const flows = Array.from(this.flows.values()).filter((flow) => flow.name === flowName);
if (flows.length > 0) {
return { ...flows[0] };
}
throw FlowNotFoundException_1.FlowNotFoundException.forName(flowName);
}
async savePngScreenShot(flowId, bytes) {
if (!this.screenshots.has(flowId)) {
this.screenshots.set(flowId, new Map());
}
const filename = `${new Date().toISOString()}.screenshot.png`;
this.screenshots.get(flowId).set(filename, Buffer.from(bytes));
return filename;
}
async getPngScreenShot(flowId, screenShotId) {
return this.getFlowFile(flowId, screenShotId);
}
async saveToolCall(flowId, toolCall) {
if (!this.toolCalls.has(flowId)) {
this.toolCalls.set(flowId, []);
}
this.toolCalls.get(flowId).push({ ...toolCall });
}
async getToolCalls(flowId) {
if (!this.flows.has(flowId)) {
throw FlowNotFoundException_1.FlowNotFoundException.forId(flowId);
}
const calls = this.toolCalls.get(flowId) || [];
return [...calls].sort((a, b) => (a.startedAt || 0) - (b.startedAt || 0));
}
/**
* Get flows with pagination and filtering from in-memory storage.
*/
async getFlows(query) {
const { limit = 20, pageToken, name, runMode, state, startedAfter, startedBefore, } = query || {};
// Validate inputs.
const validLimit = Math.min(Math.max(1, limit), 100);
// Get all flows
let filteredFlows = Array.from(this.flows.values());
// Apply filters
if (name) {
filteredFlows = filteredFlows.filter((flow) => flow.name === name);
}
if (runMode) {
filteredFlows = filteredFlows.filter((flow) => flow.runMode === runMode);
}
if (state) {
filteredFlows = filteredFlows.filter((flow) => flow.state === state);
}
// Apply startedAfter filter
if (startedAfter !== undefined) {
filteredFlows = filteredFlows.filter((flow) => (flow.startedAt || 0) >= startedAfter);
}
// Apply startedBefore filter
if (startedBefore !== undefined) {
filteredFlows = filteredFlows.filter((flow) => (flow.startedAt || 0) <= startedBefore);
}
// Sort by startedAt (newest first).
filteredFlows.sort((a, b) => (b.startedAt || 0) - (a.startedAt || 0));
// Parse page token to get the offset.
const offset = pageToken ? parseInt(pageToken, 10) : 0;
// Slice the array to get paginated results.
const paginatedFlows = filteredFlows.slice(offset, offset + validLimit);
// Check if there are more results.
const hasMore = offset + validLimit < filteredFlows.length;
// Calculate next page token.
const nextPageToken = hasMore
? (offset + validLimit).toString()
: undefined;
return {
items: paginatedFlows.map((flow) => ({ ...flow })), // Return copies to prevent modification
nextPageToken,
};
}
async setVideo(flowId, bytes) {
this.videos.set(flowId, Buffer.from(bytes));
}
async getVideoSegment(flowId, startOffset, length) {
const video = this.videos.get(flowId);
if (!video) {
return null;
}
const totalLength = video.length;
const adjustedLength = Math.min(length, totalLength - startOffset);
return {
bytes: video.slice(startOffset, startOffset + adjustedLength),
totalLength,
startOffset,
};
}
async getFlowFile(flowId, fileId) {
const flowFiles = this.files.get(flowId);
if (!flowFiles) {
return null;
}
const file = flowFiles.get(fileId);
return file ? Buffer.from(file) : null;
}
async setFlowFile(flowId, fileId, fileBytes) {
if (!this.files.has(flowId)) {
this.files.set(flowId, new Map());
}
this.files.get(flowId).set(fileId, Buffer.from(fileBytes));
}
async setBrowserState(flowId, browserState) {
this.browserStates.set(flowId, { ...browserState });
}
async getBrowserState(flowId) {
const state = this.browserStates.get(flowId);
return state ? { ...state } : null;
}
async deleteFlow(flowId) {
this.flows.delete(flowId);
this.screenshots.delete(flowId);
this.toolCalls.delete(flowId);
this.videos.delete(flowId);
this.files.delete(flowId);
this.browserStates.delete(flowId);
}
}
exports.FlowsPersistenceVolatile = FlowsPersistenceVolatile;
//# sourceMappingURL=FlowsPersistenceVolatile.js.map