Setting up drizzle and fix site not showing in private resource

This commit is contained in:
Owen
2026-02-12 12:05:15 -08:00
parent bff9d33ee6
commit 52484c774e
6 changed files with 107 additions and 58 deletions

3
.gitignore vendored
View File

@@ -51,4 +51,5 @@ dynamic/
scratch/
tsconfig.json
hydrateSaas.ts
CLAUDE.md
CLAUDE.md
drizzle.config.ts

View File

@@ -1,14 +1,15 @@
import { APP_PATH } from "@server/lib/consts";
import { defineConfig } from "drizzle-kit";
import path from "path";
const schema = [path.join("server", "db", "pg", "schema")];
const schema = [path.join("server", "db", "sqlite", "schema")];
export default defineConfig({
dialect: "postgresql",
dialect: "sqlite",
schema: schema,
out: path.join("server", "migrations"),
verbose: true,
dbCredentials: {
url: process.env.DATABASE_URL as string
url: path.join(APP_PATH, "db", "db.sqlite")
}
});

1
server/setup/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
migrations.ts

View File

@@ -1,45 +1,78 @@
#! /usr/bin/env node
import { migrate } from "drizzle-orm/node-postgres/migrator";
import { db } from "../db/pg";
import semver from "semver";
import { versionMigrations } from "../db/pg";
import { __DIRNAME, APP_VERSION } from "@server/lib/consts";
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
import { db, exists } from "../db/sqlite";
import path from "path";
import m1 from "./scriptsPg/1.6.0";
import m2 from "./scriptsPg/1.7.0";
import m3 from "./scriptsPg/1.8.0";
import m4 from "./scriptsPg/1.9.0";
import m5 from "./scriptsPg/1.10.0";
import m6 from "./scriptsPg/1.10.2";
import m7 from "./scriptsPg/1.11.0";
import m8 from "./scriptsPg/1.11.1";
import m9 from "./scriptsPg/1.12.0";
import m10 from "./scriptsPg/1.13.0";
import m11 from "./scriptsPg/1.14.0";
import m12 from "./scriptsPg/1.15.0";
import semver from "semver";
import { versionMigrations } from "../db/sqlite";
import { __DIRNAME, APP_PATH, APP_VERSION } from "@server/lib/consts";
import { SqliteError } from "better-sqlite3";
import fs from "fs";
import m1 from "./scriptsSqlite/1.0.0-beta1";
import m2 from "./scriptsSqlite/1.0.0-beta2";
import m3 from "./scriptsSqlite/1.0.0-beta3";
import m4 from "./scriptsSqlite/1.0.0-beta5";
import m5 from "./scriptsSqlite/1.0.0-beta6";
import m6 from "./scriptsSqlite/1.0.0-beta9";
import m7 from "./scriptsSqlite/1.0.0-beta10";
import m8 from "./scriptsSqlite/1.0.0-beta12";
import m13 from "./scriptsSqlite/1.0.0-beta13";
import m15 from "./scriptsSqlite/1.0.0-beta15";
import m16 from "./scriptsSqlite/1.0.0";
import m17 from "./scriptsSqlite/1.1.0";
import m18 from "./scriptsSqlite/1.2.0";
import m19 from "./scriptsSqlite/1.3.0";
import m20 from "./scriptsSqlite/1.5.0";
import m21 from "./scriptsSqlite/1.6.0";
import m22 from "./scriptsSqlite/1.7.0";
import m23 from "./scriptsSqlite/1.8.0";
import m24 from "./scriptsSqlite/1.9.0";
import m25 from "./scriptsSqlite/1.10.0";
import m26 from "./scriptsSqlite/1.10.1";
import m27 from "./scriptsSqlite/1.10.2";
import m28 from "./scriptsSqlite/1.11.0";
import m29 from "./scriptsSqlite/1.11.1";
import m30 from "./scriptsSqlite/1.12.0";
import m31 from "./scriptsSqlite/1.13.0";
import m32 from "./scriptsSqlite/1.14.0";
import m33 from "./scriptsSqlite/1.15.0";
import m34 from "./scriptsSqlite/1.15.3";
// THIS CANNOT IMPORT ANYTHING FROM THE SERVER
// EXCEPT FOR THE DATABASE AND THE SCHEMA
// Define the migration list with versions and their corresponding functions
const migrations = [
{ version: "1.6.0", run: m1 },
{ version: "1.7.0", run: m2 },
{ version: "1.8.0", run: m3 },
{ version: "1.9.0", run: m4 },
{ version: "1.10.0", run: m5 },
{ version: "1.10.2", run: m6 },
{ version: "1.11.0", run: m7 },
{ version: "1.11.1", run: m8 },
{ version: "1.12.0", run: m9 },
{ version: "1.13.0", run: m10 },
{ version: "1.14.0", run: m11 },
{ version: "1.15.0", run: m12 }
{ version: "1.0.0-beta.1", run: m1 },
{ version: "1.0.0-beta.2", run: m2 },
{ version: "1.0.0-beta.3", run: m3 },
{ version: "1.0.0-beta.5", run: m4 },
{ version: "1.0.0-beta.6", run: m5 },
{ version: "1.0.0-beta.9", run: m6 },
{ version: "1.0.0-beta.10", run: m7 },
{ version: "1.0.0-beta.12", run: m8 },
{ version: "1.0.0-beta.13", run: m13 },
{ version: "1.0.0-beta.15", run: m15 },
{ version: "1.0.0", run: m16 },
{ version: "1.1.0", run: m17 },
{ version: "1.2.0", run: m18 },
{ version: "1.3.0", run: m19 },
{ version: "1.5.0", run: m20 },
{ version: "1.6.0", run: m21 },
{ version: "1.7.0", run: m22 },
{ version: "1.8.0", run: m23 },
{ version: "1.9.0", run: m24 },
{ version: "1.10.0", run: m25 },
{ version: "1.10.1", run: m26 },
{ version: "1.10.2", run: m27 },
{ version: "1.11.0", run: m28 },
{ version: "1.11.1", run: m29 },
{ version: "1.12.0", run: m30 },
{ version: "1.13.0", run: m31 },
{ version: "1.14.0", run: m32 },
{ version: "1.15.0", run: m33 },
{ version: "1.15.3", run: m34 }
// Add new migrations here as they are created
] as {
version: string;
run: () => Promise<void>;
}[];
] as const;
await run();
@@ -48,6 +81,27 @@ async function run() {
await runMigrations();
}
function backupDb() {
// make dir config/db/backups
const appPath = APP_PATH;
const dbDir = path.join(appPath, "db");
const backupsDir = path.join(dbDir, "backups");
// check if the backups directory exists and create it if it doesn't
if (!fs.existsSync(backupsDir)) {
fs.mkdirSync(backupsDir, { recursive: true });
}
// copy the db.sqlite file to backups
// add the date to the filename
const date = new Date();
const dateString = `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}_${date.getHours()}-${date.getMinutes()}-${date.getSeconds()}`;
const dbPath = path.join(dbDir, "db.sqlite");
const backupPath = path.join(backupsDir, `db_${dateString}.sqlite`);
fs.copyFileSync(dbPath, backupPath);
}
export async function runMigrations() {
if (process.env.DISABLE_MIGRATIONS) {
console.log("Migrations are disabled. Skipping...");
@@ -56,23 +110,12 @@ export async function runMigrations() {
try {
const appVersion = APP_VERSION;
// determine if the migrations table exists
const exists = await db
.select()
.from(versionMigrations)
.limit(1)
.execute()
.then((res) => res.length > 0)
.catch(() => false);
if (exists) {
console.log("Migrations table exists, running scripts...");
await executeScripts();
} else {
console.log("Migrations table does not exist, creating it...");
console.log("Running migrations...");
try {
await migrate(db, {
migrate(db, {
migrationsFolder: path.join(__DIRNAME, "init") // put here during the docker build
});
console.log("Migrations completed successfully.");
@@ -105,7 +148,7 @@ async function executeScripts() {
const pendingMigrations = lastExecuted
.map((m) => m)
.sort((a, b) => semver.compare(b.version, a.version));
const startVersion = pendingMigrations[0]?.version ?? "0.0.0";
const startVersion = pendingMigrations[0]?.version ?? APP_VERSION;
console.log(`Starting migrations from version ${startVersion}`);
const migrationsToRun = migrations.filter((migration) =>
@@ -122,6 +165,11 @@ async function executeScripts() {
console.log(`Running migration ${migration.version}`);
try {
if (!process.env.DISABLE_BACKUP_ON_MIGRATION) {
// Backup the database before running the migration
backupDb();
}
await migration.run();
// Update version in database
@@ -138,19 +186,17 @@ async function executeScripts() {
);
} catch (e) {
if (
e instanceof Error &&
typeof (e as any).code === "string" &&
(e as any).code === "23505"
e instanceof SqliteError &&
e.code === "SQLITE_CONSTRAINT_UNIQUE"
) {
console.error("Migration has already run! Skipping...");
continue; // or return, depending on context
continue;
}
console.error(
`Failed to run migration ${migration.version}:`,
e
);
throw e;
throw e; // Re-throw to stop migration process
}
}

View File

@@ -303,7 +303,7 @@ export default function CreateInternalResourceDialog({
const [udpCustomPorts, setUdpCustomPorts] = useState<string>("");
const availableSites = sites.filter(
(site) => site.type === "newt" && site.subnet
(site) => site.type === "newt"
);
const form = useForm<FormData>({

View File

@@ -397,7 +397,7 @@ export default function EditInternalResourceDialog({
);
const availableSites = sites.filter(
(site) => site.type === "newt" && site.subnet
(site) => site.type === "newt"
);
const form = useForm<FormData>({