Files
2026-09-01 11:10:39 +08:00

272 lines
6.3 KiB
TypeScript

import { apiRequest, createUuid } from "./_shared";
import type { ScriptType } from "./scripts";
import type {
CronPreview,
PythonVersion,
Schedule,
ScheduleNodeRunArtifacts,
ScheduleRunDetail,
ScheduleRunStatus,
ScheduleRunSummary,
} from "./schedules";
export type ScheduleNode = {
node_id: string;
schedule_id: string;
node_key: string;
node_name: string;
versions_id: string;
timeout_seconds: number;
retry_count: number;
retry_interval_sec: number;
position_x: number;
position_y: number;
arguments_json: Record<string, unknown>;
env_refs_json: Record<string, string>;
python_version: PythonVersion;
created_at: string;
updated_at: string;
version: {
versions_id: string;
version_label: string;
script_id: string;
script_name: string;
script_type: ScriptType;
content_hash: string;
created_at: string;
};
};
export type ScheduleEdge = {
edge_id: string;
schedule_id: string;
source_node_id: string;
target_node_id: string;
condition_expr: string | null;
created_at: string;
};
export type DagValidation = {
valid: boolean;
node_count: number;
edge_count: number;
root_node_ids: string[];
leaf_node_ids: string[];
topological_order: string[];
errors: Array<{
code: string;
message: string;
edge_id?: string;
node_ids?: string[];
}>;
};
export type ScheduleNodeRunStatus =
| ScheduleRunStatus
| "skipped";
export type ScheduleNodeRun = {
node_run_id: string;
run_id: string;
node_id: string;
versions_id: string;
attempt_no: number;
node_status: ScheduleNodeRunStatus;
state_version: number;
started_at: string | null;
finished_at: string | null;
duration_ms: number | null;
exit_code: number | null;
message: string | null;
logs_object_id: string | null;
result_object_id: string | null;
};
export async function createScheduleNode(
workspaceId: string,
scheduleId: string,
input: {
workflow_version: number;
node_key: string;
node_name: string;
versions_id: string;
timeout_seconds?: number;
retry_count?: number;
retry_interval_sec?: number;
position_x?: number;
position_y?: number;
arguments_json?: Record<string, unknown>;
env_refs_json?: Record<string, string>;
python_version?: PythonVersion;
},
): Promise<Schedule> {
return apiRequest<Schedule>(
`/api/v1/schedules/${scheduleId}/nodes`,
{ method: "POST", body: JSON.stringify(input) },
workspaceId,
);
}
export async function updateScheduleNode(
workspaceId: string,
scheduleId: string,
nodeId: string,
input: {
workflow_version: number;
node_name?: string;
versions_id?: string;
timeout_seconds?: number;
retry_count?: number;
retry_interval_sec?: number;
position_x?: number;
position_y?: number;
arguments_json?: Record<string, unknown>;
env_refs_json?: Record<string, string>;
python_version?: PythonVersion;
},
): Promise<Schedule> {
return apiRequest<Schedule>(
`/api/v1/schedules/${scheduleId}/nodes/${nodeId}`,
{ method: "PUT", body: JSON.stringify(input) },
workspaceId,
);
}
export async function deleteScheduleNode(
workspaceId: string,
scheduleId: string,
nodeId: string,
workflowVersion: number,
options: { delete_execution_history?: boolean } = {},
): Promise<Schedule> {
return apiRequest<Schedule>(
`/api/v1/schedules/${scheduleId}/nodes/${nodeId}`,
{
method: "DELETE",
body: JSON.stringify({ workflow_version: workflowVersion, ...options }),
},
workspaceId,
);
}
export async function createScheduleEdge(
workspaceId: string,
scheduleId: string,
input: {
workflow_version: number;
source_node_id: string;
target_node_id: string;
condition_expr?: string | null;
},
): Promise<Schedule> {
return apiRequest<Schedule>(
`/api/v1/schedules/${scheduleId}/edges`,
{ method: "POST", body: JSON.stringify(input) },
workspaceId,
);
}
export async function deleteScheduleEdge(
workspaceId: string,
scheduleId: string,
edgeId: string,
workflowVersion: number,
): Promise<Schedule> {
return apiRequest<Schedule>(
`/api/v1/schedules/${scheduleId}/edges/${edgeId}`,
{ method: "DELETE", body: JSON.stringify({ workflow_version: workflowVersion }) },
workspaceId,
);
}
export async function validateSchedule(
workspaceId: string,
scheduleId: string,
): Promise<DagValidation & {
schedule_id: string;
workflow_version: number;
}> {
return apiRequest(
`/api/v1/schedules/${scheduleId}/validate`,
{ method: "POST" },
workspaceId,
);
}
export async function previewCron(
workspaceId: string,
input: {
cron_expression: string;
timezone: string;
count?: number;
base_time?: string;
},
): Promise<CronPreview> {
return apiRequest<CronPreview>(
"/api/v1/cron/preview",
{ method: "POST", body: JSON.stringify(input) },
workspaceId,
);
}
export async function runScheduleNow(
workspaceId: string,
scheduleId: string,
): Promise<ScheduleRunDetail> {
return apiRequest<ScheduleRunDetail>(
`/api/v1/schedules/${scheduleId}/run`,
{
method: "POST",
headers: {
"Idempotency-Key": createUuid(),
},
body: JSON.stringify({ reason: "manual_run" }),
},
workspaceId,
);
}
export async function listScheduleRuns(
workspaceId: string,
input: {
scheduleId?: string;
status?: ScheduleRunStatus;
limit?: number;
} = {},
): Promise<ScheduleRunSummary[]> {
const query = new URLSearchParams();
if (input.scheduleId) query.set("schedule_id", input.scheduleId);
if (input.status) query.set("status", input.status);
query.set("limit", String(input.limit ?? 20));
return apiRequest<ScheduleRunSummary[]>(
`/api/v1/schedule-runs?${query.toString()}`,
{},
workspaceId,
);
}
export async function getScheduleRun(
workspaceId: string,
runId: string,
): Promise<ScheduleRunDetail> {
return apiRequest<ScheduleRunDetail>(
`/api/v1/schedule-runs/${runId}`,
{},
workspaceId,
);
}
export async function getScheduleNodeRunArtifacts(
workspaceId: string,
runId: string,
nodeRunId: string,
): Promise<ScheduleNodeRunArtifacts> {
return apiRequest<ScheduleNodeRunArtifacts>(
`/api/v1/schedule-runs/${runId}/node-runs/${nodeRunId}/artifacts`,
{},
workspaceId,
);
}
// ----------------------------------------------------------------------------