diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-12-03 05:28:29 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-12-04 23:26:25 +0900 |
| commit | 950217ed3ca93a0aa0e964c2a8474ffc13c71912 (patch) | |
| tree | f5a8575a74aa8203a8fd49846ab859670009ffd7 /pkgs/server/src/routes/auth.ts | |
| parent | 7e75e0fa8f26a7890c210c67e4474778811b15bc (diff) | |
| download | kioku-950217ed3ca93a0aa0e964c2a8474ffc13c71912.tar.gz kioku-950217ed3ca93a0aa0e964c2a8474ffc13c71912.tar.zst kioku-950217ed3ca93a0aa0e964c2a8474ffc13c71912.zip | |
feat(auth): add user registration endpoint
Implement POST /api/auth/register endpoint with:
- Argon2 password hashing
- Zod validation for username (1-255 chars) and password (8-255 chars)
- Duplicate username check (returns 409 Conflict)
- Returns created user with id, username, and createdAt
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'pkgs/server/src/routes/auth.ts')
| -rw-r--r-- | pkgs/server/src/routes/auth.ts | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/pkgs/server/src/routes/auth.ts b/pkgs/server/src/routes/auth.ts new file mode 100644 index 0000000..3906d65 --- /dev/null +++ b/pkgs/server/src/routes/auth.ts @@ -0,0 +1,50 @@ +import { createUserSchema } from "@kioku/shared"; +import * as argon2 from "argon2"; +import { eq } from "drizzle-orm"; +import { Hono } from "hono"; +import { db, users } from "../db"; +import { Errors } from "../middleware"; + +const auth = new Hono(); + +auth.post("/register", async (c) => { + const body = await c.req.json(); + + const parsed = createUserSchema.safeParse(body); + if (!parsed.success) { + throw Errors.validationError(parsed.error.issues[0]?.message); + } + + const { username, password } = parsed.data; + + // Check if username already exists + const existingUser = await db + .select({ id: users.id }) + .from(users) + .where(eq(users.username, username)) + .limit(1); + + if (existingUser.length > 0) { + throw Errors.conflict("Username already exists", "USERNAME_EXISTS"); + } + + // Hash password with Argon2 + const passwordHash = await argon2.hash(password); + + // Create user + const [newUser] = await db + .insert(users) + .values({ + username, + passwordHash, + }) + .returning({ + id: users.id, + username: users.username, + createdAt: users.createdAt, + }); + + return c.json({ user: newUser }, 201); +}); + +export { auth }; |
