From 22e2cde06dfe32482c733e13d12c79cadb673ff4 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Tue, 21 Apr 2026 19:12:36 -0700 Subject: [PATCH 1/5] fix(deps): bump drizzle-orm to 0.45.2 (GHSA-gpj5-g38j-94v9) Resolves Dependabot alert #98. Drizzle ORM <0.45.2 improperly escaped quoted SQL identifiers, allowing SQL injection via untrusted input passed to APIs like sql.identifier() or .as(). Co-Authored-By: Claude Opus 4.7 --- apps/docs/package.json | 2 +- apps/sim/package.json | 6 +++--- bun.lock | 32 ++++++++++++++++++++++---------- package.json | 2 +- packages/db/package.json | 2 +- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/apps/docs/package.json b/apps/docs/package.json index 5b764a30e84..8c314fb40bf 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -20,7 +20,7 @@ "@vercel/og": "^0.6.5", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "drizzle-orm": "^0.44.5", + "drizzle-orm": "^0.45.2", "fumadocs-core": "16.6.7", "fumadocs-mdx": "14.2.8", "fumadocs-openapi": "10.3.13", diff --git a/apps/sim/package.json b/apps/sim/package.json index 6794c71c55f..337acfa8fb7 100644 --- a/apps/sim/package.json +++ b/apps/sim/package.json @@ -63,7 +63,7 @@ "@hookform/resolvers": "^4.1.3", "@linear/sdk": "40.0.0", "@marsidev/react-turnstile": "1.4.2", - "@modelcontextprotocol/sdk": "1.20.2", + "@modelcontextprotocol/sdk": "1.25.3", "@opentelemetry/api": "^1.9.0", "@opentelemetry/exporter-jaeger": "2.1.0", "@opentelemetry/exporter-trace-otlp-http": "^0.200.0", @@ -121,7 +121,7 @@ "decimal.js": "10.6.0", "docx": "^9.6.1", "docx-preview": "^0.3.7", - "drizzle-orm": "^0.44.5", + "drizzle-orm": "^0.45.2", "encoding": "0.1.13", "entities": "6.0.1", "es-toolkit": "1.45.1", @@ -244,7 +244,7 @@ "overrides": { "next": "16.1.6", "@next/env": "16.1.6", - "drizzle-orm": "^0.44.5", + "drizzle-orm": "^0.45.2", "postgres": "^3.4.5", "react-floater": { "react": "$react", diff --git a/bun.lock b/bun.lock index a906e4d2896..75de2d6f038 100644 --- a/bun.lock +++ b/bun.lock @@ -26,7 +26,7 @@ "@vercel/og": "^0.6.5", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "drizzle-orm": "^0.44.5", + "drizzle-orm": "^0.45.2", "fumadocs-core": "16.6.7", "fumadocs-mdx": "14.2.8", "fumadocs-openapi": "10.3.13", @@ -88,7 +88,7 @@ "@hookform/resolvers": "^4.1.3", "@linear/sdk": "40.0.0", "@marsidev/react-turnstile": "1.4.2", - "@modelcontextprotocol/sdk": "1.20.2", + "@modelcontextprotocol/sdk": "1.25.3", "@opentelemetry/api": "^1.9.0", "@opentelemetry/exporter-jaeger": "2.1.0", "@opentelemetry/exporter-trace-otlp-http": "^0.200.0", @@ -146,7 +146,7 @@ "decimal.js": "10.6.0", "docx": "^9.6.1", "docx-preview": "^0.3.7", - "drizzle-orm": "^0.44.5", + "drizzle-orm": "^0.45.2", "encoding": "0.1.13", "entities": "6.0.1", "es-toolkit": "1.45.1", @@ -284,7 +284,7 @@ "name": "@sim/db", "version": "0.1.0", "dependencies": { - "drizzle-orm": "^0.44.5", + "drizzle-orm": "^0.45.2", "postgres": "^3.4.5", "uuid": "^11.1.0", "zod": "^3.24.2", @@ -355,7 +355,7 @@ ], "overrides": { "@next/env": "16.1.6", - "drizzle-orm": "^0.44.5", + "drizzle-orm": "^0.45.2", "next": "16.1.6", "postgres": "^3.4.5", "react": "19.2.4", @@ -790,6 +790,8 @@ "@hexagon/base64": ["@hexagon/base64@1.1.28", "", {}, "sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw=="], + "@hono/node-server": ["@hono/node-server@1.19.14", "", { "peerDependencies": { "hono": "^4" } }, "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw=="], + "@hookform/resolvers": ["@hookform/resolvers@4.1.3", "", { "dependencies": { "@standard-schema/utils": "^0.3.0" }, "peerDependencies": { "react-hook-form": "^7.0.0" } }, "sha512-Jsv6UOWYTrEFJ/01ZrnwVXs7KDvP8XIo115i++5PWvNkNvkrsTfGiLS6w+eJ57CYtUtDQalUWovCZDHFJ8u1VQ=="], "@iconify/types": ["@iconify/types@2.0.0", "", {}, "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="], @@ -892,7 +894,7 @@ "@microsoft/fetch-event-source": ["@microsoft/fetch-event-source@2.0.1", "", {}, "sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA=="], - "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.20.2", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-6rqTdFt67AAAzln3NOKsXRmv5ZzPkgbfaebKBqUbts7vK1GZudqnrun5a8d3M/h955cam9RHZ6Jb4Y1XhnmFPg=="], + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.25.3", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "jose": "^6.1.1", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.0" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ=="], "@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.4.6", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-y+x3H1xBZd38n10NZF/rEBlvDOOMQ6LKUTHqr8R9VkJ+mmQOYtJFxIlkkK8fZrtOiL6VixbOBWMbZGBdal3Z1g=="], @@ -2252,7 +2254,7 @@ "drizzle-kit": ["drizzle-kit@0.31.10", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "tsx": "^4.21.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw=="], - "drizzle-orm": ["drizzle-orm@0.44.7", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-quIpnYznjU9lHshEOAYLoZ9s3jweleHlZIAWR/jX9gAWNg/JhQ1wj0KGRf7/Zm+obRrYd9GjPVJg790QY9N5AQ=="], + "drizzle-orm": ["drizzle-orm@0.45.2", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q=="], "duck": ["duck@0.1.12", "", { "dependencies": { "underscore": "^1.13.1" } }, "sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg=="], @@ -2568,6 +2570,8 @@ "hexer": ["hexer@1.5.0", "", { "dependencies": { "ansi-color": "^0.2.1", "minimist": "^1.1.0", "process": "^0.10.0", "xtend": "^4.0.0" }, "bin": { "hexer": "./cli.js" } }, "sha512-dyrPC8KzBzUJ19QTIo1gXNqIISRXQ0NwteW6OeQHRN4ZuZeHkdODfj0zHBdOlHbRY8GqbqK57C9oWSvQZizFsg=="], + "hono": ["hono@4.12.14", "", {}, "sha512-am5zfg3yu6sqn5yjKBNqhnTX7Cv+m00ox+7jbaKkrLMRJ4rAdldd1xPd/JzbBWspqaQv6RSTrgFN95EsfhC+7w=="], + "html-encoding-sniffer": ["html-encoding-sniffer@4.0.0", "", { "dependencies": { "whatwg-encoding": "^3.1.1" } }, "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ=="], "html-escaper": ["html-escaper@2.0.2", "", {}, "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="], @@ -2730,6 +2734,8 @@ "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], "jsonpointer": ["jsonpointer@5.0.1", "", {}, "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ=="], @@ -4828,6 +4834,8 @@ "@browserbasehq/stagehand/@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.39.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" } }, "sha512-eMyDIPRZbt1CCLErRCi3exlAvNkBtRe+kW5vvJyef93PmNr/clstYgHhtvmkxN82nlKgzyGPCyGxrm0JQ1ZIdg=="], + "@browserbasehq/stagehand/@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.20.2", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-6rqTdFt67AAAzln3NOKsXRmv5ZzPkgbfaebKBqUbts7vK1GZudqnrun5a8d3M/h955cam9RHZ6Jb4Y1XhnmFPg=="], + "@cerebras/cerebras_cloud_sdk/@types/node": ["@types/node@18.19.130", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg=="], "@cerebras/cerebras_cloud_sdk/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], @@ -4846,7 +4854,9 @@ "@langchain/core/uuid": ["uuid@10.0.0", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ=="], - "@modelcontextprotocol/sdk/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], + "@modelcontextprotocol/sdk/jose": ["jose@6.2.2", "", {}, "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ=="], + + "@modelcontextprotocol/sdk/zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], "@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], @@ -5914,6 +5924,8 @@ "@browserbasehq/stagehand/@anthropic-ai/sdk/node-fetch": ["node-fetch@2.7.0", "", { "dependencies": { "whatwg-url": "^5.0.0" }, "peerDependencies": { "encoding": "^0.1.0" }, "optionalPeers": ["encoding"] }, "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A=="], + "@browserbasehq/stagehand/@modelcontextprotocol/sdk/ajv": ["ajv@6.14.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], + "@cerebras/cerebras_cloud_sdk/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="], "@cerebras/cerebras_cloud_sdk/node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], @@ -5962,8 +5974,6 @@ "@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="], - "@modelcontextprotocol/sdk/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], - "@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], "@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], @@ -6630,6 +6640,8 @@ "@browserbasehq/stagehand/@anthropic-ai/sdk/node-fetch/whatwg-url": ["whatwg-url@5.0.0", "", { "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" } }, "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw=="], + "@browserbasehq/stagehand/@modelcontextprotocol/sdk/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + "@cerebras/cerebras_cloud_sdk/node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], "@cerebras/cerebras_cloud_sdk/node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], diff --git a/package.json b/package.json index d78396fbb5c..4a49cf7cd4c 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "react-dom": "19.2.4", "next": "16.1.6", "@next/env": "16.1.6", - "drizzle-orm": "^0.44.5", + "drizzle-orm": "^0.45.2", "postgres": "^3.4.5" }, "devDependencies": { diff --git a/packages/db/package.json b/packages/db/package.json index 92b8abd9cc0..147f89bb887 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -29,7 +29,7 @@ "format:check": "biome format ." }, "dependencies": { - "drizzle-orm": "^0.44.5", + "drizzle-orm": "^0.45.2", "postgres": "^3.4.5", "uuid": "^11.1.0", "zod": "^3.24.2" From 2e3a34179205292bab10e2e059a88de48a8b3f42 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Tue, 21 Apr 2026 19:15:42 -0700 Subject: [PATCH 2/5] chore(mcp): adopt native SDK types after @modelcontextprotocol/sdk 1.25.3 bump Replace hand-written schema/annotation shapes with the SDK's exported Tool, JSONRPCResultResponse, and Tool['annotations'] types so changes upstream flow through automatically. Co-Authored-By: Claude Opus 4.7 --- apps/sim/app/api/mcp/serve/[serverId]/route.ts | 13 +++++-------- apps/sim/lib/copilot/tools/mcp/definitions.ts | 13 +++++-------- apps/sim/lib/mcp/client.ts | 16 ++-------------- 3 files changed, 12 insertions(+), 30 deletions(-) diff --git a/apps/sim/app/api/mcp/serve/[serverId]/route.ts b/apps/sim/app/api/mcp/serve/[serverId]/route.ts index dbb9a0bf916..85c302de282 100644 --- a/apps/sim/app/api/mcp/serve/[serverId]/route.ts +++ b/apps/sim/app/api/mcp/serve/[serverId]/route.ts @@ -10,9 +10,10 @@ import { isJSONRPCRequest, type JSONRPCError, type JSONRPCMessage, - type JSONRPCResponse, + type JSONRPCResultResponse, type ListToolsResult, type RequestId, + type Tool, } from '@modelcontextprotocol/sdk/types.js' import { db } from '@sim/db' import { workflow, workflowMcpServer, workflowMcpTool, workspace } from '@sim/db/schema' @@ -41,11 +42,11 @@ interface ExecuteAuthContext { apiKey?: string | null } -function createResponse(id: RequestId, result: unknown): JSONRPCResponse { +function createResponse(id: RequestId, result: unknown): JSONRPCResultResponse { return { jsonrpc: '2.0', id, - result: result as JSONRPCResponse['result'], + result: result as JSONRPCResultResponse['result'], } } @@ -235,11 +236,7 @@ async function handleToolsList(id: RequestId, serverId: string): Promise { - const schema = tool.parameterSchema as { - type?: string - properties?: Record - required?: string[] - } | null + const schema = tool.parameterSchema as Partial | null return { name: tool.toolName, description: tool.toolDescription || `Execute workflow: ${tool.toolName}`, diff --git a/apps/sim/lib/copilot/tools/mcp/definitions.ts b/apps/sim/lib/copilot/tools/mcp/definitions.ts index 65e02d1e94b..5adc4471c6b 100644 --- a/apps/sim/lib/copilot/tools/mcp/definitions.ts +++ b/apps/sim/lib/copilot/tools/mcp/definitions.ts @@ -1,14 +1,11 @@ -export type ToolAnnotations = { - readOnlyHint?: boolean - destructiveHint?: boolean - idempotentHint?: boolean - openWorldHint?: boolean -} +import type { Tool } from '@modelcontextprotocol/sdk/types.js' + +export type ToolAnnotations = NonNullable export type DirectToolDef = { name: string description: string - inputSchema: { type: 'object'; properties?: Record; required?: string[] } + inputSchema: Tool['inputSchema'] toolId: string annotations?: ToolAnnotations } @@ -16,7 +13,7 @@ export type DirectToolDef = { export type SubagentToolDef = { name: string description: string - inputSchema: { type: 'object'; properties?: Record; required?: string[] } + inputSchema: Tool['inputSchema'] agentId: string annotations?: ToolAnnotations } diff --git a/apps/sim/lib/mcp/client.ts b/apps/sim/lib/mcp/client.ts index f26adf33b7f..0918750b153 100644 --- a/apps/sim/lib/mcp/client.ts +++ b/apps/sim/lib/mcp/client.ts @@ -97,9 +97,7 @@ export class McpClient { version: '1.0.0', }, { - capabilities: { - tools: {}, - }, + capabilities: {}, } ) } @@ -261,21 +259,11 @@ export class McpClient { } } - /** - * Check if server has capability - */ - hasCapability(capability: string): boolean { - const serverCapabilities = this.client.getServerCapabilities() - return !!serverCapabilities?.[capability] - } - /** * Check if the server declared `capabilities.tools.listChanged: true` during initialization. */ hasListChangedCapability(): boolean { - const caps = this.client.getServerCapabilities() - const toolsCap = caps?.tools as Record | undefined - return !!toolsCap?.listChanged + return !!this.client.getServerCapabilities()?.tools?.listChanged } /** From ffce93b9758a5aa3388fa0f14a482a1f98515516 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Tue, 21 Apr 2026 19:25:03 -0700 Subject: [PATCH 3/5] refactor(types): use drizzle $inferSelect for row types Replace hand-written interfaces that duplicated schema shape with typeof table.$inferSelect aliases for webhook, workflow, and workspaceFiles rows. Also simplify metadata insert/update to use .returning() instead of field-by-field copies. Co-Authored-By: Claude Opus 4.7 --- apps/sim/lib/uploads/server/metadata.ts | 127 ++++-------------- apps/sim/lib/webhooks/polling/orchestrator.ts | 6 +- apps/sim/lib/webhooks/polling/types.ts | 22 +-- apps/sim/lib/webhooks/polling/utils.ts | 2 +- apps/sim/lib/webhooks/processor.ts | 24 +--- 5 files changed, 37 insertions(+), 144 deletions(-) diff --git a/apps/sim/lib/uploads/server/metadata.ts b/apps/sim/lib/uploads/server/metadata.ts index a45b8a06274..04e79470ba5 100644 --- a/apps/sim/lib/uploads/server/metadata.ts +++ b/apps/sim/lib/uploads/server/metadata.ts @@ -6,18 +6,7 @@ import type { StorageContext } from '../shared/types' const logger = createLogger('FileMetadata') -export interface FileMetadataRecord { - id: string - key: string - userId: string - workspaceId: string | null - context: string - originalName: string - contentType: string - size: number - deletedAt?: Date | null - uploadedAt: Date -} +export type FileMetadataRecord = typeof workspaceFiles.$inferSelect export interface FileMetadataInsertOptions { key: string @@ -52,7 +41,7 @@ export async function insertFileMetadata( .limit(1) if (existingDeleted.length > 0 && existingDeleted[0].deletedAt) { - await db + const [restored] = await db .update(workspaceFiles) .set({ userId, @@ -65,19 +54,9 @@ export async function insertFileMetadata( uploadedAt: new Date(), }) .where(eq(workspaceFiles.id, existingDeleted[0].id)) + .returning() - return { - id: existingDeleted[0].id, - key, - userId, - workspaceId: workspaceId || null, - context, - originalName, - contentType, - size, - deletedAt: null, - uploadedAt: new Date(), - } + return restored } const existing = await db @@ -87,48 +66,29 @@ export async function insertFileMetadata( .limit(1) if (existing.length > 0) { - return { - id: existing[0].id, - key: existing[0].key, - userId: existing[0].userId, - workspaceId: existing[0].workspaceId, - context: existing[0].context, - originalName: existing[0].originalName, - contentType: existing[0].contentType, - size: existing[0].size, - deletedAt: existing[0].deletedAt, - uploadedAt: existing[0].uploadedAt, - } + return existing[0] } const fileId = id || (await import('uuid')).v4() try { - await db.insert(workspaceFiles).values({ - id: fileId, - key, - userId, - workspaceId: workspaceId || null, - context, - originalName, - contentType, - size, - deletedAt: null, - uploadedAt: new Date(), - }) + const [inserted] = await db + .insert(workspaceFiles) + .values({ + id: fileId, + key, + userId, + workspaceId: workspaceId || null, + context, + originalName, + contentType, + size, + deletedAt: null, + uploadedAt: new Date(), + }) + .returning() - return { - id: fileId, - key, - userId, - workspaceId: workspaceId || null, - context, - originalName, - contentType, - size, - deletedAt: null, - uploadedAt: new Date(), - } + return inserted } catch (error) { if ( (error as any)?.code === '23505' || @@ -141,18 +101,7 @@ export async function insertFileMetadata( .limit(1) if (existingAfterError.length > 0) { - return { - id: existingAfterError[0].id, - key: existingAfterError[0].key, - userId: existingAfterError[0].userId, - workspaceId: existingAfterError[0].workspaceId, - context: existingAfterError[0].context, - originalName: existingAfterError[0].originalName, - contentType: existingAfterError[0].contentType, - size: existingAfterError[0].size, - deletedAt: existingAfterError[0].deletedAt, - uploadedAt: existingAfterError[0].uploadedAt, - } + return existingAfterError[0] } } @@ -186,22 +135,7 @@ export async function getFileMetadataByKey( .where(conditions.length > 1 ? and(...conditions) : conditions[0]) .limit(1) - if (!record) { - return null - } - - return { - id: record.id, - key: record.key, - userId: record.userId, - workspaceId: record.workspaceId, - context: record.context, - originalName: record.originalName, - contentType: record.contentType, - size: record.size, - deletedAt: record.deletedAt, - uploadedAt: record.uploadedAt, - } + return record ?? null } /** @@ -225,24 +159,11 @@ export async function getFileMetadataByContext( conditions.push(isNull(workspaceFiles.deletedAt)) } - const records = await db + return db .select() .from(workspaceFiles) .where(conditions.length > 1 ? and(...conditions) : conditions[0]) .orderBy(workspaceFiles.uploadedAt) - - return records.map((record) => ({ - id: record.id, - key: record.key, - userId: record.userId, - workspaceId: record.workspaceId, - context: record.context, - originalName: record.originalName, - contentType: record.contentType, - size: record.size, - deletedAt: record.deletedAt, - uploadedAt: record.uploadedAt, - })) } /** diff --git a/apps/sim/lib/webhooks/polling/orchestrator.ts b/apps/sim/lib/webhooks/polling/orchestrator.ts index 14133e76a48..6a7f553eb7d 100644 --- a/apps/sim/lib/webhooks/polling/orchestrator.ts +++ b/apps/sim/lib/webhooks/polling/orchestrator.ts @@ -1,7 +1,7 @@ import { createLogger } from '@sim/logger' import { generateShortId } from '@sim/utils/id' import { getPollingHandler } from '@/lib/webhooks/polling/registry' -import type { PollSummary, WebhookRecord, WorkflowRecord } from '@/lib/webhooks/polling/types' +import type { PollSummary } from '@/lib/webhooks/polling/types' import { fetchActiveWebhooks, runWithConcurrency } from '@/lib/webhooks/polling/utils' /** Poll all active webhooks for a given provider. */ @@ -27,8 +27,8 @@ export async function pollProvider(providerName: string): Promise { async (entry) => { const requestId = generateShortId() return handler.pollWebhook({ - webhookData: entry.webhook as WebhookRecord, - workflowData: entry.workflow as WorkflowRecord, + webhookData: entry.webhook, + workflowData: entry.workflow, requestId, logger, }) diff --git a/apps/sim/lib/webhooks/polling/types.ts b/apps/sim/lib/webhooks/polling/types.ts index a69b0427f25..226750095fd 100644 --- a/apps/sim/lib/webhooks/polling/types.ts +++ b/apps/sim/lib/webhooks/polling/types.ts @@ -1,3 +1,4 @@ +import type { webhook, workflow } from '@sim/db/schema' import type { Logger } from '@sim/logger' /** Summary returned after polling all webhooks for a provider. */ @@ -15,25 +16,8 @@ export interface PollWebhookContext { logger: Logger } -/** DB row shape for the webhook table. */ -export interface WebhookRecord { - id: string - path: string - provider: string | null - blockId: string | null - providerConfig: unknown - credentialSetId: string | null - workflowId: string - [key: string]: unknown -} - -/** DB row shape for the workflow table. */ -export interface WorkflowRecord { - id: string - userId: string - workspaceId: string - [key: string]: unknown -} +export type WebhookRecord = typeof webhook.$inferSelect +export type WorkflowRecord = typeof workflow.$inferSelect /** * Strategy interface for provider-specific polling behavior. diff --git a/apps/sim/lib/webhooks/polling/utils.ts b/apps/sim/lib/webhooks/polling/utils.ts index cca46585258..7d42a2e7a6b 100644 --- a/apps/sim/lib/webhooks/polling/utils.ts +++ b/apps/sim/lib/webhooks/polling/utils.ts @@ -96,7 +96,7 @@ export async function fetchActiveWebhooks( ) ) - return rows as unknown as { webhook: WebhookRecord; workflow: WorkflowRecord }[] + return rows } /** diff --git a/apps/sim/lib/webhooks/processor.ts b/apps/sim/lib/webhooks/processor.ts index 654041de608..4c9569e4c5f 100644 --- a/apps/sim/lib/webhooks/processor.ts +++ b/apps/sim/lib/webhooks/processor.ts @@ -642,21 +642,8 @@ export interface PolledWebhookEventResult { statusCode?: number } -interface PolledWebhookRecord { - id: string - path: string - provider: string | null - blockId: string | null - providerConfig: unknown - credentialSetId: string | null - workflowId: string -} - -interface PolledWorkflowRecord { - id: string - userId: string - workspaceId: string -} +type PolledWebhookRecord = typeof webhook.$inferSelect +type PolledWorkflowRecord = typeof workflow.$inferSelect /** * Processes a polled webhook event directly, bypassing the HTTP trigger route. @@ -739,6 +726,7 @@ export async function processPolledWebhookEvent( triggerType: 'webhook', } satisfies AsyncExecutionCorrelation) + const workspaceId = foundWorkflow.workspaceId ?? undefined const payload = { webhookId: foundWebhook.id, workflowId: foundWorkflow.id, @@ -751,7 +739,7 @@ export async function processPolledWebhookEvent( headers: { 'content-type': 'application/json' } as Record, path: foundWebhook.path, blockId: foundWebhook.blockId ?? undefined, - workspaceId: foundWorkflow.workspaceId, + workspaceId, ...(credentialId ? { credentialId } : {}), } @@ -759,7 +747,7 @@ export async function processPolledWebhookEvent( const jobId = await (await getJobQueue()).enqueue('webhook-execution', payload, { metadata: { workflowId: foundWorkflow.id, - workspaceId: foundWorkflow.workspaceId, + workspaceId, userId: actorUserId, correlation, }, @@ -772,7 +760,7 @@ export async function processPolledWebhookEvent( const jobId = await jobQueue.enqueue('webhook-execution', payload, { metadata: { workflowId: foundWorkflow.id, - workspaceId: foundWorkflow.workspaceId, + workspaceId, userId: actorUserId, correlation, }, From 0d9a14e46a54b8be09e92ce6bc73825a01b42b99 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Tue, 21 Apr 2026 19:39:07 -0700 Subject: [PATCH 4/5] fix(uploads): fall through to INSERT if restore-deleted row races a hard delete If a hard delete races between the initial SELECT and the restore UPDATE, .returning() yields no row. Previously the function would return undefined and silently violate the Promise contract. Now the function falls through to the INSERT path, which already handles uniqueness races via the 23505 catch. Co-Authored-By: Claude Opus 4.7 --- apps/sim/lib/uploads/server/metadata.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/sim/lib/uploads/server/metadata.ts b/apps/sim/lib/uploads/server/metadata.ts index 04e79470ba5..e9b40c430af 100644 --- a/apps/sim/lib/uploads/server/metadata.ts +++ b/apps/sim/lib/uploads/server/metadata.ts @@ -56,7 +56,9 @@ export async function insertFileMetadata( .where(eq(workspaceFiles.id, existingDeleted[0].id)) .returning() - return restored + if (restored) { + return restored + } } const existing = await db From 3bb327ffbd7ac7991cca3eb75dca30130311f2fb Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Tue, 21 Apr 2026 19:42:25 -0700 Subject: [PATCH 5/5] chore(uploads): align metadata.ts with global standards Replace dynamic uuid import with generateId() per @sim/utils/id convention, narrow the error catch off `any`, and convert the inline comment to TSDoc. Co-Authored-By: Claude Opus 4.7 --- apps/sim/lib/uploads/server/metadata.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/sim/lib/uploads/server/metadata.ts b/apps/sim/lib/uploads/server/metadata.ts index e9b40c430af..38162a9398e 100644 --- a/apps/sim/lib/uploads/server/metadata.ts +++ b/apps/sim/lib/uploads/server/metadata.ts @@ -1,6 +1,7 @@ import { db } from '@sim/db' import { workspaceFiles } from '@sim/db/schema' import { createLogger } from '@sim/logger' +import { generateId } from '@sim/utils/id' import { and, eq, isNull } from 'drizzle-orm' import type { StorageContext } from '../shared/types' @@ -16,7 +17,8 @@ export interface FileMetadataInsertOptions { originalName: string contentType: string size: number - id?: string // Optional - will generate UUID if not provided + /** Optional — a UUID is generated when omitted. */ + id?: string } export interface FileMetadataQueryOptions { @@ -71,7 +73,7 @@ export async function insertFileMetadata( return existing[0] } - const fileId = id || (await import('uuid')).v4() + const fileId = id || generateId() try { const [inserted] = await db @@ -92,10 +94,8 @@ export async function insertFileMetadata( return inserted } catch (error) { - if ( - (error as any)?.code === '23505' || - (error instanceof Error && error.message.includes('unique')) - ) { + const code = (error as { code?: string } | null)?.code + if (code === '23505' || (error instanceof Error && error.message.includes('unique'))) { const existingAfterError = await db .select() .from(workspaceFiles)