novel-reader-sdk
Version:
SDK for Novel Reader API
386 lines (347 loc) • 8.26 kB
text/typescript
/**
* Shared Types for Novel Reader Scraping Service
*
* Single source of truth for all API types used by both service and client
*/
// ===== Core Data Models =====
export interface Review {
username: string;
rating: number;
progress?: string;
date: string;
content: string;
likes: number;
spoilers?: Array<{ position: number; content: string }>;
}
export interface NovelDetails extends NovelSearchResult {
alternativeTitles?: string[];
author?: string;
artist?: string;
year?: number;
status?: string;
licensed?: boolean;
englishPublisher?: string;
tags?: string[];
reviews?: Review[];
chapterList?: Array<{
title: string;
url: string;
releaseDate?: string;
group?: string;
}>;
}
export interface Chapter {
title: string;
url: string;
chapterNumber?: number;
publishedAt?: string;
}
export interface ChapterData {
title: string;
content: string;
navigation: {
previousChapter?: string;
nextChapter?: string;
};
}
export interface NovelSearchResult {
title: string;
url: string;
coverUrl?: string;
rating?: number;
chapters?: number;
status?: string;
genres?: string[];
description?: string;
}
export interface SiteConfiguration {
name: string;
hostname: string;
configuration: {
titleSelector: string;
contentSelector: string;
contentParagraphSelector: string;
navigationSelectors: {
previousChapter: string;
nextChapter: string;
};
};
status: 'active' | 'inactive';
useProxy: boolean;
}
// ===== API Response Types =====
export interface ScrapingServiceResponse<T> {
results: T;
}
export interface PaginatedResponse<T> {
results: T[];
pagination: {
page: number;
total: number;
hasNext: boolean;
};
}
export interface ApiError {
error: {
code: string;
message: string;
};
}
// ===== Health Management Types =====
/**
* Service health status levels
*/
export type ServiceStatus = 'healthy' | 'degraded' | 'unhealthy';
/**
* Browser manager health status
*/
export interface BrowserHealthStatus {
status: ServiceStatus;
activeInstances: number;
availableInstances: number;
totalInstances: number;
maxInstances: number;
error?: string;
}
/**
* Proxy provider breakdown statistics
*/
export interface ProxyProviderBreakdown {
total: number;
healthy: number;
unhealthy: number;
}
/**
* Comprehensive proxy health status
*/
export interface ProxyHealthStatus {
status: ServiceStatus;
pool: {
enabled: boolean;
totalProxies: number;
healthyProxies: number;
unhealthyProxies: number;
healthyPercentage: number;
hasEnoughHealthyProxies: boolean;
};
providers: Record<'getproxylist' | 'proxyscrape' | 'geonode', ProxyProviderBreakdown>;
schedule: {
lastRefresh: string;
nextRefresh: string;
lastHealthCheck: string;
nextHealthCheck: string;
};
recommendations: string[];
error?: string;
}
/**
* Complete health overview for dashboards
*/
export interface HealthOverview {
timestamp: string;
serviceStatus: {
isOnline: boolean;
};
overall: {
status: ServiceStatus;
};
browser: BrowserHealthStatus | null;
proxy: ProxyHealthStatus | null;
errors: {
overall?: string;
proxy?: string;
browser?: string;
};
}
// ===== Health Status Types =====
export interface ProxyPoolInfo {
enabled: boolean;
totalProxies: number;
healthyProxies: number;
unhealthyProxies: number;
healthyPercentage: number;
hasEnoughHealthyProxies: boolean;
}
export interface HealthStatus {
status: 'healthy' | 'degraded' | 'unhealthy';
timestamp: string;
version: string;
browser: {
activeInstances: number;
availableInstances: number;
totalInstances: number;
maxInstances: number;
};
proxy: ProxyPoolInfo;
}
// ===== Request/Response Schemas =====
export interface SearchNovelsRequest {
query: string;
page?: number;
limit?: number;
}
export interface ScrapeChapterRequest {
url: string;
customConfig?: Partial<SiteConfiguration['configuration']>;
}
export interface BatchScrapeRequest {
urls: string[];
maxConcurrent?: number;
}
export interface ValidateUrlRequest {
url: string;
}
export interface TestSiteConfigRequest {
hostname: string;
testUrl: string;
}
// ===== Database Scraper Types =====
export interface DatabaseInfo {
id: string;
name: string;
description: string;
supportedOperations: ('search' | 'latest' | 'popular' | 'novel')[];
status: 'active' | 'inactive';
}
export interface LatestNovelsRequest {
page?: number;
limit?: number;
}
export interface PopularNovelsRequest {
period?: 'day' | 'week' | 'month' | 'all';
page?: number;
limit?: number;
}
export interface NovelDetailsRequest {
url: string;
includeChapters?: boolean;
}
// ===== Error Types =====
export type ErrorCode =
| 'INTERNAL_SERVER_ERROR'
| 'NOT_FOUND'
| 'BAD_REQUEST'
| 'UNSUPPORTED_SITE'
| 'CONTENT_NOT_FOUND'
| 'BROWSER_ERROR'
| 'TIMEOUT_ERROR'
| 'RATE_LIMIT_EXCEEDED';
export type ErrorType =
| 'SCRAPING_ERROR'
| 'CHAPTER_NOT_FOUND'
| 'CONTENT_NOT_FOUND'
| 'UNSUPPORTED_SITE'
| 'BROWSER_ERROR'
| 'TIMEOUT_ERROR'
| 'VALIDATION_ERROR'
| 'RATE_LIMIT_ERROR';
// ===== Utility Types =====
export type DatabaseId = 'novelupdates';
export type SupportedOperation = 'search' | 'latest' | 'popular' | 'novel';
// ===== API Route Definitions =====
export interface ApiRoutes {
databases: {
list: {
method: 'GET';
path: '/api/v1/databases';
response: ScrapingServiceResponse<DatabaseInfo[]>;
};
search: {
method: 'GET';
path: '/api/v1/databases/:id/search';
params: { id: DatabaseId };
query: SearchNovelsRequest;
response: PaginatedResponse<NovelSearchResult>;
};
latest: {
method: 'GET';
path: '/api/v1/databases/:id/latest';
params: { id: DatabaseId };
query: LatestNovelsRequest;
response: PaginatedResponse<NovelSearchResult>;
};
popular: {
method: 'GET';
path: '/api/v1/databases/:id/popular';
params: { id: DatabaseId };
query: PopularNovelsRequest;
response: PaginatedResponse<NovelSearchResult>;
};
novel: {
method: 'GET';
path: '/api/v1/databases/:id/novel';
params: { id: DatabaseId };
query: NovelDetailsRequest;
response: ScrapingServiceResponse<NovelDetails>;
};
};
chapters: {
scrape: {
method: 'POST';
path: '/api/v1/chapters/scrape';
body: ScrapeChapterRequest;
response: ScrapingServiceResponse<ChapterData>;
};
batch: {
method: 'POST';
path: '/api/v1/chapters/batch';
body: BatchScrapeRequest;
response: ScrapingServiceResponse<ChapterData[]>;
};
validateUrl: {
method: 'GET';
path: '/api/v1/chapters/validate-url';
query: ValidateUrlRequest;
response: ScrapingServiceResponse<{ supported: boolean; hostname: string }>;
};
};
sites: {
list: {
method: 'GET';
path: '/api/v1/sites';
response: ScrapingServiceResponse<SiteConfiguration[]>;
};
get: {
method: 'GET';
path: '/api/v1/sites/:hostname';
params: { hostname: string };
response: ScrapingServiceResponse<SiteConfiguration>;
};
update: {
method: 'PUT';
path: '/api/v1/sites/:hostname';
params: { hostname: string };
body: Partial<SiteConfiguration>;
response: ScrapingServiceResponse<SiteConfiguration>;
};
test: {
method: 'POST';
path: '/api/v1/sites/:hostname/test';
params: { hostname: string };
body: TestSiteConfigRequest;
response: ScrapingServiceResponse<{ success: boolean; data?: ChapterData }>;
};
};
health: {
overall: {
method: 'GET';
path: '/api/v1/health';
response: HealthStatus;
};
overview: {
method: 'GET';
path: '/api/v1/health/overview';
response: HealthOverview;
};
proxy: {
method: 'GET';
path: '/api/v1/health/proxy';
response: ProxyHealthStatus;
};
browser: {
method: 'GET';
path: '/api/v1/health/browser';
response: BrowserHealthStatus;
};
};
}