import { z } from 'zod'; import { authUserSchema } from './auth'; import { serverResponseSchema } from './servers'; export const whmcsHealthResponseSchema = z.object({ status: z.literal('ok'), integrationId: z.string(), billingProvider: z.string(), }); export const whmcsPlanCatalogItemSchema = z.object({ id: z.string().uuid(), slug: z.string(), name: z.string(), maxRamMb: z.number().int(), isFree: z.boolean(), }); export const whmcsPlanCatalogResponseSchema = z.object({ plans: z.array(whmcsPlanCatalogItemSchema), }); export const whmcsUpsertClientRequestSchema = z.object({ email: z.string().email(), username: z.string().min(3).max(32), displayName: z.string().max(64).optional(), }); export const whmcsUpsertClientResponseSchema = z.object({ userId: z.string().uuid(), externalClientId: z.string(), created: z.boolean(), }); export const whmcsProvisionServiceRequestSchema = z.object({ externalServiceId: z.string().min(1).max(64), externalClientId: z.string().min(1).max(64), externalProductId: z.string().max(64).optional(), planSlug: z.string().min(1).max(64), serverName: z.string().min(1).max(64), minecraftVersion: z.string().min(1).max(32).default('1.21.1'), softwareFamily: z .enum(['VANILLA', 'PAPER', 'PURPUR', 'FABRIC', 'FORGE', 'NEOFORGE', 'QUILT', 'BEDROCK_DEDICATED']) .default('VANILLA'), edition: z.enum(['JAVA', 'BEDROCK']).default('JAVA'), eulaAccepted: z.literal(true), }); export const whmcsServiceResponseSchema = z.object({ externalServiceId: z.string(), status: z.enum(['PENDING', 'ACTIVE', 'SUSPENDED', 'TERMINATED']), server: serverResponseSchema, }); export const whmcsChangePackageRequestSchema = z.object({ planSlug: z.string().min(1).max(64), ramMb: z.number().int().min(512).max(65536).optional(), }); export const whmcsSuspendRequestSchema = z.object({ reason: z.string().max(256).optional(), }); export const whmcsSsoRoleSchema = z.enum(['owner', 'admin']); export const whmcsSsoKindSchema = z.enum(['service', 'admin']); export const whmcsCreateSsoRequestSchema = z.object({ externalClientId: z.string().min(1).max(64), externalUserId: z.string().min(1).max(64), role: whmcsSsoRoleSchema.default('owner'), kind: whmcsSsoKindSchema.default('service'), targetPath: z.string().max(256).optional(), }); export const whmcsCreateSsoResponseSchema = z.object({ ticketId: z.string().uuid(), redirectUrl: z.string().url(), expiresAt: z.string().datetime(), targetPath: z.string(), }); export const ssoConsumeRequestSchema = z.object({ ticket: z.string().min(32).max(256), }); export const ssoImpersonationSchema = z.object({ isImpersonation: z.boolean(), label: z.string().optional(), }); export const ssoConsumeResponseSchema = z.object({ redirectPath: z.string(), user: authUserSchema, impersonation: ssoImpersonationSchema.optional(), }); export type WhmcsHealthResponse = z.infer; export type WhmcsPlanCatalogResponse = z.infer; export type WhmcsUpsertClientRequest = z.infer; export type WhmcsUpsertClientResponse = z.infer; export type WhmcsProvisionServiceRequest = z.infer; export type WhmcsServiceResponse = z.infer; export type WhmcsChangePackageRequest = z.infer; export type WhmcsSuspendRequest = z.infer; export type WhmcsCreateSsoRequest = z.infer; export type WhmcsCreateSsoResponse = z.infer; export type SsoConsumeRequest = z.infer; export type SsoConsumeResponse = z.infer; export const whmcsExpectedStatusSchema = z.enum([ 'Pending', 'Active', 'Suspended', 'Terminated', 'Cancelled', ]); export const whmcsReconcileRequestSchema = z.object({ expectedWhmcsStatus: whmcsExpectedStatusSchema.optional(), expectedPlanSlug: z.string().max(64).optional(), expectedRamMb: z.number().int().min(512).max(65536).optional(), dryRun: z.boolean().default(false), autoRepair: z.boolean().default(false), }); export const reconciliationSeveritySchema = z.enum([ 'INFO', 'WARNING', 'BLOCKING', 'DESTRUCTIVE', 'SECURITY', ]); export const reconciliationIssueSchema = z.object({ id: z.string().uuid(), code: z.string(), severity: reconciliationSeveritySchema, message: z.string(), externalServiceId: z.string().nullable(), serverId: z.string().uuid().nullable(), details: z.record(z.unknown()).optional(), autoRepaired: z.boolean(), }); export const whmcsReconcileResponseSchema = z.object({ runId: z.string().uuid(), dryRun: z.boolean(), issues: z.array(reconciliationIssueSchema), repaired: z.array(z.string()), }); export const whmcsListAccountsResponseSchema = z.object({ accounts: z.array( z.object({ externalServiceId: z.string(), externalClientId: z.string(), serverId: z.string().uuid(), domain: z.string(), username: z.string().nullable(), status: z.enum(['Active', 'Suspended', 'Terminated', 'Pending']), planSlug: z.string(), ramMb: z.number().int(), gameCloudStatus: z.string(), linkStatus: z.enum(['PENDING', 'ACTIVE', 'SUSPENDED', 'TERMINATED']), lastReconciledAt: z.string().datetime().nullable(), }), ), }); export const whmcsImportServiceRequestSchema = z.object({ externalServiceId: z.string().min(1).max(64), externalClientId: z.string().min(1).max(64), serverId: z.string().uuid(), externalProductId: z.string().max(64).optional(), expectedPlanSlug: z.string().max(64).optional(), }); export const integrationEventSchema = z.object({ id: z.string().uuid(), eventType: z.string(), payload: z.record(z.unknown()), status: z.enum(['PENDING', 'ACKNOWLEDGED', 'DEAD_LETTER']), createdAt: z.string().datetime(), }); export const whmcsEventsResponseSchema = z.object({ events: z.array(integrationEventSchema), nextCursor: z.string().uuid().nullable(), }); export const whmcsEventsAckRequestSchema = z.object({ eventIds: z.array(z.string().uuid()).min(1).max(100), deadLetter: z.boolean().default(false), deadLetterReason: z.string().max(512).optional(), }); export const whmcsEventsAckResponseSchema = z.object({ acknowledged: z.number().int(), }); export const whmcsUsageMetricsSchema = z.object({ runtime_minutes: z.number(), memory_gib_minutes: z.number(), cpu_core_minutes: z.number(), storage_gib_days: z.number(), backup_storage_gib_days: z.number(), egress_gib: z.number(), extra_port_days: z.number(), priority_queue_minutes: z.number(), managed_service_units: z.number(), }); export const whmcsUsageUpdateSchema = z.object({ diskUsageGiB: z.number(), bandwidthGiB: z.number(), }); export const whmcsUsageQuerySchema = z.object({ periodStart: z.string().datetime().optional(), periodEnd: z.string().datetime().optional(), testMode: z.coerce.boolean().default(false), }); export const whmcsUsageResponseSchema = z.object({ exportId: z.string().uuid(), externalServiceId: z.string(), serverId: z.string().uuid(), periodStart: z.string().datetime(), periodEnd: z.string().datetime(), metrics: whmcsUsageMetricsSchema, usageUpdate: whmcsUsageUpdateSchema, contentHash: z.string(), status: z.enum(['DRAFT', 'EXPORTED', 'ADJUSTED']), isTestMode: z.boolean(), adjustments: z.array( z.object({ metricKey: z.string(), delta: z.number(), reason: z.string(), }), ), }); export const whmcsUsageAdjustmentRequestSchema = z.object({ periodStart: z.string().datetime(), periodEnd: z.string().datetime(), adjustments: z .array( z.object({ metricKey: z.string().min(1).max(64), delta: z.number(), reason: z.string().min(1).max(256), }), ) .min(1) .max(20), testMode: z.boolean().default(false), }); export type WhmcsReconcileRequest = z.infer; export type WhmcsReconcileResponse = z.infer; export type WhmcsListAccountsResponse = z.infer; export type WhmcsImportServiceRequest = z.infer; export type WhmcsEventsResponse = z.infer; export type WhmcsEventsAckRequest = z.infer; export type WhmcsEventsAckResponse = z.infer; export type WhmcsUsageResponse = z.infer; export type WhmcsUsageAdjustmentRequest = z.infer; export const whmcsDashboardStatsResponseSchema = z.object({ integrationId: z.string(), billingProvider: z.enum(['internal', 'whmcs', 'stripe']), moduleVersion: z.string(), linkedClients: z.number().int(), linkedServices: z.number().int(), suspendedServices: z.number().int(), terminatedServices: z.number().int(), pendingEvents: z.number().int(), deadLetterEvents: z.number().int(), openReconciliationIssues: z.number().int(), exportedUsagePeriods: z.number().int(), eventsCursor: z.string().uuid().nullable(), lastEventSyncAt: z.string().datetime().nullable(), lastReconciliationAt: z.string().datetime().nullable(), mtlsEnabled: z.boolean(), mtlsFingerprintRegistered: z.boolean(), }); export type WhmcsDashboardStatsResponse = z.infer; export const whmcsRegisterMtlsRequestSchema = z.object({ fingerprint: z.string().min(32).max(128), subject: z.string().max(256).optional(), }); export const whmcsMtlsStatusResponseSchema = z.object({ integrationId: z.string(), mtlsEnabled: z.boolean(), fingerprintRegistered: z.boolean(), fingerprintPreview: z.string().nullable(), subject: z.string().nullable(), }); export const whmcsValidatePlanRequestSchema = z.object({ planSlug: z.string().min(1).max(64), }); export const whmcsValidatePlanResponseSchema = z.object({ valid: z.boolean(), planSlug: z.string(), plan: whmcsPlanCatalogItemSchema.nullable(), }); export type WhmcsRegisterMtlsRequest = z.infer; export type WhmcsMtlsStatusResponse = z.infer; export type WhmcsValidatePlanResponse = z.infer;