OpenAPI spec at /api/docs with a Scalar viewer, opt-in via FEAT_API_DOCS

This commit is contained in:
jarek committed 2026-08-17 09:50:34 +02:00
1 parent ba8670af66
commit da26f7f764
251 files changed
+32497 -66

No files matched your search

+6
View File
@@ -47,6 +47,12 @@ export interface ScheduleInfo {
vulnerabilityCriteria?: VulnerabilityCriteria | null;
}
/**
* @openapi
* summary: List all schedules (container/env auto-updates, git syncs, image-prune, backups, repo maintenance, system jobs)
* resp-200: {schedules:array<{id:integer!, type:string!, name:string!, entityName:string!, environmentId:integer, enabled:boolean!, cronExpression:string, nextRun:string, isSystem:boolean!}>!}
* resp-500: Unexpected error while assembling the schedule list
*/
export const GET: RequestHandler = async ({ cookies }) => {
const auth = await authorize(cookies);
@@ -20,6 +20,16 @@ import {
import { unregisterSchedule } from '$lib/server/scheduler';
import { authorize } from '$lib/server/authorize';
/**
* @openapi
* summary: Delete (or disable, for policy-driven types) a schedule by type and id
* path: type:string! Schedule type (container_update, git_stack_sync, env_update_check, image_prune, backup, repo_prune, repo_check, repo_verify, system_cleanup)
* path: id:integer! Schedule id (semantics depend on type — container/git-stack/backup-config id, environment id, or a synthetic repo-policy id) (from GET /api/schedules)
* resp-200: {success:boolean!}
* resp-400: Invalid schedule id, invalid/unsupported type, or system_cleanup (cannot be removed)
* resp-404: Schedule (or backup destination, for repo_* types) not found
* resp-500: Unexpected error while deleting the schedule
*/
export const DELETE: RequestHandler = async ({ params, cookies }) => {
const auth = await authorize(cookies);
@@ -18,6 +18,16 @@ import { authorize } from '$lib/server/authorize';
import { getAutoUpdateSettingById, getGitStack } from '$lib/server/db';
import { BACKUPS_ENABLED } from '$lib/server/features';
/**
* @openapi
* summary: Manually trigger a single run of a schedule (outside its cron), by type and id
* path: type:string! Schedule type (container_update, git_stack_sync, system_cleanup, env_update_check, image_prune, backup, repo_prune, repo_check, repo_verify)
* path: id:integer! Schedule id (semantics depend on type) (from GET /api/schedules)
* resp-200: {success:boolean!, message:string!}
* resp-400: Invalid schedule id/type, or the triggered task itself reported failure
* resp-404: Schedule, backup config, or backup destination not found (or backup feature disabled)
* resp-500: Unexpected error while triggering the schedule
*/
export const POST: RequestHandler = async ({ params, cookies }) => {
const auth = await authorize(cookies);
@@ -10,6 +10,16 @@ import { registerSchedule, unregisterSchedule } from '$lib/server/scheduler';
import { authorize } from '$lib/server/authorize';
import { auditBackup, auditBackupDestination } from '$lib/server/audit';
/**
* @openapi
* summary: Toggle a schedule's enabled/disabled state (registers/unregisters the croner job accordingly)
* path: type:string! Schedule type (container_update, git_stack_sync, env_update_check, image_prune, backup, repo_prune, repo_check, repo_verify, system_cleanup)
* path: id:integer! Schedule id (semantics depend on type) (from GET /api/schedules)
* resp-200: {success:boolean!, enabled:boolean!}
* resp-400: Invalid schedule id, unsupported type, or system_cleanup (cannot be paused)
* resp-404: Schedule, backup config, or backup destination not found
* resp-500: Unexpected error while toggling the schedule
*/
export const POST: RequestHandler = async (event) => {
const { params, cookies } = event;
const auth = await authorize(cookies);
@@ -24,6 +24,22 @@ import {
type ScheduleStatus
} from '$lib/server/db';
/**
* @openapi
* summary: List schedule execution history, filterable and paginated
* query: scheduleType:string Filter by schedule type (container_update, git_stack_sync, ...)
* query: scheduleId:integer Filter by the numeric id of the schedule (from GET /api/schedules)
* query: environmentId:integer Filter by environment id ("null" for global/system schedules) (from GET /api/environments)
* query: status:string Filter by execution status (queued/running/success/warning/failed/skipped)
* query: statuses:string Comma-separated list of statuses (alternative to status)
* query: triggeredBy:string Filter by trigger (cron/webhook/manual)
* query: fromDate:string ISO date lower bound
* query: toDate:string ISO date upper bound
* query: limit:integer Page size (default 50)
* query: offset:integer Page offset (default 0)
* resp-200: {executions:array<{id:integer!, scheduleType:string!, status:string!, startedAt:string!}>!, total:integer!, limit:integer!, offset:integer!}
* resp-500: Unexpected error while loading execution history
*/
export const GET: RequestHandler = async ({ url }) => {
try {
const scheduleType = url.searchParams.get('scheduleType') as ScheduleType | null;
@@ -10,6 +10,15 @@ import type { RequestHandler } from './$types';
import { getScheduleExecution, deleteScheduleExecution } from '$lib/server/db';
import { authorize } from '$lib/server/authorize';
/**
* @openapi
* summary: Get a single schedule execution, including its logs
* path: id:integer! Execution id (from GET /api/schedules/executions)
* resp-200: {id:integer!, scheduleType:string!, status:string!, startedAt:string!, log:string}
* resp-400: Invalid execution id
* resp-404: Execution not found
* resp-500: Unexpected error while loading the execution
*/
export const GET: RequestHandler = async ({ params }) => {
try {
const id = parseInt(params.id, 10);
@@ -29,6 +38,15 @@ export const GET: RequestHandler = async ({ params }) => {
}
};
/**
* @openapi
* summary: Delete a single schedule execution record
* path: id:integer! Execution id (from GET /api/schedules/executions)
* resp-200: {success:boolean!}
* resp-400: Invalid execution id
* resp-403: Permission denied (RBAC 'schedules:edit' missing)
* resp-500: Unexpected error while deleting the execution
*/
export const DELETE: RequestHandler = async ({ params, cookies }) => {
const auth = await authorize(cookies);
if (auth.authEnabled && !await auth.can('schedules', 'edit')) {
@@ -16,6 +16,12 @@ import { authorize } from '$lib/server/authorize';
const getHideSystemJobsKey = (userId?: number) =>
userId ? `user_${userId}_schedules_hide_system_jobs` : 'schedules_hide_system_jobs';
/**
* @openapi
* summary: Get the schedules-page display preference (hide system jobs), per-user with a global fallback
* resp-200: {hideSystemJobs:boolean!}
* resp-500: Unexpected error while loading the setting
*/
export const GET: RequestHandler = async ({ cookies }) => {
try {
const auth = await authorize(cookies);
@@ -37,6 +43,15 @@ export const GET: RequestHandler = async ({ cookies }) => {
}
};
/**
* @openapi
* summary: Update the schedules-page display preference (hide system jobs) for the current user
* body: {hideSystemJobs:boolean}
* body-example: {"hideSystemJobs":true}
* resp-200: {success:boolean!, hideSystemJobs:boolean}
* resp-400: hideSystemJobs is not a boolean
* resp-500: Unexpected error while saving the setting
*/
export const PUT: RequestHandler = async ({ request, cookies }) => {
try {
const auth = await authorize(cookies);
@@ -336,6 +336,12 @@ async function getSchedulesData(): Promise<ScheduleInfo[]> {
return schedules;
}
/**
* @openapi
* summary: Server-Sent Events stream that polls and pushes schedule updates (same shape as GET /api/schedules)
* resp-200: text/event-stream response, periodically emitting the current schedule list as SSE "data:" messages
* resp-403: Permission denied (RBAC 'schedules:view' missing)
*/
export const GET: RequestHandler = async ({ cookies }) => {
const auth = await authorize(cookies);
if (auth.authEnabled && !await auth.can('schedules', 'view')) {
@@ -14,6 +14,15 @@ const SYSTEM_SCHEDULE_CLEANUP_ID = 1;
const SYSTEM_EVENT_CLEANUP_ID = 2;
const SYSTEM_SCANNER_CLEANUP_ID = 4;
/**
* @openapi
* summary: Toggle one of the three built-in system cleanup jobs (schedule/event/scanner cleanup) on or off
* path: id:integer! System schedule id (1=schedule cleanup, 2=event cleanup, 4=scanner cleanup) (from GET /api/schedules)
* resp-200: {success:boolean!, enabled:boolean!}
* resp-400: Invalid or unknown system schedule id
* resp-403: Permission denied (RBAC 'settings:edit' missing)
* resp-500: Unexpected error while toggling the job
*/
export const POST: RequestHandler = async ({ params, cookies }) => {
const auth = await authorize(cookies);
if (auth.authEnabled && !await auth.can('settings', 'edit')) {