diff --git a/apps/web/src/dashboard/index.html b/apps/web/src/dashboard/index.html
index d45998d..9e0c76e 100644
--- a/apps/web/src/dashboard/index.html
+++ b/apps/web/src/dashboard/index.html
@@ -119,7 +119,7 @@
document.getElementById('register-btn').addEventListener('click', async () => {
setLoading('register-btn', true, 'Creating...');
try {
- const res = await fetch(`${API}/auth/register`, {
+ const res = await fetch(`${API}/account/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({}),
diff --git a/apps/web/src/index.ts b/apps/web/src/index.ts
index 46c067b..2d3d1cd 100644
--- a/apps/web/src/index.ts
+++ b/apps/web/src/index.ts
@@ -3,7 +3,7 @@ import { cors } from "@elysiajs/cors";
import { swagger } from "@elysiajs/swagger";
import { checks } from "./routes/checks";
import { monitors } from "./routes/monitors";
-import { auth, account } from "./routes/auth";
+import { account } from "./routes/auth";
import { internal } from "./routes/internal";
import { dashboard } from "./routes/dashboard";
import { migrate } from "./db";
@@ -15,7 +15,6 @@ const app = new Elysia()
.use(swagger({ path: "/docs", documentation: { info: { title: "PingQL API", version: "0.1.0" } } }))
.get("/", () => ({ name: "PingQL", version: "0.1.0", docs: "/docs", dashboard: "/dashboard" }), { detail: { hide: true } })
.use(dashboard)
- .use(auth)
.use(account)
.use(monitors)
.use(checks)
diff --git a/apps/web/src/routes/auth.ts b/apps/web/src/routes/auth.ts
index 71d7906..0ecb82d 100644
--- a/apps/web/src/routes/auth.ts
+++ b/apps/web/src/routes/auth.ts
@@ -2,14 +2,12 @@ import { Elysia, t } from "elysia";
import { randomBytes, createHash } from "crypto";
import sql from "../db";
-// Generate a memorable 16-digit account key: XXXX-XXXX-XXXX-XXXX
function generateAccountKey(): string {
const bytes = randomBytes(8);
const hex = bytes.toString("hex").toUpperCase();
return `${hex.slice(0, 4)}-${hex.slice(4, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}`;
}
-// Middleware: validate account key from Authorization header
export function requireAuth(app: Elysia) {
return app.derive(async ({ headers, error }) => {
const key = headers["authorization"]?.replace("Bearer ", "").trim();
@@ -23,8 +21,28 @@ export function requireAuth(app: Elysia) {
}
export const account = new Elysia({ prefix: "/account" })
+ // Create account
+ .post("/register", async ({ body }) => {
+ const key = generateAccountKey();
+ const emailHash = body.email
+ ? createHash("sha256").update(body.email.toLowerCase().trim()).digest("hex")
+ : null;
+
+ await sql`INSERT INTO accounts (id, email_hash) VALUES (${key}, ${emailHash})`;
+
+ return {
+ key,
+ ...(body.email ? { email_registered: true } : { email_registered: false }),
+ };
+ }, {
+ body: t.Object({
+ email: t.Optional(t.String({ format: "email", description: "Optional. Used for recovery and alerts." })),
+ }),
+ detail: { summary: "Create account", tags: ["account"] },
+ })
+
+ // Update email
.use(requireAuth)
- // Update email (post-registration or settings)
.post("/email", async ({ accountId, body }) => {
const emailHash = body.email
? createHash("sha256").update(body.email.toLowerCase().trim()).digest("hex")
@@ -37,25 +55,3 @@ export const account = new Elysia({ prefix: "/account" })
}),
detail: { summary: "Update account email", tags: ["account"] },
});
-
-export const auth = new Elysia({ prefix: "/auth" })
- // Create a new account — no email required
- .post("/register", async ({ body }) => {
- const key = generateAccountKey();
- const emailHash = body.email
- ? createHash("sha256").update(body.email.toLowerCase().trim()).digest("hex")
- : null;
-
- await sql`INSERT INTO accounts (id, email_hash) VALUES (${key}, ${emailHash})`;
-
- return {
- key,
- message: "Save this key — it's your only credential. We don't store it.",
- ...(body.email ? { email_registered: true } : { email_registered: false }),
- };
- }, {
- body: t.Object({
- email: t.Optional(t.String({ format: "email", description: "Optional. Only used for account recovery." })),
- }),
- detail: { summary: "Create account", tags: ["auth"] },
- });