UNPKG

@5minds/processcube_engine

Version:

The ProcessCube Engine. Stores and executes BPMNs.

644 lines • 35.7 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FlowNodeHandler = void 0; const dayjs_1 = __importDefault(require("dayjs")); const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep")); const uuid = __importStar(require("uuid")); const processcube_engine_sdk_1 = require("@5minds/processcube_engine_sdk"); const index_1 = require("../../Contracts/InternalMessages/index"); const EventAggregator_1 = __importDefault(require("../../Tools/EventAggregator")); class FlowNodeHandler { flowNode; processInstance; set flowNodeInstanceId(value) { this.loggingMetaData.flowNodeInstanceId = value; this._flowNodeInstanceId = value; } get flowNodeInstanceId() { return this._flowNodeInstanceId; } previousFlowNodeInstanceId; state; processToken; processEventSubscriptions = []; flowNodeHandlerFactory; flowNodeInstanceAdapter; eventMiddlewareHandler; logger; startedAt; finishedAt; _flowNodeInstanceId = undefined; loggingMetaData = {}; interruptionCallback = () => { }; constructor(eventMiddlewareHandler, flowNodeHandlerFactory, flowNodeInstanceAdapter, flowNode, processInstance, namespace) { this.flowNode = flowNode; this.eventMiddlewareHandler = eventMiddlewareHandler; this.flowNodeHandlerFactory = flowNodeHandlerFactory; this.flowNodeInstanceAdapter = flowNodeInstanceAdapter; this.flowNodeInstanceId = uuid.v4(); this.processToken = {}; this.state = processcube_engine_sdk_1.FlowNodeInstanceState.running; this.processInstance = processInstance; this.loggingMetaData.correlationId = this.processInstance.getCorrelationId(); this.loggingMetaData.processInstanceId = this.processInstance.getProcessInstanceId(); this.loggingMetaData.flowNodeId = this.flowNode.id; this.loggingMetaData.flowNodeInstanceId = this.flowNodeInstanceId; this.logger = new processcube_engine_sdk_1.Logger(namespace, this.loggingMetaData); } /** * Gets the callback that gets called when the Flow Node was interrupted. * This happens, when an interrupting Boundary Event was triggered, or the Process Instance gets terminated. */ get onInterruptedCallback() { return this.interruptionCallback; } set onInterruptedCallback(value) { this.interruptionCallback = value; } getInstanceId() { return this.flowNodeInstanceId; } getFlowNode() { return this.flowNode; } async cancel(processToken) { await this.onInterruptedCallback(processToken); await this.persistOnCancel(); await this.afterExecute(); } async beforeExecute() { this.subscribeToMiddlewareEvent(); } async afterExecute() { this.processEventSubscriptions.forEach((subscription) => EventAggregator_1.default.unsubscribe(subscription)); this.processEventSubscriptions = []; } /** * Hook for resuming a Flow Node Handler that is currently in a suspended state. */ async resumeAfterSuspend(flowNodeInstance, resumptionCanceledCallback) { return this.processInstance.getProcessModelFacade().getNextFlowNodesFor(this.flowNode); } /** * Main hook for executing and a FlowNode type specific handler. */ async executeHandler(resumptionCanceledCallback) { return this.processInstance.getProcessModelFacade().getNextFlowNodesFor(this.flowNode); } async persistOnEnter(previousFlowNodeInstanceIds, typeData) { const previousFlowNodeInstanceId = previousFlowNodeInstanceIds && previousFlowNodeInstanceIds.length > 0 ? previousFlowNodeInstanceIds.join(';') : this.previousFlowNodeInstanceId; const flowNodeLane = this.processInstance.getProcessModelFacade().getLaneForFlowNode(this.flowNode.id); const createPersistOnEnterRequest = () => { return { flowNodeInstanceId: this.flowNodeInstanceId, flowNodeId: this.flowNode.id, flowNodeType: this.flowNode.bpmnType, flowNodeName: this.flowNode.name, flowNodeLane: flowNodeLane?.name ?? '', eventType: this.flowNode.eventType, correlationId: this.processInstance.getCorrelationId(), processDefinitionId: this.processInstance.getProcessDefinitionId(), processModelId: this.processInstance.getProcessModelId(), embeddedProcessModelId: this.processInstance.getEmbeddedProcessModelId(), processInstanceId: this.processInstance.getProcessInstanceId(), ownerId: this.processInstance.getOwner().userId, currentToken: this.processToken, previousFlowNodeInstanceId: previousFlowNodeInstanceId, parentProcessInstanceId: this.processInstance.getParentProcessInstance()?.getProcessInstanceId(), flowNodeInstanceTypeData: typeData, triggeredByFlowNodeInstanceId: typeData?.triggeredByFlowNodeInstanceId, }; }; try { await this.runPreScript(); const persistOnEnterRequest = createPersistOnEnterRequest(); await this.flowNodeInstanceAdapter.persistOnEnter(persistOnEnterRequest); this.startedAt = dayjs_1.default.utc().toDate(); const metadata = await this.executeRuntimePropertyExpressionsOnFlowNode(); await this.logFlowNodePersistenceEvent(processcube_engine_sdk_1.EngineEventType.OnFlowNodeEntered, processcube_engine_sdk_1.LogLevel.debug, { writtenCorrelationMetadata: metadata.correlationMetdata, writtenProcessInstanceMetadata: metadata.processInstanceMetadata, triggeredByFlowNodeInstanceId: typeData?.triggeredByFlowNodeInstanceId ?? undefined, }); } catch (error) { // Note that we can only persist an error state, if the Flow Node Instance was already persisted through "persistOnEnter". // Running this multiple times is safe, because a second persistOnEnter will do nothing but update the "previousFlowNodeInstanceId" property, // which is a workaround for the Parallel Join Gateway. const persistOnEnterRequest = createPersistOnEnterRequest(); await this.flowNodeInstanceAdapter.persistOnEnter(persistOnEnterRequest); throw error; } } async persistOnSuspend(updatedTokenPayload, typeData) { this.state = processcube_engine_sdk_1.FlowNodeInstanceState.suspended; const data = { tokenPayload: updatedTokenPayload, typeData: typeData, }; await this.flowNodeInstanceAdapter.persistOnSuspend(this.flowNodeInstanceId, data); await this.logFlowNodePersistenceEvent(processcube_engine_sdk_1.EngineEventType.OnFlowNodeSuspended, processcube_engine_sdk_1.LogLevel.debug); } async persistOnExit(typeData) { this.state = processcube_engine_sdk_1.FlowNodeInstanceState.finished; try { await this.runPostScript(); const dataObjectValues = await this.runOutgoingDataObjectExpressions(); this.finishedAt = dayjs_1.default.utc().toDate(); const data = { finishedAt: this.finishedAt, tokenPayload: this.processToken, typeData: typeData, dataObjectValues: dataObjectValues, triggeredByFlowNodeInstanceId: typeData?.triggeredByFlowNodeInstanceId, }; await this.flowNodeInstanceAdapter.persistOnExit(this.flowNodeInstanceId, data); await this.logFlowNodePersistenceEvent(processcube_engine_sdk_1.EngineEventType.OnFlowNodeExited, processcube_engine_sdk_1.LogLevel.debug, { writtenDataObjectValues: dataObjectValues, triggeredByFlowNodeInstanceId: typeData?.triggeredByFlowNodeInstanceId, }); } catch (error) { this.state = processcube_engine_sdk_1.FlowNodeInstanceState.error; // Errors during "persistOnExit" usually occur with post-script, or data object expression execution. error.additionalInformation = { processInstanceId: this.processInstance.getProcessInstanceId(), correlationId: this.processInstance.getCorrelationId(), }; const data = { tokenPayload: this.processToken, typeData: typeData, error: error, }; await this.flowNodeInstanceAdapter.persistOnError(this.flowNodeInstanceId, data); await this.logFlowNodePersistenceEvent(processcube_engine_sdk_1.EngineEventType.OnFlowNodeError, processcube_engine_sdk_1.LogLevel.error); throw error; } } async persistOnCancel(typeData) { this.state = processcube_engine_sdk_1.FlowNodeInstanceState.canceled; this.finishedAt = dayjs_1.default.utc().toDate(); const data = { finishedAt: this.finishedAt, tokenPayload: this.processToken, typeData: typeData, }; await this.flowNodeInstanceAdapter.persistOnCancel(this.flowNodeInstanceId, data); await this.logFlowNodePersistenceEvent(processcube_engine_sdk_1.EngineEventType.OnFlowNodeCanceled, processcube_engine_sdk_1.LogLevel.debug); } async persistOnTerminate(typeData) { // This check is necessary, in case the Promise-Chain was broken further down the road. if (!(this.state === processcube_engine_sdk_1.FlowNodeInstanceState.running || this.state === processcube_engine_sdk_1.FlowNodeInstanceState.suspended)) { return; } this.state = processcube_engine_sdk_1.FlowNodeInstanceState.terminated; this.finishedAt = dayjs_1.default.utc().toDate(); const data = { finishedAt: this.finishedAt, tokenPayload: this.processToken, typeData: typeData, }; await this.flowNodeInstanceAdapter.persistOnTerminate(this.flowNodeInstanceId, data); await this.logFlowNodePersistenceEvent(processcube_engine_sdk_1.EngineEventType.OnFlowNodeTerminated, processcube_engine_sdk_1.LogLevel.error); } async persistOnError(error, typeData) { // This check is necessary, in case the Promise-Chain was broken further down the road. if (!(this.state === processcube_engine_sdk_1.FlowNodeInstanceState.running || this.state === processcube_engine_sdk_1.FlowNodeInstanceState.suspended)) { return; } this.state = processcube_engine_sdk_1.FlowNodeInstanceState.error; this.finishedAt = dayjs_1.default.utc().toDate(); const data = { finishedAt: this.finishedAt, tokenPayload: this.processToken, error: error, typeData: typeData, }; await this.flowNodeInstanceAdapter.persistOnError(this.flowNodeInstanceId, data); EventAggregator_1.default.publish(index_1.eventAggregatorSettings.messagePaths.activityError, { correlationId: this.processInstance.getCorrelationId(), processDefinitionId: this.processInstance.getProcessDefinitionId(), processModelId: this.processInstance.getProcessModelId(), embeddedProcessModelId: this.processInstance.getEmbeddedProcessModelId(), processModelName: this.processInstance.getProcessModelName(), processInstanceId: this.processInstance.getProcessInstanceId(), parentProcessInstanceId: this.processInstance.getParentProcessInstance()?.getProcessInstanceId(), flowNodeId: this.flowNode.id, flowNodeName: this.flowNode.name, flowNodeType: this.flowNode.bpmnType, flowNodeLane: this.processInstance.getProcessModelFacade().getLaneForFlowNode(this.flowNode.id)?.name, flowNodeInstanceId: this.flowNodeInstanceId, processInstanceOwner: this.processInstance.getOwner(), currentToken: this.processToken, previousFlowNodeInstanceId: this.previousFlowNodeInstanceId, error: { name: error.name, code: error.code, message: error.message, category: error.category, fatal: error.fatal, }, }); await this.logFlowNodePersistenceEvent(processcube_engine_sdk_1.EngineEventType.OnFlowNodeError, processcube_engine_sdk_1.LogLevel.error); } subscribeToProcessKilledEvent(rejectionFunction) { return this.processInstance.onKillProcess(async (message) => { const killerId = message?.killedBy?.userId ?? undefined; const errorMsg = `Process was killed by user \`${killerId}\``; await this.persistOnTerminate(); await this.onInterruptedCallback(this.processToken); await this.afterExecute(); const processKilledError = new processcube_engine_sdk_1.GoneError(errorMsg); processKilledError.additionalInformation = { processInstanceWasTerminated: true, killedBy: message.killedBy, }; return rejectionFunction(processKilledError); }); } subscribeToProcessError(rejectionFunction) { return this.processInstance.onProcessError(async (message) => { const payloadIsDefined = message != undefined; this.processToken = payloadIsDefined ? message.currentToken : {}; const error = new processcube_engine_sdk_1.InternalServerError('ProcessInstance encountered an error!'); error.additionalInformation = message.currentToken; await this.onInterruptedCallback(this.processToken); await this.persistOnTerminate(); await this.afterExecute(); return rejectionFunction(error); }); } subscribeToTerminateEndEventReached(resolveFunction) { return this.processInstance.onTerminateEndEventReached(async (message) => { this.processToken = message.currentToken ?? {}; this.logger.debug('Cancelling Flow Node Execution, because a Terminate End Event has been reached.'); await this.onInterruptedCallback(this.processToken); await this.persistOnCancel(); await this.afterExecute(); return resolveFunction(); }); } subscribeToMiddlewareEvent() { const tokenPayloadChangeMessagePath = index_1.eventAggregatorSettings.messagePaths.tokenPayloadChange.replace(index_1.eventAggregatorSettings.messageParams.flowNodeInstanceId, this.flowNodeInstanceId); const tokenPayloadChangeFinishedMessagePath = index_1.eventAggregatorSettings.messagePaths.tokenPayloadChangeFinished.replace(index_1.eventAggregatorSettings.messageParams.flowNodeInstanceId, this.flowNodeInstanceId); this.processEventSubscriptions.push(EventAggregator_1.default.subscribe(tokenPayloadChangeMessagePath, async (tokenChangeEvent) => { this.processToken = tokenChangeEvent.tokenPayload ? { ...tokenChangeEvent.tokenPayload } : {}; const tokenTypeToChange = tokenChangeEvent.eventType === processcube_engine_sdk_1.EngineEventType.OnFlowNodeExited || tokenChangeEvent.eventType === processcube_engine_sdk_1.EngineEventType.OnFlowNodeError || tokenChangeEvent.eventType === processcube_engine_sdk_1.EngineEventType.OnFlowNodeCanceled || tokenChangeEvent.eventType === processcube_engine_sdk_1.EngineEventType.OnFlowNodeTerminated ? 'endToken' : 'startToken'; await this.flowNodeInstanceAdapter.changeProcessTokenPayload(this.flowNodeInstanceId, tokenTypeToChange, this.processToken); EventAggregator_1.default.publish(tokenPayloadChangeFinishedMessagePath); })); } async handleNextFlowNode(nextFlowNode, allFlowNodeInstancesToResume) { const nextFlowNodeHandler = this.flowNodeHandlerFactory.create(nextFlowNode, this.processInstance); const flowNodeInstanceToResume = allFlowNodeInstancesToResume ? this.findNextFlowNodeInstance(allFlowNodeInstancesToResume, nextFlowNode.id) : undefined; if (flowNodeInstanceToResume) { return nextFlowNodeHandler.resume(flowNodeInstanceToResume, allFlowNodeInstancesToResume); } return nextFlowNodeHandler.execute(this.flowNodeInstanceId, this.processToken); } findNextFlowNodeInstance(allFlowNodeInstances, nextFlowNodeId) { return allFlowNodeInstances.find((instance) => { // ParallelJoinGateways always have multiple "previousFlowNodeInstanceIds", separated by ";" (i.e.: ID1;ID2;ID3 etc) const instanceFollowedCurrentFlowNode = instance.previousFlowNodeInstanceId?.indexOf(this.flowNodeInstanceId) > -1; const flowNodeIdsMatch = instance.flowNodeId === nextFlowNodeId; return instanceFollowedCurrentFlowNode && flowNodeIdsMatch; }); } async handleError(error, resolveCallback, rejectCallback) { // This happens, when trying to suspend a Flow Node Instance that was already finished (in whatever way). // We must not perform another state transition to "error", because that would just apply a different unintended state to it. const isStateTransitionError = new RegExp(`^Cannot change state of Flow Node Instance \`${this.flowNodeInstanceId}\``, 'gi').test(error.message); if (isStateTransitionError) { this.logger.debug(error.message, { err: error }); return resolveCallback(); } const isTerminationEvent = error.additionalInformation?.processInstanceWasTerminated === true; if (isTerminationEvent) { await this.persistOnTerminate(); } else { await this.persistOnError(error); } await this.afterExecute(); return rejectCallback(error); } ensureHasClaim() { const processModelHasNoLanes = !this.processInstance.getProcessModelFacade().getProcessModelHasLanes(); const processWasStartedByRootAccessToken = this.processInstance.getStartedByRootAccessToken(); if (processModelHasNoLanes || processWasStartedByRootAccessToken) { return; } const laneForFlowNode = this.processInstance.getProcessModelFacade().getLaneForFlowNode(this.flowNode.id); const claimName = laneForFlowNode.name; if (claimName) { this.processInstance.ensureOwnerHasClaim(claimName); } } /** * Executes all expressions for updating some meta property on the containing ProcessInstance. * For example "engine.setProcessInstanceMetadata.propertyName" or "engine.setCorrelationMetadata.propertyName". * * These expressions can be found within the FlowNode's extension properties. * * @async */ async executeRuntimePropertyExpressionsOnFlowNode() { const correlationMetdata = await this.setCorrelationMetadata(); const processInstanceMetadata = await this.setProcessInstanceMetadata(); return { correlationMetdata, processInstanceMetadata, }; } async postEventToEventMiddlewares(payload) { const runtimeExpressionParameters = this.processInstance.buildRuntimeExpressionDataForFlowNodeInstance({ currentFlowNode: this.flowNode, currentToken: this.processToken, previousFlowNode: this.processInstance.getProcessModelFacade().getPreviousFlowNodesFor(this.flowNode)?.pop(), allowNonObjectResults: false, }); await this.eventMiddlewareHandler.triggerEvent((0, lodash_clonedeep_1.default)(payload), runtimeExpressionParameters); } async setCorrelationMetadata() { const correlationMetadataProperties = this.flowNode.extensionElements?.camundaExtensionProperties?.filter((property) => property.name.startsWith('engine.setCorrelationMetadata.')) ?? []; if (!correlationMetadataProperties || correlationMetadataProperties.length == 0) { return; } const changedMetaData = {}; for (const property of correlationMetadataProperties) { if (!property.value || property.value.trim().length === 0) { continue; } const metadataKey = property.name.replace('engine.setCorrelationMetadata.', '').trim(); if (!metadataKey) { const correlationPropertyNameMissing = new processcube_engine_sdk_1.BadRequestError("Must provide a name with 'engine.setCorrelationMetadata' expressions!", 'process'); correlationPropertyNameMissing.additionalInformation = { processInstanceId: this.processInstance.getProcessInstanceId(), correlationId: this.processInstance.getCorrelationId(), flowNodeId: this.flowNode.id, flowNodeName: this.flowNode.name, metaDataKey: metadataKey, }; throw correlationPropertyNameMissing; } changedMetaData[metadataKey] = await this.processInstance.setCorrelationMetadataValue(metadataKey, property.value, this.flowNode, this.flowNodeInstanceId, this.processToken); } await this.publishCorrelationMetadataChangedNotification(changedMetaData); return changedMetaData; } async setProcessInstanceMetadata() { const processMetadataProperties = this.flowNode.extensionElements?.camundaExtensionProperties?.filter((property) => property.name.startsWith('engine.setProcessInstanceMetadata.')) ?? []; if (!processMetadataProperties || processMetadataProperties.length == 0) { return; } const changedMetaData = {}; for (const property of processMetadataProperties) { if (!property.value || property.value.trim().length === 0) { continue; } const metadataKey = property.name.replace('engine.setProcessInstanceMetadata.', '').trim(); if (!metadataKey) { const processInstancePropertyNameMissing = new processcube_engine_sdk_1.BadRequestError("Must provide a name with 'engine.setProcessInstanceMetadata' expressions!", 'process'); processInstancePropertyNameMissing.additionalInformation = { processInstanceId: this.processInstance.getProcessInstanceId(), correlationId: this.processInstance.getCorrelationId(), flowNodeId: this.flowNode.id, flowNodeName: this.flowNode.name, metaDataKey: metadataKey, }; throw processInstancePropertyNameMissing; } changedMetaData[metadataKey] = await this.processInstance.setProcessInstanceMetadataValue(metadataKey, property.value, this.flowNode, this.flowNodeInstanceId, this.processToken); } this.publishProcessInstanceMetadataChangedNotification(changedMetaData); return changedMetaData; } async runPreScript() { const preScript = this.flowNode.extensionElements?.camundaExtensionProperties?.find((prop) => prop.name === 'engine.runPreScript')?.value; if (!preScript) { return; } try { const result = await this.processInstance.executeRuntimeExpression({ expression: preScript, currentFlowNode: this.flowNode, currentToken: this.processToken, previousFlowNode: this.processInstance.getProcessModelFacade().getPreviousFlowNodesFor(this.flowNode)?.pop(), allowNonObjectResults: false, }); this.processToken = result ?? {}; } catch (error) { const errorCategoryPrefix = error.category ? `Failure in ${error.category}: ` : ''; this.logger.error(`${errorCategoryPrefix}Error in Pre Script`, { err: (0, processcube_engine_sdk_1.serializeJson)(error), correlationId: this.processInstance.getCorrelationId(), processInstanceId: this.processInstance.getProcessInstanceId(), processModelId: this.processInstance.getProcessModelId(), embeddedProcessModelId: this.processInstance.getEmbeddedProcessModelId(), flowNodeId: this.flowNode.id, flowNodeInstanceId: this.flowNodeInstanceId, }); const sanitizedMessage = error.message.replace(errorCategoryPrefix, ''); const preScriptError = new processcube_engine_sdk_1.BadRequestError(`Failure in process: Error in Pre Script: ${sanitizedMessage}`, error.category); preScriptError.additionalInformation = { originalError: error.message, correlationId: this.processInstance.getCorrelationId(), processInstanceId: this.processInstance.getProcessInstanceId(), processModelId: this.processInstance.getProcessModelId(), embeddedProcessModelId: this.processInstance.getEmbeddedProcessModelId(), flowNodeId: this.flowNode.id, flowNodeInstanceId: this.flowNodeInstanceId, }; throw preScriptError; } } async runPostScript() { const postScript = this.flowNode.extensionElements?.camundaExtensionProperties?.find((prop) => prop.name === 'engine.runPostScript')?.value; if (!postScript) { return; } try { const result = await this.processInstance.executeRuntimeExpression({ expression: postScript, currentFlowNode: this.flowNode, currentToken: this.processToken, previousFlowNode: this.processInstance.getProcessModelFacade().getPreviousFlowNodesFor(this.flowNode)?.pop(), allowNonObjectResults: false, }); this.processToken = result ?? {}; } catch (error) { const errorCategoryPrefix = error.category ? `Failure in ${error.category}: ` : ''; this.logger.error(`${errorCategoryPrefix}Error in Post Script`, { err: (0, processcube_engine_sdk_1.serializeJson)(error), correlationId: this.processInstance.getCorrelationId(), processInstanceId: this.processInstance.getProcessInstanceId(), processModelId: this.processInstance.getProcessModelId(), embeddedProcessModelId: this.processInstance.getEmbeddedProcessModelId(), flowNodeId: this.flowNode.id, flowNodeInstanceId: this.flowNodeInstanceId, }); const sanitizedMessage = error.message.replace(errorCategoryPrefix, ''); const postScriptError = new processcube_engine_sdk_1.BadRequestError(`Failure in process: Error in Post Script: ${sanitizedMessage}`, error.category); postScriptError.additionalInformation = { originalError: error.message, correlationId: this.processInstance.getCorrelationId(), processInstanceId: this.processInstance.getProcessInstanceId(), processModelId: this.processInstance.getProcessModelId(), embeddedProcessModelId: this.processInstance.getEmbeddedProcessModelId(), flowNodeId: this.flowNode.id, flowNodeInstanceId: this.flowNodeInstanceId, }; throw postScriptError; } } async runOutgoingDataObjectExpressions() { const dataObjectOutputReferences = this.processInstance.getProcessModelFacade().getOutputDataObjectReferencesForFlowNode(this.flowNode.id); if (dataObjectOutputReferences.length === 0) { return; } const dataObjectValueCollection = {}; for (const dataObjectReference of dataObjectOutputReferences) { const dataOutputAssociation = this.flowNode.dataOutputAssociations.find((entry) => entry.targetRef === dataObjectReference.id); const dataObjectValue = dataOutputAssociation.dataSource?.length > 0 ? await this.parseDataObjectExpression(dataOutputAssociation.dataSource, dataObjectReference.id) : this.processToken; dataObjectValueCollection[dataObjectReference.id] = dataObjectValue; this.processInstance.getDataObjectFacade().storeValue(dataObjectReference.id, dataObjectValue); } return dataObjectValueCollection; } async parseDataObjectExpression(expression, dataObjectId) { try { const payload = await this.processInstance.executeRuntimeExpression({ expression: expression, currentFlowNode: this.flowNode, currentToken: this.processToken, dataObjectId: dataObjectId, allowNonObjectResults: false, }); return payload; } catch (error) { const parserError = new processcube_engine_sdk_1.BadRequestError(`Failed to execute DataObject expression!`, error.category); const additionalInformation = { expression: expression, dataObjectId: dataObjectId, currentDataObjectValue: this.processInstance.getDataObjectFacade().getValue(dataObjectId) ?? {}, correlationId: this.processInstance.getCorrelationId(), flowNodeInstanceId: this.flowNodeInstanceId, flowNodeId: this.flowNode.id, processInstanceId: this.processInstance.getProcessInstanceId(), originalErrorMessage: error.message, }; parserError.additionalInformation = additionalInformation; this.logger.error(parserError.message, additionalInformation); throw parserError; } } async logFlowNodePersistenceEvent(eventType, logLevel, additionalData = {}) { const now = dayjs_1.default.utc().toDate(); const currentFlowNodeMetadata = processcube_engine_sdk_1.FlowNodeViewModelFactory.getViewModel(this.flowNode, { processModelId: this.processInstance.getProcessModelId(), processModelName: this.processInstance.getProcessModelName(), }); await this.postEventToEventMiddlewares({ correlationId: this.processInstance.getCorrelationId(), eventType: eventType, flowNodeId: this.flowNode.id, flowNodeInstanceId: this.flowNodeInstanceId, flowNodeType: this.flowNode.bpmnType, currentFlowNode: currentFlowNodeMetadata, logLevel: logLevel, processInstanceId: this.processInstance.getProcessInstanceId(), parentProcessInstanceId: this.processInstance.getParentProcessInstance()?.getProcessInstanceId(), processDefinitionId: this.processInstance.getProcessDefinitionId(), processDefinitionHash: this.processInstance.getProcessDefinitionHash(), processModelId: this.processInstance.getProcessModelId(), embeddedProcessModelId: this.processInstance.getEmbeddedProcessModelId(), processModelName: this.processInstance.getProcessModelName(), timestamp: now, flowNodeEnteredAt: this.startedAt, flowNodeExitedAt: this.finishedAt, processStartedAt: this.processInstance.getStartedAt(), tokenPayload: this.processToken, ...additionalData, }); } publishProcessInstanceMetadataChangedNotification(changedMetadata) { const message = { correlationId: this.processInstance.getCorrelationId(), processDefinitionId: this.processInstance.getProcessDefinitionId(), processModelId: this.processInstance.getProcessModelId(), processModelName: this.processInstance.getProcessModelName(), embeddedProcessModelId: this.processInstance.getEmbeddedProcessModelId(), processInstanceId: this.processInstance.getProcessInstanceId(), flowNodeInstanceId: this.flowNodeInstanceId, processInstanceOwner: this.processInstance.getOwner(), currentToken: this.processToken ?? {}, changedMetadata: changedMetadata, }; EventAggregator_1.default.publish(index_1.eventAggregatorSettings.messagePaths.processInstanceMetadataChanged, message); } async publishCorrelationMetadataChangedNotification(changedMetadata) { const message = { correlationId: this.processInstance.getCorrelationId(), processDefinitionId: this.processInstance.getProcessDefinitionId(), processModelId: this.processInstance.getProcessModelId(), embeddedProcessModelId: this.processInstance.getEmbeddedProcessModelId(), processModelName: this.processInstance.getProcessModelName(), processInstanceId: this.processInstance.getProcessInstanceId(), flowNodeInstanceId: this.flowNodeInstanceId, processInstanceOwner: this.processInstance.getOwner(), currentToken: this.processToken ?? {}, changedMetadata: changedMetadata, }; await new Promise((resolve) => { const publishMetadataChangesToProcessInstances = index_1.eventAggregatorSettings.messagePaths.changeCorrelationMetadata.replace(index_1.eventAggregatorSettings.messageParams.correlationId, this.processInstance.getCorrelationId()); EventAggregator_1.default.publish(publishMetadataChangesToProcessInstances, message, resolve); }); EventAggregator_1.default.publish(index_1.eventAggregatorSettings.messagePaths.correlationMetadataChanged, message); } } exports.FlowNodeHandler = FlowNodeHandler; //# sourceMappingURL=FlowNodeHandler.js.map