UNPKG

donobu

Version:

Create browser automations with an LLM agent and replay them as Playwright scripts.

218 lines 8.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FlowsPersistenceVolatile = void 0; const FlowNotFoundException_1 = require("../../exceptions/FlowNotFoundException"); const MiscUtils_1 = require("../../utils/MiscUtils"); /** * A volatile (in-memory) implementation of FlowsPersistence. */ class FlowsPersistenceVolatile { constructor(flows = new Map(), screenshots = new Map(), toolCalls = new Map(), videos = new Map(), files = new Map(), browserStates = new Map(), aiQueries = new Map()) { this.flows = flows; this.screenshots = screenshots; this.toolCalls = toolCalls; this.videos = videos; this.files = files; this.browserStates = browserStates; this.aiQueries = aiQueries; } async setFlowMetadata(flowMetadata) { this.flows.set(flowMetadata.id, { ...flowMetadata }); } async getFlowMetadataById(flowId) { const metadata = this.flows.get(flowId); if (!metadata) { throw FlowNotFoundException_1.FlowNotFoundException.forId(flowId); } return { ...metadata }; } async getFlowMetadataByName(flowName) { const matches = Array.from(this.flows.values()).filter((flow) => flow.name === flowName); if (matches.length === 0) { throw FlowNotFoundException_1.FlowNotFoundException.forName(flowName); } // Return the one with the latest startedAt matches.sort((a, b) => (b.startedAt || 0) - (a.startedAt || 0)); return { ...matches[0] }; } /** * Get flows with pagination and filtering from in-memory storage. */ async getFlowsMetadata(query) { const { limit = 20, pageToken, name, partialName, runMode, state, testId, orphaned, startedAfter, startedBefore, sortBy, sortOrder, } = query || {}; // Validate inputs. const validLimit = Math.min(Math.max(1, limit), 100); // Get all flows let filteredFlows = Array.from(this.flows.values()); // Apply filters // partialName takes precedence over name if both are provided. if (partialName) { const lower = partialName.toLowerCase(); filteredFlows = filteredFlows.filter((flow) => flow.name?.toLowerCase().includes(lower)); } else 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); } if (testId) { filteredFlows = filteredFlows.filter((flow) => flow.testId === testId); } if (orphaned === true) { filteredFlows = filteredFlows.filter((flow) => flow.testId === null || flow.testId === undefined); } else if (orphaned === false) { filteredFlows = filteredFlows.filter((flow) => flow.testId !== null && flow.testId !== undefined); } // 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); } const sortCol = sortBy ?? 'created_at'; const sortAsc = sortOrder === 'asc'; filteredFlows.sort((a, b) => { const aVal = String(a[sortCol] ?? ''); const bVal = String(b[sortCol] ?? ''); const cmp = aVal < bVal ? -1 : aVal > bVal ? 1 : 0; return sortAsc ? cmp : -cmp; }); // 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 saveScreenShot(flowId, bytes) { if (!this.screenshots.has(flowId)) { this.screenshots.set(flowId, new Map()); } const imageType = MiscUtils_1.MiscUtils.detectImageType(bytes); const filename = `${new Date().toISOString()}.screenshot.${imageType}`; this.screenshots.get(flowId).set(filename, Buffer.from(bytes)); return filename; } async getScreenShot(flowId, screenShotId) { return this.getFlowFile(flowId, screenShotId); } async setToolCall(flowId, toolCall) { if (!this.toolCalls.has(flowId)) { this.toolCalls.set(flowId, []); } const calls = this.toolCalls.get(flowId); const existingIndex = calls.findIndex((c) => c.id === toolCall.id); if (existingIndex >= 0) { calls[existingIndex] = { ...toolCall }; } else { calls.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)); } async deleteToolCall(flowId, toolCallId) { if (!this.flows.has(flowId)) { throw FlowNotFoundException_1.FlowNotFoundException.forId(flowId); } const calls = this.toolCalls.get(flowId); if (!calls || calls.length === 0) { return; } const index = calls.findIndex((call) => call.id === toolCallId); if (index !== -1) { calls.splice(index, 1); } if (calls.length === 0) { this.toolCalls.delete(flowId); } } async setAiQuery(flowId, aiQuery) { if (!this.aiQueries.has(flowId)) { this.aiQueries.set(flowId, []); } const queries = this.aiQueries.get(flowId); const existingIndex = queries.findIndex((q) => q.id === aiQuery.id); if (existingIndex >= 0) { queries[existingIndex] = { ...aiQuery }; } else { queries.push({ ...aiQuery }); } } async getAiQueries(flowId) { if (!this.flows.has(flowId)) { throw FlowNotFoundException_1.FlowNotFoundException.forId(flowId); } const queries = this.aiQueries.get(flowId) || []; return [...queries].sort((a, b) => a.startedAt - b.startedAt); } 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.aiQueries.delete(flowId); this.videos.delete(flowId); this.files.delete(flowId); this.browserStates.delete(flowId); } } exports.FlowsPersistenceVolatile = FlowsPersistenceVolatile; //# sourceMappingURL=FlowsPersistenceVolatile.js.map