diff --git a/server/db/schema.ts b/server/db/schema.ts index 33d979e7..3d5f234f 100644 --- a/server/db/schema.ts +++ b/server/db/schema.ts @@ -3,7 +3,7 @@ import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core"; export const domains = sqliteTable("domains", { domainId: text("domainId").primaryKey(), - baseDomain: text("baseDomain").notNull().unique(), + baseDomain: text("baseDomain").notNull(), configManaged: integer("configManaged", { mode: "boolean" }) .notNull() .default(false) diff --git a/server/lib/config.ts b/server/lib/config.ts index 74f2d9dd..e35c0e8d 100644 --- a/server/lib/config.ts +++ b/server/lib/config.ts @@ -42,7 +42,7 @@ const configSchema = z.object({ z.string(), z.object({ base_domain: hostnameSchema.transform((url) => url.toLowerCase()), - cert_resolver: z.string(), + cert_resolver: z.string().optional(), prefer_wildcard_cert: z.boolean().optional() }) ), diff --git a/server/routers/resource/updateResource.ts b/server/routers/resource/updateResource.ts index ce574299..2baa61bc 100644 --- a/server/routers/resource/updateResource.ts +++ b/server/routers/resource/updateResource.ts @@ -68,6 +68,8 @@ const updateHttpResourceBodySchema = z } ); +export type UpdateResourceResponse = Resource; + const updateRawResourceBodySchema = z .object({ name: z.string().min(1).max(255).optional(), diff --git a/server/setup/scripts/1.0.0-beta15.ts b/server/setup/scripts/1.0.0-beta15.ts new file mode 100644 index 00000000..cb116082 --- /dev/null +++ b/server/setup/scripts/1.0.0-beta15.ts @@ -0,0 +1,78 @@ +import db from "@server/db"; +import { configFilePath1, configFilePath2 } from "@server/lib/consts"; +import fs from "fs"; +import yaml from "js-yaml"; +import { sql } from "drizzle-orm"; + +const version = "1.0.0-beta.15"; + +export default async function migration() { + console.log(`Running setup script ${version}...`); + + try { + db.transaction((trx) => {}); + + console.log(`Migrated database schema`); + } catch (e) { + console.log("Unable to migrate database schema"); + throw e; + } + + try { + // Determine which config file exists + const filePaths = [configFilePath1, configFilePath2]; + let filePath = ""; + for (const path of filePaths) { + if (fs.existsSync(path)) { + filePath = path; + break; + } + } + + if (!filePath) { + throw new Error( + `No config file found (expected config.yml or config.yaml).` + ); + } + + // Read and parse the YAML file + let rawConfig: any; + const fileContents = fs.readFileSync(filePath, "utf8"); + rawConfig = yaml.load(fileContents); + + const baseDomain = rawConfig.app.base_domain; + const certResolver = rawConfig.traefik.cert_resolver; + const preferWildcardCert = rawConfig.traefik.prefer_wildcard_cert; + + delete rawConfig.traefik.prefer_wildcard_cert; + delete rawConfig.traefik.cert_resolver; + delete rawConfig.app.base_domain; + + rawConfig.domains = { + domain1: { + base_domain: baseDomain + } + }; + + if (certResolver) { + rawConfig.domains.domain1.cert_resolver = certResolver; + } + + if (preferWildcardCert) { + rawConfig.domains.domain1.prefer_wildcard_cert = preferWildcardCert; + } + + // Write the updated YAML back to the file + const updatedYaml = yaml.dump(rawConfig); + fs.writeFileSync(filePath, updatedYaml, "utf8"); + + console.log(`Moved base_domain to new domains section`); + } catch (e) { + console.log( + `Unable to migrate config file and move base_domain to domains. Error: ${e}` + ); + return; + } + + console.log(`${version} migration complete`); +} diff --git a/src/app/[orgId]/settings/resources/[resourceId]/general/page.tsx b/src/app/[orgId]/settings/resources/[resourceId]/general/page.tsx index c8603b0f..0790605c 100644 --- a/src/app/[orgId]/settings/resources/[resourceId]/general/page.tsx +++ b/src/app/[orgId]/settings/resources/[resourceId]/general/page.tsx @@ -60,6 +60,7 @@ import { SelectTrigger, SelectValue } from "@app/components/ui/select"; +import { UpdateResourceResponse } from "@server/routers/resource"; const GeneralFormSchema = z .object({ @@ -191,13 +192,16 @@ export default function GeneralForm() { setSaveLoading(true); const res = await api - .post(`resource/${resource?.resourceId}`, { - name: data.name, - subdomain: data.http ? data.subdomain : undefined, - proxyPort: data.proxyPort, - isBaseDomain: data.http ? data.isBaseDomain : undefined, - domainId: data.http ? data.domainId : undefined - }) + .post>( + `resource/${resource?.resourceId}`, + { + name: data.name, + subdomain: data.http ? data.subdomain : undefined, + proxyPort: data.proxyPort, + isBaseDomain: data.http ? data.isBaseDomain : undefined, + domainId: data.http ? data.domainId : undefined + } + ) .catch((e) => { toast({ variant: "destructive", @@ -215,11 +219,14 @@ export default function GeneralForm() { description: "The resource has been updated successfully" }); + const resource = res.data.data; + updateResource({ name: data.name, subdomain: data.subdomain, proxyPort: data.proxyPort, - isBaseDomain: data.isBaseDomain + isBaseDomain: data.isBaseDomain, + fullDomain: resource.fullDomain }); router.refresh();