16 Commits

Author SHA1 Message Date
urania 28e2eab5ba v0.7.3
release / release (push) Successful in 5s
2026-06-26 14:48:00 +02:00
urania 439784bdbb fix: auth on homepage 2026-06-26 14:48:00 +02:00
urania a773df9c46 v0.7.2
release / release (push) Successful in 4s
2026-06-26 14:23:25 +02:00
urania b80ad26a15 fix: auth on homepage 2026-06-26 14:23:25 +02:00
urania 862b12c444 v0.7.1
release / release (push) Successful in 4s
2026-06-26 14:01:38 +02:00
urania f6434af4a2 fix: release and admin bootstrap 2026-06-26 14:01:38 +02:00
urania 4ad394b70b v0.7.0
release / release (push) Successful in 4s
2026-06-26 13:57:27 +02:00
urania 5d8237386d feat: bootstrap admin user on first run 2026-06-26 13:57:00 +02:00
urania d11cdce8b5 v0.6.6
release / release (push) Successful in 4s
2026-06-26 13:49:12 +02:00
urania db8fa8928d v0.6.5
release / release (push) Successful in 4s
2026-06-26 13:48:53 +02:00
urania 5777e4910e feat: bootstrap admin user on first run
When the user table is empty, init creates an admin via better-auth's
admin.createUser API. ADMIN_USERNAME / ADMIN_EMAIL / ADMIN_PASSWORD
configure it; password is generated and logged once if not provided.

Also silence the cosmetic async_hooks warning by marking it external.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-26 13:48:27 +02:00
urania 58ccce0d71 v0.6.4
release / release (push) Successful in 5s
2026-06-26 11:28:44 +02:00
urania e862a75fd0 v0.6.3
release / release (push) Successful in 4s
2026-06-26 11:28:37 +02:00
urania 70fc51ed01 fix: labels on container 2026-06-26 11:28:25 +02:00
urania c02a11bf27 v0.6.2
release / release (push) Successful in 4s
2026-06-26 11:17:58 +02:00
urania 36f71cb4a9 fix: dockerfile 2026-06-26 11:17:56 +02:00
8 changed files with 70 additions and 19 deletions
+17
View File
@@ -39,3 +39,20 @@ jobs:
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Content-Type: application/json" \
--data @-
- name: Trigger Komodo build
env:
KOMODO_WEBHOOK_URL: https://komodo.urania.dev/listener/github/build/urania_builder_nadir
KOMODO_WEBHOOK_SECRET: ${{ secrets.KOMODO_WEBHOOK_SECRET }}
run: |
# Komodo's GitHub listener requires `ref` + a matching HMAC signature.
BODY=$(jq -nc --arg sha "$GITHUB_SHA" \
'{ref:"refs/heads/main", after:$sha,
repository:{full_name:"${{ github.repository }}",
clone_url:"${{ github.server_url }}/${{ github.repository }}.git"}}')
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$KOMODO_WEBHOOK_SECRET" -hex | awk '{print $NF}')
curl -fsSL -X POST "$KOMODO_WEBHOOK_URL" \
-H "Content-Type: application/json" \
-H "X-GitHub-Event: push" \
-H "X-Hub-Signature-256: sha256=$SIG" \
-d "$BODY"
+2 -1
View File
@@ -28,4 +28,5 @@ project.inlang/cache/
*.db
CONTEXT.md
build.sh
.claude
.claude
release.sh
+13
View File
@@ -12,6 +12,19 @@ COPY . .
RUN bun run build
FROM base AS release
ARG VERSION=dev
ARG REVISION=unknown
ARG CREATED
LABEL org.opencontainers.image.title="nadir" \
org.opencontainers.image.description="SvelteKit dashboard for nadir-agent — central web console for Nadir backend nodes." \
org.opencontainers.image.documentation="https://nadir.urania.dev/docs" \
org.opencontainers.image.url="https://tea.urania.dev/urania/nadir-webui" \
org.opencontainers.image.source="https://tea.urania.dev/urania/nadir-webui" \
org.opencontainers.image.authors="Mirko Isaia <m.isaia@urania.dev>" \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.revision="${REVISION}" \
org.opencontainers.image.created="${CREATED}"
ENV NODE_ENV=production \
DATABASE_URL=/app/data/db.sqlite \
HOST=0.0.0.0 \
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "clean",
"private": true,
"version": "0.6.1",
"version": "0.7.3",
"type": "module",
"scripts": {
"dev:types": "bun run type:generate && bun --bun vite dev --host",
-15
View File
@@ -1,15 +0,0 @@
#!/usr/bin/env bash
# Cut a release: bump package.json, tag, push.
# Gitea Actions creates the release; Komodo builds & pushes the image via webhook.
# Usage: ./release.sh [patch|minor|major] (default: patch)
set -euo pipefail
cd "$(dirname "$0")"
BUMP="${1:-patch}"
[ -z "$(git status --porcelain)" ] || { echo "working tree dirty, commit first"; exit 1; }
# bumps version in package.json AND creates commit + tag vX.Y.Z
bun pm version "$BUMP"
git push --follow-tags
echo "released v$(bun -e 'console.log(require("./package.json").version)')"
+32 -1
View File
@@ -5,9 +5,11 @@ import { getAuth } from '$lib/auth/server';
import { getTextDirection } from '$lib/paraglide/runtime';
import { paraglideMiddleware } from '$lib/paraglide/server';
import { getConfig } from '$lib/server/config';
import { db } from '$lib/server/db';
import { svelteKitHandler } from 'better-auth/svelte-kit';
import { randomBytes } from 'node:crypto';
export const init: ServerInit = () => {
export const init: ServerInit = async () => {
const env = process.env;
const errors: string[] = [];
@@ -20,6 +22,34 @@ export const init: ServerInit = () => {
if (errors.length)
throw new Error(`Invalid environment:\n - ${errors.join('\n - ')}`);
// Bootstrap an admin if the user table is empty.
const userCount = db.$client.prepare('SELECT COUNT(*) AS c FROM user').get() as { c: number };
if (userCount.c > 0) return;
const username = env.ADMIN_USERNAME?.trim() || 'admin';
const email = env.ADMIN_EMAIL?.trim() || `${username}@example.com`;
const provided = env.ADMIN_PASSWORD?.trim();
const password = provided || randomBytes(18).toString('base64url');
await getAuth().api.createUser({
body: {
data: { displayUsername: username, emailVerified: true, username },
email,
name: username,
password,
role: 'admin'
}
});
const line = '━'.repeat(64);
if (provided) {
console.log(`${line}\nBootstrap admin "${username}" created (ADMIN_PASSWORD).\n${line}`);
} else {
console.log(
`${line}\nBootstrap admin created — sign in with these and rotate immediately:\n username: ${username}\n password: ${password}\nSet ADMIN_PASSWORD env to pick your own.\n${line}`
);
}
};
const handleBetterAuth: Handle = async ({ event, resolve }) => {
@@ -33,6 +63,7 @@ const handleBetterAuth: Handle = async ({ event, resolve }) => {
event.locals.session = session.session;
event.locals.user = session.user;
} else if (
event.url.pathname !== "/" &&
!event.url.pathname.startsWith('/auth') &&
!event.url.pathname.startsWith('/api/auth') &&
event.url.pathname !== '/install.sh'
+1
View File
@@ -0,0 +1 @@
export const load = () => {};
+4 -1
View File
@@ -5,11 +5,14 @@ import adapter from 'svelte-adapter-bun';
import { defineConfig } from 'vite';
export default defineConfig({
build: {
rollupOptions: { external: ['async_hooks'] }
},
plugins: [
tailwindcss(),
sveltekit({
adapter: adapter({
precompress:true
precompress: true
}),
compilerOptions: {
experimental: { async: true },