feat(auth): add User, Cookie, Session entities + errors + config

This commit is contained in:
2026-05-05 00:38:49 +02:00
parent 54dc9d33d5
commit ceffd05063
7 changed files with 113 additions and 0 deletions

View File

@@ -0,0 +1 @@
export const SESSION_COOKIE = "session";

View File

@@ -0,0 +1,15 @@
type CookieAttributes = {
secure?: boolean;
path?: string;
domain?: string;
sameSite?: "lax" | "strict" | "none";
httpOnly?: boolean;
maxAge?: number;
expires?: Date;
};
export type Cookie = {
name: string;
value: string;
attributes: CookieAttributes;
};

View File

@@ -0,0 +1,23 @@
export class AuthenticationError extends Error {
constructor(message: string, options?: ErrorOptions) {
super(message, options);
}
}
export class UnauthenticatedError extends Error {
constructor(message: string, options?: ErrorOptions) {
super(message, options);
}
}
export class UnauthorizedError extends Error {
constructor(message: string, options?: ErrorOptions) {
super(message, options);
}
}
export class InputParseError extends Error {
constructor(message: string, options?: ErrorOptions) {
super(message, options);
}
}

View File

@@ -0,0 +1,23 @@
import { describe, expect, it } from "vitest";
import { sessionSchema } from "./session";
describe("sessionSchema", () => {
it("accepts a valid session", () => {
const result = sessionSchema.parse({
id: "session_1",
userId: "1",
expiresAt: new Date(),
});
expect(result.userId).toBe("1");
});
it("rejects non-Date expiresAt", () => {
expect(() =>
sessionSchema.parse({
id: "session_1",
userId: "1",
expiresAt: "2026-05-04",
}),
).toThrow();
});
});

View File

@@ -0,0 +1,9 @@
import { z } from "zod";
export const sessionSchema = z.object({
id: z.string(),
userId: z.string(),
expiresAt: z.date(),
});
export type Session = z.infer<typeof sessionSchema>;

View File

@@ -0,0 +1,33 @@
import { describe, expect, it } from "vitest";
import { userSchema } from "./user";
describe("userSchema", () => {
it("accepts a valid user", () => {
const result = userSchema.parse({
id: "1",
username: "alice",
passwordHash: "hashed_password_1",
});
expect(result.username).toBe("alice");
});
it("rejects username shorter than 3 chars", () => {
expect(() =>
userSchema.parse({
id: "1",
username: "ab",
passwordHash: "hashed_password_1",
}),
).toThrow();
});
it("rejects passwordHash shorter than 6 chars", () => {
expect(() =>
userSchema.parse({
id: "1",
username: "alice",
passwordHash: "abc",
}),
).toThrow();
});
});

View File

@@ -0,0 +1,9 @@
import { z } from "zod";
export const userSchema = z.object({
id: z.string(),
username: z.string().min(3).max(31),
passwordHash: z.string().min(6).max(255),
});
export type User = z.infer<typeof userSchema>;