diff --git a/README.md b/README.md index 708a3c8d..178838b6 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ docker compose up -d # Verify all services are healthy docker compose ps +curl -f http://localhost:8081/health || echo "Temporal UI not ready yet" ``` ### 4. Create Temporal Namespace diff --git a/backend/openapi.json b/backend/openapi.json index 556df8da..903d47eb 100644 --- a/backend/openapi.json +++ b/backend/openapi.json @@ -30,8 +30,15 @@ } }, "responses": { - "201": { - "description": "" + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkflowResponseDto" + } + } + } } }, "tags": [ @@ -43,7 +50,17 @@ "parameters": [], "responses": { "200": { - "description": "" + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WorkflowResponseDto" + } + } + } + } } }, "tags": [ @@ -76,7 +93,14 @@ }, "responses": { "200": { - "description": "" + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkflowResponseDto" + } + } + } } }, "tags": [ @@ -97,7 +121,14 @@ ], "responses": { "200": { - "description": "" + "description": "", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkflowResponseDto" + } + } + } } }, "tags": [ @@ -1161,14 +1192,33 @@ "type": "string" }, "type": { - "type": "string", - "enum": [ - "string", - "array", - "object", - "file", - "any", - "secret" + "oneOf": [ + { + "type": "string", + "enum": [ + "string", + "array", + "object", + "file", + "secret", + "number" + ] + }, + { + "type": "array", + "items": { + "type": "string", + "enum": [ + "string", + "array", + "object", + "file", + "secret", + "number" + ] + }, + "minItems": 1 + } ] }, "required": { @@ -1199,8 +1249,8 @@ "array", "object", "file", - "any", - "secret" + "secret", + "number" ] }, "description": { @@ -1961,6 +2011,276 @@ "viewport" ] }, + "WorkflowResponseDto": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "graph": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "nodes": { + "minItems": 1, + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "position": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ] + }, + "data": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "config": { + "default": {}, + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "label" + ] + } + }, + "required": [ + "id", + "type", + "position", + "data" + ] + } + }, + "edges": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "source": { + "type": "string" + }, + "target": { + "type": "string" + }, + "sourceHandle": { + "type": "string" + }, + "targetHandle": { + "type": "string" + } + }, + "required": [ + "id", + "source", + "target" + ] + } + }, + "viewport": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "zoom": { + "type": "number" + } + }, + "required": [ + "x", + "y", + "zoom" + ] + } + }, + "required": [ + "name", + "nodes", + "edges", + "viewport" + ] + }, + "nodes": { + "minItems": 1, + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "position": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ] + }, + "data": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "config": { + "default": {}, + "type": "object", + "propertyNames": { + "type": "string" + }, + "additionalProperties": {} + } + }, + "required": [ + "label" + ] + } + }, + "required": [ + "id", + "type", + "position", + "data" + ] + } + }, + "edges": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "source": { + "type": "string" + }, + "target": { + "type": "string" + }, + "sourceHandle": { + "type": "string" + }, + "targetHandle": { + "type": "string" + } + }, + "required": [ + "id", + "source", + "target" + ] + } + }, + "viewport": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + }, + "zoom": { + "type": "number" + } + }, + "required": [ + "x", + "y", + "zoom" + ] + }, + "compiledDefinition": { + "nullable": true + }, + "lastRun": { + "type": "string", + "nullable": true + }, + "runCount": { + "type": "integer", + "minimum": 0, + "maximum": 9007199254740991 + }, + "createdAt": { + "type": "string" + }, + "updatedAt": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "graph", + "nodes", + "edges", + "viewport", + "compiledDefinition", + "lastRun", + "runCount", + "createdAt", + "updatedAt" + ] + }, "UpdateWorkflowRequestDto": { "type": "object", "properties": { diff --git a/backend/src/__tests__/backend-integration.test.ts b/backend/src/__tests__/backend-integration.test.ts index d9d17e0a..08e223f7 100644 --- a/backend/src/__tests__/backend-integration.test.ts +++ b/backend/src/__tests__/backend-integration.test.ts @@ -8,6 +8,14 @@ import { drizzle } from 'drizzle-orm/node-postgres'; import { sql } from 'drizzle-orm'; import { Client as MinioClient } from 'minio'; import { randomUUID } from 'node:crypto'; +import { + WorkflowGraph, + WorkflowGraphSchema, + WorkflowResponse, + WorkflowNode +} from '../workflows/dto/workflow-graph.dto'; +import { WorkflowDefinition } from '../dsl/types'; +import { UploadedFile } from '../storage/storage.service'; const runIntegration = process.env.RUN_BACKEND_INTEGRATION === 'true'; @@ -17,28 +25,7 @@ const baseUrl = const api = (path: string) => `${baseUrl}${path}`; -type WorkflowNodePayload = { - id: string; - type: string; - position: { x: number; y: number }; - data: { label: string; config: Record }; -}; - -type WorkflowPayload = { - name: string; - description?: string; - nodes: WorkflowNodePayload[]; - edges: Array<{ - id: string; - source: string; - target: string; - sourceHandle?: string; - targetHandle?: string; - }>; - viewport: { x: number; y: number; zoom: number }; -}; - -const normalizeNode = (override: Partial = {}): WorkflowNodePayload => ({ +const normalizeNode = (override: Partial = {}): WorkflowNode => ({ id: override.id ?? 'node-1', type: override.type ?? 'core.trigger.manual', position: override.position ?? { x: 0, y: 0 }, @@ -48,17 +35,85 @@ const normalizeNode = (override: Partial = {}): WorkflowNod }, }); -type WorkflowGraphOverrides = Partial> & { - nodes?: Array>; +type WorkflowGraphOverrides = Partial> & { + nodes?: Array>; }; -const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPayload => ({ - name: overrides.name ?? `Test Workflow ${randomUUID().slice(0, 8)}`, - description: overrides.description ?? 'Integration test workflow', - nodes: (overrides.nodes ?? [normalizeNode()]).map((node) => normalizeNode(node)), - edges: overrides.edges ?? [], - viewport: overrides.viewport ?? { x: 0, y: 0, zoom: 1 }, -}); +const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowGraph => { + const baseGraph: WorkflowGraph = { + name: overrides.name ?? `Test Workflow ${randomUUID().slice(0, 8)}`, + description: overrides.description ?? 'Integration test workflow', + nodes: (overrides.nodes ?? [normalizeNode()]).map((node) => normalizeNode(node)), + edges: overrides.edges ?? [], + viewport: overrides.viewport ?? { x: 0, y: 0, zoom: 1 }, + }; + + // Validate with Zod schema to ensure correct structure + return WorkflowGraphSchema.parse(baseGraph); +}; + +const readJson = async (response: Response): Promise => + (await response.json()) as T; + +type ComponentPortType = 'string' | 'array' | 'object' | 'file' | 'secret' | 'number'; + +interface Component { + id: string; + slug: string; + name: string; + version: string; + type: string; + category: string; + description: string; + documentation: string; + documentationUrl: string | null; + icon: string | null; + logo: string | null; + author: { + name: string; + type: 'shipsecai' | 'community'; + url: string | null; + } | null; + isLatest: boolean; + deprecated: boolean; + example: string | null; + runner: { + kind: 'inline' | 'docker' | 'remote'; + image: string | null; + command: string[] | null; + }; + inputs: Array<{ + id: string; + label: string; + type: ComponentPortType | ComponentPortType[]; + required: boolean; + description: string | null; + }>; + outputs: Array<{ + id: string; + label: string; + type: ComponentPortType; + description: string | null; + }>; + parameters: Array<{ + id: string; + label: string; + type: 'text' | 'textarea' | 'number' | 'boolean' | 'select' | 'multi-select' | 'json' | 'secret'; + required: boolean; + default: any; + placeholder: string | null; + description: string | null; + helpText: string | null; + options: Array<{ + label: string; + value: any; + }> | null; + min: number | null; + max: number | null; + rows: number | null; + }>; + examples: string[]; +} (runIntegration ? describe : describe.skip)('Backend Integration Tests', () => { let app: INestApplication; @@ -118,7 +173,7 @@ const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPay it('should list workflows (basic connectivity test)', async () => { const response = await fetch(api('/workflows')); expect(response.ok).toBe(true); - const data = await response.json(); + const data = await readJson(response); expect(Array.isArray(data)).toBe(true); }); }); @@ -134,7 +189,7 @@ const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPay }); expect(response.ok).toBe(true); - const workflow = await response.json(); + const workflow: WorkflowResponse = await readJson(response); expect(workflow).toHaveProperty('id'); expect(workflow.name).toBe(workflowData.name); expect(workflow.description).toBe(workflowData.description); @@ -156,10 +211,10 @@ const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPay const response = await fetch(api('/workflows')); expect(response.ok).toBe(true); - const workflows = await response.json(); + const workflows: WorkflowResponse[] = await readJson(response); expect(Array.isArray(workflows)).toBe(true); expect(workflows.length).toBeGreaterThanOrEqual(2); - workflows.forEach((w: any) => { + workflows.forEach((w) => { expect(Array.isArray(w.nodes)).toBe(true); expect(w.nodes[0]).toHaveProperty('data'); }); @@ -172,12 +227,12 @@ const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPay headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(buildWorkflowGraph({ name: 'Test Workflow' })), }); - const created = await createResponse.json(); + const created: WorkflowResponse = await readJson(createResponse); // Get the workflow const response = await fetch(api(`/workflows/${created.id}`)); expect(response.ok).toBe(true); - const workflow = await response.json(); + const workflow: WorkflowResponse = await readJson(response); expect(workflow.id).toBe(created.id); expect(workflow.name).toBe('Test Workflow'); expect(workflow.nodes[0].data.label).toBe('Manual Trigger'); @@ -194,7 +249,7 @@ const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPay headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(originalGraph), }); - const created = await createResponse.json(); + const created: WorkflowResponse = await readJson(createResponse); // Verify the workflow was created expect(created).toHaveProperty('id'); @@ -220,7 +275,7 @@ const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPay }); expect(updateResponse.ok).toBe(true); - const updated = await updateResponse.json(); + const updated: WorkflowResponse = await readJson(updateResponse); expect(updated.name).toBe('Updated Title'); expect(updated.description).toBe('Updated description'); expect(updated.nodes[0].data.label).toBe('Updated Trigger'); @@ -236,14 +291,14 @@ const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPay headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(buildWorkflowGraph({ name: 'Commit Workflow' })), }); - const workflow = await createResponse.json(); + const workflow: WorkflowResponse = await readJson(createResponse); const response = await fetch(api(`/workflows/${workflow.id}/commit`), { method: 'POST', }); expect(response.ok).toBe(true); - const compiled = await response.json(); + const compiled: WorkflowDefinition = await readJson(response); expect(compiled.title).toBe('Commit Workflow'); expect(compiled.entrypoint.ref).toBe(workflow.nodes[0].id); expect(Array.isArray(compiled.actions)).toBe(true); @@ -261,7 +316,7 @@ const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPay headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(invalidGraph), }); - const workflow = await createResponse.json(); + const workflow: WorkflowResponse = await readJson(createResponse); const response = await fetch(api(`/workflows/${workflow.id}/commit`), { method: 'POST', @@ -287,7 +342,7 @@ const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPay }); expect(response.ok).toBe(true); - const file = await response.json(); + const file: UploadedFile = await readJson(response); expect(file).toHaveProperty('id'); expect(file.fileName).toBe(fileName); expect(file.mimeType).toBe('text/plain'); @@ -307,15 +362,15 @@ const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPay method: 'POST', body: formData, }); - const uploadedFile = await uploadResponse.json(); + const uploadedFile: UploadedFile = await readJson(uploadResponse); // List files const response = await fetch(api('/files')); expect(response.ok).toBe(true); - const files = await response.json(); + const files: UploadedFile[] = await readJson(response); expect(Array.isArray(files)).toBe(true); expect(files.length).toBeGreaterThanOrEqual(1); - expect(files.some((f: any) => f.id === uploadedFile.id)).toBe(true); + expect(files.some((f) => f.id === uploadedFile.id)).toBe(true); // Cleanup await minioClient.removeObject(testBucket, uploadedFile.id); @@ -332,7 +387,7 @@ const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPay method: 'POST', body: formData, }); - const uploadedFile = await uploadResponse.json(); + const uploadedFile: UploadedFile = await readJson(uploadResponse); // Download the file const response = await fetch(api(`/files/${uploadedFile.id}/download`)); @@ -354,7 +409,7 @@ const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPay method: 'POST', body: formData, }); - const uploadedFile = await uploadResponse.json(); + const uploadedFile: UploadedFile = await readJson(uploadResponse); // Delete the file const response = await fetch(api(`/files/${uploadedFile.id}`), { @@ -364,8 +419,8 @@ const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPay // Verify it's deleted const listResponse = await fetch(api('/files')); - const files = await listResponse.json(); - expect(files.some((f: any) => f.id === uploadedFile.id)).toBe(false); + const files: UploadedFile[] = await readJson(listResponse); + expect(files.some((f) => f.id === uploadedFile.id)).toBe(false); }); }); @@ -373,7 +428,7 @@ const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPay it('should list all components', async () => { const response = await fetch(api('/components')); expect(response.ok).toBe(true); - const components = await response.json(); + const components: Component[] = await readJson(response); expect(Array.isArray(components)).toBe(true); expect(components.length).toBeGreaterThanOrEqual(4); // We have at least 4 components registered @@ -388,7 +443,7 @@ const buildWorkflowGraph = (overrides: WorkflowGraphOverrides = {}): WorkflowPay it('should get a specific component by id', async () => { const response = await fetch(api('/components/core.trigger.manual')); expect(response.ok).toBe(true); - const component = await response.json(); + const component: Component = await readJson(response); expect(component.id).toBe('core.trigger.manual'); expect(component).toHaveProperty('name'); expect(Array.isArray(component.inputs)).toBe(true); diff --git a/backend/src/components/components.controller.ts b/backend/src/components/components.controller.ts index aa25af47..8dce9978 100644 --- a/backend/src/components/components.controller.ts +++ b/backend/src/components/components.controller.ts @@ -98,7 +98,16 @@ export class ComponentsController { properties: { id: { type: 'string' }, label: { type: 'string' }, - type: { type: 'string', enum: ['string', 'array', 'object', 'file', 'any', 'secret'] }, + type: { + oneOf: [ + { type: 'string', enum: ['string', 'array', 'object', 'file', 'secret', 'number'] }, + { + type: 'array', + items: { type: 'string', enum: ['string', 'array', 'object', 'file', 'secret', 'number'] }, + minItems: 1, + }, + ], + }, required: { type: 'boolean' }, description: { type: 'string', nullable: true }, }, @@ -111,7 +120,7 @@ export class ComponentsController { properties: { id: { type: 'string' }, label: { type: 'string' }, - type: { type: 'string', enum: ['string', 'array', 'object', 'file', 'any', 'secret'] }, + type: { type: 'string', enum: ['string', 'array', 'object', 'file', 'secret', 'number'] }, description: { type: 'string', nullable: true }, }, }, diff --git a/backend/src/main.ts b/backend/src/main.ts index cae687f1..1072d379 100644 --- a/backend/src/main.ts +++ b/backend/src/main.ts @@ -18,7 +18,6 @@ async function bootstrap() { methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], allowedHeaders: ['Content-Type', 'Authorization', 'Accept'], }); - const port = Number(process.env.PORT ?? 3211); const host = process.env.HOST ?? '0.0.0.0'; diff --git a/backend/src/trace/__tests__/log-stream.service.spec.ts b/backend/src/trace/__tests__/log-stream.service.spec.ts index b3b8fc91..2a74e48f 100644 --- a/backend/src/trace/__tests__/log-stream.service.spec.ts +++ b/backend/src/trace/__tests__/log-stream.service.spec.ts @@ -43,11 +43,11 @@ const originalFetch = global.fetch; }); it('returns log entries from Loki', async () => { - const calls: Array<{ input: RequestInfo | URL; init?: RequestInit }> = []; + const calls: Array<{ input: string | URL; init?: RequestInit }> = []; const nanoTs = (BigInt(record.firstTimestamp.getTime()) * 1000000n).toString(); // @ts-expect-error override global fetch for test - global.fetch = async (input: RequestInfo | URL, init?: RequestInit) => { + global.fetch = async (input: string | URL, init?: RequestInit) => { calls.push({ input, init }); return { ok: true, diff --git a/backend/src/workflows/__tests__/workflow-ai-agent.spec.ts b/backend/src/workflows/__tests__/workflow-ai-agent.spec.ts new file mode 100644 index 00000000..7badabe7 --- /dev/null +++ b/backend/src/workflows/__tests__/workflow-ai-agent.spec.ts @@ -0,0 +1,234 @@ +import { describe, expect, it } from 'bun:test'; + +import '@shipsec/worker/components'; + +import { WorkflowGraphSchema } from '../dto/workflow-graph.dto'; +import { compileWorkflowGraph } from '../../dsl/compiler'; +import type { WorkflowDefinition } from '../../dsl/types'; +import { WorkflowsService } from '../workflows.service'; +import type { WorkflowRepository } from '../repository/workflow.repository'; + +const workflowId = 'd177b3c0-644e-40f0-8aa2-7b4f2c13a3af'; +const now = new Date(); + +const workflowGraph = WorkflowGraphSchema.parse({ + id: workflowId, + name: 'AI Agent with Gemini routing', + description: 'Manual prompt to Gemini, forward to LangGraph-style agent, log response.', + nodes: [ + { + id: 'manual-trigger', + type: 'core.trigger.manual', + position: { x: 0, y: 0 }, + data: { + label: 'Manual Trigger', + config: { + runtimeInputs: [ + { id: 'userPrompt', label: 'User Prompt', type: 'text', required: true }, + ], + }, + }, + }, + { + id: 'gemini-chat', + type: 'core.gemini.chat', + position: { x: 320, y: 0 }, + data: { + label: 'Gemini Chat', + config: { + systemPrompt: 'Translate the request into a Gemini answer.', + userPrompt: '{{inputs.userPrompt}}', + model: 'gemini-2.5-flash', + temperature: 0.7, + maxTokens: 1024, + }, + }, + }, + { + id: 'agent-node', + type: 'core.ai.agent', + position: { x: 640, y: 160 }, + data: { + label: 'AI Agent', + config: { + systemPrompt: 'Combine Gemini output with MCP knowledge.', + temperature: 0.5, + maxTokens: 1024, + memorySize: 8, + stepLimit: 4, + }, + }, + }, + { + id: 'console-log', + type: 'core.console.log', + position: { x: 960, y: 160 }, + data: { + label: 'Console Log', + config: { + label: 'Agent Output', + }, + }, + }, + ], + edges: [ + { + id: 'manual-to-gemini', + source: 'manual-trigger', + target: 'gemini-chat', + sourceHandle: 'userPrompt', + targetHandle: 'userPrompt', + }, + { + id: 'gemini-to-agent-input', + source: 'gemini-chat', + target: 'agent-node', + sourceHandle: 'responseText', + targetHandle: 'userInput', + }, + { + id: 'gemini-to-agent-model', + source: 'gemini-chat', + target: 'agent-node', + sourceHandle: 'chatModel', + targetHandle: 'chatModel', + }, + { + id: 'agent-to-console', + source: 'agent-node', + target: 'console-log', + sourceHandle: 'responseText', + targetHandle: 'data', + }, + ], + viewport: { x: 0, y: 0, zoom: 1 }, +}); + +describe('Workflow d177b3c0-644e-40f0-8aa2-7b4f2c13a3af', () => { + it('compiles the workflow graph into ordered actions', () => { + const definition = compileWorkflowGraph(workflowGraph); + + expect(definition.entrypoint.ref).toBe('manual-trigger'); + expect(definition.actions.map((action) => action.ref)).toEqual([ + 'manual-trigger', + 'gemini-chat', + 'agent-node', + 'console-log', + ]); + + const geminiAction = definition.actions.find((action) => action.ref === 'gemini-chat'); + expect(geminiAction?.dependsOn).toEqual(['manual-trigger']); + expect(geminiAction?.inputMappings?.userPrompt).toEqual({ + sourceRef: 'manual-trigger', + sourceHandle: 'userPrompt', + }); + + const agentAction = definition.actions.find((action) => action.componentId === 'core.ai.agent'); + expect(agentAction?.dependsOn).toEqual(['gemini-chat']); + expect(agentAction?.inputMappings?.userInput).toEqual({ + sourceRef: 'gemini-chat', + sourceHandle: 'responseText', + }); + expect(agentAction?.inputMappings?.chatModel).toEqual({ + sourceRef: 'gemini-chat', + sourceHandle: 'chatModel', + }); + + const consoleAction = definition.actions.find((action) => action.ref === 'console-log'); + expect(consoleAction?.dependsOn).toEqual(['agent-node']); + expect(consoleAction?.inputMappings?.data).toEqual({ + sourceRef: 'agent-node', + sourceHandle: 'responseText', + }); + }); + + it('commits the workflow via service and persists compiled definition', async () => { + let savedDefinition: WorkflowDefinition | null = null; + + const repositoryMock: Partial = { + async findById(id: string) { + if (id !== workflowId) { + return undefined; + } + return { + id: workflowId, + name: workflowGraph.name, + description: workflowGraph.description ?? null, + graph: workflowGraph, + compiledDefinition: null, + lastRun: null, + runCount: 0, + createdAt: now, + updatedAt: now, + } as any; + }, + async saveCompiledDefinition(id: string, definition: WorkflowDefinition) { + savedDefinition = definition; + return { + id, + name: workflowGraph.name, + description: workflowGraph.description ?? null, + graph: workflowGraph, + compiledDefinition: definition, + lastRun: null, + runCount: 0, + createdAt: now, + updatedAt: now, + } as any; + }, + async create() { + throw new Error('Not implemented in test'); + }, + async update() { + throw new Error('Not implemented in test'); + }, + async delete() { + return; + }, + async list() { + return []; + }, + async incrementRunCount() { + return { + id: workflowId, + name: workflowGraph.name, + description: workflowGraph.description ?? null, + graph: workflowGraph, + compiledDefinition: savedDefinition, + lastRun: now, + runCount: 1, + createdAt: now, + updatedAt: now, + } as any; + }, + }; + + const runRepositoryMock = { + async upsert() { + return; + }, + async findByRunId() { + return undefined; + }, + }; + + const traceRepositoryMock = { + async countByType() { + return 0; + }, + }; + + const service = new WorkflowsService( + repositoryMock as WorkflowRepository, + runRepositoryMock as any, + traceRepositoryMock as any, + {} as any, + ); + + const definition = await service.commit(workflowId); + + expect(savedDefinition).not.toBeNull(); + expect(savedDefinition!.actions.length).toBe(4); + expect(definition.actions.find((action) => action.componentId === 'core.ai.agent')).toBeDefined(); + }); +}); diff --git a/backend/src/workflows/dto/workflow-graph.dto.ts b/backend/src/workflows/dto/workflow-graph.dto.ts index f1e58029..a789153d 100644 --- a/backend/src/workflows/dto/workflow-graph.dto.ts +++ b/backend/src/workflows/dto/workflow-graph.dto.ts @@ -20,6 +20,7 @@ export const WorkflowNodeSchema = z.object({ x: z.number(), y: z.number(), }), + data: WorkflowNodeDataSchema, }); @@ -41,6 +42,7 @@ export const WorkflowGraphSchema = z.object({ }); export type WorkflowGraph = z.infer; +export type WorkflowNode = z.infer; export class WorkflowGraphDto extends createZodDto(WorkflowGraphSchema) {} export class CreateWorkflowRequestDto extends WorkflowGraphDto {} @@ -109,3 +111,41 @@ export const WorkflowLogsQuerySchema = z.object({ export class WorkflowLogsQueryDto extends createZodDto(WorkflowLogsQuerySchema) {} export type WorkflowLogsQuery = z.infer; + +// API Response DTOs for flattened workflow structures +// These represent the actual API response format after the service flattens the graph fields + +// Type for service layer (with Date objects from DB) +export interface ServiceWorkflowResponse { + id: string; + name: string; + description?: string | null; + graph: z.infer; // The original stored graph + nodes: z.infer['nodes']; // Flattened from graph.nodes + edges: z.infer['edges']; // Flattened from graph.edges + viewport: z.infer['viewport']; // Flattened from graph.viewport + compiledDefinition: any | null; + lastRun: Date | null; + runCount: number; + createdAt: Date; + updatedAt: Date; +} + +// Zod schema for API response validation (with string dates for JSON serialization) +export const WorkflowResponseSchema = z.object({ + id: z.string(), + name: z.string(), + description: z.string().optional().nullable(), + graph: WorkflowGraphSchema, // The original stored graph + nodes: z.array(WorkflowNodeSchema).min(1), // Flattened from graph.nodes + edges: z.array(WorkflowEdgeSchema), // Flattened from graph.edges + viewport: WorkflowViewportSchema, // Flattened from graph.viewport + compiledDefinition: z.unknown().nullable(), + lastRun: z.string().nullable(), // Date string from JSON serialization + runCount: z.number().int().nonnegative(), + createdAt: z.string(), // Date string from JSON serialization + updatedAt: z.string(), // Date string from JSON serialization +}); + +export type WorkflowResponse = z.infer; +export class WorkflowResponseDto extends createZodDto(WorkflowResponseSchema) {} diff --git a/backend/src/workflows/workflows.controller.ts b/backend/src/workflows/workflows.controller.ts index aa4bd849..a2e89b6c 100644 --- a/backend/src/workflows/workflows.controller.ts +++ b/backend/src/workflows/workflows.controller.ts @@ -32,6 +32,10 @@ import { WorkflowLogsQuerySchema, UpdateWorkflowRequestDto, WorkflowGraphSchema, + WorkflowResponseDto, + WorkflowResponse, + WorkflowResponseSchema, + ServiceWorkflowResponse, } from './dto/workflow-graph.dto'; import { TraceService } from '../trace/trace.service'; import { WorkflowsService } from './workflows.service'; @@ -189,16 +193,20 @@ export class WorkflowsController { @Post() @UsePipes(new ZodValidationPipe(WorkflowGraphSchema)) - async create(@Body() body: CreateWorkflowRequestDto) { - return this.workflowsService.create(body); + @ApiOkResponse({ type: WorkflowResponseDto }) + async create(@Body() body: CreateWorkflowRequestDto): Promise { + const serviceResponse = await this.workflowsService.create(body); + return this.transformServiceResponseToApi(serviceResponse); } @Put(':id') + @ApiOkResponse({ type: WorkflowResponseDto }) async update( @Param('id') id: string, @Body(new ZodValidationPipe(WorkflowGraphSchema)) body: UpdateWorkflowRequestDto, - ) { - return this.workflowsService.update(id, body); + ): Promise { + const serviceResponse = await this.workflowsService.update(id, body); + return this.transformServiceResponseToApi(serviceResponse); } @Get('/runs') @@ -240,8 +248,10 @@ export class WorkflowsController { } @Get(':id') - async findOne(@Param('id') id: string) { - return this.workflowsService.findById(id); + @ApiOkResponse({ type: WorkflowResponseDto }) + async findOne(@Param('id') id: string): Promise { + const serviceResponse = await this.workflowsService.findById(id); + return this.transformServiceResponseToApi(serviceResponse); } @Delete(':id') @@ -632,7 +642,18 @@ export class WorkflowsController { } @Get() - async findAll() { - return this.workflowsService.list(); + @ApiOkResponse({ type: [WorkflowResponseDto] }) + async findAll(): Promise { + const serviceResponses = await this.workflowsService.list(); + return serviceResponses.map(response => this.transformServiceResponseToApi(response)); + } + + private transformServiceResponseToApi(serviceResponse: ServiceWorkflowResponse): WorkflowResponse { + return { + ...serviceResponse, + lastRun: serviceResponse.lastRun?.toISOString() ?? null, + createdAt: serviceResponse.createdAt.toISOString(), + updatedAt: serviceResponse.updatedAt.toISOString(), + }; } } diff --git a/backend/src/workflows/workflows.service.ts b/backend/src/workflows/workflows.service.ts index 06b09342..e76eec07 100644 --- a/backend/src/workflows/workflows.service.ts +++ b/backend/src/workflows/workflows.service.ts @@ -8,7 +8,7 @@ import { TemporalService, type WorkflowRunStatus as TemporalWorkflowRunStatus, } from '../temporal/temporal.service'; -import { WorkflowGraphDto, WorkflowGraphSchema } from './dto/workflow-graph.dto'; +import { WorkflowGraphDto, WorkflowGraphSchema, WorkflowResponse, ServiceWorkflowResponse } from './dto/workflow-graph.dto'; import { WorkflowRecord, WorkflowRepository, @@ -74,7 +74,7 @@ export class WorkflowsService { private readonly temporalService: TemporalService, ) {} - async create(dto: WorkflowGraphDto): Promise { + async create(dto: WorkflowGraphDto): Promise { const input = this.parse(dto); const record = await this.repository.create(input); const flattened = this.flattenWorkflowGraph(record); @@ -84,7 +84,7 @@ export class WorkflowsService { return flattened; } - async update(id: string, dto: WorkflowGraphDto): Promise { + async update(id: string, dto: WorkflowGraphDto): Promise { const input = this.parse(dto); const record = await this.repository.update(id, input); const flattened = this.flattenWorkflowGraph(record); @@ -94,7 +94,7 @@ export class WorkflowsService { return flattened; } - async findById(id: string): Promise { + async findById(id: string): Promise { const record = await this.repository.findById(id); if (!record) { throw new NotFoundException(`Workflow ${id} not found`); @@ -102,14 +102,14 @@ export class WorkflowsService { return this.flattenWorkflowGraph(record); } - private flattenWorkflowGraph(record: WorkflowRecord): WorkflowRecord { + private flattenWorkflowGraph(record: WorkflowRecord): ServiceWorkflowResponse { // Flatten graph.{nodes, edges, viewport} to top level for API compatibility return { ...record, nodes: record.graph.nodes, edges: record.graph.edges, viewport: record.graph.viewport, - } as WorkflowRecord; + }; } async delete(id: string): Promise { @@ -117,7 +117,7 @@ export class WorkflowsService { this.logger.log(`Deleted workflow ${id}`); } - async list(): Promise { + async list(): Promise { const records = await this.repository.list(); const flattened = records.map((record) => this.flattenWorkflowGraph(record)); this.logger.log(`Loaded ${flattened.length} workflow(s) from repository`); diff --git a/backend/tsconfig.json b/backend/tsconfig.json index f94598d6..e0b6482e 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -2,6 +2,7 @@ "compilerOptions": { "target": "ES2022", "module": "ESNext", + "lib": ["ES2022"], "moduleResolution": "bundler", "types": ["bun-types"], "experimentalDecorators": true, diff --git a/bun.lock b/bun.lock index cc867783..3ae98737 100644 --- a/bun.lock +++ b/bun.lock @@ -72,6 +72,7 @@ "@radix-ui/react-slot": "^1.2.3", "@shipsec/backend-client": "workspace:*", "@shipsec/shared": "workspace:*", + "ai": "^5.0.76", "autoprefixer": "^10.4.21", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -145,12 +146,15 @@ "name": "@shipsec/worker", "version": "0.1.0", "dependencies": { + "@ai-sdk/google": "^3.0.0-beta.27", + "@ai-sdk/openai": "^3.0.0-beta.34", "@grpc/grpc-js": "^1.14.0", "@shipsec/component-sdk": "*", "@shipsec/shared": "*", "@temporalio/client": "^1.11.3", "@temporalio/worker": "^1.11.3", "@temporalio/workflow": "^1.11.3", + "ai": "^6.0.0-beta.68", "dotenv": "^17.2.3", "drizzle-orm": "^0.44.6", "long": "^5.3.2", @@ -162,7 +166,6 @@ "@types/minio": "^7.1.1", "@types/node": "^20.16.11", "@types/pg": "^8.15.5", - "bun-types": "^1.2.23", "tsx": "^4.20.6", "typescript": "^5.6.3", }, @@ -171,11 +174,21 @@ "packages": { "@adobe/css-tools": ["@adobe/css-tools@4.4.4", "", {}, "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg=="], + "@ai-sdk/gateway": ["@ai-sdk/gateway@2.0.0-beta.37", "", { "dependencies": { "@ai-sdk/provider": "3.0.0-beta.8", "@ai-sdk/provider-utils": "4.0.0-beta.20", "@vercel/oidc": "3.0.3" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-7EpQSI4GnlSCupwYDuzLQH9qzifnMSWJ+urWlIPwRH/rROIzkHLn+kGdZAV1eD+wM0QIH1LY6equmD/hRu1s0A=="], + + "@ai-sdk/google": ["@ai-sdk/google@3.0.0-beta.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.0-beta.8", "@ai-sdk/provider-utils": "4.0.0-beta.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-iBDOnsrFcFeU2WCWQtGv9AtqCa0401LIao6ffGfW622xxtqjiVJhdccj3aU+7C9uwbKB0Opmx/kcpbhHXq5Qug=="], + + "@ai-sdk/openai": ["@ai-sdk/openai@3.0.0-beta.34", "", { "dependencies": { "@ai-sdk/provider": "3.0.0-beta.8", "@ai-sdk/provider-utils": "4.0.0-beta.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-qHzf4r0nxLaPeCNjOy24Wr8AG8OgngaRI7ymgn7FpVJX8Z26vsHgdvhrz4QKmSGZl5Ek6hP13XU8ykKc1wQ41w=="], + + "@ai-sdk/provider": ["@ai-sdk/provider@3.0.0-beta.8", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-DECiv2zheg6uSBk85bZAo3egIKaMwp/mdbOY/g7ndNCkVc2l2b6m98Std7Xu6Bs128eAWPsE630ilKGQ9uZcLA=="], + + "@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.0-beta.20", "", { "dependencies": { "@ai-sdk/provider": "3.0.0-beta.8", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.5" }, "peerDependencies": { "@valibot/to-json-schema": "^1.3.0", "arktype": "^2.1.22", "effect": "^3.18.4", "zod": "^3.25.76 || ^4.1.8" }, "optionalPeers": ["@valibot/to-json-schema", "arktype", "effect"] }, "sha512-5tfooQSLjpTFAHrH3AH/bduGtgqwxG+DN3Zz4yTtprThSoGMGgiYgWWqVyu0BaaR+HGwyi3KTja+WXXaJnr1uQ=="], + "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], "@asamuzakjp/css-color": ["@asamuzakjp/css-color@4.0.5", "", { "dependencies": { "@csstools/css-calc": "^2.1.4", "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "lru-cache": "^11.2.1" } }, "sha512-lMrXidNhPGsDjytDy11Vwlb6OIGrT3CmLg3VWNFyWkLWtijKl7xjvForlh8vuj0SHGjgl4qZEQzUmYTeQA2JFQ=="], - "@asamuzakjp/dom-selector": ["@asamuzakjp/dom-selector@6.7.0", "", { "dependencies": { "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", "lru-cache": "^11.2.2" } }, "sha512-GrYRsKf8oVnPHsA+4dOAnPybrhT3cQ0xykXxjj2DaOni5xOlV1T8/Nqo+iNUO7wh9bs3jViIFsxJKFzDTU/ulQ=="], + "@asamuzakjp/dom-selector": ["@asamuzakjp/dom-selector@6.6.2", "", { "dependencies": { "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", "lru-cache": "^11.2.2" } }, "sha512-+AG0jN9HTwfDLBhjhX1FKi6zlIAc/YGgEHlN/OMaHD1pOPFsC5CpYQpLkPX0aFjyaVmoq9330cQDCU4qnSL1qA=="], "@asamuzakjp/nwsapi": ["@asamuzakjp/nwsapi@2.3.9", "", {}, "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q=="], @@ -239,57 +252,57 @@ "@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="], - "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.11", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.10", "", { "os": "aix", "cpu": "ppc64" }, "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw=="], - "@esbuild/android-arm": ["@esbuild/android-arm@0.25.11", "", { "os": "android", "cpu": "arm" }, "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg=="], + "@esbuild/android-arm": ["@esbuild/android-arm@0.25.10", "", { "os": "android", "cpu": "arm" }, "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w=="], - "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.11", "", { "os": "android", "cpu": "arm64" }, "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ=="], + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.10", "", { "os": "android", "cpu": "arm64" }, "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg=="], - "@esbuild/android-x64": ["@esbuild/android-x64@0.25.11", "", { "os": "android", "cpu": "x64" }, "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g=="], + "@esbuild/android-x64": ["@esbuild/android-x64@0.25.10", "", { "os": "android", "cpu": "x64" }, "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg=="], - "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA=="], - "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ=="], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg=="], - "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.11", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA=="], + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.10", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg=="], - "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.11", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw=="], + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.10", "", { "os": "freebsd", "cpu": "x64" }, "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA=="], - "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.11", "", { "os": "linux", "cpu": "arm" }, "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw=="], + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.10", "", { "os": "linux", "cpu": "arm" }, "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg=="], - "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA=="], + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ=="], - "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.11", "", { "os": "linux", "cpu": "ia32" }, "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw=="], + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.10", "", { "os": "linux", "cpu": "ia32" }, "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ=="], - "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw=="], + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg=="], - "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ=="], + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA=="], - "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.11", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw=="], + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.10", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA=="], - "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww=="], + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.10", "", { "os": "linux", "cpu": "none" }, "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA=="], - "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.11", "", { "os": "linux", "cpu": "s390x" }, "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw=="], + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.10", "", { "os": "linux", "cpu": "s390x" }, "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew=="], - "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.11", "", { "os": "linux", "cpu": "x64" }, "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ=="], + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.10", "", { "os": "linux", "cpu": "x64" }, "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA=="], - "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg=="], + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.10", "", { "os": "none", "cpu": "arm64" }, "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A=="], - "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.11", "", { "os": "none", "cpu": "x64" }, "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A=="], + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.10", "", { "os": "none", "cpu": "x64" }, "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig=="], - "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.11", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg=="], + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.10", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw=="], - "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.11", "", { "os": "openbsd", "cpu": "x64" }, "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw=="], + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.10", "", { "os": "openbsd", "cpu": "x64" }, "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw=="], - "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ=="], + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.10", "", { "os": "none", "cpu": "arm64" }, "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag=="], - "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.11", "", { "os": "sunos", "cpu": "x64" }, "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA=="], + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.10", "", { "os": "sunos", "cpu": "x64" }, "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ=="], - "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q=="], + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw=="], - "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.11", "", { "os": "win32", "cpu": "ia32" }, "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA=="], + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.10", "", { "os": "win32", "cpu": "ia32" }, "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw=="], - "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.11", "", { "os": "win32", "cpu": "x64" }, "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA=="], + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.10", "", { "os": "win32", "cpu": "x64" }, "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw=="], "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.0", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g=="], @@ -347,11 +360,11 @@ "@jsonjoy.com/base64": ["@jsonjoy.com/base64@1.1.2", "", { "peerDependencies": { "tslib": "2" } }, "sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA=="], - "@jsonjoy.com/buffers": ["@jsonjoy.com/buffers@1.2.1", "", { "peerDependencies": { "tslib": "2" } }, "sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA=="], + "@jsonjoy.com/buffers": ["@jsonjoy.com/buffers@1.2.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-6RX+W5a+ZUY/c/7J5s5jK9UinLfJo5oWKh84fb4X0yK2q4WXEWUWZWuEMjvCb1YNUQhEAhUfr5scEGOH7jC4YQ=="], "@jsonjoy.com/codegen": ["@jsonjoy.com/codegen@1.0.0", "", { "peerDependencies": { "tslib": "2" } }, "sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g=="], - "@jsonjoy.com/json-pack": ["@jsonjoy.com/json-pack@1.21.0", "", { "dependencies": { "@jsonjoy.com/base64": "^1.1.2", "@jsonjoy.com/buffers": "^1.2.0", "@jsonjoy.com/codegen": "^1.0.0", "@jsonjoy.com/json-pointer": "^1.0.2", "@jsonjoy.com/util": "^1.9.0", "hyperdyperid": "^1.2.0", "thingies": "^2.5.0", "tree-dump": "^1.1.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg=="], + "@jsonjoy.com/json-pack": ["@jsonjoy.com/json-pack@1.16.0", "", { "dependencies": { "@jsonjoy.com/base64": "^1.1.2", "@jsonjoy.com/buffers": "^1.2.0", "@jsonjoy.com/codegen": "^1.0.0", "@jsonjoy.com/json-pointer": "^1.0.2", "@jsonjoy.com/util": "^1.9.0", "hyperdyperid": "^1.2.0", "thingies": "^2.5.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-L4/W6WRI7pXYJbPGqzYH1zJfckE/0ZP8ttNg/EPLwC+P23wSZYRmz2DNydAu2a8uc20bPlxsvWcYvDYoBJ5BYQ=="], "@jsonjoy.com/json-pointer": ["@jsonjoy.com/json-pointer@1.0.2", "", { "dependencies": { "@jsonjoy.com/codegen": "^1.0.0", "@jsonjoy.com/util": "^1.9.0" }, "peerDependencies": { "tslib": "2" } }, "sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg=="], @@ -371,7 +384,7 @@ "@nestjs/platform-express": ["@nestjs/platform-express@10.4.20", "", { "dependencies": { "body-parser": "1.20.3", "cors": "2.8.5", "express": "4.21.2", "multer": "2.0.2", "tslib": "2.8.1" }, "peerDependencies": { "@nestjs/common": "^10.0.0", "@nestjs/core": "^10.0.0" } }, "sha512-rh97mX3rimyf4xLMLHuTOBKe6UD8LOJ14VlJ1F/PTd6C6ZK9Ak6EHuJvdaGcSFQhd3ZMBh3I6CuujKGW9pNdIg=="], - "@nestjs/swagger": ["@nestjs/swagger@11.2.1", "", { "dependencies": { "@microsoft/tsdoc": "0.15.1", "@nestjs/mapped-types": "2.1.0", "js-yaml": "4.1.0", "lodash": "4.17.21", "path-to-regexp": "8.3.0", "swagger-ui-dist": "5.29.4" }, "peerDependencies": { "@fastify/static": "^8.0.0", "@nestjs/common": "^11.0.1", "@nestjs/core": "^11.0.1", "class-transformer": "*", "class-validator": "*", "reflect-metadata": "^0.1.12 || ^0.2.0" }, "optionalPeers": ["@fastify/static", "class-transformer", "class-validator"] }, "sha512-1MS7xf0pzc1mofG53xrrtrurnziafPUHkqzRm4YUVPA/egeiMaSerQBD/feiAeQ2BnX0WiLsTX4HQFO0icvOjQ=="], + "@nestjs/swagger": ["@nestjs/swagger@11.2.0", "", { "dependencies": { "@microsoft/tsdoc": "0.15.1", "@nestjs/mapped-types": "2.1.0", "js-yaml": "4.1.0", "lodash": "4.17.21", "path-to-regexp": "8.2.0", "swagger-ui-dist": "5.21.0" }, "peerDependencies": { "@fastify/static": "^8.0.0", "@nestjs/common": "^11.0.1", "@nestjs/core": "^11.0.1", "class-transformer": "*", "class-validator": "*", "reflect-metadata": "^0.1.12 || ^0.2.0" }, "optionalPeers": ["@fastify/static", "class-transformer", "class-validator"] }, "sha512-5wolt8GmpNcrQv34tIPUtPoV1EeFbCetm40Ij3+M0FNNnf2RJ3FyWfuQvI8SBlcJyfaounYVTKzKHreFXsUyOg=="], "@nestjs/testing": ["@nestjs/testing@10.4.20", "", { "dependencies": { "tslib": "2.8.1" }, "peerDependencies": { "@nestjs/common": "^10.0.0", "@nestjs/core": "^10.0.0", "@nestjs/microservices": "^10.0.0", "@nestjs/platform-express": "^10.0.0" }, "optionalPeers": ["@nestjs/microservices", "@nestjs/platform-express"] }, "sha512-nMkRDukDKskdPruM6EsgMq7yJua+CPZM6I6FrLP8yXw8BiVSPv9Nm0CtcGGwt3kgZF9hfxKjGqLjsvVBsv6Vfw=="], @@ -385,6 +398,8 @@ "@nuxtjs/opencollective": ["@nuxtjs/opencollective@0.3.2", "", { "dependencies": { "chalk": "^4.1.0", "consola": "^2.15.0", "node-fetch": "^2.6.1" }, "bin": { "opencollective": "bin/opencollective.js" } }, "sha512-um0xL3fO7Mf4fDxcqx9KryrB7zgRM5JSlvGN5AGkP6JLM5XEKyjeAiPbNxdXVXQ16isuAhYpvP88NgL2BGd6aA=="], + "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], + "@paralleldrive/cuid2": ["@paralleldrive/cuid2@2.2.2", "", { "dependencies": { "@noble/hashes": "^1.1.5" } }, "sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA=="], "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], @@ -563,6 +578,8 @@ "@shipsec/worker": ["@shipsec/worker@workspace:worker"], + "@standard-schema/spec": ["@standard-schema/spec@1.0.0", "", {}, "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA=="], + "@swc/core": ["@swc/core@1.13.5", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.24" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.13.5", "@swc/core-darwin-x64": "1.13.5", "@swc/core-linux-arm-gnueabihf": "1.13.5", "@swc/core-linux-arm64-gnu": "1.13.5", "@swc/core-linux-arm64-musl": "1.13.5", "@swc/core-linux-x64-gnu": "1.13.5", "@swc/core-linux-x64-musl": "1.13.5", "@swc/core-win32-arm64-msvc": "1.13.5", "@swc/core-win32-ia32-msvc": "1.13.5", "@swc/core-win32-x64-msvc": "1.13.5" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-WezcBo8a0Dg2rnR82zhwoR6aRNxeTGfK5QCD6TQ+kg3xx/zNT02s/0o+81h/3zhvFSB24NtqEr8FTw88O5W/JQ=="], "@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.13.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-lKNv7SujeXvKn16gvQqUQI5DdyY8v7xcoO3k06/FJbHJS90zEwZdQiMNRiqpYw/orU543tPaWgz7cIYWhbopiQ=="], @@ -593,21 +610,21 @@ "@tailwindcss/typography": ["@tailwindcss/typography@0.5.19", "", { "dependencies": { "postcss-selector-parser": "6.0.10" }, "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, "sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg=="], - "@temporalio/activity": ["@temporalio/activity@1.13.1", "", { "dependencies": { "@temporalio/client": "1.13.1", "@temporalio/common": "1.13.1", "abort-controller": "^3.0.0" } }, "sha512-0qFTqvjMpcc0J8aVqnG2joF7drPcnMMG3BerfW5Y7RbR8xfdWLpndT3nHdblp+qCrbEmj3AchFluuShlQh8s0Q=="], + "@temporalio/activity": ["@temporalio/activity@1.13.0", "", { "dependencies": { "@temporalio/client": "1.13.0", "@temporalio/common": "1.13.0", "abort-controller": "^3.0.0" } }, "sha512-/h+S7+D7JylaRGZq/3q6h0HxFwFop5zO7qWWrYAT7HCgXdtVNZJWEbPjpV9elJXDVSZ7lIz4GrZREATYZ38Txw=="], - "@temporalio/client": ["@temporalio/client@1.13.1", "", { "dependencies": { "@grpc/grpc-js": "^1.12.4", "@temporalio/common": "1.13.1", "@temporalio/proto": "1.13.1", "abort-controller": "^3.0.0", "long": "^5.2.3", "uuid": "^9.0.1" } }, "sha512-EW++yWZhMhHOBCJ5hz4EZank9D5NskJO2zq25THXWGWRDNLeZPGT2rblOPz38Yexu7N6JcSLh8OglWRDohMCzg=="], + "@temporalio/client": ["@temporalio/client@1.13.0", "", { "dependencies": { "@grpc/grpc-js": "^1.12.4", "@temporalio/common": "1.13.0", "@temporalio/proto": "1.13.0", "abort-controller": "^3.0.0", "long": "^5.2.3", "uuid": "^9.0.1" } }, "sha512-cIEqEFNy8HdvlKGTJQH80C8vUWG0PUAYVS++EGuSNmU3TFb/3TaV/ATVlBiLeiIr05lbDl3LAsWxTSO3gaRXEg=="], - "@temporalio/common": ["@temporalio/common@1.13.1", "", { "dependencies": { "@temporalio/proto": "1.13.1", "long": "^5.2.3", "ms": "3.0.0-canary.1", "nexus-rpc": "^0.0.1", "proto3-json-serializer": "^2.0.0" } }, "sha512-Z8t+uN33gu0Hw0T6o0J0Lmn2v6KJ2j7rDBjPYJwRTqrzY8On8wCkgkrq0JaqNRoMzkSJCjj+eanuBswiltsZlg=="], + "@temporalio/common": ["@temporalio/common@1.13.0", "", { "dependencies": { "@temporalio/proto": "1.13.0", "long": "^5.2.3", "ms": "3.0.0-canary.1", "nexus-rpc": "^0.0.1", "proto3-json-serializer": "^2.0.0" } }, "sha512-YBUXof7zsLbjI+J+FdndbN0JPZY3vKbBWhXV5T4efLZD1IyFmHww10bayDk+37/aVCgqPalBbgWHJnkwk0tRYA=="], - "@temporalio/core-bridge": ["@temporalio/core-bridge@1.13.1", "", { "dependencies": { "@grpc/grpc-js": "^1.12.4", "@temporalio/common": "1.13.1", "arg": "^5.0.2", "cargo-cp-artifact": "^0.1.8", "which": "^4.0.0" } }, "sha512-GTkEnvCqpq8cPDRksn+TCU257cprU7j6nvQqHAmzDeKZ76aCs6NHarOmvyQytPEUqXkRawEpUDm4M4EHx1d+zw=="], + "@temporalio/core-bridge": ["@temporalio/core-bridge@1.13.0", "", { "dependencies": { "@grpc/grpc-js": "^1.12.4", "@temporalio/common": "1.13.0", "arg": "^5.0.2", "cargo-cp-artifact": "^0.1.8", "which": "^4.0.0" } }, "sha512-xJpO+6m88Bdt2g9n13CvfiLy0Rw80Rn8bbCG1U87LPVPoR2xbE2YgcX7ps56zptiQgrSldT7S8UYU2f5X5iAyQ=="], - "@temporalio/nexus": ["@temporalio/nexus@1.13.1", "", { "dependencies": { "@temporalio/client": "1.13.1", "@temporalio/common": "1.13.1", "@temporalio/proto": "1.13.1", "long": "^5.2.3", "nexus-rpc": "^0.0.1" } }, "sha512-kA3m1USLorqHqtHh8eT0BW2plTmvaUNa0LT0kjkK095UDf07A0Xez5xMWN7TQRmDYgkvOULACt2bHACOAyCJDA=="], + "@temporalio/nexus": ["@temporalio/nexus@1.13.0", "", { "dependencies": { "@temporalio/client": "1.13.0", "@temporalio/common": "1.13.0", "@temporalio/proto": "1.13.0", "long": "^5.2.3", "nexus-rpc": "^0.0.1" } }, "sha512-YKVIWzE8/83aGzaR28Y2m45WWlAxboKjHrvpdIrWogYEB7sG6dgju07zIqCKtXcA/k7ja29fq638y5ii7SLP8Q=="], - "@temporalio/proto": ["@temporalio/proto@1.13.1", "", { "dependencies": { "long": "^5.2.3", "protobufjs": "^7.2.5" } }, "sha512-Lx7ge+XEk9Gk7z5gXX5VreSNLr4GfBxhe4wxmoDI618PilL0hA14nTh48fZxi72gfSFSfZmJCDBEak6lNdbA2A=="], + "@temporalio/proto": ["@temporalio/proto@1.13.0", "", { "dependencies": { "long": "^5.2.3", "protobufjs": "^7.2.5" } }, "sha512-jplwOQAgghdRJljTVI9Lawar4L0vGM+vT0TfxvKm+/hVf4CpPEAwvy+El9doR4wu1uYg9g94LnPmZdzoUu5qyA=="], - "@temporalio/worker": ["@temporalio/worker@1.13.1", "", { "dependencies": { "@grpc/grpc-js": "^1.12.4", "@swc/core": "^1.3.102", "@temporalio/activity": "1.13.1", "@temporalio/client": "1.13.1", "@temporalio/common": "1.13.1", "@temporalio/core-bridge": "1.13.1", "@temporalio/nexus": "1.13.1", "@temporalio/proto": "1.13.1", "@temporalio/workflow": "1.13.1", "abort-controller": "^3.0.0", "heap-js": "^2.6.0", "memfs": "^4.6.0", "nexus-rpc": "^0.0.1", "proto3-json-serializer": "^2.0.0", "protobufjs": "^7.2.5", "rxjs": "^7.8.1", "source-map": "^0.7.4", "source-map-loader": "^4.0.2", "supports-color": "^8.1.1", "swc-loader": "^0.2.3", "unionfs": "^4.5.1", "webpack": "^5.94.0" } }, "sha512-YcB7WviQmmrruziT4xEXUBAkM3NiQLLMc92n7xvjE1cdEfmVuUD+MSzqhqQll004bcHQu67ZhCm9T0GNfErhIQ=="], + "@temporalio/worker": ["@temporalio/worker@1.13.0", "", { "dependencies": { "@grpc/grpc-js": "^1.12.4", "@swc/core": "^1.3.102", "@temporalio/activity": "1.13.0", "@temporalio/client": "1.13.0", "@temporalio/common": "1.13.0", "@temporalio/core-bridge": "1.13.0", "@temporalio/nexus": "1.13.0", "@temporalio/proto": "1.13.0", "@temporalio/workflow": "1.13.0", "abort-controller": "^3.0.0", "heap-js": "^2.6.0", "memfs": "^4.6.0", "nexus-rpc": "^0.0.1", "proto3-json-serializer": "^2.0.0", "protobufjs": "^7.2.5", "rxjs": "^7.8.1", "source-map": "^0.7.4", "source-map-loader": "^4.0.2", "supports-color": "^8.1.1", "swc-loader": "^0.2.3", "unionfs": "^4.5.1", "webpack": "^5.94.0" } }, "sha512-NmtDleOccUVrYwbg8H3gjQt5dPMbKG6SUTegO9KlhipsEuJQ69OAeenMhjUmuEsZhG/jkaFwPR81JnAvBovgIw=="], - "@temporalio/workflow": ["@temporalio/workflow@1.13.1", "", { "dependencies": { "@temporalio/common": "1.13.1", "@temporalio/proto": "1.13.1", "nexus-rpc": "^0.0.1" } }, "sha512-Wbuvk3rK6F6hVQbXDHB5JuYZVEUWV6eSs1HoB9J15/N+1dOFLVykyBd8lw7Fn5dxNEI1F1nmS4VCJVV47AlZhQ=="], + "@temporalio/workflow": ["@temporalio/workflow@1.13.0", "", { "dependencies": { "@temporalio/common": "1.13.0", "@temporalio/proto": "1.13.0", "nexus-rpc": "^0.0.1" } }, "sha512-8mVMB55cwl0e4+EBlp1prQyttJ8qYZfhsieVcygirr5xXKBU6wcSCun3sAk16lTYa4S5We7XZPyZk0vBB6/WOA=="], "@testing-library/dom": ["@testing-library/dom@10.4.1", "", { "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^5.0.1", "aria-query": "5.3.0", "dom-accessibility-api": "^0.5.9", "lz-string": "^1.5.0", "picocolors": "1.1.1", "pretty-format": "^27.0.2" } }, "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg=="], @@ -723,7 +740,7 @@ "@types/multer": ["@types/multer@2.0.0", "", { "dependencies": { "@types/express": "*" } }, "sha512-C3Z9v9Evij2yST3RSBktxP9STm6OdMc5uR1xF1SGr98uv8dUlAL2hqwrZ3GVB3uyMyiegnscEK6PGtYvNrjTjw=="], - "@types/node": ["@types/node@20.19.22", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-hRnu+5qggKDSyWHlnmThnUqg62l29Aj/6vcYgUaSFL9oc7DVjeWEQN3PRgdSc6F8d9QRMWkf36CLMch1Do/+RQ=="], + "@types/node": ["@types/node@20.19.19", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-pb1Uqj5WJP7wrcbLU7Ru4QtA0+3kAXrkutGiD26wUKzSMgNNaPARTUDQmElUXp64kh3cWdou3Q0C7qwwxqSFmg=="], "@types/pg": ["@types/pg@8.15.5", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-LF7lF6zWEKxuT3/OR8wAZGzkg4ENGXFNyiV/JeOt9z5B+0ZVwbql9McqX5c/WStFq1GaGso7H1AzP/qSzmlCKQ=="], @@ -733,9 +750,9 @@ "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="], - "@types/react-dom": ["@types/react-dom@19.2.2", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw=="], + "@types/react-dom": ["@types/react-dom@19.2.1", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A=="], - "@types/send": ["@types/send@1.2.0", "", { "dependencies": { "@types/node": "*" } }, "sha512-zBF6vZJn1IaMpg3xUF25VK3gd3l8zwE0ZLRX7dsQyQi+jp4E8mMDJNGDYnYse+bQhYwWERTxVwHpi3dMOq7RKQ=="], + "@types/send": ["@types/send@0.17.5", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w=="], "@types/serve-static": ["@types/serve-static@1.15.9", "", { "dependencies": { "@types/http-errors": "*", "@types/node": "*", "@types/send": "<1" } }, "sha512-dOTIuqpWLyl3BBXU3maNQsS4A3zuuoYRNIvYSxxhebPfXg2mzWQEPne/nlJ37yOse6uGgR386uTpdsx4D0QZWA=="], @@ -745,25 +762,27 @@ "@types/validator": ["@types/validator@13.15.3", "", {}, "sha512-7bcUmDyS6PN3EuD9SlGGOxM77F8WLVsrwkxyWxKnxzmXoequ6c7741QBrANq6htVRGOITJ7z72mTP6Z4XyuG+Q=="], - "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.46.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.46.1", "@typescript-eslint/type-utils": "8.46.1", "@typescript-eslint/utils": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.46.1", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ=="], + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.46.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.46.0", "@typescript-eslint/type-utils": "8.46.0", "@typescript-eslint/utils": "8.46.0", "@typescript-eslint/visitor-keys": "8.46.0", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.46.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA=="], + + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.46.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.46.0", "@typescript-eslint/types": "8.46.0", "@typescript-eslint/typescript-estree": "8.46.0", "@typescript-eslint/visitor-keys": "8.46.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ=="], - "@typescript-eslint/parser": ["@typescript-eslint/parser@8.46.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.46.1", "@typescript-eslint/types": "8.46.1", "@typescript-eslint/typescript-estree": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA=="], + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.46.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.46.0", "@typescript-eslint/types": "^8.46.0", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ=="], - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.46.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.46.1", "@typescript-eslint/types": "^8.46.1", "debug": "^4.3.4" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg=="], + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.46.0", "", { "dependencies": { "@typescript-eslint/types": "8.46.0", "@typescript-eslint/visitor-keys": "8.46.0" } }, "sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw=="], - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.46.1", "", { "dependencies": { "@typescript-eslint/types": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1" } }, "sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A=="], + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.46.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw=="], - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.46.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g=="], + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.46.0", "", { "dependencies": { "@typescript-eslint/types": "8.46.0", "@typescript-eslint/typescript-estree": "8.46.0", "@typescript-eslint/utils": "8.46.0", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg=="], - "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.46.1", "", { "dependencies": { "@typescript-eslint/types": "8.46.1", "@typescript-eslint/typescript-estree": "8.46.1", "@typescript-eslint/utils": "8.46.1", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-+BlmiHIiqufBxkVnOtFwjah/vrkF4MtKKvpXrKSPLCkCtAp8H01/VV43sfqA98Od7nJpDcFnkwgyfQbOG0AMvw=="], + "@typescript-eslint/types": ["@typescript-eslint/types@8.46.0", "", {}, "sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA=="], - "@typescript-eslint/types": ["@typescript-eslint/types@8.46.1", "", {}, "sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ=="], + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.46.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.46.0", "@typescript-eslint/tsconfig-utils": "8.46.0", "@typescript-eslint/types": "8.46.0", "@typescript-eslint/visitor-keys": "8.46.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg=="], - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.46.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.46.1", "@typescript-eslint/tsconfig-utils": "8.46.1", "@typescript-eslint/types": "8.46.1", "@typescript-eslint/visitor-keys": "8.46.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg=="], + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.46.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.46.0", "@typescript-eslint/types": "8.46.0", "@typescript-eslint/typescript-estree": "8.46.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g=="], - "@typescript-eslint/utils": ["@typescript-eslint/utils@8.46.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.46.1", "@typescript-eslint/types": "8.46.1", "@typescript-eslint/typescript-estree": "8.46.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ=="], + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.46.0", "", { "dependencies": { "@typescript-eslint/types": "8.46.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q=="], - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.46.1", "", { "dependencies": { "@typescript-eslint/types": "8.46.1", "eslint-visitor-keys": "^4.2.1" } }, "sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA=="], + "@vercel/oidc": ["@vercel/oidc@3.0.3", "", {}, "sha512-yNEQvPcVrK9sIe637+I0jD6leluPxzwJKx/Haw6F4H77CdDsszUn5V3o96LPziXkSNE2B83+Z3mjqGKBK/R6Gg=="], "@vitejs/plugin-react": ["@vitejs/plugin-react@5.0.4", "", { "dependencies": { "@babel/core": "^7.28.4", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.38", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA=="], @@ -815,6 +834,8 @@ "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], + "ai": ["ai@6.0.0-beta.68", "", { "dependencies": { "@ai-sdk/gateway": "2.0.0-beta.37", "@ai-sdk/provider": "3.0.0-beta.8", "@ai-sdk/provider-utils": "4.0.0-beta.20", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-QOoGvEgtMmsbJUm1ZbdmzB8nklc+dbVgD3X1BNvmkh5y6OAi1uhTtO2hFadzxn0Z7BRuR/Xqd1y1y5uawFfTUg=="], + "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], "ajv-formats": ["ajv-formats@2.1.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA=="], @@ -879,7 +900,7 @@ "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], - "baseline-browser-mapping": ["baseline-browser-mapping@2.8.17", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-j5zJcx6golJYTG6c05LUZ3Z8Gi+M62zRT/ycz4Xq4iCOdpcxwg7ngEYD4KA0eWZC7U17qh/Smq8bYbACJ0ipBA=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.8.13", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-7s16KR8io8nIBWQyCYhmFhd+ebIzb9VKTzki+wOJXHTxTnV6+mFGH3+Jwn1zoKaY9/H9T/0BcKCZnzXljPnpSQ=="], "basic-ftp": ["basic-ftp@5.0.5", "", {}, "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg=="], @@ -921,7 +942,7 @@ "camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="], - "caniuse-lite": ["caniuse-lite@1.0.30001751", "", {}, "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw=="], + "caniuse-lite": ["caniuse-lite@1.0.30001748", "", {}, "sha512-5P5UgAr0+aBmNiplks08JLw+AW/XG/SurlgZLgB1dDLfAw7EfRGxIwzPHxdSCGY/BTKDqIVyJL87cCN6s0ZR0w=="], "cargo-cp-artifact": ["cargo-cp-artifact@0.1.9", "", { "bin": { "cargo-cp-artifact": "bin/cargo-cp-artifact.js" } }, "sha512-6F+UYzTaGB+awsTXg0uSJA1/b/B3DDJzpKVRu0UmyI7DmNeaAl2RFHuTGIN6fEgpadRxoXGb7gbC1xo4C3IdyA=="], @@ -1077,7 +1098,7 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], - "electron-to-chromium": ["electron-to-chromium@1.5.237", "", {}, "sha512-icUt1NvfhGLar5lSWH3tHNzablaA5js3HVHacQimfP8ViEBOQv+L7DKEuHdbTZ0SKCO1ogTJTIL1Gwk9S6Qvcg=="], + "electron-to-chromium": ["electron-to-chromium@1.5.232", "", {}, "sha512-ENirSe7wf8WzyPCibqKUG1Cg43cPaxH4wRR7AJsX7MCABCHBIOFqvaYODSLKUuZdraxUTHRE/0A2Aq8BYKEHOg=="], "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], @@ -1107,7 +1128,7 @@ "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "^1.2.7", "is-date-object": "^1.0.5", "is-symbol": "^1.0.4" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], - "esbuild": ["esbuild@0.25.11", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.11", "@esbuild/android-arm": "0.25.11", "@esbuild/android-arm64": "0.25.11", "@esbuild/android-x64": "0.25.11", "@esbuild/darwin-arm64": "0.25.11", "@esbuild/darwin-x64": "0.25.11", "@esbuild/freebsd-arm64": "0.25.11", "@esbuild/freebsd-x64": "0.25.11", "@esbuild/linux-arm": "0.25.11", "@esbuild/linux-arm64": "0.25.11", "@esbuild/linux-ia32": "0.25.11", "@esbuild/linux-loong64": "0.25.11", "@esbuild/linux-mips64el": "0.25.11", "@esbuild/linux-ppc64": "0.25.11", "@esbuild/linux-riscv64": "0.25.11", "@esbuild/linux-s390x": "0.25.11", "@esbuild/linux-x64": "0.25.11", "@esbuild/netbsd-arm64": "0.25.11", "@esbuild/netbsd-x64": "0.25.11", "@esbuild/openbsd-arm64": "0.25.11", "@esbuild/openbsd-x64": "0.25.11", "@esbuild/openharmony-arm64": "0.25.11", "@esbuild/sunos-x64": "0.25.11", "@esbuild/win32-arm64": "0.25.11", "@esbuild/win32-ia32": "0.25.11", "@esbuild/win32-x64": "0.25.11" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q=="], + "esbuild": ["esbuild@0.25.10", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.10", "@esbuild/android-arm": "0.25.10", "@esbuild/android-arm64": "0.25.10", "@esbuild/android-x64": "0.25.10", "@esbuild/darwin-arm64": "0.25.10", "@esbuild/darwin-x64": "0.25.10", "@esbuild/freebsd-arm64": "0.25.10", "@esbuild/freebsd-x64": "0.25.10", "@esbuild/linux-arm": "0.25.10", "@esbuild/linux-arm64": "0.25.10", "@esbuild/linux-ia32": "0.25.10", "@esbuild/linux-loong64": "0.25.10", "@esbuild/linux-mips64el": "0.25.10", "@esbuild/linux-ppc64": "0.25.10", "@esbuild/linux-riscv64": "0.25.10", "@esbuild/linux-s390x": "0.25.10", "@esbuild/linux-x64": "0.25.10", "@esbuild/netbsd-arm64": "0.25.10", "@esbuild/netbsd-x64": "0.25.10", "@esbuild/openbsd-arm64": "0.25.10", "@esbuild/openbsd-x64": "0.25.10", "@esbuild/openharmony-arm64": "0.25.10", "@esbuild/sunos-x64": "0.25.10", "@esbuild/win32-arm64": "0.25.10", "@esbuild/win32-ia32": "0.25.10", "@esbuild/win32-x64": "0.25.10" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ=="], "esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="], @@ -1125,7 +1146,7 @@ "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@6.1.1", "", { "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", "zod": "^3.22.4 || ^4.0.0", "zod-validation-error": "^3.0.3 || ^4.0.0" }, "peerDependencies": { "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" } }, "sha512-St9EKZzOAQF704nt2oJvAKZHjhrpg25ClQoaAlHmPZuajFldVLqRDW4VBNAS01NzeiQF0m0qhG1ZA807K6aVaQ=="], - "eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.24", "", { "peerDependencies": { "eslint": ">=8.40" } }, "sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w=="], + "eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.23", "", { "peerDependencies": { "eslint": ">=8.40" } }, "sha512-G4j+rv0NmbIR45kni5xJOrYvCtyD3/7LjpVH8MPPcudXDcNu8gv+4ATTDXTtbRR8rTCM5HxECvCSsRmxKnWDsA=="], "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], @@ -1153,6 +1174,8 @@ "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], + "eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="], + "express": ["express@4.21.2", "", { "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "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.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" } }, "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA=="], "extrareqp2": ["extrareqp2@1.0.0", "", { "dependencies": { "follow-redirects": "^1.14.0" } }, "sha512-Gum0g1QYb6wpPJCVypWP3bbIuaibcFiJcpuPM10YSXp/tzqi84x9PJageob+eN4xVRIOto4wjSGNLyMD54D2xA=="], @@ -1237,7 +1260,7 @@ "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], - "get-tsconfig": ["get-tsconfig@4.12.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-LScr2aNr2FbjAjZh2C6X6BxRx1/x+aTDExct/xyq2XKbYOiG5c0aK7pMsSuyc0brz3ibr/lbQiHD9jzt4lccJw=="], + "get-tsconfig": ["get-tsconfig@4.11.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-sNsqf7XKQ38IawiVGPOoAlqZo1DMrO7TU+ZcZwi7yLl7/7S0JwmoBMKz/IkUPhSoXM0Ng3vT0yB1iCe5XavDeQ=="], "get-uri": ["get-uri@6.0.5", "", { "dependencies": { "basic-ftp": "^5.0.2", "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4" } }, "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg=="], @@ -1403,6 +1426,8 @@ "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="], + "json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="], + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], @@ -1417,13 +1442,13 @@ "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], - "libphonenumber-js": ["libphonenumber-js@1.12.24", "", {}, "sha512-l5IlyL9AONj4voSd7q9xkuQOL4u8Ty44puTic7J88CmdXkxfGsRfoVLXHCxppwehgpb/Chdb80FFehHqjN3ItQ=="], + "libphonenumber-js": ["libphonenumber-js@1.12.23", "", {}, "sha512-RN3q3gImZ91BvRDYjWp7ICz3gRn81mW5L4SW+2afzNCC0I/nkXstBgZThQGTE3S/9q5J90FH4dP+TXx8NhdZKg=="], "lilconfig": ["lilconfig@3.1.3", "", {}, "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw=="], "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], - "loader-runner": ["loader-runner@4.3.1", "", {}, "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q=="], + "loader-runner": ["loader-runner@4.3.0", "", {}, "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg=="], "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], @@ -1509,7 +1534,7 @@ "node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], - "node-releases": ["node-releases@2.0.25", "", {}, "sha512-4auku8B/vw5psvTiiN9j1dAOsXvMoGqJuKJcR+dTdqiXEK20mMTk1UEo3HS16LeGQsVG6+qKTPM9u/qQ2LqATA=="], + "node-releases": ["node-releases@2.0.23", "", {}, "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg=="], "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], @@ -1537,7 +1562,7 @@ "openapi-fetch": ["openapi-fetch@0.12.5", "", { "dependencies": { "openapi-typescript-helpers": "^0.0.15" } }, "sha512-FnAMWLt0MNL6ComcL4q/YbB1tUgyz5YnYtwA1+zlJ5xcucmK5RlWsgH1ynxmEeu8fGJkYjm8armU/HVpORc9lw=="], - "openapi-typescript": ["openapi-typescript@7.10.1", "", { "dependencies": { "@redocly/openapi-core": "^1.34.5", "ansi-colors": "^4.1.3", "change-case": "^5.4.4", "parse-json": "^8.3.0", "supports-color": "^10.2.2", "yargs-parser": "^21.1.1" }, "peerDependencies": { "typescript": "^5.x" }, "bin": { "openapi-typescript": "bin/cli.js" } }, "sha512-rBcU8bjKGGZQT4K2ekSTY2Q5veOQbVG/lTKZ49DeCyT9z62hM2Vj/LLHjDHC9W7LJG8YMHcdXpRZDqC1ojB/lw=="], + "openapi-typescript": ["openapi-typescript@7.9.1", "", { "dependencies": { "@redocly/openapi-core": "^1.34.5", "ansi-colors": "^4.1.3", "change-case": "^5.4.4", "parse-json": "^8.3.0", "supports-color": "^10.1.0", "yargs-parser": "^21.1.1" }, "peerDependencies": { "typescript": "^5.x" }, "bin": { "openapi-typescript": "bin/cli.js" } }, "sha512-9gJtoY04mk6iPMbToPjPxEAtfXZ0dTsMZtsgUI8YZta0btPPig9DJFP4jlerQD/7QOwYgb0tl+zLUpDf7vb7VA=="], "openapi-typescript-helpers": ["openapi-typescript-helpers@0.0.15", "", {}, "sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw=="], @@ -1685,9 +1710,9 @@ "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["@types/react"] }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], - "react-router": ["react-router@7.9.4", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-SD3G8HKviFHg9xj7dNODUKDFgpG4xqD5nhyd0mYoB5iISepuZAvzSr8ywxgxKJ52yRzf/HWtVHc9AWwoTbljvA=="], + "react-router": ["react-router@7.9.3", "", { "dependencies": { "cookie": "^1.0.1", "set-cookie-parser": "^2.6.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" }, "optionalPeers": ["react-dom"] }, "sha512-4o2iWCFIwhI/eYAIL43+cjORXYn/aRQPgtFRRZb3VzoyQ5Uej0Bmqj7437L97N9NJW4wnicSwLOLS+yCXfAPgg=="], - "react-router-dom": ["react-router-dom@7.9.4", "", { "dependencies": { "react-router": "7.9.4" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-f30P6bIkmYvnHHa5Gcu65deIXoA2+r3Eb6PJIAddvsT9aGlchMatJ51GgpU470aSqRRbFX22T70yQNUGuW3DfA=="], + "react-router-dom": ["react-router-dom@7.9.3", "", { "dependencies": { "react-router": "7.9.3" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-1QSbA0TGGFKTAc/aWjpfW/zoEukYfU4dc1dLkT/vvf54JoGMkW+fNA+3oyo2gWVW1GM7BxjJVHz5GnPJv40rvg=="], "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], @@ -1859,7 +1884,7 @@ "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - "swagger-ui-dist": ["swagger-ui-dist@5.29.4", "", { "dependencies": { "@scarf/scarf": "=1.4.0" } }, "sha512-gJFDz/gyLOCQtWwAgqs6Rk78z9ONnqTnlW11gimG9nLap8drKa3AJBKpzIQMIjl5PD2Ix+Tn+mc/tfoT2tgsng=="], + "swagger-ui-dist": ["swagger-ui-dist@5.21.0", "", { "dependencies": { "@scarf/scarf": "=1.4.0" } }, "sha512-E0K3AB6HvQd8yQNSMR7eE5bk+323AUxjtCz/4ZNKiahOlPhPJxqn3UPIGs00cyY/dhrTDJ61L7C/a8u6zhGrZg=="], "swagger-ui-express": ["swagger-ui-express@5.0.1", "", { "dependencies": { "swagger-ui-dist": ">=5.0.0" }, "peerDependencies": { "express": ">=4.0.0 || >=5.0.0-beta" } }, "sha512-SrNU3RiBGTLLmFU8GIJdOdanJTl4TOmT27tt3bWWHppqYmAZ6IDuEuBvMU6nZq0zLEe6b/1rACXCgLZqO6ZfrA=="], @@ -1971,7 +1996,7 @@ "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], - "vite": ["vite@7.1.10", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA=="], + "vite": ["vite@7.1.9", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg=="], "vizion": ["vizion@2.2.1", "", { "dependencies": { "async": "^2.6.3", "git-node-fs": "^1.0.0", "ini": "^1.3.5", "js-git": "^0.7.8" } }, "sha512-sfAcO2yeSU0CSPFI/DmZp3FsFE9T+8913nv1xWBOyzODv13fwkn6Vl7HqxGpkr9F608M+8SuFId3s+BlZqfXww=="], @@ -2061,7 +2086,7 @@ "@nestjs/config/dotenv": ["dotenv@16.4.5", "", {}, "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg=="], - "@nestjs/swagger/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], + "@nestjs/swagger/path-to-regexp": ["path-to-regexp@8.2.0", "", {}, "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ=="], "@pm2/agent/chalk": ["chalk@3.0.0", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="], @@ -2115,23 +2140,21 @@ "@testing-library/dom/dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="], - "@types/body-parser/@types/node": ["@types/node@24.8.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q=="], + "@types/body-parser/@types/node": ["@types/node@24.7.0", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw=="], - "@types/connect/@types/node": ["@types/node@24.8.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q=="], + "@types/connect/@types/node": ["@types/node@24.7.0", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw=="], "@types/express/@types/express-serve-static-core": ["@types/express-serve-static-core@5.1.0", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA=="], - "@types/express-serve-static-core/@types/node": ["@types/node@24.8.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q=="], - - "@types/pg/@types/node": ["@types/node@24.8.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q=="], + "@types/express-serve-static-core/@types/node": ["@types/node@24.7.0", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw=="], - "@types/send/@types/node": ["@types/node@24.8.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q=="], + "@types/pg/@types/node": ["@types/node@24.7.0", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw=="], - "@types/serve-static/@types/node": ["@types/node@24.8.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q=="], + "@types/send/@types/node": ["@types/node@24.7.0", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw=="], - "@types/serve-static/@types/send": ["@types/send@0.17.5", "", { "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w=="], + "@types/serve-static/@types/node": ["@types/node@24.7.0", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw=="], - "@types/superagent/@types/node": ["@types/node@24.8.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q=="], + "@types/superagent/@types/node": ["@types/node@24.7.0", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw=="], "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], @@ -2145,7 +2168,7 @@ "body-parser/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], - "bun-types/@types/node": ["@types/node@24.8.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q=="], + "bun-types/@types/node": ["@types/node@24.7.0", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw=="], "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], @@ -2173,7 +2196,7 @@ "glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], - "jest-worker/@types/node": ["@types/node@24.8.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q=="], + "jest-worker/@types/node": ["@types/node@24.7.0", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw=="], "jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], @@ -2197,7 +2220,7 @@ "pretty-format/react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], - "protobufjs/@types/node": ["@types/node@24.8.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q=="], + "protobufjs/@types/node": ["@types/node@24.7.0", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw=="], "proxy-addr/ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], @@ -2221,11 +2244,13 @@ "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], - "ssa-frontend/@types/node": ["@types/node@24.8.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q=="], + "ssa-frontend/@types/node": ["@types/node@24.7.0", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw=="], + + "ssa-frontend/ai": ["ai@5.0.76", "", { "dependencies": { "@ai-sdk/gateway": "2.0.0", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.12", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZCxi1vrpyCUnDbtYrO/W8GLvyacV9689f00yshTIQ3mFFphbD7eIv40a2AOZBv3GGRA7SSRYIDnr56wcS/gyQg=="], "sucrase/commander": ["commander@4.1.1", "", {}, "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="], - "swagger-ui-express/swagger-ui-dist": ["swagger-ui-dist@5.29.5", "", { "dependencies": { "@scarf/scarf": "=1.4.0" } }, "sha512-2zFnjONgLXlz8gLToRKvXHKJdqXF6UGgCmv65i8T6i/UrjDNyV1fIQ7FauZA40SaivlGKEvW2tw9XDyDhfcXqQ=="], + "swagger-ui-express/swagger-ui-dist": ["swagger-ui-dist@5.29.3", "", { "dependencies": { "@scarf/scarf": "=1.4.0" } }, "sha512-U99f/2YocRA2Mxqx3eUBRhQonWVtE5dIvMs0Zlsn4a4ip8awMq0JxXhU+Sidtna2WlZrHbK2Rro3RZvYUymRbA=="], "tailwindcss/postcss-selector-parser": ["postcss-selector-parser@6.1.2", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg=="], @@ -2305,7 +2330,7 @@ "@types/express-serve-static-core/@types/node/undici-types": ["undici-types@7.14.0", "", {}, "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA=="], - "@types/express/@types/express-serve-static-core/@types/node": ["@types/node@24.8.1", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q=="], + "@types/express/@types/express-serve-static-core/@types/node": ["@types/node@24.7.0", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw=="], "@types/pg/@types/node/undici-types": ["undici-types@7.14.0", "", {}, "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA=="], @@ -2349,6 +2374,12 @@ "ssa-frontend/@types/node/undici-types": ["undici-types@7.14.0", "", {}, "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA=="], + "ssa-frontend/ai/@ai-sdk/gateway": ["@ai-sdk/gateway@2.0.0", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.12", "@vercel/oidc": "3.0.3" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Gj0PuawK7NkZuyYgO/h5kDK/l6hFOjhLdTq3/Lli1FTl47iGmwhH1IZQpAL3Z09BeFYWakcwUmn02ovIm2wy9g=="], + + "ssa-frontend/ai/@ai-sdk/provider": ["@ai-sdk/provider@2.0.0", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA=="], + + "ssa-frontend/ai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.12", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.5" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZtbdvYxdMoria+2SlNarEk6Hlgyf+zzcznlD55EAl+7VZvJaSg2sqPvwArY7L6TfDEDJsnCq0fdhBSkYo0Xqdg=="], + "webpack/eslint-scope/estraverse": ["estraverse@4.3.0", "", {}, "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="], "@types/express/@types/express-serve-static-core/@types/node/undici-types": ["undici-types@7.14.0", "", {}, "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA=="], diff --git a/frontend/MAINTAINING.md b/frontend/MAINTAINING.md index e5f9631a..2f28949a 100644 --- a/frontend/MAINTAINING.md +++ b/frontend/MAINTAINING.md @@ -259,12 +259,17 @@ const onEdgesChange = useCallback((changes) => { **Type Compatibility Matrix** (`src/utils/connectionValidation.ts`): ```typescript -const TYPE_HIERARCHY: Record = { - 'any': ['string', 'array', 'object', 'file'], - 'file': ['string', 'array', 'object', 'any'], - 'array': ['string', 'any'], - 'object': ['string', 'any'], +const SOURCE_COMPATIBILITY: Record = { + string: ['string'], + array: ['array'], + object: ['object'], + file: ['file'], + secret: ['secret'], + number: ['number'], } + +const normalizePortTypes = (type: PortType | PortType[]) => + Array.isArray(type) ? type : [type] ``` **Smart Required Detection** (`src/components/workflow/WorkflowNode.tsx`): @@ -579,4 +584,4 @@ markClean() 2. Add component version management 3. ~~Implement save workflow functionality with API persistence~~ ✅ COMPLETED 4. Add execution results/history tabs in BottomPanel -5. Add toast notifications for connection validation errors and save confirmations \ No newline at end of file +5. Add toast notifications for connection validation errors and save confirmations diff --git a/frontend/e2e/workflow-undo.e2e.ts b/frontend/e2e/workflow-undo.e2e.ts new file mode 100644 index 00000000..efc88613 --- /dev/null +++ b/frontend/e2e/workflow-undo.e2e.ts @@ -0,0 +1,24 @@ +import { test, expect } from '@playwright/test' + +const undoShortcut = process.platform === 'darwin' ? 'Meta+KeyZ' : 'Control+KeyZ' + +test.describe('Workflow undo playground', () => { + test('restores a deleted node when undo is pressed', async ({ page }) => { + await page.goto('/__playground__/undo') + + const nodeCount = page.getByTestId('node-count') + await expect(nodeCount).toHaveText(/Nodes: 2/) + await expect(page.getByTestId('edge-count')).toHaveText(/Edges: 1/) + + const sourceNode = page.getByRole('button', { name: /Source Node/i }) + await sourceNode.click() + + await page.keyboard.press('Delete') + await expect(nodeCount).toHaveText(/Nodes: 1/) + await expect(page.getByTestId('edge-count')).toHaveText(/Edges: 0/) + + await page.keyboard.press(undoShortcut) + await expect(nodeCount).toHaveText(/Nodes: 2/) + await expect(page.getByTestId('edge-count')).toHaveText(/Edges: 1/) + }) +}) diff --git a/frontend/package.json b/frontend/package.json index bd20d568..289ba193 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,5 +1,5 @@ { - "name": "ssa-frontend", + "name": "@shipsec/frontend", "version": "1.0.0", "main": "index.js", "type": "module", @@ -49,6 +49,7 @@ "@radix-ui/react-slot": "^1.2.3", "@shipsec/backend-client": "workspace:*", "@shipsec/shared": "workspace:*", + "ai": "^5.0.76", "autoprefixer": "^10.4.21", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/frontend/src/components/layout/Sidebar.tsx b/frontend/src/components/layout/Sidebar.tsx index 524c91a7..06890d0c 100644 --- a/frontend/src/components/layout/Sidebar.tsx +++ b/frontend/src/components/layout/Sidebar.tsx @@ -1,8 +1,6 @@ -import { useEffect, useState } from 'react' +import { useEffect } from 'react' import * as LucideIcons from 'lucide-react' import { useComponentStore } from '@/store/componentStore' -import { ComponentBadge } from '@/components/workflow/ComponentBadge' -import { FileUpload } from '@/components/workflow/FileUpload' import type { ComponentMetadata } from '@/schemas/component' import { cn } from '@/lib/utils' import { env } from '@/config/env' @@ -59,23 +57,17 @@ function ComponentItem({ component }: ComponentItemProps) { component.logo && "hidden" )} />
-
- {component.name} -
- {component.author?.type === 'shipsecai' && ( - - )} - {component.deprecated && } -
+
+ {component.name} + {component.version && ( + + v{component.version} + + )}

{description}

- {component.version && ( - - v{component.version} - - )}
) @@ -83,7 +75,6 @@ function ComponentItem({ component }: ComponentItemProps) { export function Sidebar() { const { getAllComponents, getComponentsByType, fetchComponents, loading, error } = useComponentStore() - const [showFileUpload, setShowFileUpload] = useState(false) const frontendBranch = env.VITE_FRONTEND_BRANCH.trim() const backendBranch = env.VITE_BACKEND_BRANCH.trim() const hasBranchInfo = Boolean(frontendBranch || backendBranch) @@ -169,35 +160,6 @@ export function Sidebar() { )} - - {/* File Upload Section */} -
- - - {showFileUpload && ( -
- { - console.log('File uploaded:', fileId, fileName) - // Could show a success toast here - }} - /> -
- )} -
) } diff --git a/frontend/src/components/timeline/EventInspector.tsx b/frontend/src/components/timeline/EventInspector.tsx index 12bc2e4e..6c316895 100644 --- a/frontend/src/components/timeline/EventInspector.tsx +++ b/frontend/src/components/timeline/EventInspector.tsx @@ -2,6 +2,7 @@ import React, { useState, useMemo, useEffect, useRef } from 'react' import { ChevronDown, FileText, AlertCircle, CheckCircle, Activity } from 'lucide-react' import { Badge } from '@/components/ui/badge' import { MessageModal } from '@/components/ui/MessageModal' +import { createPreview } from '@/utils/textPreview' import { useExecutionTimelineStore, type TimelineEvent } from '@/store/executionTimelineStore' import { cn } from '@/lib/utils' @@ -261,6 +262,10 @@ export function EventInspector({ className }: EventInspectorProps) { const isRecentLiveEvent = playbackMode === 'live' && isLatestEvent const isCurrentReplayEvent = playbackMode === 'replay' && isCurrent const nodeState = event.nodeId ? nodeStates[event.nodeId] : undefined + const messagePreview = event.message ? createPreview(event.message, { charLimit: 220, lineLimit: 6 }) : null + const messagePreviewText = messagePreview + ? (messagePreview.truncated ? `${messagePreview.text.trimEnd()}\n…` : messagePreview.text) + : '' return (
  • Message
    -
    - {event.message} -
    - {event.message.length > 100 && ( +
    +                                {messagePreviewText}
    +                              
    + {messagePreview?.truncated && ( - - + )}
    - -
    - {inspectorTab === 'events' && ( -
    -
    - -
    -
    - -
    +
    +
    + + +
    - )} - - {inspectorTab === 'logs' && ( -
    -
    -
    - {displayLogs.length} log entries - {retrySummary.totalRetries > 0 && ( - - {retrySummary.totalRetries} retries across {retrySummary.nodesWithRetries} node{retrySummary.nodesWithRetries === 1 ? '' : 's'} - - )} +
    + +
    + {inspectorTab === 'events' && ( +
    +
    + +
    +
    +
    - - {playbackMode === 'live' ? (isPlaying ? 'Live (following)' : 'Live paused') : 'Execution playback'} -
    -
    - {displayLogs.length === 0 ? ( -
    - No logs to display for this run. + )} + + {inspectorTab === 'logs' && ( +
    +
    +
    + {displayLogs.length} log entries + {retrySummary.totalRetries > 0 && ( + + {retrySummary.totalRetries} retries across {retrySummary.nodesWithRetries} node{retrySummary.nodesWithRetries === 1 ? '' : 's'} + + )}
    - ) : ( - displayLogs.map((log) => ( -
    -
    - {formatTime(log.timestamp)} - - {log.level.toUpperCase()} - -
    - {log.nodeId && ( -
    Node: {log.nodeId}
    - )} -
    -
    - {log.message ?? log.error?.message ?? log.type} -
    - {(log.message ?? log.error?.message ?? log.type)?.length > 100 && ( - -
    -
    ${log.message ?? log.error?.message ?? log.type}
    -
    - `; - document.body.appendChild(modal); - modal.addEventListener('click', (e) => { - if (e.target === modal) modal.remove(); - }); - }} - > - View full message - - )} -
    + + {playbackMode === 'live' ? (isPlaying ? 'Live (following)' : 'Live paused') : 'Execution playback'} + +
    +
    + {displayLogs.length === 0 ? ( +
    + No logs to display for this run.
    - )) - )} + ) : ( + displayLogs.map((log) => { + const executionLog = log as ExecutionLog + const fullMessage = buildLogMessage(executionLog) + const preview = createPreview(fullMessage, { charLimit: 220, lineLimit: 4 }) + const previewText = preview.truncated + ? `${preview.text.trimEnd()}\n…` + : preview.text + + return ( +
    +
    + {formatTime(log.timestamp)} + + {log.level.toUpperCase()} + +
    + {log.nodeId && ( +
    Node: {log.nodeId}
    + )} +
    +
    +                            {previewText}
    +                          
    + {preview.truncated && ( + + )} +
    +
    + ) + }) + )} +
    -
    - )} + )} - {inspectorTab === 'data' && ( -
    - Data flow visualization is on the roadmap—stay tuned. -
    - )} -
    - + {inspectorTab === 'data' && ( +
    + Data flow visualization is on the roadmap—stay tuned. +
    + )} +
    + + setLogModal((prev) => ({ ...prev, open }))} + title={logModal.title || 'Log message'} + message={logModal.message} + /> + ) } diff --git a/frontend/src/components/timeline/RunSelector.tsx b/frontend/src/components/timeline/RunSelector.tsx index f338741e..b3316fb1 100644 --- a/frontend/src/components/timeline/RunSelector.tsx +++ b/frontend/src/components/timeline/RunSelector.tsx @@ -79,6 +79,21 @@ export function RunSelector() { } }, [currentLiveRunId, selectedRunId, selectRun]) + // Fallback to the most recent historical run when nothing is selected + useEffect(() => { + if (selectedRunId || currentLiveRunId || availableRuns.length === 0) { + return + } + + const [latestRun] = [...availableRuns].sort( + (a, b) => new Date(b.startTime).getTime() - new Date(a.startTime).getTime() + ) + + if (latestRun) { + selectRun(latestRun.id) + } + }, [availableRuns, selectedRunId, currentLiveRunId, selectRun]) + const selectedRun = availableRuns.find(run => run.id === selectedRunId) const currentLiveRun = availableRuns.find(run => run.id === currentLiveRunId) @@ -279,4 +294,4 @@ export function RunSelector() { )}
    ) -} \ No newline at end of file +} diff --git a/frontend/src/components/workflow/Canvas.tsx b/frontend/src/components/workflow/Canvas.tsx index 37282590..82beeaf2 100644 --- a/frontend/src/components/workflow/Canvas.tsx +++ b/frontend/src/components/workflow/Canvas.tsx @@ -1,4 +1,4 @@ -import { useCallback, useState, useEffect, type Dispatch, type SetStateAction } from 'react' +import { useCallback, useState, useEffect, useRef, type Dispatch, type SetStateAction } from 'react' import { ReactFlow, Background, @@ -35,6 +35,13 @@ const edgeTypes = { default: DataFlowEdge, // Default to our enhanced edge } +const MAX_DELETE_HISTORY = 10 + +interface DeleteHistoryEntry { + nodes: Node[] + edges: Edge[] +} + interface CanvasProps { className?: string nodes: Node[] @@ -63,6 +70,7 @@ export function Canvas({ const { mode } = useWorkflowUiStore() const { toast } = useToast() const applyEdgesChange = onEdgesChange + const deleteHistoryRef = useRef([]) useEffect(() => { if (mode === 'execution') { @@ -349,29 +357,118 @@ export function Canvas({ if (mode !== 'design') { return } + + const target = event.target as HTMLElement | null + if (target) { + const closestFormElement = target.closest('input, textarea, select, [contenteditable="true"], [role="textbox"]') + const isFormElement = + target.tagName === 'INPUT' || + target.tagName === 'TEXTAREA' || + target.tagName === 'SELECT' || + target.getAttribute('contenteditable') === 'true' || + Boolean(closestFormElement) + + if (isFormElement) { + return + } + } + // Close config panel on Escape if (event.key === 'Escape') { setSelectedNode(null) return } + const isUndoShortcut = + (event.key === 'z' || event.key === 'Z') && + (event.metaKey || event.ctrlKey) && + !event.shiftKey + + if (isUndoShortcut) { + event.preventDefault() + const lastDeletion = deleteHistoryRef.current.pop() + if (!lastDeletion) { + return + } + + if (lastDeletion.nodes.length > 0) { + setNodes((nds) => { + const existingIds = new Set(nds.map((node) => node.id)) + const nodesToRestore = lastDeletion.nodes + .filter((node) => !existingIds.has(node.id)) + .map((node) => ({ ...node, selected: false })) + + if (nodesToRestore.length === 0) { + return nds + } + + return nds.concat(nodesToRestore) + }) + } + + if (lastDeletion.edges.length > 0) { + setEdges((eds) => { + const existingIds = new Set(eds.map((edge) => edge.id)) + const edgesToRestore = lastDeletion.edges + .filter((edge) => !existingIds.has(edge.id)) + .map((edge) => ({ ...edge, selected: false })) + + if (edgesToRestore.length === 0) { + return eds + } + + return eds.concat(edgesToRestore) + }) + } + + setSelectedNode(null) + markDirty() + return + } + if (event.key === 'Delete' || event.key === 'Backspace') { + event.preventDefault() const selectedNodes = nodes.filter((node) => node.selected) const selectedEdges = edges.filter((edge) => edge.selected) + const nodeIds = new Set(selectedNodes.map((node) => node.id)) + const edgesFromNodes = edges.filter( + (edge) => nodeIds.has(edge.source) || nodeIds.has(edge.target) + ) + const selectedEdgeIds = new Set(selectedEdges.map((edge) => edge.id)) + const dedupedEdges = new Map() + + edgesFromNodes.forEach((edge) => { + dedupedEdges.set(edge.id, { ...edge, selected: false }) + }) + selectedEdges.forEach((edge) => { + dedupedEdges.set(edge.id, { ...edge, selected: false }) + }) + + const historyEntryNodes = selectedNodes.map((node) => ({ ...node, selected: false })) + const historyEntryEdges = Array.from(dedupedEdges.values()) + + if (historyEntryNodes.length > 0 || historyEntryEdges.length > 0) { + const history = deleteHistoryRef.current.slice(-(MAX_DELETE_HISTORY - 1)) + history.push({ + nodes: historyEntryNodes, + edges: historyEntryEdges, + }) + deleteHistoryRef.current = history + } if (selectedNodes.length > 0) { - const nodeIds = selectedNodes.map((node) => node.id) - setNodes((nds) => nds.filter((node) => !nodeIds.includes(node.id))) + setNodes((nds) => nds.filter((node) => !nodeIds.has(node.id))) setEdges((eds) => eds.filter((edge) => - !nodeIds.includes(edge.source) && !nodeIds.includes(edge.target) + !nodeIds.has(edge.source) && !nodeIds.has(edge.target) )) setSelectedNode(null) - markDirty() } if (selectedEdges.length > 0) { - const edgeIds = selectedEdges.map((edge) => edge.id) - setEdges((eds) => eds.filter((edge) => !edgeIds.includes(edge.id))) + setEdges((eds) => eds.filter((edge) => !selectedEdgeIds.has(edge.id))) + } + + if (selectedNodes.length > 0 || selectedEdges.length > 0) { markDirty() } } diff --git a/frontend/src/components/workflow/ComponentBadge.tsx b/frontend/src/components/workflow/ComponentBadge.tsx index caf38e74..b5bececb 100644 --- a/frontend/src/components/workflow/ComponentBadge.tsx +++ b/frontend/src/components/workflow/ComponentBadge.tsx @@ -60,27 +60,27 @@ export function ComponentBadge({ type, version, compact = false, className }: Co const Icon = config.icon const isOfficial = type === 'official' const effectiveCompact = compact || isOfficial + const showLabel = !(type === 'official' && compact) // Customize label for outdated badge with version - let label = type === 'outdated' && version + const label = type === 'outdated' && version ? `v${version} available` : config.label - if (type === 'official' && compact) { - label = 'SSA' - } - return ( - {label} + {showLabel && label} ) } @@ -170,7 +170,9 @@ export function ComponentMetadataSummary({ ? 'flex flex-col gap-1' : 'flex items-center gap-1 flex-wrap' - const versionClass = compact ? 'text-[10px]' : 'text-xs' + const versionClass = compact + ? 'text-[10px] font-medium uppercase tracking-[0.08em]' + : 'text-xs font-mono' return (
    @@ -192,7 +194,7 @@ export function ComponentMetadataSummary({
    )} {hasVersion && ( - + v{component.version} )} diff --git a/frontend/src/components/workflow/ConfigPanel.tsx b/frontend/src/components/workflow/ConfigPanel.tsx index 22ad3edc..abea3bbf 100644 --- a/frontend/src/components/workflow/ConfigPanel.tsx +++ b/frontend/src/components/workflow/ConfigPanel.tsx @@ -1,12 +1,13 @@ import { X, ExternalLink } from 'lucide-react' import * as LucideIcons from 'lucide-react' import { Button } from '@/components/ui/button' +import { Input } from '@/components/ui/input' import { cn } from '@/lib/utils' import { useComponentStore } from '@/store/componentStore' -import { ComponentMetadataSummary } from './ComponentBadge' import { ParameterFieldWrapper } from './ParameterField' import type { Node } from 'reactflow' import type { NodeData } from '@/schemas/node' +import { inputSupportsType, normalizePortTypes } from '@/utils/portUtils' interface ConfigPanelProps { selectedNode: Node | null @@ -28,8 +29,13 @@ export function ConfigPanel({ selectedNode, onClose, onUpdateNode }: ConfigPanel const nodeData = selectedNode.data as any const updatedParameters = { - ...nodeData.parameters, - [paramId]: value, + ...(nodeData.parameters ?? {}), + } + + if (value === undefined) { + delete updatedParameters[paramId] + } else { + updatedParameters[paramId] = value } onUpdateNode(selectedNode.id, { @@ -125,11 +131,6 @@ export function ConfigPanel({ selectedNode, onClose, onUpdateNode }: ConfigPanel

    {component.name}

    -

    {component.description}

    @@ -145,81 +146,118 @@ export function ConfigPanel({ selectedNode, onClose, onUpdateNode }: ConfigPanel
    Inputs
    - {componentInputs.map((input) => ( -
    -
    - {input.label} - {input.required && ( - *required + {componentInputs.map((input) => { + const connection = nodeData.inputs?.[input.id] + const manualValue = manualParameters[input.id] + const supportsManualString = inputSupportsType(input, 'string') + const supportsManualOverride = supportsManualString || input.valuePriority === 'manual-first' + const manualValueProvided = + supportsManualOverride && + manualValue !== undefined && + manualValue !== null && + (typeof manualValue === 'string' + ? manualValue.trim().length > 0 + : true) + const typeLabel = normalizePortTypes(input.type).join(' | ') + + return ( +
    +
    + {input.label} + {input.required && ( + *required + )} +
    +
    + Type: {typeLabel} +
    + {input.description && ( +

    + {input.description} +

    )} -
    -
    - Type: {input.type} -
    - {input.description && ( -

    - {input.description} -

    - )} - {/* Connection status */} -
    -
    - {(() => { - const connection = nodeData.inputs?.[input.id] - const manualValueProvided = - input.valuePriority === 'manual-first' && - Object.prototype.hasOwnProperty.call(manualParameters, input.id) && - manualParameters[input.id] !== undefined - if (manualValueProvided) { - return ( - <> -
    - • Manual value will be used -
    - {connection ? ( -
    - Connection available from{' '} - - {connection.source} - - . It will be used if the manual value is cleared. -
    - ) : ( -
    - No connection required while a manual value is set. -
    - )} - - ) - } + {supportsManualString && ( +
    + + { + const nextValue = e.target.value + if (nextValue === '') { + handleParameterChange(input.id, undefined) + } else { + handleParameterChange(input.id, nextValue) + } + }} + placeholder="Enter text to use without a connection" + className="text-sm" + /> +

    + When set, this input no longer requires a connection. +

    +
    + )} - if (connection) { - return ( -
    -
    - ✓ Connected + {/* Connection status */} +
    +
    + {manualValueProvided ? ( + <> +
    + • Manual value in use +
    + {supportsManualString && typeof manualValue === 'string' && manualValue.trim().length > 0 && ( +
    + Value:{' '} + + {manualValue} +
    + )} + {connection ? (
    - Source:{' '} + Connection available from{' '} {connection.source} + . It will be used if the manual value is cleared.
    + ) : (
    - Output:{' '} - - {connection.output} - + No connection required while a manual value is set.
    + )} + + ) : connection ? ( +
    +
    + ✓ Connected
    - ) - } - - return ( +
    + Source:{' '} + + {connection.source} + +
    +
    + Output:{' '} + + {connection.output} + +
    +
    + ) : (
    {input.required ? ( @@ -231,12 +269,12 @@ export function ConfigPanel({ selectedNode, onClose, onUpdateNode }: ConfigPanel )}
    - ) - })()} + )} +
    -
    - ))} + ) + })}
    )} @@ -382,7 +420,7 @@ export function ConfigPanel({ selectedNode, onClose, onUpdateNode }: ConfigPanel
    Node ID: {selectedNode.id} - v{component.version} + {component.slug}
    diff --git a/frontend/src/components/workflow/RunWorkflowDialog.tsx b/frontend/src/components/workflow/RunWorkflowDialog.tsx index 21101818..bdd42a43 100644 --- a/frontend/src/components/workflow/RunWorkflowDialog.tsx +++ b/frontend/src/components/workflow/RunWorkflowDialog.tsx @@ -14,10 +14,17 @@ import { Textarea } from '@/components/ui/textarea' import { Play, Loader2 } from 'lucide-react' import { api } from '@/services/api' +type RuntimeInputType = 'file' | 'text' | 'number' | 'json' | 'array' | 'string' +type NormalizedRuntimeInputType = Exclude + +const normalizeRuntimeInputType = ( + type: RuntimeInputType, +): NormalizedRuntimeInputType => (type === 'string' ? 'text' : type) + interface RuntimeInputDefinition { id: string label: string - type: 'file' | 'text' | 'number' | 'json' | 'array' + type: RuntimeInputType required: boolean description?: string } @@ -25,7 +32,6 @@ interface RuntimeInputDefinition { interface RunWorkflowDialogProps { open: boolean onOpenChange: (open: boolean) => void - workflowId: string runtimeInputs: RuntimeInputDefinition[] onRun: (inputs: Record) => void } @@ -33,7 +39,6 @@ interface RunWorkflowDialogProps { export function RunWorkflowDialog({ open, onOpenChange, - workflowId: _workflowId, runtimeInputs, onRun, }: RunWorkflowDialogProps) { @@ -74,15 +79,16 @@ export function RunWorkflowDialog({ const handleInputChange = ( inputId: string, value: unknown, - type: RuntimeInputDefinition['type'] + type: RuntimeInputType, ) => { setErrors(prev => ({ ...prev, [inputId]: '' })) + const normalizedType = normalizeRuntimeInputType(type) // Parse based on type let parsedValue = value - if (type === 'number') { + if (normalizedType === 'number') { parsedValue = value ? parseFloat(value as string) : undefined - } else if (type === 'array') { + } else if (normalizedType === 'array') { const textValue = typeof value === 'string' ? value : '' const trimmedValue = textValue.trim() @@ -113,7 +119,7 @@ export function RunWorkflowDialog({ parsedValue = fallback } } - } else if (type === 'json') { + } else if (normalizedType === 'json') { try { parsedValue = value ? JSON.parse(value as string) : undefined } catch (error) { @@ -149,8 +155,9 @@ export function RunWorkflowDialog({ const renderInput = (input: RuntimeInputDefinition) => { const hasError = !!errors[input.id] const isUploading = uploading[input.id] + const inputType = normalizeRuntimeInputType(input.type) - switch (input.type) { + switch (inputType) { case 'file': return (
    @@ -197,7 +204,7 @@ export function RunWorkflowDialog({