From b2cf4b50cb9b25d198168a67701164ebd898bfe4 Mon Sep 17 00:00:00 2001 From: ComplementaryPogo Date: Mon, 15 Dec 2025 02:28:02 -0600 Subject: [PATCH 01/13] Dockerfile and dockerignore --- .dockerignore | 45 +++++++++++++++++++++++++++++++++++++++++++++ Dockerfile | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..3de65df --- /dev/null +++ b/.dockerignore @@ -0,0 +1,45 @@ +# Dependencies +node_modules + +# Build output +build +.svelte-kit + +# Git +.git +.gitignore + +# IDE +.vscode +.idea +*.swp +*.swo + +# Logs +logs +*.log +npm-debug.log* + +# OS files +.DS_Store +Thumbs.db + +# Docker +Dockerfile +docker-compose*.yml +.dockerignore + +# Documentation +README.md +LICENSE +*.md + +# Development/Test +.env.local +.env.*.local +coverage +.nyc_output + +# Config (mounted at runtime, not baked in) +# Keep config examples for build stage +!config/*.example.* diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c876d7f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,47 @@ +FROM node:22-slim AS base +RUN corepack enable && corepack prepare pnpm@latest --activate +WORKDIR /app + +FROM base AS deps + +COPY package.json pnpm-lock.yaml ./ +COPY patches ./patches/ +RUN pnpm install --frozen-lockfile + +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . +RUN mkdir -p src/routes/\(custom\) && \ + mkdir -p src/components/custom && \ + mkdir -p src/lib/server && \ + cp config/custom.example.css config/custom.css && \ + cp config/Home.example.svelte config/Home.svelte && \ + cp config/config.example.toml config/config.toml && \ + ln config/custom.css src/custom.css && \ + ln config/Home.svelte src/components/custom/Home.svelte && \ + ln config/config.toml src/lib/server/config.toml +RUN pnpm run build + +FROM node:22-slim AS runtime +RUN apt-get update && apt-get install -y --no-install-recommends \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* +WORKDIR /app +RUN groupadd --gid 1001 diadem && \ + useradd --uid 1001 --gid diadem --shell /bin/bash --create-home diadem +COPY --from=builder --chown=diadem:diadem /app/build ./build +COPY --from=builder --chown=diadem:diadem /app/package.json ./ +COPY --from=deps --chown=diadem:diadem /app/node_modules ./node_modules +RUN mkdir -p /app/config && chown diadem:diadem /app/config +USER diadem +ENV NODE_ENV=production +ENV HOST=0.0.0.0 +ENV PORT=3900 + +EXPOSE 3900 + +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ + CMD node -e "fetch('http://localhost:${PORT:-3900}').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))" + +CMD ["node", "build/index.js"] From a9ac9c297382abf890ce9065d68a4b954d1a5a02 Mon Sep 17 00:00:00 2001 From: ComplementaryPogo Date: Mon, 15 Dec 2025 02:59:18 -0600 Subject: [PATCH 02/13] Docker entrypoint for DB --- .env.example | 8 ++++++ Dockerfile | 12 ++++++-- docker-compose.yml | 65 ++++++++++++++++++++++++++++++++++++++++++++ docker-entrypoint.sh | 17 ++++++++++++ 4 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 .env.example create mode 100644 docker-compose.yml create mode 100644 docker-entrypoint.sh diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..8fea93c --- /dev/null +++ b/.env.example @@ -0,0 +1,8 @@ +# Diadem Application +DIADEM_PORT=3900 + +# MariaDB Database (Diadem Internal) +MARIADB_ROOT_PASSWORD=changeme_root +MARIADB_DATABASE=diadem +MARIADB_USER=diadem +MARIADB_PASSWORD=changeme diff --git a/Dockerfile b/Dockerfile index c876d7f..b624c22 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,7 +33,15 @@ RUN groupadd --gid 1001 diadem && \ COPY --from=builder --chown=diadem:diadem /app/build ./build COPY --from=builder --chown=diadem:diadem /app/package.json ./ COPY --from=deps --chown=diadem:diadem /app/node_modules ./node_modules + +# Files needed for drizzle-kit db:push at runtime +COPY --from=builder --chown=diadem:diadem /app/drizzle.config.ts ./ +COPY --from=builder --chown=diadem:diadem /app/src/lib/server/db ./src/lib/server/db +COPY --from=builder --chown=diadem:diadem /app/src/lib/services ./src/lib/services + RUN mkdir -p /app/config && chown diadem:diadem /app/config +COPY --chown=diadem:diadem docker-entrypoint.sh ./ +RUN chmod +x docker-entrypoint.sh USER diadem ENV NODE_ENV=production ENV HOST=0.0.0.0 @@ -41,7 +49,7 @@ ENV PORT=3900 EXPOSE 3900 -HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ +HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \ CMD node -e "fetch('http://localhost:${PORT:-3900}').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))" -CMD ["node", "build/index.js"] +ENTRYPOINT ["./docker-entrypoint.sh"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d4fb93d --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,65 @@ +services: + diadem: + build: + context: . + dockerfile: Dockerfile + image: diadem:latest + container_name: diadem + restart: unless-stopped + ports: + - "${DIADEM_PORT:-3900}:3900" + environment: + - NODE_ENV=production + - HOST=0.0.0.0 + - PORT=3900 + volumes: + # Required: Mount your config file (both paths needed for runtime and db:push) + - ./config/config.toml:/app/build/server/config.toml:ro + - ./config/config.toml:/app/src/lib/server/config.toml:ro + # Optional: Persistent logs + - diadem-logs:/app/logs + depends_on: + diadem-db: + condition: service_healthy + networks: + - diadem-network + healthcheck: + test: ["CMD", "node", "-e", "fetch('http://localhost:3900').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + + diadem-db: + image: mariadb:11.4 + container_name: diadem-db + restart: unless-stopped + environment: + MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD:-changeme_root} + MARIADB_DATABASE: ${MARIADB_DATABASE:-diadem} + MARIADB_USER: ${MARIADB_USER:-diadem} + MARIADB_PASSWORD: ${MARIADB_PASSWORD:-changeme} + volumes: + - diadem-db-data:/var/lib/mysql + networks: + - diadem-network + healthcheck: + test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + command: + - --character-set-server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci + +volumes: + diadem-db-data: + name: diadem-db-data + diadem-logs: + name: diadem-logs + +networks: + diadem-network: + name: diadem-network + driver: bridge diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..64e4b32 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,17 @@ +#!/bin/sh +set -e + +# Only run db:push if the database appears to be uninitialized +# This prevents accidental destructive schema changes in production +if [ "${SKIP_DB_PUSH:-}" = "true" ]; then + echo "Skipping database push (SKIP_DB_PUSH=true)" +elif [ "${FORCE_DB_PUSH:-}" = "true" ]; then + echo "Running database push (forced)..." + npx drizzle-kit push --force +else + echo "Running database push..." + npx drizzle-kit push +fi + +echo "Starting Diadem..." +exec node build/index.js From ef586b987a3182d57f4a04df2e6653903c5fdb58 Mon Sep 17 00:00:00 2001 From: ComplementaryPogo Date: Mon, 15 Dec 2025 03:14:22 -0600 Subject: [PATCH 03/13] Makefile for helping push to docker easily --- Makefile | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..966d929 --- /dev/null +++ b/Makefile @@ -0,0 +1,111 @@ +# Diadem Docker Build & Release Makefile + +# Registry and image configuration (override with environment variables) +REGISTRY ?= ghcr.io +REPOSITORY ?= ccev/diadem +IMAGE_NAME ?= $(REGISTRY)/$(REPOSITORY) + +# Version tagging (defaults to git short hash) +GIT_HASH := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown") +GIT_DIRTY := $(shell git diff --quiet 2>/dev/null || echo "-dirty") +VERSION ?= $(GIT_HASH)$(GIT_DIRTY) + +# Additional tags +LATEST_TAG ?= latest + +# Docker build options +DOCKER_BUILD_ARGS ?= +DOCKER_PLATFORM ?= linux/amd64,linux/arm64 +DOCKERFILE ?= Dockerfile + +# Helm chart +HELM_CHART_PATH := helm/diadem + +.PHONY: help build release build-and-release tag clean lint helm-lint helm-package + +help: ## Show this help message + @echo "Diadem Docker Build & Release" + @echo "" + @echo "Usage: make [target]" + @echo "" + @echo "Configuration (override with environment variables):" + @echo " REGISTRY = $(REGISTRY)" + @echo " REPOSITORY = $(REPOSITORY)" + @echo " IMAGE_NAME = $(IMAGE_NAME)" + @echo " VERSION = $(VERSION)" + @echo "" + @echo "Targets:" + @awk 'BEGIN {FS = ":.*##"; printf ""} /^[a-zA-Z_-]+:.*?##/ { printf " %-15s %s\n", $$1, $$2 }' $(MAKEFILE_LIST) + +build: ## Build image for local platform only + docker build \ + --tag $(IMAGE_NAME):$(VERSION) \ + --tag $(IMAGE_NAME):$(LATEST_TAG) \ + --file $(DOCKERFILE) \ + $(DOCKER_BUILD_ARGS) \ + . + +release: ## Push locally built image to registry + docker push $(IMAGE_NAME):$(VERSION) + docker push $(IMAGE_NAME):$(LATEST_TAG) + +build-and-release: ## Build multi-platform image and push to registry + docker buildx build \ + --platform $(DOCKER_PLATFORM) \ + --tag $(IMAGE_NAME):$(VERSION) \ + --tag $(IMAGE_NAME):$(LATEST_TAG) \ + --file $(DOCKERFILE) \ + --push \ + $(DOCKER_BUILD_ARGS) \ + . + +tag: ## Tag an existing image with a new tag (e.g., make tag VERSION=abc123 NEW_TAG=v1.0.0) + @test -n "$(NEW_TAG)" || (echo "NEW_TAG is required" && exit 1) + docker buildx imagetools create \ + --tag $(IMAGE_NAME):$(NEW_TAG) \ + $(IMAGE_NAME):$(VERSION) + +clean: ## Remove local images + -docker rmi $(IMAGE_NAME):$(VERSION) 2>/dev/null + -docker rmi $(IMAGE_NAME):$(LATEST_TAG) 2>/dev/null + +lint: ## Lint Dockerfile with hadolint + @command -v hadolint >/dev/null 2>&1 && hadolint $(DOCKERFILE) || \ + docker run --rm -i hadolint/hadolint < $(DOCKERFILE) + +helm-lint: ## Lint Helm chart + helm lint $(HELM_CHART_PATH) + +helm-package: ## Package Helm chart + helm package $(HELM_CHART_PATH) + +helm-template: ## Render Helm chart templates + helm template diadem $(HELM_CHART_PATH) + +# Docker Compose targets +.PHONY: up down logs + +up: ## Start services with docker-compose + docker compose up -d + +down: ## Stop services with docker-compose + docker compose down + +logs: ## View docker-compose logs + docker compose logs -f + +# Development helpers +.PHONY: setup-buildx info + +setup-buildx: ## Set up Docker buildx for multi-platform builds + docker buildx create --name diadem-builder --use 2>/dev/null || docker buildx use diadem-builder + docker buildx inspect --bootstrap + +info: ## Show build configuration + @echo "Registry: $(REGISTRY)" + @echo "Repository: $(REPOSITORY)" + @echo "Image: $(IMAGE_NAME)" + @echo "Version: $(VERSION)" + @echo "Git Hash: $(GIT_HASH)" + @echo "Platforms: $(DOCKER_PLATFORM)" + @echo "Dockerfile: $(DOCKERFILE)" From cbbf46dc8202da03eafd040279602f5094e6c460 Mon Sep 17 00:00:00 2001 From: ComplementaryPogo Date: Mon, 15 Dec 2025 03:16:16 -0600 Subject: [PATCH 04/13] Use DIADEM_DOCKER prefix actually --- Makefile | 72 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/Makefile b/Makefile index 966d929..ba23f38 100644 --- a/Makefile +++ b/Makefile @@ -1,22 +1,22 @@ # Diadem Docker Build & Release Makefile # Registry and image configuration (override with environment variables) -REGISTRY ?= ghcr.io -REPOSITORY ?= ccev/diadem -IMAGE_NAME ?= $(REGISTRY)/$(REPOSITORY) +DIADEM_DOCKER_REGISTRY ?= ghcr.io +DIADEM_DOCKER_REPOSITORY ?= ccev/diadem +DIADEM_DOCKER_IMAGE ?= $(DIADEM_DOCKER_REGISTRY)/$(DIADEM_DOCKER_REPOSITORY) # Version tagging (defaults to git short hash) GIT_HASH := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown") GIT_DIRTY := $(shell git diff --quiet 2>/dev/null || echo "-dirty") -VERSION ?= $(GIT_HASH)$(GIT_DIRTY) +DIADEM_DOCKER_VERSION ?= $(GIT_HASH)$(GIT_DIRTY) # Additional tags -LATEST_TAG ?= latest +DIADEM_DOCKER_LATEST_TAG ?= latest # Docker build options -DOCKER_BUILD_ARGS ?= -DOCKER_PLATFORM ?= linux/amd64,linux/arm64 -DOCKERFILE ?= Dockerfile +DIADEM_DOCKER_BUILD_ARGS ?= +DIADEM_DOCKER_PLATFORM ?= linux/amd64,linux/arm64 +DIADEM_DOCKER_FILE ?= Dockerfile # Helm chart HELM_CHART_PATH := helm/diadem @@ -29,49 +29,49 @@ help: ## Show this help message @echo "Usage: make [target]" @echo "" @echo "Configuration (override with environment variables):" - @echo " REGISTRY = $(REGISTRY)" - @echo " REPOSITORY = $(REPOSITORY)" - @echo " IMAGE_NAME = $(IMAGE_NAME)" - @echo " VERSION = $(VERSION)" + @echo " DIADEM_DOCKER_REGISTRY = $(DIADEM_DOCKER_REGISTRY)" + @echo " DIADEM_DOCKER_REPOSITORY = $(DIADEM_DOCKER_REPOSITORY)" + @echo " DIADEM_DOCKER_IMAGE = $(DIADEM_DOCKER_IMAGE)" + @echo " DIADEM_DOCKER_VERSION = $(DIADEM_DOCKER_VERSION)" @echo "" @echo "Targets:" @awk 'BEGIN {FS = ":.*##"; printf ""} /^[a-zA-Z_-]+:.*?##/ { printf " %-15s %s\n", $$1, $$2 }' $(MAKEFILE_LIST) build: ## Build image for local platform only docker build \ - --tag $(IMAGE_NAME):$(VERSION) \ - --tag $(IMAGE_NAME):$(LATEST_TAG) \ - --file $(DOCKERFILE) \ - $(DOCKER_BUILD_ARGS) \ + --tag $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_VERSION) \ + --tag $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_LATEST_TAG) \ + --file $(DIADEM_DOCKER_FILE) \ + $(DIADEM_DOCKER_BUILD_ARGS) \ . release: ## Push locally built image to registry - docker push $(IMAGE_NAME):$(VERSION) - docker push $(IMAGE_NAME):$(LATEST_TAG) + docker push $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_VERSION) + docker push $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_LATEST_TAG) build-and-release: ## Build multi-platform image and push to registry docker buildx build \ - --platform $(DOCKER_PLATFORM) \ - --tag $(IMAGE_NAME):$(VERSION) \ - --tag $(IMAGE_NAME):$(LATEST_TAG) \ - --file $(DOCKERFILE) \ + --platform $(DIADEM_DOCKER_PLATFORM) \ + --tag $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_VERSION) \ + --tag $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_LATEST_TAG) \ + --file $(DIADEM_DOCKER_FILE) \ --push \ - $(DOCKER_BUILD_ARGS) \ + $(DIADEM_DOCKER_BUILD_ARGS) \ . -tag: ## Tag an existing image with a new tag (e.g., make tag VERSION=abc123 NEW_TAG=v1.0.0) +tag: ## Tag an existing image with a new tag (e.g., make tag NEW_TAG=v1.0.0) @test -n "$(NEW_TAG)" || (echo "NEW_TAG is required" && exit 1) docker buildx imagetools create \ - --tag $(IMAGE_NAME):$(NEW_TAG) \ - $(IMAGE_NAME):$(VERSION) + --tag $(DIADEM_DOCKER_IMAGE):$(NEW_TAG) \ + $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_VERSION) clean: ## Remove local images - -docker rmi $(IMAGE_NAME):$(VERSION) 2>/dev/null - -docker rmi $(IMAGE_NAME):$(LATEST_TAG) 2>/dev/null + -docker rmi $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_VERSION) 2>/dev/null + -docker rmi $(DIADEM_DOCKER_IMAGE):$(DIADEM_DOCKER_LATEST_TAG) 2>/dev/null lint: ## Lint Dockerfile with hadolint - @command -v hadolint >/dev/null 2>&1 && hadolint $(DOCKERFILE) || \ - docker run --rm -i hadolint/hadolint < $(DOCKERFILE) + @command -v hadolint >/dev/null 2>&1 && hadolint $(DIADEM_DOCKER_FILE) || \ + docker run --rm -i hadolint/hadolint < $(DIADEM_DOCKER_FILE) helm-lint: ## Lint Helm chart helm lint $(HELM_CHART_PATH) @@ -102,10 +102,10 @@ setup-buildx: ## Set up Docker buildx for multi-platform builds docker buildx inspect --bootstrap info: ## Show build configuration - @echo "Registry: $(REGISTRY)" - @echo "Repository: $(REPOSITORY)" - @echo "Image: $(IMAGE_NAME)" - @echo "Version: $(VERSION)" + @echo "Registry: $(DIADEM_DOCKER_REGISTRY)" + @echo "Repository: $(DIADEM_DOCKER_REPOSITORY)" + @echo "Image: $(DIADEM_DOCKER_IMAGE)" + @echo "Version: $(DIADEM_DOCKER_VERSION)" @echo "Git Hash: $(GIT_HASH)" - @echo "Platforms: $(DOCKER_PLATFORM)" - @echo "Dockerfile: $(DOCKERFILE)" + @echo "Platforms: $(DIADEM_DOCKER_PLATFORM)" + @echo "Dockerfile: $(DIADEM_DOCKER_FILE)" From a30cf63f7b187be17387584857bf0846e3d4badf Mon Sep 17 00:00:00 2001 From: ComplementaryPogo Date: Mon, 15 Dec 2025 05:09:32 -0600 Subject: [PATCH 05/13] Config file paths # Conflicts: # src/lib/services/config/configNode.server.ts --- docker-compose.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index d4fb93d..a10caa6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,9 +13,8 @@ services: - HOST=0.0.0.0 - PORT=3900 volumes: - # Required: Mount your config file (both paths needed for runtime and db:push) - - ./config/config.toml:/app/build/server/config.toml:ro - - ./config/config.toml:/app/src/lib/server/config.toml:ro + # Required: Mount your config file + - ./config/config.toml:/app/config/config.toml:ro # Optional: Persistent logs - diadem-logs:/app/logs depends_on: From 1eb3be5cab9e4980541e4c50a1eec74f10c5a9dd Mon Sep 17 00:00:00 2001 From: ComplementaryPogo Date: Mon, 15 Dec 2025 05:18:15 -0600 Subject: [PATCH 06/13] Revert "Config file paths" This reverts commit 305ad680cf6a5a87add6a48cb37bbc64f5530f18. --- docker-compose.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index a10caa6..d4fb93d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,8 +13,9 @@ services: - HOST=0.0.0.0 - PORT=3900 volumes: - # Required: Mount your config file - - ./config/config.toml:/app/config/config.toml:ro + # Required: Mount your config file (both paths needed for runtime and db:push) + - ./config/config.toml:/app/build/server/config.toml:ro + - ./config/config.toml:/app/src/lib/server/config.toml:ro # Optional: Persistent logs - diadem-logs:/app/logs depends_on: From 6ba9a03acf30b70733c5bb99fe1c155c151db5ef Mon Sep 17 00:00:00 2001 From: ComplementaryPogo Date: Tue, 30 Dec 2025 16:30:46 -0600 Subject: [PATCH 07/13] Add logs directory --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index b624c22..86e3342 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,7 +39,7 @@ COPY --from=builder --chown=diadem:diadem /app/drizzle.config.ts ./ COPY --from=builder --chown=diadem:diadem /app/src/lib/server/db ./src/lib/server/db COPY --from=builder --chown=diadem:diadem /app/src/lib/services ./src/lib/services -RUN mkdir -p /app/config && chown diadem:diadem /app/config +RUN mkdir -p /app/config /app/logs && chown diadem:diadem /app/config /app/logs COPY --chown=diadem:diadem docker-entrypoint.sh ./ RUN chmod +x docker-entrypoint.sh USER diadem From 89e0cd2bff2c36fb436e98f08774e6b6a9ef471e Mon Sep 17 00:00:00 2001 From: ComplementaryPogo Date: Wed, 31 Dec 2025 17:28:25 -0600 Subject: [PATCH 08/13] Consolidate logic to just invoke setup.sh --- Dockerfile | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/Dockerfile b/Dockerfile index 86e3342..6307281 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,16 +12,7 @@ FROM base AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . -RUN mkdir -p src/routes/\(custom\) && \ - mkdir -p src/components/custom && \ - mkdir -p src/lib/server && \ - cp config/custom.example.css config/custom.css && \ - cp config/Home.example.svelte config/Home.svelte && \ - cp config/config.example.toml config/config.toml && \ - ln config/custom.css src/custom.css && \ - ln config/Home.svelte src/components/custom/Home.svelte && \ - ln config/config.toml src/lib/server/config.toml -RUN pnpm run build +RUN ./setup.sh && pnpm run build FROM node:22-slim AS runtime RUN apt-get update && apt-get install -y --no-install-recommends \ From c5f7500b28dd2582f7f4bcff164b4b45b9a18ce9 Mon Sep 17 00:00:00 2001 From: ComplementaryPogo Date: Sat, 24 Jan 2026 17:43:15 -0600 Subject: [PATCH 09/13] I don't remember why I made these changes --- Dockerfile | 3 +++ README.md | 5 +++++ setup.sh | 14 +++++++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 6307281..bb7df49 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,6 +30,9 @@ COPY --from=builder --chown=diadem:diadem /app/drizzle.config.ts ./ COPY --from=builder --chown=diadem:diadem /app/src/lib/server/db ./src/lib/server/db COPY --from=builder --chown=diadem:diadem /app/src/lib/services ./src/lib/services +# Create config.toml mount point (actual config mounted at runtime) +RUN touch ./src/lib/server/config.toml && chown diadem:diadem ./src/lib/server/config.toml + RUN mkdir -p /app/config /app/logs && chown diadem:diadem /app/config /app/logs COPY --chown=diadem:diadem docker-entrypoint.sh ./ RUN chmod +x docker-entrypoint.sh diff --git a/README.md b/README.md index 5afb2fd..ed4e979 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,11 @@ set this up yourself. But I'm not stopping you: 2. `./setup.sh && pnpm install && pnpm run build` 3. `pm2 restart diadem` +### Running in Docker +1. `git clone https://github.com/ccev/diadem && cd ` +2. `cp ./config/config.example.toml ./config/config.toml` +3. Modify the config file to your liking by editing ./config/config.toml + ### Asset caching Diadem proxies and optimizes UICON repos. Clients will cache all uicons for 7 days. But I suggest adding your own caching rules, i.e. with Cloudflare: diff --git a/setup.sh b/setup.sh index 1eb4c25..f59cd24 100755 --- a/setup.sh +++ b/setup.sh @@ -9,12 +9,18 @@ ensure_linked_file() { local cfg="$2" # e.g. config/custom.txt local example="$3" # e.g. config/custom.example.txt - # if source already exists, do nothing + # if source already exists (and is not a broken symlink), do nothing if [ -e "$src" ]; then echo "$src exists, skipping" return fi + # remove broken symlinks if they exist + if [ -L "$src" ]; then + echo "$src is a broken symlink, removing" + rm "$src" + fi + echo "$src missing, setting it up" # ensure directories exist @@ -22,6 +28,12 @@ ensure_linked_file() { mkdir -p "$(dirname "$cfg")" # create config file from example if needed + # also handle case where Docker created a directory instead of a file (happens when mount source is missing) + if [ -d "$cfg" ]; then + echo "$cfg is a directory (Docker artifact?), removing" + rm -rf "$cfg" + fi + if [ ! -e "$cfg" ]; then if [ ! -e "$example" ]; then echo "ERROR: example file $example does not exist" From f1ac5da774c84b628dce5fead95ffa5f693fdf6c Mon Sep 17 00:00:00 2001 From: ComplementaryPogo Date: Sat, 24 Jan 2026 17:47:17 -0600 Subject: [PATCH 10/13] Rename docker-compose to docker-compose.example --- .dockerignore | 2 +- .gitignore | 3 +++ docker-compose.yml => docker-compose.example.yml | 0 3 files changed, 4 insertions(+), 1 deletion(-) rename docker-compose.yml => docker-compose.example.yml (100%) diff --git a/.dockerignore b/.dockerignore index 3de65df..ec1f0e7 100644 --- a/.dockerignore +++ b/.dockerignore @@ -26,7 +26,7 @@ Thumbs.db # Docker Dockerfile -docker-compose*.yml +docker-compose.example.yml .dockerignore # Documentation diff --git a/.gitignore b/.gitignore index b3a3184..7e0c0b1 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,6 @@ Thumbs.db vite.config.js.timestamp-* vite.config.ts.timestamp-* .pnpm-store + +# Docker +docker-compose.yml \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.example.yml similarity index 100% rename from docker-compose.yml rename to docker-compose.example.yml From d5cbbf678b94b512fc1906bf477c83da2fd034ef Mon Sep 17 00:00:00 2001 From: ComplementaryPogo Date: Sat, 24 Jan 2026 18:13:58 -0600 Subject: [PATCH 11/13] Docker in README.md --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ed4e979..e858405 100644 --- a/README.md +++ b/README.md @@ -35,10 +35,15 @@ set this up yourself. But I'm not stopping you: 2. `./setup.sh && pnpm install && pnpm run build` 3. `pm2 restart diadem` -### Running in Docker +### Quick-Start in Docker +These are the basic steps to get going in Docker, but are not production ready (single-node DB, no redundancy, etc) 1. `git clone https://github.com/ccev/diadem && cd ` 2. `cp ./config/config.example.toml ./config/config.toml` -3. Modify the config file to your liking by editing ./config/config.toml +3. Modify the config file to your liking by editing ./config/config.toml. You'll need to point the db at hostname `diadem-db` +4. `cp docker-compose.example.yml docker-compose.yml` +5. Modify the docker-compose file to your liking, such as pointing to an external database +6. `docker compose up --build` +7. Diadem is now running on http://localhost:3900 ### Asset caching Diadem proxies and optimizes UICON repos. Clients will cache all uicons for 7 days. From 110c832daf9174cd0d063dee300befdf858ac023 Mon Sep 17 00:00:00 2001 From: ComplementaryPogo Date: Wed, 31 Dec 2025 03:00:42 -0600 Subject: [PATCH 12/13] Add universal logging functionality --- config/config.example.toml | 3 ++ src/hooks.server.ts | 15 ++++++ src/lib/services/config/configTypes.d.ts | 5 ++ src/lib/services/user/checkPerm.ts | 11 ++++- src/lib/utils/logger.ts | 63 ++++++++++++++++++++++++ 5 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/lib/utils/logger.ts diff --git a/config/config.example.toml b/config/config.example.toml index 1482ce7..a091973 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -2,6 +2,9 @@ level = "info" #crit, error, warning, info, debug # file = "/var/log/diadem.log" +[server.log.debug] +permissions = false # Enable verbose permission checking logs + [server.golbat] url = "http://127.0.0.1:9001" secret = "" diff --git a/src/hooks.server.ts b/src/hooks.server.ts index d35144f..a9c99c9 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -13,6 +13,21 @@ import type { User } from "@/lib/server/db/internal/schema"; import { DISCORD_REFRESH_INTERVAL, PERMISSION_UPDATE_INTERVAL } from "@/lib/constants"; import { getDiscordAuth } from "@/lib/server/auth/discord"; import type { Perms } from "@/lib/utils/features"; +import { getLogger } from "@/lib/server/logging"; +import { setServerLoggerFactory } from "@/lib/utils/logger"; +import { getServerConfig } from "@/lib/services/config/config.server"; + +// Inject winston logger into universal logger for server-side use +const logConfig = getServerConfig().log; +setServerLoggerFactory((name) => { + const winstonLogger = getLogger(name); + return { + debug: (message, ...args) => winstonLogger.debug(message, ...args), + info: (message, ...args) => winstonLogger.info(message, ...args), + warning: (message, ...args) => winstonLogger.warning(message, ...args), + error: (message, ...args) => winstonLogger.error(message, ...args), + }; +}, logConfig.debug); const permissionCache: TTLCache = new TTLCache({ ttl: PERMISSION_UPDATE_INTERVAL * 1000 diff --git a/src/lib/services/config/configTypes.d.ts b/src/lib/services/config/configTypes.d.ts index a285dc7..ad9585b 100644 --- a/src/lib/services/config/configTypes.d.ts +++ b/src/lib/services/config/configTypes.d.ts @@ -72,9 +72,14 @@ export type Permissions = { features?: FeaturesKey[] } +export type Debug = { + permissions?: boolean +} + export type Log = { level: string file?: string + debug?: Debug } export type MapStyle = { diff --git a/src/lib/services/user/checkPerm.ts b/src/lib/services/user/checkPerm.ts index 92fc383..d0b8dff 100644 --- a/src/lib/services/user/checkPerm.ts +++ b/src/lib/services/user/checkPerm.ts @@ -1,7 +1,16 @@ import type { Bounds } from "@/lib/mapObjects/mapBounds"; -import { bbox, feature as makeFeature, featureCollection, intersect, polygon } from "@turf/turf"; +import { bbox, feature as makeFeature, featureCollection, intersect, polygon, union } from "@turf/turf"; import type { Feature, Polygon } from "geojson"; import { Features, type FeaturesKey, type Perms } from "@/lib/utils/features"; +import { getUniversalLogger, isDebugEnabled } from "@/lib/utils/logger"; + +const log = getUniversalLogger("checkPerm"); + +function debugLog(message: string, ...args: unknown[]) { + if (isDebugEnabled("permissions")) { + log.debug(message, ...args); + } +} function isFeatureInFeatureList(featureList: FeaturesKey[] | undefined, feature: FeaturesKey) { if (featureList === undefined) return false; diff --git a/src/lib/utils/logger.ts b/src/lib/utils/logger.ts new file mode 100644 index 0000000..ec65d51 --- /dev/null +++ b/src/lib/utils/logger.ts @@ -0,0 +1,63 @@ +/** + * Universal logger that works in both server and browser environments. + * - Server: Uses winston logger (injected via setServerLoggerFactory) + * - Browser: Falls back to console methods + */ + +type LogFn = (message: string, ...args: unknown[]) => void; + +export interface Logger { + debug: LogFn; + info: LogFn; + warning: LogFn; + error: LogFn; +} + +// Keep in sync with Debug type in @/lib/services/config/configTypes.d.ts +export type DebugCategories = { + permissions?: boolean; +}; + +// Server-side logger factory, injected at startup +let serverLoggerFactory: ((name: string) => Logger) | null = null; + +// Debug categories configuration (injected at startup) +let debugCategories: DebugCategories = {}; + +/** + * Called by server initialization to inject the winston logger factory. + * This allows the universal logger to use winston without importing from server code. + */ +export function setServerLoggerFactory(factory: (name: string) => Logger, categories?: DebugCategories) { + serverLoggerFactory = factory; + debugCategories = categories ?? {}; +} + +/** + * Check if debug logging is enabled for a specific category. + */ +export function isDebugEnabled(category: keyof DebugCategories): boolean { + return debugCategories[category] ?? false; +} + +function createBrowserLogger(name: string): Logger { + const prefix = `[${name}]`; + return { + debug: (message, ...args) => console.debug(prefix, message, ...args), + info: (message, ...args) => console.info(prefix, message, ...args), + warning: (message, ...args) => console.warn(prefix, message, ...args), + error: (message, ...args) => console.error(prefix, message, ...args), + }; +} + +/** + * Get a logger instance for the given name. + * On server (after initialization), uses winston. + * On browser or before server init, uses console. + */ +export function getUniversalLogger(name: string): Logger { + if (serverLoggerFactory) { + return serverLoggerFactory(name); + } + return createBrowserLogger(name); +} From 392567e939caa89ee6212566f8926fadd9d75b8b Mon Sep 17 00:00:00 2001 From: Malte <42342921+ccev@users.noreply.github.com> Date: Sun, 1 Feb 2026 00:22:36 +0100 Subject: [PATCH 13/13] rmeove log debug options, rename getUniversalLogger to getLogger --- config/config.example.toml | 5 +-- src/hooks.server.ts | 8 ++--- src/lib/server/api/golbatApi.ts | 12 +++---- src/lib/server/api/kojiApi.ts | 27 +++++++------- src/lib/server/auth/permissions.ts | 2 +- src/lib/server/db/external/internalQuery.ts | 16 ++++----- src/lib/server/logging.ts | 2 +- src/lib/services/config/configTypes.d.ts | 5 --- src/lib/services/user/checkPerm.ts | 12 ++----- src/lib/utils/logger.ts | 32 ++--------------- .../[id]/+page.server.ts | 2 +- src/routes/(share)/a/[area]/+page.server.ts | 35 ++++++++++--------- .../[encodedFilter]/+page.server.ts | 24 ++++++------- .../api/[queryMapObject=mapObject]/+server.ts | 3 +- src/routes/api/address/[query]/+server.ts | 3 +- src/routes/api/locale/[tag]/+server.ts | 3 +- src/routes/api/scout/+server.ts | 3 +- .../api/search/[type=searchType]/+server.ts | 3 +- src/routes/api/stats/+server.ts | 14 ++++---- src/routes/api/stats/live/+server.ts | 3 +- src/routes/api/weather/[id]/+server.ts | 3 +- .../assets/[iconset]/[...path]/+server.ts | 3 +- .../assets/[iconset]/index.json/+server.ts | 6 ++-- 23 files changed, 97 insertions(+), 129 deletions(-) diff --git a/config/config.example.toml b/config/config.example.toml index a091973..fa20ebc 100644 --- a/config/config.example.toml +++ b/config/config.example.toml @@ -1,10 +1,7 @@ [server.log] -level = "info" #crit, error, warning, info, debug +level = "info" # crit, error, warning, info, debug # file = "/var/log/diadem.log" -[server.log.debug] -permissions = false # Enable verbose permission checking logs - [server.golbat] url = "http://127.0.0.1:9001" secret = "" diff --git a/src/hooks.server.ts b/src/hooks.server.ts index a9c99c9..0f669fa 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -13,21 +13,19 @@ import type { User } from "@/lib/server/db/internal/schema"; import { DISCORD_REFRESH_INTERVAL, PERMISSION_UPDATE_INTERVAL } from "@/lib/constants"; import { getDiscordAuth } from "@/lib/server/auth/discord"; import type { Perms } from "@/lib/utils/features"; -import { getLogger } from "@/lib/server/logging"; +import { getServerLogger } from "@/lib/server/logging"; import { setServerLoggerFactory } from "@/lib/utils/logger"; import { getServerConfig } from "@/lib/services/config/config.server"; -// Inject winston logger into universal logger for server-side use -const logConfig = getServerConfig().log; setServerLoggerFactory((name) => { - const winstonLogger = getLogger(name); + const winstonLogger = getServerLogger(name); return { debug: (message, ...args) => winstonLogger.debug(message, ...args), info: (message, ...args) => winstonLogger.info(message, ...args), warning: (message, ...args) => winstonLogger.warning(message, ...args), error: (message, ...args) => winstonLogger.error(message, ...args), }; -}, logConfig.debug); +}); const permissionCache: TTLCache = new TTLCache({ ttl: PERMISSION_UPDATE_INTERVAL * 1000 diff --git a/src/lib/server/api/golbatApi.ts b/src/lib/server/api/golbatApi.ts index bd94164..427c108 100644 --- a/src/lib/server/api/golbatApi.ts +++ b/src/lib/server/api/golbatApi.ts @@ -1,8 +1,8 @@ import { getServerConfig } from "@/lib/services/config/config.server"; import type { PokemonData } from "@/lib/types/mapObjectData/pokemon"; -import { getLogger } from "@/lib/server/logging"; import type { Coords } from "@/lib/utils/coordinates"; import type { GymData } from "@/lib/types/mapObjectData/gym"; +import { getLogger } from "@/lib/utils/logger"; export type PokemonResponse = { pokemon: PokemonData[]; @@ -52,11 +52,11 @@ async function callGolbat( } export async function getSinglePokemon(id: string, thisFetch: typeof fetch = fetch) { - return await callGolbat("api/pokemon/id/" + id, "GET", undefined, thisFetch) + return await callGolbat("api/pokemon/id/" + id, "GET", undefined, thisFetch); } export async function getMultiplePokemon(body: any) { - return await callGolbat("api/pokemon/v3/scan", "POST", JSON.stringify(body)) + return await callGolbat("api/pokemon/v3/scan", "POST", JSON.stringify(body)); } export async function searchGyms(query: string, coords: Coords, range: number) { @@ -71,6 +71,6 @@ export async function searchGyms(query: string, coords: Coords, range: number) { } ], limit: 15 - } - return await callGolbat("api/gym/search", "POST", JSON.stringify(body)) -} \ No newline at end of file + }; + return await callGolbat("api/gym/search", "POST", JSON.stringify(body)); +} diff --git a/src/lib/server/api/kojiApi.ts b/src/lib/server/api/kojiApi.ts index cf0e3c9..e902f76 100644 --- a/src/lib/server/api/kojiApi.ts +++ b/src/lib/server/api/kojiApi.ts @@ -1,31 +1,32 @@ -import { getServerConfig } from '@/lib/services/config/config.server'; -import { getLogger } from '@/lib/server/logging'; -import { error, json } from "@sveltejs/kit"; +import { getServerConfig } from "@/lib/services/config/config.server"; import type { KojiFeatures } from "@/lib/features/koji"; +import { getLogger } from "@/lib/utils/logger"; -const log = getLogger("koji") +const log = getLogger("koji"); -export async function fetchKojiGeofences(thisFetch?: typeof fetch): Promise { +export async function fetchKojiGeofences( + thisFetch?: typeof fetch +): Promise { const config = getServerConfig(); if (!config.koji || !config.koji.url) { - log.warning("Koji was called, but is not configured") - return + log.warning("Koji was called, but is not configured"); + return; } - const url = config.koji.url + '/api/v1/geofence/FeatureCollection/' + config.koji.projectName; + const url = config.koji.url + "/api/v1/geofence/FeatureCollection/" + config.koji.projectName; const response = await (thisFetch ?? fetch)(url, { - method: 'GET', + method: "GET", headers: { Authorization: `Bearer ${config.koji.secret}`, - 'Content-Type': 'application/json' + "Content-Type": "application/json" } }); if (!response.ok) { - log.error("Koji Error: %d (%s)", response.status, await response.text()) - return + log.error("Koji Error: %d (%s)", response.status, await response.text()); + return; } const data = await response.json(); - return data?.data?.features ?? [] as KojiFeatures + return data?.data?.features ?? ([] as KojiFeatures); } \ No newline at end of file diff --git a/src/lib/server/auth/permissions.ts b/src/lib/server/auth/permissions.ts index 3b69961..697e757 100644 --- a/src/lib/server/auth/permissions.ts +++ b/src/lib/server/auth/permissions.ts @@ -5,8 +5,8 @@ import { getServerConfig } from "@/lib/services/config/config.server"; import type { Permissions as ConfigRule } from "@/lib/services/config/configTypes"; import { type KojiFeatures } from "@/lib/features/koji"; import { fetchKojiGeofences } from "@/lib/server/api/kojiApi"; -import { getLogger } from "@/lib/server/logging"; import type { FeaturesKey, PermArea, Perms } from "@/lib/utils/features"; +import { getLogger } from "@/lib/utils/logger"; const log = getLogger("permissions"); diff --git a/src/lib/server/db/external/internalQuery.ts b/src/lib/server/db/external/internalQuery.ts index 89fb232..7ad4e93 100644 --- a/src/lib/server/db/external/internalQuery.ts +++ b/src/lib/server/db/external/internalQuery.ts @@ -1,9 +1,9 @@ -import mysql from 'mysql2/promise'; -import { getServerConfig } from '@/lib/services/config/config.server'; -import { getDbUri } from '@/lib/services/config/dbUri.server'; -import { getLogger } from '@/lib/server/logging'; +import mysql from "mysql2/promise"; +import { getServerConfig } from "@/lib/services/config/config.server"; +import { getDbUri } from "@/lib/services/config/dbUri.server"; +import { getLogger } from "@/lib/utils/logger"; -const log = getLogger("query") +const log = getLogger("query"); const connection = mysql.createPool(getDbUri(getServerConfig().db)); @@ -14,7 +14,7 @@ export async function query( error: number | undefined; result: T; }> { - const start = performance.now() + const start = performance.now(); let result: mysql.QueryResult = []; let error: number | undefined = undefined; @@ -28,7 +28,7 @@ export async function query( ); result = queryResult[0]; } catch (e) { - log.error('SQL exception', e); + log.error("SQL exception", e); error = 500; } @@ -61,7 +61,7 @@ export async function query( } } - log.debug(`Query took %fms: %s`, (performance.now() - start).toFixed(1), sql) + log.debug(`Query took %fms: %s`, (performance.now() - start).toFixed(1), sql); return { error, result: parsedResult diff --git a/src/lib/server/logging.ts b/src/lib/server/logging.ts index 4ec3184..c884418 100644 --- a/src/lib/server/logging.ts +++ b/src/lib/server/logging.ts @@ -46,6 +46,6 @@ if (config.file) { log.add(new DailyRotateFile({ filename: config.file })) } -export function getLogger(name: string) { +export function getServerLogger(name: string) { return log.child({ label: name }) } diff --git a/src/lib/services/config/configTypes.d.ts b/src/lib/services/config/configTypes.d.ts index ad9585b..a285dc7 100644 --- a/src/lib/services/config/configTypes.d.ts +++ b/src/lib/services/config/configTypes.d.ts @@ -72,14 +72,9 @@ export type Permissions = { features?: FeaturesKey[] } -export type Debug = { - permissions?: boolean -} - export type Log = { level: string file?: string - debug?: Debug } export type MapStyle = { diff --git a/src/lib/services/user/checkPerm.ts b/src/lib/services/user/checkPerm.ts index d0b8dff..5bd62b2 100644 --- a/src/lib/services/user/checkPerm.ts +++ b/src/lib/services/user/checkPerm.ts @@ -1,16 +1,10 @@ import type { Bounds } from "@/lib/mapObjects/mapBounds"; -import { bbox, feature as makeFeature, featureCollection, intersect, polygon, union } from "@turf/turf"; +import { bbox, feature as makeFeature, featureCollection, intersect, polygon } from "@turf/turf"; import type { Feature, Polygon } from "geojson"; import { Features, type FeaturesKey, type Perms } from "@/lib/utils/features"; -import { getUniversalLogger, isDebugEnabled } from "@/lib/utils/logger"; +import { getLogger } from "@/lib/utils/logger"; -const log = getUniversalLogger("checkPerm"); - -function debugLog(message: string, ...args: unknown[]) { - if (isDebugEnabled("permissions")) { - log.debug(message, ...args); - } -} +const log = getLogger("permissions"); function isFeatureInFeatureList(featureList: FeaturesKey[] | undefined, feature: FeaturesKey) { if (featureList === undefined) return false; diff --git a/src/lib/utils/logger.ts b/src/lib/utils/logger.ts index ec65d51..b8a62e5 100644 --- a/src/lib/utils/logger.ts +++ b/src/lib/utils/logger.ts @@ -1,8 +1,4 @@ -/** - * Universal logger that works in both server and browser environments. - * - Server: Uses winston logger (injected via setServerLoggerFactory) - * - Browser: Falls back to console methods - */ +// Universal logger that works on both the server and in the browser type LogFn = (message: string, ...args: unknown[]) => void; @@ -13,31 +9,14 @@ export interface Logger { error: LogFn; } -// Keep in sync with Debug type in @/lib/services/config/configTypes.d.ts export type DebugCategories = { permissions?: boolean; }; -// Server-side logger factory, injected at startup let serverLoggerFactory: ((name: string) => Logger) | null = null; -// Debug categories configuration (injected at startup) -let debugCategories: DebugCategories = {}; - -/** - * Called by server initialization to inject the winston logger factory. - * This allows the universal logger to use winston without importing from server code. - */ -export function setServerLoggerFactory(factory: (name: string) => Logger, categories?: DebugCategories) { +export function setServerLoggerFactory(factory: (name: string) => Logger,) { serverLoggerFactory = factory; - debugCategories = categories ?? {}; -} - -/** - * Check if debug logging is enabled for a specific category. - */ -export function isDebugEnabled(category: keyof DebugCategories): boolean { - return debugCategories[category] ?? false; } function createBrowserLogger(name: string): Logger { @@ -50,12 +29,7 @@ function createBrowserLogger(name: string): Logger { }; } -/** - * Get a logger instance for the given name. - * On server (after initialization), uses winston. - * On browser or before server init, uses console. - */ -export function getUniversalLogger(name: string): Logger { +export function getLogger(name: string): Logger { if (serverLoggerFactory) { return serverLoggerFactory(name); } diff --git a/src/routes/(share)/[directLink=mapObject]/[id]/+page.server.ts b/src/routes/(share)/[directLink=mapObject]/[id]/+page.server.ts index 069fdc8..973ca92 100644 --- a/src/routes/(share)/[directLink=mapObject]/[id]/+page.server.ts +++ b/src/routes/(share)/[directLink=mapObject]/[id]/+page.server.ts @@ -4,9 +4,9 @@ import { initAllIconSets } from "@/lib/services/uicons.svelte.js"; import { loadRemoteLocale } from "@/lib/services/ingameLocale"; import { querySingleMapObject } from "@/lib/server/api/querySingleMapObject"; import { makeMapObject } from "@/lib/mapObjects/makeMapObject"; -import { getLogger } from "@/lib/server/logging"; import { getClientConfig } from "@/lib/services/config/config.server"; import { type MapData, MapObjectType } from "@/lib/mapObjects/mapObjectTypes"; +import { getLogger } from "@/lib/utils/logger"; const log = getLogger("directlink"); export const ssr = true; diff --git a/src/routes/(share)/a/[area]/+page.server.ts b/src/routes/(share)/a/[area]/+page.server.ts index e74851b..f5edee2 100644 --- a/src/routes/(share)/a/[area]/+page.server.ts +++ b/src/routes/(share)/a/[area]/+page.server.ts @@ -1,35 +1,38 @@ -import { getConfig, setConfig } from "@/lib/services/config/config"; -import { loadRemoteLocale } from "@/lib/services/ingameLocale"; import type { PageServerLoad } from "./$types"; -import { getLogger } from "@/lib/server/logging"; -import { getServerConfig } from "@/lib/services/config/config.server"; import { error } from "@sveltejs/kit"; -import { getKojiGeofences } from "@/lib/features/koji"; import { fetchKojiGeofences } from "@/lib/server/api/kojiApi"; import { getFeatureJump } from "@/lib/utils/geo"; +import { getLogger } from "@/lib/utils/logger"; -const log = getLogger("arealink") +const log = getLogger("arealink"); export const load: PageServerLoad = async ({ params, fetch }) => { - const areaName = params.area + const areaName = params.area; - log.info("Direct area link called to %s", areaName) + log.info("Direct area link called to %s", areaName); - const features = await fetchKojiGeofences(fetch) + const features = await fetchKojiGeofences(fetch); if (!features) { - log.error("Error fetching features, returning 404") - error(404) + log.error("Error fetching features, returning 404"); + error(404); } - const feature = features.find(a => a.properties.name.toLowerCase().includes(areaName.toLowerCase())) + const feature = features.find((a) => + a.properties.name.toLowerCase().includes(areaName.toLowerCase()) + ); if (!feature) { - log.info("Area %s not found", areaName) - error(404) + log.info("Area %s not found", areaName); + error(404); } - const jumpTo = getFeatureJump(feature) + const jumpTo = getFeatureJump(feature); - return { lat: jumpTo.coords.lat, lon: jumpTo.coords.lon, zoom: jumpTo.zoom, name: feature.properties.name }; + return { + lat: jumpTo.coords.lat, + lon: jumpTo.coords.lon, + zoom: jumpTo.zoom, + name: feature.properties.name + }; }; \ No newline at end of file diff --git a/src/routes/(share)/filter/[majorCategory]/[[subCategory]]/[encodedFilter]/+page.server.ts b/src/routes/(share)/filter/[majorCategory]/[[subCategory]]/[encodedFilter]/+page.server.ts index 7e74cd4..98bcc38 100644 --- a/src/routes/(share)/filter/[majorCategory]/[[subCategory]]/[encodedFilter]/+page.server.ts +++ b/src/routes/(share)/filter/[majorCategory]/[[subCategory]]/[encodedFilter]/+page.server.ts @@ -10,10 +10,10 @@ import { FiltersetRaidSchema } from "@/lib/features/filters/filtersetSchemas"; import * as m from "@/lib/paraglide/messages"; -import { getLogger } from "@/lib/server/logging"; import type { ZodSafeParseResult } from "zod"; +import { getLogger } from "@/lib/utils/logger"; -const log = getLogger("filtershare") +const log = getLogger("filtershare"); function decodeFilterset( majorCategory: FilterCategory | string, @@ -21,30 +21,30 @@ function decodeFilterset( str: string ) { const decoded: AnyFilterset = JSON.parse(decodeURIComponent(atob(str))); - log.info("Decoding filterset: %s", decoded) + log.info("Decoding filterset: %s", decoded); decoded.id = getId(); - let zodResult: ZodSafeParseResult | undefined = undefined + let zodResult: ZodSafeParseResult | undefined = undefined; if (majorCategory === "pokemon") { - zodResult = FiltersetPokemonSchema.safeParse(decoded) + zodResult = FiltersetPokemonSchema.safeParse(decoded); } else if (majorCategory === "gym" && subCategory === "raid") { - zodResult = FiltersetRaidSchema.safeParse(decoded) + zodResult = FiltersetRaidSchema.safeParse(decoded); } else if (majorCategory === "pokestop" && subCategory === "invasion") { - zodResult = FiltersetInvasionSchema.safeParse(decoded) + zodResult = FiltersetInvasionSchema.safeParse(decoded); } - if (!zodResult) return undefined + if (!zodResult) return undefined; if (zodResult?.error) { - log.crit("Decoding failed!!", zodResult?.error) - return undefined + log.crit("Decoding failed!!", zodResult?.error); + return undefined; } - const safe = zodResult.data + const safe = zodResult.data; if (safe?.title?.message && !Object.keys(m).includes(safe.title.message)) { - log.crit("Tried to send invalid message!!", safe.title.message) + log.crit("Tried to send invalid message!!", safe.title.message); return undefined; } diff --git a/src/routes/api/[queryMapObject=mapObject]/+server.ts b/src/routes/api/[queryMapObject=mapObject]/+server.ts index 2d33fac..41a4dc6 100644 --- a/src/routes/api/[queryMapObject=mapObject]/+server.ts +++ b/src/routes/api/[queryMapObject=mapObject]/+server.ts @@ -2,9 +2,10 @@ import { error, json } from "@sveltejs/kit"; import { checkFeatureInBounds } from "@/lib/services/user/checkPerm"; import { queryMapObjects } from "@/lib/server/api/queryMapObjects"; import type { MapObjectRequestData } from "@/lib/mapObjects/updateMapObject"; -import { getLogger } from "@/lib/server/logging"; +import { getServerLogger } from "@/lib/server/logging"; import { hasFeatureAnywhereServer } from "@/lib/server/auth/checkIfAuthed"; import { MapObjectType } from "@/lib/mapObjects/mapObjectTypes"; +import { getLogger } from "@/lib/utils/logger"; const log = getLogger("mapobjects"); diff --git a/src/routes/api/address/[query]/+server.ts b/src/routes/api/address/[query]/+server.ts index 44a0630..faf63f4 100644 --- a/src/routes/api/address/[query]/+server.ts +++ b/src/routes/api/address/[query]/+server.ts @@ -1,7 +1,8 @@ import { error, json } from "@sveltejs/kit"; import { getServerConfig } from "@/lib/services/config/config.server"; import type { FeatureCollection, Point } from "geojson"; -import { getLogger } from "@/lib/server/logging"; +import { getServerLogger } from "@/lib/server/logging"; +import { getLogger } from "@/lib/utils/logger"; const log = getLogger("nominatim"); diff --git a/src/routes/api/locale/[tag]/+server.ts b/src/routes/api/locale/[tag]/+server.ts index b5406bd..abe1261 100644 --- a/src/routes/api/locale/[tag]/+server.ts +++ b/src/routes/api/locale/[tag]/+server.ts @@ -1,8 +1,9 @@ import { json } from "@sveltejs/kit"; import { prefixes as localePrefixesObject } from "@/lib/services/ingameLocale"; import TTLCache from "@isaacs/ttlcache"; -import { getLogger } from "@/lib/server/logging"; +import { getServerLogger } from "@/lib/server/logging"; import { locales } from "@/lib/paraglide/runtime"; +import { getLogger } from "@/lib/utils/logger"; type Locale = (typeof locales)[number]; type RemoteLocale = { [key: string]: string }; diff --git a/src/routes/api/scout/+server.ts b/src/routes/api/scout/+server.ts index 6c85aca..9c42678 100644 --- a/src/routes/api/scout/+server.ts +++ b/src/routes/api/scout/+server.ts @@ -3,9 +3,10 @@ import type { ScoutRequest } from "@/lib/features/scout.svelte.js"; import { addScoutEntries, getScoutQueue } from "@/lib/server/api/dragoniteApi"; import { result } from "@/lib/server/api/results"; -import { getLogger } from "@/lib/server/logging"; +import { getServerLogger } from "@/lib/server/logging"; import { hasFeatureAnywhereServer } from "@/lib/server/auth/checkIfAuthed"; import { Features } from "@/lib/utils/features"; +import { getLogger } from "@/lib/utils/logger"; const log = getLogger("scout"); diff --git a/src/routes/api/search/[type=searchType]/+server.ts b/src/routes/api/search/[type=searchType]/+server.ts index 0141893..d0e8669 100644 --- a/src/routes/api/search/[type=searchType]/+server.ts +++ b/src/routes/api/search/[type=searchType]/+server.ts @@ -1,9 +1,10 @@ import { error, json } from "@sveltejs/kit"; -import { getLogger } from "@/lib/server/logging"; +import { getServerLogger } from "@/lib/server/logging"; import { hasFeatureAnywhereServer } from "@/lib/server/auth/checkIfAuthed"; import { searchGyms } from "@/lib/server/api/golbatApi"; import { Coords } from "@/lib/utils/coordinates"; import { type SearchPayload, SearchType, sortSearchResults } from "@/lib/services/search.svelte"; +import { getLogger } from "@/lib/utils/logger"; const log = getLogger("search"); diff --git a/src/routes/api/stats/+server.ts b/src/routes/api/stats/+server.ts index c034ae8..08019d0 100644 --- a/src/routes/api/stats/+server.ts +++ b/src/routes/api/stats/+server.ts @@ -1,9 +1,9 @@ import { json } from "@sveltejs/kit"; import { type MasterStats, queryMasterStats } from "@/lib/server/api/queryStats"; import TTLCache from "@isaacs/ttlcache"; -import { getLogger } from '@/lib/server/logging'; +import { getLogger } from "@/lib/utils/logger"; -const log = getLogger("stats") +const log = getLogger("stats"); const UPDATE_INTERVAL = 60 * 60 * 1000; const statsCache: TTLCache<"stats", MasterStats> = new TTLCache({ @@ -14,14 +14,14 @@ const statsCache: TTLCache<"stats", MasterStats> = new TTLCache({ export async function GET() { const stats = statsCache.get("stats"); if (stats) { - log.info("Serving cached master stats") - return json(stats) - }; + log.info("Serving cached master stats"); + return json(stats); + } try { - const start = performance.now() + const start = performance.now(); const stats = await queryMasterStats(); - log.info("Generated fresh master stats / time: %dms", (performance.now() - start).toFixed(1)) + log.info("Generated fresh master stats / time: %dms", (performance.now() - start).toFixed(1)); statsCache.set("stats", stats); return json(stats); } catch (e) { diff --git a/src/routes/api/stats/live/+server.ts b/src/routes/api/stats/live/+server.ts index da08da2..cc348a0 100644 --- a/src/routes/api/stats/live/+server.ts +++ b/src/routes/api/stats/live/+server.ts @@ -1,13 +1,12 @@ import { json } from "@sveltejs/kit"; -import { type MasterStats, queryMasterStats } from "@/lib/server/api/queryStats"; import TTLCache from "@isaacs/ttlcache"; -import { getLogger } from "@/lib/server/logging"; import { type FortLiveStats, type LiveStats, queryLiveFortStats, queryLivePokemonStats } from "@/lib/server/api/queryLiveStats"; +import { getLogger } from "@/lib/utils/logger"; const log = getLogger("livestats"); diff --git a/src/routes/api/weather/[id]/+server.ts b/src/routes/api/weather/[id]/+server.ts index 18c1ec4..466dd33 100644 --- a/src/routes/api/weather/[id]/+server.ts +++ b/src/routes/api/weather/[id]/+server.ts @@ -1,8 +1,9 @@ import { error, json } from "@sveltejs/kit"; import { query } from "@/lib/server/db/external/internalQuery"; -import { getLogger } from "@/lib/server/logging"; +import { getServerLogger } from "@/lib/server/logging"; import { hasFeatureAnywhereServer } from "@/lib/server/auth/checkIfAuthed"; import { Features } from '@/lib/utils/features'; +import { getLogger } from "@/lib/utils/logger"; const log = getLogger("mapobjects"); diff --git a/src/routes/assets/[iconset]/[...path]/+server.ts b/src/routes/assets/[iconset]/[...path]/+server.ts index 409c446..7c03087 100644 --- a/src/routes/assets/[iconset]/[...path]/+server.ts +++ b/src/routes/assets/[iconset]/[...path]/+server.ts @@ -1,8 +1,9 @@ import { error } from "@sveltejs/kit"; import { getClientConfig } from "@/lib/services/config/config.server"; import sharp, { type ResizeOptions } from "sharp"; -import { getLogger } from "@/lib/server/logging"; +import { getServerLogger } from "@/lib/server/logging"; import { ALLOWED_WIDTHS } from "@/lib/services/assets"; +import { getLogger } from "@/lib/utils/logger"; const log = getLogger("uicons"); const CACHE_AGE = 86400 * 7; // 7 days diff --git a/src/routes/assets/[iconset]/index.json/+server.ts b/src/routes/assets/[iconset]/index.json/+server.ts index 09a81a4..598a283 100644 --- a/src/routes/assets/[iconset]/index.json/+server.ts +++ b/src/routes/assets/[iconset]/index.json/+server.ts @@ -1,7 +1,7 @@ import { error } from "@sveltejs/kit"; import { getClientConfig } from "@/lib/services/config/config.server"; -import { getLogger } from "@/lib/server/logging"; import TTLCache from "@isaacs/ttlcache"; +import { getLogger } from "@/lib/utils/logger"; const log = getLogger("uicons"); const config = getClientConfig(); @@ -29,7 +29,7 @@ export async function GET({ params, fetch }) { }); } - const url = iconSet.url + "/index.json" + const url = iconSet.url + "/index.json"; const res = await fetch(url); log.info("[%s] Serving fresh index.json", iconSetId); @@ -38,7 +38,7 @@ export async function GET({ params, fetch }) { error(500, "Fetching index.json failed"); } - const text = await res.text() + const text = await res.text(); indexCache.set(iconSetId, text);