mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-05 05:04:10 -05:00
improvement(monorepo): added tsconfig package, resolved type errors in testing package (#2613)
This commit is contained in:
@@ -29,6 +29,7 @@
|
||||
"tailwind-merge": "^3.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sim/tsconfig": "workspace:*",
|
||||
"@tailwindcss/postcss": "^4.0.12",
|
||||
"@types/mdx": "^2.0.13",
|
||||
"@types/node": "^22.14.1",
|
||||
|
||||
@@ -1,29 +1,11 @@
|
||||
{
|
||||
"extends": "@sim/tsconfig/nextjs.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"target": "ESNext",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"incremental": true,
|
||||
"paths": {
|
||||
"@/.source/*": ["./.source/*"],
|
||||
"@/*": ["./*"]
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
|
||||
@@ -14,7 +14,7 @@ export async function GET() {
|
||||
headers: {
|
||||
Accept: 'application/vnd.github+json',
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
'User-Agent': 'SimStudio/1.0',
|
||||
'User-Agent': 'Sim/1.0',
|
||||
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
||||
},
|
||||
next: { revalidate: 3600 },
|
||||
|
||||
@@ -138,7 +138,10 @@ describe('OAuth Token Refresh', () => {
|
||||
})
|
||||
)
|
||||
|
||||
const [, requestOptions] = mockFetch.mock.calls[0]
|
||||
const [, requestOptions] = mockFetch.mock.calls[0] as [
|
||||
string,
|
||||
{ headers: Record<string, string>; body: string },
|
||||
]
|
||||
|
||||
const authHeader = requestOptions.headers.Authorization
|
||||
expect(authHeader).toMatch(/^Basic /)
|
||||
@@ -251,7 +254,10 @@ describe('OAuth Token Refresh', () => {
|
||||
})
|
||||
)
|
||||
|
||||
const [, requestOptions] = mockFetch.mock.calls[0]
|
||||
const [, requestOptions] = mockFetch.mock.calls[0] as [
|
||||
string,
|
||||
{ headers: Record<string, string>; body: string },
|
||||
]
|
||||
|
||||
expect(requestOptions.headers.Authorization).toBeUndefined()
|
||||
|
||||
@@ -279,7 +285,10 @@ describe('OAuth Token Refresh', () => {
|
||||
|
||||
await withMockFetch(mockFetch, () => refreshOAuthToken('github', refreshToken))
|
||||
|
||||
const [, requestOptions] = mockFetch.mock.calls[0]
|
||||
const [, requestOptions] = mockFetch.mock.calls[0] as [
|
||||
string,
|
||||
{ headers: Record<string, string>; body: string },
|
||||
]
|
||||
expect(requestOptions.headers.Accept).toBe('application/json')
|
||||
})
|
||||
|
||||
@@ -289,7 +298,10 @@ describe('OAuth Token Refresh', () => {
|
||||
|
||||
await withMockFetch(mockFetch, () => refreshOAuthToken('reddit', refreshToken))
|
||||
|
||||
const [, requestOptions] = mockFetch.mock.calls[0]
|
||||
const [, requestOptions] = mockFetch.mock.calls[0] as [
|
||||
string,
|
||||
{ headers: Record<string, string>; body: string },
|
||||
]
|
||||
expect(requestOptions.headers['User-Agent']).toBe(
|
||||
'sim-studio/1.0 (https://github.com/simstudioai/sim)'
|
||||
)
|
||||
|
||||
@@ -652,7 +652,7 @@ async function processEmails(
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Webhook-Secret': webhookData.secret || '',
|
||||
'User-Agent': 'SimStudio/1.0',
|
||||
'User-Agent': 'Sim/1.0',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
|
||||
@@ -465,7 +465,7 @@ async function processOutlookEmails(
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Webhook-Secret': webhookData.secret || '',
|
||||
'User-Agent': 'SimStudio/1.0',
|
||||
'User-Agent': 'Sim/1.0',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
|
||||
@@ -60,7 +60,7 @@ export interface RssWebhookPayload {
|
||||
const parser = new Parser({
|
||||
timeout: 30000,
|
||||
headers: {
|
||||
'User-Agent': 'SimStudio/1.0 RSS Poller',
|
||||
'User-Agent': 'Sim/1.0 RSS Poller',
|
||||
},
|
||||
})
|
||||
|
||||
@@ -255,7 +255,7 @@ async function fetchNewRssItems(
|
||||
const response = await fetch(pinnedUrl, {
|
||||
headers: {
|
||||
Host: urlValidation.originalHostname!,
|
||||
'User-Agent': 'SimStudio/1.0 RSS Poller',
|
||||
'User-Agent': 'Sim/1.0 RSS Poller',
|
||||
Accept: 'application/rss+xml, application/xml, text/xml, */*',
|
||||
},
|
||||
signal: AbortSignal.timeout(30000),
|
||||
@@ -362,7 +362,7 @@ async function processRssItems(
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Webhook-Secret': webhookData.secret || '',
|
||||
'User-Agent': 'SimStudio/1.0',
|
||||
'User-Agent': 'Sim/1.0',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
|
||||
@@ -46,10 +46,9 @@ function asAppBlocks<T>(blocks: T): Record<string, AppBlockState> {
|
||||
* These tests intentionally use old SubBlockTypes (textarea, select, messages-input, input)
|
||||
* to verify the migration logic converts them to new types.
|
||||
*/
|
||||
function legacySubBlocks<T>(
|
||||
subBlocks: T
|
||||
): Record<string, { id: string; type: string; value: any }> {
|
||||
return subBlocks as Record<string, { id: string; type: string; value: any }>
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function legacySubBlocks(subBlocks: Record<string, any>): any {
|
||||
return subBlocks
|
||||
}
|
||||
|
||||
const { mockDb, mockWorkflowBlocks, mockWorkflowEdges, mockWorkflowSubflows } = vi.hoisted(() => {
|
||||
@@ -1022,7 +1021,7 @@ describe('Database Helpers', () => {
|
||||
position: { x: 100, y: 100 },
|
||||
height: 150,
|
||||
advancedMode: false,
|
||||
subBlocks: { model: { id: 'model', type: 'select', value: 'gpt-4o' } },
|
||||
subBlocks: legacySubBlocks({ model: { id: 'model', type: 'select', value: 'gpt-4o' } }),
|
||||
}),
|
||||
mockWorkflowId
|
||||
)
|
||||
@@ -1034,11 +1033,11 @@ describe('Database Helpers', () => {
|
||||
position: { x: 200, y: 100 },
|
||||
height: 200,
|
||||
advancedMode: true,
|
||||
subBlocks: {
|
||||
subBlocks: legacySubBlocks({
|
||||
systemPrompt: { id: 'systemPrompt', type: 'textarea', value: 'System prompt' },
|
||||
userPrompt: { id: 'userPrompt', type: 'textarea', value: 'User prompt' },
|
||||
model: { id: 'model', type: 'select', value: 'gpt-4o' },
|
||||
},
|
||||
}),
|
||||
}),
|
||||
mockWorkflowId
|
||||
)
|
||||
@@ -1153,7 +1152,7 @@ describe('Database Helpers', () => {
|
||||
'agent-1': createAgentBlock({
|
||||
id: 'agent-1',
|
||||
name: 'Test Agent',
|
||||
subBlocks: {
|
||||
subBlocks: legacySubBlocks({
|
||||
systemPrompt: {
|
||||
id: 'systemPrompt',
|
||||
type: 'textarea',
|
||||
@@ -1164,7 +1163,7 @@ describe('Database Helpers', () => {
|
||||
type: 'textarea',
|
||||
value: 'Hello world',
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -1183,13 +1182,13 @@ describe('Database Helpers', () => {
|
||||
const blocks = {
|
||||
'agent-1': createAgentBlock({
|
||||
id: 'agent-1',
|
||||
subBlocks: {
|
||||
subBlocks: legacySubBlocks({
|
||||
systemPrompt: {
|
||||
id: 'systemPrompt',
|
||||
type: 'textarea',
|
||||
value: 'You are helpful',
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -1204,13 +1203,13 @@ describe('Database Helpers', () => {
|
||||
const blocks = {
|
||||
'agent-1': createAgentBlock({
|
||||
id: 'agent-1',
|
||||
subBlocks: {
|
||||
subBlocks: legacySubBlocks({
|
||||
userPrompt: {
|
||||
id: 'userPrompt',
|
||||
type: 'textarea',
|
||||
value: 'Hello',
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -1225,13 +1224,13 @@ describe('Database Helpers', () => {
|
||||
const blocks = {
|
||||
'agent-1': createAgentBlock({
|
||||
id: 'agent-1',
|
||||
subBlocks: {
|
||||
subBlocks: legacySubBlocks({
|
||||
userPrompt: {
|
||||
id: 'userPrompt',
|
||||
type: 'textarea',
|
||||
value: { input: 'Hello from object' },
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -1246,13 +1245,13 @@ describe('Database Helpers', () => {
|
||||
const blocks = {
|
||||
'agent-1': createAgentBlock({
|
||||
id: 'agent-1',
|
||||
subBlocks: {
|
||||
subBlocks: legacySubBlocks({
|
||||
userPrompt: {
|
||||
id: 'userPrompt',
|
||||
type: 'textarea',
|
||||
value: { foo: 'bar', baz: 123 },
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -1268,7 +1267,7 @@ describe('Database Helpers', () => {
|
||||
const blocks = {
|
||||
'agent-1': createAgentBlock({
|
||||
id: 'agent-1',
|
||||
subBlocks: {
|
||||
subBlocks: legacySubBlocks({
|
||||
systemPrompt: {
|
||||
id: 'systemPrompt',
|
||||
type: 'textarea',
|
||||
@@ -1284,7 +1283,7 @@ describe('Database Helpers', () => {
|
||||
type: 'messages-input',
|
||||
value: existingMessages,
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -1297,13 +1296,13 @@ describe('Database Helpers', () => {
|
||||
const blocks = {
|
||||
'agent-1': createAgentBlock({
|
||||
id: 'agent-1',
|
||||
subBlocks: {
|
||||
subBlocks: legacySubBlocks({
|
||||
model: {
|
||||
id: 'model',
|
||||
type: 'select',
|
||||
value: 'gpt-4o',
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -1316,13 +1315,13 @@ describe('Database Helpers', () => {
|
||||
const blocks = {
|
||||
'api-1': createApiBlock({
|
||||
id: 'api-1',
|
||||
subBlocks: {
|
||||
subBlocks: legacySubBlocks({
|
||||
url: {
|
||||
id: 'url',
|
||||
type: 'input',
|
||||
value: 'https://example.com',
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -1336,18 +1335,18 @@ describe('Database Helpers', () => {
|
||||
const blocks = {
|
||||
'agent-1': createAgentBlock({
|
||||
id: 'agent-1',
|
||||
subBlocks: {
|
||||
subBlocks: legacySubBlocks({
|
||||
systemPrompt: { id: 'systemPrompt', type: 'textarea', value: 'System 1' },
|
||||
},
|
||||
}),
|
||||
}),
|
||||
'api-1': createApiBlock({
|
||||
id: 'api-1',
|
||||
}),
|
||||
'agent-2': createAgentBlock({
|
||||
id: 'agent-2',
|
||||
subBlocks: {
|
||||
subBlocks: legacySubBlocks({
|
||||
userPrompt: { id: 'userPrompt', type: 'textarea', value: 'User 2' },
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -1368,10 +1367,10 @@ describe('Database Helpers', () => {
|
||||
const blocks = {
|
||||
'agent-1': createAgentBlock({
|
||||
id: 'agent-1',
|
||||
subBlocks: {
|
||||
subBlocks: legacySubBlocks({
|
||||
systemPrompt: { id: 'systemPrompt', type: 'textarea', value: '' },
|
||||
userPrompt: { id: 'userPrompt', type: 'textarea', value: '' },
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -1384,9 +1383,9 @@ describe('Database Helpers', () => {
|
||||
const blocks = {
|
||||
'agent-1': createAgentBlock({
|
||||
id: 'agent-1',
|
||||
subBlocks: {
|
||||
subBlocks: legacySubBlocks({
|
||||
systemPrompt: { id: 'systemPrompt', type: 'textarea', value: 123 },
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -1401,9 +1400,9 @@ describe('Database Helpers', () => {
|
||||
const blocks = {
|
||||
'agent-1': createAgentBlock({
|
||||
id: 'agent-1',
|
||||
subBlocks: {
|
||||
subBlocks: legacySubBlocks({
|
||||
systemPrompt: { id: 'systemPrompt', type: 'textarea', value: 'System' },
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
"generate-docs": "bun run ../../scripts/generate-docs.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sim/logger": "workspace:*",
|
||||
"@anthropic-ai/sdk": "^0.39.0",
|
||||
"@aws-sdk/client-dynamodb": "3.940.0",
|
||||
"@aws-sdk/client-rds-data": "3.940.0",
|
||||
@@ -40,6 +39,8 @@
|
||||
"@e2b/code-interpreter": "^2.0.0",
|
||||
"@google/genai": "1.34.0",
|
||||
"@hookform/resolvers": "^4.1.3",
|
||||
"@linear/sdk": "40.0.0",
|
||||
"@modelcontextprotocol/sdk": "1.20.2",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@opentelemetry/exporter-jaeger": "2.1.0",
|
||||
"@opentelemetry/exporter-trace-otlp-http": "^0.200.0",
|
||||
@@ -70,6 +71,10 @@
|
||||
"@radix-ui/react-visually-hidden": "1.2.4",
|
||||
"@react-email/components": "^0.0.34",
|
||||
"@react-email/render": "2.0.0",
|
||||
"@sim/logger": "workspace:*",
|
||||
"@t3-oss/env-nextjs": "0.13.4",
|
||||
"@tanstack/react-query": "5.90.8",
|
||||
"@tanstack/react-query-devtools": "5.90.2",
|
||||
"@trigger.dev/sdk": "4.1.2",
|
||||
"@types/react-window": "2.0.0",
|
||||
"@types/three": "0.177.0",
|
||||
@@ -82,18 +87,25 @@
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.0",
|
||||
"croner": "^9.0.0",
|
||||
"cronstrue": "3.3.0",
|
||||
"csv-parse": "6.1.0",
|
||||
"date-fns": "4.1.0",
|
||||
"decimal.js": "10.6.0",
|
||||
"drizzle-orm": "^0.44.5",
|
||||
"encoding": "0.1.13",
|
||||
"entities": "6.0.1",
|
||||
"ffmpeg-static": "5.3.0",
|
||||
"fluent-ffmpeg": "2.1.3",
|
||||
"framer-motion": "^12.5.0",
|
||||
"fuse.js": "7.1.0",
|
||||
"google-auth-library": "10.5.0",
|
||||
"gray-matter": "^4.0.3",
|
||||
"groq-sdk": "^0.15.0",
|
||||
"html-to-image": "1.11.13",
|
||||
"html-to-text": "^9.0.5",
|
||||
"input-otp": "^1.4.2",
|
||||
"ioredis": "^5.6.0",
|
||||
"isolated-vm": "6.0.2",
|
||||
"jose": "6.0.11",
|
||||
"js-tiktoken": "1.0.21",
|
||||
"js-yaml": "4.1.0",
|
||||
@@ -102,17 +114,22 @@
|
||||
"lodash": "4.17.21",
|
||||
"lucide-react": "^0.479.0",
|
||||
"mammoth": "^1.9.0",
|
||||
"mongodb": "6.19.0",
|
||||
"mysql2": "3.14.3",
|
||||
"nanoid": "^3.3.7",
|
||||
"neo4j-driver": "6.0.1",
|
||||
"next": "16.1.0-canary.21",
|
||||
"next-mdx-remote": "^5.0.0",
|
||||
"next-runtime-env": "3.3.0",
|
||||
"next-themes": "^0.4.6",
|
||||
"nodemailer": "7.0.11",
|
||||
"officeparser": "^5.2.0",
|
||||
"onedollarstats": "0.0.10",
|
||||
"openai": "^4.91.1",
|
||||
"papaparse": "5.5.3",
|
||||
"posthog-js": "1.268.9",
|
||||
"posthog-node": "5.9.2",
|
||||
"postgres": "^3.4.5",
|
||||
"prismjs": "^1.30.0",
|
||||
"react": "19.2.1",
|
||||
"react-colorful": "5.6.1",
|
||||
@@ -126,14 +143,17 @@
|
||||
"rehype-slug": "^6.0.0",
|
||||
"remark-gfm": "4.0.1",
|
||||
"resend": "^4.1.2",
|
||||
"rss-parser": "3.13.0",
|
||||
"sharp": "0.34.3",
|
||||
"socket.io": "^4.8.1",
|
||||
"socket.io-client": "4.8.1",
|
||||
"ssh2": "^1.17.0",
|
||||
"stripe": "18.5.0",
|
||||
"tailwind-merge": "^2.6.0",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
"thread-stream": "4.0.0",
|
||||
"three": "0.177.0",
|
||||
"twilio": "5.9.0",
|
||||
"unpdf": "1.4.0",
|
||||
"uuid": "^11.1.0",
|
||||
"xlsx": "0.18.5",
|
||||
@@ -142,13 +162,16 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sim/testing": "workspace:*",
|
||||
"@sim/tsconfig": "workspace:*",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
"@trigger.dev/build": "4.1.2",
|
||||
"@types/fluent-ffmpeg": "2.1.28",
|
||||
"@types/html-to-text": "9.0.4",
|
||||
"@types/js-yaml": "4.0.9",
|
||||
"@types/jsdom": "21.1.7",
|
||||
"@types/lodash": "^4.17.16",
|
||||
"@types/node": "24.2.1",
|
||||
"@types/nodemailer": "7.0.4",
|
||||
"@types/papaparse": "5.3.16",
|
||||
"@types/prismjs": "^1.26.5",
|
||||
"@types/react": "^19",
|
||||
@@ -171,6 +194,8 @@
|
||||
"trustedDependencies": [
|
||||
"canvas",
|
||||
"better-sqlite3",
|
||||
"ffmpeg-static",
|
||||
"isolated-vm",
|
||||
"sharp"
|
||||
],
|
||||
"overrides": {
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
} from '@sim/testing'
|
||||
import { beforeEach, describe, expect, it } from 'vitest'
|
||||
import { runWithUndoRedoRecordingSuspended, useUndoRedoStore } from '@/stores/undo-redo/store'
|
||||
import type { DuplicateBlockOperation, UpdateParentOperation } from '@/stores/undo-redo/types'
|
||||
|
||||
describe('useUndoRedoStore', () => {
|
||||
const workflowId = 'wf-test'
|
||||
@@ -663,7 +664,8 @@ describe('useUndoRedoStore', () => {
|
||||
)
|
||||
|
||||
const entry = undo(workflowId, userId)
|
||||
expect(entry?.operation.data.duplicatedBlockSnapshot).toMatchObject({
|
||||
const operation = entry?.operation as DuplicateBlockOperation
|
||||
expect(operation.data.duplicatedBlockSnapshot).toMatchObject({
|
||||
id: 'duplicated-block',
|
||||
name: 'Duplicated Agent',
|
||||
type: 'agent',
|
||||
@@ -716,10 +718,11 @@ describe('useUndoRedoStore', () => {
|
||||
)
|
||||
|
||||
const entry = undo(workflowId, userId)
|
||||
expect(entry?.inverse.data.oldParentId).toBe('loop-2')
|
||||
expect(entry?.inverse.data.newParentId).toBe('loop-1')
|
||||
expect(entry?.inverse.data.oldPosition).toEqual({ x: 100, y: 100 })
|
||||
expect(entry?.inverse.data.newPosition).toEqual({ x: 0, y: 0 })
|
||||
const inverse = entry?.inverse as UpdateParentOperation
|
||||
expect(inverse.data.oldParentId).toBe('loop-2')
|
||||
expect(inverse.data.newParentId).toBe('loop-1')
|
||||
expect(inverse.data.oldPosition).toEqual({ x: 100, y: 100 })
|
||||
expect(inverse.data.newPosition).toEqual({ x: 0, y: 0 })
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ export const pageContentTool: ToolConfig<WikipediaPageContentParams, WikipediaPa
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'User-Agent': 'SimStudio/1.0 (https://sim.ai)',
|
||||
'User-Agent': 'Sim/1.0 (https://sim.ai)',
|
||||
Accept:
|
||||
'text/html; charset=utf-8; profile="https://www.mediawiki.org/wiki/Specs/HTML/2.1.0"',
|
||||
}),
|
||||
|
||||
@@ -15,7 +15,7 @@ export const randomPageTool: ToolConfig<Record<string, never>, WikipediaRandomPa
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'User-Agent': 'SimStudio/1.0 (https://sim.ai)',
|
||||
'User-Agent': 'Sim/1.0 (https://sim.ai)',
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
@@ -41,7 +41,7 @@ export const searchTool: ToolConfig<WikipediaSearchParams, WikipediaSearchRespon
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'User-Agent': 'SimStudio/1.0 (https://sim.ai)',
|
||||
'User-Agent': 'Sim/1.0 (https://sim.ai)',
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@ export const pageSummaryTool: ToolConfig<WikipediaPageSummaryParams, WikipediaPa
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'User-Agent': 'SimStudio/1.0 (https://sim.ai)',
|
||||
'User-Agent': 'Sim/1.0 (https://sim.ai)',
|
||||
Accept: 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
{
|
||||
"extends": "@sim/tsconfig/nextjs.json",
|
||||
"compilerOptions": {
|
||||
"target": "es2022",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"lib": ["es2022", "dom", "dom.iterable"],
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./*"],
|
||||
@@ -28,19 +21,7 @@
|
||||
"@sim/db/*": ["../../packages/db/*"],
|
||||
"@/executor": ["./executor"],
|
||||
"@/executor/*": ["./executor/*"]
|
||||
},
|
||||
"allowJs": true,
|
||||
"noEmit": true,
|
||||
"incremental": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"jsx": "react-jsx",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
|
||||
@@ -18,18 +18,19 @@ FROM base AS deps
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json bun.lock turbo.json ./
|
||||
RUN mkdir -p apps packages/db packages/testing packages/logger
|
||||
RUN mkdir -p apps packages/db packages/testing packages/logger packages/tsconfig
|
||||
COPY apps/sim/package.json ./apps/sim/package.json
|
||||
COPY packages/db/package.json ./packages/db/package.json
|
||||
COPY packages/testing/package.json ./packages/testing/package.json
|
||||
COPY packages/logger/package.json ./packages/logger/package.json
|
||||
COPY packages/tsconfig/package.json ./packages/tsconfig/package.json
|
||||
|
||||
# Install turbo globally, then dependencies, then rebuild isolated-vm for Node.js
|
||||
RUN --mount=type=cache,id=bun-cache,target=/root/.bun/install/cache \
|
||||
--mount=type=cache,id=npm-cache,target=/root/.npm \
|
||||
bun install -g turbo && \
|
||||
HUSKY=0 bun install --omit=dev --ignore-scripts && \
|
||||
cd $(readlink -f node_modules/isolated-vm) && npx node-gyp rebuild --release && cd /app
|
||||
cd node_modules/.bun/isolated-vm@*/node_modules/isolated-vm && npx node-gyp rebuild --release && cd /app
|
||||
|
||||
# ========================================
|
||||
# Builder Stage: Build the Application
|
||||
@@ -104,7 +105,7 @@ COPY --from=builder --chown=nextjs:nodejs /app/apps/sim/.next/standalone ./
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/apps/sim/.next/static ./apps/sim/.next/static
|
||||
|
||||
# Copy isolated-vm native module (compiled for Node.js in deps stage)
|
||||
COPY --from=deps --chown=nextjs:nodejs /app/node_modules/isolated-vm ./node_modules/isolated-vm
|
||||
COPY --from=deps --chown=nextjs:nodejs /app/node_modules/.bun/isolated-vm@6.0.2/node_modules/isolated-vm ./node_modules/isolated-vm
|
||||
|
||||
# Copy the isolated-vm worker script
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/apps/sim/lib/execution/isolated-vm-worker.cjs ./apps/sim/lib/execution/isolated-vm-worker.cjs
|
||||
|
||||
@@ -11,11 +11,12 @@ RUN apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json bun.lock turbo.json ./
|
||||
RUN mkdir -p apps packages/db packages/testing packages/logger
|
||||
RUN mkdir -p apps packages/db packages/testing packages/logger packages/tsconfig
|
||||
COPY apps/sim/package.json ./apps/sim/package.json
|
||||
COPY packages/db/package.json ./packages/db/package.json
|
||||
COPY packages/testing/package.json ./packages/testing/package.json
|
||||
COPY packages/logger/package.json ./packages/logger/package.json
|
||||
COPY packages/tsconfig/package.json ./packages/tsconfig/package.json
|
||||
|
||||
# Install dependencies with cache mount for faster builds
|
||||
RUN --mount=type=cache,id=bun-cache,target=/root/.bun/install/cache \
|
||||
|
||||
28
package.json
28
package.json
@@ -33,37 +33,11 @@
|
||||
"drizzle-orm": "^0.44.5",
|
||||
"postgres": "^3.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@linear/sdk": "40.0.0",
|
||||
"@modelcontextprotocol/sdk": "1.20.2",
|
||||
"@t3-oss/env-nextjs": "0.13.4",
|
||||
"@tanstack/react-query": "5.90.8",
|
||||
"@tanstack/react-query-devtools": "5.90.2",
|
||||
"@types/fluent-ffmpeg": "2.1.28",
|
||||
"cronstrue": "3.3.0",
|
||||
"decimal.js": "10.6.0",
|
||||
"drizzle-orm": "^0.44.5",
|
||||
"ffmpeg-static": "5.3.0",
|
||||
"fluent-ffmpeg": "2.1.3",
|
||||
"isolated-vm": "6.0.2",
|
||||
"mongodb": "6.19.0",
|
||||
"neo4j-driver": "6.0.1",
|
||||
"next-runtime-env": "3.3.0",
|
||||
"nodemailer": "7.0.11",
|
||||
"onedollarstats": "0.0.10",
|
||||
"postgres": "^3.4.5",
|
||||
"remark-gfm": "4.0.1",
|
||||
"rss-parser": "3.13.0",
|
||||
"socket.io-client": "4.8.1",
|
||||
"twilio": "5.9.0",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.0.0-beta.5",
|
||||
"@next/env": "16.1.0-canary.21",
|
||||
"@octokit/rest": "^21.0.0",
|
||||
"@tailwindcss/typography": "0.5.19",
|
||||
"@types/nodemailer": "7.0.4",
|
||||
"drizzle-kit": "^0.31.4",
|
||||
"husky": "9.1.7",
|
||||
"lint-staged": "16.0.0",
|
||||
@@ -75,8 +49,6 @@
|
||||
]
|
||||
},
|
||||
"trustedDependencies": [
|
||||
"ffmpeg-static",
|
||||
"isolated-vm",
|
||||
"sharp"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,249 +1,18 @@
|
||||
# Sim SDKs
|
||||
# Packages
|
||||
|
||||
This directory contains the official SDKs for [Sim](https://sim.ai), allowing developers to execute workflows programmatically from their applications.
|
||||
## Internal
|
||||
|
||||
## Available SDKs
|
||||
| Package | Description |
|
||||
|---------|-------------|
|
||||
| [@sim/tsconfig](./tsconfig) | Shared TypeScript configs (base, nextjs, library, library-build) |
|
||||
| [@sim/db](./db) | Database schema and Drizzle ORM utilities |
|
||||
| [@sim/logger](./logger) | Structured logging with colored output |
|
||||
| [@sim/testing](./testing) | Test factories, builders, and assertions |
|
||||
|
||||
### Package Installation Commands
|
||||
## Published
|
||||
|
||||
- **TypeScript/JavaScript**: `npm install simstudio-ts-sdk`
|
||||
- **Python**: `pip install simstudio-sdk`
|
||||
|
||||
### 🟢 TypeScript/JavaScript SDK (`simstudio-ts-sdk`)
|
||||
|
||||
**Directory:** `ts-sdk/`
|
||||
|
||||
The TypeScript SDK provides type-safe workflow execution for Node.js and browser environments.
|
||||
|
||||
**Installation:**
|
||||
```bash
|
||||
npm install simstudio-ts-sdk
|
||||
# or
|
||||
yarn add simstudio-ts-sdk
|
||||
# or
|
||||
bun add simstudio-ts-sdk
|
||||
```
|
||||
|
||||
**Quick Start:**
|
||||
```typescript
|
||||
import { SimStudioClient } from 'simstudio-ts-sdk';
|
||||
|
||||
const client = new SimStudioClient({
|
||||
apiKey: 'your-api-key-here'
|
||||
});
|
||||
|
||||
const result = await client.executeWorkflow('workflow-id', {
|
||||
input: { message: 'Hello, world!' }
|
||||
});
|
||||
```
|
||||
|
||||
### 🐍 Python SDK (`simstudio-sdk`)
|
||||
|
||||
**Directory:** `python-sdk/`
|
||||
|
||||
The Python SDK provides Pythonic workflow execution with comprehensive error handling and data classes.
|
||||
|
||||
**Installation:**
|
||||
```bash
|
||||
pip install simstudio-sdk
|
||||
```
|
||||
|
||||
**Quick Start:**
|
||||
```python
|
||||
from simstudio import SimStudioClient
|
||||
|
||||
client = SimStudioClient(api_key='your-api-key-here')
|
||||
|
||||
result = client.execute_workflow('workflow-id',
|
||||
input_data={'message': 'Hello, world!'})
|
||||
```
|
||||
|
||||
## Core Features
|
||||
|
||||
Both SDKs provide the same core functionality:
|
||||
|
||||
✅ **Workflow Execution** - Execute deployed workflows with optional input data
|
||||
✅ **Status Checking** - Check deployment status and workflow readiness
|
||||
✅ **Error Handling** - Comprehensive error handling with specific error codes
|
||||
✅ **Timeout Support** - Configurable timeouts for workflow execution
|
||||
✅ **Input Validation** - Validate workflows before execution
|
||||
✅ **Type Safety** - Full type definitions (TypeScript) and data classes (Python)
|
||||
|
||||
## API Compatibility
|
||||
|
||||
Both SDKs are built on top of the same REST API endpoints:
|
||||
|
||||
- `POST /api/workflows/{id}/execute` - Execute workflow (with or without input)
|
||||
- `GET /api/workflows/{id}/status` - Get workflow status
|
||||
|
||||
## Authentication
|
||||
|
||||
Both SDKs use API key authentication via the `X-API-Key` header. You can obtain an API key by:
|
||||
|
||||
1. Logging in to your [Sim](https://sim.ai) account
|
||||
2. Navigating to your workflow
|
||||
3. Clicking "Deploy" to deploy your workflow
|
||||
4. Creating or selecting an API key during deployment
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Both SDKs support environment variable configuration:
|
||||
|
||||
```bash
|
||||
# Required
|
||||
SIM_API_KEY=your-api-key-here
|
||||
|
||||
# Optional
|
||||
SIM_BASE_URL=https://sim.ai # or your custom domain
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
Both SDKs provide consistent error handling with these error codes:
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| `UNAUTHORIZED` | Invalid API key |
|
||||
| `TIMEOUT` | Request timed out |
|
||||
| `USAGE_LIMIT_EXCEEDED` | Account usage limit exceeded |
|
||||
| `INVALID_JSON` | Invalid JSON in request body |
|
||||
| `EXECUTION_ERROR` | General execution error |
|
||||
| `STATUS_ERROR` | Error getting workflow status |
|
||||
|
||||
## Examples
|
||||
|
||||
### TypeScript Example
|
||||
|
||||
```typescript
|
||||
import { SimStudioClient, SimStudioError } from 'simstudio-ts-sdk';
|
||||
|
||||
const client = new SimStudioClient({
|
||||
apiKey: process.env.SIM_API_KEY!
|
||||
});
|
||||
|
||||
try {
|
||||
// Check if workflow is ready
|
||||
const isReady = await client.validateWorkflow('workflow-id');
|
||||
if (!isReady) {
|
||||
throw new Error('Workflow not deployed');
|
||||
}
|
||||
|
||||
// Execute workflow
|
||||
const result = await client.executeWorkflow('workflow-id', {
|
||||
input: { data: 'example' },
|
||||
timeout: 30000
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
console.log('Output:', result.output);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof SimStudioError) {
|
||||
console.error(`Error ${error.code}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Python Example
|
||||
|
||||
```python
|
||||
from simstudio import SimStudioClient, SimStudioError
|
||||
import os
|
||||
|
||||
client = SimStudioClient(api_key=os.getenv('SIM_API_KEY'))
|
||||
|
||||
try:
|
||||
# Check if workflow is ready
|
||||
is_ready = client.validate_workflow('workflow-id')
|
||||
if not is_ready:
|
||||
raise Exception('Workflow not deployed')
|
||||
|
||||
# Execute workflow
|
||||
result = client.execute_workflow('workflow-id',
|
||||
input_data={'data': 'example'},
|
||||
timeout=30.0)
|
||||
|
||||
if result.success:
|
||||
print(f'Output: {result.output}')
|
||||
|
||||
except SimStudioError as error:
|
||||
print(f'Error {error.code}: {error}')
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Building the SDKs
|
||||
|
||||
**TypeScript SDK:**
|
||||
```bash
|
||||
cd packages/ts-sdk
|
||||
bun install
|
||||
bun run build
|
||||
```
|
||||
|
||||
**Python SDK:**
|
||||
```bash
|
||||
cd packages/python-sdk
|
||||
pip install -e ".[dev]"
|
||||
python -m build
|
||||
```
|
||||
|
||||
### Running Examples
|
||||
|
||||
**TypeScript:**
|
||||
```bash
|
||||
cd packages/ts-sdk
|
||||
SIM_API_KEY=your-key bun run examples/basic-usage.ts
|
||||
```
|
||||
|
||||
**Python:**
|
||||
```bash
|
||||
cd packages/python-sdk
|
||||
SIM_API_KEY=your-key python examples/basic_usage.py
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
**TypeScript:**
|
||||
```bash
|
||||
cd packages/ts-sdk
|
||||
bun run test
|
||||
```
|
||||
|
||||
**Python:**
|
||||
```bash
|
||||
cd packages/python-sdk
|
||||
pytest
|
||||
```
|
||||
|
||||
## Publishing
|
||||
|
||||
The SDKs are automatically published to npm and PyPI when changes are pushed to the main branch. See [Publishing Setup](../.github/PUBLISHING.md) for details on:
|
||||
|
||||
- Setting up GitHub secrets for automated publishing
|
||||
- Manual publishing instructions
|
||||
- Version management and semantic versioning
|
||||
- Troubleshooting common issues
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch: `git checkout -b feature/amazing-feature`
|
||||
3. Make your changes
|
||||
4. Add tests for your changes
|
||||
5. Run the test suite: `bun run test` (TypeScript) or `pytest` (Python)
|
||||
6. Update version numbers if needed
|
||||
7. Commit your changes: `git commit -m 'Add amazing feature'`
|
||||
8. Push to the branch: `git push origin feature/amazing-feature`
|
||||
9. Open a Pull Request
|
||||
|
||||
## License
|
||||
|
||||
Both SDKs are licensed under the Apache-2.0 License. See the [LICENSE](../LICENSE) file for details.
|
||||
|
||||
## Support
|
||||
|
||||
- 📖 [Documentation](https://docs.sim.ai)
|
||||
- 💬 [Discord Community](https://discord.gg/simstudio)
|
||||
- 🐛 [Issue Tracker](https://github.com/simstudioai/sim/issues)
|
||||
- 📧 [Email Support](mailto:support@sim.ai)
|
||||
| Package | npm | Description |
|
||||
|---------|-----|-------------|
|
||||
| [cli](./cli) | `simstudio` | Run Sim locally via Docker |
|
||||
| [ts-sdk](./ts-sdk) | `simstudio-ts-sdk` | TypeScript SDK for workflow execution |
|
||||
| [python-sdk](./python-sdk) | `simstudio-sdk` | Python SDK for workflow execution |
|
||||
|
||||
@@ -2,14 +2,19 @@
|
||||
"name": "simstudio",
|
||||
"version": "0.1.19",
|
||||
"description": "Sim CLI - Run Sim with a single command",
|
||||
"main": "dist/index.js",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js"
|
||||
}
|
||||
},
|
||||
"bin": {
|
||||
"simstudio": "dist/index.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "bun run build:tsc",
|
||||
"build:tsc": "tsc",
|
||||
"build": "tsc",
|
||||
"type-check": "tsc --noEmit",
|
||||
"prepublishOnly": "bun run build"
|
||||
},
|
||||
"files": [
|
||||
@@ -19,17 +24,16 @@
|
||||
"simstudio",
|
||||
"ai",
|
||||
"workflow",
|
||||
"ui",
|
||||
"cli",
|
||||
"sim",
|
||||
"sim-studio",
|
||||
"agent",
|
||||
"agents",
|
||||
"automation",
|
||||
"docker"
|
||||
],
|
||||
"author": "Sim",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.2",
|
||||
"commander": "^11.1.0",
|
||||
@@ -38,20 +42,9 @@
|
||||
"listr2": "^6.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sim/tsconfig": "workspace:*",
|
||||
"@types/inquirer": "^8.2.6",
|
||||
"@types/node": "^20.5.1",
|
||||
"typescript": "^5.1.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"turbo": {
|
||||
"tasks": {
|
||||
"build": {
|
||||
"outputs": [
|
||||
"dist/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
"typescript": "^5.7.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
{
|
||||
"extends": "@sim/tsconfig/library-build.json",
|
||||
"compilerOptions": {
|
||||
"target": "es2020",
|
||||
"module": "ESNext",
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "node",
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"declaration": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
|
||||
@@ -24,15 +24,13 @@
|
||||
"db:studio": "bunx drizzle-kit studio --config=./drizzle.config.ts",
|
||||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"dependencies": {
|
||||
"drizzle-orm": "^0.44.5",
|
||||
"postgres": "^3.4.5"
|
||||
"postgres": "^3.4.5",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sim/tsconfig": "workspace:*",
|
||||
"typescript": "^5.7.3"
|
||||
},
|
||||
"overrides": {
|
||||
"drizzle-orm": "^0.44.5",
|
||||
"postgres": "^3.4.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
{
|
||||
"extends": "@sim/tsconfig/library.json",
|
||||
"compilerOptions": {
|
||||
"target": "es2022",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"lib": ["es2022"],
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@sim/db": ["./index.ts"],
|
||||
"@sim/db/*": ["./*"]
|
||||
},
|
||||
"resolveJsonModule": true,
|
||||
"noEmit": true
|
||||
}
|
||||
},
|
||||
"include": ["**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
"exclude": ["node_modules", "scripts"]
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"chalk": "5.6.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sim/tsconfig": "workspace:*",
|
||||
"typescript": "^5.7.3",
|
||||
"vitest": "^3.0.8"
|
||||
}
|
||||
|
||||
@@ -1,19 +1,5 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"lib": ["ES2022"],
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"noEmit": true,
|
||||
"isolatedModules": true,
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"extends": "@sim/tsconfig/library.json",
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
|
||||
@@ -41,7 +41,11 @@
|
||||
"vitest": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sim/tsconfig": "workspace:*",
|
||||
"typescript": "^5.7.3",
|
||||
"vitest": "^3.0.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"nanoid": "5.1.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { expect } from 'vitest'
|
||||
import type { BlockState, Edge, WorkflowState } from '../types'
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
/**
|
||||
* Asserts that a block exists in the workflow.
|
||||
@@ -12,7 +13,7 @@ import type { BlockState, Edge, WorkflowState } from '../types'
|
||||
* ```
|
||||
*/
|
||||
export function expectBlockExists(
|
||||
blocks: Record<string, BlockState>,
|
||||
blocks: Record<string, any>,
|
||||
blockId: string,
|
||||
expectedType?: string
|
||||
): void {
|
||||
@@ -33,7 +34,7 @@ export function expectBlockExists(
|
||||
* expectBlockNotExists(workflow.blocks, 'deleted-block')
|
||||
* ```
|
||||
*/
|
||||
export function expectBlockNotExists(blocks: Record<string, BlockState>, blockId: string): void {
|
||||
export function expectBlockNotExists(blocks: Record<string, any>, blockId: string): void {
|
||||
expect(blocks[blockId], `Block "${blockId}" should not exist`).toBeUndefined()
|
||||
}
|
||||
|
||||
@@ -45,7 +46,7 @@ export function expectBlockNotExists(blocks: Record<string, BlockState>, blockId
|
||||
* expectEdgeConnects(workflow.edges, 'block-0', 'block-1')
|
||||
* ```
|
||||
*/
|
||||
export function expectEdgeConnects(edges: Edge[], sourceId: string, targetId: string): void {
|
||||
export function expectEdgeConnects(edges: any[], sourceId: string, targetId: string): void {
|
||||
const edge = edges.find((e) => e.source === sourceId && e.target === targetId)
|
||||
expect(edge, `Edge from "${sourceId}" to "${targetId}" should exist`).toBeDefined()
|
||||
}
|
||||
@@ -58,7 +59,7 @@ export function expectEdgeConnects(edges: Edge[], sourceId: string, targetId: st
|
||||
* expectNoEdgeBetween(workflow.edges, 'block-1', 'block-0') // No reverse edge
|
||||
* ```
|
||||
*/
|
||||
export function expectNoEdgeBetween(edges: Edge[], sourceId: string, targetId: string): void {
|
||||
export function expectNoEdgeBetween(edges: any[], sourceId: string, targetId: string): void {
|
||||
const edge = edges.find((e) => e.source === sourceId && e.target === targetId)
|
||||
expect(edge, `Edge from "${sourceId}" to "${targetId}" should not exist`).toBeUndefined()
|
||||
}
|
||||
@@ -72,7 +73,7 @@ export function expectNoEdgeBetween(edges: Edge[], sourceId: string, targetId: s
|
||||
* ```
|
||||
*/
|
||||
export function expectBlockHasParent(
|
||||
blocks: Record<string, BlockState>,
|
||||
blocks: Record<string, any>,
|
||||
childId: string,
|
||||
expectedParentId: string
|
||||
): void {
|
||||
@@ -91,7 +92,7 @@ export function expectBlockHasParent(
|
||||
* expectBlockCount(workflow, 5)
|
||||
* ```
|
||||
*/
|
||||
export function expectBlockCount(workflow: WorkflowState, expectedCount: number): void {
|
||||
export function expectBlockCount(workflow: any, expectedCount: number): void {
|
||||
const actualCount = Object.keys(workflow.blocks).length
|
||||
expect(actualCount, `Workflow should have ${expectedCount} blocks`).toBe(expectedCount)
|
||||
}
|
||||
@@ -104,7 +105,7 @@ export function expectBlockCount(workflow: WorkflowState, expectedCount: number)
|
||||
* expectEdgeCount(workflow, 4)
|
||||
* ```
|
||||
*/
|
||||
export function expectEdgeCount(workflow: WorkflowState, expectedCount: number): void {
|
||||
export function expectEdgeCount(workflow: any, expectedCount: number): void {
|
||||
expect(workflow.edges.length, `Workflow should have ${expectedCount} edges`).toBe(expectedCount)
|
||||
}
|
||||
|
||||
@@ -117,7 +118,7 @@ export function expectEdgeCount(workflow: WorkflowState, expectedCount: number):
|
||||
* ```
|
||||
*/
|
||||
export function expectBlockPosition(
|
||||
blocks: Record<string, BlockState>,
|
||||
blocks: Record<string, any>,
|
||||
blockId: string,
|
||||
expectedPosition: { x: number; y: number }
|
||||
): void {
|
||||
@@ -135,7 +136,7 @@ export function expectBlockPosition(
|
||||
* expectBlockEnabled(workflow.blocks, 'block-1')
|
||||
* ```
|
||||
*/
|
||||
export function expectBlockEnabled(blocks: Record<string, BlockState>, blockId: string): void {
|
||||
export function expectBlockEnabled(blocks: Record<string, any>, blockId: string): void {
|
||||
const block = blocks[blockId]
|
||||
expect(block, `Block "${blockId}" should exist`).toBeDefined()
|
||||
expect(block.enabled, `Block "${blockId}" should be enabled`).toBe(true)
|
||||
@@ -149,7 +150,7 @@ export function expectBlockEnabled(blocks: Record<string, BlockState>, blockId:
|
||||
* expectBlockDisabled(workflow.blocks, 'disabled-block')
|
||||
* ```
|
||||
*/
|
||||
export function expectBlockDisabled(blocks: Record<string, BlockState>, blockId: string): void {
|
||||
export function expectBlockDisabled(blocks: Record<string, any>, blockId: string): void {
|
||||
const block = blocks[blockId]
|
||||
expect(block, `Block "${blockId}" should exist`).toBeDefined()
|
||||
expect(block.enabled, `Block "${blockId}" should be disabled`).toBe(false)
|
||||
@@ -164,7 +165,7 @@ export function expectBlockDisabled(blocks: Record<string, BlockState>, blockId:
|
||||
* ```
|
||||
*/
|
||||
export function expectLoopExists(
|
||||
workflow: WorkflowState,
|
||||
workflow: any,
|
||||
loopId: string,
|
||||
expectedConfig?: { iterations?: number; loopType?: string; nodes?: string[] }
|
||||
): void {
|
||||
@@ -193,7 +194,7 @@ export function expectLoopExists(
|
||||
* ```
|
||||
*/
|
||||
export function expectParallelExists(
|
||||
workflow: WorkflowState,
|
||||
workflow: any,
|
||||
parallelId: string,
|
||||
expectedConfig?: { count?: number; parallelType?: string; nodes?: string[] }
|
||||
): void {
|
||||
@@ -222,7 +223,7 @@ export function expectParallelExists(
|
||||
* expectEmptyWorkflow(workflow)
|
||||
* ```
|
||||
*/
|
||||
export function expectEmptyWorkflow(workflow: WorkflowState): void {
|
||||
export function expectEmptyWorkflow(workflow: any): void {
|
||||
expect(Object.keys(workflow.blocks).length, 'Workflow should have no blocks').toBe(0)
|
||||
expect(workflow.edges.length, 'Workflow should have no edges').toBe(0)
|
||||
expect(Object.keys(workflow.loops).length, 'Workflow should have no loops').toBe(0)
|
||||
@@ -237,7 +238,7 @@ export function expectEmptyWorkflow(workflow: WorkflowState): void {
|
||||
* expectLinearChain(workflow.edges, ['start', 'step1', 'step2', 'end'])
|
||||
* ```
|
||||
*/
|
||||
export function expectLinearChain(edges: Edge[], blockIds: string[]): void {
|
||||
export function expectLinearChain(edges: any[], blockIds: string[]): void {
|
||||
for (let i = 0; i < blockIds.length - 1; i++) {
|
||||
expectEdgeConnects(edges, blockIds[i], blockIds[i + 1])
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@ import {
|
||||
createFunctionBlock,
|
||||
createStarterBlock,
|
||||
} from '../factories/block.factory'
|
||||
import type { BlockState, Edge, Loop, Parallel, Position, WorkflowState } from '../types'
|
||||
import type { Position } from '../types'
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
/**
|
||||
* Fluent builder for creating complex workflow states.
|
||||
@@ -29,11 +31,11 @@ import type { BlockState, Edge, Loop, Parallel, Position, WorkflowState } from '
|
||||
* ```
|
||||
*/
|
||||
export class WorkflowBuilder {
|
||||
private blocks: Record<string, BlockState> = {}
|
||||
private edges: Edge[] = []
|
||||
private loops: Record<string, Loop> = {}
|
||||
private parallels: Record<string, Parallel> = {}
|
||||
private variables: WorkflowState['variables'] = []
|
||||
private blocks: Record<string, any> = {}
|
||||
private edges: any[] = []
|
||||
private loops: Record<string, any> = {}
|
||||
private parallels: Record<string, any> = {}
|
||||
private variables: any[] = []
|
||||
private isDeployed = false
|
||||
|
||||
/**
|
||||
@@ -245,8 +247,9 @@ export class WorkflowBuilder {
|
||||
|
||||
/**
|
||||
* Builds and returns the workflow state.
|
||||
* Returns `any` to be assignable to any app's workflow type.
|
||||
*/
|
||||
build(): WorkflowState {
|
||||
build(): any {
|
||||
return {
|
||||
blocks: this.blocks,
|
||||
edges: this.edges,
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
import type { BlockData, BlockOutput, BlockState, Position, SubBlockState } from '../types'
|
||||
import type { BlockData, BlockOutput, Position } from '../types'
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
/**
|
||||
* Options for creating a mock block.
|
||||
* All fields are optional - sensible defaults are provided.
|
||||
* Uses `any` for subBlocks to accept any app type without conflicts.
|
||||
*/
|
||||
export interface BlockFactoryOptions {
|
||||
id?: string
|
||||
type?: string
|
||||
name?: string
|
||||
position?: Position
|
||||
subBlocks?: Record<string, SubBlockState>
|
||||
subBlocks?: Record<string, any>
|
||||
outputs?: Record<string, BlockOutput>
|
||||
enabled?: boolean
|
||||
horizontalHandles?: boolean
|
||||
@@ -43,7 +46,7 @@ function generateBlockId(prefix = 'block'): string {
|
||||
* const block = createBlock({ type: 'function', parentId: 'loop-1' })
|
||||
* ```
|
||||
*/
|
||||
export function createBlock(options: BlockFactoryOptions = {}): BlockState {
|
||||
export function createBlock(options: BlockFactoryOptions = {}): any {
|
||||
const id = options.id ?? generateBlockId(options.type ?? 'block')
|
||||
|
||||
const data: BlockData = options.data ?? {}
|
||||
@@ -72,7 +75,7 @@ export function createBlock(options: BlockFactoryOptions = {}): BlockState {
|
||||
/**
|
||||
* Creates a starter block (workflow entry point).
|
||||
*/
|
||||
export function createStarterBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): BlockState {
|
||||
export function createStarterBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): any {
|
||||
return createBlock({
|
||||
...options,
|
||||
type: 'starter',
|
||||
@@ -83,7 +86,7 @@ export function createStarterBlock(options: Omit<BlockFactoryOptions, 'type'> =
|
||||
/**
|
||||
* Creates an agent block (AI agent execution).
|
||||
*/
|
||||
export function createAgentBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): BlockState {
|
||||
export function createAgentBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): any {
|
||||
return createBlock({
|
||||
...options,
|
||||
type: 'agent',
|
||||
@@ -94,7 +97,7 @@ export function createAgentBlock(options: Omit<BlockFactoryOptions, 'type'> = {}
|
||||
/**
|
||||
* Creates a function block (code execution).
|
||||
*/
|
||||
export function createFunctionBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): BlockState {
|
||||
export function createFunctionBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): any {
|
||||
return createBlock({
|
||||
...options,
|
||||
type: 'function',
|
||||
@@ -105,7 +108,7 @@ export function createFunctionBlock(options: Omit<BlockFactoryOptions, 'type'> =
|
||||
/**
|
||||
* Creates a condition block (branching logic).
|
||||
*/
|
||||
export function createConditionBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): BlockState {
|
||||
export function createConditionBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): any {
|
||||
return createBlock({
|
||||
...options,
|
||||
type: 'condition',
|
||||
@@ -121,7 +124,7 @@ export function createLoopBlock(
|
||||
loopType?: 'for' | 'forEach' | 'while' | 'doWhile'
|
||||
count?: number
|
||||
} = {}
|
||||
): BlockState {
|
||||
): any {
|
||||
const data: BlockData = {
|
||||
...options.data,
|
||||
loopType: options.loopType ?? 'for',
|
||||
@@ -145,7 +148,7 @@ export function createParallelBlock(
|
||||
parallelType?: 'count' | 'collection'
|
||||
count?: number
|
||||
} = {}
|
||||
): BlockState {
|
||||
): any {
|
||||
const data: BlockData = {
|
||||
...options.data,
|
||||
parallelType: options.parallelType ?? 'count',
|
||||
@@ -164,7 +167,7 @@ export function createParallelBlock(
|
||||
/**
|
||||
* Creates a router block (output routing).
|
||||
*/
|
||||
export function createRouterBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): BlockState {
|
||||
export function createRouterBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): any {
|
||||
return createBlock({
|
||||
...options,
|
||||
type: 'router',
|
||||
@@ -175,7 +178,7 @@ export function createRouterBlock(options: Omit<BlockFactoryOptions, 'type'> = {
|
||||
/**
|
||||
* Creates an API block (HTTP requests).
|
||||
*/
|
||||
export function createApiBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): BlockState {
|
||||
export function createApiBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): any {
|
||||
return createBlock({
|
||||
...options,
|
||||
type: 'api',
|
||||
@@ -186,7 +189,7 @@ export function createApiBlock(options: Omit<BlockFactoryOptions, 'type'> = {}):
|
||||
/**
|
||||
* Creates a response block (workflow output).
|
||||
*/
|
||||
export function createResponseBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): BlockState {
|
||||
export function createResponseBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): any {
|
||||
return createBlock({
|
||||
...options,
|
||||
type: 'response',
|
||||
@@ -197,7 +200,7 @@ export function createResponseBlock(options: Omit<BlockFactoryOptions, 'type'> =
|
||||
/**
|
||||
* Creates a webhook trigger block.
|
||||
*/
|
||||
export function createWebhookBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): BlockState {
|
||||
export function createWebhookBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): any {
|
||||
return createBlock({
|
||||
...options,
|
||||
type: 'webhook',
|
||||
@@ -208,7 +211,7 @@ export function createWebhookBlock(options: Omit<BlockFactoryOptions, 'type'> =
|
||||
/**
|
||||
* Creates a knowledge block (vector search).
|
||||
*/
|
||||
export function createKnowledgeBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): BlockState {
|
||||
export function createKnowledgeBlock(options: Omit<BlockFactoryOptions, 'type'> = {}): any {
|
||||
return createBlock({
|
||||
...options,
|
||||
type: 'knowledge',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Edge } from '../types'
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
/**
|
||||
* Options for creating a mock edge.
|
||||
@@ -36,7 +36,7 @@ function generateEdgeId(source: string, target: string): string {
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export function createEdge(options: EdgeFactoryOptions): Edge {
|
||||
export function createEdge(options: EdgeFactoryOptions): any {
|
||||
return {
|
||||
id: options.id ?? generateEdgeId(options.source, options.target),
|
||||
source: options.source,
|
||||
@@ -66,7 +66,7 @@ export function createEdges(
|
||||
sourceHandle?: string
|
||||
targetHandle?: string
|
||||
}>
|
||||
): Edge[] {
|
||||
): any[] {
|
||||
return connections.map((conn) => createEdge(conn))
|
||||
}
|
||||
|
||||
@@ -79,8 +79,8 @@ export function createEdges(
|
||||
* const edges = createLinearEdges(['a', 'b', 'c', 'd'])
|
||||
* ```
|
||||
*/
|
||||
export function createLinearEdges(blockIds: string[]): Edge[] {
|
||||
const edges: Edge[] = []
|
||||
export function createLinearEdges(blockIds: string[]): any[] {
|
||||
const edges: any[] = []
|
||||
for (let i = 0; i < blockIds.length - 1; i++) {
|
||||
edges.push(createEdge({ source: blockIds[i], target: blockIds[i + 1] }))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { nanoid } from 'nanoid'
|
||||
import type { BlockState, Edge } from '../types'
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
/**
|
||||
* Operation types supported by the undo/redo store.
|
||||
@@ -51,8 +52,8 @@ export interface RemoveBlockOperation extends BaseOperation {
|
||||
type: 'remove-block'
|
||||
data: {
|
||||
blockId: string
|
||||
blockSnapshot: BlockState | null
|
||||
edgeSnapshots?: Edge[]
|
||||
blockSnapshot: any
|
||||
edgeSnapshots?: any[]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +70,7 @@ export interface AddEdgeOperation extends BaseOperation {
|
||||
*/
|
||||
export interface RemoveEdgeOperation extends BaseOperation {
|
||||
type: 'remove-edge'
|
||||
data: { edgeId: string; edgeSnapshot: Edge | null }
|
||||
data: { edgeId: string; edgeSnapshot: any }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,7 +81,7 @@ export interface DuplicateBlockOperation extends BaseOperation {
|
||||
data: {
|
||||
sourceBlockId: string
|
||||
duplicatedBlockId: string
|
||||
duplicatedBlockSnapshot: BlockState
|
||||
duplicatedBlockSnapshot: any
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,10 +128,7 @@ interface OperationEntryOptions {
|
||||
/**
|
||||
* Creates a mock add-block operation entry.
|
||||
*/
|
||||
export function createAddBlockEntry(
|
||||
blockId: string,
|
||||
options: OperationEntryOptions = {}
|
||||
): OperationEntry {
|
||||
export function createAddBlockEntry(blockId: string, options: OperationEntryOptions = {}): any {
|
||||
const { id = nanoid(8), workflowId = 'wf-1', userId = 'user-1', createdAt = Date.now() } = options
|
||||
const timestamp = Date.now()
|
||||
|
||||
@@ -161,9 +159,9 @@ export function createAddBlockEntry(
|
||||
*/
|
||||
export function createRemoveBlockEntry(
|
||||
blockId: string,
|
||||
blockSnapshot: BlockState | null = null,
|
||||
blockSnapshot: any = null,
|
||||
options: OperationEntryOptions = {}
|
||||
): OperationEntry {
|
||||
): any {
|
||||
const { id = nanoid(8), workflowId = 'wf-1', userId = 'user-1', createdAt = Date.now() } = options
|
||||
const timestamp = Date.now()
|
||||
|
||||
@@ -192,10 +190,7 @@ export function createRemoveBlockEntry(
|
||||
/**
|
||||
* Creates a mock add-edge operation entry.
|
||||
*/
|
||||
export function createAddEdgeEntry(
|
||||
edgeId: string,
|
||||
options: OperationEntryOptions = {}
|
||||
): OperationEntry {
|
||||
export function createAddEdgeEntry(edgeId: string, options: OperationEntryOptions = {}): any {
|
||||
const { id = nanoid(8), workflowId = 'wf-1', userId = 'user-1', createdAt = Date.now() } = options
|
||||
const timestamp = Date.now()
|
||||
|
||||
@@ -226,9 +221,9 @@ export function createAddEdgeEntry(
|
||||
*/
|
||||
export function createRemoveEdgeEntry(
|
||||
edgeId: string,
|
||||
edgeSnapshot: Edge | null = null,
|
||||
edgeSnapshot: any = null,
|
||||
options: OperationEntryOptions = {}
|
||||
): OperationEntry {
|
||||
): any {
|
||||
const { id = nanoid(8), workflowId = 'wf-1', userId = 'user-1', createdAt = Date.now() } = options
|
||||
const timestamp = Date.now()
|
||||
|
||||
@@ -262,10 +257,7 @@ interface MoveBlockOptions extends OperationEntryOptions {
|
||||
/**
|
||||
* Creates a mock move-block operation entry.
|
||||
*/
|
||||
export function createMoveBlockEntry(
|
||||
blockId: string,
|
||||
options: MoveBlockOptions = {}
|
||||
): OperationEntry {
|
||||
export function createMoveBlockEntry(blockId: string, options: MoveBlockOptions = {}): any {
|
||||
const {
|
||||
id = nanoid(8),
|
||||
workflowId = 'wf-1',
|
||||
@@ -304,9 +296,9 @@ export function createMoveBlockEntry(
|
||||
export function createDuplicateBlockEntry(
|
||||
sourceBlockId: string,
|
||||
duplicatedBlockId: string,
|
||||
duplicatedBlockSnapshot: BlockState,
|
||||
duplicatedBlockSnapshot: any,
|
||||
options: OperationEntryOptions = {}
|
||||
): OperationEntry {
|
||||
): any {
|
||||
const { id = nanoid(8), workflowId = 'wf-1', userId = 'user-1', createdAt = Date.now() } = options
|
||||
const timestamp = Date.now()
|
||||
|
||||
@@ -343,7 +335,7 @@ export function createUpdateParentEntry(
|
||||
oldPosition?: { x: number; y: number }
|
||||
newPosition?: { x: number; y: number }
|
||||
} = {}
|
||||
): OperationEntry {
|
||||
): any {
|
||||
const {
|
||||
id = nanoid(8),
|
||||
workflowId = 'wf-1',
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import type { BlockState, Edge, Loop, Parallel, WorkflowState } from '../types'
|
||||
import { createBlock, createFunctionBlock, createStarterBlock } from './block.factory'
|
||||
import { createLinearEdges } from './edge.factory'
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
/**
|
||||
* Options for creating a mock workflow state.
|
||||
* Uses `any` for complex types to avoid conflicts with app types.
|
||||
*/
|
||||
export interface WorkflowFactoryOptions {
|
||||
blocks?: Record<string, BlockState>
|
||||
edges?: Edge[]
|
||||
loops?: Record<string, Loop>
|
||||
parallels?: Record<string, Parallel>
|
||||
blocks?: Record<string, any>
|
||||
edges?: any[]
|
||||
loops?: Record<string, any>
|
||||
parallels?: Record<string, any>
|
||||
lastSaved?: number
|
||||
isDeployed?: boolean
|
||||
variables?: WorkflowState['variables']
|
||||
variables?: any[]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -23,7 +25,7 @@ export interface WorkflowFactoryOptions {
|
||||
* const workflow = createWorkflowState()
|
||||
* ```
|
||||
*/
|
||||
export function createWorkflowState(options: WorkflowFactoryOptions = {}): WorkflowState {
|
||||
export function createWorkflowState(options: WorkflowFactoryOptions = {}): any {
|
||||
return {
|
||||
blocks: options.blocks ?? {},
|
||||
edges: options.edges ?? [],
|
||||
@@ -45,12 +47,12 @@ export function createWorkflowState(options: WorkflowFactoryOptions = {}): Workf
|
||||
* const workflow = createLinearWorkflow(3)
|
||||
* ```
|
||||
*/
|
||||
export function createLinearWorkflow(blockCount: number, spacing = 200): WorkflowState {
|
||||
export function createLinearWorkflow(blockCount: number, spacing = 200): any {
|
||||
if (blockCount < 1) {
|
||||
return createWorkflowState()
|
||||
}
|
||||
|
||||
const blocks: Record<string, BlockState> = {}
|
||||
const blocks: Record<string, any> = {}
|
||||
const blockIds: string[] = []
|
||||
|
||||
for (let i = 0; i < blockCount; i++) {
|
||||
@@ -87,8 +89,8 @@ export function createLinearWorkflow(blockCount: number, spacing = 200): Workflo
|
||||
* └─→ false-branch ┘
|
||||
* ```
|
||||
*/
|
||||
export function createBranchingWorkflow(): WorkflowState {
|
||||
const blocks: Record<string, BlockState> = {
|
||||
export function createBranchingWorkflow(): any {
|
||||
const blocks: Record<string, any> = {
|
||||
start: createStarterBlock({ id: 'start', position: { x: 0, y: 0 } }),
|
||||
condition: createBlock({
|
||||
id: 'condition',
|
||||
@@ -109,7 +111,7 @@ export function createBranchingWorkflow(): WorkflowState {
|
||||
end: createFunctionBlock({ id: 'end', name: 'End', position: { x: 600, y: 0 } }),
|
||||
}
|
||||
|
||||
const edges: Edge[] = [
|
||||
const edges: any[] = [
|
||||
{ id: 'e1', source: 'start', target: 'condition' },
|
||||
{ id: 'e2', source: 'condition', target: 'true-branch', sourceHandle: 'condition-if' },
|
||||
{ id: 'e3', source: 'condition', target: 'false-branch', sourceHandle: 'condition-else' },
|
||||
@@ -128,8 +130,8 @@ export function createBranchingWorkflow(): WorkflowState {
|
||||
* start ─→ loop[loop-body] ─→ end
|
||||
* ```
|
||||
*/
|
||||
export function createLoopWorkflow(iterations = 3): WorkflowState {
|
||||
const blocks: Record<string, BlockState> = {
|
||||
export function createLoopWorkflow(iterations = 3): any {
|
||||
const blocks: Record<string, any> = {
|
||||
start: createStarterBlock({ id: 'start', position: { x: 0, y: 0 } }),
|
||||
loop: createBlock({
|
||||
id: 'loop',
|
||||
@@ -147,12 +149,12 @@ export function createLoopWorkflow(iterations = 3): WorkflowState {
|
||||
end: createFunctionBlock({ id: 'end', name: 'End', position: { x: 500, y: 0 } }),
|
||||
}
|
||||
|
||||
const edges: Edge[] = [
|
||||
const edges: any[] = [
|
||||
{ id: 'e1', source: 'start', target: 'loop' },
|
||||
{ id: 'e2', source: 'loop', target: 'end' },
|
||||
]
|
||||
|
||||
const loops: Record<string, Loop> = {
|
||||
const loops: Record<string, any> = {
|
||||
loop: {
|
||||
id: 'loop',
|
||||
nodes: ['loop-body'],
|
||||
@@ -172,8 +174,8 @@ export function createLoopWorkflow(iterations = 3): WorkflowState {
|
||||
* start ─→ parallel[parallel-task] ─→ end
|
||||
* ```
|
||||
*/
|
||||
export function createParallelWorkflow(count = 2): WorkflowState {
|
||||
const blocks: Record<string, BlockState> = {
|
||||
export function createParallelWorkflow(count = 2): any {
|
||||
const blocks: Record<string, any> = {
|
||||
start: createStarterBlock({ id: 'start', position: { x: 0, y: 0 } }),
|
||||
parallel: createBlock({
|
||||
id: 'parallel',
|
||||
@@ -191,12 +193,12 @@ export function createParallelWorkflow(count = 2): WorkflowState {
|
||||
end: createFunctionBlock({ id: 'end', name: 'End', position: { x: 500, y: 0 } }),
|
||||
}
|
||||
|
||||
const edges: Edge[] = [
|
||||
const edges: any[] = [
|
||||
{ id: 'e1', source: 'start', target: 'parallel' },
|
||||
{ id: 'e2', source: 'parallel', target: 'end' },
|
||||
]
|
||||
|
||||
const parallels: Record<string, Parallel> = {
|
||||
const parallels: Record<string, any> = {
|
||||
parallel: {
|
||||
id: 'parallel',
|
||||
nodes: ['parallel-task'],
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
/**
|
||||
* Core types for the testing package.
|
||||
* These are simplified versions of the actual types used in apps/sim,
|
||||
* designed for test scenarios without requiring all dependencies.
|
||||
*
|
||||
* These are intentionally loose/permissive types that accept any shape of data
|
||||
* from the app. The testing package should not try to mirror app types exactly -
|
||||
* that creates maintenance burden and type drift issues.
|
||||
*
|
||||
* Tests themselves provide type safety through their actual usage of app types.
|
||||
*/
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
export interface Position {
|
||||
x: number
|
||||
y: number
|
||||
@@ -11,72 +17,26 @@ export interface Position {
|
||||
|
||||
export interface BlockData {
|
||||
parentId?: string
|
||||
extent?: 'parent'
|
||||
extent?: string
|
||||
width?: number
|
||||
height?: number
|
||||
count?: number
|
||||
loopType?: 'for' | 'forEach' | 'while' | 'doWhile'
|
||||
parallelType?: 'count' | 'collection'
|
||||
loopType?: string
|
||||
parallelType?: string
|
||||
collection?: any
|
||||
whileCondition?: string
|
||||
doWhileCondition?: string
|
||||
type?: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
/**
|
||||
* SubBlockType union for testing.
|
||||
* Matches the SubBlockType values from the app (apps/sim/blocks/types.ts).
|
||||
*/
|
||||
export type SubBlockType =
|
||||
| 'short-input'
|
||||
| 'long-input'
|
||||
| 'dropdown'
|
||||
| 'combobox'
|
||||
| 'slider'
|
||||
| 'table'
|
||||
| 'code'
|
||||
| 'switch'
|
||||
| 'tool-input'
|
||||
| 'checkbox-list'
|
||||
| 'grouped-checkbox-list'
|
||||
| 'condition-input'
|
||||
| 'eval-input'
|
||||
| 'time-input'
|
||||
| 'oauth-input'
|
||||
| 'webhook-config'
|
||||
| 'schedule-info'
|
||||
| 'file-selector'
|
||||
| 'project-selector'
|
||||
| 'channel-selector'
|
||||
| 'user-selector'
|
||||
| 'folder-selector'
|
||||
| 'knowledge-base-selector'
|
||||
| 'knowledge-tag-filters'
|
||||
| 'document-selector'
|
||||
| 'document-tag-entry'
|
||||
| 'mcp-server-selector'
|
||||
| 'mcp-tool-selector'
|
||||
| 'mcp-dynamic-args'
|
||||
| 'input-format'
|
||||
|
||||
export interface SubBlockState {
|
||||
id: string
|
||||
type: SubBlockType
|
||||
value: string | number | string[][] | null
|
||||
type: string
|
||||
value: any
|
||||
}
|
||||
|
||||
/**
|
||||
* Primitive value types for block outputs.
|
||||
*/
|
||||
export type PrimitiveValueType = 'string' | 'number' | 'boolean'
|
||||
|
||||
/**
|
||||
* BlockOutput type matching the app's structure.
|
||||
* Can be a primitive type or an object with string keys.
|
||||
*/
|
||||
export type BlockOutput =
|
||||
| PrimitiveValueType
|
||||
| { [key: string]: PrimitiveValueType | Record<string, any> }
|
||||
export type BlockOutput = any
|
||||
|
||||
export interface BlockState {
|
||||
id: string
|
||||
@@ -91,38 +51,39 @@ export interface BlockState {
|
||||
advancedMode?: boolean
|
||||
triggerMode?: boolean
|
||||
data?: BlockData
|
||||
layout?: {
|
||||
measuredWidth?: number
|
||||
measuredHeight?: number
|
||||
}
|
||||
layout?: Record<string, any>
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface Edge {
|
||||
id: string
|
||||
source: string
|
||||
target: string
|
||||
sourceHandle?: string
|
||||
targetHandle?: string
|
||||
sourceHandle?: string | null
|
||||
targetHandle?: string | null
|
||||
type?: string
|
||||
data?: Record<string, any>
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface Loop {
|
||||
id: string
|
||||
nodes: string[]
|
||||
iterations: number
|
||||
loopType: 'for' | 'forEach' | 'while' | 'doWhile'
|
||||
forEachItems?: any[] | Record<string, any> | string
|
||||
loopType: string
|
||||
forEachItems?: any
|
||||
whileCondition?: string
|
||||
doWhileCondition?: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface Parallel {
|
||||
id: string
|
||||
nodes: string[]
|
||||
distribution?: any[] | Record<string, any> | string
|
||||
distribution?: any
|
||||
count?: number
|
||||
parallelType?: 'count' | 'collection'
|
||||
parallelType?: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface WorkflowState {
|
||||
@@ -135,12 +96,8 @@ export interface WorkflowState {
|
||||
isDeployed?: boolean
|
||||
deployedAt?: Date
|
||||
needsRedeployment?: boolean
|
||||
variables?: Array<{
|
||||
id: string
|
||||
name: string
|
||||
type: 'string' | 'number' | 'boolean' | 'object' | 'array' | 'plain'
|
||||
value: any
|
||||
}>
|
||||
variables?: any[]
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface ExecutionContext {
|
||||
@@ -164,6 +121,7 @@ export interface ExecutionContext {
|
||||
completedLoops: Set<string>
|
||||
activeExecutionPath: Set<string>
|
||||
abortSignal?: AbortSignal
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface User {
|
||||
@@ -171,6 +129,7 @@ export interface User {
|
||||
email: string
|
||||
name?: string
|
||||
image?: string
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface Workspace {
|
||||
@@ -179,6 +138,7 @@ export interface Workspace {
|
||||
ownerId: string
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export interface Workflow {
|
||||
@@ -189,4 +149,5 @@ export interface Workflow {
|
||||
createdAt: Date
|
||||
updatedAt: Date
|
||||
isDeployed?: boolean
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
@@ -1,20 +1,11 @@
|
||||
{
|
||||
"extends": "@sim/tsconfig/library.json",
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@sim/testing/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
"version": "0.1.1",
|
||||
"description": "Sim SDK - Execute workflows programmatically",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -13,8 +10,8 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "bun run build:tsc",
|
||||
"build:tsc": "tsc",
|
||||
"build": "tsc",
|
||||
"type-check": "tsc --noEmit",
|
||||
"dev:watch": "tsc --watch",
|
||||
"prepublishOnly": "bun run build",
|
||||
"test": "vitest run",
|
||||
@@ -38,10 +35,11 @@
|
||||
"node-fetch": "^3.3.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sim/tsconfig": "workspace:*",
|
||||
"@types/node": "^20.5.1",
|
||||
"typescript": "^5.1.6",
|
||||
"vitest": "^3.0.8",
|
||||
"@vitest/coverage-v8": "^3.0.8"
|
||||
"@vitest/coverage-v8": "^3.0.8",
|
||||
"typescript": "^5.7.3",
|
||||
"vitest": "^3.0.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
{
|
||||
"extends": "@sim/tsconfig/library-build.json",
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ES2020",
|
||||
"lib": ["ES2020"],
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist", "**/*.test.ts"]
|
||||
|
||||
24
packages/tsconfig/base.json
Normal file
24
packages/tsconfig/base.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "Base",
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2022"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"moduleDetection": "force",
|
||||
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
|
||||
"verbatimModuleSyntax": false,
|
||||
"noUncheckedIndexedAccess": false,
|
||||
"noEmit": true
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
11
packages/tsconfig/library-build.json
Normal file
11
packages/tsconfig/library-build.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "Library (Build)",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"noEmit": false
|
||||
}
|
||||
}
|
||||
10
packages/tsconfig/library.json
Normal file
10
packages/tsconfig/library.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "Library (No Emit)",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"noEmit": true
|
||||
}
|
||||
}
|
||||
17
packages/tsconfig/nextjs.json
Normal file
17
packages/tsconfig/nextjs.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "Next.js",
|
||||
"extends": "./base.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
"incremental": true,
|
||||
"allowImportingTsExtensions": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
13
packages/tsconfig/package.json
Normal file
13
packages/tsconfig/package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "@sim/tsconfig",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "Shared TypeScript configurations for Sim monorepo",
|
||||
"exports": {
|
||||
"./base.json": "./base.json",
|
||||
"./nextjs.json": "./nextjs.json",
|
||||
"./library.json": "./library.json",
|
||||
"./library-build.json": "./library-build.json"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user