319 lines
10 KiB
TypeScript
319 lines
10 KiB
TypeScript
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<typeof whmcsHealthResponseSchema>;
|
|
export type WhmcsPlanCatalogResponse = z.infer<typeof whmcsPlanCatalogResponseSchema>;
|
|
export type WhmcsUpsertClientRequest = z.infer<typeof whmcsUpsertClientRequestSchema>;
|
|
export type WhmcsUpsertClientResponse = z.infer<typeof whmcsUpsertClientResponseSchema>;
|
|
export type WhmcsProvisionServiceRequest = z.infer<typeof whmcsProvisionServiceRequestSchema>;
|
|
export type WhmcsServiceResponse = z.infer<typeof whmcsServiceResponseSchema>;
|
|
export type WhmcsChangePackageRequest = z.infer<typeof whmcsChangePackageRequestSchema>;
|
|
export type WhmcsSuspendRequest = z.infer<typeof whmcsSuspendRequestSchema>;
|
|
export type WhmcsCreateSsoRequest = z.infer<typeof whmcsCreateSsoRequestSchema>;
|
|
export type WhmcsCreateSsoResponse = z.infer<typeof whmcsCreateSsoResponseSchema>;
|
|
export type SsoConsumeRequest = z.infer<typeof ssoConsumeRequestSchema>;
|
|
export type SsoConsumeResponse = z.infer<typeof ssoConsumeResponseSchema>;
|
|
|
|
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<typeof whmcsReconcileRequestSchema>;
|
|
export type WhmcsReconcileResponse = z.infer<typeof whmcsReconcileResponseSchema>;
|
|
export type WhmcsListAccountsResponse = z.infer<typeof whmcsListAccountsResponseSchema>;
|
|
export type WhmcsImportServiceRequest = z.infer<typeof whmcsImportServiceRequestSchema>;
|
|
export type WhmcsEventsResponse = z.infer<typeof whmcsEventsResponseSchema>;
|
|
export type WhmcsEventsAckRequest = z.infer<typeof whmcsEventsAckRequestSchema>;
|
|
export type WhmcsEventsAckResponse = z.infer<typeof whmcsEventsAckResponseSchema>;
|
|
export type WhmcsUsageResponse = z.infer<typeof whmcsUsageResponseSchema>;
|
|
export type WhmcsUsageAdjustmentRequest = z.infer<typeof whmcsUsageAdjustmentRequestSchema>;
|
|
|
|
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<typeof whmcsDashboardStatsResponseSchema>;
|
|
|
|
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<typeof whmcsRegisterMtlsRequestSchema>;
|
|
export type WhmcsMtlsStatusResponse = z.infer<typeof whmcsMtlsStatusResponseSchema>;
|
|
export type WhmcsValidatePlanResponse = z.infer<typeof whmcsValidatePlanResponseSchema>;
|