UNPKG

nestjs-temporal-core

Version:

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

530 lines 20.4 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var TemporalMetadataAccessor_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.TemporalMetadataAccessor = void 0; const common_1 = require("@nestjs/common"); const constants_1 = require("../constants"); const logger_1 = require("../utils/logger"); let TemporalMetadataAccessor = TemporalMetadataAccessor_1 = class TemporalMetadataAccessor { constructor() { this.activityMethodCache = new Map(); this.logger = (0, logger_1.createLogger)(TemporalMetadataAccessor_1.name); } isActivity(target) { try { return (Reflect.hasMetadata(constants_1.TEMPORAL_ACTIVITY, target) || Reflect.hasMetadata(constants_1.TEMPORAL_ACTIVITY, target.prototype)); } catch { return false; } } isActivityMethod(target, methodName) { try { if (!target || typeof target === 'string') return false; const targetObj = target; return (Reflect.hasMetadata(constants_1.TEMPORAL_ACTIVITY_METHOD, target, methodName || '') || (targetObj.constructor?.prototype !== undefined && Reflect.hasMetadata(constants_1.TEMPORAL_ACTIVITY_METHOD, targetObj.constructor.prototype, methodName || ''))); } catch { return false; } } getActivityMetadata(target) { try { return (Reflect.getMetadata(constants_1.TEMPORAL_ACTIVITY, target) || Reflect.getMetadata(constants_1.TEMPORAL_ACTIVITY, target.prototype) || null); } catch { return null; } } getActivityMethodMetadata(instance, methodName) { try { if (!instance) return null; const prototype = Object.getPrototypeOf(instance); if (!prototype) return null; const metadata = Reflect.getMetadata(constants_1.TEMPORAL_ACTIVITY_METHOD, prototype, methodName); if (!metadata) return null; if (!(methodName in prototype)) return null; return { name: metadata.name || methodName, originalName: methodName, methodName, className: prototype.constructor?.name || 'Unknown', options: metadata.options || metadata, handler: prototype[methodName], }; } catch { return null; } } getActivityMethodNames(target) { try { if (!target || typeof target !== 'function' || !target.prototype) return []; const prototype = target.prototype; const propertyNames = Object.getOwnPropertyNames(prototype); const methodNames = []; for (const propertyName of propertyNames) { if (propertyName === 'constructor') continue; try { if (Reflect.hasMetadata(constants_1.TEMPORAL_ACTIVITY_METHOD, prototype, propertyName)) { methodNames.push(propertyName); } } catch { } } return methodNames; } catch { return []; } } getActivityMethodName(target, methodName) { try { if (!target || typeof target === 'string') return null; const metadata = this.getActivityMethodMetadata(target, methodName || ''); return metadata?.name || methodName || null; } catch { return null; } } getActivityOptions(target) { try { const metadata = this.getActivityMetadata(target); return metadata || null; } catch { return null; } } extractActivityMethods(instance) { const errors = []; const methods = new Map(); let extractedCount = 0; if (!instance) { return { success: true, methods, errors, extractedCount: 0, }; } const constructor = instance.constructor; if (constructor && this.activityMethodCache.has(constructor)) { const cachedMethods = this.activityMethodCache.get(constructor); for (const [name, method] of cachedMethods.entries()) { if (typeof method === 'function') { methods.set(name, { name, originalName: name, methodName: name, className: constructor.name || 'Unknown', handler: method, }); extractedCount++; } else if (method && typeof method === 'object') { methods.set(name, method); extractedCount++; } } return { success: true, methods, errors, extractedCount, }; } try { const prototype = Object.getPrototypeOf(instance); if (!prototype) { this.logger.warn('No prototype found for instance'); return { success: false, methods, errors: [{ method: 'prototype', error: 'No prototype found for instance' }], extractedCount: 0, }; } const storedActivityMethods = Reflect.getMetadata(constants_1.TEMPORAL_ACTIVITY_METHOD, prototype); if (storedActivityMethods && typeof storedActivityMethods === 'object') { for (const [methodName, methodMetadata] of Object.entries(storedActivityMethods)) { try { if (typeof prototype[methodName] === 'function') { const metadata = methodMetadata; const activityName = metadata.name || methodName; methods.set(activityName, { name: activityName, originalName: methodName, methodName: methodName, className: prototype.constructor?.name || 'Unknown', options: { name: activityName, methodName: methodName, className: prototype.constructor?.name || 'Unknown', ...metadata, }, handler: prototype[methodName].bind(instance), }); extractedCount++; this.logger.debug(`Found activity method: ${activityName}`); } } catch (methodError) { const errorMessage = methodError instanceof Error ? methodError.message : 'Unknown error'; errors.push({ method: methodName, error: errorMessage }); this.logger.warn(`Failed to process method ${methodName}`, methodError); } } } else { const propertyNames = Object.getOwnPropertyNames(prototype); for (const propertyName of propertyNames) { if (propertyName === 'constructor') continue; try { const methodMetadata = Reflect.getMetadata(constants_1.TEMPORAL_ACTIVITY_METHOD, prototype, propertyName); if (methodMetadata && typeof prototype[propertyName] === 'function') { const activityName = methodMetadata.name || propertyName; methods.set(activityName, { name: activityName, originalName: propertyName, methodName: propertyName, className: prototype.constructor?.name || 'Unknown', options: { name: activityName, methodName: propertyName, className: prototype.constructor?.name || 'Unknown', ...methodMetadata, }, handler: prototype[propertyName].bind(instance), }); extractedCount++; this.logger.debug(`Found activity method: ${activityName}`); } } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; errors.push({ method: propertyName, error: errorMessage }); this.logger.warn(`Failed to process method ${propertyName}`, error); } } } if (constructor) { this.activityMethodCache.set(constructor, methods); } } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; this.logger.error('Failed to extract activity methods', error); errors.push({ method: 'extraction', error: errorMessage }); } return { success: errors.length === 0, methods, errors, extractedCount, }; } extractActivityMethodsFromClass(target) { const methods = []; try { const prototype = target.prototype; const prototypeMetadata = Reflect.getMetadata(constants_1.TEMPORAL_ACTIVITY_METHOD, prototype); if (prototypeMetadata && typeof prototypeMetadata === 'object') { for (const [methodName, metadata] of Object.entries(prototypeMetadata)) { const metadataObj = metadata; methods.push({ methodName, name: metadataObj.name || methodName, metadata: { name: metadataObj.name || methodName, methodName, className: target.name || 'Unknown', options: metadataObj.options, }, }); } } } catch (error) { this.logger.warn('Failed to extract activity methods from class', error); } return methods; } extractMethodsFromPrototype(instance) { return this.extractActivityMethods(instance); } getActivityMethodOptions(target, methodName) { try { if (!target || !methodName) return null; const metadata = Reflect.getMetadata(constants_1.TEMPORAL_ACTIVITY_METHOD, target, methodName); return metadata || null; } catch { return null; } } getSignalMethods(prototype) { try { const methods = Reflect.getMetadata(constants_1.TEMPORAL_SIGNAL_METHOD, prototype) || {}; return { success: true, methods: methods, errors: [], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; return { success: false, methods: {}, errors: [{ method: 'signal', error: errorMessage }], }; } } getQueryMethods(prototype) { try { const methods = Reflect.getMetadata(constants_1.TEMPORAL_QUERY_METHOD, prototype) || {}; return { success: true, methods: methods, errors: [], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; return { success: false, methods: {}, errors: [{ method: 'query', error: errorMessage }], }; } } getUpdateMethods(prototype) { try { const methods = Reflect.getMetadata(constants_1.TEMPORAL_UPDATE_METHOD, prototype) || {}; return { success: true, methods: methods, errors: [], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; return { success: false, methods: {}, errors: [{ method: 'update', error: errorMessage }], }; } } getChildWorkflows(prototype) { try { const workflows = Reflect.getMetadata(constants_1.TEMPORAL_CHILD_WORKFLOW, prototype) || {}; return { success: true, workflows: workflows, errors: [], }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; return { success: false, workflows: {}, errors: [{ workflow: 'child', error: errorMessage }], }; } } validateActivityClass(constructor) { const issues = []; const warnings = []; try { const className = constructor.name || 'Unknown'; const prototype = constructor.prototype; const methodCount = this.getActivityMethodNames(constructor).length; if (!this.isActivity(constructor)) { issues.push('Class is not marked with @Activity decorator'); } const hasActivityMethods = this.hasActivityMethods(prototype); if (!hasActivityMethods) { issues.push('Activity class has no methods marked with @ActivityMethod'); } if (methodCount === 0) { warnings.push('No activity methods found in class'); } if (methodCount > 50) { warnings.push('Class has many activity methods, consider splitting'); } return { isValid: issues.length === 0, issues, warnings: warnings.length > 0 ? warnings : undefined, className, methodCount, }; } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; issues.push(`Validation failed: ${errorMessage}`); return { isValid: false, issues, className: constructor.name || 'Unknown', methodCount: 0, }; } } hasActivityMethods(prototype) { if (!prototype) return false; try { const activityMethods = Reflect.getMetadata(constants_1.TEMPORAL_ACTIVITY_METHOD, prototype); if (activityMethods && typeof activityMethods === 'object') { return Object.keys(activityMethods).length > 0; } const propertyNames = Object.getOwnPropertyNames(prototype); return propertyNames.some((propertyName) => { if (propertyName === 'constructor') return false; try { return Reflect.hasMetadata(constants_1.TEMPORAL_ACTIVITY_METHOD, prototype, propertyName); } catch { return false; } }); } catch { return false; } } getAllMetadataKeys(target) { try { return Reflect.getMetadataKeys(target); } catch { return []; } } getActivityName(target) { try { const metadata = this.getActivityMetadata(target); return metadata?.name || target.name || null; } catch { return null; } } getActivityInfo(target) { try { if (!target || typeof target !== 'function') { return { className: 'Unknown', isActivity: false, activityName: null, methodNames: [], metadata: null, activityOptions: null, methodCount: 0, }; } const className = target.name || 'Unknown'; const isActivity = this.isActivity(target); const activityName = this.getActivityName(target); const methodNames = this.getActivityMethodNames(target); const metadata = this.getActivityMetadata(target); const activityOptions = this.getActivityOptions(target); return { className, isActivity, activityName, methodNames, metadata, activityOptions, methodCount: methodNames.length, }; } catch { return { className: 'Unknown', isActivity: false, activityName: null, methodNames: [], metadata: null, activityOptions: null, methodCount: 0, }; } } validateMetadata(target, expectedKeys) { const missing = []; const present = []; const targetName = typeof target === 'function' ? target.name || 'Unknown' : 'Unknown'; for (const key of expectedKeys) { try { if (!Reflect.hasMetadata(key, target)) { missing.push(key); } else { present.push(key); } } catch { missing.push(key); } } return { isValid: missing.length === 0, missing, present, target: targetName, }; } clearCache() { this.activityMethodCache.clear(); } getCacheStats() { const entries = Array.from(this.activityMethodCache.keys()).map((k) => k.name || 'Unknown'); return { size: this.activityMethodCache.size, entries, message: 'Cache statistics not available', note: 'WeakMap-based caching prevents memory leaks but limits size reporting', hitRate: 0, missRate: 0, }; } }; exports.TemporalMetadataAccessor = TemporalMetadataAccessor; exports.TemporalMetadataAccessor = TemporalMetadataAccessor = TemporalMetadataAccessor_1 = __decorate([ (0, common_1.Injectable)(), __metadata("design:paramtypes", []) ], TemporalMetadataAccessor); //# sourceMappingURL=temporal-metadata.service.js.map