aa20dbe73e
2,248 lines of gateway REST client become twelve modules by domain, with hermes.ts left as a barrel so all 144 importers stay put. The import graph is a star — every domain module imports only ./client, and client imports nothing back — so there are no cycles. The barrel names client's public exports rather than re-exporting it wholesale. Splitting a module forces its private helpers into exports so siblings can reach them, and export * would then republish them: profileScoped, connectionScoped and capabilityScoped were private to hermes.ts and have to stay that way, or a call site can assemble its own request scope and drift from the api layer.
154 lines
5.1 KiB
TypeScript
154 lines
5.1 KiB
TypeScript
import type {
|
|
AutomationBlueprint,
|
|
CronDeliveryTarget,
|
|
CronJob,
|
|
CronJobCreatePayload,
|
|
CronJobUpdates,
|
|
SessionInfo
|
|
} from '@/types/hermes'
|
|
|
|
import { connectionScoped, hermesApi, profileScoped, STARTUP_REQUEST_TIMEOUT_MS } from './client'
|
|
|
|
// The cron trigger endpoint intentionally waits for the whole job so its
|
|
// response reflects the persisted execution result. Agent jobs can run far
|
|
// longer than the Electron fetch default; keep this override local to the one
|
|
// synchronous long-operation endpoint rather than weakening all API timeouts.
|
|
const CRON_TRIGGER_REQUEST_TIMEOUT_MS = 24 * 60 * 60 * 1000
|
|
|
|
// Cron jobs are stored per-profile (<HERMES_HOME>/cron/jobs.json), and the
|
|
// backend's list endpoint defaults to 'all'. Pass a concrete profile key to
|
|
// list just that profile's jobs, or 'all' for the unified cross-profile view.
|
|
// Omitting the arg keeps the legacy 'all' default for non-profile callers.
|
|
// profileScoped() still rides along for backend-process routing.
|
|
export function getCronJobs(profile?: string): Promise<CronJob[]> {
|
|
const suffix = profile ? `?profile=${encodeURIComponent(profile)}` : ''
|
|
|
|
return hermesApi<CronJob[]>({
|
|
...profileScoped(),
|
|
...connectionScoped(),
|
|
path: `/api/cron/jobs${suffix}`,
|
|
timeoutMs: STARTUP_REQUEST_TIMEOUT_MS
|
|
})
|
|
}
|
|
|
|
export function getCronJob(jobId: string): Promise<CronJob> {
|
|
return hermesApi<CronJob>({
|
|
...profileScoped(),
|
|
...connectionScoped(),
|
|
path: `/api/cron/jobs/${encodeURIComponent(jobId)}`
|
|
})
|
|
}
|
|
|
|
export async function getCronJobRuns(jobId: string, limit = 20): Promise<SessionInfo[]> {
|
|
const { runs } = await hermesApi<{ runs: SessionInfo[] }>({
|
|
...profileScoped(),
|
|
...connectionScoped(),
|
|
path: `/api/cron/jobs/${encodeURIComponent(jobId)}/runs?limit=${limit}`
|
|
})
|
|
|
|
return runs ?? []
|
|
}
|
|
|
|
// The single source of truth for cron delivery targets (local + configured
|
|
// gateways). Both the manual cron editor and the blueprint dialog use this so
|
|
// they never offer a platform that isn't connected. Mirrors the dashboard.
|
|
export async function getCronDeliveryTargets(): Promise<CronDeliveryTarget[]> {
|
|
const { targets } = await hermesApi<{ targets: CronDeliveryTarget[] }>({
|
|
...profileScoped(),
|
|
...connectionScoped(),
|
|
path: '/api/cron/delivery-targets'
|
|
})
|
|
|
|
return targets ?? []
|
|
}
|
|
|
|
export function createCronJob(body: CronJobCreatePayload): Promise<CronJob> {
|
|
return hermesApi<CronJob>({
|
|
...profileScoped(),
|
|
...connectionScoped(),
|
|
path: '/api/cron/jobs',
|
|
method: 'POST',
|
|
body
|
|
})
|
|
}
|
|
|
|
export function updateCronJob(jobId: string, updates: CronJobUpdates): Promise<CronJob> {
|
|
return hermesApi<CronJob>({
|
|
...profileScoped(),
|
|
...connectionScoped(),
|
|
path: `/api/cron/jobs/${encodeURIComponent(jobId)}`,
|
|
method: 'PUT',
|
|
body: { updates }
|
|
})
|
|
}
|
|
|
|
export function pauseCronJob(jobId: string): Promise<CronJob> {
|
|
return hermesApi<CronJob>({
|
|
...profileScoped(),
|
|
...connectionScoped(),
|
|
path: `/api/cron/jobs/${encodeURIComponent(jobId)}/pause`,
|
|
method: 'POST'
|
|
})
|
|
}
|
|
|
|
export function resumeCronJob(jobId: string): Promise<CronJob> {
|
|
return hermesApi<CronJob>({
|
|
...profileScoped(),
|
|
...connectionScoped(),
|
|
path: `/api/cron/jobs/${encodeURIComponent(jobId)}/resume`,
|
|
method: 'POST'
|
|
})
|
|
}
|
|
|
|
export function triggerCronJob(jobId: string): Promise<CronJob> {
|
|
return hermesApi<CronJob>({
|
|
...profileScoped(),
|
|
...connectionScoped(),
|
|
path: `/api/cron/jobs/${encodeURIComponent(jobId)}/trigger`,
|
|
method: 'POST',
|
|
timeoutMs: CRON_TRIGGER_REQUEST_TIMEOUT_MS
|
|
})
|
|
}
|
|
|
|
export function deleteCronJob(jobId: string): Promise<{ ok: boolean }> {
|
|
return hermesApi<{ ok: boolean }>({
|
|
...profileScoped(),
|
|
...connectionScoped(),
|
|
path: `/api/cron/jobs/${encodeURIComponent(jobId)}`,
|
|
method: 'DELETE'
|
|
})
|
|
}
|
|
|
|
// Automation Blueprints — parameterized cron templates the backend serves from
|
|
// cron/blueprint_catalog.py. getAutomationBlueprints returns the gallery
|
|
// (deliver options already rewritten to this machine's configured gateways);
|
|
// instantiateAutomationBlueprint fills the slots and creates a real cron job via
|
|
// the same create_job path as createCronJob.
|
|
//
|
|
// Profile-scoping is intentionally asymmetric: the GET catalog is global (the
|
|
// list endpoint takes no profile — only deliver options are rewritten from the
|
|
// configured gateways), so it carries only the profileScoped() header for
|
|
// routing. instantiate creates a real per-profile job, so it names the target
|
|
// profile explicitly via ?profile=. This mirrors the dashboard's api.ts.
|
|
export function getAutomationBlueprints(): Promise<{ blueprints: AutomationBlueprint[] }> {
|
|
return hermesApi<{ blueprints: AutomationBlueprint[] }>({
|
|
...profileScoped(),
|
|
...connectionScoped(),
|
|
path: '/api/cron/blueprints',
|
|
timeoutMs: STARTUP_REQUEST_TIMEOUT_MS
|
|
})
|
|
}
|
|
|
|
export function instantiateAutomationBlueprint(
|
|
body: { blueprint: string; values: Record<string, string> },
|
|
profile: string
|
|
): Promise<CronJob> {
|
|
return hermesApi<CronJob>({
|
|
...profileScoped(),
|
|
...connectionScoped(),
|
|
path: `/api/cron/blueprints/instantiate?profile=${encodeURIComponent(profile)}`,
|
|
method: 'POST',
|
|
body
|
|
})
|
|
}
|