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
JavaScript
;
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