UNPKG

nestjs-temporal-core

Version:

Complete NestJS integration for Temporal.io with auto-discovery, declarative scheduling, enhanced monitoring, and enterprise-ready features

171 lines 9.19 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ChildWorkflow = exports.QueryMethod = exports.SignalMethod = void 0; const constants_1 = require("../constants"); require("reflect-metadata"); const logger_1 = require("../utils/logger"); const validation_1 = require("../utils/validation"); const logger = (0, logger_1.createLogger)('WorkflowDecorators'); const SignalMethod = (signalName) => { return (target, propertyKey, descriptor) => { const className = target.constructor.name; const methodName = propertyKey.toString(); const finalSignalName = signalName || methodName; logger.debug(`@SignalMethod decorator applied to method: ${className}.${methodName}`); logger.debug(`Signal name: ${finalSignalName} (provided: ${signalName || 'auto-generated'})`); if (!descriptor || typeof descriptor.value !== 'function') { const error = `@SignalMethod can only be applied to methods, not ${typeof descriptor?.value}`; logger.error(`@SignalMethod validation failed for ${className}.${methodName}: ${error}`); throw new Error(error); } if (signalName !== undefined && signalName.length === 0) { const error = 'Signal name cannot be empty'; logger.error(`@SignalMethod validation failed for ${className}.${methodName}: ${error}`); throw new Error(error); } try { (0, validation_1.validateSignalName)(finalSignalName); } catch (error) { logger.error(`@SignalMethod validation failed for ${className}.${methodName}: ${error.message}`); throw error; } const signals = Reflect.getMetadata(constants_1.TEMPORAL_SIGNAL_METHOD, target.constructor.prototype) || {}; logger.debug(`Existing signals in ${className}: [${Object.keys(signals).join(', ')}]`); if (signals[finalSignalName] && signals[finalSignalName] !== propertyKey) { const error = `Duplicate signal name "${finalSignalName}" found in class ${className}. ` + `Signal names must be unique within a workflow class.`; logger.error(`@SignalMethod validation failed: ${error}`); throw new Error(error); } logger.debug(`Registering signal "${finalSignalName}" for method ${className}.${methodName}`); try { signals[finalSignalName] = propertyKey; Reflect.defineMetadata(constants_1.TEMPORAL_SIGNAL_METHOD, signals, target.constructor.prototype); logger.debug(`Stored signal metadata on class prototype: ${className}`); const signalMetadata = { signalName: finalSignalName, methodName, className, }; Reflect.defineMetadata(constants_1.TEMPORAL_SIGNAL_METHOD + '_METHOD', signalMetadata, descriptor.value); logger.debug(`Stored individual signal metadata on method: ${className}.${methodName}`); logger.debug(`@SignalMethod decorator successfully applied to ${className}.${methodName}`); } catch (error) { logger.error(`Failed to store @SignalMethod metadata for ${className}.${methodName}:`, error); throw error; } return descriptor; }; }; exports.SignalMethod = SignalMethod; const QueryMethod = (queryName) => { return (target, propertyKey, descriptor) => { const className = target.constructor.name; const methodName = propertyKey.toString(); const finalQueryName = queryName || methodName; logger.debug(`@QueryMethod decorator applied to method: ${className}.${methodName}`); logger.debug(`Query name: ${finalQueryName} (provided: ${queryName || 'auto-generated'})`); if (!descriptor || typeof descriptor.value !== 'function') { const error = `@QueryMethod can only be applied to methods, not ${typeof descriptor?.value}`; logger.error(`@QueryMethod validation failed for ${className}.${methodName}: ${error}`); throw new Error(error); } if (queryName !== undefined && queryName.length === 0) { const error = 'Query name cannot be empty'; logger.error(`@QueryMethod validation failed for ${className}.${methodName}: ${error}`); throw new Error(error); } try { (0, validation_1.validateQueryName)(finalQueryName); } catch (error) { logger.error(`@QueryMethod validation failed for ${className}.${methodName}: ${error.message}`); throw error; } const queries = Reflect.getMetadata(constants_1.TEMPORAL_QUERY_METHOD, target.constructor.prototype) || {}; logger.debug(`Existing queries in ${className}: [${Object.keys(queries).join(', ')}]`); if (queries[finalQueryName] && queries[finalQueryName] !== propertyKey) { const error = `Duplicate query name "${finalQueryName}" found in class ${className}. ` + `Query names must be unique within a workflow class.`; logger.error(`@QueryMethod validation failed: ${error}`); throw new Error(error); } logger.debug(`Registering query "${finalQueryName}" for method ${className}.${methodName}`); try { queries[finalQueryName] = propertyKey; Reflect.defineMetadata(constants_1.TEMPORAL_QUERY_METHOD, queries, target.constructor.prototype); logger.debug(`Stored query metadata on class prototype: ${className}`); const queryMetadata = { queryName: finalQueryName, methodName, className, }; Reflect.defineMetadata(constants_1.TEMPORAL_QUERY_METHOD + '_METHOD', queryMetadata, descriptor.value); logger.debug(`Stored individual query metadata on method: ${className}.${methodName}`); logger.debug(`@QueryMethod decorator successfully applied to ${className}.${methodName}`); } catch (error) { logger.error(`Failed to store @QueryMethod metadata for ${className}.${methodName}:`, error); throw error; } return descriptor; }; }; exports.QueryMethod = QueryMethod; const ChildWorkflow = (workflowType, options) => { return (target, propertyKey) => { const className = target.constructor.name; const propertyName = propertyKey.toString(); logger.debug(`@ChildWorkflow decorator applied to property: ${className}.${propertyName}`); logger.debug(`Child workflow type: ${workflowType?.name}`); logger.debug(`Child workflow options: ${JSON.stringify(options)}`); if (!workflowType) { const error = 'Child workflow type is required'; logger.error(`@ChildWorkflow validation failed for ${className}.${propertyName}: ${error}`); throw new Error(error); } if (typeof workflowType !== 'function') { const error = 'Child workflow type must be a class constructor'; logger.error(`@ChildWorkflow validation failed for ${className}.${propertyName}: ${error}`); throw new Error(error); } const workflowName = workflowType.name; logger.debug(`Using class name as workflow name: ${workflowName}`); const childWorkflowMetadata = { workflowType, workflowName, propertyKey: propertyName, className, options: options || {}, }; logger.debug(`Storing @ChildWorkflow metadata for ${className}.${propertyName}: ${JSON.stringify(childWorkflowMetadata)}`); try { Reflect.defineMetadata(constants_1.TEMPORAL_CHILD_WORKFLOW, childWorkflowMetadata, target, propertyKey); logger.debug(`Stored @ChildWorkflow metadata for ${className}.${propertyName}`); Object.defineProperty(target, propertyKey, { get() { const error = `Child workflow ${workflowName} not initialized. This should be set up by the worker service.`; logger.warn(`Child workflow proxy not initialized: ${className}.${propertyName} -> ${workflowName}`); throw new Error(error); }, set() { const error = 'Child workflow proxy is read-only'; logger.warn(`Attempted to set child workflow proxy: ${className}.${propertyName}`); throw new Error(error); }, enumerable: false, configurable: true, }); logger.debug(`Created property descriptor for child workflow: ${className}.${propertyName}`); logger.debug(`@ChildWorkflow decorator successfully applied to ${className}.${propertyName}`); } catch (error) { logger.error(`Failed to apply @ChildWorkflow decorator to ${className}.${propertyName}:`, error); throw error; } }; }; exports.ChildWorkflow = ChildWorkflow; //# sourceMappingURL=workflow.decorator.js.map