diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..f06017a --- /dev/null +++ b/flake.lock @@ -0,0 +1,41 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1710734606, + "narHash": "sha256-rFJl+WXfksu2NkWJWKGd5Km17ZGEjFg9hOQNwstsoU8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "79bb4155141a5e68f2bdee2bf6af35b1d27d3a1d", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "systems": "systems" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..15f3cd3 --- /dev/null +++ b/flake.nix @@ -0,0 +1,28 @@ +{ + inputs = { + systems.url = "github:nix-systems/default"; + }; + + outputs = { + systems, + nixpkgs, + ... + } @ inputs: let + eachSystem = f: + nixpkgs.lib.genAttrs (import systems) ( + system: + f nixpkgs.legacyPackages.${system} + ); + in { + devShells = eachSystem (pkgs: { + default = pkgs.mkShell { + buildInputs = [ + pkgs.nodejs_20 + pkgs.nodePackages.pnpm + pkgs.nodePackages.typescript + pkgs.nodePackages.typescript-language-server + ]; + }; + }); + }; +} diff --git a/src/app/(dashboard)/page.tsx b/src/app/(dashboard)/page.tsx index 46cafc4..f2bfd5b 100644 --- a/src/app/(dashboard)/page.tsx +++ b/src/app/(dashboard)/page.tsx @@ -26,7 +26,7 @@ export default async function DashboardHome() { -

+

Hostforge is up to date. (v1.0.0)
diff --git a/src/app/error.tsx b/src/app/error.tsx index 2b6d0fe..a43c137 100644 --- a/src/app/error.tsx +++ b/src/app/error.tsx @@ -17,7 +17,7 @@ export default function Error({ if ( error.stack && error.stack.split("\n")[0] === - "TRPCClientError: You must be logged in to perform this action." + "TRPCClientError: You must be logged in to perform this action." ) { console.log("redirecting to login"); return redirect("/login"); @@ -35,6 +35,13 @@ export default function Error({ Please start the Docker daemon and reload the page.

+ ) : error.message.includes("This node is not a swarm manager.") ? ( + +

Docker is not running in swarm mode.

+

+ Check our wiki for instructions on how to resolve this issue. +

+
) : (

An unexpected error has occured:
{error.message} diff --git a/src/server/db/index.ts b/src/server/db/index.ts index 0941835..839f5f0 100644 --- a/src/server/db/index.ts +++ b/src/server/db/index.ts @@ -1,5 +1,8 @@ import SQLite3 from "better-sqlite3"; +import chalk from "chalk"; import { drizzle } from "drizzle-orm/better-sqlite3"; +import fs from "node:fs"; +import path from "node:path"; import { join } from "path"; import { env } from "~/env"; import logger from "../utils/logger"; @@ -10,6 +13,37 @@ const globalForDB = globalThis as unknown as { }; function createDatabaseInstance() { + const LOGGER = logger.child({ module: "database" }); + + // Create database folder if does not exist + const databaseFolder = path.resolve(path.dirname(env.DATABASE_PATH)); + + if (!fs.existsSync(databaseFolder)) { + LOGGER.debug( + `Folder "${chalk.yellow(databaseFolder)}" does not exist, creating...`, + ); + + try { + fs.mkdirSync(databaseFolder, { + recursive: true, + mode: 0o700, + }); + } catch (error) { + LOGGER.error( + `Failed to create database directory. Either create it manually or check the permissions of the parent folder.`, + error, + ); + + process.exit(1); + } + + LOGGER.info( + `Created previously non-existent database folder ${chalk.yellow( + databaseFolder, + )}`, + ); + } + const sqlite = new SQLite3(env.DATABASE_PATH); // enable WAL mode @@ -17,6 +51,14 @@ function createDatabaseInstance() { // load uuidv7 extension // built from https://github.com/craigpastro/sqlite-uuidv7 + if (env.SQLITE_UUIDV7_EXT_PATH) { + LOGGER.warn( + `Be careful when loading custom UUIDv7 extensions, currently Hostforge is set to load from: "${chalk.yellow( + path.resolve(env.SQLITE_UUIDV7_EXT_PATH), + )}"! Non-official extensions may contain backdoors or introduce new vulnerabilities.`, + ); + } + sqlite.loadExtension( env.SQLITE_UUIDV7_EXT_PATH ?? join( @@ -30,7 +72,7 @@ function createDatabaseInstance() { schema, logger: { logQuery(query) { - logger.child({ module: "database" }).debug(query); + LOGGER.debug(query); }, }, });