diff --git a/Dockerfile b/Dockerfile index ae1b1e5a..47349bd6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # Use the official Bun image (Bun doesn't run well on Musl but this seems to work) # See all versions at https://hub.docker.com/r/oven/bun/tags -FROM oven/bun:1.1.2-alpine as base +FROM imbios/bun-node:1.1.2-current-alpine as base # Install dependencies into temp directory # This will cache them and speed up future builds @@ -14,9 +14,6 @@ RUN bun install --frozen-lockfile FROM base as build -# Required for Prisma to work -# COPY --from=node:18-alpine /usr/local/bin/node /usr/local/bin/node - # Copy the project RUN mkdir -p /temp COPY . /temp @@ -24,10 +21,11 @@ COPY . /temp COPY --from=install /temp/node_modules /temp/node_modules # Build the project WORKDIR /temp +RUN bunx --bun prisma generate RUN bun run prod-build # copy production dependencies and source code into final image -FROM base AS release +FROM oven/bun:1.1.2-alpine # Create app directory RUN mkdir -p /app @@ -44,5 +42,6 @@ LABEL org.opencontainers.image.description "Lysand Server docker image" # CD to app WORKDIR /app ENV NODE_ENV=production +ENTRYPOINT [ "/bin/sh", "entrypoint.sh" ] # Run migrations and start the server -CMD [ "./entrypoint.sh" "start" ] +CMD [ "start" ] diff --git a/build.ts b/build.ts index 1f177970..b8856dcd 100644 --- a/build.ts +++ b/build.ts @@ -1,4 +1,5 @@ // Delete dist directory +import { $ } from "bun"; import { cp, exists, mkdir, rm } from "node:fs/promises"; import { rawRoutes } from "~routes"; @@ -13,7 +14,6 @@ await rm("./dist", { recursive: true }); await mkdir(`${process.cwd()}/dist`); -//bun build --entrypoints ./index.ts ./prisma.ts ./cli.ts --outdir dist --target bun --splitting --minify --external bullmq,@prisma/client await Bun.build({ entrypoints: [ `${process.cwd()}/index.ts`, @@ -25,7 +25,7 @@ await Bun.build({ outdir: `${process.cwd()}/dist`, target: "bun", splitting: true, - minify: true, + minify: false, external: ["bullmq"], }).then((output) => { if (!output.success) { @@ -33,6 +33,10 @@ await Bun.build({ } }); +// Fix for wrong Bun file resolution, replaces node_modules with ./node_modules inside all dynamic imports +// I apologize for this +await $`sed -i 's|import("node_modules/|import("./node_modules/|g' dist/*.js`; + // Create pages directory // mkdir ./dist/pages await mkdir(`${process.cwd()}/dist/pages`); diff --git a/bun.lockb b/bun.lockb index 92ed0512..3f886810 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/entrypoint.sh b/entrypoint.sh index 5db0a98c..ae7d86a0 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -9,23 +9,25 @@ # Exit immediately if a command exits with a non-zero status. set -e +cd ./dist + # Parse first argument case "$1" in "start") # Start the server - exec bun run ./dist/index.js --prod + exec bun run ./index.js --prod ;; "cli") # Start the CLI shift 1 - exec bun run ./dist/cli.js "$@" + exec bun run ./cli.js "$@" ;; "prisma") # Proxy all Prisma commands # Use output of dist/prisma.js to get the env variable shift 1 # Set DATABASE_URL env variable to the output of bun run ./dist/prisma.js - export DATABASE_URL=$(bun run ./dist/prisma.js) + export DATABASE_URL=$(bun run ./prisma.js) # Execute the Prisma binary exec bunx prisma "$@" ;; diff --git a/index.ts b/index.ts index 462bfcd7..75fa44e3 100644 --- a/index.ts +++ b/index.ts @@ -1,4 +1,5 @@ -import { exists, mkdir } from "node:fs/promises"; +import { exists, mkdir, writeFile } from "node:fs/promises"; +import { dirname } from "node:path"; import { connectMeili } from "@meilisearch"; import { moduleIsEntry } from "@module"; import type { PrismaClientInitializationError } from "@prisma/client/runtime/library"; @@ -10,7 +11,18 @@ import { createServer } from "~server"; const timeAtStart = performance.now(); -const requests_log = Bun.file(`${process.cwd()}/logs/requests.log`); +// Create requests file if it doesnt exist +if ( + !(await exists( + `${process.cwd()}/${dirname(config.logging.storage.requests)}`, + )) +) { + await mkdir(`${process.cwd()}/${dirname(config.logging.storage.requests)}`); + await writeFile(`${process.cwd()}/${config.logging.storage.requests}`, ""); +} +const requests_log = Bun.file( + `${process.cwd()}/${config.logging.storage.requests}`, +); const isEntry = moduleIsEntry(import.meta.url); // If imported as a module, redirect logs to /dev/null to not pollute console (e.g. in tests) const logger = new LogManager(isEntry ? requests_log : Bun.file("/dev/null")); @@ -19,16 +31,6 @@ const consoleLogger = new LogManager( ); const dualLogger = new MultiLogManager([logger, consoleLogger]); -if (!(await exists(config.logging.storage.requests))) { - await consoleLogger.log( - LogLevel.WARNING, - "Lysand", - `Creating logs directory at ${process.cwd()}/logs/`, - ); - - await mkdir(`${process.cwd()}/logs/`); -} - await dualLogger.log(LogLevel.INFO, "Lysand", "Starting Lysand..."); // NODE_ENV seems to be broken and output `development` even when set to production, so use the flag instead diff --git a/package.json b/package.json index 9b0b7b93..3f7ff857 100644 --- a/package.json +++ b/package.json @@ -1,118 +1,118 @@ { - "name": "lysand", - "module": "index.ts", - "type": "module", - "version": "0.3.0", - "description": "A project to build a federated social network", - "author": { - "email": "contact@cpluspatch.com", - "name": "CPlusPatch", - "url": "https://cpluspatch.com" - }, - "bugs": { - "url": "https://github.com/lysand-org/lysand/issues" - }, - "icon": "https://github.com/lysand-org/lysand", - "license": "AGPL-3.0", - "keywords": ["federated", "activitypub", "bun"], - "workspaces": ["packages/*"], - "maintainers": [ - { - "email": "contact@cpluspatch.com", - "name": "CPlusPatch", - "url": "https://cpluspatch.com" + "name": "lysand", + "module": "index.ts", + "type": "module", + "version": "0.3.0", + "description": "A project to build a federated social network", + "author": { + "email": "contact@cpluspatch.com", + "name": "CPlusPatch", + "url": "https://cpluspatch.com" + }, + "bugs": { + "url": "https://github.com/lysand-org/lysand/issues" + }, + "icon": "https://github.com/lysand-org/lysand", + "license": "AGPL-3.0", + "keywords": ["federated", "activitypub", "bun"], + "workspaces": ["packages/*"], + "maintainers": [ + { + "email": "contact@cpluspatch.com", + "name": "CPlusPatch", + "url": "https://cpluspatch.com" + } + ], + "repository": { + "type": "git", + "url": "git+https://github.com/lysand-org/lysand.git" + }, + "private": true, + "scripts": { + "dev": "bun run --watch index.ts", + "vite:dev": "bunx --bun vite pages", + "vite:build": "bunx --bun vite build pages", + "start": "NODE_ENV=production bun run dist/index.js --prod", + "migrate-dev": "bun prisma migrate dev", + "migrate": "bun prisma migrate deploy", + "lint": "bunx --bun eslint --config .eslintrc.cjs --ext .ts .", + "prod-build": "bunx --bun vite build pages && bun run build.ts", + "prisma": "DATABASE_URL=$(bun run prisma.ts) bunx prisma", + "generate": "bun prisma generate", + "benchmark:timeline": "bun run benchmarks/timelines.ts", + "cloc": "cloc . --exclude-dir node_modules,dist", + "cli": "bun run cli.ts" + }, + "trustedDependencies": [ + "@biomejs/biome", + "@prisma/client", + "@prisma/engines", + "esbuild", + "prisma", + "sharp", + "msgpackr-extract" + ], + "devDependencies": { + "@biomejs/biome": "1.6.4", + "@julr/unocss-preset-forms": "^0.1.0", + "@types/cli-table": "^0.3.4", + "@types/html-to-text": "^9.0.4", + "@types/ioredis": "^5.0.0", + "@types/jsonld": "^1.5.13", + "@typescript-eslint/eslint-plugin": "latest", + "@unocss/cli": "latest", + "@vitejs/plugin-vue": "latest", + "@vueuse/head": "^2.0.0", + "activitypub-types": "^1.0.3", + "bun-types": "latest", + "typescript": "latest", + "unocss": "latest", + "untyped": "^1.4.2", + "vite": "^5.2.8", + "vite-ssr": "^0.17.1", + "vue": "^3.3.9", + "vue-router": "^4.2.5", + "vue-tsc": "latest" + }, + "peerDependencies": { + "typescript": "^5.3.2" + }, + "dependencies": { + "@aws-sdk/client-s3": "^3.461.0", + "@iarna/toml": "^2.2.5", + "@json2csv/plainjs": "^7.0.6", + "@prisma/client": "^5.6.0", + "blurhash": "^2.0.5", + "bullmq": "latest", + "chalk": "^5.3.0", + "cli-parser": "workspace:*", + "cli-table": "^0.3.11", + "config-manager": "workspace:*", + "eventemitter3": "^5.0.1", + "extract-zip": "^2.0.1", + "html-to-text": "^9.0.5", + "ioredis": "^5.3.2", + "ip-matching": "^2.1.2", + "iso-639-1": "^3.1.0", + "isomorphic-dompurify": "latest", + "jsonld": "^8.3.1", + "linkify-html": "^4.1.3", + "linkify-string": "^4.1.3", + "linkifyjs": "^4.1.3", + "log-manager": "workspace:*", + "marked": "latest", + "media-manager": "workspace:*", + "megalodon": "^10.0.0", + "meilisearch": "latest", + "merge-deep-ts": "^1.2.6", + "next-route-matcher": "^1.0.1", + "oauth4webapi": "^2.4.0", + "prisma": "^5.6.0", + "prisma-json-types-generator": "^3.0.4", + "prisma-redis-middleware": "^4.8.0", + "request-parser": "workspace:*", + "semver": "^7.5.4", + "sharp": "^0.33.0-rc.2", + "strip-ansi": "^7.1.0" } - ], - "repository": { - "type": "git", - "url": "git+https://github.com/lysand-org/lysand.git" - }, - "private": true, - "scripts": { - "dev": "bun run --watch index.ts", - "vite:dev": "bunx --bun vite pages", - "vite:build": "bunx --bun vite build pages", - "start": "NODE_ENV=production bun run dist/index.js --prod", - "migrate-dev": "bun prisma migrate dev", - "migrate": "bun prisma migrate deploy", - "lint": "bunx --bun eslint --config .eslintrc.cjs --ext .ts .", - "prod-build": "bunx --bun vite build pages && bun run build.ts", - "prisma": "DATABASE_URL=$(bun run prisma.ts) bunx prisma", - "generate": "bun prisma generate", - "benchmark:timeline": "bun run benchmarks/timelines.ts", - "cloc": "cloc . --exclude-dir node_modules,dist", - "cli": "bun run cli.ts" - }, - "trustedDependencies": [ - "@biomejs/biome", - "@prisma/client", - "@prisma/engines", - "esbuild", - "prisma", - "sharp" - ], - "devDependencies": { - "@biomejs/biome": "1.6.4", - "@julr/unocss-preset-forms": "^0.1.0", - "@types/cli-table": "^0.3.4", - "@types/html-to-text": "^9.0.4", - "@types/ioredis": "^5.0.0", - "@types/jsonld": "^1.5.13", - "@typescript-eslint/eslint-plugin": "latest", - "@unocss/cli": "latest", - "@vitejs/plugin-vue": "latest", - "@vueuse/head": "^2.0.0", - "activitypub-types": "^1.0.3", - "bun-types": "latest", - "typescript": "latest", - "unocss": "latest", - "untyped": "^1.4.2", - "vite": "^5.2.8", - "vite-ssr": "^0.17.1", - "vue": "^3.3.9", - "vue-router": "^4.2.5", - "vue-tsc": "latest" - }, - "peerDependencies": { - "typescript": "^5.3.2" - }, - "dependencies": { - "@aws-sdk/client-s3": "^3.461.0", - "@iarna/toml": "^2.2.5", - "@json2csv/plainjs": "^7.0.6", - "@prisma/client": "^5.6.0", - "blurhash": "^2.0.5", - "bullmq": "latest", - "c12": "^1.10.0", - "chalk": "^5.3.0", - "cli-parser": "workspace:*", - "cli-table": "^0.3.11", - "config-manager": "workspace:*", - "eventemitter3": "^5.0.1", - "extract-zip": "^2.0.1", - "html-to-text": "^9.0.5", - "ioredis": "^5.3.2", - "ip-matching": "^2.1.2", - "iso-639-1": "^3.1.0", - "isomorphic-dompurify": "latest", - "jsonld": "^8.3.1", - "linkify-html": "^4.1.3", - "linkify-string": "^4.1.3", - "linkifyjs": "^4.1.3", - "log-manager": "workspace:*", - "marked": "latest", - "media-manager": "workspace:*", - "megalodon": "^10.0.0", - "meilisearch": "latest", - "merge-deep-ts": "^1.2.6", - "next-route-matcher": "^1.0.1", - "oauth4webapi": "^2.4.0", - "prisma": "^5.6.0", - "prisma-json-types-generator": "^3.0.4", - "prisma-redis-middleware": "^4.8.0", - "request-parser": "workspace:*", - "semver": "^7.5.4", - "sharp": "^0.33.0-rc.2", - "strip-ansi": "^7.1.0" - } } diff --git a/packages/config-manager/package.json b/packages/config-manager/package.json index b1e8fdfd..97c2dac6 100644 --- a/packages/config-manager/package.json +++ b/packages/config-manager/package.json @@ -2,5 +2,9 @@ "name": "config-manager", "version": "0.0.0", "main": "index.ts", - "dependencies": { "@iarna/toml": "^2.2.5", "merge-deep-ts": "^1.2.6" } + "dependencies": { + "@iarna/toml": "^2.2.5", + "c12": "^1.10.0", + "merge-deep-ts": "^1.2.6" + } } diff --git a/packages/log-manager/index.ts b/packages/log-manager/index.ts index 89790d7f..bbed3dea 100644 --- a/packages/log-manager/index.ts +++ b/packages/log-manager/index.ts @@ -1,4 +1,5 @@ -import { appendFile } from "node:fs/promises"; +import { appendFile, writeFile, mkdir, exists } from "node:fs/promises"; +import { dirname } from "node:path"; import type { BunFile } from "bun"; export enum LogLevel { @@ -44,11 +45,17 @@ export class LogManager { if (this.output === Bun.stdout) { await Bun.write(Bun.stdout, `${text}\n`); } else { - if (!(await this.output.exists())) { + if (!(await exists(this.output.name ?? ""))) { // Create file if it doesn't exist - await Bun.write(this.output, "", { - createPath: true, - }); + try { + await mkdir(dirname(this.output.name ?? ""), { + recursive: true, + }); + await writeFile(this.output.name ?? "", ""); + this.output = Bun.file(this.output.name ?? ""); + } catch { + // + } } await appendFile(this.output.name ?? "", `${text}\n`); } diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 177c3633..603a5a76 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -1,7 +1,7 @@ generator client { provider = "prisma-client-js" previewFeatures = ["postgresqlExtensions"] - binaryTargets = ["native", "debian-openssl-3.0.x"] + binaryTargets = ["native"] } generator json {