mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-27 10:05:32 +02:00
Merge branch 'canary' into feat/add-mattermost-notification-provider
Resolves merge conflicts between mattermost notification provider (this PR) and new canary features (resend, teams, SSO, patches, etc). All notification providers are now included: - slack, telegram, discord, email, gotify, ntfy - mattermost (this PR) - resend, pushover, custom, lark, teams (from canary)
This commit is contained in:
@@ -26,7 +26,8 @@ if (DATABASE_URL) {
|
||||
password,
|
||||
)}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}`;
|
||||
} else {
|
||||
console.warn(`
|
||||
if (process.env.NODE_ENV !== "test") {
|
||||
console.warn(`
|
||||
⚠️ [DEPRECATED DATABASE CONFIG]
|
||||
You are using the legacy hardcoded database credentials.
|
||||
This mode WILL BE REMOVED in a future release.
|
||||
@@ -34,6 +35,13 @@ if (DATABASE_URL) {
|
||||
Please migrate to Docker Secrets using POSTGRES_PASSWORD_FILE.
|
||||
Please execute this command in your server: curl -sSL https://dokploy.com/security/0.26.6.sh | bash
|
||||
`);
|
||||
dbUrl =
|
||||
"postgres://dokploy:amukds4wi9001583845717ad2@dokploy-postgres:5432/dokploy";
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
dbUrl =
|
||||
"postgres://dokploy:amukds4wi9001583845717ad2@dokploy-postgres:5432/dokploy";
|
||||
} else {
|
||||
dbUrl =
|
||||
"postgres://dokploy:amukds4wi9001583845717ad2@localhost:5432/dokploy";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,40 @@
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import { drizzle, type PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
||||
import postgres from "postgres";
|
||||
import { dbUrl } from "./constants";
|
||||
import * as schema from "./schema";
|
||||
|
||||
declare global {
|
||||
var db: PostgresJsDatabase<typeof schema> | undefined;
|
||||
}
|
||||
export { and, eq };
|
||||
export * from "./schema";
|
||||
|
||||
type Database = PostgresJsDatabase<typeof schema>;
|
||||
|
||||
/**
|
||||
* Evita problemas de redeclaración global en monorepos.
|
||||
* No usamos `declare global`.
|
||||
*/
|
||||
const globalForDb = globalThis as unknown as {
|
||||
db?: Database;
|
||||
};
|
||||
|
||||
let dbConnection: Database;
|
||||
|
||||
export let db: PostgresJsDatabase<typeof schema>;
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
db = drizzle(postgres(dbUrl), {
|
||||
// En producción no usamos global cache
|
||||
dbConnection = drizzle(postgres(dbUrl), {
|
||||
schema,
|
||||
});
|
||||
} else {
|
||||
if (!global.db)
|
||||
global.db = drizzle(postgres(dbUrl), {
|
||||
// En desarrollo reutilizamos conexión para evitar múltiples conexiones
|
||||
if (!globalForDb.db) {
|
||||
globalForDb.db = drizzle(postgres(dbUrl), {
|
||||
schema,
|
||||
});
|
||||
}
|
||||
|
||||
db = global.db;
|
||||
dbConnection = globalForDb.db;
|
||||
}
|
||||
|
||||
export const db: Database = dbConnection;
|
||||
|
||||
export { dbUrl };
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
import { nanoid } from "nanoid";
|
||||
import { projects } from "./project";
|
||||
import { server } from "./server";
|
||||
import { ssoProvider } from "./sso";
|
||||
import { user } from "./user";
|
||||
|
||||
export const account = pgTable("account", {
|
||||
@@ -78,6 +79,7 @@ export const organizationRelations = relations(
|
||||
servers: many(server),
|
||||
projects: many(projects),
|
||||
members: many(member),
|
||||
ssoProviders: many(ssoProvider),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -153,6 +155,7 @@ export const invitation = pgTable("invitation", {
|
||||
.notNull()
|
||||
.references(() => user.id, { onDelete: "cascade" }),
|
||||
teamId: text("team_id"),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
});
|
||||
|
||||
export const invitationRelations = relations(invitation, ({ one }) => ({
|
||||
|
||||
@@ -19,6 +19,7 @@ import { gitea } from "./gitea";
|
||||
import { github } from "./github";
|
||||
import { gitlab } from "./gitlab";
|
||||
import { mounts } from "./mount";
|
||||
import { patch } from "./patch";
|
||||
import { ports } from "./port";
|
||||
import { previewDeployments } from "./preview-deployments";
|
||||
import { redirects } from "./redirects";
|
||||
@@ -43,11 +44,13 @@ import {
|
||||
type ServiceModeSwarm,
|
||||
ServiceModeSwarmSchema,
|
||||
triggerType,
|
||||
type UlimitsSwarm,
|
||||
UlimitsSwarmSchema,
|
||||
type UpdateConfigSwarm,
|
||||
UpdateConfigSwarmSchema,
|
||||
} from "./shared";
|
||||
import { sshKeys } from "./ssh-key";
|
||||
import { generateAppName } from "./utils";
|
||||
import { APP_NAME_MESSAGE, APP_NAME_REGEX, generateAppName } from "./utils";
|
||||
export const sourceType = pgEnum("sourceType", [
|
||||
"docker",
|
||||
"git",
|
||||
@@ -156,7 +159,7 @@ export const applications = pgTable("application", {
|
||||
},
|
||||
),
|
||||
enableSubmodules: boolean("enableSubmodules").notNull().default(false),
|
||||
dockerfile: text("dockerfile"),
|
||||
dockerfile: text("dockerfile").default("Dockerfile"),
|
||||
dockerContextPath: text("dockerContextPath"),
|
||||
dockerBuildStage: text("dockerBuildStage"),
|
||||
// Drop
|
||||
@@ -172,6 +175,7 @@ export const applications = pgTable("application", {
|
||||
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
||||
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
||||
ulimitsSwarm: json("ulimitsSwarm").$type<UlimitsSwarm>(),
|
||||
//
|
||||
replicas: integer("replicas").default(1).notNull(),
|
||||
applicationStatus: applicationStatus("applicationStatus")
|
||||
@@ -283,11 +287,17 @@ export const applicationsRelations = relations(
|
||||
references: [registry.registryId],
|
||||
relationName: "applicationRollbackRegistry",
|
||||
}),
|
||||
patches: many(patch),
|
||||
}),
|
||||
);
|
||||
|
||||
const createSchema = createInsertSchema(applications, {
|
||||
appName: z.string(),
|
||||
appName: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(63)
|
||||
.regex(APP_NAME_REGEX, APP_NAME_MESSAGE)
|
||||
.optional(),
|
||||
createdAt: z.string(),
|
||||
applicationId: z.string(),
|
||||
autoDeploy: z.boolean(),
|
||||
@@ -321,6 +331,7 @@ const createSchema = createInsertSchema(applications, {
|
||||
sourceType: z
|
||||
.enum(["github", "docker", "git", "gitlab", "bitbucket", "gitea", "drop"])
|
||||
.optional(),
|
||||
triggerType: z.enum(["push", "tag"]).optional(),
|
||||
applicationStatus: z.enum(["idle", "running", "done", "error"]),
|
||||
buildType: z.enum([
|
||||
"dockerfile",
|
||||
@@ -359,6 +370,7 @@ const createSchema = createInsertSchema(applications, {
|
||||
cleanCache: z.boolean().optional(),
|
||||
stopGracePeriodSwarm: z.bigint().nullable(),
|
||||
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
||||
ulimitsSwarm: UlimitsSwarmSchema.nullable(),
|
||||
});
|
||||
|
||||
export const apiCreateApplication = createSchema.pick({
|
||||
@@ -369,11 +381,9 @@ export const apiCreateApplication = createSchema.pick({
|
||||
serverId: true,
|
||||
});
|
||||
|
||||
export const apiFindOneApplication = createSchema
|
||||
.pick({
|
||||
applicationId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiFindOneApplication = z.object({
|
||||
applicationId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiDeployApplication = createSchema
|
||||
.pick({
|
||||
@@ -509,11 +519,9 @@ export const apiSaveEnvironmentVariables = createSchema
|
||||
})
|
||||
.required();
|
||||
|
||||
export const apiFindMonitoringStats = createSchema
|
||||
.pick({
|
||||
appName: true,
|
||||
})
|
||||
.required();
|
||||
export const apiFindMonitoringStats = z.object({
|
||||
appName: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiUpdateApplication = createSchema
|
||||
.partial()
|
||||
|
||||
@@ -165,11 +165,9 @@ export const apiCreateBackup = createSchema.pick({
|
||||
metadata: true,
|
||||
});
|
||||
|
||||
export const apiFindOneBackup = createSchema
|
||||
.pick({
|
||||
backupId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiFindOneBackup = z.object({
|
||||
backupId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiRemoveBackup = createSchema
|
||||
.pick({
|
||||
|
||||
@@ -12,11 +12,12 @@ import { gitea } from "./gitea";
|
||||
import { github } from "./github";
|
||||
import { gitlab } from "./gitlab";
|
||||
import { mounts } from "./mount";
|
||||
import { patch } from "./patch";
|
||||
import { schedules } from "./schedule";
|
||||
import { server } from "./server";
|
||||
import { applicationStatus, triggerType } from "./shared";
|
||||
import { sshKeys } from "./ssh-key";
|
||||
import { generateAppName } from "./utils";
|
||||
import { APP_NAME_MESSAGE, APP_NAME_REGEX, generateAppName } from "./utils";
|
||||
export const sourceTypeCompose = pgEnum("sourceTypeCompose", [
|
||||
"git",
|
||||
"github",
|
||||
@@ -143,10 +144,17 @@ export const composeRelations = relations(compose, ({ one, many }) => ({
|
||||
}),
|
||||
backups: many(backups),
|
||||
schedules: many(schedules),
|
||||
patches: many(patch),
|
||||
}));
|
||||
|
||||
const createSchema = createInsertSchema(compose, {
|
||||
name: z.string().min(1),
|
||||
appName: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(63)
|
||||
.regex(APP_NAME_REGEX, APP_NAME_MESSAGE)
|
||||
.optional(),
|
||||
description: z.string(),
|
||||
env: z.string().optional(),
|
||||
composeFile: z.string().optional(),
|
||||
@@ -156,6 +164,11 @@ const createSchema = createInsertSchema(compose, {
|
||||
composePath: z.string().min(1),
|
||||
composeType: z.enum(["docker-compose", "stack"]).optional(),
|
||||
watchPaths: z.array(z.string()).optional(),
|
||||
sourceType: z
|
||||
.enum(["git", "github", "gitlab", "bitbucket", "gitea", "raw"])
|
||||
.optional(),
|
||||
triggerType: z.enum(["push", "tag"]).optional(),
|
||||
composeStatus: z.enum(["idle", "running", "done", "error"]).optional(),
|
||||
});
|
||||
|
||||
export const apiCreateCompose = createSchema.pick({
|
||||
|
||||
@@ -126,7 +126,6 @@ const schema = createInsertSchema(deployments, {
|
||||
previewDeploymentId: z.string(),
|
||||
buildServerId: z.string(),
|
||||
});
|
||||
|
||||
export const apiCreateDeployment = schema
|
||||
.pick({
|
||||
title: true,
|
||||
@@ -210,44 +209,27 @@ export const apiCreateDeploymentVolumeBackup = schema
|
||||
volumeBackupId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiFindAllByApplication = schema
|
||||
.pick({
|
||||
applicationId: true,
|
||||
})
|
||||
.extend({
|
||||
applicationId: z.string().min(1),
|
||||
})
|
||||
.required();
|
||||
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",
|
||||
]),
|
||||
});
|
||||
|
||||
@@ -61,11 +61,9 @@ export const apiCreateDestination = createSchema
|
||||
serverId: z.string().optional(),
|
||||
});
|
||||
|
||||
export const apiFindOneDestination = createSchema
|
||||
.pick({
|
||||
destinationId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiFindOneDestination = z.object({
|
||||
destinationId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiRemoveDestination = createSchema
|
||||
.pick({
|
||||
|
||||
@@ -70,7 +70,11 @@ export const domainsRelations = relations(domains, ({ one }) => ({
|
||||
}),
|
||||
}));
|
||||
|
||||
const createSchema = createInsertSchema(domains, domain._def.schema.shape);
|
||||
const createSchema = createInsertSchema(domains, {
|
||||
...domain.shape,
|
||||
// Override pgEnum so Zod 4 infers only string literals, not numeric enum index
|
||||
domainType: z.enum(["compose", "application", "preview"]).optional(),
|
||||
});
|
||||
|
||||
export const apiCreateDomain = createSchema.pick({
|
||||
host: true,
|
||||
@@ -88,11 +92,9 @@ export const apiCreateDomain = createSchema.pick({
|
||||
stripPath: true,
|
||||
});
|
||||
|
||||
export const apiFindDomain = createSchema
|
||||
.pick({
|
||||
domainId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiFindDomain = z.object({
|
||||
domainId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiFindDomainByApplication = createSchema.pick({
|
||||
applicationId: true,
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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),
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@ export const gitea = pgTable("gitea", {
|
||||
.primaryKey()
|
||||
.$defaultFn(() => nanoid()),
|
||||
giteaUrl: text("giteaUrl").default("https://gitea.com").notNull(),
|
||||
giteaInternalUrl: text("giteaInternalUrl"),
|
||||
redirectUri: text("redirect_uri"),
|
||||
clientId: text("client_id"),
|
||||
clientSecret: text("client_secret"),
|
||||
@@ -40,6 +41,7 @@ export const apiCreateGitea = createSchema.extend({
|
||||
redirectUri: z.string().optional(),
|
||||
name: z.string().min(1),
|
||||
giteaUrl: z.string().min(1),
|
||||
giteaInternalUrl: z.string().optional().nullable(),
|
||||
giteaUsername: z.string().optional(),
|
||||
accessToken: z.string().optional(),
|
||||
refreshToken: z.string().optional(),
|
||||
@@ -76,6 +78,7 @@ export const apiUpdateGitea = createSchema.extend({
|
||||
name: z.string().min(1),
|
||||
giteaId: z.string().min(1),
|
||||
giteaUrl: z.string().min(1),
|
||||
giteaInternalUrl: z.string().optional().nullable(),
|
||||
giteaUsername: z.string().optional(),
|
||||
accessToken: z.string().optional(),
|
||||
refreshToken: z.string().optional(),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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";
|
||||
@@ -11,6 +10,7 @@ export const gitlab = pgTable("gitlab", {
|
||||
.primaryKey()
|
||||
.$defaultFn(() => nanoid()),
|
||||
gitlabUrl: text("gitlabUrl").default("https://gitlab.com").notNull(),
|
||||
gitlabInternalUrl: text("gitlabInternalUrl"),
|
||||
applicationId: text("application_id"),
|
||||
redirectUri: text("redirect_uri"),
|
||||
secret: text("secret"),
|
||||
@@ -30,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(),
|
||||
@@ -41,19 +39,17 @@ export const apiCreateGitlab = createSchema.extend({
|
||||
authId: z.string().min(1),
|
||||
name: z.string().min(1),
|
||||
gitlabUrl: z.string().min(1),
|
||||
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(),
|
||||
@@ -62,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(),
|
||||
@@ -70,4 +66,6 @@ export const apiUpdateGitlab = createSchema.extend({
|
||||
name: z.string().min(1),
|
||||
gitlabId: z.string().min(1),
|
||||
gitlabUrl: z.string().min(1),
|
||||
gitProviderId: z.string().min(1),
|
||||
gitlabInternalUrl: z.string().optional().nullable(),
|
||||
});
|
||||
|
||||
@@ -18,6 +18,7 @@ export * from "./mongo";
|
||||
export * from "./mount";
|
||||
export * from "./mysql";
|
||||
export * from "./notification";
|
||||
export * from "./patch";
|
||||
export * from "./port";
|
||||
export * from "./postgres";
|
||||
export * from "./preview-deployments";
|
||||
@@ -32,6 +33,7 @@ export * from "./server";
|
||||
export * from "./session";
|
||||
export * from "./shared";
|
||||
export * from "./ssh-key";
|
||||
export * from "./sso";
|
||||
export * from "./user";
|
||||
export * from "./utils";
|
||||
export * from "./volume-backups";
|
||||
|
||||
@@ -23,10 +23,12 @@ import {
|
||||
RestartPolicySwarmSchema,
|
||||
type ServiceModeSwarm,
|
||||
ServiceModeSwarmSchema,
|
||||
type UlimitsSwarm,
|
||||
UlimitsSwarmSchema,
|
||||
type UpdateConfigSwarm,
|
||||
UpdateConfigSwarmSchema,
|
||||
} from "./shared";
|
||||
import { generateAppName } from "./utils";
|
||||
import { APP_NAME_MESSAGE, APP_NAME_REGEX, generateAppName } from "./utils";
|
||||
|
||||
export const mariadb = pgTable("mariadb", {
|
||||
mariadbId: text("mariadbId")
|
||||
@@ -67,6 +69,7 @@ export const mariadb = pgTable("mariadb", {
|
||||
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
||||
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
||||
ulimitsSwarm: json("ulimitsSwarm").$type<UlimitsSwarm>(),
|
||||
replicas: integer("replicas").default(1).notNull(),
|
||||
createdAt: text("createdAt")
|
||||
.notNull()
|
||||
@@ -96,7 +99,12 @@ export const mariadbRelations = relations(mariadb, ({ one, many }) => ({
|
||||
const createSchema = createInsertSchema(mariadb, {
|
||||
mariadbId: z.string(),
|
||||
name: z.string().min(1),
|
||||
appName: z.string().min(1),
|
||||
appName: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(63)
|
||||
.regex(APP_NAME_REGEX, APP_NAME_MESSAGE)
|
||||
.optional(),
|
||||
createdAt: z.string(),
|
||||
databaseName: z.string().min(1),
|
||||
databaseUser: z.string().min(1),
|
||||
@@ -136,28 +144,25 @@ const createSchema = createInsertSchema(mariadb, {
|
||||
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||
stopGracePeriodSwarm: z.bigint().nullable(),
|
||||
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
||||
ulimitsSwarm: UlimitsSwarmSchema.nullable(),
|
||||
});
|
||||
|
||||
export const apiCreateMariaDB = createSchema
|
||||
.pick({
|
||||
name: true,
|
||||
appName: true,
|
||||
dockerImage: true,
|
||||
databaseRootPassword: true,
|
||||
environmentId: true,
|
||||
description: true,
|
||||
databaseName: true,
|
||||
databaseUser: true,
|
||||
databasePassword: true,
|
||||
serverId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiCreateMariaDB = createSchema.pick({
|
||||
name: true,
|
||||
appName: true,
|
||||
dockerImage: true,
|
||||
databaseRootPassword: true,
|
||||
environmentId: true,
|
||||
description: true,
|
||||
databaseName: true,
|
||||
databaseUser: true,
|
||||
databasePassword: true,
|
||||
serverId: true,
|
||||
});
|
||||
|
||||
export const apiFindOneMariaDB = createSchema
|
||||
.pick({
|
||||
mariadbId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiFindOneMariaDB = z.object({
|
||||
mariadbId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiChangeMariaDBStatus = createSchema
|
||||
.pick({
|
||||
|
||||
@@ -30,10 +30,12 @@ import {
|
||||
RestartPolicySwarmSchema,
|
||||
type ServiceModeSwarm,
|
||||
ServiceModeSwarmSchema,
|
||||
type UlimitsSwarm,
|
||||
UlimitsSwarmSchema,
|
||||
type UpdateConfigSwarm,
|
||||
UpdateConfigSwarmSchema,
|
||||
} from "./shared";
|
||||
import { generateAppName } from "./utils";
|
||||
import { APP_NAME_MESSAGE, APP_NAME_REGEX, generateAppName } from "./utils";
|
||||
|
||||
export const mongo = pgTable("mongo", {
|
||||
mongoId: text("mongoId")
|
||||
@@ -70,6 +72,7 @@ export const mongo = pgTable("mongo", {
|
||||
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
||||
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
||||
ulimitsSwarm: json("ulimitsSwarm").$type<UlimitsSwarm>(),
|
||||
replicas: integer("replicas").default(1).notNull(),
|
||||
createdAt: text("createdAt")
|
||||
.notNull()
|
||||
@@ -98,7 +101,12 @@ export const mongoRelations = relations(mongo, ({ one, many }) => ({
|
||||
}));
|
||||
|
||||
const createSchema = createInsertSchema(mongo, {
|
||||
appName: z.string().min(1),
|
||||
appName: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(63)
|
||||
.regex(APP_NAME_REGEX, APP_NAME_MESSAGE)
|
||||
.optional(),
|
||||
createdAt: z.string(),
|
||||
mongoId: z.string(),
|
||||
name: z.string().min(1),
|
||||
@@ -133,27 +141,24 @@ const createSchema = createInsertSchema(mongo, {
|
||||
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||
stopGracePeriodSwarm: z.bigint().nullable(),
|
||||
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
||||
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,
|
||||
})
|
||||
.required();
|
||||
export const apiCreateMongo = createSchema.pick({
|
||||
name: true,
|
||||
appName: true,
|
||||
dockerImage: true,
|
||||
environmentId: true,
|
||||
description: true,
|
||||
databaseUser: true,
|
||||
databasePassword: true,
|
||||
serverId: true,
|
||||
replicaSets: true,
|
||||
});
|
||||
|
||||
export const apiFindOneMongo = createSchema
|
||||
.pick({
|
||||
mongoId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiFindOneMongo = z.object({
|
||||
mongoId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiChangeMongoStatus = createSchema
|
||||
.pick({
|
||||
|
||||
@@ -130,11 +130,9 @@ export const apiCreateMount = createSchema
|
||||
serviceId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiFindOneMount = createSchema
|
||||
.pick({
|
||||
mountId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiFindOneMount = z.object({
|
||||
mountId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiRemoveMount = createSchema
|
||||
.pick({
|
||||
@@ -148,12 +146,20 @@ export const apiRemoveMount = createSchema
|
||||
export const apiFindMountByApplicationId = createSchema
|
||||
.extend({
|
||||
serviceId: z.string().min(1),
|
||||
serviceType: z.enum([
|
||||
"application",
|
||||
"postgres",
|
||||
"mysql",
|
||||
"mariadb",
|
||||
"mongo",
|
||||
"redis",
|
||||
"compose",
|
||||
]),
|
||||
})
|
||||
.pick({
|
||||
serviceId: true,
|
||||
serviceType: true,
|
||||
})
|
||||
.required();
|
||||
});
|
||||
|
||||
export const apiUpdateMount = createSchema.partial().extend({
|
||||
mountId: z.string().min(1),
|
||||
|
||||
@@ -23,10 +23,12 @@ import {
|
||||
RestartPolicySwarmSchema,
|
||||
type ServiceModeSwarm,
|
||||
ServiceModeSwarmSchema,
|
||||
type UlimitsSwarm,
|
||||
UlimitsSwarmSchema,
|
||||
type UpdateConfigSwarm,
|
||||
UpdateConfigSwarmSchema,
|
||||
} from "./shared";
|
||||
import { generateAppName } from "./utils";
|
||||
import { APP_NAME_MESSAGE, APP_NAME_REGEX, generateAppName } from "./utils";
|
||||
|
||||
export const mysql = pgTable("mysql", {
|
||||
mysqlId: text("mysqlId")
|
||||
@@ -65,6 +67,7 @@ export const mysql = pgTable("mysql", {
|
||||
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
||||
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
||||
ulimitsSwarm: json("ulimitsSwarm").$type<UlimitsSwarm>(),
|
||||
replicas: integer("replicas").default(1).notNull(),
|
||||
createdAt: text("createdAt")
|
||||
.notNull()
|
||||
@@ -93,7 +96,12 @@ export const mysqlRelations = relations(mysql, ({ one, many }) => ({
|
||||
|
||||
const createSchema = createInsertSchema(mysql, {
|
||||
mysqlId: z.string(),
|
||||
appName: z.string().min(1),
|
||||
appName: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(63)
|
||||
.regex(APP_NAME_REGEX, APP_NAME_MESSAGE)
|
||||
.optional(),
|
||||
createdAt: z.string(),
|
||||
name: z.string().min(1),
|
||||
databaseName: z.string().min(1),
|
||||
@@ -133,28 +141,25 @@ const createSchema = createInsertSchema(mysql, {
|
||||
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||
stopGracePeriodSwarm: z.bigint().nullable(),
|
||||
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
||||
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,
|
||||
})
|
||||
.required();
|
||||
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,
|
||||
});
|
||||
|
||||
export const apiFindOneMySql = createSchema
|
||||
.pick({
|
||||
mysqlId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiFindOneMySql = z.object({
|
||||
mysqlId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiChangeMySqlStatus = createSchema
|
||||
.pick({
|
||||
|
||||
@@ -17,12 +17,14 @@ export const notificationType = pgEnum("notificationType", [
|
||||
"telegram",
|
||||
"discord",
|
||||
"email",
|
||||
"resend",
|
||||
"gotify",
|
||||
"ntfy",
|
||||
"mattermost",
|
||||
"pushover",
|
||||
"custom",
|
||||
"lark",
|
||||
"teams",
|
||||
]);
|
||||
|
||||
export const notifications = pgTable("notification", {
|
||||
@@ -54,6 +56,9 @@ export const notifications = pgTable("notification", {
|
||||
emailId: text("emailId").references(() => email.emailId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
resendId: text("resendId").references(() => resend.resendId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
gotifyId: text("gotifyId").references(() => gotify.gotifyId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
@@ -72,6 +77,9 @@ export const notifications = pgTable("notification", {
|
||||
pushoverId: text("pushoverId").references(() => pushover.pushoverId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
teamsId: text("teamsId").references(() => teams.teamsId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
organizationId: text("organizationId")
|
||||
.notNull()
|
||||
.references(() => organization.id, { onDelete: "cascade" }),
|
||||
@@ -118,6 +126,16 @@ export const email = pgTable("email", {
|
||||
toAddresses: text("toAddress").array().notNull(),
|
||||
});
|
||||
|
||||
export const resend = pgTable("resend", {
|
||||
resendId: text("resendId")
|
||||
.notNull()
|
||||
.primaryKey()
|
||||
.$defaultFn(() => nanoid()),
|
||||
apiKey: text("apiKey").notNull(),
|
||||
fromAddress: text("fromAddress").notNull(),
|
||||
toAddresses: text("toAddress").array().notNull(),
|
||||
});
|
||||
|
||||
export const gotify = pgTable("gotify", {
|
||||
gotifyId: text("gotifyId")
|
||||
.notNull()
|
||||
@@ -179,6 +197,14 @@ export const pushover = pgTable("pushover", {
|
||||
expire: integer("expire"),
|
||||
});
|
||||
|
||||
export const teams = pgTable("teams", {
|
||||
teamsId: text("teamsId")
|
||||
.notNull()
|
||||
.primaryKey()
|
||||
.$defaultFn(() => nanoid()),
|
||||
webhookUrl: text("webhookUrl").notNull(),
|
||||
});
|
||||
|
||||
export const notificationsRelations = relations(notifications, ({ one }) => ({
|
||||
slack: one(slack, {
|
||||
fields: [notifications.slackId],
|
||||
@@ -196,6 +222,10 @@ export const notificationsRelations = relations(notifications, ({ one }) => ({
|
||||
fields: [notifications.emailId],
|
||||
references: [email.emailId],
|
||||
}),
|
||||
resend: one(resend, {
|
||||
fields: [notifications.resendId],
|
||||
references: [resend.resendId],
|
||||
}),
|
||||
gotify: one(gotify, {
|
||||
fields: [notifications.gotifyId],
|
||||
references: [gotify.gotifyId],
|
||||
@@ -220,6 +250,10 @@ export const notificationsRelations = relations(notifications, ({ one }) => ({
|
||||
fields: [notifications.pushoverId],
|
||||
references: [pushover.pushoverId],
|
||||
}),
|
||||
teams: one(teams, {
|
||||
fields: [notifications.teamsId],
|
||||
references: [teams.teamsId],
|
||||
}),
|
||||
organization: one(organization, {
|
||||
fields: [notifications.organizationId],
|
||||
references: [organization.id],
|
||||
@@ -353,6 +387,36 @@ export const apiTestEmailConnection = apiCreateEmail.pick({
|
||||
fromAddress: true,
|
||||
});
|
||||
|
||||
export const apiCreateResend = notificationsSchema
|
||||
.pick({
|
||||
appBuildError: true,
|
||||
databaseBackup: true,
|
||||
volumeBackup: true,
|
||||
dokployRestart: true,
|
||||
name: true,
|
||||
appDeploy: true,
|
||||
dockerCleanup: true,
|
||||
serverThreshold: true,
|
||||
})
|
||||
.extend({
|
||||
apiKey: z.string().min(1),
|
||||
fromAddress: z.string().min(1),
|
||||
toAddresses: z.array(z.string()).min(1),
|
||||
})
|
||||
.required();
|
||||
|
||||
export const apiUpdateResend = apiCreateResend.partial().extend({
|
||||
notificationId: z.string().min(1),
|
||||
resendId: z.string().min(1),
|
||||
organizationId: z.string().optional(),
|
||||
});
|
||||
|
||||
export const apiTestResendConnection = apiCreateResend.pick({
|
||||
apiKey: true,
|
||||
fromAddress: true,
|
||||
toAddresses: true,
|
||||
});
|
||||
|
||||
export const apiCreateGotify = notificationsSchema
|
||||
.pick({
|
||||
appBuildError: true,
|
||||
@@ -422,6 +486,7 @@ export const apiCreateMattermost = notificationsSchema
|
||||
.pick({
|
||||
appBuildError: true,
|
||||
databaseBackup: true,
|
||||
volumeBackup: true,
|
||||
dokployRestart: true,
|
||||
name: true,
|
||||
appDeploy: true,
|
||||
@@ -438,6 +503,7 @@ export const apiCreateMattermost = notificationsSchema
|
||||
webhookUrl: true,
|
||||
appBuildError: true,
|
||||
databaseBackup: true,
|
||||
volumeBackup: true,
|
||||
dokployRestart: true,
|
||||
appDeploy: true,
|
||||
dockerCleanup: true,
|
||||
@@ -461,11 +527,9 @@ export const apiTestMattermostConnection = apiCreateMattermost
|
||||
username: z.string().optional(),
|
||||
});
|
||||
|
||||
export const apiFindOneNotification = notificationsSchema
|
||||
.pick({
|
||||
notificationId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiFindOneNotification = z.object({
|
||||
notificationId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiCreateCustom = notificationsSchema
|
||||
.pick({
|
||||
@@ -480,7 +544,7 @@ export const apiCreateCustom = notificationsSchema
|
||||
})
|
||||
.extend({
|
||||
endpoint: z.string().min(1),
|
||||
headers: z.record(z.string()).optional(),
|
||||
headers: z.record(z.string(), z.string()).optional(),
|
||||
});
|
||||
|
||||
export const apiUpdateCustom = apiCreateCustom.partial().extend({
|
||||
@@ -491,7 +555,7 @@ export const apiUpdateCustom = apiCreateCustom.partial().extend({
|
||||
|
||||
export const apiTestCustomConnection = z.object({
|
||||
endpoint: z.string().min(1),
|
||||
headers: z.record(z.string()).optional(),
|
||||
headers: z.record(z.string(), z.string()).optional(),
|
||||
});
|
||||
|
||||
export const apiCreateLark = notificationsSchema
|
||||
@@ -520,6 +584,32 @@ export const apiTestLarkConnection = apiCreateLark.pick({
|
||||
webhookUrl: true,
|
||||
});
|
||||
|
||||
export const apiCreateTeams = notificationsSchema
|
||||
.pick({
|
||||
appBuildError: true,
|
||||
databaseBackup: true,
|
||||
volumeBackup: true,
|
||||
dokployRestart: true,
|
||||
name: true,
|
||||
appDeploy: true,
|
||||
dockerCleanup: true,
|
||||
serverThreshold: true,
|
||||
})
|
||||
.extend({
|
||||
webhookUrl: z.string().min(1),
|
||||
})
|
||||
.required();
|
||||
|
||||
export const apiUpdateTeams = apiCreateTeams.partial().extend({
|
||||
notificationId: z.string().min(1),
|
||||
teamsId: z.string().min(1),
|
||||
organizationId: z.string().optional(),
|
||||
});
|
||||
|
||||
export const apiTestTeamsConnection = apiCreateTeams.pick({
|
||||
webhookUrl: true,
|
||||
});
|
||||
|
||||
export const apiCreatePushover = notificationsSchema
|
||||
.pick({
|
||||
appBuildError: true,
|
||||
@@ -595,6 +685,7 @@ export const apiSendTest = notificationsSchema
|
||||
username: z.string(),
|
||||
password: z.string(),
|
||||
toAddresses: z.array(z.string()),
|
||||
apiKey: z.string(),
|
||||
serverUrl: z.string(),
|
||||
topic: z.string(),
|
||||
appToken: z.string(),
|
||||
|
||||
100
packages/server/src/db/schema/patch.ts
Normal file
100
packages/server/src/db/schema/patch.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { relations } from "drizzle-orm";
|
||||
import { boolean, pgEnum, pgTable, text, unique } from "drizzle-orm/pg-core";
|
||||
import { createInsertSchema } from "drizzle-zod";
|
||||
import { nanoid } from "nanoid";
|
||||
import { z } from "zod";
|
||||
import { applications } from "./application";
|
||||
import { compose } from "./compose";
|
||||
|
||||
export const patchType = pgEnum("patchType", ["create", "update", "delete"]);
|
||||
|
||||
export const patch = pgTable(
|
||||
"patch",
|
||||
{
|
||||
patchId: text("patchId")
|
||||
.notNull()
|
||||
.primaryKey()
|
||||
.$defaultFn(() => nanoid()),
|
||||
type: patchType("type").notNull().default("update"),
|
||||
filePath: text("filePath").notNull(),
|
||||
enabled: boolean("enabled").notNull().default(true),
|
||||
content: text("content").notNull(),
|
||||
createdAt: text("createdAt")
|
||||
.notNull()
|
||||
.$defaultFn(() => new Date().toISOString()),
|
||||
updatedAt: text("updatedAt").$defaultFn(() => new Date().toISOString()),
|
||||
// Relations - one of these must be set
|
||||
applicationId: text("applicationId").references(
|
||||
() => applications.applicationId,
|
||||
{ onDelete: "cascade" },
|
||||
),
|
||||
composeId: text("composeId").references(() => compose.composeId, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
},
|
||||
(table) => [
|
||||
// Unique constraint: one patch per file per application/compose
|
||||
unique("patch_filepath_application_unique").on(
|
||||
table.filePath,
|
||||
table.applicationId,
|
||||
),
|
||||
unique("patch_filepath_compose_unique").on(table.filePath, table.composeId),
|
||||
],
|
||||
);
|
||||
|
||||
export const patchRelations = relations(patch, ({ one }) => ({
|
||||
application: one(applications, {
|
||||
fields: [patch.applicationId],
|
||||
references: [applications.applicationId],
|
||||
}),
|
||||
compose: one(compose, {
|
||||
fields: [patch.composeId],
|
||||
references: [compose.composeId],
|
||||
}),
|
||||
}));
|
||||
|
||||
const createSchema = createInsertSchema(patch, {
|
||||
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 apiCreatePatch = createSchema.pick({
|
||||
filePath: true,
|
||||
content: true,
|
||||
type: true,
|
||||
enabled: true,
|
||||
applicationId: true,
|
||||
composeId: true,
|
||||
});
|
||||
|
||||
export const apiFindPatch = z.object({
|
||||
patchId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiFindPatchesByApplicationId = z.object({
|
||||
applicationId: z.string().min(1),
|
||||
});
|
||||
|
||||
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 apiDeletePatch = z.object({
|
||||
patchId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiTogglePatchEnabled = z.object({
|
||||
patchId: z.string().min(1),
|
||||
enabled: z.boolean(),
|
||||
});
|
||||
@@ -49,11 +49,9 @@ export const apiCreatePort = createSchema
|
||||
})
|
||||
.required();
|
||||
|
||||
export const apiFindOnePort = createSchema
|
||||
.pick({
|
||||
portId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiFindOnePort = z.object({
|
||||
portId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiUpdatePort = createSchema
|
||||
.pick({
|
||||
|
||||
@@ -23,10 +23,12 @@ import {
|
||||
RestartPolicySwarmSchema,
|
||||
type ServiceModeSwarm,
|
||||
ServiceModeSwarmSchema,
|
||||
type UlimitsSwarm,
|
||||
UlimitsSwarmSchema,
|
||||
type UpdateConfigSwarm,
|
||||
UpdateConfigSwarmSchema,
|
||||
} from "./shared";
|
||||
import { generateAppName } from "./utils";
|
||||
import { APP_NAME_MESSAGE, APP_NAME_REGEX, generateAppName } from "./utils";
|
||||
|
||||
export const postgres = pgTable("postgres", {
|
||||
postgresId: text("postgresId")
|
||||
@@ -65,6 +67,7 @@ export const postgres = pgTable("postgres", {
|
||||
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
||||
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
||||
ulimitsSwarm: json("ulimitsSwarm").$type<UlimitsSwarm>(),
|
||||
replicas: integer("replicas").default(1).notNull(),
|
||||
createdAt: text("createdAt")
|
||||
.notNull()
|
||||
@@ -94,6 +97,12 @@ export const postgresRelations = relations(postgres, ({ one, many }) => ({
|
||||
const createSchema = createInsertSchema(postgres, {
|
||||
postgresId: z.string(),
|
||||
name: z.string().min(1),
|
||||
appName: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(63)
|
||||
.regex(APP_NAME_REGEX, APP_NAME_MESSAGE)
|
||||
.optional(),
|
||||
databasePassword: z
|
||||
.string()
|
||||
.regex(/^[a-zA-Z0-9@#%^&*()_+\-=[\]{}|;:,.<>?~`]*$/, {
|
||||
@@ -126,27 +135,24 @@ const createSchema = createInsertSchema(postgres, {
|
||||
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||
stopGracePeriodSwarm: z.bigint().nullable(),
|
||||
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
||||
ulimitsSwarm: UlimitsSwarmSchema.nullable(),
|
||||
});
|
||||
|
||||
export const apiCreatePostgres = createSchema
|
||||
.pick({
|
||||
name: true,
|
||||
appName: true,
|
||||
databaseName: true,
|
||||
databaseUser: true,
|
||||
databasePassword: true,
|
||||
dockerImage: true,
|
||||
environmentId: true,
|
||||
description: true,
|
||||
serverId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiCreatePostgres = createSchema.pick({
|
||||
name: true,
|
||||
appName: true,
|
||||
databaseName: true,
|
||||
databaseUser: true,
|
||||
databasePassword: true,
|
||||
dockerImage: true,
|
||||
environmentId: true,
|
||||
description: true,
|
||||
serverId: true,
|
||||
});
|
||||
|
||||
export const apiFindOnePostgres = createSchema
|
||||
.pick({
|
||||
postgresId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiFindOnePostgres = z.object({
|
||||
postgresId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiChangePostgresStatus = createSchema
|
||||
.pick({
|
||||
|
||||
@@ -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),
|
||||
});
|
||||
|
||||
@@ -43,12 +43,9 @@ export const apiCreateProject = createSchema.pick({
|
||||
env: true,
|
||||
});
|
||||
|
||||
export const apiFindOneProject = createSchema
|
||||
.pick({
|
||||
projectId: true,
|
||||
})
|
||||
.required();
|
||||
|
||||
export const apiFindOneProject = z.object({
|
||||
projectId: z.string().min(1),
|
||||
});
|
||||
export const apiRemoveProject = createSchema
|
||||
.pick({
|
||||
projectId: true,
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -22,10 +22,12 @@ import {
|
||||
RestartPolicySwarmSchema,
|
||||
type ServiceModeSwarm,
|
||||
ServiceModeSwarmSchema,
|
||||
type UlimitsSwarm,
|
||||
UlimitsSwarmSchema,
|
||||
type UpdateConfigSwarm,
|
||||
UpdateConfigSwarmSchema,
|
||||
} from "./shared";
|
||||
import { generateAppName } from "./utils";
|
||||
import { APP_NAME_MESSAGE, APP_NAME_REGEX, generateAppName } from "./utils";
|
||||
|
||||
export const redis = pgTable("redis", {
|
||||
redisId: text("redisId")
|
||||
@@ -64,6 +66,7 @@ export const redis = pgTable("redis", {
|
||||
networkSwarm: json("networkSwarm").$type<NetworkSwarm[]>(),
|
||||
stopGracePeriodSwarm: bigint("stopGracePeriodSwarm", { mode: "bigint" }),
|
||||
endpointSpecSwarm: json("endpointSpecSwarm").$type<EndpointSpecSwarm>(),
|
||||
ulimitsSwarm: json("ulimitsSwarm").$type<UlimitsSwarm>(),
|
||||
replicas: integer("replicas").default(1).notNull(),
|
||||
|
||||
environmentId: text("environmentId")
|
||||
@@ -88,7 +91,12 @@ export const redisRelations = relations(redis, ({ one, many }) => ({
|
||||
|
||||
const createSchema = createInsertSchema(redis, {
|
||||
redisId: z.string(),
|
||||
appName: z.string().min(1),
|
||||
appName: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(63)
|
||||
.regex(APP_NAME_REGEX, APP_NAME_MESSAGE)
|
||||
.optional(),
|
||||
createdAt: z.string(),
|
||||
name: z.string().min(1),
|
||||
databasePassword: z.string(),
|
||||
@@ -115,25 +123,22 @@ const createSchema = createInsertSchema(redis, {
|
||||
networkSwarm: NetworkSwarmSchema.nullable(),
|
||||
stopGracePeriodSwarm: z.bigint().nullable(),
|
||||
endpointSpecSwarm: EndpointSpecSwarmSchema.nullable(),
|
||||
ulimitsSwarm: UlimitsSwarmSchema.nullable(),
|
||||
});
|
||||
|
||||
export const apiCreateRedis = createSchema
|
||||
.pick({
|
||||
name: true,
|
||||
appName: true,
|
||||
databasePassword: true,
|
||||
dockerImage: true,
|
||||
environmentId: true,
|
||||
description: true,
|
||||
serverId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiCreateRedis = createSchema.pick({
|
||||
name: true,
|
||||
appName: true,
|
||||
databasePassword: true,
|
||||
dockerImage: true,
|
||||
environmentId: true,
|
||||
description: true,
|
||||
serverId: true,
|
||||
});
|
||||
|
||||
export const apiFindOneRedis = createSchema
|
||||
.pick({
|
||||
redisId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiFindOneRedis = z.object({
|
||||
redisId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiChangeRedisStatus = createSchema
|
||||
.pick({
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -471,6 +471,7 @@ table git_provider {
|
||||
table gitea {
|
||||
giteaId text [pk, not null]
|
||||
giteaUrl text [not null, default: 'https://gitea.com']
|
||||
giteaInternalUrl text
|
||||
redirect_uri text
|
||||
client_id text
|
||||
client_secret text
|
||||
@@ -497,6 +498,7 @@ table github {
|
||||
table gitlab {
|
||||
gitlabId text [pk, not null]
|
||||
gitlabUrl text [not null, default: 'https://gitlab.com']
|
||||
gitlabInternalUrl text
|
||||
application_id text
|
||||
redirect_uri text
|
||||
secret text
|
||||
|
||||
@@ -38,11 +38,9 @@ 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({
|
||||
|
||||
@@ -133,6 +133,7 @@ const createSchema = createInsertSchema(server, {
|
||||
serverId: z.string().min(1),
|
||||
name: z.string().min(1),
|
||||
description: z.string().optional(),
|
||||
serverType: z.enum(["deploy", "build"]).optional(),
|
||||
});
|
||||
|
||||
export const apiCreateServer = createSchema
|
||||
@@ -147,11 +148,9 @@ export const apiCreateServer = createSchema
|
||||
})
|
||||
.required();
|
||||
|
||||
export const apiFindOneServer = createSchema
|
||||
.pick({
|
||||
serverId: true,
|
||||
})
|
||||
.required();
|
||||
export const apiFindOneServer = z.object({
|
||||
serverId: z.string().min(1),
|
||||
});
|
||||
|
||||
export const apiRemoveServer = createSchema
|
||||
.pick({
|
||||
|
||||
@@ -2,7 +2,7 @@ import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
||||
import { user } from "./user";
|
||||
|
||||
// OLD TABLE
|
||||
export const session = pgTable("session_temp", {
|
||||
export const session = pgTable("session", {
|
||||
id: text("id").primaryKey(),
|
||||
expiresAt: timestamp("expires_at").notNull(),
|
||||
token: text("token").notNull().unique(),
|
||||
|
||||
@@ -86,6 +86,14 @@ export interface EndpointSpecSwarm {
|
||||
Ports?: EndpointPortConfigSwarm[] | undefined;
|
||||
}
|
||||
|
||||
export interface UlimitSwarm {
|
||||
Name: string;
|
||||
Soft: number;
|
||||
Hard: number;
|
||||
}
|
||||
|
||||
export type UlimitsSwarm = UlimitSwarm[];
|
||||
|
||||
export const HealthCheckSwarmSchema = z
|
||||
.object({
|
||||
Test: z.array(z.string()).optional(),
|
||||
@@ -167,12 +175,12 @@ export const NetworkSwarmSchema = z.array(
|
||||
.object({
|
||||
Target: z.string().optional(),
|
||||
Aliases: z.array(z.string()).optional(),
|
||||
DriverOpts: z.object({}).optional(),
|
||||
DriverOpts: z.record(z.string(), z.string()).optional(),
|
||||
})
|
||||
.strict(),
|
||||
);
|
||||
|
||||
export const LabelsSwarmSchema = z.record(z.string());
|
||||
export const LabelsSwarmSchema = z.record(z.string(), z.string());
|
||||
|
||||
export const EndpointPortConfigSwarmSchema = z
|
||||
.object({
|
||||
@@ -189,3 +197,13 @@ export const EndpointSpecSwarmSchema = z
|
||||
Ports: z.array(EndpointPortConfigSwarmSchema).optional(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
export const UlimitSwarmSchema = z
|
||||
.object({
|
||||
Name: z.string().min(1),
|
||||
Soft: z.number().int().min(-1),
|
||||
Hard: z.number().int().min(-1),
|
||||
})
|
||||
.strict();
|
||||
|
||||
export const UlimitsSwarmSchema = z.array(UlimitSwarmSchema);
|
||||
|
||||
@@ -2,6 +2,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";
|
||||
@@ -52,11 +53,9 @@ export const apiCreateSshKey = createSchema
|
||||
})
|
||||
.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;
|
||||
|
||||
|
||||
133
packages/server/src/db/schema/sso.ts
Normal file
133
packages/server/src/db/schema/sso.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
import { relations } from "drizzle-orm";
|
||||
import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
|
||||
import { z } from "zod";
|
||||
import { organization } from "./account";
|
||||
import { user } from "./user";
|
||||
|
||||
export const ssoProvider = pgTable("sso_provider", {
|
||||
id: text("id").primaryKey(),
|
||||
issuer: text("issuer").notNull(),
|
||||
oidcConfig: text("oidc_config"),
|
||||
samlConfig: text("saml_config"),
|
||||
providerId: text("provider_id").notNull().unique(),
|
||||
userId: text("user_id").references(() => user.id, { onDelete: "cascade" }),
|
||||
organizationId: text("organization_id").references(() => organization.id, {
|
||||
onDelete: "cascade",
|
||||
}),
|
||||
domain: text("domain").notNull(),
|
||||
createdAt: timestamp("created_at").notNull().defaultNow(),
|
||||
});
|
||||
|
||||
export const ssoProviderRelations = relations(ssoProvider, ({ one }) => ({
|
||||
organization: one(organization, {
|
||||
fields: [ssoProvider.organizationId],
|
||||
references: [organization.id],
|
||||
}),
|
||||
user: one(user, {
|
||||
fields: [ssoProvider.userId],
|
||||
references: [user.id],
|
||||
}),
|
||||
}));
|
||||
const domainRegex = /^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$/;
|
||||
export const ssoProviderBodySchema = z.object({
|
||||
providerId: z.string({}),
|
||||
issuer: z.string({}),
|
||||
domains: z
|
||||
.string()
|
||||
.array()
|
||||
.transform((val) =>
|
||||
Array.from(
|
||||
new Set(val.map((d) => d.trim().toLowerCase()).filter(Boolean)),
|
||||
),
|
||||
)
|
||||
.refine((val) => val.every((d) => domainRegex.test(d)), {
|
||||
message: "Invalid domain",
|
||||
path: ["domains"],
|
||||
}),
|
||||
oidcConfig: z
|
||||
.object({
|
||||
clientId: z.string({}),
|
||||
clientSecret: z.string({}),
|
||||
authorizationEndpoint: z.string({}).optional(),
|
||||
tokenEndpoint: z.string({}).optional(),
|
||||
userInfoEndpoint: z.string({}).optional(),
|
||||
tokenEndpointAuthentication: z
|
||||
.enum(["client_secret_post", "client_secret_basic"])
|
||||
.optional(),
|
||||
jwksEndpoint: z.string({}).optional(),
|
||||
discoveryEndpoint: z.string().optional(),
|
||||
skipDiscovery: z.boolean().optional(),
|
||||
scopes: z.array(z.string()).optional(),
|
||||
pkce: z.boolean().default(true).optional(),
|
||||
mapping: z
|
||||
.object({
|
||||
id: z.string({}),
|
||||
email: z.string({}),
|
||||
emailVerified: z.string({}).optional(),
|
||||
name: z.string({}),
|
||||
image: z.string({}).optional(),
|
||||
extraFields: z.record(z.string(), z.any()).optional(),
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
.optional(),
|
||||
samlConfig: z
|
||||
.object({
|
||||
entryPoint: z.string({}),
|
||||
cert: z.string({}),
|
||||
callbackUrl: z.string({}),
|
||||
audience: z.string().optional(),
|
||||
idpMetadata: z
|
||||
.object({
|
||||
metadata: z.string().optional(),
|
||||
entityID: z.string().optional(),
|
||||
cert: z.string().optional(),
|
||||
privateKey: z.string().optional(),
|
||||
privateKeyPass: z.string().optional(),
|
||||
isAssertionEncrypted: z.boolean().optional(),
|
||||
encPrivateKey: z.string().optional(),
|
||||
encPrivateKeyPass: z.string().optional(),
|
||||
singleSignOnService: z
|
||||
.array(
|
||||
z.object({
|
||||
Binding: z.string(),
|
||||
Location: z.string(),
|
||||
}),
|
||||
)
|
||||
.optional(),
|
||||
})
|
||||
.optional(),
|
||||
spMetadata: z.object({
|
||||
metadata: z.string().optional(),
|
||||
entityID: z.string().optional(),
|
||||
binding: z.string().optional(),
|
||||
privateKey: z.string().optional(),
|
||||
privateKeyPass: z.string().optional(),
|
||||
isAssertionEncrypted: z.boolean().optional(),
|
||||
encPrivateKey: z.string().optional(),
|
||||
encPrivateKeyPass: z.string().optional(),
|
||||
}),
|
||||
wantAssertionsSigned: z.boolean().optional(),
|
||||
authnRequestsSigned: z.boolean().optional(),
|
||||
signatureAlgorithm: z.string().optional(),
|
||||
digestAlgorithm: z.string().optional(),
|
||||
identifierFormat: z.string().optional(),
|
||||
privateKey: z.string().optional(),
|
||||
decryptionPvk: z.string().optional(),
|
||||
additionalParams: z.record(z.string(), z.any()).optional(),
|
||||
mapping: z
|
||||
.object({
|
||||
id: z.string({}),
|
||||
email: z.string({}),
|
||||
emailVerified: z.string({}).optional(),
|
||||
name: z.string({}),
|
||||
firstName: z.string({}).optional(),
|
||||
lastName: z.string({}).optional(),
|
||||
extraFields: z.record(z.string(), z.any()).optional(),
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
.optional(),
|
||||
organizationId: z.string({}).optional(),
|
||||
overrideUserInfo: z.boolean({}).default(false).optional(),
|
||||
});
|
||||
@@ -14,6 +14,7 @@ import { account, apikey, organization } from "./account";
|
||||
import { backups } from "./backups";
|
||||
import { projects } from "./project";
|
||||
import { schedules } from "./schedule";
|
||||
import { ssoProvider } from "./sso";
|
||||
/**
|
||||
* This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same
|
||||
* database instance for multiple projects.
|
||||
@@ -53,9 +54,18 @@ export const user = pgTable("user", {
|
||||
// Metrics
|
||||
enablePaidFeatures: boolean("enablePaidFeatures").notNull().default(false),
|
||||
allowImpersonation: boolean("allowImpersonation").notNull().default(false),
|
||||
// Enterprise / proprietary features
|
||||
enableEnterpriseFeatures: boolean("enableEnterpriseFeatures")
|
||||
.notNull()
|
||||
.default(false),
|
||||
licenseKey: text("licenseKey"),
|
||||
isValidEnterpriseLicense: boolean("isValidEnterpriseLicense")
|
||||
.notNull()
|
||||
.default(false),
|
||||
stripeCustomerId: text("stripeCustomerId"),
|
||||
stripeSubscriptionId: text("stripeSubscriptionId"),
|
||||
serversQuantity: integer("serversQuantity").notNull().default(0),
|
||||
trustedOrigins: text("trustedOrigins").array(),
|
||||
});
|
||||
|
||||
export const usersRelations = relations(user, ({ one, many }) => ({
|
||||
@@ -66,6 +76,7 @@ export const usersRelations = relations(user, ({ one, many }) => ({
|
||||
organizations: many(organization),
|
||||
projects: many(projects),
|
||||
apiKeys: many(apikey),
|
||||
ssoProviders: many(ssoProvider),
|
||||
backups: many(backups),
|
||||
schedules: many(schedules),
|
||||
}));
|
||||
@@ -75,6 +86,8 @@ const createSchema = createInsertSchema(user, {
|
||||
isRegistered: z.boolean().optional(),
|
||||
}).omit({
|
||||
role: true,
|
||||
trustedOrigins: true,
|
||||
isValidEnterpriseLicense: true,
|
||||
});
|
||||
|
||||
export const apiCreateUserInvitation = createSchema.pick({}).extend({
|
||||
|
||||
@@ -6,6 +6,12 @@ const alphabet = "abcdefghijklmnopqrstuvwxyz123456789";
|
||||
|
||||
const customNanoid = customAlphabet(alphabet, 6);
|
||||
|
||||
/** App name: letters, numbers, dots, underscores, hyphens only (no spaces). Safe for shell/Docker. */
|
||||
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";
|
||||
|
||||
export const generateAppName = (type: string) => {
|
||||
const verb = faker.hacker.verb().replace(/ /g, "-");
|
||||
const adjective = faker.hacker.adjective().replace(/ /g, "-");
|
||||
|
||||
Reference in New Issue
Block a user