Files
HexaHost-GameCloud/packages/contracts/src/whmcs.ts
smueller 316679a913
Some checks failed
CI / Node — lint, typecheck, test, build (push) Failing after 9s
CI / Go — node-agent tests (push) Failing after 8s
CI / Go — edge-gateway build (push) Successful in 18s
Enhance WHMCS integration with mTLS support and product mapping features. Added mTLS configuration options, updated API endpoints for mTLS status and fingerprint registration, and implemented product validation API. Updated database schema and documentation accordingly.
2026-06-30 13:17:12 +02:00

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>;