Initial commit: Cloud Instances API
Multi-cloud VM instance database with Cloudflare Workers - Linode, Vultr, AWS connector integration - D1 database with regions, instances, pricing - Query API with filtering, caching, pagination - Cron-based auto-sync (daily + 6-hourly) - Health monitoring endpoint Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
409
src/types.ts
Normal file
409
src/types.ts
Normal file
@@ -0,0 +1,409 @@
|
||||
/**
|
||||
* Vault Credentials Types
|
||||
*/
|
||||
export interface VaultCredentials {
|
||||
provider: string;
|
||||
api_token: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vault API Response Structure
|
||||
*/
|
||||
export interface VaultSecretResponse {
|
||||
data: {
|
||||
data: {
|
||||
provider: string;
|
||||
api_token: string;
|
||||
};
|
||||
metadata: {
|
||||
created_time: string;
|
||||
custom_metadata: null;
|
||||
deletion_time: string;
|
||||
destroyed: boolean;
|
||||
version: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache Entry Structure
|
||||
*/
|
||||
export interface CacheEntry<T> {
|
||||
data: T;
|
||||
expiresAt: number;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Database Entity Types
|
||||
// ============================================================
|
||||
|
||||
export interface Provider {
|
||||
id: number;
|
||||
name: string;
|
||||
display_name: string;
|
||||
api_base_url: string | null;
|
||||
last_sync_at: string | null; // ISO 8601 datetime
|
||||
sync_status: 'pending' | 'syncing' | 'success' | 'error';
|
||||
sync_error: string | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface Region {
|
||||
id: number;
|
||||
provider_id: number;
|
||||
region_code: string;
|
||||
region_name: string;
|
||||
country_code: string | null; // ISO 3166-1 alpha-2
|
||||
latitude: number | null;
|
||||
longitude: number | null;
|
||||
available: number; // SQLite boolean (0/1)
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export type InstanceFamily = 'general' | 'compute' | 'memory' | 'storage' | 'gpu';
|
||||
|
||||
export interface InstanceType {
|
||||
id: number;
|
||||
provider_id: number;
|
||||
instance_id: string;
|
||||
instance_name: string;
|
||||
vcpu: number;
|
||||
memory_mb: number;
|
||||
storage_gb: number;
|
||||
transfer_tb: number | null;
|
||||
network_speed_gbps: number | null;
|
||||
gpu_count: number;
|
||||
gpu_type: string | null;
|
||||
instance_family: InstanceFamily | null;
|
||||
metadata: string | null; // JSON string
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface Pricing {
|
||||
id: number;
|
||||
instance_type_id: number;
|
||||
region_id: number;
|
||||
hourly_price: number;
|
||||
monthly_price: number;
|
||||
currency: string;
|
||||
available: number; // SQLite boolean (0/1)
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface PriceHistory {
|
||||
id: number;
|
||||
pricing_id: number;
|
||||
hourly_price: number;
|
||||
monthly_price: number;
|
||||
recorded_at: string;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Repository Input Types (for create/update operations)
|
||||
// ============================================================
|
||||
|
||||
export type ProviderInput = Omit<Provider, 'id' | 'created_at' | 'updated_at'>;
|
||||
export type RegionInput = Omit<Region, 'id' | 'created_at' | 'updated_at'>;
|
||||
export type InstanceTypeInput = Omit<InstanceType, 'id' | 'created_at' | 'updated_at'>;
|
||||
export type PricingInput = Omit<Pricing, 'id' | 'created_at' | 'updated_at'>;
|
||||
|
||||
// ============================================================
|
||||
// Error Types
|
||||
// ============================================================
|
||||
|
||||
export class RepositoryError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
public readonly code: string,
|
||||
public readonly cause?: unknown
|
||||
) {
|
||||
super(message);
|
||||
this.name = 'RepositoryError';
|
||||
}
|
||||
}
|
||||
|
||||
// Common error codes
|
||||
export const ErrorCodes = {
|
||||
NOT_FOUND: 'NOT_FOUND',
|
||||
DUPLICATE: 'DUPLICATE',
|
||||
CONSTRAINT_VIOLATION: 'CONSTRAINT_VIOLATION',
|
||||
DATABASE_ERROR: 'DATABASE_ERROR',
|
||||
TRANSACTION_FAILED: 'TRANSACTION_FAILED',
|
||||
INVALID_INPUT: 'INVALID_INPUT',
|
||||
} as const;
|
||||
|
||||
// ============================================================
|
||||
// Pagination Types
|
||||
// ============================================================
|
||||
|
||||
export interface PaginationOptions {
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
export interface PaginatedResult<T> {
|
||||
data: T[];
|
||||
total: number;
|
||||
limit: number;
|
||||
offset: number;
|
||||
hasMore: boolean;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// API Query and Response Types
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Query parameters for instance search and filtering
|
||||
*/
|
||||
export interface InstanceQueryParams {
|
||||
/** Provider filter (provider ID or name) */
|
||||
provider?: string;
|
||||
/** Region code filter */
|
||||
region_code?: string;
|
||||
/** Instance family filter */
|
||||
family?: InstanceFamily;
|
||||
/** Minimum vCPU count */
|
||||
min_vcpu?: number;
|
||||
/** Maximum vCPU count */
|
||||
max_vcpu?: number;
|
||||
/** Minimum memory in MB */
|
||||
min_memory?: number;
|
||||
/** Maximum memory in MB */
|
||||
max_memory?: number;
|
||||
/** Minimum hourly price */
|
||||
min_price?: number;
|
||||
/** Maximum hourly price */
|
||||
max_price?: number;
|
||||
/** Filter for GPU instances */
|
||||
has_gpu?: boolean;
|
||||
/** CPU architecture filter */
|
||||
architecture?: string;
|
||||
/** Sort field (e.g., 'hourly_price', 'vcpu', 'memory_mb') */
|
||||
sort_by?: string;
|
||||
/** Sort order ('asc' or 'desc') */
|
||||
sort_order?: 'asc' | 'desc';
|
||||
/** Page number for pagination (1-indexed) */
|
||||
page?: number;
|
||||
/** Number of results per page */
|
||||
limit?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combined instance data with pricing and relationships
|
||||
*/
|
||||
export interface InstanceData extends InstanceType {
|
||||
/** Provider information */
|
||||
provider: Provider;
|
||||
/** Region information */
|
||||
region: Region;
|
||||
/** Current pricing information */
|
||||
pricing: Pricing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Paginated API response for instance queries
|
||||
*/
|
||||
export interface InstanceResponse {
|
||||
/** Array of instance data */
|
||||
data: InstanceData[];
|
||||
/** Pagination metadata */
|
||||
pagination: {
|
||||
/** Current page number (1-indexed) */
|
||||
current_page: number;
|
||||
/** Total number of pages */
|
||||
total_pages: number;
|
||||
/** Number of results per page */
|
||||
per_page: number;
|
||||
/** Total number of results */
|
||||
total_results: number;
|
||||
/** Whether there is a next page */
|
||||
has_next: boolean;
|
||||
/** Whether there is a previous page */
|
||||
has_previous: boolean;
|
||||
};
|
||||
/** Query execution metadata */
|
||||
meta: {
|
||||
/** Query execution time in milliseconds */
|
||||
query_time_ms: number;
|
||||
/** Applied filters summary */
|
||||
filters_applied: Partial<InstanceQueryParams>;
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Sync Report Types
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Synchronization report for a single provider
|
||||
*/
|
||||
export interface ProviderSyncResult {
|
||||
/** Provider identifier */
|
||||
provider: string;
|
||||
/** Synchronization success status */
|
||||
success: boolean;
|
||||
/** Number of regions synced */
|
||||
regions_synced: number;
|
||||
/** Number of instances synced */
|
||||
instances_synced: number;
|
||||
/** Number of pricing records synced */
|
||||
pricing_synced: number;
|
||||
/** Sync duration in milliseconds */
|
||||
duration_ms: number;
|
||||
/** Error message if sync failed */
|
||||
error?: string;
|
||||
/** Detailed error information */
|
||||
error_details?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complete synchronization report for all providers
|
||||
*/
|
||||
export interface SyncReport {
|
||||
/** Overall sync success status */
|
||||
success: boolean;
|
||||
/** Sync start timestamp (ISO 8601) */
|
||||
started_at: string;
|
||||
/** Sync completion timestamp (ISO 8601) */
|
||||
completed_at: string;
|
||||
/** Total sync duration in milliseconds */
|
||||
total_duration_ms: number;
|
||||
/** Results for each provider */
|
||||
providers: ProviderSyncResult[];
|
||||
/** Summary statistics */
|
||||
summary: {
|
||||
/** Total number of providers synced */
|
||||
total_providers: number;
|
||||
/** Number of successful provider syncs */
|
||||
successful_providers: number;
|
||||
/** Number of failed provider syncs */
|
||||
failed_providers: number;
|
||||
/** Total regions synced across all providers */
|
||||
total_regions: number;
|
||||
/** Total instances synced across all providers */
|
||||
total_instances: number;
|
||||
/** Total pricing records synced across all providers */
|
||||
total_pricing: number;
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Health Check Types
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Health check response
|
||||
*/
|
||||
export interface HealthResponse {
|
||||
/** Service health status */
|
||||
status: 'healthy' | 'degraded' | 'unhealthy';
|
||||
/** Service version */
|
||||
version: string;
|
||||
/** Response timestamp (ISO 8601) */
|
||||
timestamp: string;
|
||||
/** Database connection status */
|
||||
database: {
|
||||
/** Database connection status */
|
||||
connected: boolean;
|
||||
/** Database response time in milliseconds */
|
||||
latency_ms?: number;
|
||||
};
|
||||
/** Uptime in seconds */
|
||||
uptime_seconds: number;
|
||||
/** Additional health metrics */
|
||||
metrics?: {
|
||||
/** Total number of instances in database */
|
||||
total_instances?: number;
|
||||
/** Total number of providers */
|
||||
total_providers?: number;
|
||||
/** Last successful sync timestamp (ISO 8601) */
|
||||
last_sync_at?: string;
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Cloudflare Worker Environment Types
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Cloudflare Worker environment bindings and variables
|
||||
*/
|
||||
export interface Env {
|
||||
/** D1 Database binding */
|
||||
DB: D1Database;
|
||||
/** Vault server URL for credentials management */
|
||||
VAULT_URL: string;
|
||||
/** Vault authentication token */
|
||||
VAULT_TOKEN: string;
|
||||
/** Batch size for synchronization operations */
|
||||
SYNC_BATCH_SIZE?: string;
|
||||
/** Cache TTL in seconds */
|
||||
CACHE_TTL_SECONDS?: string;
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Synchronization Types
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Synchronization stage enumeration
|
||||
*/
|
||||
export enum SyncStage {
|
||||
/** Initial stage before sync starts */
|
||||
IDLE = 'idle',
|
||||
/** Fetching provider credentials from Vault */
|
||||
FETCH_CREDENTIALS = 'fetch_credentials',
|
||||
/** Fetching regions from provider API */
|
||||
FETCH_REGIONS = 'fetch_regions',
|
||||
/** Fetching instance types from provider API */
|
||||
FETCH_INSTANCES = 'fetch_instances',
|
||||
/** Fetching pricing data from provider API */
|
||||
FETCH_PRICING = 'fetch_pricing',
|
||||
/** Normalizing and transforming data */
|
||||
NORMALIZE_DATA = 'normalize_data',
|
||||
/** Storing data in database */
|
||||
STORE_DATA = 'store_data',
|
||||
/** Sync completed successfully */
|
||||
COMPLETED = 'completed',
|
||||
/** Sync failed with error */
|
||||
FAILED = 'failed',
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalized data structure for batch database operations
|
||||
*/
|
||||
export interface NormalizedData {
|
||||
/** Normalized region data ready for insertion */
|
||||
regions: RegionInput[];
|
||||
/** Normalized instance type data ready for insertion */
|
||||
instances: InstanceTypeInput[];
|
||||
/** Normalized pricing data ready for insertion */
|
||||
pricing: PricingInput[];
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Additional Utility Types
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Generic API error response
|
||||
*/
|
||||
export interface ApiError {
|
||||
/** Error status code */
|
||||
status: number;
|
||||
/** Error type identifier */
|
||||
error: string;
|
||||
/** Human-readable error message */
|
||||
message: string;
|
||||
/** Additional error details */
|
||||
details?: any;
|
||||
/** Request timestamp (ISO 8601) */
|
||||
timestamp: string;
|
||||
/** Request path that caused the error */
|
||||
path?: string;
|
||||
}
|
||||
Reference in New Issue
Block a user