Merge branch 'canary' into feat/domain-enable-disable

This commit is contained in:
Narciso
2026-08-10 22:38:27 -04:00
375 changed files with 112830 additions and 27203 deletions
+32
View File
@@ -8,6 +8,7 @@ import {
timestamp,
} from "drizzle-orm/pg-core";
import { nanoid } from "nanoid";
import { network } from "./network";
import { projects } from "./project";
import { server } from "./server";
import { ssoProvider } from "./sso";
@@ -108,6 +109,7 @@ export const organizationRelations = relations(
references: [user.id],
}),
servers: many(server),
networks: many(network),
projects: many(projects),
members: many(member),
ssoProviders: many(ssoProvider),
@@ -221,6 +223,36 @@ export const twoFactor = pgTable("two_factor", {
lockedUntil: timestamp("locked_until"),
});
export const passkey = pgTable(
"passkey",
{
id: text("id").primaryKey(),
name: text("name"),
publicKey: text("public_key").notNull(),
userId: text("user_id")
.notNull()
.references(() => user.id, { onDelete: "cascade" }),
credentialID: text("credential_id").notNull(),
counter: integer("counter").notNull(),
deviceType: text("device_type").notNull(),
backedUp: boolean("backed_up").notNull(),
transports: text("transports"),
createdAt: timestamp("created_at"),
aaguid: text("aaguid"),
},
(table) => [
index("passkey_userId_idx").on(table.userId),
index("passkey_credentialID_idx").on(table.credentialID),
],
);
export const passkeyRelations = relations(passkey, ({ one }) => ({
user: one(user, {
fields: [passkey.userId],
references: [user.id],
}),
}));
export const apikey = pgTable("apikey", {
id: text("id").primaryKey(),
name: text("name"),
+9
View File
@@ -54,6 +54,15 @@ export const apiUpdateAi = createSchema
})
.omit({ organizationId: true });
export const aiCustomProviderSchema = z.object({
name: z.string().min(1, { message: "Name is required" }),
apiUrl: z.string().url({ message: "Please enter a valid URL" }),
});
export const apiSaveAiCustomProviders = z.object({
providers: z.array(aiCustomProviderSchema),
});
export const deploySuggestionSchema = z.object({
environmentId: z.string().min(1),
id: z.string().min(1),
@@ -233,6 +233,10 @@ export const applications = pgTable("application", {
onDelete: "set null",
},
),
networkIds: text("networkIds").array().default([]),
detachDokployNetwork: boolean("detachDokployNetwork")
.notNull()
.default(false),
});
export const applicationsRelations = relations(
@@ -374,6 +378,8 @@ const createSchema = createInsertSchema(applications, {
previewRequireCollaboratorPermissions: z.boolean().optional(),
watchPaths: z.array(z.string()).optional().optional(),
previewLabels: z.array(z.string()).optional(),
networkIds: z.array(z.string()).optional(),
detachDokployNetwork: z.boolean().optional(),
cleanCache: z.boolean().optional(),
stopGracePeriodSwarm: z.number().nullable(),
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
+3 -1
View File
@@ -91,4 +91,6 @@ export type AuditResourceType =
| "cluster"
| "mount"
| "application"
| "compose";
| "compose"
| "network"
| "vaultProvider";
+38 -2
View File
@@ -1,5 +1,12 @@
import { relations } from "drizzle-orm";
import { boolean, integer, pgEnum, pgTable, text } from "drizzle-orm/pg-core";
import {
boolean,
integer,
jsonb,
pgEnum,
pgTable,
text,
} from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
@@ -80,6 +87,7 @@ export const compose = pgTable("compose", {
),
command: text("command").notNull().default(""),
//
createEnvFile: boolean("createEnvFile").notNull().default(true),
enableSubmodules: boolean("enableSubmodules").notNull().default(false),
composePath: text("composePath").notNull().default("./docker-compose.yml"),
suffix: text("suffix").notNull().default(""),
@@ -91,6 +99,7 @@ export const compose = pgTable("compose", {
.default(false),
triggerType: triggerType("triggerType").default("push"),
composeStatus: applicationStatus("composeStatus").notNull().default("idle"),
icon: text("icon"),
environmentId: text("environmentId")
.notNull()
.references(() => environments.environmentId, { onDelete: "cascade" }),
@@ -113,6 +122,15 @@ export const compose = pgTable("compose", {
serverId: text("serverId").references(() => server.serverId, {
onDelete: "cascade",
}),
serviceNetworks: jsonb("serviceNetworks")
.$type<
Array<{
serviceName: string;
networkIds: string[];
detachDokployNetwork: boolean;
}>
>()
.default([]),
});
export const composeRelations = relations(compose, ({ one, many }) => ({
@@ -166,6 +184,7 @@ const createSchema = createInsertSchema(compose, {
environmentId: z.string(),
customGitSSHKeyId: z.string().optional(),
command: z.string().optional(),
createEnvFile: z.boolean().optional(),
composePath: z.string().min(1),
composeType: z.enum(["docker-compose", "stack"]).optional(),
watchPaths: z.array(z.string()).optional(),
@@ -174,6 +193,20 @@ const createSchema = createInsertSchema(compose, {
.optional(),
triggerType: z.enum(["push", "tag"]).optional(),
composeStatus: z.enum(["idle", "running", "done", "error"]).optional(),
icon: z
.string()
.max(2 * 1024 * 1024, "Icon must be less than 2MB")
.nullable()
.optional(),
serviceNetworks: z
.array(
z.object({
serviceName: z.string(),
networkIds: z.array(z.string()),
detachDokployNetwork: z.boolean(),
}),
)
.optional(),
});
export const apiCreateCompose = createSchema.pick({
@@ -235,7 +268,10 @@ export const apiSaveEnvironmentVariablesCompose = createSchema
composeId: true,
env: true,
})
.required();
.required()
.extend({
createEnvFile: z.boolean().optional(),
});
export const apiRandomizeCompose = createSchema
.pick({
+5
View File
@@ -16,6 +16,7 @@ export const github = pgTable("github", {
githubInstallationId: text("githubInstallationId"),
githubPrivateKey: text("githubPrivateKey"),
githubWebhookSecret: text("githubWebhookSecret"),
githubUrl: text("githubUrl").default("https://github.com").notNull(),
gitProviderId: text("gitProviderId")
.notNull()
.references(() => gitProvider.gitProviderId, { onDelete: "cascade" }),
@@ -36,6 +37,10 @@ export const apiCreateGithub = z.object({
githubInstallationId: z.string().optional(),
githubPrivateKey: z.string().optional(),
githubWebhookSecret: z.string().nullable(),
githubUrl: z
.url()
.startsWith("https://", "Only https is supported for GitHub instances")
.optional(),
gitProviderId: z.string().optional(),
name: z.string().min(1),
});
+2
View File
@@ -20,6 +20,7 @@ export * from "./mariadb";
export * from "./mongo";
export * from "./mount";
export * from "./mysql";
export * from "./network";
export * from "./notification";
export * from "./patch";
export * from "./port";
@@ -41,5 +42,6 @@ export * from "./sso";
export * from "./tag";
export * from "./user";
export * from "./utils";
export * from "./vault-provider";
export * from "./volume-backups";
export * from "./web-server-settings";
+6
View File
@@ -83,6 +83,10 @@ export const libsql = pgTable("libsql", {
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "number" }),
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
replicas: integer("replicas").default(1).notNull(),
networkIds: text("networkIds").array().default([]),
detachDokployNetwork: boolean("detachDokployNetwork")
.notNull()
.default(false),
createdAt: text("createdAt")
.notNull()
.$defaultFn(() => new Date().toISOString()),
@@ -146,6 +150,8 @@ const createSchema = createInsertSchema(libsql, {
networkSwarm: NetworkSwarmSchema.nullable(),
stopGracePeriodSwarm: z.number().nullable(),
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
networkIds: z.array(z.string()).optional(),
detachDokployNetwork: z.boolean().optional(),
});
export const apiCreateLibsql = createSchema
+14 -1
View File
@@ -1,5 +1,12 @@
import { relations } from "drizzle-orm";
import { bigint, integer, json, pgTable, text } from "drizzle-orm/pg-core";
import {
bigint,
boolean,
integer,
json,
pgTable,
text,
} from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
@@ -88,6 +95,10 @@ export const mariadb = pgTable("mariadb", {
serverId: text("serverId").references(() => server.serverId, {
onDelete: "cascade",
}),
networkIds: text("networkIds").array().default([]),
detachDokployNetwork: boolean("detachDokployNetwork")
.notNull()
.default(false),
});
export const mariadbRelations = relations(mariadb, ({ one, many }) => ({
@@ -148,6 +159,8 @@ const createSchema = createInsertSchema(mariadb, {
stopGracePeriodSwarm: z.number().nullable(),
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
ulimitsSwarm: UlimitsSwarmSchema.nullable(),
networkIds: z.array(z.string()).optional(),
detachDokployNetwork: z.boolean().optional(),
});
export const apiCreateMariaDB = createSchema.pick({
+6
View File
@@ -92,6 +92,10 @@ export const mongo = pgTable("mongo", {
onDelete: "cascade",
}),
replicaSets: boolean("replicaSets").default(false),
networkIds: text("networkIds").array().default([]),
detachDokployNetwork: boolean("detachDokployNetwork")
.notNull()
.default(false),
});
export const mongoRelations = relations(mongo, ({ one, many }) => ({
@@ -146,6 +150,8 @@ const createSchema = createInsertSchema(mongo, {
stopGracePeriodSwarm: z.number().nullable(),
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
ulimitsSwarm: UlimitsSwarmSchema.nullable(),
networkIds: z.array(z.string()).optional(),
detachDokployNetwork: z.boolean().optional(),
});
export const apiCreateMongo = createSchema.pick({
+14 -1
View File
@@ -1,5 +1,12 @@
import { relations } from "drizzle-orm";
import { bigint, integer, json, pgTable, text } from "drizzle-orm/pg-core";
import {
bigint,
boolean,
integer,
json,
pgTable,
text,
} from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
@@ -86,6 +93,10 @@ export const mysql = pgTable("mysql", {
serverId: text("serverId").references(() => server.serverId, {
onDelete: "cascade",
}),
networkIds: text("networkIds").array().default([]),
detachDokployNetwork: boolean("detachDokployNetwork")
.notNull()
.default(false),
});
export const mysqlRelations = relations(mysql, ({ one, many }) => ({
@@ -145,6 +156,8 @@ const createSchema = createInsertSchema(mysql, {
stopGracePeriodSwarm: z.number().nullable(),
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
ulimitsSwarm: UlimitsSwarmSchema.nullable(),
networkIds: z.array(z.string()).optional(),
detachDokployNetwork: z.boolean().optional(),
});
export const apiCreateMySql = createSchema.pick({
+135
View File
@@ -0,0 +1,135 @@
import { relations } from "drizzle-orm";
import {
boolean,
integer,
jsonb,
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";
import { server } from "./server";
export const networkDriver = pgEnum("networkDriver", ["bridge", "overlay"]);
export const network = pgTable("network", {
networkId: text("networkId")
.notNull()
.primaryKey()
.$defaultFn(() => nanoid()),
name: text("name").notNull(),
driver: networkDriver("driver").notNull().default("bridge"),
internal: boolean("internal").notNull().default(false),
attachable: boolean("attachable").notNull().default(false),
enableIPv4: boolean("enableIPv4").notNull().default(true),
enableIPv6: boolean("enableIPv6").notNull().default(false),
mtu: integer("mtu"),
ipam: jsonb("ipam")
.$type<{
driver?: string;
config?: Array<{ subnet?: string; gateway?: string; ipRange?: string }>;
}>()
.default({}),
createdAt: text("createdAt")
.notNull()
.$defaultFn(() => new Date().toISOString()),
organizationId: text("organizationId")
.notNull()
.references(() => organization.id, { onDelete: "cascade" }),
serverId: text("serverId").references(() => server.serverId, {
onDelete: "cascade",
}),
});
export const networkRelations = relations(network, ({ one }) => ({
organization: one(organization, {
fields: [network.organizationId],
references: [organization.id],
}),
server: one(server, {
fields: [network.serverId],
references: [server.serverId],
}),
}));
const createSchema = createInsertSchema(network, {
networkId: z.string().min(1),
name: z.string().min(1),
driver: z.enum(["bridge", "overlay"]).optional(),
internal: z.boolean().optional(),
attachable: z.boolean().optional(),
enableIPv4: z.boolean().optional(),
enableIPv6: z.boolean().optional(),
mtu: z.number().int().min(68).max(65535).optional().nullable(),
ipam: z
.object({
driver: z.string().optional(),
config: z
.array(
z.object({
subnet: z.string().optional(),
gateway: z.string().optional(),
ipRange: z.string().optional(),
}),
)
.optional(),
})
.optional(),
organizationId: z.string().min(1),
serverId: z.string().optional().nullable(),
});
const validateNetworkInput = (
input: {
enableIPv4?: boolean;
enableIPv6?: boolean;
ipam?: {
config?: Array<{ subnet?: string; gateway?: string; ipRange?: string }>;
} | null;
},
ctx: z.RefinementCtx,
) => {
if (input.enableIPv4 === false && input.enableIPv6 !== true) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["enableIPv4"],
message: "IPv4 or IPv6 must be enabled",
});
}
for (const [index, entry] of (input.ipam?.config ?? []).entries()) {
if (!entry.subnet && (entry.gateway || entry.ipRange)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ["ipam", "config", index, "subnet"],
message: "Gateway and IP range require a subnet",
});
}
}
};
export const apiCreateNetwork = createSchema
.pick({
name: true,
driver: true,
internal: true,
attachable: true,
enableIPv4: true,
enableIPv6: true,
mtu: true,
ipam: true,
serverId: true,
})
.partial()
.required({ name: true })
.superRefine(validateNetworkInput);
export const apiFindOneNetwork = z.object({
networkId: z.string().min(1),
});
export const apiRemoveNetwork = z.object({
networkId: z.string().min(1),
});
+14 -1
View File
@@ -1,5 +1,12 @@
import { relations } from "drizzle-orm";
import { bigint, integer, json, pgTable, text } from "drizzle-orm/pg-core";
import {
bigint,
boolean,
integer,
json,
pgTable,
text,
} from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
@@ -86,6 +93,10 @@ export const postgres = pgTable("postgres", {
serverId: text("serverId").references(() => server.serverId, {
onDelete: "cascade",
}),
networkIds: text("networkIds").array().default([]),
detachDokployNetwork: boolean("detachDokployNetwork")
.notNull()
.default(false),
});
export const postgresRelations = relations(postgres, ({ one, many }) => ({
@@ -140,6 +151,8 @@ const createSchema = createInsertSchema(postgres, {
stopGracePeriodSwarm: z.number().nullable(),
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
ulimitsSwarm: UlimitsSwarmSchema.nullable(),
networkIds: z.array(z.string()).optional(),
detachDokployNetwork: z.boolean().optional(),
});
export const apiCreatePostgres = createSchema.pick({
+14 -1
View File
@@ -1,5 +1,12 @@
import { relations } from "drizzle-orm";
import { bigint, integer, json, pgTable, text } from "drizzle-orm/pg-core";
import {
bigint,
boolean,
integer,
json,
pgTable,
text,
} from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
@@ -80,6 +87,10 @@ export const redis = pgTable("redis", {
serverId: text("serverId").references(() => server.serverId, {
onDelete: "cascade",
}),
networkIds: text("networkIds").array().default([]),
detachDokployNetwork: boolean("detachDokployNetwork")
.notNull()
.default(false),
});
export const redisRelations = relations(redis, ({ one, many }) => ({
@@ -129,6 +140,8 @@ const createSchema = createInsertSchema(redis, {
stopGracePeriodSwarm: z.number().nullable(),
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
ulimitsSwarm: UlimitsSwarmSchema.nullable(),
networkIds: z.array(z.string()).optional(),
detachDokployNetwork: z.boolean().optional(),
});
export const apiCreateRedis = createSchema.pick({
+2 -1
View File
@@ -1,4 +1,5 @@
import type { Application } from "@dokploy/server/services/application";
import type { Environment } from "@dokploy/server/services/environment";
import type { Mount } from "@dokploy/server/services/mount";
import type { Port } from "@dokploy/server/services/port";
import type { Project } from "@dokploy/server/services/project";
@@ -27,7 +28,7 @@ export const rollbacks = pgTable("rollback", {
.$defaultFn(() => new Date().toISOString()),
fullContext: jsonb("fullContext").$type<
Application & {
environment: {
environment: Environment & {
project: Project;
};
mounts: Mount[];
+4 -1
View File
@@ -57,6 +57,7 @@ export const schedules = pgTable("schedule", {
});
export type Schedule = typeof schedules.$inferSelect;
export type ScheduleType = Schedule["scheduleType"];
export const schedulesRelations = relations(schedules, ({ one, many }) => ({
application: one(applications, {
@@ -78,7 +79,9 @@ export const schedulesRelations = relations(schedules, ({ one, many }) => ({
deployments: many(deployments),
}));
export const createScheduleSchema = createInsertSchema(schedules);
export const createScheduleSchema = createInsertSchema(schedules, {
scheduleType: z.enum(["application", "compose", "server", "dokploy-server"]),
});
export const updateScheduleSchema = createScheduleSchema.extend({
scheduleId: z.string().min(1),
+2
View File
@@ -19,6 +19,7 @@ import { libsql } from "./libsql";
import { mariadb } from "./mariadb";
import { mongo } from "./mongo";
import { mysql } from "./mysql";
import { network } from "./network";
import { postgres } from "./postgres";
import { redis } from "./redis";
import { schedules } from "./schedule";
@@ -125,6 +126,7 @@ export const serverRelations = relations(server, ({ one, many }) => ({
mysql: many(mysql),
postgres: many(postgres),
certificates: many(certificates),
networks: many(network),
organization: one(organization, {
fields: [server.organizationId],
references: [organization.id],
+6
View File
@@ -41,6 +41,12 @@ export const APP_NAME_REGEX = /^[a-zA-Z0-9._-]+$/;
export const APP_NAME_MESSAGE =
"App name can only contain letters, numbers, dots, underscores and hyphens";
/** Docker volume name: must start alphanumeric, then letters/numbers/._- only. Safe for shell. */
export const VOLUME_NAME_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/;
export const VOLUME_NAME_MESSAGE =
"Volume name must start with a letter or number and contain only letters, numbers, dots, underscores and hyphens";
/** Database password: blocks shell-dangerous characters like $ ! ' " \ / and spaces. */
export const DATABASE_PASSWORD_REGEX =
/^[a-zA-Z0-9@#%^&*()_+\-=[\]{}|;:,.<>?~`]*$/;
@@ -0,0 +1,145 @@
import { jsonb, pgEnum, pgTable, text, uniqueIndex } from "drizzle-orm/pg-core";
import { createInsertSchema } from "drizzle-zod";
import { nanoid } from "nanoid";
import { z } from "zod";
import { organization } from "./account";
export const vaultProviderType = pgEnum("VaultProviderType", [
"hashicorp",
"infisical",
"aws",
"doppler",
"azure",
]);
export const hashicorpVaultConfigSchema = z.object({
providerType: z.literal("hashicorp"),
url: z.string().url(),
token: z.string().min(1),
namespace: z.string().optional(),
mount: z.string().min(1).default("secret"),
});
export const infisicalVaultConfigSchema = z.object({
providerType: z.literal("infisical"),
siteUrl: z.string().url().default("https://app.infisical.com"),
clientId: z.string().min(1),
clientSecret: z.string().min(1),
projectId: z.string().min(1),
environmentSlug: z.string().min(1),
secretPath: z.string().default("/"),
});
export const awsVaultConfigSchema = z.object({
providerType: z.literal("aws"),
region: z.string().min(1),
accessKeyId: z.string().min(1),
secretAccessKey: z.string().min(1),
endpoint: z.string().url().optional(),
});
export const dopplerVaultConfigSchema = z.object({
providerType: z.literal("doppler"),
serviceToken: z.string().min(1),
project: z.string().optional(),
config: z.string().optional(),
});
export const azureVaultConfigSchema = z.object({
providerType: z.literal("azure"),
vaultUri: z.string().url(),
tenantId: z.string().min(1),
clientId: z.string().min(1),
clientSecret: z.string().min(1),
});
export const vaultProviderConfigSchema = z.discriminatedUnion("providerType", [
hashicorpVaultConfigSchema,
infisicalVaultConfigSchema,
awsVaultConfigSchema,
dopplerVaultConfigSchema,
azureVaultConfigSchema,
]);
export type VaultProviderConfig = z.infer<typeof vaultProviderConfigSchema>;
export const vaultProviderAssignmentSchema = z.object({
projectId: z.string().min(1),
environmentIds: z.array(z.string().min(1)).default([]),
});
export type VaultProviderAssignment = z.infer<
typeof vaultProviderAssignmentSchema
>;
export const vaultProvider = pgTable(
"vault_provider",
{
vaultProviderId: text("vaultProviderId")
.notNull()
.primaryKey()
.$defaultFn(() => nanoid()),
name: text("name").notNull(),
providerType: vaultProviderType("providerType").notNull(),
config: jsonb("config").$type<VaultProviderConfig>().notNull(),
assignments: jsonb("assignments")
.$type<VaultProviderAssignment[]>()
.notNull()
.default([]),
organizationId: text("organizationId")
.notNull()
.references(() => organization.id, { onDelete: "cascade" }),
createdAt: text("createdAt")
.notNull()
.$defaultFn(() => new Date().toISOString()),
},
(table) => [
uniqueIndex("vault_provider_org_name_idx").on(
table.organizationId,
table.name,
),
],
);
const vaultProviderNameSchema = z
.string()
.min(1)
.max(64)
.regex(
/^[a-zA-Z0-9_-]+$/,
"Name can only contain letters, numbers, dashes and underscores",
);
const createSchema = createInsertSchema(vaultProvider);
export const apiCreateVaultProvider = createSchema.pick({}).extend({
name: vaultProviderNameSchema,
config: vaultProviderConfigSchema,
assignments: z.array(vaultProviderAssignmentSchema),
});
export const apiUpdateVaultProvider = createSchema.pick({}).extend({
vaultProviderId: z.string().min(1),
name: vaultProviderNameSchema,
config: vaultProviderConfigSchema,
assignments: z.array(vaultProviderAssignmentSchema),
});
export const apiFindOneVaultProvider = z.object({
vaultProviderId: z.string().min(1),
});
export const apiRemoveVaultProvider = z.object({
vaultProviderId: z.string().min(1),
});
export const apiTestVaultProvider = z.object({
vaultProviderId: z.string().min(1).optional(),
config: vaultProviderConfigSchema.optional(),
});
export const apiListVaultSecretNames = z.object({
vaultProviderId: z.string().min(1),
projectId: z.string().min(1),
environmentId: z.string().optional(),
});
@@ -14,7 +14,11 @@ import { serviceType } from "./mount";
import { mysql } from "./mysql";
import { postgres } from "./postgres";
import { redis } from "./redis";
import { generateAppName } from "./utils";
import {
generateAppName,
VOLUME_NAME_MESSAGE,
VOLUME_NAME_REGEX,
} from "./utils";
export const volumeBackups = pgTable("volume_backup", {
volumeBackupId: text("volumeBackupId")
@@ -113,7 +117,9 @@ export const volumeBackupsRelations = relations(
}),
);
export const createVolumeBackupSchema = createInsertSchema(volumeBackups).omit({
export const createVolumeBackupSchema = createInsertSchema(volumeBackups, {
volumeName: z.string().regex(VOLUME_NAME_REGEX, VOLUME_NAME_MESSAGE),
}).omit({
volumeBackupId: true,
});