import { PollTimeout } from "../error.js";
import { constructParams } from "../util.js";
function mapAsset(a) {
return {
...a,
created: new Date(a.created),
modified: new Date(a.modified),
};
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function* iterOwn(m) {
for (const [k, v] of Object.entries(m)) {
if (Object.hasOwn(m, k))
yield [k, v];
}
}
function mapIO(io) {
const obj = { params: io.params };
if (io.assets) {
const assets = Object.fromEntries(Array.from(iterOwn(io.assets)).map(([k, v]) => [k, mapAsset(v)]));
obj.assets = assets;
}
return obj;
}
function job(j) {
return {
...j,
created: new Date(j.created),
started: j.started ? new Date(j.started) : null,
finished: j.finished ? new Date(j.finished) : null,
inputs: mapIO(j.inputs),
outputs: mapIO(j.outputs),
assets: j.assets?.map(mapAsset)
};
}
/** Metafold jobs endpoint. */
export class Jobs {
client;
constructor(client) {
this.client = client;
}
/**
* List jobs.
*
* @param {Object} [params] - Optional list parameters.
* @param {string} [params.sort] - Sort string. For details on syntax see the Metafold API docs.
* Supported sorting fields are: "id", "name", "created", "started", or "finished".
* @param {string} [params.q] - Query string. For details on syntax see the Metafold API docs.
* Supported search fields are: "id", "name", "type", and "state".
* @returns List of job resources.
*/
async list({ sort, q } = {}) {
const params = constructParams({ sort, q });
const r = await this.client.get(`/projects/${this.client.projectID}/jobs`, { params });
return r.data.map(job);
}
/**
* Get a job.
*
* @param {string} id - ID of job to get.
* @returns Job resource.
*/
async get(id) {
const r = await this.client.get(`/projects/${this.client.projectID}/jobs/${id}`);
return job(r.data);
}
/**
* Dispatch a new job and wait for the result.
*
* See Metafold API docs for the full list of jobs.
*
* @param {string} type - Job type.
* @param {Object} params - Job parameters.
* @param {string} [name] - Job name.
* @param {number} [timeout=12000] - Time in seconds to wait for a result.
* @returns Completed job resource.
*/
async run(type, params, name, timeout = 1000 * 60 * 2) {
const url = await this.runStatus(type, params, name);
let r = null;
try {
r = await this.client.poll(url, timeout, 1);
}
catch (e) {
if (e instanceof PollTimeout) {
throw new Error(`Job '${name ?? type}' failed to complete within ${timeout} ms`, { cause: e });
}
else {
throw e;
}
}
return job(r.data);
}
/**
* Poll the given URL every one second.
*
* Helpful for waiting on job results given a status URL.
*
* @param {string} url - Workflow status url.
* @param {number} [timeout=12000] - Time in seconds to wait for a result.
* @param {number} [every=1] - Frequency in seconds.
* @returns HTTP response.
*
* @deprecated Use Client.poll instead.
*/
poll(url, timeout = 1000 * 60 * 2, every = 1) {
console.warn("Jobs.poll is deprecated, please use Client.poll instead");
return this.client.poll(url, timeout, every);
}
/**
* Dispatch a new job and return immediately without waiting for result.
*
* See Metafold API docs for the full list of jobs.
*
* @param {string} type - Job type.
* @param {Object} params - Job parameters.
* @param {string} [name] - Job name.
* @returns {string} Job status url.
*/
async runStatus(type, params, name) {
const data = constructParams({ type, parameters: params, name });
const r = await this.client.post(`/projects/${this.client.projectID}/jobs`, data, {
headers: { "Content-Type": "application/json" },
});
return r.data.link;
}
/**
* Update a job.
*
* @param {string} id - ID of job to update.
* @param {Object} [params] - Optional update parameters.
* @param {string} [params.name] - New job name. The existing name remains unchanged if undefined.
* @returns Updated job resource.
*/
async update(id, { name } = {}) {
const data = constructParams({ name });
const r = await this.client.patch(`/projects/${this.client.projectID}/jobs/${id}`, data);
return job(r.data);
}
}