chore(repo): rebase fixes and quality improvements for realtime split

Addresses merge-time issues and gaps from the realtime app split:
- Retarget stale vi.mock paths to @sim/workflow-persistence/subblocks
- Restore README branding, fix AGENTS.md script reference
- Restore TSDoc on workflow-persistence subblocks helpers
- Use toError() from @sim/utils/errors in save.ts
- Add vitest config + local mocks so @sim/audit tests run standalone
- Move socket.io-client to devDependencies in apps/realtime
- Add missing package COPY steps to docker/app.Dockerfile
- Add check:boundaries/check:realtime-prune scripts and wire into CI

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Waleed Latif
2026-04-22 21:15:16 -07:00
parent 388538605a
commit a8cc431d77
15 changed files with 133 additions and 62 deletions

View File

@@ -104,10 +104,10 @@ jobs:
run: bun run lint:check
- name: Enforce monorepo boundaries
run: bun run scripts/check-monorepo-boundaries.ts
run: bun run check:boundaries
- name: Verify realtime prune graph
run: bun run scripts/check-realtime-prune-graph.ts
run: bun run check:realtime-prune
- name: Run tests with coverage
env:

View File

@@ -53,7 +53,7 @@ packages/
### Package boundaries
- `apps/* → packages/*` only. Packages never import from `apps/*`.
- Each package has explicit subpath `exports` maps; no barrels that accidentally pull in heavy halves.
- `apps/realtime` intentionally avoids Next.js, React, the block/tool registry, provider SDKs, and the executor. CI enforces this via `scripts/check-monorepo-boundaries.ts` and `scripts/check-realtime-image-size.ts`.
- `apps/realtime` intentionally avoids Next.js, React, the block/tool registry, provider SDKs, and the executor. CI enforces this via `scripts/check-monorepo-boundaries.ts` and `scripts/check-realtime-prune-graph.ts`.
- Auth is shared across services via the Better Auth "Shared Database Session" pattern: both apps read the same `BETTER_AUTH_SECRET` and point at the same DB via `@sim/db`.
### Naming Conventions

View File

@@ -1,55 +1,69 @@
<p align="center">
<a href="https://sim.ai" target="_blank" rel="noopener noreferrer">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="apps/sim/public/logo/wordmark.svg">
<source media="(prefers-color-scheme: light)" srcset="apps/sim/public/logo/wordmark-dark.svg">
<img src="apps/sim/public/logo/wordmark-dark.svg" alt="Sim Logo" width="380"/>
</picture>
</a>
</p>
<p align="center">The open-source platform to build AI agents and run your agentic workforce. Connect 1,000+ integrations and LLMs to orchestrate agentic workflows.</p>
The open-source platform to build AI agents and run your agentic workforce. Connect 1,000+ integrations and LLMs to orchestrate agentic workflows.
<p align="center">
<a href="https://sim.ai" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/badge/sim.ai-33c482" alt="Sim.ai"></a>
<a href="https://discord.gg/Hr4UWYEcTT" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/badge/Discord-Join%20Server-5865F2?logo=discord&logoColor=white" alt="Discord"></a>
<a href="https://x.com/simdotai" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/twitter/follow/simdotai?style=social" alt="Twitter"></a>
<a href="https://docs.sim.ai" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/badge/Docs-33c482.svg" alt="Documentation"></a>
</p>
<p align="center">
<a href="https://deepwiki.com/simstudioai/sim" target="_blank" rel="noopener noreferrer"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a> <a href="https://cursor.com/link/prompt?text=Help%20me%20set%20up%20Sim%20locally.%20Follow%20these%20steps%3A%0A%0A1.%20First%2C%20verify%20Docker%20is%20installed%20and%20running%3A%0A%20%20%20docker%20--version%0A%20%20%20docker%20info%0A%0A2.%20Clone%20the%20repository%3A%0A%20%20%20git%20clone%20https%3A%2F%2Fgithub.com%2Fsimstudioai%2Fsim.git%0A%20%20%20cd%20sim%0A%0A3.%20Start%20the%20services%20with%20Docker%20Compose%3A%0A%20%20%20docker%20compose%20-f%20docker-compose.prod.yml%20up%20-d%0A%0A4.%20Wait%20for%20all%20containers%20to%20be%20healthy%20(this%20may%20take%201-2%20minutes)%3A%0A%20%20%20docker%20compose%20-f%20docker-compose.prod.yml%20ps%0A%0A5.%20Verify%20the%20app%20is%20accessible%20at%20http%3A%2F%2Flocalhost%3A3000%0A%0AIf%20there%20are%20any%20errors%2C%20help%20me%20troubleshoot%20them.%20Common%20issues%3A%0A-%20Port%203000%2C%203002%2C%20or%205432%20already%20in%20use%0A-%20Docker%20not%20running%0A-%20Insufficient%20memory%20(needs%2012GB%2B%20RAM)%0A%0AFor%20local%20AI%20models%20with%20Ollama%2C%20use%20this%20instead%20of%20step%203%3A%0A%20%20%20docker%20compose%20-f%20docker-compose.ollama.yml%20--profile%20setup%20up%20-d"><img src="https://img.shields.io/badge/Set%20Up%20with-Cursor-000000?logo=cursor&logoColor=white" alt="Set Up with Cursor"></a>
</p>
### Build Workflows with Ease
Design agent workflows visually on a canvas—connect agents, tools, and blocks, then run them instantly.
<p align="center">
<img src="apps/sim/public/static/workflow.gif" alt="Workflow Builder Demo" width="800"/>
</p>
### Supercharge with Copilot
Leverage Copilot to generate nodes, fix errors, and iterate on flows directly from natural language.
<p align="center">
<img src="apps/sim/public/static/copilot.gif" alt="Copilot Demo" width="800"/>
</p>
### Integrate Vector Databases
Upload documents to a vector store and let agents answer questions grounded in your specific content.
<p align="center">
<img src="apps/sim/public/static/knowledge.gif" alt="Knowledge Uploads and Retrieval Demo" width="800"/>
</p>
## Quickstart
### Cloud-hosted: [sim.ai](https://sim.ai)
<a href="https://sim.ai" target="_blank" rel="noopener noreferrer"><img src="https://img.shields.io/badge/sim.ai-33c482?logo=data:image/svg%2bxml;base64,PHN2ZyB3aWR0aD0iNjE2IiBoZWlnaHQ9IjYxNiIgdmlld0JveD0iMCAwIDYxNiA2MTYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMF8xMTU5XzMxMykiPgo8cGF0aCBkPSJNNjE2IDBIMFY2MTZINjE2VjBaIiBmaWxsPSIjMzNjNDgyIi8+CjxwYXRoIGQ9Ik04MyAzNjUuNTY3SDExM0MxMTMgMzczLjgwNSAxMTYgMzgwLjM3MyAxMjIgMzg1LjI3MkMxMjggMzg5Ljk0OCAxMzYuMTExIDM5Mi4yODUgMTQ2LjMzMyAzOTIuMjg1QzE1Ny40NDQgMzkyLjI4NSAxNjYgMzkwLjE3MSAxNzIgMzg1LjkzOUMxNzcuOTk5IDM4MS40ODcgMTgxIDM3NS41ODYgMTgxIDM2OC4yMzlDMTgxIDM2Mi44OTUgMTc5LjMzMyAzNTguNDQyIDE3NiAzNTQuODhDMTcyLjg4OSAzNTEuMzE4IDE2Ny4xMTEgMzQ4LjQyMiAxNTguNjY3IDM0Ni4xOTZMMTMwIDMzOS41MTdDMTE1LjU1NSAzMzUuOTU1IDEwNC43NzggMzMwLjQ5OSA5Ny42NjY1IDMyMy4xNTFDOTAuNzc3NSAzMTUuODA0IDg3LjMzMzQgMzA2LjExOSA4Ny4zMzM0IDI5NC4wOTZDODcuMzMzNCAyODQuMDc2IDg5Ljg4OSAyNzUuMzkyIDk0Ljk5OTYgMjY4LjA0NUMxMDAuMzMzIDI2MC42OTcgMTA3LjU1NSAyNTUuMDIgMTE2LjY2NiAyNTEuMDEyQzEyNiAyNDcuMDA0IDEzNi42NjcgMjQ1IDE0OC42NjYgMjQ1QzE2MC42NjcgMjQ1IDE3MSAyNDcuMTE2IDE3OS42NjcgMjUxLjM0NkMxODguNTU1IDI1NS41NzYgMTk1LjQ0NCAyNjEuNDc3IDIwMC4zMzMgMjY5LjA0N0MyMDUuNDQ0IDI3Ni42MTcgMjA4LjExMSAyODUuNjM0IDIwOC4zMzMgMjk2LjA5OUgxNzguMzMzQzE3OC4xMTEgMjg3LjYzOCAxNzUuMzMzIDI4MS4wNyAxNjkuOTk5IDI3Ni4zOTRDMTY0LjY2NiAyNzEuNzE5IDE1Ny4yMjIgMjY5LjM4MSAxNDcuNjY3IDI2OS4zODFDMTM3Ljg4OSAyNjkuMzgxIDEzMC4zMzMgMjcxLjQ5NiAxMjUgMjc1LjcyNkMxMTkuNjY2IDI3OS45NTcgMTE3IDI4NS43NDYgMTE3IDI5My4wOTNDMTE3IDMwNC4wMDMgMTI1IDMxMS40NjIgMTQxIDMxNS40N0wxNjkuNjY3IDMyMi40ODNDMTgzLjQ0NSAzMjUuNiAxOTMuNzc4IDMzMC43MjIgMjAwLjY2NyAzMzcuODQ3QzIwNy41NTUgMzQ0Ljc0OSAyMTEgMzU0LjIxMiAyMTEgMzY2LjIzNUMyMTEgMzc2LjQ3NyAyMDguMjIyIDM4NS40OTQgMjAyLjY2NiAzOTMuMjg3QzE5Ny4xMTEgNDAwLjg1NyAxODkuNDQ0IDQwNi43NTggMTc5LjY2NyA0MTAuOTg5QzE3MC4xMTEgNDE0Ljk5NiAxNTguNzc4IDQxNyAxNDUuNjY3IDQxN0MxMjYuNTU1IDQxNyAxMTEuMzMzIDQxMi4zMjUgOTkuOTk5NyA0MDIuOTczQzg4LjY2NjggMzkzLjYyMSA4MyAzODEuMTUzIDgzIDM2NS41NjdaIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMjMyLjI5MSA0MTNWMjUwLjA4MkMyNDQuNjg0IDI1NC42MTQgMjUwLjE0OCAyNTQuNjE0IDI2My4zNzEgMjUwLjA4MlY0MTNIMjMyLjI5MVpNMjQ3LjUgMjM5LjMxM0MyNDEuOTkgMjM5LjMxMyAyMzcuMTQgMjM3LjMxMyAyMzIuOTUyIDIzMy4zMTZDMjI4Ljk4NCAyMjkuMDk1IDIyNyAyMjQuMjA5IDIyNyAyMTguNjU2QzIyNyAyMTIuODgyIDIyOC45ODQgMjA3Ljk5NSAyMzIuOTUyIDIwMy45OTdDMjM3LjE0IDE5OS45OTkgMjQxLjk5IDE5OCAyNDcuNSAxOThDMjUzLjIzMSAxOTggMjU4LjA4IDE5OS45OTkgMjYyLjA0OSAyMDMuOTk3QzI2Ni4wMTYgMjA3Ljk5NSAyNjggMjEyLjg4MiAyNjggMjE4LjY1NkMyNjggMjI0LjIwOSAyNjYuMDE2IDIyOS4wOTUgMjYyLjA0OSAyMzMuMzE2QzI1OC4wOCAyMzcuMzEzIDI1My4yMzEgMjM5LjMxMyAyNDcuNSAyMzkuMzEzWiIgZmlsbD0id2hpdGUiLz4KPHBhdGggZD0iTTMxOS4zMzMgNDEzSDI4OFYyNDkuNjc2SDMxNlYyNzcuMjMzQzMxOS4zMzMgMjY4LjEwNCAzMjUuNzc4IDI2MC4zNjQgMzM0LjY2NyAyNTQuMzUyQzM0My43NzggMjQ4LjExNyAzNTQuNzc4IDI0NSAzNjcuNjY3IDI0NUMzODIuMTExIDI0NSAzOTQuMTEyIDI0OC44OTcgNDAzLjY2NyAyNTYuNjlDNDEzLjIyMiAyNjQuNDg0IDQxOS40NDQgMjc0LjgzNyA0MjIuMzM0IDI4Ny43NTJINDE2LjY2N0M0MTguODg5IDI3NC44MzcgNDI1IDI2NC40ODQgNDM1IDI1Ni42OUM0NDUgMjQ4Ljg5NyA0NTcuMzM0IDI0NSA0NzIgMjQ1QzQ5MC42NjYgMjQ1IDUwNS4zMzQgMjUwLjQ1NSA1MTYgMjYxLjM2NkM1MjYuNjY3IDI3Mi4yNzYgNTMyIDI4Ny4xOTUgNTMyIDMwNi4xMjFWNDEzSDUwMS4zMzNWMzEzLjgwNEM1MDEuMzMzIDMwMC44ODkgNDk4IDI5MC45ODEgNDkxLjMzMyAyODQuMDc4QzQ4NC44ODkgMjc2Ljk1MiA0NzYuMTExIDI3My4zOSA0NjUgMjczLjM5QzQ1Ny4yMjIgMjczLjM5IDQ1MC4zMzMgMjc1LjE3MSA0NDQuMzM0IDI3OC43MzRDNDM4LjU1NiAyODIuMDc0IDQzNCAyODYuOTcyIDQzMC42NjcgMjkzLjQzQzQyNy4zMzMgMjk5Ljg4NyA0MjUuNjY3IDMwNy40NTcgNDI1LjY2NyAzMTYuMTQxVjQxM0gzOTQuNjY3VjMxMy40NjlDMzk0LjY2NyAzMDAuNTU1IDM5MS40NDUgMjkwLjc1OCAzODUgMjg0LjA3OEMzNzguNTU2IDI3Ny4xNzUgMzY5Ljc3OCAyNzMuNzI0IDM1OC42NjcgMjczLjcyNEMzNTAuODg5IDI3My43MjQgMzQ0IDI3NS41MDUgMzM4IDI3OS4wNjhDMzMyLjIyMiAyODIuNDA4IDMyNy42NjcgMjg3LjMwNyAzMjQuMzMzIDI5My43NjNDMzIxIDI5OS45OTggMzE5LjMzMyAzMDcuNDU3IDMxOS4zMzMgMzE2LjE0MVY0MTNaIiBmaWxsPSJ3aGl0ZSIvPgo8L2c+CjxkZWZzPgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzExNTlfMzEzIj4KPHJlY3Qgd2lkdGg9IjYxNiIgaGVpZ2h0PSI2MTYiIGZpbGw9IndoaXRlIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+&logoColor=white" alt="Sim.ai"></a>
### Self-hosted: NPM Package
```bash
npx simstudio
```
→ [http://localhost:3000](http://localhost:3000)
→ http://localhost:3000
#### Note
Docker must be installed and running on your machine.
#### Options
| Flag | Description |
| ------------------- | ----------------------------------- |
| Flag | Description |
|------|-------------|
| `-p, --port <port>` | Port to run Sim on (default `3000`) |
| `--no-pull` | Skip pulling latest Docker images |
| `--no-pull` | Skip pulling latest Docker images |
### Self-hosted: Docker Compose
@@ -75,7 +89,7 @@ bun install
bun run prepare # Set up pre-commit hooks
```
1. Set up PostgreSQL with pgvector:
2. Set up PostgreSQL with pgvector:
```bash
docker run --name simstudio-db -e POSTGRES_PASSWORD=your_password -e POSTGRES_DB=simstudio -p 5432:5432 -d pgvector/pgvector:pg17
@@ -83,61 +97,43 @@ docker run --name simstudio-db -e POSTGRES_PASSWORD=your_password -e POSTGRES_DB
Or install manually via the [pgvector guide](https://github.com/pgvector/pgvector#installation).
1. Configure environment:
3. Configure environment:
```bash
# Main app env (large, app-specific: OAuth secrets, LLM keys, etc.)
cp apps/sim/.env.example apps/sim/.env
# Create your secrets
perl -i -pe "s/your_encryption_key/$(openssl rand -hex 32)/" apps/sim/.env
perl -i -pe "s/your_internal_api_secret/$(openssl rand -hex 32)/" apps/sim/.env
perl -i -pe "s/your_api_encryption_key/$(openssl rand -hex 32)/" apps/sim/.env
# Realtime server env (small: just the ~6 shared values)
cp apps/realtime/.env.example apps/realtime/.env
# Copy DATABASE_URL, BETTER_AUTH_URL, BETTER_AUTH_SECRET, INTERNAL_API_SECRET,
# and NEXT_PUBLIC_APP_URL from apps/sim/.env into apps/realtime/.env so both
# services use the same auth secret and DB.
# DB migration env
# DB configs for migration
cp packages/db/.env.example packages/db/.env
# Edit each .env to set DATABASE_URL="postgresql://postgres:your_password@localhost:5432/simstudio"
# Edit both .env files to set DATABASE_URL="postgresql://postgres:your_password@localhost:5432/simstudio"
```
We use per-app `.env` files (the Turborepo-canonical pattern) rather than a
single root `.env`. This mirrors production — each service has its own env
block in Docker Compose / k8s — and keeps sim's app secrets (OAuth, LLM keys,
Stripe, etc.) out of the realtime server's process scope. The shared values
(DATABASE_URL, BETTER_AUTH_SECRET, INTERNAL_API_SECRET, etc.) are duplicated
across `apps/sim/.env` and `apps/realtime/.env`; that's the trade-off.
Production uses env vars passed through Docker Compose / Kubernetes directly
and does not read any `.env` files.
1. Run migrations:
4. Run migrations:
```bash
cd packages/db && bun run db:migrate
```
1. Start development servers:
5. Start development servers:
```bash
bun run dev:full # Starts Next.js app and realtime socket server
```
Or run separately: `bun run dev` (Next.js) and `bun run dev:sockets` (realtime). All scripts run from the repo root.
Or run separately: `bun run dev` (Next.js) and `cd apps/sim && bun run dev:sockets` (realtime).
## Copilot API Keys
Copilot is a Sim-managed service. To use Copilot on a self-hosted instance:
- Go to [https://sim.ai](https://sim.ai) → Settings → Copilot and generate a Copilot API key
- Set `COPILOT_API_KEY` in `apps/sim/.env` to that value
- Go to https://sim.ai → Settings → Copilot and generate a Copilot API key
- Set `COPILOT_API_KEY` environment variable in your self-hosted apps/sim/.env file to that value
## Environment Variables
See the [environment variables reference](https://docs.sim.ai/self-hosting/environment-variables) for the full list, or [`apps/sim/.env.example`](apps/sim/.env.example) (main app) and [`apps/realtime/.env.example`](apps/realtime/.env.example) (realtime server) for defaults.
See the [environment variables reference](https://docs.sim.ai/self-hosting/environment-variables) for the full list, or [`apps/sim/.env.example`](apps/sim/.env.example) for defaults.
## Tech Stack
@@ -164,4 +160,4 @@ We welcome contributions! Please see our [Contributing Guide](.github/CONTRIBUTI
This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.
Made with ❤️ by the Sim Team
<p align="center">Made with ❤️ by the Sim Team</p>

View File

@@ -35,13 +35,13 @@
"postgres": "^3.4.5",
"redis": "5.10.0",
"socket.io": "^4.8.1",
"socket.io-client": "4.8.1",
"zod": "^3.24.2"
},
"devDependencies": {
"@sim/testing": "workspace:*",
"@sim/tsconfig": "workspace:*",
"@types/node": "24.2.1",
"socket.io-client": "4.8.1",
"typescript": "^5.7.3",
"vitest": "^3.0.8"
}

View File

@@ -40,7 +40,7 @@ vi.mock('@/serializer', () => ({
Serializer: vi.fn(),
}))
vi.mock('@/lib/workflows/subblocks', () => ({
vi.mock('@sim/workflow-persistence/subblocks', () => ({
mergeSubblockStateWithValues: mockMergeSubblockStateWithValues,
mergeSubBlockValues: mockMergeSubBlockValues,
}))

View File

@@ -59,7 +59,7 @@ vi.mock('@/lib/logs/execution/trace-spans/trace-spans', () => ({
vi.mock('@/lib/workflows/persistence/utils', () => workflowsPersistenceUtilsMock)
vi.mock('@/lib/workflows/subblocks', () => ({
vi.mock('@sim/workflow-persistence/subblocks', () => ({
mergeSubblockStateWithValues: mergeSubblockStateWithValuesMock,
}))

View File

@@ -1,5 +1,6 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "simstudio",
@@ -68,13 +69,13 @@
"postgres": "^3.4.5",
"redis": "5.10.0",
"socket.io": "^4.8.1",
"socket.io-client": "4.8.1",
"zod": "^3.24.2",
},
"devDependencies": {
"@sim/testing": "workspace:*",
"@sim/tsconfig": "workspace:*",
"@types/node": "24.2.1",
"socket.io-client": "4.8.1",
"typescript": "^5.7.3",
"vitest": "^3.0.8",
},
@@ -301,8 +302,10 @@
"drizzle-orm": "^0.45.2",
},
"devDependencies": {
"@sim/testing": "workspace:*",
"@sim/tsconfig": "workspace:*",
"typescript": "^5.7.3",
"vitest": "^3.0.8",
},
},
"packages/auth": {
@@ -442,6 +445,7 @@
"dependencies": {
"@sim/db": "workspace:*",
"@sim/logger": "workspace:*",
"@sim/utils": "workspace:*",
"@sim/workflow-types": "workspace:*",
"drizzle-orm": "^0.45.2",
"reactflow": "^11.11.4",

View File

@@ -18,13 +18,30 @@ FROM base AS deps
WORKDIR /app
COPY package.json bun.lock turbo.json ./
RUN mkdir -p apps packages/db packages/testing packages/logger packages/tsconfig packages/utils
RUN mkdir -p apps \
packages/audit \
packages/db \
packages/logger \
packages/realtime-protocol \
packages/security \
packages/testing \
packages/tsconfig \
packages/utils \
packages/workflow-authz \
packages/workflow-persistence \
packages/workflow-types
COPY apps/sim/package.json ./apps/sim/package.json
COPY packages/audit/package.json ./packages/audit/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/realtime-protocol/package.json ./packages/realtime-protocol/package.json
COPY packages/security/package.json ./packages/security/package.json
COPY packages/testing/package.json ./packages/testing/package.json
COPY packages/tsconfig/package.json ./packages/tsconfig/package.json
COPY packages/utils/package.json ./packages/utils/package.json
COPY packages/workflow-authz/package.json ./packages/workflow-authz/package.json
COPY packages/workflow-persistence/package.json ./packages/workflow-persistence/package.json
COPY packages/workflow-types/package.json ./packages/workflow-types/package.json
# Install dependencies, then rebuild isolated-vm for Node.js
# Use --linker=hoisted for flat node_modules layout (required for Docker multi-stage builds)
@@ -49,10 +66,17 @@ COPY --from=deps /app/node_modules ./node_modules
# Copy package configuration files (needed for build)
COPY package.json bun.lock turbo.json ./
COPY apps/sim/package.json ./apps/sim/package.json
COPY packages/audit/package.json ./packages/audit/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/realtime-protocol/package.json ./packages/realtime-protocol/package.json
COPY packages/security/package.json ./packages/security/package.json
COPY packages/testing/package.json ./packages/testing/package.json
COPY packages/tsconfig/package.json ./packages/tsconfig/package.json
COPY packages/utils/package.json ./packages/utils/package.json
COPY packages/workflow-authz/package.json ./packages/workflow-authz/package.json
COPY packages/workflow-persistence/package.json ./packages/workflow-persistence/package.json
COPY packages/workflow-types/package.json ./packages/workflow-types/package.json
# Copy workspace configuration files (needed for turbo)
COPY apps/sim/next.config.ts ./apps/sim/next.config.ts

View File

@@ -21,6 +21,8 @@
"lint:helm": "helm lint ./helm/sim --strict --values ./helm/sim/test/values-lint.yaml",
"lint:all": "turbo run lint && bun run lint:helm",
"check": "turbo run format:check",
"check:boundaries": "bun run scripts/check-monorepo-boundaries.ts",
"check:realtime-prune": "bun run scripts/check-realtime-prune-graph.ts",
"mship-contracts:generate": "bun run scripts/sync-mothership-stream-contract.ts",
"mship-contracts:check": "bun run scripts/sync-mothership-stream-contract.ts --check",
"mship-tools:generate": "bun run scripts/sync-tool-catalog.ts",

View File

@@ -20,7 +20,9 @@
"lint": "biome check --write --unsafe .",
"lint:check": "biome check .",
"format": "biome format --write .",
"format:check": "biome format ."
"format:check": "biome format .",
"test": "vitest run",
"test:watch": "vitest"
},
"dependencies": {
"@sim/db": "workspace:*",
@@ -29,7 +31,9 @@
"drizzle-orm": "^0.45.2"
},
"devDependencies": {
"@sim/testing": "workspace:*",
"@sim/tsconfig": "workspace:*",
"typescript": "^5.7.3"
"typescript": "^5.7.3",
"vitest": "^3.0.8"
}
}

View File

@@ -13,6 +13,21 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
vi.mock('@sim/db', () => ({
...dbChainMock,
auditLog: { id: 'id', workspaceId: 'workspace_id' },
user: { id: 'id', name: 'name', email: 'email' },
}))
vi.mock('drizzle-orm', () => ({
eq: vi.fn(),
and: vi.fn(),
or: vi.fn(),
sql: vi.fn(),
}))
vi.mock('@sim/logger', () => ({
createLogger: () => ({
info: vi.fn(),
warn: vi.fn(),
error: vi.fn(),
debug: vi.fn(),
}),
}))
vi.mock('@sim/utils/id', () => ({
generateId: () => 'test-uuid-123',

View File

@@ -0,0 +1,9 @@
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: false,
environment: 'node',
include: ['src/**/*.test.ts'],
},
})

View File

@@ -41,6 +41,7 @@
"dependencies": {
"@sim/db": "workspace:*",
"@sim/logger": "workspace:*",
"@sim/utils": "workspace:*",
"@sim/workflow-types": "workspace:*",
"drizzle-orm": "^0.45.2",
"reactflow": "^11.11.4"

View File

@@ -1,5 +1,6 @@
import { db, workflowBlocks, workflowEdges, workflowSubflows } from '@sim/db'
import { createLogger } from '@sim/logger'
import { toError } from '@sim/utils/errors'
import type { BlockState, WorkflowState } from '@sim/workflow-types/workflow'
import { SUBFLOW_TYPES } from '@sim/workflow-types/workflow'
import type { InferInsertModel } from 'drizzle-orm'
@@ -101,7 +102,7 @@ export async function saveWorkflowToNormalizedTables(
logger.error(`Error saving workflow ${workflowId} to normalized tables:`, error)
return {
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
error: toError(error).message,
}
}
}

View File

@@ -2,6 +2,13 @@ import type { BlockState, SubBlockState } from '@sim/workflow-types/workflow'
export const DEFAULT_SUBBLOCK_TYPE = 'short-input'
/**
* Merges subblock values into the provided subblock structures.
* Falls back to a default subblock shape when a value has no structure.
* @param subBlocks - Existing subblock definitions from the workflow
* @param values - Stored subblock values keyed by subblock id
* @returns Merged subblock structures with updated values
*/
export function mergeSubBlockValues(
subBlocks: Record<string, unknown> | undefined,
values: Record<string, unknown> | undefined
@@ -29,6 +36,14 @@ export function mergeSubBlockValues(
return merged
}
/**
* Merges workflow block states with explicit subblock values while maintaining block structure.
* Values that are null or undefined do not override existing subblock values.
* @param blocks - Block configurations from workflow state
* @param subBlockValues - Subblock values keyed by blockId -> subBlockId -> value
* @param blockId - Optional specific block ID to merge (merges all if not provided)
* @returns Merged block states with updated subblocks
*/
export function mergeSubblockStateWithValues(
blocks: Record<string, BlockState>,
subBlockValues: Record<string, Record<string, unknown>> = {},