feat(api, web): интеграция RuVDS API v2
Docker / build (push) Failing after 21s

Синк VPS, баланса, платежей и тарифов через Bearer-токен из личного кабинета.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-06-29 14:10:15 +07:00
co-authored by Cursor
parent ce6414c65f
commit 9a29d88b95
19 changed files with 1526 additions and 12 deletions
@@ -14,7 +14,7 @@ import { providerAccountSchema, type ProviderAccountFormValues } from '@/lib/sch
import type { BillingMode, Provider } from '@/types/entities'
import { billingModeLabel } from '@/lib/format'
import { api, ApiError } from '@/lib/api-client'
import { accountCredentialLabels, isUserApiType } from '@/lib/provider-sync'
import { accountCredentialLabels, isTokenApiType } from '@/lib/provider-sync'
const EMPTY: ProviderAccountFormValues = {
providerId: '',
@@ -85,8 +85,10 @@ export function ProviderAccountEditSheet({
onOpenChange={onOpenChange}
title={isEdit ? 'Редактировать аккаунт' : 'Новый аккаунт'}
description={
isUserApiType(initialProvider?.apiType)
? 'API Token хранится на сервере и используется для синка с UserAPI'
isTokenApiType(initialProvider?.apiType)
? initialProvider?.apiType === 'ruvds'
? 'API-токен RuVDS хранится на сервере (создаётся в настройках ЛК RuVDS)'
: 'API Token хранится на сервере и используется для синка с UserAPI'
: initialProvider?.apiType === '4vps'
? 'Panel ID и API Key хранятся на сервере и используются для синка с 4VPS'
: initialProvider?.apiType === 'veesp'
@@ -105,10 +107,12 @@ export function ProviderAccountEditSheet({
const apiBaseUrl = (provider?.apiBaseUrl ?? '').trim()
const apiLogin = watch('apiLogin')?.trim() ?? ''
const apiPassword = watch('apiPassword')?.trim() ?? ''
const apiCredentials = buildApiCredentials(apiLogin, apiPassword)
const canTest = Boolean(apiBaseUrl && apiCredentials)
const credLabels = accountCredentialLabels(provider?.apiType)
const tokenOnly = isUserApiType(provider?.apiType)
const tokenOnly = isTokenApiType(provider?.apiType)
const apiCredentials = tokenOnly
? apiPassword
: buildApiCredentials(apiLogin, apiPassword)
const canTest = Boolean(apiBaseUrl && (tokenOnly ? apiPassword : apiCredentials))
return (
<>
@@ -6,7 +6,7 @@ import { SelectField } from '@/components/select-field'
import type { ZodType } from 'zod'
import { providerSchema, type ProviderFormValues } from '@/lib/schemas'
import type { ApiType } from '@/types/entities'
import { isUserApiType, USER_API_DEFAULT_BASE_URL, VEESP_DEFAULT_BASE_URL } from '@cfdm/shared/contracts/provider'
import { isUserApiType, RUVDS_DEFAULT_BASE_URL, USER_API_DEFAULT_BASE_URL, VEESP_DEFAULT_BASE_URL } from '@cfdm/shared/contracts/provider'
const EMPTY: ProviderFormValues = {
name: '',
@@ -60,6 +60,8 @@ export function ProviderEditSheet({
? 'Базовый URL API, например https://4vps.su/api'
: apiType === 'veesp'
? 'Базовый URL Veesp API, например https://secure.veesp.com/api'
: apiType === 'ruvds'
? 'Базовый URL RuVDS API v2, например https://api.ruvds.com'
: isUserApiType(apiType)
? `Базовый URL UserAPI, например ${USER_API_DEFAULT_BASE_URL[apiType]}`
: 'Один URL на хостера для BILLmanager'
@@ -68,6 +70,8 @@ export function ProviderEditSheet({
? 'https://4vps.su/api'
: apiType === 'veesp'
? VEESP_DEFAULT_BASE_URL
: apiType === 'ruvds'
? RUVDS_DEFAULT_BASE_URL
: isUserApiType(apiType)
? USER_API_DEFAULT_BASE_URL[apiType]
: undefined
@@ -91,6 +95,7 @@ export function ProviderEditSheet({
{ value: 'macloud', label: 'Маклауд' },
{ value: 'vdsina', label: 'VDSina' },
{ value: 'veesp', label: 'Veesp' },
{ value: 'ruvds', label: 'RuVDS' },
{ value: 'none', label: 'Нет' },
]}
/>
+9 -2
View File
@@ -1,8 +1,8 @@
import { isSyncApiType, isUserApiType } from '@cfdm/shared/contracts/provider'
import { isSyncApiType, isTokenApiType, isUserApiType } from '@cfdm/shared/contracts/provider'
import type { ProviderAccount, Provider } from '@/types/entities'
export { isSyncApiType, isUserApiType }
export { isSyncApiType, isTokenApiType, isUserApiType }
export function providerByIdMap(providers: Provider[]): Map<string, Provider> {
return new Map(providers.map((p) => [p.id, p]))
@@ -76,6 +76,13 @@ export function accountCredentialLabels(apiType?: string | null): {
loginPlaceholder: '[email protected]',
}
}
if (String(apiType).toLowerCase() === 'ruvds') {
return {
loginLabel: '',
passwordLabel: 'API Token',
loginPlaceholder: '',
}
}
if (isUserApiType(apiType)) {
return {
loginLabel: '',