diff --git a/Dockerfile b/Dockerfile index 506e880..53d86d8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,38 +1,37 @@ -FROM --platform=$BUILDPLATFORM oven/bun:1.2 AS base +FROM --platform=$BUILDPLATFORM oven/bun:1.2 AS builder LABEL maintainer="Grimoire Developers " LABEL description="Bookmark manager for the wizards" LABEL org.opencontainers.image.source="https://github.com/goniszewski/grimoire" RUN adduser --disabled-password --gecos '' --uid 10001 grimoire -FROM base AS builder - -RUN mkdir -p /etc/s6-overlay/s6-rc.d/grimoire /etc/s6-overlay/s6-rc.d/user/contents.d /app/data +RUN mkdir -p /etc/s6-overlay/s6-rc.d/grimoire /etc/s6-overlay/s6-rc.d/user/contents.d && \ + mkdir -p /app/data # Different build strategy based on architecture ARG TARGETARCH RUN if [ "${TARGETARCH}" = "arm64" ]; then \ - # ARM64 build - avoid libc-bin issues - apt-get update && \ - apt-mark hold libc-bin && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - xz-utils wget python3 python3-pip build-essential && \ - rm -rf /var/lib/apt/lists/*; \ + # ARM64 build - avoid libc-bin issues + apt-get update && \ + apt-mark hold libc-bin && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + xz-utils wget python3 python3-pip build-essential && \ + rm -rf /var/lib/apt/lists/*; \ else \ - # Standard installation for other architectures - apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - xz-utils python3 python3-pip wget build-essential && \ - rm -rf /var/lib/apt/lists/*; \ + # Standard installation for other architectures + apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + xz-utils python3 python3-pip wget build-essential && \ + rm -rf /var/lib/apt/lists/*; \ fi ARG S6_OVERLAY_VERSION=3.1.6.2 RUN case "${TARGETARCH}" in \ - "amd64") S6_ARCH="x86_64" ;; \ - "arm64") S6_ARCH="aarch64" ;; \ - "386") S6_ARCH="i686" ;; \ - "arm/v7") S6_ARCH="armhf" ;; \ - "arm/v6") S6_ARCH="arm" ;; \ - *) S6_ARCH="x86_64" && echo "Warning: Unknown architecture ${TARGETARCH}, defaulting to x86_64" ;; \ + "amd64") S6_ARCH="x86_64" ;; \ + "arm64") S6_ARCH="aarch64" ;; \ + "386") S6_ARCH="i686" ;; \ + "arm/v7") S6_ARCH="armhf" ;; \ + "arm/v6") S6_ARCH="arm" ;; \ + *) S6_ARCH="x86_64" && echo "Warning: Unknown architecture ${TARGETARCH}, defaulting to x86_64" ;; \ esac && \ echo "Architecture: Docker ${TARGETARCH} -> s6-overlay ${S6_ARCH}" && \ wget -q -O /tmp/s6-overlay-noarch.tar.xz https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz && \ @@ -51,8 +50,7 @@ ENV S6_KEEP_ENV=1 \ S6_SYNC_DISKS=1 RUN bun i -g svelte-kit@latest - -RUN mkdir -p /app/data && chown -R grimoire:grimoire /app/data && chmod 766 /app/data +RUN mkdir -p /app/data && chown -R grimoire:grimoire /app/data WORKDIR /app FROM builder AS dependencies @@ -73,18 +71,15 @@ ENV NODE_ENV=production \ NODE_OPTIONS="--max-old-space-size=4096" RUN bun --bun run build -FROM base AS release - -RUN mkdir -p /app/data && chown -R grimoire:grimoire /app/data && chmod 766 /app/data -WORKDIR /app +FROM builder AS release -# Copy only the necessary files for the release +COPY --from=dependencies /app/node_modules ./node_modules COPY --from=build /app/build ./build COPY --from=build /app/migrations ./migrations COPY --from=build /app/migrate.js ./migrate.js COPY --from=build /app/package.json ./package.json -COPY docker-entrypoint.sh / +RUN chown -R grimoire:grimoire /app ENV NODE_ENV=production \ PUBLIC_ORIGIN=${PUBLIC_ORIGIN:-http://localhost:5173} \ ORIGIN=${PUBLIC_ORIGIN:-http://localhost:5173} \ @@ -92,10 +87,7 @@ ENV NODE_ENV=production \ PUBLIC_HTTPS_ONLY=${PUBLIC_HTTPS_ONLY:-false} \ PUBLIC_SIGNUP_DISABLED=${PUBLIC_SIGNUP_DISABLED:-false} \ BODY_SIZE_LIMIT=${BODY_SIZE_LIMIT:-5000000} - -RUN chmod +x /docker-entrypoint.sh -USER grimoire EXPOSE ${PORT} HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:$PORT/api/health || exit 1 -ENTRYPOINT ["/docker-entrypoint.sh"] +ENTRYPOINT ["/init"] diff --git a/README.md b/README.md index 907743e..1302e27 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,24 @@ chmod +x ./run-dev.sh && ./run-dev.sh > [!TIP] > Although the above setups are intended for development, they are also suitable for daily use. For a better experience, it is recommended to use a Node.js process manager, such as [PM2](https://github.com/Unitech/pm2). +
+ Run using One-Click Deploy and Kubernetes (Helm) + +### ⚡ One-Click Deploy + +| Cloud Provider | Deploy Button | +|----------------|---------------| +| AWS | | +| DigitalOcean | | +| Render | | +| Helm | `helm repo add deploystack https://deploystackio.github.io/deploy-templates/`
`helm repo update`
`helm install goniszewski-grimoire deploystack/goniszewski-grimoire` | + +Change or add deploy options at [awesome-docker-run](https://github.com/deploystackio/awesome-docker-run/tree/main/commands/grimoire) + +Generated by DeployStack.io + +
+ ## Development Check out the [development guide](https://grimoire.pro/docs/getting-started/development) to learn how to set up the project for development. diff --git a/bun.lockb b/bun.lockb index 1578df8..c403e84 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh deleted file mode 100644 index 32715d4..0000000 --- a/docker-entrypoint.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -chown -R grimoire:grimoire /app/data -chmod 755 /app/data -bun --bun run run-migrations && bun ./build/index.js diff --git a/docker/etc/s6-overlay/s6-rc.d/grimoire/dependencies b/docker/etc/s6-overlay/s6-rc.d/grimoire/dependencies new file mode 100644 index 0000000..2ca4c17 --- /dev/null +++ b/docker/etc/s6-overlay/s6-rc.d/grimoire/dependencies @@ -0,0 +1 @@ +init-data-permissions \ No newline at end of file diff --git a/docker/etc/s6-overlay/s6-rc.d/grimoire/run b/docker/etc/s6-overlay/s6-rc.d/grimoire/run index 45d1335..7f2f443 100644 --- a/docker/etc/s6-overlay/s6-rc.d/grimoire/run +++ b/docker/etc/s6-overlay/s6-rc.d/grimoire/run @@ -2,8 +2,38 @@ cd /app +<<<<<<< HEAD +echo "Starting Grimoire application" +echo "Current user: $(whoami)" +echo "Working directory: $(pwd)" +echo "Data directory permissions:" +ls -la /app/data/ + +echo "Testing database access as grimoire user:" +s6-setuidgid grimoire ls -la /app/data/ + +# Run migrations first +echo "Running database migrations..." +if ! s6-setuidgid grimoire /usr/local/bin/bun run run-migrations; then + echo "ERROR: Database migration failed" + echo "Data directory details:" + ls -la /app/data/ + echo "Process info:" + echo "Running as: $(s6-setuidgid grimoire whoami)" + echo "UID: $(s6-setuidgid grimoire id -u)" + echo "GID: $(s6-setuidgid grimoire id -g)" + exit 1 +fi + +echo "Migrations completed successfully" + +# Start the application +echo "Starting application server..." +exec s6-setuidgid grimoire /usr/local/bin/bun ./build/index.js +======= # Run migrations first /usr/local/bin/bun run run-migrations # Start the application exec /usr/local/bin/bun ./build/index.js +>>>>>>> 8890939 (Release v0.5.0 (#168)) diff --git a/docker/etc/s6-overlay/s6-rc.d/init-data-permissions/type b/docker/etc/s6-overlay/s6-rc.d/init-data-permissions/type new file mode 100644 index 0000000..3d92b15 --- /dev/null +++ b/docker/etc/s6-overlay/s6-rc.d/init-data-permissions/type @@ -0,0 +1 @@ +oneshot \ No newline at end of file diff --git a/docker/etc/s6-overlay/s6-rc.d/init-data-permissions/up b/docker/etc/s6-overlay/s6-rc.d/init-data-permissions/up new file mode 100755 index 0000000..08c607d --- /dev/null +++ b/docker/etc/s6-overlay/s6-rc.d/init-data-permissions/up @@ -0,0 +1 @@ +/etc/s6-overlay/scripts/init-data-permissions.sh \ No newline at end of file diff --git a/docker/etc/s6-overlay/s6-rc.d/user/contents.d/init-data-permissions b/docker/etc/s6-overlay/s6-rc.d/user/contents.d/init-data-permissions new file mode 100644 index 0000000..e69de29 diff --git a/docker/etc/s6-overlay/scripts/init-data-permissions.sh b/docker/etc/s6-overlay/scripts/init-data-permissions.sh new file mode 100755 index 0000000..d8d0f30 --- /dev/null +++ b/docker/etc/s6-overlay/scripts/init-data-permissions.sh @@ -0,0 +1,62 @@ +#!/command/with-contenv bash + +echo "Starting init-data-permissions service" + +GRIMOIRE_UID=$(id -u grimoire) +GRIMOIRE_GID=$(id -g grimoire) +echo "Grimoire user: UID=$GRIMOIRE_UID, GID=$GRIMOIRE_GID" + +echo "Creating /app/data directory" +mkdir -p /app/data + +# Check current ownership and fix if needed (also volume mounts) +DATA_OWNER=$(stat -c '%U' /app/data 2>/dev/null || echo "unknown") +echo "Current /app/data owner: $DATA_OWNER" + +if [ "$DATA_OWNER" != "grimoire" ]; then + echo "Fixing ownership of /app/data (was owned by $DATA_OWNER)" + chown grimoire:grimoire /app/data +fi + +# Ensure user-uploads dir exists +echo "Creating /app/data/user-uploads directory" +mkdir -p /app/data/user-uploads + +echo "Setting ownership to grimoire:grimoire" +chown -R grimoire:grimoire /app/data + +# Set proper permissions: owner can read/write/execute, group can read/execute, others can read/execute +echo "Setting directory permissions" +chmod 755 /app/data +chmod 755 /app/data/user-uploads + +echo "Testing write permissions" +if ! su grimoire -c "touch /app/data/.test_write && rm -f /app/data/.test_write" 2>/dev/null; then + echo "ERROR: grimoire user cannot write to /app/data" + echo "Directory info:" + ls -la /app/data + exit 1 +fi +echo "Write permissions verified" + +# Check any existing database files have correct permissions +if [ -f /app/data/db.sqlite ]; then + echo "Setting database file permissions" + chown grimoire:grimoire /app/data/db.sqlite + chmod 644 /app/data/db.sqlite +fi + +# Check WAL and SHM files have correct permissions if they exist +if [ -f /app/data/db.sqlite-wal ]; then + echo "Setting WAL file permissions" + chown grimoire:grimoire /app/data/db.sqlite-wal + chmod 644 /app/data/db.sqlite-wal +fi + +if [ -f /app/data/db.sqlite-shm ]; then + echo "Setting SHM file permissions" + chown grimoire:grimoire /app/data/db.sqlite-shm + chmod 644 /app/data/db.sqlite-shm +fi + +echo "Data directory permissions initialized successfully" \ No newline at end of file diff --git a/package.json b/package.json index 165c430..8f82948 100644 --- a/package.json +++ b/package.json @@ -38,64 +38,65 @@ }, "type": "module", "devDependencies": { - "@libsql/client": "^0.11.0", - "@sveltejs/adapter-auto": "^3.2.4", + "@libsql/client": "^0.15.7", + "@sveltejs/adapter-auto": "^3.3.1", "@sveltejs/kit": "^2.5.27", "@tailwindcss/typography": "^0.5.14", "@types/adm-zip": "^0.5.5", - "@types/bun": "^1.1.9", - "@types/express": "^4.17.21", + "@types/bun": "^1.2.13", + "@types/express": "^4.17.22", "@types/express-http-proxy": "^1.6.6", "@types/swagger-ui": "^3.52.4", - "@typescript-eslint/eslint-plugin": "^8.5.0", - "@typescript-eslint/parser": "^8.5.0", - "@vitest/coverage-v8": "^2.1.1", - "autoprefixer": "^10.4.20", - "drizzle-kit": "^0.24.2", - "eslint": "^9.10.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-perfectionist": "^3.6.0", - "eslint-plugin-svelte": "^2.44.0", - "postcss": "^8.4.47", + "@typescript-eslint/eslint-plugin": "^8.32.1", + "@typescript-eslint/parser": "^8.32.1", + "@vitest/coverage-v8": "^2.1.9", + "autoprefixer": "^10.4.21", + "drizzle-kit": "^0.31.1", + "eslint": "^9.27.0", + "eslint-config-prettier": "^10.1.5", + "eslint-plugin-perfectionist": "^3.9.1", + "eslint-plugin-svelte": "^2.46.1", + "postcss": "^8.5.3", "prettier": "^3.3.3", "prettier-plugin-svelte": "^3.2.6", - "prettier-plugin-tailwindcss": "^0.6.6", - "release-it": "^17.6.0", - "svelte": "^4.2.19", + "prettier-plugin-tailwindcss": "^0.6.11", + "release-it": "^19.0.2", + "svelte": "^4.2.20", "svelte-adapter-bun": "^0.5.2", - "svelte-check": "^4.0.2", - "tailwindcss": "^3.4.11", - "tslib": "^2.7.0", - "typescript": "^5.6.2", - "vite": "^5.4.5", - "vitest": "^2.1.1" + "svelte-check": "^4.2.1", + "tailwindcss": "^3.4.17", + "tslib": "^2.8.1", + "typescript": "^5.8.3", + "vite": "^5.4.19", + "vitest": "^2.1.9" }, "dependencies": { "@extractus/article-extractor": "^8.0.10", "@lucia-auth/adapter-drizzle": "^1.1.0", - "@sveltejs/vite-plugin-svelte": "^3.1.2", + "@node-rs/argon2": "^2.0.2", + "@sveltejs/vite-plugin-svelte": "^3.0.0", "@tabler/icons": "^3.16.0", "@tabler/icons-svelte": "^3.16.0", "@tailwindcss/line-clamp": "^0.4.4", "@types/html-to-text": "^9.0.4", "@types/sanitize-html": "^2.13.0", "adm-zip": "^0.5.16", - "chalk": "^5.3.0", - "daisyui": "^4.12.10", - "dotenv": "^16.4.5", - "drizzle-orm": "^0.33.0", + "chalk": "^5.4.1", + "daisyui": "^4.12.24", + "dotenv": "^16.5.0", + "drizzle-orm": "^0.43.1", "es-toolkit": "^1.31.0", "eslint-plugin-drizzle": "^0.2.3", - "express": "^4.21.0", + "express": "^4.21.2", "fuse.js": "^7.0.0", "html-to-text": "^9.0.5", "joi": "^17.13.3", - "lucia": "^3.2.0", + "lucia": "^3.2.2", "node-parse-bookmarks": "^1.0.3", "sanitize-html": "^2.13.0", "svelte-french-toast": "^1.2.0", "svelte-select": "^5.8.3", - "swagger-ui": "^5.17.14", - "url-metadata": "^4.1.1" + "swagger-ui": "^5.21.0", + "url-metadata": "^4.1.4" } } diff --git a/src/lib/database/db.ts b/src/lib/database/db.ts index 6bb0fff..618ce25 100644 --- a/src/lib/database/db.ts +++ b/src/lib/database/db.ts @@ -1,5 +1,6 @@ import { Database } from 'bun:sqlite'; import { drizzle } from 'drizzle-orm/bun-sqlite'; +import fs from 'fs'; import path from 'path'; import * as schema from './schema'; @@ -12,7 +13,14 @@ class DbConnection { private db: Database; private constructor() { - this.db = new Database(path.join(path.resolve(process.cwd(), 'data'), 'db.sqlite'), { + const dbPath = path.join(path.resolve(process.cwd(), 'data'), 'db.sqlite'); + + const dataDir = path.dirname(dbPath); + if (!fs.existsSync(dataDir)) { + fs.mkdirSync(dataDir, { recursive: true }); + } + + this.db = new Database(dbPath, { create: true }); this.db.exec('PRAGMA journal_mode = WAL;'); diff --git a/src/routes/logout/+page.svelte b/src/routes/logout/+page.svelte index c92fbed..3cc0361 100644 --- a/src/routes/logout/+page.svelte +++ b/src/routes/logout/+page.svelte @@ -1 +1,25 @@ -
Logged out
+ + +
+ {#if mounted} +
+

Logging out...

+
+ {:else} +

Loading...

+ {/if} +