UNPKG

integreat

Version:
151 lines 6.61 kB
import { nanoid } from 'nanoid'; import Schedule from './Schedule.js'; import Step, { createPreconditionsValidator, statusFromResponses, getPrevStepId, getLastJobWithResponse, prepareMutation, mutateResponse, breakSymbol, } from './Step.js'; import { isObject, isOkResponse, isErrorResponse } from '../utils/is.js'; import { setResponseOnAction } from '../utils/action.js'; import { setOrigin } from '../utils/response.js'; const isActionJob = (job) => isObject(job) && isObject(job.action); const isFlowJob = (job) => isObject(job) && Array.isArray(job.flow); const generateSubMeta = ({ ident, project, cid }, jobId, gid) => ({ ident, jobId, ...(project ? { project } : {}), ...(cid ? { cid } : {}), ...(gid ? { gid } : {}), }); const messageFromResponse = (response) => response.error || response.warning || 'Unknown error'; const messageFromStep = (isFlow) => (response) => { return isErrorResponse(response) || response.warning ? isFlow ? `- '${response.origin}': ${messageFromResponse(response)} (${response.status})` : `- ${messageFromResponse(response)} (${response.status})` : undefined; }; function generateJobMessage(responses, jobId, isFlow, isOk) { if (responses.length > 1) { const stepMessage = responses .map(messageFromStep(isFlow)) .filter(Boolean) .join('\n'); return isOk ? `Message from steps:\n${stepMessage}` : isFlow ? `Steps failed:\n${stepMessage}` : `Could not finish job '${jobId}': ${stepMessage}`; } else { return !isOk || responses[0].warning ? messageFromResponse(responses[0]) : undefined; } } const removeOriginAndWarning = ({ origin, warning, ...response }) => response; const setOriginOnResponses = (responses, jobId) => responses.map((response) => setOrigin(response, `job:${jobId}:step`, true)); function setMessageAndOrigin(response, jobId, isFlow) { const responses = response.responses || [response]; const isOk = isOkResponse(response); const bareResponse = removeOriginAndWarning(response); if (isOk) { const warningResponses = responses.filter((resp) => resp.warning); const jobWarning = warningResponses.length > 0 ? generateJobMessage(warningResponses, jobId, isFlow, isOk) : undefined; return { ...bareResponse, ...(jobWarning ? { warning: jobWarning } : {}), ...(response.responses ? { responses: setOriginOnResponses(response.responses, jobId) } : {}), }; } else { const errorResponses = responses.filter(isErrorResponse); const jobError = errorResponses.length > 0 ? generateJobMessage(errorResponses, jobId, isFlow, isOk) : undefined; const origin = errorResponses.length === 1 ? `job:${jobId}:step:${errorResponses[0].origin}` : `job:${jobId}`; return { ...bareResponse, status: statusFromResponses(responses), error: jobError, origin, responses: setOriginOnResponses(responses, jobId), }; } } function getResponse(jobId, steps, responses, isFlow) { const lastResponse = getLastJobWithResponse(steps, responses); if (!lastResponse) { return { status: 'noaction' }; } else { return setMessageAndOrigin(lastResponse, jobId, isFlow); } } const getId = (jobDef) => typeof jobDef.id === 'string' && jobDef.id ? jobDef.id : nanoid(); const calculateProgress = (index, stepsCount) => (index + 1) / (stepsCount + 1); export default class Job { id; schedule; #steps = []; #validatePreconditions = async () => [null, false]; #postmutator; #isFlow = false; constructor(jobDef, mapTransform, mapOptions, failOnErrorInPostconditions = false) { this.id = getId(jobDef); if (isFlowJob(jobDef)) { this.#isFlow = true; this.#steps = jobDef.flow .filter((step) => Array.isArray(step) || isActionJob(step)) .map((stepDef, index, steps) => new Step(stepDef, mapTransform, mapOptions, failOnErrorInPostconditions, getPrevStepId(index, steps))); this.#validatePreconditions = createPreconditionsValidator(jobDef.preconditions, undefined, mapTransform, mapOptions, failOnErrorInPostconditions, undefined); const postmutation = jobDef.postmutation || jobDef.responseMutation; this.#postmutator = postmutation ? prepareMutation(postmutation, mapTransform, mapOptions, !!jobDef.responseMutation) : undefined; } else if (isActionJob(jobDef)) { this.#steps = [ new Step(jobDef, mapTransform, mapOptions, failOnErrorInPostconditions, undefined, true), ]; } if (jobDef.cron && this.#steps.length > 0) { this.schedule = new Schedule(jobDef); } } async run(action, dispatch, setProgress, gid) { if (this.#steps.length === 0) { return { status: 'noaction', warning: `Job '${this.id}' has no action or flow`, origin: `job:${this.id}`, }; } let actionResponses = { action }; const [preconditionsResponse] = await this.#validatePreconditions(actionResponses); if (!preconditionsResponse) { const meta = generateSubMeta(action.meta || {}, this.id, gid); for (const [index, step] of this.#steps.entries()) { const { [breakSymbol]: doBreak, ...responses } = await step.run(meta, actionResponses, dispatch); setProgress(calculateProgress(index, this.#steps.length)); actionResponses = { ...actionResponses, ...responses }; if (doBreak) { break; } } } const response = preconditionsResponse ?? getResponse(this.id, this.#steps, actionResponses, this.#isFlow); if (this.#postmutator) { actionResponses = { ...actionResponses, action: { ...action, response } }; const { response: mutatedResponse } = await mutateResponse(setResponseOnAction(action, response), actionResponses, `job:${this.id}`, this.#postmutator); return mutatedResponse || response; } else { return response; } } } //# sourceMappingURL=Job.js.map