feat(api, web): enhance agent management and linting capabilities
- Added a new linting command for OpenAPI specifications in the package.json, improving code quality checks. - Updated frontend documentation to clarify component usage and structure, including detailed descriptions for `SettingsShell` and `Auth callback`. - Refactored agent-related API routes to streamline control-plane functionalities, consolidating multiple routes for better organization. - Improved error handling in the API to provide more informative responses for validation errors, enhancing user feedback during interactions. These changes enhance the overall development experience and improve the management of agents within the application.
This commit is contained in:
1 parent
fb95ef22b3
commit
f160992d94
68 files changed
+3155
-6899
No files matched your search
@@ -0,0 +1,88 @@
|
||||
import type { FastifyPluginAsync } from 'fastify'
|
||||
import { repos } from '@evofw/db'
|
||||
import { createInstallLinkBodySchema } from '@evofw/shared'
|
||||
import { AppError } from '../plugins/error-handler.js'
|
||||
import {
|
||||
mapInstallLink,
|
||||
randomToken,
|
||||
} from '../services/install-links.js'
|
||||
import { hashToken } from '../plugins/auth.js'
|
||||
import type { AppConfig } from '../config.js'
|
||||
import { auditMutation } from '../services/audit.js'
|
||||
|
||||
export const installLinksRoutes: FastifyPluginAsync<{ config: AppConfig }> = async (
|
||||
app,
|
||||
opts,
|
||||
) => {
|
||||
const { config } = opts
|
||||
|
||||
app.get('/install-links', async () => ({
|
||||
items: repos
|
||||
.listInstallLinks(app.db)
|
||||
.map((row) => mapInstallLink(row, config.publicBaseUrl)),
|
||||
}))
|
||||
|
||||
app.post('/install-links', async (req, reply) => {
|
||||
const body = createInstallLinkBodySchema.parse(req.body)
|
||||
const linkId = randomToken(10)
|
||||
const slug = randomToken(16)
|
||||
if (
|
||||
repos.getInstallLink(app.db, linkId) ||
|
||||
repos.getInstallLinkBySlug(app.db, slug)
|
||||
) {
|
||||
throw new AppError('CONFLICT', 'Retry create (id collision)', 409)
|
||||
}
|
||||
|
||||
const agentId = crypto.randomUUID()
|
||||
const inviteToken = `invite:${agentId}`
|
||||
const now = new Date().toISOString()
|
||||
const name = body.name.trim()
|
||||
const platform = body.platform ?? 'linux'
|
||||
|
||||
app.sqlite.transaction(() => {
|
||||
repos.insertAgent(app.db, {
|
||||
id: agentId,
|
||||
name,
|
||||
hostname: null,
|
||||
platform,
|
||||
tokenPrefix: inviteToken.slice(0, 12),
|
||||
tokenHash: hashToken(inviteToken),
|
||||
status: 'invited',
|
||||
defaultAction: 'accept',
|
||||
policyGeneration: 1,
|
||||
clientVersion: null,
|
||||
settingsJson: '{}',
|
||||
createdAt: now,
|
||||
})
|
||||
repos.insertInstallLink(app.db, {
|
||||
id: linkId,
|
||||
slug,
|
||||
clientName: name,
|
||||
platform,
|
||||
agentId,
|
||||
createdAt: now,
|
||||
useCount: 0,
|
||||
})
|
||||
})()
|
||||
|
||||
const row = repos.getInstallLink(app.db, linkId)!
|
||||
auditMutation(app, config, req, {
|
||||
action: 'agent.create',
|
||||
targetType: 'app_resource',
|
||||
targetId: agentId,
|
||||
summary: `Создан агент (invite): ${name}`,
|
||||
details: { agent_id: agentId, platform, install_link_id: linkId },
|
||||
})
|
||||
return reply.code(201).send(mapInstallLink(row, config.publicBaseUrl))
|
||||
})
|
||||
|
||||
app.delete<{ Params: { id: string } }>(
|
||||
'/install-links/:id',
|
||||
async (req) => {
|
||||
const row = repos.getInstallLink(app.db, req.params.id)
|
||||
if (!row) throw new AppError('NOT_FOUND', 'Install link not found', 404)
|
||||
const updated = repos.revokeInstallLink(app.db, row.id)
|
||||
return mapInstallLink(updated!, config.publicBaseUrl)
|
||||
},
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user