Browse Source

feat: add API endpoints to get, update, and delete tasks

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
main
npmrun 2 weeks ago
parent
commit
825116ecdc
  1. 12
      server/api/scheduler/tasks/[id].delete.ts
  2. 13
      server/api/scheduler/tasks/[id].get.ts
  3. 58
      server/api/scheduler/tasks/[id].put.ts

12
server/api/scheduler/tasks/[id].delete.ts

@ -0,0 +1,12 @@
import { deleteTask } from "../../../service/scheduler";
import { removeTask } from "../../../scheduler/engine";
export default defineWrappedResponseHandler(async (event) => {
const id = getRouterParam(event, "id");
if (!id) return R.throwError(400, "Missing id", null);
removeTask(id);
await deleteTask(id);
return R.success(null);
});

13
server/api/scheduler/tasks/[id].get.ts

@ -0,0 +1,13 @@
import { getTaskById, getRecentExecutions } from "../../../service/scheduler";
export default defineWrappedResponseHandler(async (event) => {
const id = getRouterParam(event, "id");
if (!id) return R.throwError(400, "Missing id", null);
const task = await getTaskById(id);
if (!task) return R.throwError(404, "Task not found", null);
const recentExecutions = await getRecentExecutions(id, 20);
return R.success({ task, recentExecutions });
});

58
server/api/scheduler/tasks/[id].put.ts

@ -0,0 +1,58 @@
import { z } from "zod";
import { updateTask, getTaskById } from "../../../service/scheduler";
import { reloadTask } from "../../../scheduler/engine";
import { Cron } from "croner";
const updateTaskSchema = z.object({
name: z.string().min(1).optional(),
cronExpression: z.string().min(1).optional(),
type: z.enum(["function", "http"]).optional(),
functionName: z.string().optional().nullable(),
functionPayload: z.string().optional().nullable(),
httpMethod: z.enum(["GET", "POST", "PUT", "DELETE"]).optional().nullable(),
httpUrl: z.string().optional().nullable(),
httpHeaders: z.string().optional().nullable(),
httpBody: z.string().optional().nullable(),
catchUp: z.union([z.boolean(), z.number()]).optional(),
enabled: z.union([z.boolean(), z.number()]).optional(),
maxRetries: z.number().int().min(0).optional(),
retryDelaySeconds: z.number().int().min(1).optional(),
timeoutSeconds: z.number().int().min(1).optional(),
});
export default defineWrappedResponseHandler(async (event) => {
const id = getRouterParam(event, "id");
if (!id) return R.throwError(400, "Missing id", null);
const body = await readBody(event);
const parsed = updateTaskSchema.safeParse(body);
if (!parsed.success) {
return R.throwError(422, "Validation failed", parsed.error.issues);
}
const existing = await getTaskById(id);
if (!existing) return R.throwError(404, "Task not found", null);
// Validate cron if provided
const cronExpr = parsed.data.cronExpression ?? existing.cronExpression;
try {
new Cron(cronExpr);
} catch {
return R.throwError(422, "Invalid cron expression", null);
}
const updateData: Record<string, unknown> = { ...parsed.data };
if (parsed.data.catchUp !== undefined) {
updateData.catchUp = parsed.data.catchUp ? 1 : 0;
}
if (parsed.data.enabled !== undefined) {
updateData.enabled = parsed.data.enabled ? 1 : 0;
}
const task = await updateTask(id, updateData as Parameters<typeof updateTask>[1]);
if (task) {
reloadTask(task.id);
}
return R.success(task);
});
Loading…
Cancel
Save