diff --git a/.changeset/slick-tires-brake.md b/.changeset/slick-tires-brake.md new file mode 100644 index 0000000..054feca --- /dev/null +++ b/.changeset/slick-tires-brake.md @@ -0,0 +1,6 @@ +--- +"@durable-agent/agent": patch +"@durable-agent/core": patch +--- + +made durable-tool more durable diff --git a/apps/playground/package.json b/apps/playground/package.json index 920ca48..0b965d6 100644 --- a/apps/playground/package.json +++ b/apps/playground/package.json @@ -12,6 +12,10 @@ "retry": "tsx src/error-retry.ts", "blog": "tsx src/blog-pipeline.ts", "parallel": "tsx src/parallel-research.ts", + "server": "tsx src/sleep-server.ts", + "server:dev": "tsx watch src/sleep-server.ts", + "express": "tsx src/express-example.ts", + "express:dev": "tsx watch src/express-example.ts", "build": "tsc --build", "typecheck": "tsc --noEmit" }, @@ -21,10 +25,12 @@ "@durable-agent/core": "workspace:*", "@openworkflow/backend-postgres": "^0.4.0", "dotenv": "^16.4.5", + "express": "^4.21.2", "openworkflow": "^0.4.1", "zod": "^3.24.1" }, "devDependencies": { + "@types/express": "^5.0.0", "@types/node": "^22.10.2", "tsx": "^4.19.2", "typescript": "^5.7.2" diff --git a/apps/playground/src/express-example.ts b/apps/playground/src/express-example.ts new file mode 100644 index 0000000..4de8f05 --- /dev/null +++ b/apps/playground/src/express-example.ts @@ -0,0 +1,178 @@ +import "dotenv/config"; +import express, { Request, Response } from "express"; +import { DurableAgent, tool } from "@durable-agent/agent"; +import { BackendPostgres } from "@openworkflow/backend-postgres"; +import { openai } from "@ai-sdk/openai"; +import { z } from "zod"; + +const app = express(); +const PORT = process.env.PORT || 3000; + +app.use(express.json()); + +let durableAgent: DurableAgent; +let researcher: ReturnType; + +async function initDurableAgent() { + const backend = await BackendPostgres.connect(process.env.DATABASE_URL || ""); + + durableAgent = new DurableAgent({ + backend, + model: openai("gpt-4o"), + concurrency: 10, + }); + + researcher = durableAgent.defineAgent({ + name: "olaedo-v5-sleep", + system: + "You are a helpful research assistant. Provide concise, informative answers.", + tools: { + search: tool({ + description: + "Search for information on a topic (takes ~1 hour to process)", + parameters: z.object({ + query: z.string().describe("The search query"), + }), + execute: async ({ query }, ctx) => { + // 1. Do work BEFORE sleep (this gets cached) + const searchId = await ctx.step.run("initiate-search", async () => { + console.log(`Starting search for: ${query}`); + // Simulate starting a long-running search job + return { id: `search-${Date.now()}`, query }; + }); + + // 2. Sleep - workflow pauses here, worker released + await ctx.step.sleep("5m"); + + // 3. Do work AFTER sleep (this runs when resumed) + const results = await ctx.step.run("get-results", async () => { + console.log(`Getting results for search: ${searchId.id}`); + // Simulate fetching results after the wait + return { + query: searchId.query, + results: [ + `Result 1 for "${searchId.query}"`, + `Result 2 for "${searchId.query}"`, + `Result 3 for "${searchId.query}"`, + ], + }; + }); + + // 4. Return meaningful result to LLM + return `Search results for "${ + results.query + }":\n${results.results.join("\n")}`; + }, + }), + }, + maxIterations: 5, + }); + + await durableAgent.start(); + console.log("Durable Agent started"); +} + +app.get("/", (_req: Request, res: Response) => { + res.json({ message: "Durable Agent Express App" }); +}); + +app.get("/health", (_req: Request, res: Response) => { + res.json({ status: "ok" }); +}); + +// Start agent - returns immediately with runId +app.post("/agent/run", async (req: Request, res: Response) => { + try { + const { task } = req.body; + + if (!task) { + res.status(400).json({ error: "Task is required" }); + return; + } + + const handle = await researcher.run({ task }); + + console.log("this is the json: ", JSON.stringify(handle, null, 2)); + + // Return immediately - don't wait for result! + res.json({ + runId: handle.id, + message: "Agent started. Use /agent/:id/status to check progress.", + }); + } catch (error) { + console.error("Agent error:", error); + res.status(500).json({ error: "Agent execution failed" }); + } +}); + +// Check status - non-blocking +app.get("/agent/:id/status", async (req: Request, res: Response) => { + try { + const handle = durableAgent.getHandle(req.params.id || ""); + const description = await handle.describe(); + + res.json({ + runId: req.params.id, + state: description.state, + availableAt: description.availableAt, + startedAt: description.startedAt, + completedAt: description.completedAt, + error: description.error, + // Only include output if completed + ...(description.state === "completed" && { output: description.output }), + }); + } catch (error) { + console.error("Status error:", error); + res.status(500).json({ error: "Failed to get status" }); + } +}); + +// Get result - blocking (waits for completion) +app.get("/agent/:id/result", async (req: Request, res: Response) => { + try { + const handle = durableAgent.getHandle(req.params.id || ""); + + // This blocks until complete - use with caution! + const result = await handle.result(); + + res.json({ + status: result.status, + output: result.output, + iterations: result.iterations, + }); + } catch (error) { + console.error("Result error:", error); + res.status(500).json({ error: "Failed to get result" }); + } +}); + +// Cancel a running agent + +app.post("/agent/:id/cancel", async (req: Request, res: Response) => { + try { + const handle = durableAgent.getHandle(req.params.id || ""); + await handle.cancel(); + res.json({ message: "Agent cancelled" }); + } catch (error) { + console.error("Cancel error:", error); + res.status(500).json({ error: "Failed to cancel" }); + } +}); + +async function main() { + await initDurableAgent(); + + app.listen(PORT, () => { + console.log(`Server is running on http://localhost:${PORT}`); + }); +} + +main().catch(console.error); + +process.on("SIGINT", async () => { + console.log("Shutting down..."); + if (durableAgent) { + await durableAgent.stop(); + } + process.exit(0); +}); diff --git a/apps/playground/src/sleep-server.ts b/apps/playground/src/sleep-server.ts new file mode 100644 index 0000000..c76151d --- /dev/null +++ b/apps/playground/src/sleep-server.ts @@ -0,0 +1,290 @@ +/** + * Sleep Server Example + * + * Demonstrates how to use durable tools with sleep in an Express server. + * The workflow properly pauses during sleep and resumes after the duration. + * + * Run with: pnpm --filter @durable-agent/playground server + * + * API Endpoints: + * POST /agent/run - Start a new agent run (returns runId immediately) + * GET /agent/:id/status - Check status (non-blocking) + * GET /agent/:id/result - Wait for result (blocking) + * POST /agent/:id/cancel - Cancel a running agent + */ + +import "dotenv/config"; +import express, { Request, Response } from "express"; +import { DurableAgent, tool } from "@durable-agent/agent"; +import { BackendPostgres } from "@openworkflow/backend-postgres"; +import { openai } from "@ai-sdk/openai"; +import { z } from "zod"; + +const app = express(); +const PORT = process.env.PORT || 3000; + +app.use(express.json()); + +let durableAgent: DurableAgent; +let researcher: ReturnType; +let summarizer: ReturnType; +let sequentialPipeline: ReturnType; + +async function initDurableAgent() { + const backend = await BackendPostgres.connect(process.env.DATABASE_URL || ""); + + durableAgent = new DurableAgent({ + backend, + model: openai("gpt-4o"), + concurrency: 10, + }); + + researcher = durableAgent.defineAgent({ + name: "researcher-sleep-example", + system: + "You are a helpful research assistant. Use the search tool to find information. Provide concise, informative answers based on the search results.", + tools: { + search: tool({ + description: + "Search for information on a topic. This search takes time to process - results will be available after the processing completes.", + parameters: z.object({ + query: z.string().describe("The search query"), + }), + execute: async ({ query }, ctx) => { + // 1. Do work BEFORE sleep (this gets cached) + const searchId = await ctx.step.run("initiate-search", async () => { + console.log(`[${new Date().toISOString()}] Starting search for: ${query}`); + // Simulate starting a long-running search job + return { id: `search-${Date.now()}`, query }; + }); + + // 2. Sleep - workflow pauses here, worker released + // Change this duration for testing (e.g., "10s", "1m", "1h") + await ctx.step.sleep("2m"); + + // 3. Do work AFTER sleep (this runs when resumed) + const results = await ctx.step.run("get-results", async () => { + console.log(`[${new Date().toISOString()}] Getting results for search: ${searchId.id}`); + // Simulate fetching results after the wait + return { + query: searchId.query, + results: [ + `Result 1 for "${searchId.query}": This is the first finding from our comprehensive search.`, + `Result 2 for "${searchId.query}": Here is additional relevant information discovered.`, + `Result 3 for "${searchId.query}": Final insight from the search results.`, + ], + }; + }); + + // 4. Return meaningful result to LLM + return `Search completed for "${results.query}":\n\n${results.results.join("\n\n")}`; + }, + }), + }, + maxIterations: 10, + }); + + // Define a summarizer agent with a tool that also sleeps + summarizer = durableAgent.defineAgent({ + name: "summarizer-sleep-example", + system: + "You are a summarization expert. Use the summarize tool to process and summarize the research provided.", + tools: { + summarize: tool({ + description: "Process and summarize research content. Takes a short time to analyze.", + parameters: z.object({ + content: z.string().describe("The content to summarize"), + }), + execute: async ({ content }, ctx) => { + // 1. Start processing + const processId = await ctx.step.run("start-summary", async () => { + console.log(`[${new Date().toISOString()}] Starting summarization...`); + return { id: `summary-${Date.now()}`, contentLength: content.length }; + }); + + // 2. Short sleep (30 seconds) + await ctx.step.sleep("1m"); + + // 3. Return processed summary + const result = await ctx.step.run("finish-summary", async () => { + console.log(`[${new Date().toISOString()}] Summarization complete for ${processId.id}`); + return `Summary of ${processId.contentLength} characters:\n\n${content.slice(0, 200)}...\n\n[Processed after 2m delay]`; + }); + + return result; + }, + }), + }, + maxIterations: 10, + }); + + // Define a sequential pipeline: researcher -> summarizer + // The researcher will sleep, then the summarizer will process the results + sequentialPipeline = durableAgent.sequentialAgent({ + name: "research-and-summarize-pipeline", + agents: [researcher, summarizer], + }); + + await durableAgent.start(); + console.log("Durable Agent started"); +} + +app.get("/", (_req: Request, res: Response) => { + res.json({ + message: "Durable Agent Sleep Example Server", + endpoints: { + "POST /agent/run": "Start a single agent run", + "POST /sequential/run": "Start sequential pipeline (researcher -> summarizer)", + "GET /agent/:id/status": "Check status (non-blocking)", + "GET /agent/:id/result": "Wait for result (blocking)", + "POST /agent/:id/cancel": "Cancel a running agent", + }, + }); +}); + +app.get("/health", (_req: Request, res: Response) => { + res.json({ status: "ok" }); +}); + +// Start single agent - returns immediately with runId +app.post("/agent/run", async (req: Request, res: Response) => { + try { + const { task } = req.body; + + if (!task) { + res.status(400).json({ error: "Task is required" }); + return; + } + + console.log(`[${new Date().toISOString()}] Starting agent with task: ${task}`); + const handle = await researcher.run({ task }); + + // Return immediately - don't wait for result! + res.json({ + runId: handle.id, + message: "Agent started. Use /agent/:id/status to check progress.", + }); + } catch (error) { + console.error("Agent error:", error); + res.status(500).json({ error: "Agent execution failed" }); + } +}); + +// Start sequential pipeline - returns immediately with runId +// Pipeline: researcher (with sleep) -> summarizer +app.post("/sequential/run", async (req: Request, res: Response) => { + try { + const { task } = req.body; + + if (!task) { + res.status(400).json({ error: "Task is required" }); + return; + } + + console.log(`[${new Date().toISOString()}] Starting sequential pipeline with task: ${task}`); + const handle = await sequentialPipeline.run({ task }); + + // Return immediately - don't wait for result! + res.json({ + runId: handle.id, + message: "Sequential pipeline started (researcher -> summarizer). Use /agent/:id/status to check progress.", + }); + } catch (error) { + console.error("Sequential pipeline error:", error); + res.status(500).json({ error: "Sequential pipeline execution failed" }); + } +}); + +// Check status - non-blocking +app.get("/agent/:id/status", async (req: Request, res: Response) => { + try { + const handle = durableAgent.getHandle(req.params.id || ""); + const description = await handle.describe(); + console.log("Description:", description); + + res.json({ + runId: req.params.id, + state: description.state, + availableAt: description.availableAt, + startedAt: description.startedAt, + completedAt: description.completedAt, + error: description.error, + // Only include output if completed + ...(description.state === "completed" && { output: description.output }), + }); + } catch (error) { + console.error("Status error:", error); + res.status(500).json({ error: "Failed to get status" }); + } +}); + +// Get result - blocking (waits for completion) +app.get("/agent/:id/result", async (req: Request, res: Response) => { + try { + const handle = durableAgent.getHandle(req.params.id || ""); + + // This blocks until complete - use with caution! + const result = await handle.result(); + + res.json({ + status: result.status, + output: result.output, + iterations: result.iterations, + }); + } catch (error) { + console.error("Result error:", error); + res.status(500).json({ error: "Failed to get result" }); + } +}); + +// Cancel a running agent +app.post("/agent/:id/cancel", async (req: Request, res: Response) => { + try { + const handle = durableAgent.getHandle(req.params.id || ""); + await handle.cancel(); + res.json({ message: "Agent cancelled" }); + } catch (error) { + console.error("Cancel error:", error); + res.status(500).json({ error: "Failed to cancel" }); + } +}); + +async function main() { + await initDurableAgent(); + + app.listen(PORT, () => { + console.log(` +======================================== + Durable Agent Sleep Example Server +======================================== + +Server running at: http://localhost:${PORT} + +Single agent test: + curl -X POST http://localhost:${PORT}/agent/run \\ + -H "Content-Type: application/json" \\ + -d '{"task": "Search for information about TypeScript"}' + +Sequential pipeline test (researcher -> summarizer): + curl -X POST http://localhost:${PORT}/sequential/run \\ + -H "Content-Type: application/json" \\ + -d '{"task": "Research the benefits of TypeScript"}' + +Check status: + curl http://localhost:${PORT}/agent//status + +Note: The search tool sleeps for 2 minutes. Watch the logs! +======================================== +`); + }); +} + +main().catch(console.error); + +process.on("SIGINT", async () => { + console.log("\nShutting down..."); + if (durableAgent) { + await durableAgent.stop(); + } + process.exit(0); +}); diff --git a/packages/agent/src/durable-agent.ts b/packages/agent/src/durable-agent.ts index eb55a31..fc13666 100644 --- a/packages/agent/src/durable-agent.ts +++ b/packages/agent/src/durable-agent.ts @@ -13,6 +13,7 @@ import type { DurableAgentConfig, DefinedAgent, AgentRunHandle, + AgentRunDescription, SequentialAgentConfig, ParallelAgentConfig, ParallelAgent, @@ -73,11 +74,7 @@ export class DurableAgent { config, run: async (input: AgentInput): Promise => { const handle = await workflow.run(input); - return { - id: handle.workflowRun.id, - result: () => handle.result() as Promise, - cancel: () => handle.cancel(), - }; + return this.createHandle(handle.workflowRun.id); }, }; } @@ -103,6 +100,138 @@ export class DurableAgent { } } + /** + * Get a handle for an existing workflow run by ID + * + * Use this to check status or wait for results of a previously started agent run + * + * @example + * ```typescript + * // Start an agent + * const handle = await researcher.run({ task: "..." }); + * const runId = handle.id; + * + * // Later, retrieve the handle + * const retrieved = durableAgent.getHandle(runId); + * const status = await retrieved.describe(); + * + * if (status.state === "completed") { + * console.log(status.output); + * } + * ``` + */ + getHandle(runId: string): AgentRunHandle { + return this.createHandle(runId); + } + + /** + * Create a handle for a workflow run + */ + private createHandle(runId: string): AgentRunHandle { + return { + id: runId, + describe: () => this.describeRun(runId), + result: () => this.waitForResult(runId), + cancel: () => this.cancelRun(runId), + }; + } + + /** + * Get the current state of a workflow run (non-blocking) + */ + private async describeRun(runId: string): Promise { + const workflowRun = await this.backend.getWorkflowRun({ + workflowRunId: runId, + }); + + if (!workflowRun) { + throw new Error(`Workflow run not found: ${runId}`); + } + + // Map OpenWorkflow status to our status + let state: AgentRunDescription["state"]; + switch (workflowRun.status) { + case "pending": + state = "pending"; + break; + case "running": + state = "running"; + break; + case "sleeping": + state = "sleeping"; + break; + case "completed": + case "succeeded": + state = "completed"; + break; + case "failed": + case "canceled": + state = "failed"; + break; + default: + state = "pending"; + } + + // Extract error message if present + const errorObj = workflowRun.error as { message?: string } | null; + const errorMessage = errorObj?.message; + + return { + state, + availableAt: workflowRun.availableAt ?? undefined, + startedAt: workflowRun.startedAt ?? undefined, + completedAt: workflowRun.finishedAt ?? undefined, + error: errorMessage, + output: + state === "completed" + ? (workflowRun.output as unknown as AgentResult | undefined) + : undefined, + }; + } + + /** + * Wait for a workflow run to complete and return the result (blocking) + */ + private async waitForResult(runId: string): Promise { + // Poll until the workflow completes + const POLL_INTERVAL_MS = 1000; + + while (true) { + const workflowRun = await this.backend.getWorkflowRun({ + workflowRunId: runId, + }); + + if (!workflowRun) { + throw new Error(`Workflow run not found: ${runId}`); + } + + if ( + workflowRun.status === "completed" || + workflowRun.status === "succeeded" + ) { + return workflowRun.output as unknown as AgentResult; + } + + if ( + workflowRun.status === "failed" || + workflowRun.status === "canceled" + ) { + const errorObj = workflowRun.error as { message?: string } | null; + throw new Error(errorObj?.message ?? `Workflow ${workflowRun.status}`); + } + + // Still running or sleeping - wait and poll again + await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS)); + } + } + + /** + * Cancel a workflow run + */ + private async cancelRun(runId: string): Promise { + await this.backend.cancelWorkflowRun({ workflowRunId: runId }); + } + /** * Create a sequential agent that runs multiple agents in order * @@ -167,11 +296,7 @@ export class DurableAgent { config: { name: config.name }, run: async (input: AgentInput): Promise => { const handle = await workflow.run(input); - return { - id: handle.workflowRun.id, - result: () => handle.result() as Promise, - cancel: () => handle.cancel(), - }; + return this.createHandle(handle.workflowRun.id); }, }; } @@ -261,11 +386,13 @@ export class DurableAgent { input: AgentInput ): Promise> => { const handle = await workflow.run(input); + const runId = handle.workflowRun.id; return { - id: handle.workflowRun.id, + id: runId, + describe: () => this.describeRun(runId), result: () => handle.result() as Promise>, - cancel: () => handle.cancel(), + cancel: () => this.cancelRun(runId), }; }, }; @@ -438,12 +565,6 @@ Continue the work based on the above.`; const fns: StrategyExecutionFunctions = { generateResponse: async (ctx) => { return stepManager.run(`llm-${ctx.iteration}`, async () => { - console.log("generate Msg input", { - model: this.model, - messages: this.convertMessages(ctx.messages), - tools: this.convertTools(ctx.tools), - maxOutputTokens: config.maxTokens, - }); const result = await generateText({ model: this.model, messages: this.convertMessages(ctx.messages), @@ -526,6 +647,11 @@ Continue the work based on the above.`; fns ); } catch (error) { + // Re-throw SleepSignal - it must propagate to OpenWorkflow to pause the workflow + if (error instanceof Error && error.name === "SleepSignal") { + throw error; + } + // Handle errors with hook if provided if (config.hooks?.onError) { const action = await config.hooks.onError( @@ -607,7 +733,6 @@ Continue the work based on the above.`; }); } } - return result; } diff --git a/packages/agent/src/index.ts b/packages/agent/src/index.ts index 34e5000..af55bb2 100644 --- a/packages/agent/src/index.ts +++ b/packages/agent/src/index.ts @@ -32,6 +32,7 @@ export type { // Composition types DefinedAgent, AgentRunHandle, + AgentRunDescription, SequentialAgentConfig, SequentialAgentHooks, ParallelAgentConfig, diff --git a/packages/agent/src/sequential-agent.test.ts b/packages/agent/src/sequential-agent.test.ts index f916e1b..a0404c6 100644 --- a/packages/agent/src/sequential-agent.test.ts +++ b/packages/agent/src/sequential-agent.test.ts @@ -43,6 +43,10 @@ function createMockAgent( return { id: `run-${name}-${Date.now()}`, + describe: async () => ({ + state: status === "completed" ? "completed" : "failed" as const, + output: result, + }), result: async () => result, cancel: async () => {}, }; @@ -314,6 +318,10 @@ describe("sequentialAgent", () => { return { id: "run-agent2", + describe: async () => ({ + state: "completed" as const, + output: result, + }), result: async () => result, cancel: async () => {}, }; @@ -615,6 +623,9 @@ function createSequentialAgentFunction( const handle = await workflow.run(input); return { id: handle.workflowRun.id, + describe: async () => ({ + state: "running" as const, + }), result: () => handle.result(), cancel: () => handle.cancel(), }; diff --git a/packages/agent/src/tool-executor.ts b/packages/agent/src/tool-executor.ts index 4c147ce..40bc210 100644 --- a/packages/agent/src/tool-executor.ts +++ b/packages/agent/src/tool-executor.ts @@ -139,6 +139,11 @@ export class ToolExecutor { isError: false, }; } catch (error) { + // Re-throw SleepSignal - it should propagate up to pause the workflow + if (error instanceof Error && error.name === "SleepSignal") { + throw error; + } + const completedAt = new Date(); const errorMessage = error instanceof Error ? error.message : String(error); @@ -164,15 +169,51 @@ export class ToolExecutor { /** * Execute multiple tool calls in parallel + * + * Uses Promise.allSettled to ensure all non-sleeping tools complete + * and are cached before any SleepSignal is propagated. This prevents + * tools from being executed twice when a workflow resumes after sleep. */ async executeAll( toolCalls: readonly ToolCall[], iteration: number, memory: Record = {} ): Promise { - return Promise.all( + const settled = await Promise.allSettled( toolCalls.map((toolCall) => this.execute(toolCall, iteration, memory)) ); + + // Separate results and errors + const results: ToolResult[] = []; + let sleepSignal: Error | null = null; + let otherError: Error | null = null; + + for (const result of settled) { + if (result.status === "fulfilled") { + results.push(result.value); + } else { + // Check if it's a SleepSignal (from OpenWorkflow) + if (result.reason?.name === "SleepSignal") { + sleepSignal = result.reason; + } else { + // Track other errors + otherError = result.reason; + } + } + } + + // If there was a sleep signal, propagate it after letting other tools complete + // This ensures completed tools are cached before the workflow sleeps + if (sleepSignal) { + throw sleepSignal; + } + + // If there was another error, throw it + if (otherError) { + throw otherError; + } + + return results; } /** diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 667a56b..e7f29a9 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -40,6 +40,7 @@ export type { // Composition types DefinedAgent, AgentRunHandle, + AgentRunDescription, SequentialAgentConfig, SequentialAgentHooks, ParallelAgentConfig, diff --git a/packages/core/src/types/agent.ts b/packages/core/src/types/agent.ts index 3e9ddd5..62f797b 100644 --- a/packages/core/src/types/agent.ts +++ b/packages/core/src/types/agent.ts @@ -184,13 +184,40 @@ export interface DefinedAgent { run(input: AgentInput): Promise; } +/** + * Description of a running agent's current state + * Returned by handle.describe() for non-blocking status checks + */ +export interface AgentRunDescription { + /** Current state of the workflow */ + readonly state: "pending" | "running" | "sleeping" | "completed" | "failed"; + /** When a sleeping workflow will become available again */ + readonly availableAt?: Date; + /** When the workflow started */ + readonly startedAt?: Date; + /** When the workflow completed (if completed or failed) */ + readonly completedAt?: Date; + /** Error message if state is "failed" */ + readonly error?: string; + /** Result output if state is "completed" */ + readonly output?: AgentResult; +} + /** * Handle for a running agent */ export interface AgentRunHandle { /** Unique identifier for this run */ readonly id: string; - /** Wait for and return the result */ + /** + * Get current state without waiting (non-blocking) + * Use this to check status, especially for long-running workflows + */ + describe(): Promise; + /** + * Wait for and return the result (blocking) + * This will not return until the workflow completes + */ result(): Promise; /** Cancel the running agent */ cancel(): Promise; @@ -290,7 +317,12 @@ export interface ParallelAgentRunHandle< > { /** Unique identifier for this run */ readonly id: string; - /** Wait for and return the result */ + /** + * Get current state without waiting (non-blocking) + * Use this to check status, especially for long-running workflows + */ + describe(): Promise; + /** Wait for and return the result (blocking) */ result(): Promise>; /** Cancel the running agent */ cancel(): Promise; diff --git a/packages/core/src/types/index.ts b/packages/core/src/types/index.ts index a113716..f172558 100644 --- a/packages/core/src/types/index.ts +++ b/packages/core/src/types/index.ts @@ -34,6 +34,7 @@ export type { DurableAgentConfig, DefinedAgent, AgentRunHandle, + AgentRunDescription, SequentialAgentConfig, SequentialAgentHooks, ParallelAgentConfig, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cb985e5..5162597 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,6 +47,9 @@ importers: dotenv: specifier: ^16.4.5 version: 16.6.1 + express: + specifier: ^4.21.2 + version: 4.22.1 openworkflow: specifier: ^0.4.1 version: 0.4.1 @@ -54,6 +57,9 @@ importers: specifier: ^3.24.1 version: 3.25.76 devDependencies: + '@types/express': + specifier: ^5.0.0 + version: 5.0.6 '@types/node': specifier: ^22.10.2 version: 22.19.3 @@ -659,15 +665,42 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@types/body-parser@1.19.6': + resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/express-serve-static-core@5.1.0': + resolution: {integrity: sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==} + + '@types/express@5.0.6': + resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==} + + '@types/http-errors@2.0.5': + resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} + '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} '@types/node@22.19.3': resolution: {integrity: sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==} + '@types/qs@6.14.0': + resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} + + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + + '@types/send@1.2.1': + resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} + + '@types/serve-static@2.2.0': + resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} + '@vercel/oidc@3.0.5': resolution: {integrity: sha512-fnYhv671l+eTTp48gB4zEsTW/YtRgRPnkI2nT7x6qw5rkI1Lq2hTmQIpHPgyThI0znLK+vX2n9XxKdXZ7BUbbw==} engines: {node: '>= 20'} @@ -701,6 +734,10 @@ packages: '@vitest/utils@2.1.9': resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==} + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + ai@6.0.3: resolution: {integrity: sha512-OOo+/C+sEyscoLnbY3w42vjQDICioVNyS+F+ogwq6O5RJL/vgWGuiLzFwuP7oHTeni/MkmX8tIge48GTdaV7QQ==} engines: {node: '>=18'} @@ -721,6 +758,9 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} @@ -733,14 +773,30 @@ packages: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} + body-parser@1.20.4: + resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + chai@5.3.3: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} @@ -756,6 +812,21 @@ packages: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} + content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + cookie-signature@1.0.7: + resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -763,6 +834,14 @@ packages: dataloader@1.4.0: resolution: {integrity: sha512-68s5jYdlvasItOJnCuI2Q9s4q98g0pCyL3HrcKJu8KNugUl8ahgmZYg38ysLTgQjjXX3H8CJLkAvWrclWfcalw==} + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -776,6 +855,14 @@ packages: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} @@ -792,13 +879,36 @@ packages: resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} engines: {node: '>=10'} + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + enquirer@2.4.1: resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} engines: {node: '>=8.6'} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} @@ -809,6 +919,9 @@ packages: engines: {node: '>=18'} hasBin: true + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} @@ -817,6 +930,10 @@ packages: estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + eventsource-parser@3.0.6: resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} engines: {node: '>=18.0.0'} @@ -825,6 +942,10 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + express@4.22.1: + resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} + engines: {node: '>= 0.10.0'} + extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} @@ -839,10 +960,22 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + finalhandler@1.3.2: + resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} + engines: {node: '>= 0.8'} + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} engines: {node: '>=6 <7 || >=8'} @@ -856,6 +989,17 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + get-tsconfig@4.13.0: resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} @@ -867,13 +1011,33 @@ packages: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + human-id@4.1.3: resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} hasBin: true + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + iconv-lite@0.7.1: resolution: {integrity: sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==} engines: {node: '>=0.10.0'} @@ -882,6 +1046,13 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -932,18 +1103,49 @@ packages: magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -952,6 +1154,10 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + node-fetch@2.7.0: resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} engines: {node: 4.x || >=6.0.0} @@ -961,6 +1167,14 @@ packages: encoding: optional: true + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + openworkflow@0.4.1: resolution: {integrity: sha512-i9uXyzih5fWCHIoE+ug4zScb5CVn4wZUNphrWKFFxTOOboYirsMsx2p6OSMBOqoCzOrW1b6FQr4OCqoZqQnNeg==} engines: {node: '>=20'} @@ -991,6 +1205,10 @@ packages: package-manager-detector@0.2.11: resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -999,6 +1217,9 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-to-regexp@0.1.12: + resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -1039,12 +1260,28 @@ packages: engines: {node: '>=14'} hasBin: true + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@2.5.3: + resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} + engines: {node: '>= 0.8'} + read-yaml-file@1.1.0: resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} engines: {node: '>=6'} @@ -1068,6 +1305,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -1076,6 +1316,17 @@ packages: engines: {node: '>=10'} hasBin: true + send@0.19.2: + resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} + engines: {node: '>= 0.8.0'} + + serve-static@1.16.3: + resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} + engines: {node: '>= 0.8.0'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1084,6 +1335,22 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -1108,6 +1375,10 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} @@ -1145,6 +1416,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -1187,6 +1462,10 @@ packages: resolution: {integrity: sha512-5JIA5aYBAJSAhrhbyag1ZuMSgUZnHtI+Sq3H8D3an4fL8PeF+L1yYvbEJg47akP1PFfATMf5ehkqFnxfkmuwZQ==} hasBin: true + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -1199,6 +1478,18 @@ packages: resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} engines: {node: '>= 4.0.0'} + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + vite-node@2.1.9: resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -1729,14 +2020,51 @@ snapshots: '@standard-schema/spec@1.1.0': {} + '@types/body-parser@1.19.6': + dependencies: + '@types/connect': 3.4.38 + '@types/node': 22.19.3 + + '@types/connect@3.4.38': + dependencies: + '@types/node': 22.19.3 + '@types/estree@1.0.8': {} + '@types/express-serve-static-core@5.1.0': + dependencies: + '@types/node': 22.19.3 + '@types/qs': 6.14.0 + '@types/range-parser': 1.2.7 + '@types/send': 1.2.1 + + '@types/express@5.0.6': + dependencies: + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 5.1.0 + '@types/serve-static': 2.2.0 + + '@types/http-errors@2.0.5': {} + '@types/node@12.20.55': {} '@types/node@22.19.3': dependencies: undici-types: 6.21.0 + '@types/qs@6.14.0': {} + + '@types/range-parser@1.2.7': {} + + '@types/send@1.2.1': + dependencies: + '@types/node': 22.19.3 + + '@types/serve-static@2.2.0': + dependencies: + '@types/http-errors': 2.0.5 + '@types/node': 22.19.3 + '@vercel/oidc@3.0.5': {} '@vitest/expect@2.1.9': @@ -1779,6 +2107,11 @@ snapshots: loupe: 3.2.1 tinyrainbow: 1.2.0 + accepts@1.3.8: + dependencies: + mime-types: 2.1.35 + negotiator: 0.6.3 + ai@6.0.3(zod@3.25.76): dependencies: '@ai-sdk/gateway': 3.0.2(zod@3.25.76) @@ -1797,6 +2130,8 @@ snapshots: argparse@2.0.1: {} + array-flatten@1.1.1: {} + array-union@2.1.0: {} assertion-error@2.0.1: {} @@ -1805,12 +2140,41 @@ snapshots: dependencies: is-windows: 1.0.2 + body-parser@1.20.4: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.14.0 + raw-body: 2.5.3 + type-is: 1.6.18 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + braces@3.0.3: dependencies: fill-range: 7.1.1 + bytes@3.1.2: {} + cac@6.7.14: {} + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + chai@5.3.3: dependencies: assertion-error: 2.0.1 @@ -1825,6 +2189,16 @@ snapshots: ci-info@3.9.0: {} + content-disposition@0.5.4: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + + cookie-signature@1.0.7: {} + + cookie@0.7.2: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -1833,12 +2207,20 @@ snapshots: dataloader@1.4.0: {} + debug@2.6.9: + dependencies: + ms: 2.0.0 + debug@4.4.3: dependencies: ms: 2.1.3 deep-eql@5.0.2: {} + depd@2.0.0: {} + + destroy@1.2.0: {} + detect-indent@6.1.0: {} dir-glob@3.0.1: @@ -1849,13 +2231,31 @@ snapshots: dotenv@8.6.0: {} + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + ee-first@1.1.1: {} + + encodeurl@2.0.0: {} + enquirer@2.4.1: dependencies: ansi-colors: 4.1.3 strip-ansi: 6.0.1 + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + es-module-lexer@1.7.0: {} + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + esbuild@0.21.5: optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 @@ -1911,16 +2311,56 @@ snapshots: '@esbuild/win32-ia32': 0.27.2 '@esbuild/win32-x64': 0.27.2 + escape-html@1.0.3: {} + esprima@4.0.1: {} estree-walker@3.0.3: dependencies: '@types/estree': 1.0.8 + etag@1.8.1: {} + eventsource-parser@3.0.6: {} expect-type@1.3.0: {} + express@4.22.1: + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.4 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.0.7 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.2 + fresh: 0.5.2 + http-errors: 2.0.1 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.12 + proxy-addr: 2.0.7 + qs: 6.14.0 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.2 + serve-static: 1.16.3 + setprototypeof: 1.2.0 + statuses: 2.0.2 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + extendable-error@0.1.7: {} fast-glob@3.3.3: @@ -1939,11 +2379,27 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@1.3.2: + dependencies: + debug: 2.6.9 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + find-up@4.1.0: dependencies: locate-path: 5.0.0 path-exists: 4.0.0 + forwarded@0.2.0: {} + + fresh@0.5.2: {} + fs-extra@7.0.1: dependencies: graceful-fs: 4.2.11 @@ -1959,6 +2415,26 @@ snapshots: fsevents@2.3.3: optional: true + function-bind@1.1.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + get-tsconfig@4.13.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -1976,16 +2452,40 @@ snapshots: merge2: 1.4.1 slash: 3.0.0 + gopd@1.2.0: {} + graceful-fs@4.2.11: {} + has-symbols@1.1.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + human-id@4.1.3: {} + iconv-lite@0.4.24: + dependencies: + safer-buffer: 2.1.2 + iconv-lite@0.7.1: dependencies: safer-buffer: 2.1.2 ignore@5.3.2: {} + inherits@2.0.4: {} + + ipaddr.js@1.9.1: {} + is-extglob@2.1.1: {} is-glob@4.0.3: @@ -2029,23 +2529,49 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + math-intrinsics@1.1.0: {} + + media-typer@0.3.0: {} + + merge-descriptors@1.0.3: {} + merge2@1.4.1: {} + methods@1.1.2: {} + micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime@1.6.0: {} + mri@1.2.0: {} + ms@2.0.0: {} + ms@2.1.3: {} nanoid@3.3.11: {} + negotiator@0.6.3: {} + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 + object-inspect@1.13.4: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + openworkflow@0.4.1: {} outdent@0.5.0: {} @@ -2070,10 +2596,14 @@ snapshots: dependencies: quansync: 0.2.11 + parseurl@1.3.3: {} + path-exists@4.0.0: {} path-key@3.1.1: {} + path-to-regexp@0.1.12: {} + path-type@4.0.0: {} pathe@1.1.2: {} @@ -2098,10 +2628,28 @@ snapshots: prettier@3.7.4: {} + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + quansync@0.2.11: {} queue-microtask@1.2.3: {} + range-parser@1.2.1: {} + + raw-body@2.5.3: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + read-yaml-file@1.1.0: dependencies: graceful-fs: 4.2.11 @@ -2147,16 +2695,75 @@ snapshots: dependencies: queue-microtask: 1.2.3 + safe-buffer@5.2.1: {} + safer-buffer@2.1.2: {} semver@7.7.3: {} + send@0.19.2: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.1 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serve-static@1.16.3: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.2 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 shebang-regex@3.0.0: {} + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + siginfo@2.0.0: {} signal-exit@4.1.0: {} @@ -2174,6 +2781,8 @@ snapshots: stackback@0.0.2: {} + statuses@2.0.2: {} + std-env@3.10.0: {} strip-ansi@6.0.1: @@ -2198,6 +2807,8 @@ snapshots: dependencies: is-number: 7.0.0 + toidentifier@1.0.1: {} + tr46@0.0.3: {} tsx@4.21.0: @@ -2234,12 +2845,23 @@ snapshots: turbo-windows-64: 2.7.2 turbo-windows-arm64: 2.7.2 + type-is@1.6.18: + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.35 + typescript@5.9.3: {} undici-types@6.21.0: {} universalify@0.1.2: {} + unpipe@1.0.0: {} + + utils-merge@1.0.1: {} + + vary@1.1.2: {} + vite-node@2.1.9(@types/node@22.19.3): dependencies: cac: 6.7.14