@kaze-no-manga/models
v1.0.0
Published
π Shared TypeScript types, Zod schemas, and GraphQL definitions for Kaze no Manga ecosystem
Maintainers
Readme
@kaze/models
Shared TypeScript types, Zod schemas, and GraphQL definitions for Kaze no Manga
Overview
This package contains all shared data models, type definitions, validation schemas, and GraphQL types used across the Kaze no Manga ecosystem.
Features
- π TypeScript Interfaces: Strongly-typed data models
- β Zod Schemas: Runtime validation and type inference
- π· GraphQL Types: Generated from SDL schemas
- π Type Safety: End-to-end type safety across all services
Installation
npm install @kaze/modelsUsage
TypeScript Interfaces
import { Manga, Chapter, User, LibraryEntry } from '@kaze/models'
const manga: Manga = {
id: '123',
title: 'One Piece',
altTitles: ['γ―γ³γγΌγΉ'],
// ...
}Zod Schemas
import { mangaSchema, chapterSchema } from '@kaze/models/schemas'
// Validate data
const result = mangaSchema.safeParse(data)
if (result.success) {
console.log(result.data) // Typed as Manga
} else {
console.error(result.error)
}
// Type inference
type MangaInput = z.infer<typeof mangaSchema>GraphQL Types
import { Query, Mutation, MangaResolvers } from '@kaze/models/graphql'
// Use in resolvers
const resolvers: MangaResolvers = {
Query: {
getManga: async (_, { id }) => {
// Return type is automatically typed
}
}
}Core Models
User
interface User {
id: string // Cognito ID
email: string
name?: string
avatar?: string
preferences: UserPreferences
createdAt: Date
updatedAt: Date
}
interface UserPreferences {
notifications: {
email: boolean
push: boolean
maxPerDay: number
}
reader: {
imageWidth: 'fit' | 'full'
spacing: number
theme: 'light' | 'dark' | 'auto'
}
}Manga
interface Manga {
id: string
title: string
altTitles: string[]
description?: string
coverImage?: string
status: MangaStatus
genres: string[]
authors: string[]
year?: number
sources: MangaSource[]
createdAt: Date
updatedAt: Date
}
type MangaStatus = 'ongoing' | 'completed' | 'hiatus' | 'cancelled'
interface MangaSource {
sourceId: string // Reference to Source entity
sourceMangaId: string // ID on the source platform
url: string
priority: number // For automatic source selection
lastChecked: Date
}Source
interface Source {
id: string
name: string // 'MangaPark', 'OmegaScans'
baseUrl: string
status: SourceStatus
priority: number
createdAt: Date
updatedAt: Date
}
type SourceStatus = 'active' | 'deprecated' | 'unavailable'Chapter
interface Chapter {
id: string
mangaId: string
sourceId: string
number: number // Supports decimals (5.5, 5.1)
title?: string
releaseDate?: Date
images: ChapterImage[]
createdAt: Date
updatedAt: Date
}
interface ChapterImage {
url: string // S3 URL after download
originalUrl: string // Original source URL
page: number
width?: number
height?: number
}Library Entry
interface LibraryEntry {
userId: string
mangaId: string
status: ReadingStatus
rating?: number // 1-10
notes?: string
currentChapterId?: string
currentChapterNumber?: number
lastReadAt?: Date
addedAt: Date
updatedAt: Date
}
type ReadingStatus = 'reading' | 'completed' | 'plan_to_read' | 'dropped' | 'on_hold'Reading History
interface ReadingHistory {
id: string
userId: string
mangaId: string
chapterId: string
chapterNumber: number
completed: boolean
readAt: Date
}Notification
interface Notification {
id: string
userId: string
mangaId: string
chapterId: string
type: NotificationType
title: string
message: string
read: boolean
sentAt: Date
readAt?: Date
}
type NotificationType = 'new_chapter' | 'manga_completed' | 'source_changed'GraphQL Schema
Queries
type Query {
# Manga
searchManga(query: String!): [Manga!]!
getManga(id: ID!): Manga
getChapters(mangaId: ID!): [Chapter!]!
# Library
getLibrary: [LibraryEntry!]!
getReadingHistory(limit: Int): [ReadingHistory!]!
# User
getProfile: User!
getNotifications(unreadOnly: Boolean): [Notification!]!
}Mutations
type Mutation {
# Library
addToLibrary(mangaId: ID!): LibraryEntry!
updateLibraryEntry(mangaId: ID!, input: LibraryEntryInput!): LibraryEntry!
removeFromLibrary(mangaId: ID!): Boolean!
# Progress
updateProgress(mangaId: ID!, chapterId: ID!): LibraryEntry!
markChapterAsRead(chapterId: ID!): ReadingHistory!
# User
updatePreferences(input: UserPreferencesInput!): User!
markNotificationAsRead(id: ID!): Notification!
}Validation Schemas
All models have corresponding Zod schemas for runtime validation:
import { z } from 'zod'
export const mangaSchema = z.object({
id: z.string().uuid(),
title: z.string().min(1).max(500),
altTitles: z.array(z.string()).default([]),
description: z.string().max(5000).optional(),
status: z.enum(['ongoing', 'completed', 'hiatus', 'cancelled']),
genres: z.array(z.string()),
authors: z.array(z.string()),
year: z.number().int().min(1900).max(2100).optional(),
// ...
})
export const chapterSchema = z.object({
id: z.string().uuid(),
mangaId: z.string().uuid(),
number: z.number().positive(),
title: z.string().max(500).optional(),
// ...
})Code Generation
GraphQL types are automatically generated from SDL schemas:
# Generate TypeScript types from GraphQL schema
npm run codegenConfiguration in codegen.yml:
schema: './src/graphql/schema.graphql'
generates:
./src/graphql/types.ts:
plugins:
- typescript
- typescript-resolversPackage Structure
models/
βββ src/
β βββ types/
β β βββ user.ts
β β βββ manga.ts
β β βββ chapter.ts
β β βββ library.ts
β β βββ index.ts
β βββ schemas/
β β βββ user.schema.ts
β β βββ manga.schema.ts
β β βββ chapter.schema.ts
β β βββ library.schema.ts
β β βββ index.ts
β βββ graphql/
β β βββ schema.graphql
β β βββ types.ts (generated)
β β βββ index.ts
β βββ index.ts
βββ codegen.yml
βββ package.json
βββ README.mdDevelopment
# Install dependencies
npm install
# Generate GraphQL types
npm run codegen
# Build package
npm run build
# Run tests
npm test
# Publish (private)
npm publishVersioning
This package follows Semantic Versioning:
- Major: Breaking changes to types or schemas
- Minor: New types or optional fields
- Patch: Bug fixes or documentation updates
License
MIT License - see LICENSE for details.
Part of the Kaze no Manga project
