feat(mcp): подготовить сервер и доступ к приёмке
This commit is contained in:
commit
bf3d50e1ff
3835 files changed
+537122
No files matched your search
@@ -0,0 +1,79 @@
|
||||
import { z } from "zod"
|
||||
import {
|
||||
acmeCloudflareSettingsDtoSchema,
|
||||
certificateIssueJobSchema,
|
||||
certificateIssueRequestSchema,
|
||||
certificateRenewSettingsDtoSchema,
|
||||
certificatesListResponseSchema,
|
||||
certificatesStateSchema,
|
||||
putAcmeCloudflareSettingsSchema,
|
||||
putCertificateRenewSettingsSchema,
|
||||
testAcmeCloudflareSettingsSchema,
|
||||
} from "@mmapp/contracts/certificates"
|
||||
import type { CertificateIssueRequest } from "@mmapp/contracts/certificates"
|
||||
import { ApiClientError, requestJson } from "@/shared/api/http-client"
|
||||
|
||||
const issueAckSchema = z.object({ jobId: z.string().min(1).refine(value => value.trim() === value) })
|
||||
const acmeTestSchema = z.object({ ok: z.boolean(), message: z.string().optional() })
|
||||
|
||||
function certificateJson(baseUrl: string, path: string, options?: RequestInit) {
|
||||
const signal = AbortSignal.any([...(options?.signal ? [options.signal] : []), AbortSignal.timeout(30_000)])
|
||||
return requestJson<unknown>(baseUrl, path, { ...options, signal })
|
||||
}
|
||||
|
||||
export async function listCertificates(baseUrl: string, options?: RequestInit) {
|
||||
return certificatesListResponseSchema.parse(await certificateJson(baseUrl, "/api/certificates", { ...options, method: "GET" }))
|
||||
}
|
||||
|
||||
export async function refreshCertificates(baseUrl: string, options?: RequestInit) {
|
||||
return certificatesListResponseSchema.parse(await certificateJson(baseUrl, "/api/certificates/refresh", { ...options, method: "POST" }))
|
||||
}
|
||||
|
||||
export async function createCertificateIssueJob(baseUrl: string, payload: CertificateIssueRequest, options?: RequestInit) {
|
||||
const body = certificateIssueRequestSchema.parse(payload)
|
||||
const result = issueAckSchema.parse(await certificateJson(baseUrl, "/api/certificates/issue", { ...options, method: "POST", body: JSON.stringify(body) }))
|
||||
if (body.requestId && result.jobId !== body.requestId) throw new Error("Подтверждение относится к другому запросу выпуска")
|
||||
return result
|
||||
}
|
||||
|
||||
export async function getCertificateIssueJob(baseUrl: string, jobId: string, options?: RequestInit) {
|
||||
const result = certificateIssueJobSchema.parse(await certificateJson(baseUrl, "/api/certificates/issue/" + encodeURIComponent(jobId), { ...options, method: "GET" }))
|
||||
if (result.id !== jobId) throw new Error("Ответ относится к другой задаче выпуска")
|
||||
return result
|
||||
}
|
||||
|
||||
export async function getAcmeSettings(baseUrl: string, options?: RequestInit) {
|
||||
return acmeCloudflareSettingsDtoSchema.parse(await certificateJson(baseUrl, "/api/certificates/acme-settings", { ...options, method: "GET" }))
|
||||
}
|
||||
|
||||
export async function putAcmeSettings(baseUrl: string, payload: { directoryUrl?: string; defaultZoneId?: string | null; cloudflareApiToken?: string | null }, options?: RequestInit) {
|
||||
const body = putAcmeCloudflareSettingsSchema.parse(payload)
|
||||
return acmeCloudflareSettingsDtoSchema.parse(await certificateJson(baseUrl, "/api/certificates/acme-settings", { ...options, method: "PUT", body: JSON.stringify(body) }))
|
||||
}
|
||||
|
||||
export async function testAcmeSettings(baseUrl: string, payload?: { cloudflareApiToken?: string }, options?: RequestInit) {
|
||||
const body = testAcmeCloudflareSettingsSchema.parse(payload ?? {})
|
||||
try {
|
||||
return acmeTestSchema.parse(await certificateJson(baseUrl, "/api/certificates/acme-settings/test", { ...options, method: "POST", body: JSON.stringify(body) }))
|
||||
} catch (error) {
|
||||
// Backend возвращает message для отказа Cloudflare, а не стандартное error.
|
||||
if (error instanceof ApiClientError) {
|
||||
const failure = acmeTestSchema.safeParse(error.payload)
|
||||
if (failure.success && !failure.data.ok && failure.data.message) throw new ApiClientError(failure.data.message, error.status, error.payload)
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCertificateRenewSettings(baseUrl: string, options?: RequestInit) {
|
||||
return certificateRenewSettingsDtoSchema.parse(await certificateJson(baseUrl, "/api/certificates/renew-settings", { ...options, method: "GET" }))
|
||||
}
|
||||
|
||||
export async function putCertificateRenewSettings(baseUrl: string, payload: { enabled?: boolean; intervalSec?: number; renewBeforeDays?: number }, options?: RequestInit) {
|
||||
const body = putCertificateRenewSettingsSchema.parse(payload)
|
||||
return certificateRenewSettingsDtoSchema.parse(await certificateJson(baseUrl, "/api/certificates/renew-settings", { ...options, method: "PUT", body: JSON.stringify(body) }))
|
||||
}
|
||||
|
||||
export async function readCertificatesState(baseUrl: string, options?: RequestInit) {
|
||||
return certificatesStateSchema.parse(await certificateJson(baseUrl, "/api/certificates/state", { ...options, method: "GET" }))
|
||||
}
|
||||
Reference in new issue
Block a user