IKHSAN
ENID Baca dalam Bahasa Indonesia

homeio

Public

Forked from doctor-io/homeio

Branch
main
Latest commit
958d74616 October 2026

scheduled-tasks.ts

Open raw
import { z } from "zod";

export type ScheduledTaskType = "shell" | "script" | "restart-app" | "backup" | "pull-images";

export type ScheduledTaskConfig =
  | { type: "shell"; command: string }
  | { type: "script"; script: string }
  | { type: "restart-app"; appId: string; appName: string }
  | { type: "backup" }
  | { type: "pull-images" };

export type ScheduledTaskRecord = {
  id: string;
  label: string;
  taskType: ScheduledTaskType;
  taskConfig: ScheduledTaskConfig;
  cronExpression: string;
  enabled: boolean;
  lastRunAt: string | null;
  lastRunStatus: "success" | "error" | null;
  lastRunOutput: string | null;
  nextRunAt: string | null;
  createdAt: string;
};

export type CreateScheduledTaskInput = {
  label: string;
  taskType: ScheduledTaskType;
  taskConfig: ScheduledTaskConfig;
  cronExpression: string;
  enabled?: boolean;
};

export type UpdateScheduledTaskInput = {
  label?: string;
  taskType?: ScheduledTaskType;
  taskConfig?: ScheduledTaskConfig;
  cronExpression?: string;
  enabled?: boolean;
};

export type ScheduledTasksListResponse = {
  tasks: ScheduledTaskRecord[];
};

export const CRON_PRESETS = [
  { label: "Every hour", value: "0 * * * *" },
  { label: "Daily at 3 AM", value: "0 3 * * *" },
  { label: "Weekly (Sun 3 AM)", value: "0 3 * * 0" },
  { label: "Monthly (1st, 3 AM)", value: "0 3 1 * *" },
  { label: "Custom…", value: "custom" },
] as const;

export const SHELL_COMMAND_ALLOWLIST = [
  "df -h",
  "docker system prune -f",
  "docker image prune -af",
  "docker volume prune -f",
  "apt-get update",
  "apt-get upgrade -y",
  "apt-get autoremove -y",
  "journalctl --vacuum-size=500M",
  "sync && echo 3 > /proc/sys/vm/drop_caches",
] as const;

// 5-field cron: basic validation (digits, *, commas, hyphens, slashes)
const cronField = /^(\*|[0-9,\-*/]+)$/;
export const CRON_EXPRESSION_REGEX = /^(\*|[0-9,\-*/]+)\s+(\*|[0-9,\-*/]+)\s+(\*|[0-9,\-*/]+)\s+(\*|[0-9,\-*/]+)\s+(\*|[0-9,\-*/]+)$/;

const taskConfigSchema = z.discriminatedUnion("type", [
  z.object({ type: z.literal("shell"), command: z.enum(SHELL_COMMAND_ALLOWLIST) }),
  z.object({ type: z.literal("script"), script: z.string().min(1).max(32_768) }),
  z.object({ type: z.literal("restart-app"), appId: z.string().min(1), appName: z.string().min(1) }),
  z.object({ type: z.literal("backup") }),
  z.object({ type: z.literal("pull-images") }),
]);

export const createScheduledTaskSchema = z.object({
  label: z.string().min(1).max(200),
  taskType: z.enum(["shell", "script", "restart-app", "backup", "pull-images"]),
  taskConfig: taskConfigSchema,
  cronExpression: z.string().regex(CRON_EXPRESSION_REGEX, "Invalid cron expression"),
  enabled: z.boolean().optional(),
});

export const updateScheduledTaskSchema = z.object({
  label: z.string().min(1).max(200).optional(),
  taskType: z.enum(["shell", "script", "restart-app", "backup", "pull-images"]).optional(),
  taskConfig: taskConfigSchema.optional(),
  cronExpression: z.string().regex(CRON_EXPRESSION_REGEX, "Invalid cron expression").optional(),
  enabled: z.boolean().optional(),
});
bytes
3,079
lines
93
Type
ts
Latest commit
16 October 2026