Add shared package: types, schemas, plans and API client

Holds everything web, mobile and API must agree on: DTOs, zod input
schemas, plan entitlements (the single place feature gates live),
streaming-service link helpers, feed ordering and a typed API client.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
This commit is contained in:
2026-10-03 09:59:02 -04:00
co-authored by Claude Opus 5.5
parent 3627f29f73
commit 57c1733bab
9 changed files with 351 additions and 0 deletions
+46
View File
@@ -0,0 +1,46 @@
import { z } from 'zod';
import { STREAMING_SERVICES } from './services';
export const usernameSchema = z
.string()
.trim()
.toLowerCase()
.regex(/^[a-z0-9_]{3,32}$/, 'Username must be 3-32 characters: letters, numbers, underscores');
export const registerSchema = z.object({
username: usernameSchema,
email: z.email().trim().toLowerCase(),
password: z.string().min(8, 'Password must be at least 8 characters').max(200),
});
export const loginSchema = z.object({
email: z.email().trim().toLowerCase(),
password: z.string().min(1).max(200),
});
export const updateMeSchema = z.object({
displayName: z.string().trim().max(64).nullable().optional(),
bio: z.string().trim().max(280).nullable().optional(),
avatarUrl: z.url().max(500).nullable().optional(),
preferredService: z.enum(STREAMING_SERVICES).nullable().optional(),
});
export const setFeaturedSchema = z.union([
z.object({ deezerId: z.string().regex(/^\d+$/), comment: z.string().trim().max(280).nullable().optional() }),
z.object({ trackId: z.uuid(), comment: z.string().trim().max(280).nullable().optional() }),
]);
export const connectUsernameSchema = z.object({
username: z.string().trim().min(1).max(64),
});
export type RegisterInput = z.infer<typeof registerSchema>;
export type LoginInput = z.infer<typeof loginSchema>;
export type UpdateMeInput = z.infer<typeof updateMeSchema>;
export type SetFeaturedInput = z.infer<typeof setFeaturedSchema>;
export const jellyfinConnectSchema = z.object({
serverUrl: z.string().trim().min(1).max(500),
username: z.string().trim().min(1).max(128),
password: z.string().max(256).default(''),
});