diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index 5ca4666b5..d86cf3226 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -55,7 +55,7 @@ "@codemirror/legacy-modes": "6.4.0", "@codemirror/view": "6.29.0", "@dokploy/server": "workspace:*", - "@dokploy/trpc-openapi": "0.0.13", + "@dokploy/trpc-openapi": "0.0.14", "@faker-js/faker": "^8.4.1", "@hookform/resolvers": "^5.2.2", "@octokit/auth-app": "^6.1.3", @@ -144,7 +144,7 @@ "ssh2": "1.15.0", "stripe": "17.2.0", "superjson": "^2.2.2", - "swagger-ui-react": "^5.31.1", + "swagger-ui-react": "^5.31.2", "tailwind-merge": "^2.6.0", "tailwindcss-animate": "^1.0.7", "toml": "3.0.0", diff --git a/apps/dokploy/pages/swagger.tsx b/apps/dokploy/pages/swagger.tsx index cc01cd342..1b962c945 100644 --- a/apps/dokploy/pages/swagger.tsx +++ b/apps/dokploy/pages/swagger.tsx @@ -17,13 +17,19 @@ const Home: NextPage = () => { useEffect(() => { if (data) { const protocolAndHost = `${window.location.protocol}//${window.location.host}/api`; + // Force OpenAPI 3.0 so Swagger UI uses the 3.0 parser (avoids ApiDOM 3.1 refract bug) const newSpec = { ...data, + openapi: "3.0.3", servers: [{ url: protocolAndHost }], externalDocs: { - url: `${protocolAndHost}/settings.getOpenApiDocument`, + url: `${protocolAndHost}/trpc/settings.getOpenApiDocument`, }, }; + // Remove 3.1-only fields that could confuse the 3.0 parser + if ("jsonSchemaDialect" in newSpec) { + delete (newSpec as Record).jsonSchemaDialect; + } setSpec(newSpec); } }, [data]); diff --git a/apps/dokploy/server/api/routers/settings.ts b/apps/dokploy/server/api/routers/settings.ts index bb7269fa7..697a9b630 100644 --- a/apps/dokploy/server/api/routers/settings.ts +++ b/apps/dokploy/server/api/routers/settings.ts @@ -530,12 +530,12 @@ export const settingsRouter = createTRPCRouter({ getOpenApiDocument: protectedProcedure.query( async ({ ctx }): Promise => { const protocol = ctx.req.headers["x-forwarded-proto"]; - const url = `${protocol}://${ctx.req.headers.host}/api`; + const url = `${protocol}://${ctx.req.headers.host}/api/trpc`; const openApiDocument = generateOpenApiDocument(appRouter, { title: "tRPC OpenAPI", - version: "1.0.0", + version: packageInfo.version, baseUrl: url, - docsUrl: `${url}/settings.getOpenApiDocument`, + docsUrl: `${url}/trpc/settings.getOpenApiDocument`, tags: [ "admin", "docker", @@ -572,7 +572,7 @@ export const settingsRouter = createTRPCRouter({ openApiDocument.info = { title: "Dokploy API", description: "Endpoints for dokploy", - version: "1.0.0", + version: packageInfo.version, }; // Add security schemes configuration diff --git a/packages/server/src/db/schema/ai.ts b/packages/server/src/db/schema/ai.ts index 558f2648e..63de40eb7 100644 --- a/packages/server/src/db/schema/ai.ts +++ b/packages/server/src/db/schema/ai.ts @@ -37,22 +37,22 @@ const createSchema = createInsertSchema(ai, { isEnabled: z.boolean().optional(), }); -export const apiCreateAi = createSchema - .pick({ - name: true, - apiUrl: true, - apiKey: true, - model: true, - isEnabled: true, - }) - .required(); +export const apiCreateAi = z.object({ + name: z.string().min(1, { message: "Name is required" }), + apiUrl: z.string().url({ message: "Please enter a valid URL" }), + apiKey: z.string(), + model: z.string().min(1, { message: "Model is required" }), + isEnabled: z.boolean().optional(), +}); -export const apiUpdateAi = createSchema - .partial() - .extend({ - aiId: z.string().min(1), - }) - .omit({ organizationId: true }); +export const apiUpdateAi = z.object({ + aiId: z.string().min(1), + name: z.string().min(1, { message: "Name is required" }).optional(), + apiUrl: z.string().url({ message: "Please enter a valid URL" }).optional(), + apiKey: z.string().optional(), + model: z.string().min(1, { message: "Model is required" }).optional(), + isEnabled: z.boolean().optional(), +}); export const deploySuggestionSchema = z.object({ environmentId: z.string().min(1), diff --git a/packages/server/src/db/schema/application.ts b/packages/server/src/db/schema/application.ts index 515fad32b..f326c3ede 100644 --- a/packages/server/src/db/schema/application.ts +++ b/packages/server/src/db/schema/application.ts @@ -524,9 +524,72 @@ export const apiFindMonitoringStats = z.object({ appName: z.string().min(1), }); -export const apiUpdateApplication = createSchema - .partial() - .extend({ - applicationId: z.string().min(1), - }) - .omit({ serverId: true }); +export const apiUpdateApplication = z.object({ + applicationId: z.string().min(1), + name: z.string().min(1).optional(), + appName: z.string().optional(), + description: z.string().optional(), + env: z.string().optional(), + environmentId: z.string().optional(), + title: z.string().optional(), + subtitle: z.string().optional(), + enabled: z.boolean().optional(), + command: z.string().optional(), + args: z.array(z.string()).optional(), + memoryReservation: z.string().optional(), + memoryLimit: z.string().optional(), + cpuReservation: z.string().optional(), + cpuLimit: z.string().optional(), + buildArgs: z.string().optional(), + buildSecrets: z.string().optional(), + watchPaths: z.array(z.string()).optional(), + previewEnv: z.string().optional(), + previewBuildArgs: z.string().optional(), + previewBuildSecrets: z.string().optional(), + previewLabels: z.array(z.string()).optional(), + previewWildcard: z.string().optional(), + previewPort: z.number().optional(), + previewHttps: z.boolean().optional(), + previewPath: z.string().optional(), + previewLimit: z.number().optional(), + isPreviewDeploymentsActive: z.boolean().optional(), + previewRequireCollaboratorPermissions: z.boolean().optional(), + rollbackActive: z.boolean().optional(), + sourceType: z.enum(["docker", "git", "github", "gitlab", "bitbucket", "gitea", "drop"]).optional(), + cleanCache: z.boolean().optional(), + repository: z.string().optional(), + owner: z.string().optional(), + branch: z.string().optional(), + buildPath: z.string().optional(), + triggerType: z.enum(["push", "tag"]).optional(), + autoDeploy: z.boolean().optional(), + gitlabProjectId: z.number().optional(), + gitlabRepository: z.string().optional(), + gitlabOwner: z.string().optional(), + gitlabBranch: z.string().optional(), + gitlabBuildPath: z.string().optional(), + giteaRepository: z.string().optional(), + giteaOwner: z.string().optional(), + giteaBranch: z.string().optional(), + giteaBuildPath: z.string().optional(), + bitbucketRepository: z.string().optional(), + bitbucketRepositorySlug: z.string().optional(), + bitbucketOwner: z.string().optional(), + bitbucketBranch: z.string().optional(), + bitbucketBuildPath: z.string().optional(), + dockerImage: z.string().optional(), + username: z.string().optional(), + password: z.string().optional(), + registryUrl: z.string().optional(), + customGitUrl: z.string().optional(), + customGitBranch: z.string().optional(), + customGitBuildPath: z.string().optional(), + customGitSSHKeyId: z.string().optional(), + dockerfile: z.string().optional(), + dockerContextPath: z.string().optional(), + dockerBuildStage: z.string().optional(), + buildType: z.enum(["dockerfile", "heroku_buildpacks", "paketo_buildpacks", "nixpacks", "static", "railpack"]).optional(), + publishDirectory: z.string().optional(), + isStaticSpa: z.boolean().optional(), + createEnvFile: z.boolean().optional(), +}); diff --git a/packages/server/src/db/schema/compose.ts b/packages/server/src/db/schema/compose.ts index f11024812..b77962ca4 100644 --- a/packages/server/src/db/schema/compose.ts +++ b/packages/server/src/db/schema/compose.ts @@ -172,24 +172,26 @@ const createSchema = createInsertSchema(compose, { watchPaths: z.array(z.string()).optional(), }); -export const apiCreateCompose = createSchema.pick({ - name: true, - description: true, - environmentId: true, - composeType: true, - appName: true, - serverId: true, - composeFile: true, +export const apiCreateCompose = z.object({ + name: z.string().min(1), + description: z.string().optional(), + environmentId: z.string().min(1), + composeType: z.enum(["docker-compose", "stack"]).optional(), + appName: z + .string() + .min(1) + .max(63) + .regex(APP_NAME_REGEX, APP_NAME_MESSAGE) + .optional(), + serverId: z.string().optional(), + composeFile: z.string().optional(), }); -export const apiCreateComposeByTemplate = createSchema - .pick({ - environmentId: true, - }) - .extend({ - id: z.string().min(1), - serverId: z.string().optional(), - }); +export const apiCreateComposeByTemplate = z.object({ + environmentId: z.string().min(1), + id: z.string().min(1), + serverId: z.string().optional(), +}); export const apiFindCompose = z.object({ composeId: z.string().min(1), @@ -217,20 +219,25 @@ export const apiFetchServices = z.object({ type: z.enum(["fetch", "cache"]).optional().default("cache"), }); -export const apiUpdateCompose = createSchema - .partial() - .extend({ - composeId: z.string(), - composeFile: z.string().optional(), - command: z.string().optional(), - }) - .omit({ serverId: true }); +export const apiUpdateCompose = z.object({ + composeId: z.string().min(1), + composeFile: z.string().optional(), + command: z.string().optional(), + name: z.string().min(1).optional(), + description: z.string().optional(), + env: z.string().optional(), + appName: z.string().optional(), + environmentId: z.string().optional(), + composeType: z.enum(["docker-compose", "stack"]).optional(), + sourceType: z + .enum(["git", "github", "gitlab", "bitbucket", "gitea", "raw"]) + .optional(), + triggerType: z.enum(["push", "tag"]).optional(), + watchPaths: z.array(z.string()).optional(), + composePath: z.string().min(1).optional(), +}); -export const apiRandomizeCompose = createSchema - .pick({ - composeId: true, - }) - .extend({ - suffix: z.string().optional(), - composeId: z.string().min(1), - }); +export const apiRandomizeCompose = z.object({ + composeId: z.string().min(1), + suffix: z.string().optional(), +}); diff --git a/packages/server/src/db/schema/deployment.ts b/packages/server/src/db/schema/deployment.ts index 4e2666e5b..5f839519c 100644 --- a/packages/server/src/db/schema/deployment.ts +++ b/packages/server/src/db/schema/deployment.ts @@ -126,122 +126,84 @@ const schema = createInsertSchema(deployments, { previewDeploymentId: z.string(), buildServerId: z.string(), }); -export const apiCreateDeployment = schema - .pick({ - title: true, - status: true, - logPath: true, - applicationId: true, - description: true, - previewDeploymentId: true, - }) - .extend({ - applicationId: z.string().min(1), - }); +export const apiCreateDeployment = z.object({ + title: z.string().min(1), + status: z.string().default("running"), + logPath: z.string().min(1), + applicationId: z.string().min(1), + description: z.string().optional(), + previewDeploymentId: z.string().optional(), +}); -export const apiCreateDeploymentPreview = schema - .pick({ - title: true, - status: true, - logPath: true, - description: true, - previewDeploymentId: true, - }) - .extend({ - previewDeploymentId: z.string().min(1), - }); +export const apiCreateDeploymentPreview = z.object({ + title: z.string().min(1), + status: z.string().default("running"), + logPath: z.string().min(1), + description: z.string().optional(), + previewDeploymentId: z.string().min(1), +}); -export const apiCreateDeploymentCompose = schema - .pick({ - title: true, - status: true, - logPath: true, - composeId: true, - description: true, - }) - .extend({ - composeId: z.string().min(1), - }); +export const apiCreateDeploymentCompose = z.object({ + title: z.string().min(1), + status: z.string().default("running"), + logPath: z.string().min(1), + composeId: z.string().min(1), + description: z.string().optional(), +}); -export const apiCreateDeploymentBackup = schema - .pick({ - title: true, - status: true, - logPath: true, - backupId: true, - description: true, - }) - .extend({ - backupId: z.string().min(1), - }); +export const apiCreateDeploymentBackup = z.object({ + title: z.string().min(1), + status: z.string().default("running"), + logPath: z.string().min(1), + backupId: z.string().min(1), + description: z.string().optional(), +}); -export const apiCreateDeploymentServer = schema - .pick({ - title: true, - status: true, - logPath: true, - serverId: true, - description: true, - }) - .extend({ - serverId: z.string().min(1), - }); +export const apiCreateDeploymentServer = z.object({ + title: z.string().min(1), + status: z.string().default("running"), + logPath: z.string().min(1), + serverId: z.string().min(1), + description: z.string().optional(), +}); -export const apiCreateDeploymentSchedule = schema - .pick({ - title: true, - status: true, - logPath: true, - description: true, - }) - .extend({ - scheduleId: z.string().min(1), - }); +export const apiCreateDeploymentSchedule = z.object({ + title: z.string().min(1), + status: z.string().default("running"), + logPath: z.string().min(1), + description: z.string().optional(), + scheduleId: z.string().min(1), +}); -export const apiCreateDeploymentVolumeBackup = schema - .pick({ - title: true, - status: true, - logPath: true, - description: true, - }) - .extend({ - volumeBackupId: z.string().min(1), - }); +export const apiCreateDeploymentVolumeBackup = z.object({ + title: z.string().min(1), + status: z.string().default("running"), + logPath: z.string().min(1), + description: z.string().optional(), + volumeBackupId: z.string().min(1), +}); export const apiFindAllByApplication = z.object({ applicationId: z.string().min(1), }); -export const apiFindAllByCompose = schema - .pick({ - composeId: true, - }) - .extend({ - composeId: z.string().min(1), - }) - .required(); +export const apiFindAllByCompose = z.object({ + composeId: z.string().min(1), +}); -export const apiFindAllByServer = schema - .pick({ - serverId: true, - }) - .extend({ - serverId: z.string().min(1), - }) - .required(); +export const apiFindAllByServer = z.object({ + serverId: z.string().min(1), +}); -export const apiFindAllByType = z - .object({ - id: z.string().min(1), - type: z.enum([ - "application", - "compose", - "server", - "schedule", - "previewDeployment", - "backup", - "volumeBackup", - ]), - }) - .required(); +export const apiFindAllByType = z.object({ + id: z.string().min(1), + type: z.enum([ + "application", + "compose", + "server", + "schedule", + "previewDeployment", + "backup", + "volumeBackup", + ]), +}); diff --git a/packages/server/src/db/schema/destination.ts b/packages/server/src/db/schema/destination.ts index 8e51aef91..477f24c49 100644 --- a/packages/server/src/db/schema/destination.ts +++ b/packages/server/src/db/schema/destination.ts @@ -46,43 +46,33 @@ const createSchema = createInsertSchema(destinations, { region: z.string(), }); -export const apiCreateDestination = createSchema - .pick({ - name: true, - provider: true, - accessKey: true, - bucket: true, - region: true, - endpoint: true, - secretAccessKey: true, - }) - .required() - .extend({ - serverId: z.string().optional(), - }); +export const apiCreateDestination = z.object({ + name: z.string().min(1), + provider: z.string(), + accessKey: z.string(), + bucket: z.string(), + region: z.string(), + endpoint: z.string(), + secretAccessKey: z.string(), + serverId: z.string().optional(), +}); export const apiFindOneDestination = z.object({ destinationId: z.string().min(1), }); -export const apiRemoveDestination = createSchema - .pick({ - destinationId: true, - }) - .required(); +export const apiRemoveDestination = z.object({ + destinationId: z.string().min(1), +}); -export const apiUpdateDestination = createSchema - .pick({ - name: true, - accessKey: true, - bucket: true, - region: true, - endpoint: true, - secretAccessKey: true, - destinationId: true, - provider: true, - }) - .required() - .extend({ - serverId: z.string().optional(), - }); +export const apiUpdateDestination = z.object({ + destinationId: z.string().min(1), + name: z.string().min(1).optional(), + accessKey: z.string().optional(), + bucket: z.string().optional(), + region: z.string().optional(), + endpoint: z.string().optional(), + provider: z.string().optional(), + secretAccessKey: z.string().optional(), + serverId: z.string().optional(), +}); diff --git a/packages/server/src/db/schema/environment.ts b/packages/server/src/db/schema/environment.ts index add3d8657..342fb1708 100644 --- a/packages/server/src/db/schema/environment.ts +++ b/packages/server/src/db/schema/environment.ts @@ -1,6 +1,5 @@ import { relations } from "drizzle-orm"; import { boolean, pgTable, text } from "drizzle-orm/pg-core"; -import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { applications } from "./application"; @@ -46,46 +45,30 @@ export const environmentRelations = relations( }), ); -const createSchema = createInsertSchema(environments, { +export const apiCreateEnvironment = z.object({ + name: z.string().min(1), + description: z.string().optional(), + projectId: z.string().min(1), +}); + +export const apiFindOneEnvironment = z.object({ + environmentId: z.string().min(1), +}); + +export const apiRemoveEnvironment = z.object({ + environmentId: z.string().min(1), +}); + +export const apiUpdateEnvironment = z.object({ + environmentId: z.string().min(1), + name: z.string().min(1).optional(), + description: z.string().optional(), + projectId: z.string().optional(), + env: z.string().optional(), +}); + +export const apiDuplicateEnvironment = z.object({ environmentId: z.string().min(1), name: z.string().min(1), description: z.string().optional(), }); - -export const apiCreateEnvironment = createSchema.pick({ - name: true, - description: true, - projectId: true, -}); - -export const apiFindOneEnvironment = createSchema - .pick({ - environmentId: true, - }) - .required(); - -export const apiRemoveEnvironment = createSchema - .pick({ - environmentId: true, - }) - .required(); - -export const apiUpdateEnvironment = createSchema - .partial() - .extend({ - environmentId: z.string().min(1), - }) - .omit({ - isDefault: true, - }); - -export const apiDuplicateEnvironment = createSchema - .pick({ - environmentId: true, - name: true, - description: true, - }) - .required({ - environmentId: true, - name: true, - }); diff --git a/packages/server/src/db/schema/git-provider.ts b/packages/server/src/db/schema/git-provider.ts index 3d2c7027c..74dd5cd94 100644 --- a/packages/server/src/db/schema/git-provider.ts +++ b/packages/server/src/db/schema/git-provider.ts @@ -1,6 +1,5 @@ import { relations } from "drizzle-orm"; import { pgEnum, pgTable, text } from "drizzle-orm/pg-core"; -import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { organization } from "./account"; @@ -62,10 +61,6 @@ export const gitProviderRelations = relations(gitProvider, ({ one }) => ({ }), })); -const createSchema = createInsertSchema(gitProvider); - -export const apiRemoveGitProvider = createSchema - .extend({ - gitProviderId: z.string().min(1), - }) - .pick({ gitProviderId: true }); +export const apiRemoveGitProvider = z.object({ + gitProviderId: z.string().min(1), +}); diff --git a/packages/server/src/db/schema/github.ts b/packages/server/src/db/schema/github.ts index fb8a267a7..b943b9945 100644 --- a/packages/server/src/db/schema/github.ts +++ b/packages/server/src/db/schema/github.ts @@ -1,6 +1,5 @@ import { relations } from "drizzle-orm"; import { integer, pgTable, text } from "drizzle-orm/pg-core"; -import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { gitProvider } from "./git-provider"; @@ -29,8 +28,7 @@ export const githubProviderRelations = relations(github, ({ one }) => ({ }), })); -const createSchema = createInsertSchema(github); -export const apiCreateGithub = createSchema.extend({ +export const apiCreateGithub = z.object({ githubAppName: z.string().optional(), githubAppId: z.number().optional(), githubClientId: z.string().optional(), @@ -48,13 +46,11 @@ export const apiFindGithubBranches = z.object({ githubId: z.string().optional(), }); -export const apiFindOneGithub = createSchema - .extend({ - githubId: z.string().min(1), - }) - .pick({ githubId: true }); +export const apiFindOneGithub = z.object({ + githubId: z.string().min(1), +}); -export const apiUpdateGithub = createSchema.extend({ +export const apiUpdateGithub = z.object({ githubId: z.string().min(1), name: z.string().min(1), gitProviderId: z.string().min(1), diff --git a/packages/server/src/db/schema/gitlab.ts b/packages/server/src/db/schema/gitlab.ts index 0d2bc8a0d..09811870a 100644 --- a/packages/server/src/db/schema/gitlab.ts +++ b/packages/server/src/db/schema/gitlab.ts @@ -1,6 +1,5 @@ import { relations } from "drizzle-orm"; import { integer, pgTable, text } from "drizzle-orm/pg-core"; -import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { gitProvider } from "./git-provider"; @@ -31,9 +30,7 @@ export const gitlabProviderRelations = relations(gitlab, ({ one }) => ({ }), })); -const createSchema = createInsertSchema(gitlab); - -export const apiCreateGitlab = createSchema.extend({ +export const apiCreateGitlab = z.object({ applicationId: z.string().optional(), secret: z.string().optional(), groupName: z.string().optional(), @@ -45,17 +42,14 @@ export const apiCreateGitlab = createSchema.extend({ gitlabInternalUrl: z.string().optional().nullable(), }); -export const apiFindOneGitlab = createSchema - .extend({ - gitlabId: z.string().min(1), - }) - .pick({ gitlabId: true }); +export const apiFindOneGitlab = z.object({ + gitlabId: z.string().min(1), +}); -export const apiGitlabTestConnection = createSchema - .extend({ - groupName: z.string().optional(), - }) - .pick({ gitlabId: true, groupName: true }); +export const apiGitlabTestConnection = z.object({ + gitlabId: z.string().min(1), + groupName: z.string().optional(), +}); export const apiFindGitlabBranches = z.object({ id: z.number().optional(), @@ -64,7 +58,7 @@ export const apiFindGitlabBranches = z.object({ gitlabId: z.string().optional(), }); -export const apiUpdateGitlab = createSchema.extend({ +export const apiUpdateGitlab = z.object({ applicationId: z.string().optional(), secret: z.string().optional(), groupName: z.string().optional(), diff --git a/packages/server/src/db/schema/mariadb.ts b/packages/server/src/db/schema/mariadb.ts index ac4b0e823..e629c1282 100644 --- a/packages/server/src/db/schema/mariadb.ts +++ b/packages/server/src/db/schema/mariadb.ts @@ -198,12 +198,27 @@ export const apiResetMariadb = createSchema }) .required(); -export const apiUpdateMariaDB = createSchema - .partial() - .extend({ - mariadbId: z.string().min(1), - }) - .omit({ serverId: true }); +export const apiUpdateMariaDB = z.object({ + mariadbId: z.string().min(1), + name: z.string().min(1).optional(), + appName: z.string().optional(), + description: z.string().optional(), + dockerImage: z.string().optional(), + command: z.string().optional(), + args: z.array(z.string()).optional(), + env: z.string().optional(), + databaseName: z.string().min(1).optional(), + databaseUser: z.string().min(1).optional(), + databasePassword: z.string().optional(), + databaseRootPassword: z.string().optional(), + memoryReservation: z.string().optional(), + memoryLimit: z.string().optional(), + cpuReservation: z.string().optional(), + cpuLimit: z.string().optional(), + externalPort: z.number().optional(), + applicationStatus: z.enum(["idle", "running", "done", "error"]).optional(), + environmentId: z.string().optional(), +}); export const apiRebuildMariadb = createSchema .pick({ diff --git a/packages/server/src/db/schema/mongo.ts b/packages/server/src/db/schema/mongo.ts index ff315bbf6..7f9d2d523 100644 --- a/packages/server/src/db/schema/mongo.ts +++ b/packages/server/src/db/schema/mongo.ts @@ -144,65 +144,79 @@ const createSchema = createInsertSchema(mongo, { ulimitsSwarm: UlimitsSwarmSchema.nullable(), }); -export const apiCreateMongo = createSchema.pick({ - name: true, - appName: true, - dockerImage: true, - environmentId: true, - description: true, - databaseUser: true, - databasePassword: true, - serverId: true, - replicaSets: true, +const mongoPasswordSchema = z + .string() + .regex(/^[a-zA-Z0-9@#%^&*()_+\-=[\]{}|;:,.<>?~`]*$/, { + message: + "Password contains invalid characters. Please avoid: $ ! ' \" \\ / and space characters for database compatibility", + }); + +export const apiCreateMongo = z.object({ + name: z.string().min(1), + appName: z + .string() + .min(1) + .max(63) + .regex(APP_NAME_REGEX, APP_NAME_MESSAGE) + .optional(), + dockerImage: z.string().default("mongo:15"), + environmentId: z.string().min(1), + description: z.string().optional(), + databaseUser: z.string().min(1), + databasePassword: mongoPasswordSchema, + serverId: z.string().optional(), + replicaSets: z.boolean().default(false), }); export const apiFindOneMongo = z.object({ mongoId: z.string().min(1), }); -export const apiChangeMongoStatus = createSchema - .pick({ - mongoId: true, - applicationStatus: true, - }) - .required(); +export const apiChangeMongoStatus = z.object({ + mongoId: z.string().min(1), + applicationStatus: z.enum(["idle", "running", "done", "error"]), +}); -export const apiSaveEnvironmentVariablesMongo = createSchema - .pick({ - mongoId: true, - env: true, - }) - .required(); +export const apiSaveEnvironmentVariablesMongo = z.object({ + mongoId: z.string().min(1), + env: z.string().optional(), +}); -export const apiSaveExternalPortMongo = createSchema - .pick({ - mongoId: true, - externalPort: true, - }) - .required(); +export const apiSaveExternalPortMongo = z.object({ + mongoId: z.string().min(1), + externalPort: z.number(), +}); -export const apiDeployMongo = createSchema - .pick({ - mongoId: true, - }) - .required(); +export const apiDeployMongo = z.object({ + mongoId: z.string().min(1), +}); -export const apiUpdateMongo = createSchema - .partial() - .extend({ - mongoId: z.string().min(1), - }) - .omit({ serverId: true }); +export const apiUpdateMongo = z.object({ + mongoId: z.string().min(1), + name: z.string().min(1).optional(), + appName: z.string().optional(), + description: z.string().optional(), + dockerImage: z.string().optional(), + command: z.string().optional(), + args: z.array(z.string()).optional(), + env: z.string().optional(), + databaseUser: z.string().min(1).optional(), + databasePassword: mongoPasswordSchema.optional(), + memoryReservation: z.string().optional(), + memoryLimit: z.string().optional(), + cpuReservation: z.string().optional(), + cpuLimit: z.string().optional(), + externalPort: z.number().optional(), + applicationStatus: z.enum(["idle", "running", "done", "error"]).optional(), + environmentId: z.string().optional(), + replicaSets: z.boolean().optional(), +}); -export const apiResetMongo = createSchema - .pick({ - mongoId: true, - appName: true, - }) - .required(); +export const apiResetMongo = z.object({ + mongoId: z.string().min(1), + appName: z.string().min(1), +}); -export const apiRebuildMongo = createSchema - .pick({ - mongoId: true, - }) - .required(); +export const apiRebuildMongo = z.object({ + mongoId: z.string().min(1), +}); diff --git a/packages/server/src/db/schema/mount.ts b/packages/server/src/db/schema/mount.ts index 299f39caf..90c0ceb7e 100644 --- a/packages/server/src/db/schema/mount.ts +++ b/packages/server/src/db/schema/mount.ts @@ -116,45 +116,54 @@ export type ServiceType = NonNullable< z.infer["serviceType"] >; -export const apiCreateMount = createSchema - .pick({ - type: true, - hostPath: true, - volumeName: true, - content: true, - mountPath: true, - serviceType: true, - filePath: true, - }) - .extend({ - serviceId: z.string().min(1), - }); +const serviceTypeEnum = z.enum([ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose", +]); -export const apiFindOneMount = createSchema - .pick({ - mountId: true, - }) - .required(); +export const apiCreateMount = z.object({ + type: z.enum(["bind", "volume", "file"]), + hostPath: z.string().optional(), + volumeName: z.string().optional(), + content: z.string().optional(), + mountPath: z.string().min(1), + serviceType: serviceTypeEnum.default("application"), + filePath: z.string().optional(), + serviceId: z.string().min(1), +}); -export const apiRemoveMount = createSchema - .pick({ - mountId: true, - }) - // .extend({ - // appName: z.string().min(1), - // }) - .required(); - -export const apiFindMountByApplicationId = createSchema - .extend({ - serviceId: z.string().min(1), - }) - .pick({ - serviceId: true, - serviceType: true, - }) - .required(); - -export const apiUpdateMount = createSchema.partial().extend({ +export const apiFindOneMount = z.object({ mountId: z.string().min(1), }); + +export const apiRemoveMount = z.object({ + mountId: z.string().min(1), +}); + +export const apiFindMountByApplicationId = z.object({ + serviceId: z.string().min(1), + serviceType: serviceTypeEnum, +}); + +export const apiUpdateMount = z.object({ + mountId: z.string().min(1), + type: z.enum(["bind", "volume", "file"]).optional(), + hostPath: z.string().optional(), + volumeName: z.string().optional(), + filePath: z.string().optional(), + content: z.string().optional(), + serviceType: serviceTypeEnum.optional(), + mountPath: z.string().min(1).optional(), + applicationId: z.string().optional(), + postgresId: z.string().optional(), + mariadbId: z.string().optional(), + mongoId: z.string().optional(), + mysqlId: z.string().optional(), + redisId: z.string().optional(), + composeId: z.string().optional(), +}); diff --git a/packages/server/src/db/schema/mysql.ts b/packages/server/src/db/schema/mysql.ts index a5f066de8..39ea223a7 100644 --- a/packages/server/src/db/schema/mysql.ts +++ b/packages/server/src/db/schema/mysql.ts @@ -144,66 +144,81 @@ const createSchema = createInsertSchema(mysql, { ulimitsSwarm: UlimitsSwarmSchema.nullable(), }); -export const apiCreateMySql = createSchema.pick({ - name: true, - appName: true, - dockerImage: true, - environmentId: true, - description: true, - databaseName: true, - databaseUser: true, - databasePassword: true, - databaseRootPassword: true, - serverId: true, +const mysqlPasswordSchema = z + .string() + .regex(/^[a-zA-Z0-9@#%^&*()_+\-=[\]{}|;:,.<>?~`]*$/, { + message: + "Password contains invalid characters. Please avoid: $ ! ' \" \\ / and space characters for database compatibility", + }); + +export const apiCreateMySql = z.object({ + name: z.string().min(1), + appName: z + .string() + .min(1) + .max(63) + .regex(APP_NAME_REGEX, APP_NAME_MESSAGE) + .optional(), + dockerImage: z.string().default("mysql:8"), + environmentId: z.string().min(1), + description: z.string().optional(), + databaseName: z.string().min(1), + databaseUser: z.string().min(1), + databasePassword: mysqlPasswordSchema, + databaseRootPassword: mysqlPasswordSchema.optional(), + serverId: z.string().optional(), }); export const apiFindOneMySql = z.object({ mysqlId: z.string().min(1), }); -export const apiChangeMySqlStatus = createSchema - .pick({ - mysqlId: true, - applicationStatus: true, - }) - .required(); +export const apiChangeMySqlStatus = z.object({ + mysqlId: z.string().min(1), + applicationStatus: z.enum(["idle", "running", "done", "error"]), +}); -export const apiSaveEnvironmentVariablesMySql = createSchema - .pick({ - mysqlId: true, - env: true, - }) - .required(); +export const apiSaveEnvironmentVariablesMySql = z.object({ + mysqlId: z.string().min(1), + env: z.string().optional(), +}); -export const apiSaveExternalPortMySql = createSchema - .pick({ - mysqlId: true, - externalPort: true, - }) - .required(); +export const apiSaveExternalPortMySql = z.object({ + mysqlId: z.string().min(1), + externalPort: z.number(), +}); -export const apiResetMysql = createSchema - .pick({ - mysqlId: true, - appName: true, - }) - .required(); +export const apiResetMysql = z.object({ + mysqlId: z.string().min(1), + appName: z.string().min(1), +}); -export const apiDeployMySql = createSchema - .pick({ - mysqlId: true, - }) - .required(); +export const apiDeployMySql = z.object({ + mysqlId: z.string().min(1), +}); -export const apiUpdateMySql = createSchema - .partial() - .extend({ - mysqlId: z.string().min(1), - }) - .omit({ serverId: true }); +export const apiUpdateMySql = z.object({ + mysqlId: z.string().min(1), + name: z.string().min(1).optional(), + appName: z.string().optional(), + description: z.string().optional(), + dockerImage: z.string().optional(), + command: z.string().optional(), + args: z.array(z.string()).optional(), + env: z.string().optional(), + databaseName: z.string().min(1).optional(), + databaseUser: z.string().min(1).optional(), + databasePassword: mysqlPasswordSchema.optional(), + databaseRootPassword: mysqlPasswordSchema.optional(), + memoryReservation: z.string().optional(), + memoryLimit: z.string().optional(), + cpuReservation: z.string().optional(), + cpuLimit: z.string().optional(), + externalPort: z.number().optional(), + applicationStatus: z.enum(["idle", "running", "done", "error"]).optional(), + environmentId: z.string().optional(), +}); -export const apiRebuildMysql = createSchema - .pick({ - mysqlId: true, - }) - .required(); +export const apiRebuildMysql = z.object({ + mysqlId: z.string().min(1), +}); diff --git a/packages/server/src/db/schema/notification.ts b/packages/server/src/db/schema/notification.ts index 686ba297b..df486097e 100644 --- a/packages/server/src/db/schema/notification.ts +++ b/packages/server/src/db/schema/notification.ts @@ -464,11 +464,9 @@ export const apiTestNtfyConnection = apiCreateNtfy.pick({ priority: true, }); -export const apiFindOneNotification = notificationsSchema - .pick({ - notificationId: true, - }) - .required(); +export const apiFindOneNotification = z.object({ + notificationId: z.string().min(1), +}); export const apiCreateCustom = notificationsSchema .pick({ diff --git a/packages/server/src/db/schema/patch.ts b/packages/server/src/db/schema/patch.ts index c4fc1abd2..a4bc1b32e 100644 --- a/packages/server/src/db/schema/patch.ts +++ b/packages/server/src/db/schema/patch.ts @@ -62,13 +62,13 @@ const createSchema = createInsertSchema(patch, { composeId: z.string().optional(), }); -export const apiCreatePatch = createSchema.pick({ - filePath: true, - content: true, - type: true, - enabled: true, - applicationId: true, - composeId: true, +export const apiCreatePatch = z.object({ + filePath: z.string().min(1), + content: z.string(), + type: z.enum(["create", "update", "delete"]).optional(), + enabled: z.boolean().optional(), + applicationId: z.string().optional(), + composeId: z.string().optional(), }); export const apiFindPatch = z.object({ @@ -83,12 +83,13 @@ export const apiFindPatchesByComposeId = z.object({ composeId: z.string().min(1), }); -export const apiUpdatePatch = createSchema - .partial() - .extend({ - patchId: z.string().min(1), - }) - .omit({ applicationId: true, composeId: true }); +export const apiUpdatePatch = z.object({ + patchId: z.string().min(1), + filePath: z.string().min(1).optional(), + content: z.string().optional(), + type: z.enum(["create", "update", "delete"]).optional(), + enabled: z.boolean().optional(), +}); export const apiDeletePatch = z.object({ patchId: z.string().min(1), diff --git a/packages/server/src/db/schema/port.ts b/packages/server/src/db/schema/port.ts index 30f79cc40..e5fe7d313 100644 --- a/packages/server/src/db/schema/port.ts +++ b/packages/server/src/db/schema/port.ts @@ -39,28 +39,22 @@ const createSchema = createInsertSchema(ports, { protocol: z.enum(["tcp", "udp"]).default("tcp"), }); -export const apiCreatePort = createSchema - .pick({ - publishedPort: true, - publishMode: true, - targetPort: true, - protocol: true, - applicationId: true, - }) - .required(); +export const apiCreatePort = z.object({ + publishedPort: z.number(), + publishMode: z.enum(["ingress", "host"]).default("ingress"), + targetPort: z.number(), + protocol: z.enum(["tcp", "udp"]).default("tcp"), + applicationId: z.string().min(1), +}); -export const apiFindOnePort = createSchema - .pick({ - portId: true, - }) - .required(); +export const apiFindOnePort = z.object({ + portId: z.string().min(1), +}); -export const apiUpdatePort = createSchema - .pick({ - portId: true, - publishedPort: true, - publishMode: true, - targetPort: true, - protocol: true, - }) - .required(); +export const apiUpdatePort = z.object({ + portId: z.string().min(1), + publishedPort: z.number(), + publishMode: z.enum(["ingress", "host"]), + targetPort: z.number(), + protocol: z.enum(["tcp", "udp"]), +}); diff --git a/packages/server/src/db/schema/postgres.ts b/packages/server/src/db/schema/postgres.ts index 1079976fa..8189be6e9 100644 --- a/packages/server/src/db/schema/postgres.ts +++ b/packages/server/src/db/schema/postgres.ts @@ -188,12 +188,26 @@ export const apiResetPostgres = createSchema }) .required(); -export const apiUpdatePostgres = createSchema - .partial() - .extend({ - postgresId: z.string().min(1), - }) - .omit({ serverId: true }); +export const apiUpdatePostgres = z.object({ + postgresId: z.string().min(1), + name: z.string().min(1).optional(), + appName: z.string().optional(), + description: z.string().optional(), + dockerImage: z.string().optional(), + command: z.string().optional(), + args: z.array(z.string()).optional(), + env: z.string().optional(), + databaseName: z.string().min(1).optional(), + databaseUser: z.string().min(1).optional(), + databasePassword: z.string().optional(), + memoryReservation: z.string().optional(), + memoryLimit: z.string().optional(), + cpuReservation: z.string().optional(), + cpuLimit: z.string().optional(), + externalPort: z.number().optional(), + applicationStatus: z.enum(["idle", "running", "done", "error"]).optional(), + environmentId: z.string().optional(), +}); export const apiRebuildPostgres = createSchema .pick({ diff --git a/packages/server/src/db/schema/preview-deployments.ts b/packages/server/src/db/schema/preview-deployments.ts index 3bdab2c25..3ce0f39d5 100644 --- a/packages/server/src/db/schema/preview-deployments.ts +++ b/packages/server/src/db/schema/preview-deployments.ts @@ -58,17 +58,12 @@ export const createSchema = createInsertSchema(previewDeployments, { applicationId: z.string(), }); -export const apiCreatePreviewDeployment = createSchema - .pick({ - applicationId: true, - domainId: true, - branch: true, - pullRequestId: true, - pullRequestNumber: true, - pullRequestURL: true, - pullRequestTitle: true, - }) - .extend({ - applicationId: z.string().min(1), - // deploymentId: z.string().min(1), - }); +export const apiCreatePreviewDeployment = z.object({ + applicationId: z.string().min(1), + domainId: z.string().optional(), + branch: z.string().min(1), + pullRequestId: z.string().min(1), + pullRequestNumber: z.string().min(1), + pullRequestURL: z.string().min(1), + pullRequestTitle: z.string().min(1), +}); diff --git a/packages/server/src/db/schema/project.ts b/packages/server/src/db/schema/project.ts index ba4859ad6..fb98d67fa 100644 --- a/packages/server/src/db/schema/project.ts +++ b/packages/server/src/db/schema/project.ts @@ -37,32 +37,23 @@ const createSchema = createInsertSchema(projects, { description: z.string().optional(), }); -export const apiCreateProject = createSchema.pick({ - name: true, - description: true, - env: true, +export const apiCreateProject = z.object({ + name: z.string().min(1), + description: z.string().optional(), + env: z.string(), }); export const apiFindOneProject = z.object({ projectId: z.string().min(1), }); -export const apiRemoveProject = createSchema - .pick({ - projectId: true, - }) - .required(); - -// export const apiUpdateProject = createSchema -// .pick({ -// name: true, -// description: true, -// projectId: true, -// env: true, -// }) -// .required(); - -export const apiUpdateProject = createSchema.partial().extend({ +export const apiRemoveProject = z.object({ projectId: z.string().min(1), }); -// .omit({ serverId: true }); + +export const apiUpdateProject = z.object({ + projectId: z.string().min(1), + name: z.string().min(1).optional(), + description: z.string().optional(), + env: z.string().optional(), +}); diff --git a/packages/server/src/db/schema/redirects.ts b/packages/server/src/db/schema/redirects.ts index 5b8e8eb22..6d14537d0 100644 --- a/packages/server/src/db/schema/redirects.ts +++ b/packages/server/src/db/schema/redirects.ts @@ -35,11 +35,9 @@ const createSchema = createInsertSchema(redirects, { permanent: z.boolean().optional(), }); -export const apiFindOneRedirect = createSchema - .pick({ - redirectId: true, - }) - .required(); +export const apiFindOneRedirect = z.object({ + redirectId: z.string().min(1), +}); export const apiCreateRedirect = createSchema .pick({ diff --git a/packages/server/src/db/schema/redis.ts b/packages/server/src/db/schema/redis.ts index e44ecff2a..044d22a48 100644 --- a/packages/server/src/db/schema/redis.ts +++ b/packages/server/src/db/schema/redis.ts @@ -174,12 +174,24 @@ export const apiResetRedis = createSchema }) .required(); -export const apiUpdateRedis = createSchema - .partial() - .extend({ - redisId: z.string().min(1), - }) - .omit({ serverId: true }); +export const apiUpdateRedis = z.object({ + redisId: z.string().min(1), + name: z.string().min(1).optional(), + appName: z.string().optional(), + description: z.string().optional(), + dockerImage: z.string().optional(), + command: z.string().optional(), + args: z.array(z.string()).optional(), + env: z.string().optional(), + databasePassword: z.string().optional(), + memoryReservation: z.string().optional(), + memoryLimit: z.string().optional(), + cpuReservation: z.string().optional(), + cpuLimit: z.string().optional(), + externalPort: z.number().optional(), + applicationStatus: z.enum(["idle", "running", "done", "error"]).optional(), + environmentId: z.string().optional(), +}); export const apiRebuildRedis = createSchema .pick({ diff --git a/packages/server/src/db/schema/registry.ts b/packages/server/src/db/schema/registry.ts index dd00bf19d..ee9ca662a 100644 --- a/packages/server/src/db/schema/registry.ts +++ b/packages/server/src/db/schema/registry.ts @@ -94,11 +94,9 @@ export const apiRemoveRegistry = createSchema }) .required(); -export const apiFindOneRegistry = createSchema - .pick({ - registryId: true, - }) - .required(); +export const apiFindOneRegistry = z.object({ + registryId: z.string().min(1), +}); export const apiUpdateRegistry = createSchema.partial().extend({ registryId: z.string().min(1), diff --git a/packages/server/src/db/schema/security.ts b/packages/server/src/db/schema/security.ts index 2223a3b29..3eaeed79c 100644 --- a/packages/server/src/db/schema/security.ts +++ b/packages/server/src/db/schema/security.ts @@ -38,24 +38,18 @@ const createSchema = createInsertSchema(security, { password: z.string().min(1), }); -export const apiFindOneSecurity = createSchema - .pick({ - securityId: true, - }) - .required(); +export const apiFindOneSecurity = z.object({ + securityId: z.string().min(1), +}); -export const apiCreateSecurity = createSchema - .pick({ - applicationId: true, - username: true, - password: true, - }) - .required(); +export const apiCreateSecurity = z.object({ + applicationId: z.string().min(1), + username: z.string().min(1), + password: z.string().min(1), +}); -export const apiUpdateSecurity = createSchema - .pick({ - securityId: true, - username: true, - password: true, - }) - .required(); +export const apiUpdateSecurity = z.object({ + securityId: z.string().min(1), + username: z.string().min(1), + password: z.string().min(1), +}); diff --git a/packages/server/src/db/schema/server.ts b/packages/server/src/db/schema/server.ts index b778b3f9a..10badd1e4 100644 --- a/packages/server/src/db/schema/server.ts +++ b/packages/server/src/db/schema/server.ts @@ -7,7 +7,6 @@ import { pgTable, text, } from "drizzle-orm/pg-core"; -import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { organization } from "./account"; @@ -129,82 +128,59 @@ export const serverRelations = relations(server, ({ one, many }) => ({ schedules: many(schedules), })); -const createSchema = createInsertSchema(server, { - serverId: z.string().min(1), +export const apiCreateServer = z.object({ name: z.string().min(1), description: z.string().optional(), - // Override pgEnums so Zod 4 infers only string literals, not numeric enum indices + ipAddress: z.string().min(1), + port: z.number(), + username: z.string().min(1), + sshKeyId: z.string().optional(), serverType: z.enum(["deploy", "build"]).optional(), - serverStatus: z.enum(["active", "inactive"]).optional(), }); -export const apiCreateServer = createSchema - .pick({ - name: true, - description: true, - ipAddress: true, - port: true, - username: true, - sshKeyId: true, - serverType: true, - }) - .required(); +export const apiFindOneServer = z.object({ + serverId: z.string().min(1), +}); -export const apiFindOneServer = createSchema - .pick({ - serverId: true, - }) - .required(); +export const apiRemoveServer = z.object({ + serverId: z.string().min(1), +}); -export const apiRemoveServer = createSchema - .pick({ - serverId: true, - }) - .required(); +export const apiUpdateServer = z.object({ + serverId: z.string().min(1), + name: z.string().min(1).optional(), + description: z.string().optional(), + ipAddress: z.string().min(1).optional(), + port: z.number().optional(), + username: z.string().min(1).optional(), + sshKeyId: z.string().optional(), + serverType: z.enum(["deploy", "build"]).optional(), + command: z.string().optional(), +}); -export const apiUpdateServer = createSchema - .pick({ - name: true, - description: true, - serverId: true, - ipAddress: true, - port: true, - username: true, - sshKeyId: true, - }) - .required() - .extend({ - serverType: z.enum(["deploy", "build"]), - command: z.string().optional(), - }); +const metricsConfigSchema = z.object({ + server: z.object({ + refreshRate: z.number().min(2), + port: z.number().min(1), + token: z.string(), + urlCallback: z.string().url(), + retentionDays: z.number().min(1), + cronJob: z.string().min(1), + thresholds: z.object({ + cpu: z.number().min(0), + memory: z.number().min(0), + }), + }), + containers: z.object({ + refreshRate: z.number().min(2), + services: z.object({ + include: z.array(z.string()).optional(), + exclude: z.array(z.string()).optional(), + }), + }), +}); -export const apiUpdateServerMonitoring = createSchema - .pick({ - serverId: true, - }) - .required() - .extend({ - metricsConfig: z - .object({ - server: z.object({ - refreshRate: z.number().min(2), - port: z.number().min(1), - token: z.string(), - urlCallback: z.string().url(), - retentionDays: z.number().min(1), - cronJob: z.string().min(1), - thresholds: z.object({ - cpu: z.number().min(0), - memory: z.number().min(0), - }), - }), - containers: z.object({ - refreshRate: z.number().min(2), - services: z.object({ - include: z.array(z.string()).optional(), - exclude: z.array(z.string()).optional(), - }), - }), - }) - .required(), - }); +export const apiUpdateServerMonitoring = z.object({ + serverId: z.string().min(1), + metricsConfig: metricsConfigSchema, +}); diff --git a/packages/server/src/db/schema/ssh-key.ts b/packages/server/src/db/schema/ssh-key.ts index 8a66d6d9d..35c1e1f96 100644 --- a/packages/server/src/db/schema/ssh-key.ts +++ b/packages/server/src/db/schema/ssh-key.ts @@ -1,7 +1,7 @@ import { relations } from "drizzle-orm"; import { pgTable, text } from "drizzle-orm/pg-core"; -import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; +import { z } from "zod"; import { sshKeyCreate, sshKeyType } from "../validations"; import { organization } from "./account"; import { applications } from "./application"; @@ -36,47 +36,28 @@ export const sshKeysRelations = relations(sshKeys, ({ many, one }) => ({ }), })); -const createSchema = createInsertSchema( - sshKeys, - /* Private key is not stored in the DB */ - sshKeyCreate.omit({ privateKey: true }).shape, -); +export const apiCreateSshKey = z + .object({ + name: z.string().min(1), + description: z.string().optional(), + organizationId: z.string().min(1), + publicKey: sshKeyCreate.shape.publicKey, + privateKey: sshKeyCreate.shape.privateKey, + }); -export const apiCreateSshKey = createSchema - .pick({ - name: true, - description: true, - privateKey: true, - publicKey: true, - organizationId: true, - }) - .merge(sshKeyCreate.pick({ privateKey: true })); - -export const apiFindOneSshKey = createSchema - .pick({ - sshKeyId: true, - }) - .required(); +export const apiFindOneSshKey = z.object({ + sshKeyId: z.string().min(1), +}); export const apiGenerateSSHKey = sshKeyType; -export const apiRemoveSshKey = createSchema - .pick({ - sshKeyId: true, - }) - .required(); +export const apiRemoveSshKey = z.object({ + sshKeyId: z.string().min(1), +}); -export const apiUpdateSshKey = createSchema - .pick({ - name: true, - description: true, - lastUsedAt: true, - }) - .partial() - .merge( - createSchema - .pick({ - sshKeyId: true, - }) - .required(), - ); +export const apiUpdateSshKey = z.object({ + sshKeyId: z.string().min(1), + name: z.string().optional(), + description: z.string().optional(), + lastUsedAt: z.string().optional(), +}); diff --git a/packages/server/src/db/schema/user.ts b/packages/server/src/db/schema/user.ts index 75e9ebf54..13a434194 100644 --- a/packages/server/src/db/schema/user.ts +++ b/packages/server/src/db/schema/user.ts @@ -7,7 +7,6 @@ import { text, timestamp, } from "drizzle-orm/pg-core"; -import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { account, apikey, organization } from "./account"; @@ -81,76 +80,41 @@ export const usersRelations = relations(user, ({ one, many }) => ({ schedules: many(schedules), })); -const createSchema = createInsertSchema(user, { - id: z.string().min(1), - isRegistered: z.boolean().optional(), -}).omit({ - role: true, - trustedOrigins: true, - isValidEnterpriseLicense: true, -}); - -export const apiCreateUserInvitation = createSchema.pick({}).extend({ +export const apiCreateUserInvitation = z.object({ email: z.string().email(), }); -export const apiRemoveUser = createSchema - .pick({ - id: true, - }) - .required(); +export const apiRemoveUser = z.object({ + id: z.string().min(1), +}); -export const apiFindOneToken = createSchema - .pick({}) - .required() - .extend({ - token: z.string().min(1), - }); +export const apiFindOneToken = z.object({ + token: z.string().min(1), +}); -export const apiAssignPermissions = createSchema - .pick({ - id: true, - // canCreateProjects: true, - // canCreateServices: true, - // canDeleteProjects: true, - // canDeleteServices: true, - // accessedProjects: true, - // accessedServices: true, - // canAccessToTraefikFiles: true, - // canAccessToDocker: true, - // canAccessToAPI: true, - // canAccessToSSHKeys: true, - // canAccessToGitProviders: true, - }) - .extend({ - accessedProjects: z.array(z.string()).optional(), - accessedEnvironments: z.array(z.string()).optional(), - accessedServices: z.array(z.string()).optional(), - canCreateProjects: z.boolean().optional(), - canCreateServices: z.boolean().optional(), - canDeleteProjects: z.boolean().optional(), - canDeleteServices: z.boolean().optional(), - canAccessToDocker: z.boolean().optional(), - canAccessToTraefikFiles: z.boolean().optional(), - canAccessToAPI: z.boolean().optional(), - canAccessToSSHKeys: z.boolean().optional(), - canAccessToGitProviders: z.boolean().optional(), - canDeleteEnvironments: z.boolean().optional(), - canCreateEnvironments: z.boolean().optional(), - }) - .required(); +export const apiAssignPermissions = z.object({ + id: z.string().min(1), + accessedProjects: z.array(z.string()).optional(), + accessedEnvironments: z.array(z.string()).optional(), + accessedServices: z.array(z.string()).optional(), + canCreateProjects: z.boolean().optional(), + canCreateServices: z.boolean().optional(), + canDeleteProjects: z.boolean().optional(), + canDeleteServices: z.boolean().optional(), + canAccessToDocker: z.boolean().optional(), + canAccessToTraefikFiles: z.boolean().optional(), + canAccessToAPI: z.boolean().optional(), + canAccessToSSHKeys: z.boolean().optional(), + canAccessToGitProviders: z.boolean().optional(), + canDeleteEnvironments: z.boolean().optional(), + canCreateEnvironments: z.boolean().optional(), +}); -export const apiFindOneUser = createSchema - .pick({ - id: true, - }) - .required(); +export const apiFindOneUser = z.object({ + id: z.string().min(1), +}); -export const apiFindOneUserByAuth = createSchema - .pick({ - // authId: true, - }) - .required(); +export const apiFindOneUserByAuth = z.object({}); export const apiTraefikConfig = z.object({ traefikConfig: z.string().min(1), @@ -219,7 +183,7 @@ export const apiReadStatsLogs = z.object({ .optional(), }); -export const apiUpdateUser = createSchema.partial().extend({ +export const apiUpdateUser = z.object({ email: z .string() .email("Please enter a valid email address") diff --git a/packages/server/src/db/schema/volume-backups.ts b/packages/server/src/db/schema/volume-backups.ts index 0c6520069..8858daabe 100644 --- a/packages/server/src/db/schema/volume-backups.ts +++ b/packages/server/src/db/schema/volume-backups.ts @@ -1,6 +1,5 @@ import { relations } from "drizzle-orm"; import { boolean, integer, pgTable, text } from "drizzle-orm/pg-core"; -import { createInsertSchema } from "drizzle-zod"; import { nanoid } from "nanoid"; import { z } from "zod"; import { applications } from "./application"; @@ -105,12 +104,45 @@ export const volumeBackupsRelations = relations( }), ); -export const createVolumeBackupSchema = createInsertSchema(volumeBackups).omit({ - volumeBackupId: true, +const serviceTypeEnum = z.enum([ + "application", + "postgres", + "mysql", + "mariadb", + "mongo", + "redis", + "compose", +]); + +export const createVolumeBackupSchema = z.object({ + name: z.string().min(1), + volumeName: z.string().min(1), + prefix: z.string().min(1), + serviceType: serviceTypeEnum.default("application"), + appName: z.string().min(1).optional(), + serviceName: z.string().optional(), + turnOff: z.boolean().default(false), + cronExpression: z.string().min(1), + keepLatestCount: z.number().optional(), + enabled: z.boolean().optional(), + applicationId: z.string().optional(), + postgresId: z.string().optional(), + mariadbId: z.string().optional(), + mongoId: z.string().optional(), + mysqlId: z.string().optional(), + redisId: z.string().optional(), + composeId: z.string().optional(), + destinationId: z.string().min(1), }); -export const updateVolumeBackupSchema = createVolumeBackupSchema.extend({ +export const updateVolumeBackupSchema = z.object({ volumeBackupId: z.string().min(1), + name: z.string().min(1).optional(), + destinationId: z.string().optional(), + cronExpression: z.string().optional(), + keepLatestCount: z.number().optional(), + enabled: z.boolean().optional(), + turnOff: z.boolean().optional(), }); export const apiFindOneVolumeBackup = z.object({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 02166bb0f..1436d3311 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -135,8 +135,8 @@ importers: specifier: workspace:* version: link:../../packages/server '@dokploy/trpc-openapi': - specifier: 0.0.13 - version: 0.0.13(@trpc/server@11.10.0(typescript@5.9.3))(zod-openapi@5.4.6(zod@4.3.6))(zod@4.3.6) + specifier: 0.0.14 + version: 0.0.14(@trpc/server@11.10.0(typescript@5.9.3))(zod-openapi@5.4.6(zod@4.3.6))(zod@4.3.6) '@faker-js/faker': specifier: ^8.4.1 version: 8.4.1 @@ -408,7 +408,7 @@ importers: specifier: ^2.2.2 version: 2.2.6 swagger-ui-react: - specifier: ^5.31.1 + specifier: ^5.31.2 version: 5.31.2(@types/react@18.3.5)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) tailwind-merge: specifier: ^2.6.0 @@ -1282,11 +1282,11 @@ packages: '@codemirror/view@6.39.15': resolution: {integrity: sha512-aCWjgweIIXLBHh7bY6cACvXuyrZ0xGafjQ2VInjp4RM4gMfscK5uESiNdrH0pE+e1lZr2B4ONGsjchl2KsKZzg==} - '@dokploy/trpc-openapi@0.0.13': - resolution: {integrity: sha512-oDQtYgQUGHy3u6NNzeaM1nSY34/bEhpmxKHups+0XkSbdTmfcA3lioaffTWX6cCgqMX+/pK5oO747Rn8pHOOVg==} + '@dokploy/trpc-openapi@0.0.14': + resolution: {integrity: sha512-Kg5XIObHWk2v8PeHJcD0l9AJk8iukpYiUVvcaLgITylWGokkMGmyupfr1FZY/U3DZtBfmIsGKtP41dVOQ9XD9A==} peerDependencies: '@trpc/server': ^11.1.0 - zod: ^4.0.0 + zod: ^4.3.6 zod-openapi: ^5.0.1 '@drizzle-team/brocli@0.10.2': @@ -8802,7 +8802,7 @@ snapshots: style-mod: 4.1.3 w3c-keyname: 2.2.8 - '@dokploy/trpc-openapi@0.0.13(@trpc/server@11.10.0(typescript@5.9.3))(zod-openapi@5.4.6(zod@4.3.6))(zod@4.3.6)': + '@dokploy/trpc-openapi@0.0.14(@trpc/server@11.10.0(typescript@5.9.3))(zod-openapi@5.4.6(zod@4.3.6))(zod@4.3.6)': dependencies: '@trpc/server': 11.10.0(typescript@5.9.3) co-body: 6.2.0