refactor: consolidate codebase — remove archived code, deduplicate packages, standardize middleware

- Delete 17 server-archived/ directories (consolidated into apps/api/)
- Delete apps-archived/ (clock, wisekeep) and services-archived/ (it-landing, ollama-metrics-proxy)
- Fix type safety: replace all `any` casts in cross-app-queries.ts with proper Local* types
- Remove duplicate shared-auth-stores package (identical copy of shared-auth-ui/stores/)
- Remove duplicate theme store from shared-stores (canonical version in shared-theme)
- Migrate memoro-server rate-limiter to shared-hono/rateLimitMiddleware
- Migrate uload-server JWT auth + error handler to shared-hono (authMiddleware, errorHandler)
- Migrate arcade-server error handling to shared-hono
- Merge shared-profile-ui and shared-app-onboarding into shared-ui
- Unify /clock route into /times/clock, remove redirect stubs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-03 12:55:58 +02:00
parent 7ee57b7afd
commit d8ce4eaf34
309 changed files with 172 additions and 21667 deletions

View file

@ -1,21 +0,0 @@
{
"name": "@moodlit/server",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "bun run --watch src/index.ts",
"start": "bun run src/index.ts",
"type-check": "tsc --noEmit"
},
"dependencies": {
"drizzle-orm": "^0.44.7",
"hono": "^4.7.0",
"jose": "^6.1.2",
"postgres": "^3.4.7"
},
"devDependencies": {
"@types/bun": "^1.2.0",
"typescript": "^5.0.0"
}
}

View file

@ -1,16 +0,0 @@
export interface Config {
port: number;
databaseUrl: string;
manaAuthUrl: string;
cors: { origins: string[] };
}
export function loadConfig(): Config {
return {
port: parseInt(process.env.PORT || '3073', 10),
databaseUrl:
process.env.DATABASE_URL || 'postgresql://manacore:devpassword@localhost:5432/mana_sync',
manaAuthUrl: process.env.MANA_CORE_AUTH_URL || 'http://localhost:3001',
cors: { origins: (process.env.CORS_ORIGINS || 'http://localhost:5173').split(',') },
};
}

View file

@ -1,17 +0,0 @@
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { loadConfig } from './config';
import { errorHandler } from './middleware/error-handler';
import { healthRoutes } from './routes/health';
import { presetRoutes } from './routes/presets';
const config = loadConfig();
const app = new Hono();
app.onError(errorHandler);
app.use('*', cors({ origin: config.cors.origins, credentials: true }));
app.route('/health', healthRoutes);
app.route('/api/v1/presets', presetRoutes);
export default { port: config.port, fetch: app.fetch };

View file

@ -1,19 +0,0 @@
import { HTTPException } from 'hono/http-exception';
export class NotFoundError extends HTTPException {
constructor(message = 'Not found') {
super(404, { message });
}
}
export class BadRequestError extends HTTPException {
constructor(message = 'Bad request') {
super(400, { message });
}
}
export class UnauthorizedError extends HTTPException {
constructor(message = 'Unauthorized') {
super(401, { message });
}
}

View file

@ -1,11 +0,0 @@
import type { ErrorHandler } from 'hono';
import { HTTPException } from 'hono/http-exception';
export const errorHandler: ErrorHandler = (err, c) => {
if (err instanceof HTTPException) {
return c.json({ statusCode: err.status, message: err.message }, err.status);
}
console.error('Unhandled error:', err);
return c.json({ statusCode: 500, message: 'Internal server error' }, 500);
};

View file

@ -1,46 +0,0 @@
import type { MiddlewareHandler } from 'hono';
import { createRemoteJWKSet, jwtVerify } from 'jose';
import { UnauthorizedError } from '../lib/errors';
export interface AuthUser {
userId: string;
email: string;
role: string;
}
let jwks: ReturnType<typeof createRemoteJWKSet> | null = null;
function getJwks(authUrl: string) {
if (!jwks) {
jwks = createRemoteJWKSet(new URL('/api/auth/jwks', authUrl));
}
return jwks;
}
export function jwtAuth(authUrl: string): MiddlewareHandler {
return async (c, next) => {
const authHeader = c.req.header('Authorization');
if (!authHeader?.startsWith('Bearer ')) {
throw new UnauthorizedError('Missing or invalid Authorization header');
}
const token = authHeader.slice(7);
try {
const { payload } = await jwtVerify(token, getJwks(authUrl), {
issuer: authUrl,
audience: 'manacore',
});
const user: AuthUser = {
userId: payload.sub || '',
email: (payload.email as string) || '',
role: (payload.role as string) || 'user',
};
c.set('user', user);
await next();
} catch {
throw new UnauthorizedError('Invalid or expired token');
}
};
}

View file

@ -1,10 +0,0 @@
import { Hono } from 'hono';
export const healthRoutes = new Hono().get('/', (c) =>
c.json({
status: 'ok',
service: 'moodlit-server',
runtime: 'bun',
timestamp: new Date().toISOString(),
})
);

View file

@ -1,29 +0,0 @@
import { Hono } from 'hono';
const DEFAULT_MOODS = [
{ id: 'fire', name: 'Fire', colors: ['#ff6b35', '#f72585', '#ff006e'], animation: 'flicker' },
{ id: 'breath', name: 'Breath', colors: ['#4361ee', '#3a0ca3', '#7209b7'], animation: 'pulse' },
{
id: 'northern-lights',
name: 'Northern Lights',
colors: ['#06d6a0', '#118ab2', '#073b4c'],
animation: 'aurora',
},
{ id: 'thunder', name: 'Thunder', colors: ['#14213d', '#fca311', '#e5e5e5'], animation: 'flash' },
{
id: 'sunset',
name: 'Sunset',
colors: ['#ff6b6b', '#feca57', '#ff9ff3'],
animation: 'gradient',
},
{ id: 'ocean', name: 'Ocean', colors: ['#0077b6', '#00b4d8', '#90e0ef'], animation: 'wave' },
{ id: 'forest', name: 'Forest', colors: ['#2d6a4f', '#40916c', '#52b788'], animation: 'sway' },
{
id: 'lavender',
name: 'Lavender',
colors: ['#7b2cbf', '#9d4edd', '#c77dff'],
animation: 'pulse',
},
];
export const presetRoutes = new Hono().get('/', (c) => c.json(DEFAULT_MOODS));

View file

@ -1,16 +0,0 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022"],
"types": ["bun-types"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}