chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:20:55 +08:00
commit d25d482dc2
13754 changed files with 4996608 additions and 0 deletions
@@ -0,0 +1,319 @@
import { z } from 'zod'
import {
introspectionResponseSchema,
nonEmptyRecordSchema,
sqlRowsResponseSchema,
} from '@/lib/api/contracts/tools/databases/shared'
import {
type ContractBodyInput,
type ContractJsonResponse,
defineRouteContract,
} from '@/lib/api/contracts/types'
const secureFlagSchema = z
.union([z.boolean(), z.string()])
.transform((value) => (typeof value === 'string' ? value.toLowerCase() === 'true' : value))
.default(true)
export const clickhouseConnectionBodySchema = z.object({
host: z.string().min(1, 'Host is required'),
port: z.coerce.number().int().positive('Port must be a positive integer'),
database: z.string().min(1, 'Database name is required'),
username: z.string().min(1, 'Username is required'),
password: z.string().default(''),
secure: secureFlagSchema,
})
export const clickhouseQueryBodySchema = clickhouseConnectionBodySchema.extend({
query: z.string().min(1, 'Query is required'),
})
export const clickhouseExecuteBodySchema = clickhouseQueryBodySchema
export const clickhouseInsertBodySchema = clickhouseConnectionBodySchema.extend({
table: z.string().min(1, 'Table name is required'),
data: nonEmptyRecordSchema('Data object cannot be empty'),
})
export const clickhouseUpdateBodySchema = clickhouseConnectionBodySchema.extend({
table: z.string().min(1, 'Table name is required'),
data: nonEmptyRecordSchema('Data object cannot be empty'),
where: z.string().min(1, 'WHERE clause is required'),
})
export const clickhouseDeleteBodySchema = clickhouseConnectionBodySchema.extend({
table: z.string().min(1, 'Table name is required'),
where: z.string().min(1, 'WHERE clause is required'),
})
export const clickhouseIntrospectBodySchema = clickhouseConnectionBodySchema
export const clickhouseQueryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/query',
body: clickhouseQueryBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseExecuteContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/execute',
body: clickhouseExecuteBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseInsertContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/insert',
body: clickhouseInsertBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseUpdateContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/update',
body: clickhouseUpdateBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseDeleteContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/delete',
body: clickhouseDeleteBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseIntrospectContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/introspect',
body: clickhouseIntrospectBodySchema,
response: { mode: 'json', schema: introspectionResponseSchema },
})
const clickhouseTableBodySchema = clickhouseConnectionBodySchema.extend({
table: z.string().min(1, 'Table name is required'),
})
const clickhouseCountResponseSchema = z.object({
message: z.string(),
count: z.number(),
})
const clickhouseDdlResponseSchema = z.object({
message: z.string(),
ddl: z.string(),
})
export const clickhouseListDatabasesBodySchema = clickhouseConnectionBodySchema
export const clickhouseListTablesBodySchema = clickhouseConnectionBodySchema
export const clickhouseDescribeTableBodySchema = clickhouseTableBodySchema
export const clickhouseShowCreateTableBodySchema = clickhouseTableBodySchema
export const clickhouseCountRowsBodySchema = clickhouseTableBodySchema.extend({
where: z.string().optional(),
})
export const clickhouseListPartitionsBodySchema = clickhouseTableBodySchema
export const clickhouseListMutationsBodySchema = clickhouseConnectionBodySchema.extend({
table: z.string().optional(),
onlyRunning: z
.union([z.boolean(), z.string()])
.transform((value) => (typeof value === 'string' ? value.toLowerCase() === 'true' : value))
.default(false),
})
export const clickhouseListRunningQueriesBodySchema = clickhouseConnectionBodySchema
export const clickhouseTableStatsBodySchema = clickhouseConnectionBodySchema.extend({
table: z.string().optional(),
})
export const clickhouseListClustersBodySchema = clickhouseConnectionBodySchema
export const clickhouseCreateDatabaseBodySchema = clickhouseConnectionBodySchema.extend({
name: z.string().min(1, 'Database name is required'),
})
export const clickhouseDropDatabaseBodySchema = clickhouseConnectionBodySchema.extend({
name: z.string().min(1, 'Database name is required'),
})
export const clickhouseCreateTableBodySchema = clickhouseConnectionBodySchema.extend({
table: z.string().min(1, 'Table name is required'),
columns: z
.array(
z.object({
name: z.string().min(1, 'Column name is required'),
type: z.string().min(1, 'Column type is required'),
})
)
.min(1, 'At least one column is required'),
engine: z.string().min(1).default('MergeTree'),
orderBy: z.string().min(1, 'ORDER BY expression is required'),
partitionBy: z.string().optional(),
})
export const clickhouseDropTableBodySchema = clickhouseTableBodySchema
export const clickhouseTruncateTableBodySchema = clickhouseTableBodySchema
export const clickhouseRenameTableBodySchema = clickhouseTableBodySchema.extend({
newTable: z.string().min(1, 'New table name is required'),
})
export const clickhouseOptimizeTableBodySchema = clickhouseTableBodySchema.extend({
final: z
.union([z.boolean(), z.string()])
.transform((value) => (typeof value === 'string' ? value.toLowerCase() === 'true' : value))
.default(false),
})
export const clickhouseDropPartitionBodySchema = clickhouseTableBodySchema.extend({
partition: z.string().min(1, 'Partition expression is required'),
})
export const clickhouseKillQueryBodySchema = clickhouseConnectionBodySchema.extend({
queryId: z.string().min(1, 'Query ID is required'),
})
export const clickhouseInsertRowsBodySchema = clickhouseTableBodySchema.extend({
rows: z.array(z.record(z.string(), z.unknown())).min(1, 'At least one row is required'),
})
export const clickhouseListDatabasesContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/list-databases',
body: clickhouseListDatabasesBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseListTablesContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/list-tables',
body: clickhouseListTablesBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseDescribeTableContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/describe-table',
body: clickhouseDescribeTableBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseShowCreateTableContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/show-create-table',
body: clickhouseShowCreateTableBodySchema,
response: { mode: 'json', schema: clickhouseDdlResponseSchema },
})
export const clickhouseCountRowsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/count-rows',
body: clickhouseCountRowsBodySchema,
response: { mode: 'json', schema: clickhouseCountResponseSchema },
})
export const clickhouseListPartitionsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/list-partitions',
body: clickhouseListPartitionsBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseListMutationsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/list-mutations',
body: clickhouseListMutationsBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseListRunningQueriesContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/list-running-queries',
body: clickhouseListRunningQueriesBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseTableStatsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/table-stats',
body: clickhouseTableStatsBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseListClustersContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/list-clusters',
body: clickhouseListClustersBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseCreateDatabaseContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/create-database',
body: clickhouseCreateDatabaseBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseDropDatabaseContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/drop-database',
body: clickhouseDropDatabaseBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseCreateTableContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/create-table',
body: clickhouseCreateTableBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseDropTableContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/drop-table',
body: clickhouseDropTableBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseTruncateTableContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/truncate-table',
body: clickhouseTruncateTableBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseRenameTableContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/rename-table',
body: clickhouseRenameTableBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseOptimizeTableContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/optimize-table',
body: clickhouseOptimizeTableBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseDropPartitionContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/drop-partition',
body: clickhouseDropPartitionBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseKillQueryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/kill-query',
body: clickhouseKillQueryBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const clickhouseInsertRowsContract = defineRouteContract({
method: 'POST',
path: '/api/tools/clickhouse/insert-rows',
body: clickhouseInsertRowsBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export type ClickHouseQueryRequest = ContractBodyInput<typeof clickhouseQueryContract>
export type ClickHouseQueryResponse = ContractJsonResponse<typeof clickhouseQueryContract>
export type ClickHouseExecuteRequest = ContractBodyInput<typeof clickhouseExecuteContract>
export type ClickHouseExecuteResponse = ContractJsonResponse<typeof clickhouseExecuteContract>
export type ClickHouseInsertRequest = ContractBodyInput<typeof clickhouseInsertContract>
export type ClickHouseInsertResponse = ContractJsonResponse<typeof clickhouseInsertContract>
export type ClickHouseUpdateRequest = ContractBodyInput<typeof clickhouseUpdateContract>
export type ClickHouseUpdateResponse = ContractJsonResponse<typeof clickhouseUpdateContract>
export type ClickHouseDeleteRequest = ContractBodyInput<typeof clickhouseDeleteContract>
export type ClickHouseDeleteResponse = ContractJsonResponse<typeof clickhouseDeleteContract>
export type ClickHouseIntrospectRequest = ContractBodyInput<typeof clickhouseIntrospectContract>
export type ClickHouseIntrospectResponse = ContractJsonResponse<typeof clickhouseIntrospectContract>
@@ -0,0 +1,8 @@
export * from '@/lib/api/contracts/tools/databases/mongodb'
export * from '@/lib/api/contracts/tools/databases/mysql'
export * from '@/lib/api/contracts/tools/databases/neo4j'
export * from '@/lib/api/contracts/tools/databases/postgresql'
export * from '@/lib/api/contracts/tools/databases/rds'
export * from '@/lib/api/contracts/tools/databases/redis'
export * from '@/lib/api/contracts/tools/databases/shared'
export * from '@/lib/api/contracts/tools/databases/supabase'
@@ -0,0 +1,217 @@
import { z } from 'zod'
import {
introspectionResponseSchema,
mongoDocumentsResponseSchema,
sslModeSchema,
} from '@/lib/api/contracts/tools/databases/shared'
import {
type ContractBodyInput,
type ContractJsonResponse,
defineRouteContract,
} from '@/lib/api/contracts/types'
// Un-refined base so the downstream operation schemas can .extend it; each
// reattaches mongoUsernamePasswordPaired after its own .extend.
const mongoConnectionBaseSchema = z.object({
host: z.string().min(1, 'Host is required'),
port: z.coerce.number().int().positive('Port must be a positive integer'),
database: z.string().min(1, 'Database name is required'),
username: z.string().min(1, 'Username is required').optional(),
password: z.string().min(1, 'Password is required').optional(),
authSource: z.string().optional(),
ssl: sslModeSchema,
})
const mongoUsernamePasswordPaired = (data: { username?: string; password?: string }) =>
Boolean(data.username) === Boolean(data.password)
const mongoUsernamePasswordPairedError = {
message: 'Username and password must be provided together',
path: ['password' as const],
}
const mongoJsonStringOrObjectSchema = (message: string) =>
z
.union([z.string(), z.object({}).passthrough()])
.transform((val) => {
if (typeof val === 'object' && val !== null) {
return JSON.stringify(val)
}
return val
})
.refine((val) => val && val.trim() !== '', { message })
const booleanStringSchema = z
.union([z.boolean(), z.string(), z.undefined()])
.optional()
.transform((val) => {
if (val === 'true' || val === true) return true
if (val === 'false' || val === false) return false
return false
})
export const mongodbQueryBodySchema = mongoConnectionBaseSchema
.extend({
collection: z.string().min(1, 'Collection name is required'),
query: z
.union([z.string(), z.object({}).passthrough()])
.optional()
.default('{}')
.transform((val) => {
if (typeof val === 'object' && val !== null) {
return JSON.stringify(val)
}
return val || '{}'
}),
limit: z
.union([z.coerce.number().int().positive(), z.literal(''), z.undefined()])
.optional()
.transform((val) => {
if (val === '' || val === undefined || val === null) {
return 100
}
return val
}),
sort: z
.union([z.string(), z.object({}).passthrough(), z.null()])
.optional()
.transform((val) => {
if (typeof val === 'object' && val !== null) {
return JSON.stringify(val)
}
return val
}),
})
.refine(mongoUsernamePasswordPaired, mongoUsernamePasswordPairedError)
export const mongodbExecuteBodySchema = mongoConnectionBaseSchema
.extend({
collection: z.string().min(1, 'Collection name is required'),
pipeline: z
.union([z.string(), z.array(z.object({}).passthrough())])
.transform((val) => {
if (Array.isArray(val)) {
return JSON.stringify(val)
}
return val
})
.refine((val) => val && val.trim() !== '', {
message: 'Pipeline is required',
}),
})
.refine(mongoUsernamePasswordPaired, mongoUsernamePasswordPairedError)
export const mongodbInsertBodySchema = mongoConnectionBaseSchema
.extend({
collection: z.string().min(1, 'Collection name is required'),
documents: z
.union([z.array(z.record(z.string(), z.unknown())), z.string()])
.transform((val) => {
if (typeof val === 'string') {
try {
const parsed = JSON.parse(val)
return Array.isArray(parsed) ? parsed : [parsed]
} catch {
throw new Error('Invalid JSON in documents field')
}
}
return val
})
.refine((val) => Array.isArray(val) && val.length > 0, {
message: 'At least one document is required',
}),
})
.refine(mongoUsernamePasswordPaired, mongoUsernamePasswordPairedError)
export const mongodbUpdateBodySchema = mongoConnectionBaseSchema
.extend({
collection: z.string().min(1, 'Collection name is required'),
filter: mongoJsonStringOrObjectSchema('Filter is required for MongoDB Update').refine(
(val) => val !== '{}',
{ message: 'Filter is required for MongoDB Update' }
),
update: mongoJsonStringOrObjectSchema('Update is required'),
upsert: booleanStringSchema,
multi: booleanStringSchema,
})
.refine(mongoUsernamePasswordPaired, mongoUsernamePasswordPairedError)
export const mongodbDeleteBodySchema = mongoConnectionBaseSchema
.extend({
collection: z.string().min(1, 'Collection name is required'),
filter: mongoJsonStringOrObjectSchema('Filter is required for MongoDB Delete').refine(
(val) => val !== '{}',
{ message: 'Filter is required for MongoDB Delete' }
),
multi: booleanStringSchema,
})
.refine(mongoUsernamePasswordPaired, mongoUsernamePasswordPairedError)
export const mongodbIntrospectBodySchema = z
.object({
host: z.string().min(1, 'Host is required'),
port: z.coerce.number().int().positive('Port must be a positive integer'),
database: z.string().optional(),
username: z.string().optional(),
password: z.string().optional(),
authSource: z.string().optional(),
ssl: sslModeSchema,
})
.refine((data) => Boolean(data.username) === Boolean(data.password), {
message: 'Username and password must be provided together',
path: ['password'],
})
export const mongodbQueryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/mongodb/query',
body: mongodbQueryBodySchema,
response: { mode: 'json', schema: mongoDocumentsResponseSchema },
})
export const mongodbExecuteContract = defineRouteContract({
method: 'POST',
path: '/api/tools/mongodb/execute',
body: mongodbExecuteBodySchema,
response: { mode: 'json', schema: mongoDocumentsResponseSchema },
})
export const mongodbInsertContract = defineRouteContract({
method: 'POST',
path: '/api/tools/mongodb/insert',
body: mongodbInsertBodySchema,
response: { mode: 'json', schema: mongoDocumentsResponseSchema },
})
export const mongodbUpdateContract = defineRouteContract({
method: 'POST',
path: '/api/tools/mongodb/update',
body: mongodbUpdateBodySchema,
response: { mode: 'json', schema: mongoDocumentsResponseSchema },
})
export const mongodbDeleteContract = defineRouteContract({
method: 'POST',
path: '/api/tools/mongodb/delete',
body: mongodbDeleteBodySchema,
response: { mode: 'json', schema: mongoDocumentsResponseSchema },
})
export const mongodbIntrospectContract = defineRouteContract({
method: 'POST',
path: '/api/tools/mongodb/introspect',
body: mongodbIntrospectBodySchema,
response: { mode: 'json', schema: introspectionResponseSchema },
})
export type MongoDBQueryRequest = ContractBodyInput<typeof mongodbQueryContract>
export type MongoDBQueryResponse = ContractJsonResponse<typeof mongodbQueryContract>
export type MongoDBExecuteRequest = ContractBodyInput<typeof mongodbExecuteContract>
export type MongoDBExecuteResponse = ContractJsonResponse<typeof mongodbExecuteContract>
export type MongoDBInsertRequest = ContractBodyInput<typeof mongodbInsertContract>
export type MongoDBInsertResponse = ContractJsonResponse<typeof mongodbInsertContract>
export type MongoDBUpdateRequest = ContractBodyInput<typeof mongodbUpdateContract>
export type MongoDBUpdateResponse = ContractJsonResponse<typeof mongodbUpdateContract>
export type MongoDBDeleteRequest = ContractBodyInput<typeof mongodbDeleteContract>
export type MongoDBDeleteResponse = ContractJsonResponse<typeof mongodbDeleteContract>
export type MongoDBIntrospectRequest = ContractBodyInput<typeof mongodbIntrospectContract>
export type MongoDBIntrospectResponse = ContractJsonResponse<typeof mongodbIntrospectContract>
@@ -0,0 +1,76 @@
import {
introspectionResponseSchema,
sqlConnectionBodySchema,
sqlDeleteBodySchema,
sqlInsertBodySchema,
sqlQueryBodySchema,
sqlRowsResponseSchema,
sqlUpdateBodySchema,
} from '@/lib/api/contracts/tools/databases/shared'
import {
type ContractBodyInput,
type ContractJsonResponse,
defineRouteContract,
} from '@/lib/api/contracts/types'
export const mysqlQueryBodySchema = sqlQueryBodySchema
export const mysqlExecuteBodySchema = sqlQueryBodySchema
export const mysqlInsertBodySchema = sqlInsertBodySchema
export const mysqlUpdateBodySchema = sqlUpdateBodySchema
export const mysqlDeleteBodySchema = sqlDeleteBodySchema
export const mysqlIntrospectBodySchema = sqlConnectionBodySchema
export const mysqlQueryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/mysql/query',
body: mysqlQueryBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const mysqlExecuteContract = defineRouteContract({
method: 'POST',
path: '/api/tools/mysql/execute',
body: mysqlExecuteBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const mysqlInsertContract = defineRouteContract({
method: 'POST',
path: '/api/tools/mysql/insert',
body: mysqlInsertBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const mysqlUpdateContract = defineRouteContract({
method: 'POST',
path: '/api/tools/mysql/update',
body: mysqlUpdateBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const mysqlDeleteContract = defineRouteContract({
method: 'POST',
path: '/api/tools/mysql/delete',
body: mysqlDeleteBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const mysqlIntrospectContract = defineRouteContract({
method: 'POST',
path: '/api/tools/mysql/introspect',
body: mysqlIntrospectBodySchema,
response: { mode: 'json', schema: introspectionResponseSchema },
})
export type MySQLQueryRequest = ContractBodyInput<typeof mysqlQueryContract>
export type MySQLQueryResponse = ContractJsonResponse<typeof mysqlQueryContract>
export type MySQLExecuteRequest = ContractBodyInput<typeof mysqlExecuteContract>
export type MySQLExecuteResponse = ContractJsonResponse<typeof mysqlExecuteContract>
export type MySQLInsertRequest = ContractBodyInput<typeof mysqlInsertContract>
export type MySQLInsertResponse = ContractJsonResponse<typeof mysqlInsertContract>
export type MySQLUpdateRequest = ContractBodyInput<typeof mysqlUpdateContract>
export type MySQLUpdateResponse = ContractJsonResponse<typeof mysqlUpdateContract>
export type MySQLDeleteRequest = ContractBodyInput<typeof mysqlDeleteContract>
export type MySQLDeleteResponse = ContractJsonResponse<typeof mysqlDeleteContract>
export type MySQLIntrospectRequest = ContractBodyInput<typeof mysqlIntrospectContract>
export type MySQLIntrospectResponse = ContractJsonResponse<typeof mysqlIntrospectContract>
@@ -0,0 +1,99 @@
import { z } from 'zod'
import {
introspectionResponseSchema,
neo4jEncryptionSchema,
neo4jResponseSchema,
} from '@/lib/api/contracts/tools/databases/shared'
import {
type ContractBodyInput,
type ContractJsonResponse,
defineRouteContract,
} from '@/lib/api/contracts/types'
export const neo4jConnectionBodySchema = z.object({
host: z.string().min(1, 'Host is required'),
port: z.coerce.number().int().positive('Port must be a positive integer'),
database: z.string().min(1, 'Database name is required'),
username: z.string().min(1, 'Username is required'),
password: z.string().min(1, 'Password is required'),
encryption: neo4jEncryptionSchema,
})
export const neo4jCypherBodySchema = neo4jConnectionBodySchema.extend({
cypherQuery: z.string().min(1, 'Cypher query is required'),
parameters: z.record(z.string(), z.unknown()).nullable().optional().default({}),
})
export const neo4jQueryBodySchema = neo4jCypherBodySchema
export const neo4jExecuteBodySchema = neo4jCypherBodySchema
export const neo4jCreateBodySchema = neo4jCypherBodySchema
export const neo4jUpdateBodySchema = neo4jCypherBodySchema
export const neo4jMergeBodySchema = neo4jCypherBodySchema
export const neo4jDeleteBodySchema = neo4jCypherBodySchema.extend({
detach: z.boolean().optional().default(false),
})
export const neo4jIntrospectBodySchema = neo4jConnectionBodySchema
export const neo4jQueryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/neo4j/query',
body: neo4jQueryBodySchema,
response: { mode: 'json', schema: neo4jResponseSchema },
})
export const neo4jExecuteContract = defineRouteContract({
method: 'POST',
path: '/api/tools/neo4j/execute',
body: neo4jExecuteBodySchema,
response: { mode: 'json', schema: neo4jResponseSchema },
})
export const neo4jCreateContract = defineRouteContract({
method: 'POST',
path: '/api/tools/neo4j/create',
body: neo4jCreateBodySchema,
response: { mode: 'json', schema: neo4jResponseSchema },
})
export const neo4jUpdateContract = defineRouteContract({
method: 'POST',
path: '/api/tools/neo4j/update',
body: neo4jUpdateBodySchema,
response: { mode: 'json', schema: neo4jResponseSchema },
})
export const neo4jDeleteContract = defineRouteContract({
method: 'POST',
path: '/api/tools/neo4j/delete',
body: neo4jDeleteBodySchema,
response: { mode: 'json', schema: neo4jResponseSchema },
})
export const neo4jMergeContract = defineRouteContract({
method: 'POST',
path: '/api/tools/neo4j/merge',
body: neo4jMergeBodySchema,
response: { mode: 'json', schema: neo4jResponseSchema },
})
export const neo4jIntrospectContract = defineRouteContract({
method: 'POST',
path: '/api/tools/neo4j/introspect',
body: neo4jIntrospectBodySchema,
response: { mode: 'json', schema: introspectionResponseSchema },
})
export type Neo4jQueryRequest = ContractBodyInput<typeof neo4jQueryContract>
export type Neo4jQueryResponse = ContractJsonResponse<typeof neo4jQueryContract>
export type Neo4jExecuteRequest = ContractBodyInput<typeof neo4jExecuteContract>
export type Neo4jExecuteResponse = ContractJsonResponse<typeof neo4jExecuteContract>
export type Neo4jCreateRequest = ContractBodyInput<typeof neo4jCreateContract>
export type Neo4jCreateResponse = ContractJsonResponse<typeof neo4jCreateContract>
export type Neo4jUpdateRequest = ContractBodyInput<typeof neo4jUpdateContract>
export type Neo4jUpdateResponse = ContractJsonResponse<typeof neo4jUpdateContract>
export type Neo4jDeleteRequest = ContractBodyInput<typeof neo4jDeleteContract>
export type Neo4jDeleteResponse = ContractJsonResponse<typeof neo4jDeleteContract>
export type Neo4jMergeRequest = ContractBodyInput<typeof neo4jMergeContract>
export type Neo4jMergeResponse = ContractJsonResponse<typeof neo4jMergeContract>
export type Neo4jIntrospectRequest = ContractBodyInput<typeof neo4jIntrospectContract>
export type Neo4jIntrospectResponse = ContractJsonResponse<typeof neo4jIntrospectContract>
@@ -0,0 +1,79 @@
import { z } from 'zod'
import {
introspectionResponseSchema,
sqlConnectionBodySchema,
sqlDeleteBodySchema,
sqlInsertBodySchema,
sqlQueryBodySchema,
sqlRowsResponseSchema,
sqlUpdateBodySchema,
} from '@/lib/api/contracts/tools/databases/shared'
import {
type ContractBodyInput,
type ContractJsonResponse,
defineRouteContract,
} from '@/lib/api/contracts/types'
export const postgresqlQueryBodySchema = sqlQueryBodySchema
export const postgresqlExecuteBodySchema = sqlQueryBodySchema
export const postgresqlInsertBodySchema = sqlInsertBodySchema
export const postgresqlUpdateBodySchema = sqlUpdateBodySchema
export const postgresqlDeleteBodySchema = sqlDeleteBodySchema
export const postgresqlIntrospectBodySchema = sqlConnectionBodySchema.extend({
schema: z.string().default('public'),
})
export const postgresqlQueryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/postgresql/query',
body: postgresqlQueryBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const postgresqlExecuteContract = defineRouteContract({
method: 'POST',
path: '/api/tools/postgresql/execute',
body: postgresqlExecuteBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const postgresqlInsertContract = defineRouteContract({
method: 'POST',
path: '/api/tools/postgresql/insert',
body: postgresqlInsertBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const postgresqlUpdateContract = defineRouteContract({
method: 'POST',
path: '/api/tools/postgresql/update',
body: postgresqlUpdateBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const postgresqlDeleteContract = defineRouteContract({
method: 'POST',
path: '/api/tools/postgresql/delete',
body: postgresqlDeleteBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const postgresqlIntrospectContract = defineRouteContract({
method: 'POST',
path: '/api/tools/postgresql/introspect',
body: postgresqlIntrospectBodySchema,
response: { mode: 'json', schema: introspectionResponseSchema },
})
export type PostgreSQLQueryRequest = ContractBodyInput<typeof postgresqlQueryContract>
export type PostgreSQLQueryResponse = ContractJsonResponse<typeof postgresqlQueryContract>
export type PostgreSQLExecuteRequest = ContractBodyInput<typeof postgresqlExecuteContract>
export type PostgreSQLExecuteResponse = ContractJsonResponse<typeof postgresqlExecuteContract>
export type PostgreSQLInsertRequest = ContractBodyInput<typeof postgresqlInsertContract>
export type PostgreSQLInsertResponse = ContractJsonResponse<typeof postgresqlInsertContract>
export type PostgreSQLUpdateRequest = ContractBodyInput<typeof postgresqlUpdateContract>
export type PostgreSQLUpdateResponse = ContractJsonResponse<typeof postgresqlUpdateContract>
export type PostgreSQLDeleteRequest = ContractBodyInput<typeof postgresqlDeleteContract>
export type PostgreSQLDeleteResponse = ContractJsonResponse<typeof postgresqlDeleteContract>
export type PostgreSQLIntrospectRequest = ContractBodyInput<typeof postgresqlIntrospectContract>
export type PostgreSQLIntrospectResponse = ContractJsonResponse<typeof postgresqlIntrospectContract>
@@ -0,0 +1,97 @@
import { z } from 'zod'
import {
introspectionResponseSchema,
nonEmptyRecordSchema,
sqlRowsResponseSchema,
} from '@/lib/api/contracts/tools/databases/shared'
import {
type ContractBodyInput,
type ContractJsonResponse,
defineRouteContract,
} from '@/lib/api/contracts/types'
const rdsConnectionBodySchema = z.object({
region: z.string().min(1, 'AWS region is required'),
accessKeyId: z.string().min(1, 'AWS access key ID is required'),
secretAccessKey: z.string().min(1, 'AWS secret access key is required'),
resourceArn: z.string().min(1, 'Resource ARN is required'),
secretArn: z.string().min(1, 'Secret ARN is required'),
database: z.string().optional(),
})
export const rdsQueryBodySchema = rdsConnectionBodySchema.extend({
query: z.string().min(1, 'Query is required'),
})
export const rdsInsertBodySchema = rdsConnectionBodySchema.extend({
table: z.string().min(1, 'Table name is required'),
data: nonEmptyRecordSchema('Data object must have at least one field'),
})
export const rdsUpdateBodySchema = rdsConnectionBodySchema.extend({
table: z.string().min(1, 'Table name is required'),
data: nonEmptyRecordSchema('Data object must have at least one field'),
conditions: nonEmptyRecordSchema('At least one condition is required'),
})
export const rdsDeleteBodySchema = rdsConnectionBodySchema.extend({
table: z.string().min(1, 'Table name is required'),
conditions: nonEmptyRecordSchema('At least one condition is required'),
})
export const rdsIntrospectBodySchema = rdsConnectionBodySchema.extend({
schema: z.string().optional(),
engine: z.enum(['aurora-postgresql', 'aurora-mysql']).optional(),
})
export const rdsQueryContract = defineRouteContract({
method: 'POST',
path: '/api/tools/rds/query',
body: rdsQueryBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const rdsExecuteContract = defineRouteContract({
method: 'POST',
path: '/api/tools/rds/execute',
body: rdsQueryBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const rdsInsertContract = defineRouteContract({
method: 'POST',
path: '/api/tools/rds/insert',
body: rdsInsertBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const rdsUpdateContract = defineRouteContract({
method: 'POST',
path: '/api/tools/rds/update',
body: rdsUpdateBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const rdsDeleteContract = defineRouteContract({
method: 'POST',
path: '/api/tools/rds/delete',
body: rdsDeleteBodySchema,
response: { mode: 'json', schema: sqlRowsResponseSchema },
})
export const rdsIntrospectContract = defineRouteContract({
method: 'POST',
path: '/api/tools/rds/introspect',
body: rdsIntrospectBodySchema,
response: { mode: 'json', schema: introspectionResponseSchema },
})
export type RdsQueryRequest = ContractBodyInput<typeof rdsQueryContract>
export type RdsQueryResponse = ContractJsonResponse<typeof rdsQueryContract>
export type RdsExecuteRequest = ContractBodyInput<typeof rdsExecuteContract>
export type RdsExecuteResponse = ContractJsonResponse<typeof rdsExecuteContract>
export type RdsInsertRequest = ContractBodyInput<typeof rdsInsertContract>
export type RdsInsertResponse = ContractJsonResponse<typeof rdsInsertContract>
export type RdsUpdateRequest = ContractBodyInput<typeof rdsUpdateContract>
export type RdsUpdateResponse = ContractJsonResponse<typeof rdsUpdateContract>
export type RdsDeleteRequest = ContractBodyInput<typeof rdsDeleteContract>
export type RdsDeleteResponse = ContractJsonResponse<typeof rdsDeleteContract>
export type RdsIntrospectRequest = ContractBodyInput<typeof rdsIntrospectContract>
export type RdsIntrospectResponse = ContractJsonResponse<typeof rdsIntrospectContract>
@@ -0,0 +1,23 @@
import { z } from 'zod'
import { redisExecuteResponseSchema } from '@/lib/api/contracts/tools/databases/shared'
import {
type ContractBodyInput,
type ContractJsonResponse,
defineRouteContract,
} from '@/lib/api/contracts/types'
export const redisExecuteBodySchema = z.object({
url: z.string().min(1, 'Redis connection URL is required'),
command: z.string().min(1, 'Redis command is required'),
args: z.array(z.union([z.string(), z.number()])).default([]),
})
export const redisExecuteContract = defineRouteContract({
method: 'POST',
path: '/api/tools/redis/execute',
body: redisExecuteBodySchema,
response: { mode: 'json', schema: redisExecuteResponseSchema },
})
export type RedisExecuteRequest = ContractBodyInput<typeof redisExecuteContract>
export type RedisExecuteResponse = ContractJsonResponse<typeof redisExecuteContract>
@@ -0,0 +1,106 @@
import { getErrorMessage } from '@sim/utils/errors'
import { z } from 'zod'
export const sslModeSchema = z.enum(['disabled', 'required', 'preferred']).default('preferred')
export const neo4jEncryptionSchema = z.enum(['enabled', 'disabled']).default('disabled')
export const nonEmptyRecordSchema = (message: string) =>
z.record(z.string(), z.unknown()).refine((obj) => Object.keys(obj).length > 0, { message })
const jsonObjectStringSchema = (message: string, includeReceivedValue = false) =>
z
.string()
.min(1)
.transform((str) => {
try {
const parsed = JSON.parse(str)
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
throw new Error('Data must be a JSON object')
}
return parsed
} catch (error) {
if (!includeReceivedValue) {
throw new Error(message)
}
const errorMessage = getErrorMessage(error, 'Unknown error')
throw new Error(`${message}: ${errorMessage}. Received: ${str.substring(0, 100)}...`)
}
})
export const sqlConnectionBodySchema = z.object({
host: z.string().min(1, 'Host is required'),
port: z.coerce.number().int().positive('Port must be a positive integer'),
database: z.string().min(1, 'Database name is required'),
username: z.string().min(1, 'Username is required'),
password: z.string().min(1, 'Password is required'),
ssl: sslModeSchema,
})
export const sqlQueryBodySchema = sqlConnectionBodySchema.extend({
query: z.string().min(1, 'Query is required'),
})
const sqlInsertDataSchema = z.union([
nonEmptyRecordSchema('Data object cannot be empty'),
jsonObjectStringSchema('Invalid JSON format in data field', true),
])
const sqlUpdateDataSchema = z.union([
nonEmptyRecordSchema('Data object cannot be empty'),
jsonObjectStringSchema('Invalid JSON format in data field'),
])
export const sqlInsertBodySchema = sqlConnectionBodySchema.extend({
table: z.string().min(1, 'Table name is required'),
data: sqlInsertDataSchema,
})
export const sqlUpdateBodySchema = sqlConnectionBodySchema.extend({
table: z.string().min(1, 'Table name is required'),
data: sqlUpdateDataSchema,
where: z.string().min(1, 'WHERE clause is required'),
})
export const sqlDeleteBodySchema = sqlConnectionBodySchema.extend({
table: z.string().min(1, 'Table name is required'),
where: z.string().min(1, 'WHERE clause is required'),
})
export const sqlRowsResponseSchema = z.object({
message: z.string(),
rows: z.array(z.unknown()),
rowCount: z.number(),
})
export const mongoDocumentsResponseSchema = z
.object({
message: z.string(),
documents: z.array(z.unknown()).optional(),
documentCount: z.number().optional(),
})
.passthrough()
export const neo4jResponseSchema = z
.object({
message: z.string(),
})
.passthrough()
export const introspectionResponseSchema = z
.object({
message: z.string(),
})
.passthrough()
export const redisExecuteResponseSchema = z.object({
result: z.unknown(),
})
export const supabaseStorageUploadResponseSchema = z.object({
success: z.literal(true),
output: z.object({
message: z.string(),
results: z.record(z.string(), z.unknown()),
}),
})
@@ -0,0 +1,35 @@
import { z } from 'zod'
import { supabaseStorageUploadResponseSchema } from '@/lib/api/contracts/tools/databases/shared'
import {
type ContractBodyInput,
type ContractJsonResponse,
defineRouteContract,
} from '@/lib/api/contracts/types'
import { FileInputSchema } from '@/lib/uploads/utils/file-schemas'
export const supabaseStorageUploadBodySchema = z.object({
projectId: z
.string()
.min(1, 'Project ID is required')
.regex(/^[a-z0-9]+$/, 'Project ID must contain only lowercase alphanumeric characters'),
apiKey: z.string().min(1, 'API key is required'),
bucket: z.string().min(1, 'Bucket name is required'),
fileName: z.string().min(1, 'File name is required'),
path: z.string().optional().nullable(),
fileData: FileInputSchema,
contentType: z.string().optional().nullable(),
cacheControl: z.string().optional().nullable(),
upsert: z.boolean().optional().default(false),
})
export const supabaseStorageUploadContract = defineRouteContract({
method: 'POST',
path: '/api/tools/supabase/storage-upload',
body: supabaseStorageUploadBodySchema,
response: { mode: 'json', schema: supabaseStorageUploadResponseSchema },
})
export type SupabaseStorageUploadRequest = ContractBodyInput<typeof supabaseStorageUploadContract>
export type SupabaseStorageUploadResponse = ContractJsonResponse<
typeof supabaseStorageUploadContract
>