@ductape/sdk 0.0.4-v99 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/agent-context.d.ts +3 -1
- package/dist/agents/agent-context.js +19 -3
- package/dist/agents/agent-context.js.map +1 -1
- package/dist/agents/agents.service.js +9 -5
- package/dist/agents/agents.service.js.map +1 -1
- package/dist/agents/types/agents.types.d.ts +14 -1
- package/dist/agents/types/agents.types.js.map +1 -1
- package/dist/api/services/appApi.service.js +15 -6
- package/dist/api/services/appApi.service.js.map +1 -1
- package/dist/api/services/logsApi.service.d.ts +51 -0
- package/dist/api/services/logsApi.service.js +19 -2
- package/dist/api/services/logsApi.service.js.map +1 -1
- package/dist/api/services/processorApi.service.d.ts +568 -2
- package/dist/api/services/processorApi.service.js +412 -21
- package/dist/api/services/processorApi.service.js.map +1 -1
- package/dist/api/services/productsApi.service.d.ts +20 -0
- package/dist/api/services/productsApi.service.js +44 -15
- package/dist/api/services/productsApi.service.js.map +1 -1
- package/dist/api/services/secretsApi.service.js +0 -11
- package/dist/api/services/secretsApi.service.js.map +1 -1
- package/dist/api/services/webhooksApi.service.js +13 -6
- package/dist/api/services/webhooksApi.service.js.map +1 -1
- package/dist/api/services/workflowApi.service.js +30 -12
- package/dist/api/services/workflowApi.service.js.map +1 -1
- package/dist/api/urls.d.ts +26 -0
- package/dist/api/urls.js +30 -3
- package/dist/api/urls.js.map +1 -1
- package/dist/apps/validators/joi-validators/update.appAction.validator.js +12 -1
- package/dist/apps/validators/joi-validators/update.appAction.validator.js.map +1 -1
- package/dist/brokers/brokers.service.d.ts +140 -2
- package/dist/brokers/brokers.service.js +444 -36
- package/dist/brokers/brokers.service.js.map +1 -1
- package/dist/brokers/types/index.d.ts +251 -0
- package/dist/brokers/utils/providers/rabbitmq.service.d.ts +14 -4
- package/dist/brokers/utils/providers/rabbitmq.service.js +22 -35
- package/dist/brokers/utils/providers/rabbitmq.service.js.map +1 -1
- package/dist/cache/cache.manager.d.ts +84 -5
- package/dist/cache/cache.manager.js +478 -38
- package/dist/cache/cache.manager.js.map +1 -1
- package/dist/cache/cache.service.d.ts +5 -0
- package/dist/cache/cache.service.js +163 -6
- package/dist/cache/cache.service.js.map +1 -1
- package/dist/cache/index.d.ts +1 -1
- package/dist/cache/index.js +3 -1
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/types/index.d.ts +4 -0
- package/dist/database/databases.service.d.ts +70 -2
- package/dist/database/databases.service.js +150 -35
- package/dist/database/databases.service.js.map +1 -1
- package/dist/database/types/dashboard.interface.d.ts +74 -0
- package/dist/database/types/dashboard.interface.js +7 -0
- package/dist/database/types/dashboard.interface.js.map +1 -0
- package/dist/database/types/index.d.ts +1 -0
- package/dist/graph/graphs.service.d.ts +50 -12
- package/dist/graph/graphs.service.js +689 -203
- package/dist/graph/graphs.service.js.map +1 -1
- package/dist/graph/types/connection.interface.d.ts +2 -2
- package/dist/index.d.ts +286 -4
- package/dist/index.js +370 -21
- package/dist/index.js.map +1 -1
- package/dist/logs/logs.types.d.ts +16 -3
- package/dist/logs/logs.types.js +11 -0
- package/dist/logs/logs.types.js.map +1 -1
- package/dist/notifications/notifications.service.d.ts +3 -0
- package/dist/notifications/notifications.service.js +57 -14
- package/dist/notifications/notifications.service.js.map +1 -1
- package/dist/notifications/types/notifications.types.d.ts +50 -0
- package/dist/processor/services/processor.service.d.ts +132 -8
- package/dist/processor/services/processor.service.js +1174 -267
- package/dist/processor/services/processor.service.js.map +1 -1
- package/dist/processor/utils/processor.utils.d.ts +5 -0
- package/dist/processor/utils/processor.utils.js +65 -12
- package/dist/processor/utils/processor.utils.js.map +1 -1
- package/dist/processor/utils/storage.util.js +11 -2
- package/dist/processor/utils/storage.util.js.map +1 -1
- package/dist/products/services/products.service.d.ts +19 -2
- package/dist/products/services/products.service.js +388 -54
- package/dist/products/services/products.service.js.map +1 -1
- package/dist/products/validators/joi-validators/create.productFeature.validator.js +1 -1
- package/dist/products/validators/joi-validators/create.productJob.validator.js +2 -2
- package/dist/products/validators/joi-validators/create.productJob.validator.js.map +1 -1
- package/dist/products/validators/joi-validators/create.productMessageBrokerTopic.validator.js +1 -0
- package/dist/products/validators/joi-validators/create.productMessageBrokerTopic.validator.js.map +1 -1
- package/dist/products/validators/joi-validators/create.productNotification.validator.js +23 -12
- package/dist/products/validators/joi-validators/create.productNotification.validator.js.map +1 -1
- package/dist/resilience/fallback.service.d.ts +1 -0
- package/dist/resilience/fallback.service.js +2 -0
- package/dist/resilience/fallback.service.js.map +1 -1
- package/dist/resilience/quota.service.d.ts +1 -0
- package/dist/resilience/quota.service.js +2 -0
- package/dist/resilience/quota.service.js.map +1 -1
- package/dist/secrets/secrets.resolver.js +4 -1
- package/dist/secrets/secrets.resolver.js.map +1 -1
- package/dist/secrets/secrets.service.js +0 -12
- package/dist/secrets/secrets.service.js.map +1 -1
- package/dist/secrets/secrets.types.d.ts +3 -3
- package/dist/secrets/secrets.types.js +5 -5
- package/dist/secrets/secrets.types.js.map +1 -1
- package/dist/sessions/index.d.ts +1 -1
- package/dist/sessions/index.js +4 -1
- package/dist/sessions/index.js.map +1 -1
- package/dist/sessions/sessions.helper.d.ts +23 -3
- package/dist/sessions/sessions.helper.js +20 -3
- package/dist/sessions/sessions.helper.js.map +1 -1
- package/dist/sessions/sessions.resolver.d.ts +31 -0
- package/dist/sessions/sessions.resolver.js +230 -1
- package/dist/sessions/sessions.resolver.js.map +1 -1
- package/dist/sessions/sessions.service.d.ts +18 -2
- package/dist/sessions/sessions.service.js +121 -57
- package/dist/sessions/sessions.service.js.map +1 -1
- package/dist/sessions/types/index.d.ts +65 -21
- package/dist/storage/storage.service.d.ts +3 -0
- package/dist/storage/storage.service.js +179 -39
- package/dist/storage/storage.service.js.map +1 -1
- package/dist/types/index.types.d.ts +2 -0
- package/dist/types/inputs.types.d.ts +1 -0
- package/dist/types/inputs.types.js +3 -2
- package/dist/types/inputs.types.js.map +1 -1
- package/dist/types/processor.types.d.ts +72 -6
- package/dist/types/processor.types.js.map +1 -1
- package/dist/types/productsBuilder.types.d.ts +10 -0
- package/dist/types/productsBuilder.types.js +4 -0
- package/dist/types/productsBuilder.types.js.map +1 -1
- package/dist/vector/adapters/weaviate.adapter.js +22 -6
- package/dist/vector/adapters/weaviate.adapter.js.map +1 -1
- package/dist/vector/vector-database.service.d.ts +4 -2
- package/dist/vector/vector-database.service.js +71 -29
- package/dist/vector/vector-database.service.js.map +1 -1
- package/dist/workflows/types/workflows.types.d.ts +61 -3
- package/dist/workflows/types/workflows.types.js.map +1 -1
- package/dist/workflows/workflow-builder.js +17 -2
- package/dist/workflows/workflow-builder.js.map +1 -1
- package/dist/workflows/workflow-executor.d.ts +97 -18
- package/dist/workflows/workflow-executor.js +1449 -244
- package/dist/workflows/workflow-executor.js.map +1 -1
- package/dist/workflows/workflows.service.d.ts +2 -0
- package/dist/workflows/workflows.service.js +538 -74
- package/dist/workflows/workflows.service.js.map +1 -1
- package/package.json +11 -1
- package/dist/processor/services/fallback.service.d.ts +0 -5
- package/dist/processor/services/fallback.service.js +0 -43
- package/dist/processor/services/fallback.service.js.map +0 -1
- package/dist/processor/services/messagebrokers/aws-sqs.service.d.ts +0 -15
- package/dist/processor/services/messagebrokers/aws-sqs.service.js +0 -77
- package/dist/processor/services/messagebrokers/aws-sqs.service.js.map +0 -1
- package/dist/processor/services/messagebrokers/google-pubsub.service.d.ts +0 -16
- package/dist/processor/services/messagebrokers/google-pubsub.service.js +0 -34
- package/dist/processor/services/messagebrokers/google-pubsub.service.js.map +0 -1
- package/dist/processor/services/messagebrokers/index.d.ts +0 -3
- package/dist/processor/services/messagebrokers/index.js +0 -26
- package/dist/processor/services/messagebrokers/index.js.map +0 -1
- package/dist/processor/services/messagebrokers/kafka.service.d.ts +0 -14
- package/dist/processor/services/messagebrokers/kafka.service.js +0 -45
- package/dist/processor/services/messagebrokers/kafka.service.js.map +0 -1
- package/dist/processor/services/messagebrokers/messagebrokers.type.d.ts +0 -6
- package/dist/processor/services/messagebrokers/messagebrokers.type.js +0 -3
- package/dist/processor/services/messagebrokers/messagebrokers.type.js.map +0 -1
- package/dist/processor/services/messagebrokers/rabbitmq.service.d.ts +0 -14
- package/dist/processor/services/messagebrokers/rabbitmq.service.js +0 -67
- package/dist/processor/services/messagebrokers/rabbitmq.service.js.map +0 -1
- package/dist/processor/services/messagebrokers/redis.service.d.ts +0 -18
- package/dist/processor/services/messagebrokers/redis.service.js +0 -82
- package/dist/processor/services/messagebrokers/redis.service.js.map +0 -1
- package/dist/processor/services/quota.service.d.ts +0 -15
- package/dist/processor/services/quota.service.js +0 -63
- package/dist/processor/services/quota.service.js.map +0 -1
- package/dist/test/index.d.ts +0 -3
- package/dist/test/index.js +0 -11
- package/dist/test/index.js.map +0 -1
- package/dist/test/test.appBuilder.d.ts +0 -0
- package/dist/test/test.appBuilder.js +0 -1
- package/dist/test/test.appBuilder.js.map +0 -1
- package/dist/test/test.broker.kafka.d.ts +0 -1
- package/dist/test/test.broker.kafka.js +0 -172
- package/dist/test/test.broker.kafka.js.map +0 -1
- package/dist/test/test.broker.nats.d.ts +0 -1
- package/dist/test/test.broker.nats.js +0 -193
- package/dist/test/test.broker.nats.js.map +0 -1
- package/dist/test/test.broker.pubsub.d.ts +0 -1
- package/dist/test/test.broker.pubsub.js +0 -171
- package/dist/test/test.broker.pubsub.js.map +0 -1
- package/dist/test/test.broker.rabbitmq.d.ts +0 -1
- package/dist/test/test.broker.rabbitmq.js +0 -164
- package/dist/test/test.broker.rabbitmq.js.map +0 -1
- package/dist/test/test.broker.redis.d.ts +0 -1
- package/dist/test/test.broker.redis.js +0 -168
- package/dist/test/test.broker.redis.js.map +0 -1
- package/dist/test/test.broker.sqs.d.ts +0 -1
- package/dist/test/test.broker.sqs.js +0 -158
- package/dist/test/test.broker.sqs.js.map +0 -1
- package/dist/test/test.caches.d.ts +0 -1
- package/dist/test/test.caches.js +0 -231
- package/dist/test/test.caches.js.map +0 -1
- package/dist/test/test.database.d.ts +0 -1
- package/dist/test/test.database.dynamo.d.ts +0 -1
- package/dist/test/test.database.dynamo.js +0 -265
- package/dist/test/test.database.dynamo.js.map +0 -1
- package/dist/test/test.database.js +0 -140
- package/dist/test/test.database.js.map +0 -1
- package/dist/test/test.database.mongo.d.ts +0 -1
- package/dist/test/test.database.mongo.js +0 -371
- package/dist/test/test.database.mongo.js.map +0 -1
- package/dist/test/test.database.mysql.d.ts +0 -1
- package/dist/test/test.database.mysql.js +0 -415
- package/dist/test/test.database.mysql.js.map +0 -1
- package/dist/test/test.database.postgres.d.ts +0 -1
- package/dist/test/test.database.postgres.js +0 -412
- package/dist/test/test.database.postgres.js.map +0 -1
- package/dist/test/test.email.brevo.d.ts +0 -1
- package/dist/test/test.email.brevo.js +0 -326
- package/dist/test/test.email.brevo.js.map +0 -1
- package/dist/test/test.email.mailgun.d.ts +0 -1
- package/dist/test/test.email.mailgun.js +0 -352
- package/dist/test/test.email.mailgun.js.map +0 -1
- package/dist/test/test.email.postmark.d.ts +0 -1
- package/dist/test/test.email.postmark.js +0 -316
- package/dist/test/test.email.postmark.js.map +0 -1
- package/dist/test/test.email.sendgrid.d.ts +0 -1
- package/dist/test/test.email.sendgrid.js +0 -365
- package/dist/test/test.email.sendgrid.js.map +0 -1
- package/dist/test/test.email.smtp.d.ts +0 -1
- package/dist/test/test.email.smtp.js +0 -323
- package/dist/test/test.email.smtp.js.map +0 -1
- package/dist/test/test.graph.arangodb.d.ts +0 -1
- package/dist/test/test.graph.arangodb.js +0 -358
- package/dist/test/test.graph.arangodb.js.map +0 -1
- package/dist/test/test.graph.memgraph.d.ts +0 -1
- package/dist/test/test.graph.memgraph.js +0 -320
- package/dist/test/test.graph.memgraph.js.map +0 -1
- package/dist/test/test.graph.neo4j.d.ts +0 -1
- package/dist/test/test.graph.neo4j.js +0 -218
- package/dist/test/test.graph.neo4j.js.map +0 -1
- package/dist/test/test.graph.neptune.d.ts +0 -1
- package/dist/test/test.graph.neptune.js +0 -331
- package/dist/test/test.graph.neptune.js.map +0 -1
- package/dist/test/test.health.d.ts +0 -0
- package/dist/test/test.health.js +0 -1
- package/dist/test/test.health.js.map +0 -1
- package/dist/test/test.import.d.ts +0 -0
- package/dist/test/test.import.js +0 -1
- package/dist/test/test.import.js.map +0 -1
- package/dist/test/test.import.openapi.d.ts +0 -0
- package/dist/test/test.import.openapi.js +0 -1
- package/dist/test/test.import.openapi.js.map +0 -1
- package/dist/test/test.imports.d.ts +0 -1
- package/dist/test/test.imports.js +0 -21
- package/dist/test/test.imports.js.map +0 -1
- package/dist/test/test.logs.d.ts +0 -0
- package/dist/test/test.logs.js +0 -1
- package/dist/test/test.logs.js.map +0 -1
- package/dist/test/test.notifications.d.ts +0 -1
- package/dist/test/test.notifications.js +0 -198
- package/dist/test/test.notifications.js.map +0 -1
- package/dist/test/test.notifiers.d.ts +0 -0
- package/dist/test/test.notifiers.js +0 -1
- package/dist/test/test.notifiers.js.map +0 -1
- package/dist/test/test.processor.d.ts +0 -0
- package/dist/test/test.processor.js +0 -1
- package/dist/test/test.processor.js.map +0 -1
- package/dist/test/test.productBuilder.d.ts +0 -0
- package/dist/test/test.productBuilder.js +0 -1
- package/dist/test/test.productBuilder.js.map +0 -1
- package/dist/test/test.products.d.ts +0 -0
- package/dist/test/test.products.js +0 -1
- package/dist/test/test.products.js.map +0 -1
- package/dist/test/test.push.expo.d.ts +0 -1
- package/dist/test/test.push.expo.js +0 -442
- package/dist/test/test.push.expo.js.map +0 -1
- package/dist/test/test.push.firebase.d.ts +0 -1
- package/dist/test/test.push.firebase.js +0 -409
- package/dist/test/test.push.firebase.js.map +0 -1
- package/dist/test/test.session.d.ts +0 -1
- package/dist/test/test.session.js +0 -299
- package/dist/test/test.session.js.map +0 -1
- package/dist/test/test.sms.nexmo.d.ts +0 -1
- package/dist/test/test.sms.nexmo.js +0 -278
- package/dist/test/test.sms.nexmo.js.map +0 -1
- package/dist/test/test.sms.twilio.d.ts +0 -1
- package/dist/test/test.sms.twilio.js +0 -275
- package/dist/test/test.sms.twilio.js.map +0 -1
- package/dist/test/test.storage.d.ts +0 -1
- package/dist/test/test.storage.js +0 -202
- package/dist/test/test.storage.js.map +0 -1
- package/dist/test/test.triggers.d.ts +0 -1
- package/dist/test/test.triggers.js +0 -314
- package/dist/test/test.triggers.js.map +0 -1
- package/dist/test/test.vector.pinecone.d.ts +0 -1
- package/dist/test/test.vector.pinecone.js +0 -238
- package/dist/test/test.vector.pinecone.js.map +0 -1
- package/dist/test/test.vector.qdrant.d.ts +0 -1
- package/dist/test/test.vector.qdrant.js +0 -307
- package/dist/test/test.vector.qdrant.js.map +0 -1
- package/dist/test/test.vector.weaviate.d.ts +0 -1
- package/dist/test/test.vector.weaviate.js +0 -325
- package/dist/test/test.vector.weaviate.js.map +0 -1
|
@@ -106,10 +106,14 @@ class WorkflowService {
|
|
|
106
106
|
this.productId = '';
|
|
107
107
|
/** Cache manager for 3-tier caching */
|
|
108
108
|
this.cacheManager = null;
|
|
109
|
+
/** Local cache for cache configurations to avoid repeated API calls */
|
|
110
|
+
this.cacheConfigCache = new Map();
|
|
111
|
+
console.log('[WorkflowService] constructor', { hasConfig: !!config, env_type: config === null || config === void 0 ? void 0 : config.env_type, hasRedis: !!(config === null || config === void 0 ? void 0 : config.redis_client) });
|
|
109
112
|
this.config = config || null;
|
|
110
113
|
this._privateKey = (config === null || config === void 0 ? void 0 : config.private_key) || '';
|
|
111
114
|
if (config) {
|
|
112
115
|
this.workflowApiService = new workflowApi_service_1.WorkflowApiService(config.env_type);
|
|
116
|
+
console.log('[WorkflowService] WorkflowApiService initialized', { env_type: config.env_type });
|
|
113
117
|
// Initialize CacheManager if Redis client is provided
|
|
114
118
|
if (config.redis_client) {
|
|
115
119
|
this.cacheManager = new cache_manager_1.CacheManager({
|
|
@@ -120,7 +124,14 @@ class WorkflowService {
|
|
|
120
124
|
env_type: config.env_type,
|
|
121
125
|
redis_client: config.redis_client,
|
|
122
126
|
});
|
|
127
|
+
console.log('[WorkflowService] CacheManager initialized');
|
|
123
128
|
}
|
|
129
|
+
else {
|
|
130
|
+
console.log('[WorkflowService] No redis_client provided, cache disabled');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
console.log('[WorkflowService] No config provided, service unconfigured');
|
|
124
135
|
}
|
|
125
136
|
}
|
|
126
137
|
// ==================== CONFIGURATION ====================
|
|
@@ -128,6 +139,7 @@ class WorkflowService {
|
|
|
128
139
|
* Update service configuration
|
|
129
140
|
*/
|
|
130
141
|
updateConfig(config) {
|
|
142
|
+
console.log('[WorkflowService] updateConfig', { env_type: config.env_type, workspace_id: config.workspace_id });
|
|
131
143
|
this.config = config;
|
|
132
144
|
this.workflowApiService = new workflowApi_service_1.WorkflowApiService(config.env_type);
|
|
133
145
|
}
|
|
@@ -136,20 +148,19 @@ class WorkflowService {
|
|
|
136
148
|
*/
|
|
137
149
|
getAuthPayload() {
|
|
138
150
|
if (!this.config) {
|
|
151
|
+
console.log('[WorkflowService] getAuthPayload failed: no config');
|
|
139
152
|
throw WorkflowError.configurationError('WorkflowService not configured. Please provide config when initializing.');
|
|
140
153
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
public_key: this.config.public_key,
|
|
145
|
-
token: this.config.token,
|
|
146
|
-
};
|
|
154
|
+
const hasAccessKey = !!this.config.access_key;
|
|
155
|
+
console.log('[WorkflowService] getAuthPayload', { user_id: this.config.user_id, workspace_id: this.config.workspace_id, hasAccessKey });
|
|
156
|
+
return Object.assign({ user_id: this.config.user_id, workspace_id: this.config.workspace_id, public_key: this.config.public_key, token: this.config.token }, (this.config.access_key && { access_key: this.config.access_key }));
|
|
147
157
|
}
|
|
148
158
|
/**
|
|
149
159
|
* Ensure WorkflowApiService is initialized
|
|
150
160
|
*/
|
|
151
161
|
ensureApiService() {
|
|
152
162
|
if (!this.workflowApiService) {
|
|
163
|
+
console.log('[WorkflowService] ensureApiService failed: WorkflowApiService not initialized');
|
|
153
164
|
throw WorkflowError.configurationError('WorkflowService not configured. Please provide config when initializing.');
|
|
154
165
|
}
|
|
155
166
|
return this.workflowApiService;
|
|
@@ -158,6 +169,8 @@ class WorkflowService {
|
|
|
158
169
|
* Get service configuration
|
|
159
170
|
*/
|
|
160
171
|
getConfig() {
|
|
172
|
+
var _a;
|
|
173
|
+
console.log('[WorkflowService] getConfig', { hasConfig: !!this.config, env_type: (_a = this.config) === null || _a === void 0 ? void 0 : _a.env_type });
|
|
161
174
|
return this.config;
|
|
162
175
|
}
|
|
163
176
|
// ==================== PRODUCT BUILDER MANAGEMENT ====================
|
|
@@ -166,14 +179,18 @@ class WorkflowService {
|
|
|
166
179
|
*/
|
|
167
180
|
createNewProductBuilder() {
|
|
168
181
|
if (!this.config) {
|
|
182
|
+
console.log('[WorkflowService] createNewProductBuilder failed: no config');
|
|
169
183
|
throw WorkflowError.configurationError('WorkflowService not configured. Please provide config when initializing.');
|
|
170
184
|
}
|
|
185
|
+
console.log('[WorkflowService] createNewProductBuilder', { env_type: this.config.env_type, hasAccessKey: !!this.config.access_key });
|
|
171
186
|
return new products_service_1.default({
|
|
172
187
|
workspace_id: this.config.workspace_id,
|
|
173
188
|
public_key: this.config.public_key,
|
|
174
189
|
user_id: this.config.user_id,
|
|
175
190
|
token: this.config.token,
|
|
176
191
|
env_type: this.config.env_type,
|
|
192
|
+
access_key: this.config.access_key,
|
|
193
|
+
workspace_private_key: this._privateKey || undefined,
|
|
177
194
|
});
|
|
178
195
|
}
|
|
179
196
|
/**
|
|
@@ -182,11 +199,16 @@ class WorkflowService {
|
|
|
182
199
|
async getProductBuilder(productTag) {
|
|
183
200
|
let builder = this.productBuilders.get(productTag);
|
|
184
201
|
if (!builder) {
|
|
202
|
+
console.log('[WorkflowService] getProductBuilder creating new builder', { productTag });
|
|
185
203
|
builder = this.createNewProductBuilder();
|
|
186
204
|
await builder.initializeProductByTag(productTag);
|
|
187
205
|
this.productBuilders.set(productTag, builder);
|
|
188
206
|
// Update productId for logging
|
|
189
207
|
this.productId = builder.fetchProductId() || '';
|
|
208
|
+
console.log('[WorkflowService] getProductBuilder initialized', { productTag, productId: this.productId });
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
console.log('[WorkflowService] getProductBuilder cache hit', { productTag });
|
|
190
212
|
}
|
|
191
213
|
return builder;
|
|
192
214
|
}
|
|
@@ -195,6 +217,7 @@ class WorkflowService {
|
|
|
195
217
|
*/
|
|
196
218
|
initializeLogService() {
|
|
197
219
|
if (!this.logService && this.config) {
|
|
220
|
+
console.log('[WorkflowService] initializeLogService', { productId: this.productId });
|
|
198
221
|
this.logService = new logs_service_1.default({
|
|
199
222
|
product_id: this.productId,
|
|
200
223
|
workspace_id: this.config.workspace_id,
|
|
@@ -209,11 +232,25 @@ class WorkflowService {
|
|
|
209
232
|
* Validate cache tag exists in product and return cache configuration
|
|
210
233
|
*/
|
|
211
234
|
async validateCache(productTag, cacheTag) {
|
|
235
|
+
const cacheKey = `${productTag}:${cacheTag}`;
|
|
236
|
+
const cached = this.cacheConfigCache.get(cacheKey);
|
|
237
|
+
const now = Date.now();
|
|
238
|
+
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
239
|
+
console.log('[WorkflowService] validateCache', { productTag, cacheTag, cacheKey, hasCached: !!cached });
|
|
240
|
+
// Return cached config if still valid
|
|
241
|
+
if (cached && (now - cached.fetchedAt) < CACHE_TTL) {
|
|
242
|
+
console.log('[WorkflowService] validateCache using cached config', { cacheKey, expiry: cached.expiry });
|
|
243
|
+
return { expiry: cached.expiry };
|
|
244
|
+
}
|
|
245
|
+
// Fetch from API and cache the result
|
|
212
246
|
const builder = await this.getProductBuilder(productTag);
|
|
213
247
|
const cache = await builder.fetchCache(cacheTag);
|
|
214
248
|
if (!cache) {
|
|
249
|
+
console.log('[WorkflowService] validateCache cache config not found', { cacheTag });
|
|
215
250
|
throw WorkflowError.validationError(`Cache configuration '${cacheTag}' does not exist`);
|
|
216
251
|
}
|
|
252
|
+
this.cacheConfigCache.set(cacheKey, { expiry: cache.expiry, fetchedAt: now });
|
|
253
|
+
console.log('[WorkflowService] validateCache fetched and cached', { cacheKey, expiry: cache.expiry });
|
|
217
254
|
return { expiry: cache.expiry };
|
|
218
255
|
}
|
|
219
256
|
/**
|
|
@@ -221,8 +258,10 @@ class WorkflowService {
|
|
|
221
258
|
*/
|
|
222
259
|
createNewProcessor() {
|
|
223
260
|
if (!this.config) {
|
|
261
|
+
console.log('[WorkflowService] createNewProcessor failed: no config');
|
|
224
262
|
throw WorkflowError.configurationError('WorkflowService not configured. Please provide config when initializing.');
|
|
225
263
|
}
|
|
264
|
+
console.log('[WorkflowService] createNewProcessor', { env_type: this.config.env_type, hasAccessKey: !!this.config.access_key });
|
|
226
265
|
return new processor_service_1.default({
|
|
227
266
|
workspace_id: this.config.workspace_id,
|
|
228
267
|
public_key: this.config.public_key,
|
|
@@ -230,6 +269,7 @@ class WorkflowService {
|
|
|
230
269
|
token: this.config.token,
|
|
231
270
|
env_type: this.config.env_type,
|
|
232
271
|
private_key: this._privateKey,
|
|
272
|
+
access_key: this.config.access_key,
|
|
233
273
|
});
|
|
234
274
|
}
|
|
235
275
|
// ==================== WORKFLOW CRUD OPERATIONS ====================
|
|
@@ -250,13 +290,16 @@ class WorkflowService {
|
|
|
250
290
|
* ```
|
|
251
291
|
*/
|
|
252
292
|
async create(productTag, workflowData) {
|
|
253
|
-
var _a;
|
|
293
|
+
var _a, _b, _c;
|
|
294
|
+
console.log('[WorkflowService] create ENTRY', { productTag, tag: workflowData.tag, name: workflowData.name, stepsCount: (_b = (_a = workflowData.steps) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0 });
|
|
254
295
|
// Validate required fields
|
|
255
|
-
if (!workflowData.name || !workflowData.tag || !((
|
|
296
|
+
if (!workflowData.name || !workflowData.tag || !((_c = workflowData.steps) === null || _c === void 0 ? void 0 : _c.length)) {
|
|
297
|
+
console.log('[WorkflowService] create validation failed: missing name, tag, or steps');
|
|
256
298
|
throw WorkflowError.validationError('Workflow requires name, tag, and at least one step');
|
|
257
299
|
}
|
|
258
300
|
// Persist to backend using ProductBuilder
|
|
259
301
|
const builder = await this.getProductBuilder(productTag);
|
|
302
|
+
console.log('[WorkflowService] create calling builder.createWorkflow', { tag: workflowData.tag });
|
|
260
303
|
await builder.createWorkflow(workflowData);
|
|
261
304
|
// Store locally
|
|
262
305
|
const localConfig = {
|
|
@@ -272,6 +315,7 @@ class WorkflowService {
|
|
|
272
315
|
envs: workflowData.envs,
|
|
273
316
|
};
|
|
274
317
|
this.localConfigs.set(workflowData.tag, localConfig);
|
|
318
|
+
console.log('[WorkflowService] create SUCCESS', { productTag, tag: workflowData.tag });
|
|
275
319
|
}
|
|
276
320
|
/**
|
|
277
321
|
* Fetch all workflows for a product
|
|
@@ -283,19 +327,27 @@ class WorkflowService {
|
|
|
283
327
|
* ```
|
|
284
328
|
*/
|
|
285
329
|
async fetchAll(productTag) {
|
|
330
|
+
var _a;
|
|
331
|
+
console.log('[WorkflowService] fetchAll ENTRY', { productTag });
|
|
286
332
|
// Return local configs if no product tag
|
|
287
333
|
if (!productTag) {
|
|
334
|
+
const localCount = this.localConfigs.size;
|
|
335
|
+
console.log('[WorkflowService] fetchAll no productTag, returning local configs', { count: localCount });
|
|
288
336
|
return Array.from(this.localConfigs.values());
|
|
289
337
|
}
|
|
290
338
|
// Fetch from API using ProductBuilder
|
|
291
339
|
try {
|
|
292
340
|
const builder = await this.getProductBuilder(productTag);
|
|
341
|
+
console.log('[WorkflowService] fetchAll calling builder.fetchWorkflows', { productTag });
|
|
293
342
|
const workflows = await builder.fetchWorkflows();
|
|
294
343
|
// Convert IProductWorkflow[] to IWorkflowConfig[]
|
|
295
|
-
|
|
344
|
+
const result = workflows.map((wf) => this.productWorkflowToConfig(wf));
|
|
345
|
+
console.log('[WorkflowService] fetchAll SUCCESS', { productTag, count: result.length });
|
|
346
|
+
return result;
|
|
296
347
|
}
|
|
297
348
|
catch (error) {
|
|
298
349
|
// Fall back to local configs if API fails
|
|
350
|
+
console.log('[WorkflowService] fetchAll API failed, falling back to local', { productTag, error: (_a = error === null || error === void 0 ? void 0 : error.message) !== null && _a !== void 0 ? _a : error });
|
|
299
351
|
return Array.from(this.localConfigs.values());
|
|
300
352
|
}
|
|
301
353
|
}
|
|
@@ -309,25 +361,33 @@ class WorkflowService {
|
|
|
309
361
|
* ```
|
|
310
362
|
*/
|
|
311
363
|
async fetch(workflowTag, productTag) {
|
|
364
|
+
var _a, _b;
|
|
365
|
+
console.log('[WorkflowService] fetch ENTRY', { workflowTag, productTag });
|
|
312
366
|
// If productTag is provided, fetch from API
|
|
313
367
|
if (productTag) {
|
|
314
368
|
try {
|
|
315
369
|
const builder = await this.getProductBuilder(productTag);
|
|
370
|
+
console.log('[WorkflowService] fetch calling builder.fetchWorkflow', { workflowTag, productTag });
|
|
316
371
|
const workflow = await builder.fetchWorkflow(workflowTag);
|
|
317
372
|
if (workflow) {
|
|
318
373
|
const config = this.productWorkflowToConfig(workflow);
|
|
319
374
|
// Update local cache
|
|
320
375
|
this.localConfigs.set(workflowTag, config);
|
|
376
|
+
console.log('[WorkflowService] fetch SUCCESS from API', { workflowTag, productTag, stepsCount: (_a = config.steps) === null || _a === void 0 ? void 0 : _a.length });
|
|
321
377
|
return config;
|
|
322
378
|
}
|
|
379
|
+
console.log('[WorkflowService] fetch not found on API', { workflowTag, productTag });
|
|
323
380
|
return null;
|
|
324
381
|
}
|
|
325
382
|
catch (error) {
|
|
326
383
|
// Fall back to local config
|
|
384
|
+
console.log('[WorkflowService] fetch API failed, trying local', { workflowTag, productTag, error: (_b = error === null || error === void 0 ? void 0 : error.message) !== null && _b !== void 0 ? _b : error });
|
|
327
385
|
return this.localConfigs.get(workflowTag) || null;
|
|
328
386
|
}
|
|
329
387
|
}
|
|
330
|
-
|
|
388
|
+
const local = this.localConfigs.get(workflowTag) || null;
|
|
389
|
+
console.log('[WorkflowService] fetch from local only', { workflowTag, found: !!local });
|
|
390
|
+
return local;
|
|
331
391
|
}
|
|
332
392
|
/**
|
|
333
393
|
* Update a workflow
|
|
@@ -342,6 +402,7 @@ class WorkflowService {
|
|
|
342
402
|
*/
|
|
343
403
|
async update(workflowTag, productTag, updates) {
|
|
344
404
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
405
|
+
console.log('[WorkflowService] update ENTRY', { workflowTag, productTag, updateKeys: Object.keys(updates || {}) });
|
|
345
406
|
// Update in backend
|
|
346
407
|
const builder = await this.getProductBuilder(productTag);
|
|
347
408
|
await builder.updateWorkflow(workflowTag, updates);
|
|
@@ -351,6 +412,7 @@ class WorkflowService {
|
|
|
351
412
|
const updated = Object.assign(Object.assign({}, existing), { name: updates.name || existing.name, description: (_a = updates.description) !== null && _a !== void 0 ? _a : existing.description, input: (_b = updates.input) !== null && _b !== void 0 ? _b : existing.input, output: (_c = updates.output) !== null && _c !== void 0 ? _c : existing.output, steps: updates.steps || existing.steps, signals: (_d = updates.signals) !== null && _d !== void 0 ? _d : existing.signals, queries: (_e = updates.queries) !== null && _e !== void 0 ? _e : existing.queries, options: (_f = updates.options) !== null && _f !== void 0 ? _f : existing.options, envs: (_g = updates.envs) !== null && _g !== void 0 ? _g : existing.envs });
|
|
352
413
|
this.localConfigs.set(workflowTag, updated);
|
|
353
414
|
}
|
|
415
|
+
console.log('[WorkflowService] update SUCCESS', { workflowTag, productTag });
|
|
354
416
|
}
|
|
355
417
|
/**
|
|
356
418
|
* Delete a workflow
|
|
@@ -361,11 +423,13 @@ class WorkflowService {
|
|
|
361
423
|
* ```
|
|
362
424
|
*/
|
|
363
425
|
async delete(workflowTag, productTag) {
|
|
426
|
+
console.log('[WorkflowService] delete ENTRY', { workflowTag, productTag });
|
|
364
427
|
// Delete from backend
|
|
365
428
|
const builder = await this.getProductBuilder(productTag);
|
|
366
429
|
await builder.deleteWorkflow(workflowTag);
|
|
367
430
|
// Remove from local cache
|
|
368
431
|
this.localConfigs.delete(workflowTag);
|
|
432
|
+
console.log('[WorkflowService] delete SUCCESS', { workflowTag, productTag });
|
|
369
433
|
}
|
|
370
434
|
// ==================== CODE-FIRST API ====================
|
|
371
435
|
/**
|
|
@@ -397,16 +461,22 @@ class WorkflowService {
|
|
|
397
461
|
* ```
|
|
398
462
|
*/
|
|
399
463
|
async define(options) {
|
|
464
|
+
var _a, _b;
|
|
465
|
+
console.log('[WorkflowService] define ENTRY', { tag: options.tag, name: options.name, product: options.product });
|
|
400
466
|
// Validate required fields
|
|
401
467
|
if (!options.tag || !options.name || !options.handler) {
|
|
468
|
+
console.log('[WorkflowService] define validation failed: missing tag, name, or handler');
|
|
402
469
|
throw WorkflowError.validationError('Workflow definition requires tag, name, and handler');
|
|
403
470
|
}
|
|
404
471
|
// Create a workflow compiler instance
|
|
405
472
|
const compiler = new WorkflowCompiler(options);
|
|
406
|
-
// Compile the handler to JSON schema
|
|
407
|
-
|
|
473
|
+
// Compile the handler to JSON schema (await so async handler runs and steps are captured)
|
|
474
|
+
console.log('[WorkflowService] define compiling handler (compileAsync)', { tag: options.tag });
|
|
475
|
+
const schema = await compiler.compileAsync();
|
|
476
|
+
console.log('[WorkflowService] define compiled schema', { tag: schema.tag, stepsCount: (_b = (_a = schema.steps) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0 });
|
|
408
477
|
// If product is specified, create the workflow
|
|
409
478
|
if (options.product) {
|
|
479
|
+
console.log('[WorkflowService] define creating workflow on backend', { product: options.product, tag: schema.tag });
|
|
410
480
|
await this.create(options.product, schema);
|
|
411
481
|
}
|
|
412
482
|
// Store locally
|
|
@@ -423,6 +493,7 @@ class WorkflowService {
|
|
|
423
493
|
envs: schema.envs,
|
|
424
494
|
};
|
|
425
495
|
this.localConfigs.set(schema.tag, localConfig);
|
|
496
|
+
console.log('[WorkflowService] define SUCCESS', { tag: options.tag, product: options.product });
|
|
426
497
|
// Return the defined workflow with compile method
|
|
427
498
|
return {
|
|
428
499
|
tag: options.tag,
|
|
@@ -453,41 +524,55 @@ class WorkflowService {
|
|
|
453
524
|
* ```
|
|
454
525
|
*/
|
|
455
526
|
async execute(options) {
|
|
456
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
527
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
528
|
+
console.log('[WorkflowService] execute ENTRY', { product: options.product, env: options.env, tag: options.tag, hasSession: !!options.session, cache: options.cache });
|
|
457
529
|
if (!this.config) {
|
|
530
|
+
console.log('[WorkflowService] execute failed: no config');
|
|
458
531
|
throw WorkflowError.configurationError('WorkflowService not configured. Please provide config when initializing.');
|
|
459
532
|
}
|
|
460
533
|
const process_id = (0, processor_utils_1.generateObjectId)();
|
|
534
|
+
console.log('[WorkflowService] execute process_id', { process_id });
|
|
461
535
|
// Session log fields (will be populated if session is provided)
|
|
462
536
|
let sessionLogFields = {};
|
|
463
537
|
let resolvedOptions = options;
|
|
464
538
|
// Fetch the workflow configuration from backend
|
|
465
539
|
const builder = await this.getProductBuilder(options.product);
|
|
540
|
+
console.log('[WorkflowService] execute fetching workflow', { tag: options.tag, product: options.product });
|
|
466
541
|
const workflow = await builder.fetchWorkflow(options.tag);
|
|
467
542
|
if (!workflow) {
|
|
543
|
+
console.log('[WorkflowService] execute workflow not found', { tag: options.tag });
|
|
468
544
|
throw WorkflowError.notFoundError(`Workflow ${options.tag} not found`);
|
|
469
545
|
}
|
|
546
|
+
console.log('[WorkflowService] execute workflow loaded', { tag: workflow.tag, stepsCount: (_b = (_a = workflow.steps) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0 });
|
|
470
547
|
// Process session if provided - verify and resolve $Session{} references
|
|
471
548
|
if (options.session) {
|
|
472
549
|
const privateKey = builder.fetchPrivateKey();
|
|
473
550
|
if (privateKey) {
|
|
474
551
|
const { processSessionForExecution } = await Promise.resolve().then(() => __importStar(require('../sessions')));
|
|
475
|
-
const sessionResult = await processSessionForExecution(options.session, privateKey, options, options.env
|
|
552
|
+
const sessionResult = await processSessionForExecution(options.session, privateKey, options, options.env, {
|
|
553
|
+
fetchSessionSelector: async (sessionTag) => {
|
|
554
|
+
const sessionConfig = await builder.fetchSession(sessionTag);
|
|
555
|
+
return sessionConfig === null || sessionConfig === void 0 ? void 0 : sessionConfig.selector;
|
|
556
|
+
},
|
|
557
|
+
});
|
|
476
558
|
if (sessionResult.error) {
|
|
559
|
+
console.log('[WorkflowService] execute session validation failed', { error: sessionResult.error });
|
|
477
560
|
throw WorkflowError.executionError(`Session validation failed: ${sessionResult.error}`);
|
|
478
561
|
}
|
|
479
562
|
resolvedOptions = sessionResult.input;
|
|
480
563
|
sessionLogFields = sessionResult.logFields;
|
|
564
|
+
console.log('[WorkflowService] execute session resolved', { hasLogFields: Object.keys(sessionLogFields).length > 0 });
|
|
481
565
|
}
|
|
482
566
|
}
|
|
483
567
|
// Initialize logging
|
|
484
568
|
this.initializeLogService();
|
|
485
569
|
const baseLogs = Object.assign({ product_tag: options.product, workspace_id: this.config.workspace_id, env: options.env, process_id, type: logs_types_1.LogEventTypes.WORKFLOW, parent_tag: options.tag, data: { workflow: options.tag, operation: 'execute' } }, sessionLogFields);
|
|
486
|
-
(
|
|
570
|
+
(_c = this.logService) === null || _c === void 0 ? void 0 : _c.add(Object.assign(Object.assign({}, baseLogs), { message: 'Workflow execute - initiated', status: logs_types_1.LogEventStatus.PROCESSING }));
|
|
487
571
|
const { cache } = options;
|
|
488
572
|
try {
|
|
489
573
|
// Check cache for idempotency (prevent duplicate executions with same input)
|
|
490
574
|
if (cache && this.cacheManager && this._privateKey) {
|
|
575
|
+
console.log('[WorkflowService] execute checking cache', { cache, tag: options.tag });
|
|
491
576
|
const cacheConfig = await this.validateCache(options.product, cache);
|
|
492
577
|
const cacheOptions = {
|
|
493
578
|
cache_tag: cache,
|
|
@@ -501,18 +586,21 @@ class WorkflowService {
|
|
|
501
586
|
};
|
|
502
587
|
const cached = await this.cacheManager.fetch(cacheOptions);
|
|
503
588
|
if (cached.hit && cached.data) {
|
|
504
|
-
|
|
505
|
-
(
|
|
589
|
+
console.log('[WorkflowService] execute cache HIT', { cache, source: cached.source });
|
|
590
|
+
(_d = this.logService) === null || _d === void 0 ? void 0 : _d.add(Object.assign(Object.assign({}, baseLogs), { message: `Workflow execute - cache hit (${cached.source})`, successful_execution: true, status: logs_types_1.LogEventStatus.SUCCESS, data: { workflow: options.tag, operation: 'execute', cache_source: cached.source }, cache_tag: cache, cache_key: cached.key, cache_status: true }));
|
|
591
|
+
(_e = this.logService) === null || _e === void 0 ? void 0 : _e.publish();
|
|
506
592
|
return cached.data;
|
|
507
593
|
}
|
|
508
594
|
}
|
|
509
|
-
// Create and run the workflow executor with resolved options and session context
|
|
510
|
-
|
|
595
|
+
// Create and run the workflow executor with resolved options and session context (pass builder to avoid duplicate init)
|
|
596
|
+
console.log('[WorkflowService] execute creating WorkflowExecutor and running', { tag: options.tag });
|
|
597
|
+
const executor = new workflow_executor_1.WorkflowExecutor(this.config, workflow, resolvedOptions, this._privateKey, sessionLogFields, builder);
|
|
511
598
|
const result = await executor.execute();
|
|
512
|
-
|
|
599
|
+
console.log('[WorkflowService] execute executor completed', { tag: options.tag, status: result === null || result === void 0 ? void 0 : result.status });
|
|
600
|
+
// Store in cache for idempotency (fire-and-forget)
|
|
513
601
|
if (cache && this.cacheManager && this._privateKey) {
|
|
514
602
|
const cacheConfig = await this.validateCache(options.product, cache);
|
|
515
|
-
|
|
603
|
+
this.cacheManager.store({
|
|
516
604
|
cache_tag: cache,
|
|
517
605
|
product_tag: options.product,
|
|
518
606
|
component_tag: options.tag,
|
|
@@ -523,13 +611,15 @@ class WorkflowService {
|
|
|
523
611
|
expiry: cacheConfig.expiry,
|
|
524
612
|
}, result);
|
|
525
613
|
}
|
|
526
|
-
(
|
|
527
|
-
(
|
|
614
|
+
(_f = this.logService) === null || _f === void 0 ? void 0 : _f.add(Object.assign(Object.assign({}, baseLogs), { message: 'Workflow execute - success', successful_execution: true, status: logs_types_1.LogEventStatus.SUCCESS }));
|
|
615
|
+
(_g = this.logService) === null || _g === void 0 ? void 0 : _g.publish();
|
|
616
|
+
console.log('[WorkflowService] execute SUCCESS', { tag: options.tag, process_id });
|
|
528
617
|
return result;
|
|
529
618
|
}
|
|
530
619
|
catch (error) {
|
|
531
|
-
(
|
|
532
|
-
|
|
620
|
+
console.log('[WorkflowService] execute FAILED', { tag: options.tag, process_id, error: (_h = error === null || error === void 0 ? void 0 : error.message) !== null && _h !== void 0 ? _h : error });
|
|
621
|
+
(_j = this.logService) === null || _j === void 0 ? void 0 : _j.add(Object.assign(Object.assign({}, baseLogs), { message: 'Workflow execute - failed', failed_execution: true, data: { workflow: options.tag, operation: 'execute', error: error.message || String(error) }, status: logs_types_1.LogEventStatus.FAIL }));
|
|
622
|
+
await ((_k = this.logService) === null || _k === void 0 ? void 0 : _k.publish());
|
|
533
623
|
throw error;
|
|
534
624
|
}
|
|
535
625
|
}
|
|
@@ -560,6 +650,7 @@ class WorkflowService {
|
|
|
560
650
|
*/
|
|
561
651
|
async dispatch(data) {
|
|
562
652
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
653
|
+
console.log('[WorkflowService] dispatch ENTRY', { product: data.product, env: data.env, workflow: data.workflow, schedule: !!data.schedule, session: !!data.session, cache: data.cache });
|
|
563
654
|
const process_id = (0, processor_utils_1.generateObjectId)();
|
|
564
655
|
const processorService = this.createNewProcessor();
|
|
565
656
|
const productBuilder = await this.getProductBuilder(data.product);
|
|
@@ -567,6 +658,7 @@ class WorkflowService {
|
|
|
567
658
|
const startAt = typeof schedule.start_at === 'string' ? new Date(schedule.start_at).getTime() : schedule.start_at || Date.now();
|
|
568
659
|
// Generate job tag based on workflow
|
|
569
660
|
const jobTag = `workflow:${data.workflow}`;
|
|
661
|
+
console.log('[WorkflowService] dispatch jobTag', { jobTag, startAt, cron: schedule.cron, every: schedule.every });
|
|
570
662
|
// Session log fields (will be populated if session is provided)
|
|
571
663
|
let sessionLogFields = {};
|
|
572
664
|
let resolvedData = data;
|
|
@@ -575,12 +667,19 @@ class WorkflowService {
|
|
|
575
667
|
const privateKey = productBuilder.fetchPrivateKey();
|
|
576
668
|
if (privateKey) {
|
|
577
669
|
const { processSessionForExecution } = await Promise.resolve().then(() => __importStar(require('../sessions')));
|
|
578
|
-
const sessionResult = await processSessionForExecution(data.session, privateKey, data, data.env
|
|
670
|
+
const sessionResult = await processSessionForExecution(data.session, privateKey, data, data.env, {
|
|
671
|
+
fetchSessionSelector: async (sessionTag) => {
|
|
672
|
+
const sessionConfig = await productBuilder.fetchSession(sessionTag);
|
|
673
|
+
return sessionConfig === null || sessionConfig === void 0 ? void 0 : sessionConfig.selector;
|
|
674
|
+
},
|
|
675
|
+
});
|
|
579
676
|
if (sessionResult.error) {
|
|
677
|
+
console.log('[WorkflowService] dispatch session validation failed', { error: sessionResult.error });
|
|
580
678
|
throw WorkflowError.executionError(`Session validation failed: ${sessionResult.error}`);
|
|
581
679
|
}
|
|
582
680
|
resolvedData = sessionResult.input;
|
|
583
681
|
sessionLogFields = sessionResult.logFields;
|
|
682
|
+
console.log('[WorkflowService] dispatch session resolved');
|
|
584
683
|
}
|
|
585
684
|
}
|
|
586
685
|
// Initialize logging
|
|
@@ -591,6 +690,7 @@ class WorkflowService {
|
|
|
591
690
|
try {
|
|
592
691
|
// Check cache for idempotency (prevent duplicate dispatches with same input)
|
|
593
692
|
if (cache && this.cacheManager && this._privateKey) {
|
|
693
|
+
console.log('[WorkflowService] dispatch checking cache', { cache, workflow: data.workflow });
|
|
594
694
|
const cacheConfig = await this.validateCache(data.product, cache);
|
|
595
695
|
const cacheOptions = {
|
|
596
696
|
cache_tag: cache,
|
|
@@ -604,14 +704,17 @@ class WorkflowService {
|
|
|
604
704
|
};
|
|
605
705
|
const cached = await this.cacheManager.fetch(cacheOptions);
|
|
606
706
|
if (cached.hit && cached.data) {
|
|
607
|
-
|
|
707
|
+
console.log('[WorkflowService] dispatch cache HIT', { cache, source: cached.source });
|
|
708
|
+
(_c = this.logService) === null || _c === void 0 ? void 0 : _c.add(Object.assign(Object.assign({}, baseLogs), { message: `Workflow dispatch - cache hit (${cached.source})`, successful_execution: true, status: logs_types_1.LogEventStatus.SUCCESS, data: { workflow: data.workflow, operation: 'dispatch', cache_source: cached.source }, cache_tag: cache, cache_key: cached.key, cache_status: true }));
|
|
608
709
|
(_d = this.logService) === null || _d === void 0 ? void 0 : _d.publish();
|
|
609
710
|
return cached.data;
|
|
610
711
|
}
|
|
611
712
|
}
|
|
612
713
|
// Check if job exists, if not create it
|
|
714
|
+
console.log('[WorkflowService] dispatch fetching existing job', { jobTag });
|
|
613
715
|
const existingJob = await productBuilder.fetchJob(jobTag);
|
|
614
716
|
if (!existingJob) {
|
|
717
|
+
console.log('[WorkflowService] dispatch job not found, creating', { jobTag });
|
|
615
718
|
await productBuilder.createJob({
|
|
616
719
|
tag: jobTag,
|
|
617
720
|
name: `Workflow: ${data.workflow}`,
|
|
@@ -643,8 +746,10 @@ class WorkflowService {
|
|
|
643
746
|
}
|
|
644
747
|
: undefined,
|
|
645
748
|
};
|
|
749
|
+
console.log('[WorkflowService] dispatch calling processJob', { jobTag, hasRepeat: !!(schedule.cron || schedule.every) });
|
|
646
750
|
await processorService.processJob(jobInput);
|
|
647
751
|
const isRecurring = !!(schedule.cron || schedule.every);
|
|
752
|
+
console.log('[WorkflowService] dispatch processJob completed', { isRecurring });
|
|
648
753
|
let nextRunAt;
|
|
649
754
|
if (isRecurring && schedule.every) {
|
|
650
755
|
nextRunAt = startAt + schedule.every;
|
|
@@ -657,10 +762,10 @@ class WorkflowService {
|
|
|
657
762
|
recurring: isRecurring,
|
|
658
763
|
next_run_at: nextRunAt,
|
|
659
764
|
};
|
|
660
|
-
// Store in cache for idempotency
|
|
765
|
+
// Store in cache for idempotency (fire-and-forget)
|
|
661
766
|
if (cache && this.cacheManager && this._privateKey) {
|
|
662
767
|
const cacheConfig = await this.validateCache(data.product, cache);
|
|
663
|
-
|
|
768
|
+
this.cacheManager.store({
|
|
664
769
|
cache_tag: cache,
|
|
665
770
|
product_tag: data.product,
|
|
666
771
|
component_tag: data.workflow,
|
|
@@ -673,9 +778,11 @@ class WorkflowService {
|
|
|
673
778
|
}
|
|
674
779
|
(_e = this.logService) === null || _e === void 0 ? void 0 : _e.add(Object.assign(Object.assign({}, baseLogs), { message: 'Workflow dispatch - success', successful_execution: true, data: { workflow: data.workflow, operation: 'dispatch', job_id }, status: logs_types_1.LogEventStatus.SUCCESS }));
|
|
675
780
|
(_f = this.logService) === null || _f === void 0 ? void 0 : _f.publish();
|
|
781
|
+
console.log('[WorkflowService] dispatch SUCCESS', { workflow: data.workflow, job_id: result.job_id, status: result.status });
|
|
676
782
|
return result;
|
|
677
783
|
}
|
|
678
784
|
catch (error) {
|
|
785
|
+
console.log('[WorkflowService] dispatch FAILED', { workflow: data.workflow, error: String(error) });
|
|
679
786
|
(_g = this.logService) === null || _g === void 0 ? void 0 : _g.add(Object.assign(Object.assign({}, baseLogs), { message: 'Workflow dispatch - failed', failed_execution: true, data: { workflow: data.workflow, operation: 'dispatch', error: String(error) }, status: logs_types_1.LogEventStatus.FAIL }));
|
|
680
787
|
await ((_h = this.logService) === null || _h === void 0 ? void 0 : _h.publish());
|
|
681
788
|
throw error;
|
|
@@ -698,6 +805,7 @@ class WorkflowService {
|
|
|
698
805
|
*/
|
|
699
806
|
async signal(options) {
|
|
700
807
|
var _a, _b, _c, _d, _e, _f;
|
|
808
|
+
console.log('[WorkflowService] signal ENTRY', { workflow_id: options.workflow_id, signal: options.signal, product: options.product, env: options.env });
|
|
701
809
|
const process_id = (0, processor_utils_1.generateObjectId)();
|
|
702
810
|
// Initialize logging
|
|
703
811
|
if (options.product) {
|
|
@@ -718,16 +826,19 @@ class WorkflowService {
|
|
|
718
826
|
try {
|
|
719
827
|
const apiService = this.ensureApiService();
|
|
720
828
|
const auth = this.getAuthPayload();
|
|
829
|
+
console.log('[WorkflowService] signal calling apiService.sendSignal', { workflow_id: options.workflow_id, signal: options.signal });
|
|
721
830
|
await apiService.sendSignal(options.workflow_id, {
|
|
722
831
|
product: options.product,
|
|
723
832
|
env: options.env,
|
|
724
833
|
signal: options.signal,
|
|
725
834
|
payload: options.payload,
|
|
726
835
|
}, auth);
|
|
836
|
+
console.log('[WorkflowService] signal SUCCESS', { workflow_id: options.workflow_id, signal: options.signal });
|
|
727
837
|
(_c = this.logService) === null || _c === void 0 ? void 0 : _c.add(Object.assign(Object.assign({}, baseLogs), { message: 'Workflow signal - success', successful_execution: true, status: logs_types_1.LogEventStatus.SUCCESS }));
|
|
728
838
|
(_d = this.logService) === null || _d === void 0 ? void 0 : _d.publish();
|
|
729
839
|
}
|
|
730
840
|
catch (error) {
|
|
841
|
+
console.log('[WorkflowService] signal FAILED', { workflow_id: options.workflow_id, signal: options.signal, error: String(error) });
|
|
731
842
|
(_e = this.logService) === null || _e === void 0 ? void 0 : _e.add(Object.assign(Object.assign({}, baseLogs), { message: 'Workflow signal - failed', failed_execution: true, data: { workflow_id: options.workflow_id, signal: options.signal, operation: 'signal', error: String(error) }, status: logs_types_1.LogEventStatus.FAIL }));
|
|
732
843
|
await ((_f = this.logService) === null || _f === void 0 ? void 0 : _f.publish());
|
|
733
844
|
throw error;
|
|
@@ -749,6 +860,7 @@ class WorkflowService {
|
|
|
749
860
|
* ```
|
|
750
861
|
*/
|
|
751
862
|
async query(options) {
|
|
863
|
+
console.log('[WorkflowService] query ENTRY', { workflow_id: options.workflow_id, query: options.query, product: options.product, env: options.env });
|
|
752
864
|
// Query is handled by getting workflow status and extracting query result
|
|
753
865
|
const status = await this.status({
|
|
754
866
|
product: options.product,
|
|
@@ -756,10 +868,13 @@ class WorkflowService {
|
|
|
756
868
|
workflow_id: options.workflow_id,
|
|
757
869
|
});
|
|
758
870
|
if (!status) {
|
|
871
|
+
console.log('[WorkflowService] query workflow not found', { workflow_id: options.workflow_id });
|
|
759
872
|
throw WorkflowError.notFoundError(`Workflow ${options.workflow_id} not found`);
|
|
760
873
|
}
|
|
874
|
+
const result = (status.state[options.query] || status);
|
|
875
|
+
console.log('[WorkflowService] query SUCCESS', { workflow_id: options.workflow_id, query: options.query, hasResult: result !== undefined });
|
|
761
876
|
// Return the state which contains query results
|
|
762
|
-
return
|
|
877
|
+
return result;
|
|
763
878
|
}
|
|
764
879
|
// ==================== REPLAY, RESTART & RESUME ====================
|
|
765
880
|
/**
|
|
@@ -777,8 +892,10 @@ class WorkflowService {
|
|
|
777
892
|
*/
|
|
778
893
|
async replay(options) {
|
|
779
894
|
var _a, _b, _c, _d, _e, _f;
|
|
895
|
+
console.log('[WorkflowService] replay ENTRY', { workflow_id: options.workflow_id, product: options.product, env: options.env });
|
|
780
896
|
const process_id = (0, processor_utils_1.generateObjectId)();
|
|
781
897
|
if (!this.config) {
|
|
898
|
+
console.log('[WorkflowService] replay failed: no config');
|
|
782
899
|
throw WorkflowError.configurationError('WorkflowService not configured. Please provide config when initializing.');
|
|
783
900
|
}
|
|
784
901
|
// Initialize logging
|
|
@@ -796,15 +913,19 @@ class WorkflowService {
|
|
|
796
913
|
(_b = this.logService) === null || _b === void 0 ? void 0 : _b.add(Object.assign(Object.assign({}, baseLogs), { message: 'Workflow replay - initiated', status: logs_types_1.LogEventStatus.PROCESSING }));
|
|
797
914
|
try {
|
|
798
915
|
// Get original workflow execution state from backend
|
|
916
|
+
console.log('[WorkflowService] replay fetching original status', { workflow_id: options.workflow_id });
|
|
799
917
|
const originalStatus = await this.status({
|
|
800
918
|
product: options.product,
|
|
801
919
|
env: options.env,
|
|
802
920
|
workflow_id: options.workflow_id,
|
|
803
921
|
});
|
|
804
922
|
if (!originalStatus) {
|
|
923
|
+
console.log('[WorkflowService] replay original workflow not found', { workflow_id: options.workflow_id });
|
|
805
924
|
throw WorkflowError.notFoundError(`Workflow ${options.workflow_id} not found`);
|
|
806
925
|
}
|
|
926
|
+
console.log('[WorkflowService] replay original status', { workflow_tag: originalStatus.workflow_tag, status: originalStatus.status });
|
|
807
927
|
// Execute with the same input
|
|
928
|
+
console.log('[WorkflowService] replay executing with same input', { tag: originalStatus.workflow_tag });
|
|
808
929
|
const result = await this.execute({
|
|
809
930
|
product: options.product,
|
|
810
931
|
env: options.env,
|
|
@@ -814,9 +935,11 @@ class WorkflowService {
|
|
|
814
935
|
});
|
|
815
936
|
(_c = this.logService) === null || _c === void 0 ? void 0 : _c.add(Object.assign(Object.assign({}, baseLogs), { message: 'Workflow replay - success', successful_execution: true, status: logs_types_1.LogEventStatus.SUCCESS }));
|
|
816
937
|
(_d = this.logService) === null || _d === void 0 ? void 0 : _d.publish();
|
|
938
|
+
console.log('[WorkflowService] replay SUCCESS', { workflow_id: options.workflow_id, replayed_from: options.workflow_id });
|
|
817
939
|
return Object.assign(Object.assign({}, result), { replayed_from: options.workflow_id });
|
|
818
940
|
}
|
|
819
941
|
catch (error) {
|
|
942
|
+
console.log('[WorkflowService] replay FAILED', { workflow_id: options.workflow_id, error: String(error) });
|
|
820
943
|
(_e = this.logService) === null || _e === void 0 ? void 0 : _e.add(Object.assign(Object.assign({}, baseLogs), { message: 'Workflow replay - failed', failed_execution: true, data: { workflow_id: options.workflow_id, operation: 'replay', error: String(error) }, status: logs_types_1.LogEventStatus.FAIL }));
|
|
821
944
|
await ((_f = this.logService) === null || _f === void 0 ? void 0 : _f.publish());
|
|
822
945
|
throw error;
|
|
@@ -837,7 +960,9 @@ class WorkflowService {
|
|
|
837
960
|
* ```
|
|
838
961
|
*/
|
|
839
962
|
async restart(options) {
|
|
963
|
+
console.log('[WorkflowService] restart ENTRY', { workflow_id: options.workflow_id, product: options.product, env: options.env, hasInput: !!options.input });
|
|
840
964
|
if (!this.config) {
|
|
965
|
+
console.log('[WorkflowService] restart failed: no config');
|
|
841
966
|
throw WorkflowError.configurationError('WorkflowService not configured. Please provide config when initializing.');
|
|
842
967
|
}
|
|
843
968
|
// Get original workflow execution state from backend
|
|
@@ -847,8 +972,10 @@ class WorkflowService {
|
|
|
847
972
|
workflow_id: options.workflow_id,
|
|
848
973
|
});
|
|
849
974
|
if (!originalStatus) {
|
|
975
|
+
console.log('[WorkflowService] restart workflow not found', { workflow_id: options.workflow_id });
|
|
850
976
|
throw WorkflowError.notFoundError(`Workflow ${options.workflow_id} not found`);
|
|
851
977
|
}
|
|
978
|
+
console.log('[WorkflowService] restart original status', { workflow_tag: originalStatus.workflow_tag });
|
|
852
979
|
// Determine the new input
|
|
853
980
|
let newInput;
|
|
854
981
|
if (options.input) {
|
|
@@ -864,12 +991,14 @@ class WorkflowService {
|
|
|
864
991
|
newInput = originalStatus.input || {};
|
|
865
992
|
}
|
|
866
993
|
// Execute with the new input
|
|
994
|
+
console.log('[WorkflowService] restart executing with new input', { tag: originalStatus.workflow_tag, inputKeys: Object.keys(newInput || {}) });
|
|
867
995
|
const result = await this.execute({
|
|
868
996
|
product: options.product,
|
|
869
997
|
env: options.env,
|
|
870
998
|
tag: originalStatus.workflow_tag,
|
|
871
999
|
input: newInput,
|
|
872
1000
|
});
|
|
1001
|
+
console.log('[WorkflowService] restart SUCCESS', { workflow_id: options.workflow_id, restarted_from: options.workflow_id });
|
|
873
1002
|
return Object.assign(Object.assign({}, result), { restarted_from: options.workflow_id });
|
|
874
1003
|
}
|
|
875
1004
|
/**
|
|
@@ -886,7 +1015,10 @@ class WorkflowService {
|
|
|
886
1015
|
* ```
|
|
887
1016
|
*/
|
|
888
1017
|
async resume(options) {
|
|
1018
|
+
var _a, _b;
|
|
1019
|
+
console.log('[WorkflowService] resume ENTRY', { workflow_id: options.workflow_id, product: options.product, env: options.env, from_checkpoint: options.from_checkpoint, from_step: options.from_step });
|
|
889
1020
|
if (!this.config) {
|
|
1021
|
+
console.log('[WorkflowService] resume failed: no config');
|
|
890
1022
|
throw WorkflowError.configurationError('WorkflowService not configured. Please provide config when initializing.');
|
|
891
1023
|
}
|
|
892
1024
|
// Get original workflow execution state from backend
|
|
@@ -896,15 +1028,19 @@ class WorkflowService {
|
|
|
896
1028
|
workflow_id: options.workflow_id,
|
|
897
1029
|
});
|
|
898
1030
|
if (!originalStatus) {
|
|
1031
|
+
console.log('[WorkflowService] resume workflow not found', { workflow_id: options.workflow_id });
|
|
899
1032
|
throw WorkflowError.notFoundError(`Workflow ${options.workflow_id} not found`);
|
|
900
1033
|
}
|
|
1034
|
+
console.log('[WorkflowService] resume original status', { workflow_tag: originalStatus.workflow_tag, completed_steps: (_b = (_a = originalStatus.completed_steps) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0 });
|
|
901
1035
|
// Fetch the workflow configuration
|
|
902
1036
|
const builder = await this.getProductBuilder(options.product);
|
|
903
1037
|
const workflow = await builder.fetchWorkflow(originalStatus.workflow_tag);
|
|
904
1038
|
if (!workflow) {
|
|
1039
|
+
console.log('[WorkflowService] resume workflow config not found', { tag: originalStatus.workflow_tag });
|
|
905
1040
|
throw WorkflowError.notFoundError(`Workflow ${originalStatus.workflow_tag} not found`);
|
|
906
1041
|
}
|
|
907
1042
|
// Create executor with resume options
|
|
1043
|
+
console.log('[WorkflowService] resume creating executor and resuming', { tag: workflow.tag });
|
|
908
1044
|
const executor = new workflow_executor_1.WorkflowExecutor(this.config, workflow, {
|
|
909
1045
|
product: options.product,
|
|
910
1046
|
env: options.env,
|
|
@@ -919,6 +1055,7 @@ class WorkflowService {
|
|
|
919
1055
|
from_step: options.from_step,
|
|
920
1056
|
skip_steps: options.skip_steps,
|
|
921
1057
|
});
|
|
1058
|
+
console.log('[WorkflowService] resume SUCCESS', { workflow_id: options.workflow_id, resumed_from: options.workflow_id });
|
|
922
1059
|
return Object.assign(Object.assign({}, result), { resumed_from: options.workflow_id, resumed_checkpoint: options.from_checkpoint });
|
|
923
1060
|
}
|
|
924
1061
|
/**
|
|
@@ -935,7 +1072,9 @@ class WorkflowService {
|
|
|
935
1072
|
* ```
|
|
936
1073
|
*/
|
|
937
1074
|
async replayFromStep(options) {
|
|
1075
|
+
console.log('[WorkflowService] replayFromStep ENTRY', { workflow_id: options.workflow_id, from_step: options.from_step, product: options.product, env: options.env });
|
|
938
1076
|
if (!this.config) {
|
|
1077
|
+
console.log('[WorkflowService] replayFromStep failed: no config');
|
|
939
1078
|
throw WorkflowError.configurationError('WorkflowService not configured. Please provide config when initializing.');
|
|
940
1079
|
}
|
|
941
1080
|
// Get original workflow execution state
|
|
@@ -945,20 +1084,24 @@ class WorkflowService {
|
|
|
945
1084
|
workflow_id: options.workflow_id,
|
|
946
1085
|
});
|
|
947
1086
|
if (!originalStatus) {
|
|
1087
|
+
console.log('[WorkflowService] replayFromStep workflow not found', { workflow_id: options.workflow_id });
|
|
948
1088
|
throw WorkflowError.notFoundError(`Workflow ${options.workflow_id} not found`);
|
|
949
1089
|
}
|
|
950
1090
|
// Fetch the workflow configuration
|
|
951
1091
|
const builder = await this.getProductBuilder(options.product);
|
|
952
1092
|
const workflow = await builder.fetchWorkflow(originalStatus.workflow_tag);
|
|
953
1093
|
if (!workflow) {
|
|
1094
|
+
console.log('[WorkflowService] replayFromStep workflow config not found', { tag: originalStatus.workflow_tag });
|
|
954
1095
|
throw WorkflowError.notFoundError(`Workflow ${originalStatus.workflow_tag} not found`);
|
|
955
1096
|
}
|
|
956
1097
|
// Find steps before from_step to mark as completed
|
|
957
1098
|
const stepIndex = workflow.steps.findIndex((s) => s.tag === options.from_step);
|
|
958
1099
|
if (stepIndex === -1) {
|
|
1100
|
+
console.log('[WorkflowService] replayFromStep step not found', { from_step: options.from_step });
|
|
959
1101
|
throw WorkflowError.validationError(`Step ${options.from_step} not found in workflow`);
|
|
960
1102
|
}
|
|
961
1103
|
const completedSteps = workflow.steps.slice(0, stepIndex).map((s) => s.tag);
|
|
1104
|
+
console.log('[WorkflowService] replayFromStep stepIndex and completedSteps', { from_step: options.from_step, stepIndex, completedStepsCount: completedSteps.length });
|
|
962
1105
|
// Create executor with partial state
|
|
963
1106
|
const executor = new workflow_executor_1.WorkflowExecutor(this.config, workflow, {
|
|
964
1107
|
product: options.product,
|
|
@@ -972,6 +1115,7 @@ class WorkflowService {
|
|
|
972
1115
|
state: originalStatus.state,
|
|
973
1116
|
step_outputs: options.step_outputs,
|
|
974
1117
|
});
|
|
1118
|
+
console.log('[WorkflowService] replayFromStep SUCCESS', { workflow_id: options.workflow_id, from_step: options.from_step });
|
|
975
1119
|
return Object.assign(Object.assign({}, result), { replayed_from: options.workflow_id });
|
|
976
1120
|
}
|
|
977
1121
|
// ==================== STATUS & MANAGEMENT ====================
|
|
@@ -988,12 +1132,15 @@ class WorkflowService {
|
|
|
988
1132
|
* ```
|
|
989
1133
|
*/
|
|
990
1134
|
async status(options) {
|
|
1135
|
+
console.log('[WorkflowService] status ENTRY', { workflow_id: options.workflow_id, product: options.product, env: options.env });
|
|
991
1136
|
const apiService = this.ensureApiService();
|
|
992
1137
|
const auth = this.getAuthPayload();
|
|
993
1138
|
const response = await apiService.getStatus(options.workflow_id, options.product, options.env, auth);
|
|
994
1139
|
if (!response) {
|
|
1140
|
+
console.log('[WorkflowService] status not found', { workflow_id: options.workflow_id });
|
|
995
1141
|
return null;
|
|
996
1142
|
}
|
|
1143
|
+
console.log('[WorkflowService] status SUCCESS', { workflow_id: response.workflow_id, workflow_tag: response.workflow_tag, status: response.status });
|
|
997
1144
|
return {
|
|
998
1145
|
workflow_id: response.workflow_id,
|
|
999
1146
|
workflow_tag: response.workflow_tag,
|
|
@@ -1022,9 +1169,22 @@ class WorkflowService {
|
|
|
1022
1169
|
* ```
|
|
1023
1170
|
*/
|
|
1024
1171
|
async cancel(options) {
|
|
1172
|
+
var _a, _b, _c, _d;
|
|
1173
|
+
console.log('[WorkflowService] cancel ENTRY', {
|
|
1174
|
+
workflow_id: options.workflow_id,
|
|
1175
|
+
product: options.product,
|
|
1176
|
+
env: options.env,
|
|
1177
|
+
reason: options.reason,
|
|
1178
|
+
});
|
|
1025
1179
|
const apiService = this.ensureApiService();
|
|
1026
1180
|
const auth = this.getAuthPayload();
|
|
1027
1181
|
const response = await apiService.cancel(options.workflow_id, options.product, options.env, options.reason || 'Cancelled by user', auth);
|
|
1182
|
+
console.log('[WorkflowService] cancel SUCCESS', {
|
|
1183
|
+
workflow_id: options.workflow_id,
|
|
1184
|
+
cancelled: response.cancelled,
|
|
1185
|
+
rolled_back_count: (_b = (_a = response.rolled_back_steps) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0,
|
|
1186
|
+
failed_rollbacks_count: (_d = (_c = response.failed_rollbacks) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0,
|
|
1187
|
+
});
|
|
1028
1188
|
return {
|
|
1029
1189
|
cancelled: response.cancelled,
|
|
1030
1190
|
rolled_back_steps: response.rolled_back_steps,
|
|
@@ -1044,9 +1204,12 @@ class WorkflowService {
|
|
|
1044
1204
|
* ```
|
|
1045
1205
|
*/
|
|
1046
1206
|
async history(options) {
|
|
1207
|
+
var _a, _b, _c, _d;
|
|
1208
|
+
console.log('[WorkflowService] history ENTRY', { workflow_id: options.workflow_id, product: options.product, env: options.env });
|
|
1047
1209
|
const apiService = this.ensureApiService();
|
|
1048
1210
|
const auth = this.getAuthPayload();
|
|
1049
1211
|
const response = await apiService.getHistory(options.workflow_id, options.product, options.env, auth);
|
|
1212
|
+
console.log('[WorkflowService] history SUCCESS', { workflow_id: response.workflow_id, eventsCount: (_b = (_a = response.events) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0, checkpointsCount: (_d = (_c = response.checkpoints) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0 });
|
|
1050
1213
|
return {
|
|
1051
1214
|
workflow_id: response.workflow_id,
|
|
1052
1215
|
workflow_tag: response.workflow_tag,
|
|
@@ -1075,12 +1238,15 @@ class WorkflowService {
|
|
|
1075
1238
|
* ```
|
|
1076
1239
|
*/
|
|
1077
1240
|
async stepDetail(options) {
|
|
1241
|
+
console.log('[WorkflowService] stepDetail ENTRY', { workflow_id: options.workflow_id, step_tag: options.step_tag, product: options.product, env: options.env });
|
|
1078
1242
|
const apiService = this.ensureApiService();
|
|
1079
1243
|
const auth = this.getAuthPayload();
|
|
1080
1244
|
const response = await apiService.getStepDetail(options.workflow_id, options.step_tag, options.product, options.env, auth);
|
|
1081
1245
|
if (!response) {
|
|
1246
|
+
console.log('[WorkflowService] stepDetail not found', { workflow_id: options.workflow_id, step_tag: options.step_tag });
|
|
1082
1247
|
return null;
|
|
1083
1248
|
}
|
|
1249
|
+
console.log('[WorkflowService] stepDetail SUCCESS', { workflow_id: options.workflow_id, step_tag: response.tag, status: response.status });
|
|
1084
1250
|
return {
|
|
1085
1251
|
tag: response.tag,
|
|
1086
1252
|
name: response.name,
|
|
@@ -1109,9 +1275,12 @@ class WorkflowService {
|
|
|
1109
1275
|
* ```
|
|
1110
1276
|
*/
|
|
1111
1277
|
async relatedExecutions(options) {
|
|
1278
|
+
var _a, _b;
|
|
1279
|
+
console.log('[WorkflowService] relatedExecutions ENTRY', { workflow_id: options.workflow_id, product: options.product, env: options.env });
|
|
1112
1280
|
const apiService = this.ensureApiService();
|
|
1113
1281
|
const auth = this.getAuthPayload();
|
|
1114
1282
|
const response = await apiService.getRelatedExecutions(options.workflow_id, options.product, options.env, auth);
|
|
1283
|
+
console.log('[WorkflowService] relatedExecutions SUCCESS', { workflow_id: options.workflow_id, executionsCount: (_b = (_a = response.executions) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0 });
|
|
1115
1284
|
return {
|
|
1116
1285
|
original: response.original,
|
|
1117
1286
|
executions: response.executions.map((e) => ({
|
|
@@ -1138,9 +1307,11 @@ class WorkflowService {
|
|
|
1138
1307
|
* ```
|
|
1139
1308
|
*/
|
|
1140
1309
|
async compare(options) {
|
|
1310
|
+
console.log('[WorkflowService] compare ENTRY', { workflow_ids: options.workflow_ids, product: options.product, env: options.env });
|
|
1141
1311
|
const apiService = this.ensureApiService();
|
|
1142
1312
|
const auth = this.getAuthPayload();
|
|
1143
1313
|
const response = await apiService.compareExecutions(options.workflow_ids, options.product, options.env, auth);
|
|
1314
|
+
console.log('[WorkflowService] compare SUCCESS', { workflow_ids: response.workflows });
|
|
1144
1315
|
return {
|
|
1145
1316
|
workflows: response.workflows,
|
|
1146
1317
|
input_diff: response.input_diff,
|
|
@@ -1169,21 +1340,198 @@ class WorkflowService {
|
|
|
1169
1340
|
}
|
|
1170
1341
|
exports.WorkflowService = WorkflowService;
|
|
1171
1342
|
// ==================== WORKFLOW COMPILER ====================
|
|
1343
|
+
/** Symbol to detect workflow input proxy when serializing step input to operator strings */
|
|
1344
|
+
const INPUT_PROXY_SYMBOL = Symbol.for('RecordingContext.inputProxy');
|
|
1345
|
+
/** Symbol to detect step result proxy (values are already operator strings) */
|
|
1346
|
+
const STEP_RESULT_PROXY_SYMBOL = Symbol.for('RecordingContext.stepResultProxy');
|
|
1347
|
+
/** Symbol on step result proxy to get the operator string (for nested result paths) */
|
|
1348
|
+
const STEP_RESULT_REF_STRING = Symbol.for('RecordingContext.stepResultRefString');
|
|
1349
|
+
/**
|
|
1350
|
+
* Create a proxy for ctx.input so that ctx.input.field compiles to $Input{field}.
|
|
1351
|
+
* When the whole proxy is used as a value (e.g. body: ctx.input), it is replaced
|
|
1352
|
+
* with an object of $Input{key} for each key in the workflow input schema.
|
|
1353
|
+
*/
|
|
1354
|
+
function createInputProxy(schemaKeys) {
|
|
1355
|
+
const refs = Object.fromEntries(schemaKeys.map((k) => [k, `$Input{${k}}`]));
|
|
1356
|
+
const proxy = new Proxy(refs, {
|
|
1357
|
+
get(target, prop) {
|
|
1358
|
+
if (prop === INPUT_PROXY_SYMBOL)
|
|
1359
|
+
return true;
|
|
1360
|
+
if (typeof prop === 'string' && prop in target)
|
|
1361
|
+
return target[prop];
|
|
1362
|
+
return `$Input{${String(prop)}}`;
|
|
1363
|
+
},
|
|
1364
|
+
});
|
|
1365
|
+
proxy[INPUT_PROXY_SYMBOL] = true;
|
|
1366
|
+
return proxy;
|
|
1367
|
+
}
|
|
1172
1368
|
/**
|
|
1173
|
-
*
|
|
1369
|
+
* Create a proxy for a step result so that result.field compiles to $Sequence{main}{stepTag}{field}.
|
|
1370
|
+
* Supports nested paths: result.data.nested.foo → $Sequence{main}{stepTag}{data.nested.foo}.
|
|
1371
|
+
* When a property is read, recordUsage(stepTag) is called so depends_on can be inferred.
|
|
1174
1372
|
*/
|
|
1373
|
+
function createStepResultProxy(workflowTag, stepTag, pathPrefix = '', recordUsage) {
|
|
1374
|
+
const refString = pathPrefix ? `$Sequence{main}{${stepTag}}{${pathPrefix}}` : undefined;
|
|
1375
|
+
return new Proxy({}, {
|
|
1376
|
+
get(_, prop) {
|
|
1377
|
+
if (prop === STEP_RESULT_PROXY_SYMBOL)
|
|
1378
|
+
return true;
|
|
1379
|
+
if (prop === STEP_RESULT_REF_STRING)
|
|
1380
|
+
return refString;
|
|
1381
|
+
// So template literals like `${paymentResult.transactionId}` get the operator string
|
|
1382
|
+
if (prop === Symbol.toPrimitive) {
|
|
1383
|
+
return (hint) => (hint === 'string' && refString ? refString : undefined);
|
|
1384
|
+
}
|
|
1385
|
+
if (prop === 'toString' || prop === 'valueOf') {
|
|
1386
|
+
return () => refString !== null && refString !== void 0 ? refString : '';
|
|
1387
|
+
}
|
|
1388
|
+
if (typeof prop === 'string') {
|
|
1389
|
+
recordUsage === null || recordUsage === void 0 ? void 0 : recordUsage(stepTag);
|
|
1390
|
+
}
|
|
1391
|
+
const fullPath = pathPrefix ? `${pathPrefix}.${String(prop)}` : String(prop);
|
|
1392
|
+
return createStepResultProxy(workflowTag, stepTag, fullPath, recordUsage);
|
|
1393
|
+
},
|
|
1394
|
+
});
|
|
1395
|
+
}
|
|
1396
|
+
/**
|
|
1397
|
+
* Recursively convert recorded step input to operator strings per Ductape operator docs.
|
|
1398
|
+
* - Replaces input-proxy values with { key: '$Input{key}', ... } for all workflow input keys.
|
|
1399
|
+
* - Leaves values that are already operator strings (e.g. from step result proxy) as-is.
|
|
1400
|
+
* - Strings containing operator refs ($Input{...}, $Sequence{main}{...}{...}, $Now) are converted to $Concat([...], "").
|
|
1401
|
+
* - Default delimiter is "" so template literals like `receipts/${ctx.input.orderId}.txt` become receipts/ORD-001.txt not receipts/ ORD-001 .txt.
|
|
1402
|
+
* - Recurses into plain objects and arrays; leaves other primitives unchanged.
|
|
1403
|
+
*/
|
|
1404
|
+
const OPERATOR_REF_IN_STRING_REGEX = /(\$Input\{[^}]+\}|\$Sequence\{main\}\{[^}]+\}\{[^}]*\}|\$Now)/g;
|
|
1405
|
+
function convertStringToConcatIfOperatorRefs(str, delimiter = '') {
|
|
1406
|
+
OPERATOR_REF_IN_STRING_REGEX.lastIndex = 0;
|
|
1407
|
+
const tokens = str.split(OPERATOR_REF_IN_STRING_REGEX);
|
|
1408
|
+
const parts = [];
|
|
1409
|
+
for (const t of tokens) {
|
|
1410
|
+
if (!t)
|
|
1411
|
+
continue;
|
|
1412
|
+
const isOp = t.startsWith('$Input{') || t.startsWith('$Sequence{') || t === '$Now';
|
|
1413
|
+
if (isOp) {
|
|
1414
|
+
parts.push(t);
|
|
1415
|
+
}
|
|
1416
|
+
else {
|
|
1417
|
+
const trimmed = t.trim();
|
|
1418
|
+
if (trimmed.length > 0)
|
|
1419
|
+
parts.push(trimmed);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
if (parts.length <= 1)
|
|
1423
|
+
return str;
|
|
1424
|
+
return `$Concat([${parts.map((s) => (s.startsWith('$') ? s : JSON.stringify(s))).join(', ')}], "${delimiter.replace(/"/g, '\\"')}")`;
|
|
1425
|
+
}
|
|
1426
|
+
function convertToOperatorInput(value, inputProxy, schemaKeys) {
|
|
1427
|
+
if (value === null || value === undefined)
|
|
1428
|
+
return value;
|
|
1429
|
+
if (inputProxy && value === inputProxy) {
|
|
1430
|
+
return Object.fromEntries(schemaKeys.map((k) => [k, `$Input{${k}}`]));
|
|
1431
|
+
}
|
|
1432
|
+
const v = value;
|
|
1433
|
+
if (typeof v === 'object' && v !== null && v[INPUT_PROXY_SYMBOL] === true) {
|
|
1434
|
+
return Object.fromEntries(schemaKeys.map((k) => [k, `$Input{${k}}`]));
|
|
1435
|
+
}
|
|
1436
|
+
// Step result proxy (including nested result.data.foo) exposes operator string via STEP_RESULT_REF_STRING
|
|
1437
|
+
if (typeof v === 'object' && v !== null && typeof v[STEP_RESULT_REF_STRING] === 'string') {
|
|
1438
|
+
return v[STEP_RESULT_REF_STRING];
|
|
1439
|
+
}
|
|
1440
|
+
if (Array.isArray(value)) {
|
|
1441
|
+
return value.map((item) => convertToOperatorInput(item, inputProxy, schemaKeys));
|
|
1442
|
+
}
|
|
1443
|
+
if (typeof value === 'object' && value !== null && !(value instanceof Date)) {
|
|
1444
|
+
const out = {};
|
|
1445
|
+
for (const key of Object.keys(value)) {
|
|
1446
|
+
out[key] = convertToOperatorInput(value[key], inputProxy, schemaKeys);
|
|
1447
|
+
}
|
|
1448
|
+
return out;
|
|
1449
|
+
}
|
|
1450
|
+
if (typeof value === 'string') {
|
|
1451
|
+
return convertStringToConcatIfOperatorRefs(value);
|
|
1452
|
+
}
|
|
1453
|
+
return value;
|
|
1454
|
+
}
|
|
1455
|
+
/**
|
|
1456
|
+
* Recording context that captures step definitions during handler execution.
|
|
1457
|
+
* Uses operator strings ($Input{field}, $Sequence{main}{stepTag}{field}) per Ductape operator docs.
|
|
1458
|
+
*/
|
|
1459
|
+
/** Build a step condition from a branch override so the step only runs when the overridden step's output matches (e.g. $Step{validate}{valid} == true). */
|
|
1460
|
+
function buildConditionFromOverride(stepTag, override) {
|
|
1461
|
+
if (override === null || override === undefined)
|
|
1462
|
+
return '';
|
|
1463
|
+
if (typeof override !== 'object' || Array.isArray(override)) {
|
|
1464
|
+
return `$Step{${stepTag}}{value} == ${JSON.stringify(override)}`;
|
|
1465
|
+
}
|
|
1466
|
+
const parts = [];
|
|
1467
|
+
for (const [key, val] of Object.entries(override)) {
|
|
1468
|
+
if (typeof val !== 'object' || val === null || Array.isArray(val)) {
|
|
1469
|
+
parts.push(`$Step{${stepTag}}{${key}} == ${JSON.stringify(val)}`);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
return parts.length === 0 ? '' : parts.join(' && ');
|
|
1473
|
+
}
|
|
1474
|
+
/** Build a step condition from a scenario (recordInput) so the step only runs when workflow input matches (e.g. $Input{type} == 'a'). */
|
|
1475
|
+
function buildConditionFromScenario(scenario) {
|
|
1476
|
+
const parts = [];
|
|
1477
|
+
for (const [key, val] of Object.entries(scenario)) {
|
|
1478
|
+
if (val !== undefined && (typeof val !== 'object' || val === null || Array.isArray(val))) {
|
|
1479
|
+
parts.push(`$Input{${key}} == ${JSON.stringify(val)}`);
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
return parts.length === 0 ? '' : parts.join(' && ');
|
|
1483
|
+
}
|
|
1484
|
+
/** Create ctx.input that prefers recordInput values (for loops/switch) and falls back to $Input{field} for other keys. */
|
|
1485
|
+
function createHybridInputProxy(recordInput, inputProxy) {
|
|
1486
|
+
const base = recordInput !== null && recordInput !== void 0 ? recordInput : {};
|
|
1487
|
+
if (!inputProxy)
|
|
1488
|
+
return base;
|
|
1489
|
+
return new Proxy(base, {
|
|
1490
|
+
get(target, prop) {
|
|
1491
|
+
if (typeof prop !== 'string')
|
|
1492
|
+
return target[prop];
|
|
1493
|
+
if (prop in target && target[prop] !== undefined) {
|
|
1494
|
+
return target[prop];
|
|
1495
|
+
}
|
|
1496
|
+
return inputProxy[prop];
|
|
1497
|
+
},
|
|
1498
|
+
has(target, prop) {
|
|
1499
|
+
return prop in target || (inputProxy && prop in inputProxy);
|
|
1500
|
+
},
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1175
1503
|
class RecordingContext {
|
|
1176
|
-
constructor(_input,
|
|
1177
|
-
this._input = _input;
|
|
1178
|
-
this._workflowTag = _workflowTag;
|
|
1504
|
+
constructor(_input, workflowTag, workflowInputSchema, stepResultOverrides, scenarioCondition, recordInput) {
|
|
1179
1505
|
this._steps = [];
|
|
1180
1506
|
this._stepOrder = 0;
|
|
1181
1507
|
this._currentStepTag = null;
|
|
1508
|
+
/** Step being built for the current ctx.step() call; updated in place by _updateCurrentStep so we emit one step per ctx.step(). */
|
|
1509
|
+
this._pendingStep = null;
|
|
1182
1510
|
this._pendingRollback = null;
|
|
1511
|
+
this._inputProxy = null;
|
|
1512
|
+
/** Step tags whose result was read during the current step (for inferring depends_on) */
|
|
1513
|
+
this._stepResultDependencies = new Set();
|
|
1514
|
+
/** When set, the next step we push gets this condition (from a prior step's branch override). */
|
|
1515
|
+
this._pendingConditionFromOverride = null;
|
|
1516
|
+
this._stepResultOverrides = {};
|
|
1517
|
+
/** When set (from recordScenarios), every step we push gets this condition so it only runs when input matches. */
|
|
1518
|
+
this._scenarioCondition = null;
|
|
1519
|
+
this._recordInput = null;
|
|
1520
|
+
this._hybridInput = null;
|
|
1521
|
+
this._workflowTag = workflowTag;
|
|
1522
|
+
this._inputSchemaKeys = workflowInputSchema ? Object.keys(workflowInputSchema) : [];
|
|
1523
|
+
this._stepResultOverrides = stepResultOverrides !== null && stepResultOverrides !== void 0 ? stepResultOverrides : {};
|
|
1524
|
+
this._scenarioCondition = scenarioCondition !== null && scenarioCondition !== void 0 ? scenarioCondition : null;
|
|
1525
|
+
this._recordInput = recordInput !== null && recordInput !== void 0 ? recordInput : null;
|
|
1526
|
+
if (this._inputSchemaKeys.length > 0) {
|
|
1527
|
+
this._inputProxy = createInputProxy(this._inputSchemaKeys);
|
|
1528
|
+
}
|
|
1529
|
+
this._hybridInput = createHybridInputProxy(this._recordInput, this._inputProxy);
|
|
1183
1530
|
}
|
|
1184
|
-
// Readonly workflow metadata
|
|
1531
|
+
// Readonly workflow metadata — prefer recordInput for control flow (loops, switch), fall back to $Input{field}
|
|
1185
1532
|
get input() {
|
|
1186
|
-
|
|
1533
|
+
var _a, _b;
|
|
1534
|
+
return ((_b = (_a = this._hybridInput) !== null && _a !== void 0 ? _a : this._inputProxy) !== null && _b !== void 0 ? _b : {});
|
|
1187
1535
|
}
|
|
1188
1536
|
get workflow_id() {
|
|
1189
1537
|
return `compile-${this._workflowTag}`;
|
|
@@ -1212,39 +1560,86 @@ class RecordingContext {
|
|
|
1212
1560
|
get current_step() {
|
|
1213
1561
|
return this._currentStepTag;
|
|
1214
1562
|
}
|
|
1563
|
+
/** At record time returns "$Now" so template literals like `at ${ctx.now()}` compile to $Concat(..., "$Now"). */
|
|
1564
|
+
get now() {
|
|
1565
|
+
return '$Now';
|
|
1566
|
+
}
|
|
1215
1567
|
/**
|
|
1216
1568
|
* Record a step definition
|
|
1217
1569
|
*/
|
|
1218
1570
|
async step(tag, handler, rollback, options) {
|
|
1219
1571
|
this._currentStepTag = tag;
|
|
1220
1572
|
this._stepOrder++;
|
|
1221
|
-
|
|
1573
|
+
this._stepResultDependencies = new Set();
|
|
1574
|
+
// Create step placeholder - will be updated in place by component calls (_updateCurrentStep)
|
|
1222
1575
|
const step = {
|
|
1223
1576
|
tag,
|
|
1577
|
+
name: tag,
|
|
1224
1578
|
type: productsBuilder_types_1.WorkflowStepType.ACTION,
|
|
1225
1579
|
event: '',
|
|
1226
1580
|
input: {},
|
|
1227
1581
|
options,
|
|
1228
1582
|
};
|
|
1229
|
-
|
|
1583
|
+
this._pendingStep = step;
|
|
1584
|
+
// Execute handler to capture component calls and step return value
|
|
1585
|
+
let stepReturn;
|
|
1230
1586
|
try {
|
|
1231
|
-
await handler();
|
|
1587
|
+
stepReturn = await handler();
|
|
1232
1588
|
}
|
|
1233
1589
|
catch (e) {
|
|
1234
1590
|
// Ignore errors during compilation - we're just tracing
|
|
1235
1591
|
}
|
|
1592
|
+
this._pendingStep = null;
|
|
1593
|
+
// Parse and store step output in schema (operator strings for downstream $Step{tag}{field} references)
|
|
1594
|
+
const valueToCapture = stepReturn !== undefined && stepReturn !== null && typeof stepReturn === 'object' && !Array.isArray(stepReturn)
|
|
1595
|
+
? stepReturn.output !== undefined && stepReturn.process_id !== undefined
|
|
1596
|
+
? stepReturn.output
|
|
1597
|
+
: stepReturn
|
|
1598
|
+
: stepReturn;
|
|
1599
|
+
if (valueToCapture !== undefined && valueToCapture !== null && typeof valueToCapture === 'object' && !Array.isArray(valueToCapture)) {
|
|
1600
|
+
step.output = convertToOperatorInput(valueToCapture, this._inputProxy, this._inputSchemaKeys);
|
|
1601
|
+
}
|
|
1602
|
+
else if (valueToCapture !== undefined && valueToCapture !== null) {
|
|
1603
|
+
step.output = { value: convertToOperatorInput(valueToCapture, this._inputProxy, this._inputSchemaKeys) };
|
|
1604
|
+
}
|
|
1605
|
+
else {
|
|
1606
|
+
step.output = {};
|
|
1607
|
+
}
|
|
1236
1608
|
// If rollback was provided, try to capture it
|
|
1237
1609
|
if (rollback && this._pendingRollback) {
|
|
1238
1610
|
step.rollback = this._pendingRollback;
|
|
1239
1611
|
this._pendingRollback = null;
|
|
1240
1612
|
}
|
|
1241
|
-
//
|
|
1242
|
-
if (step.event) {
|
|
1243
|
-
|
|
1613
|
+
// Always add the step (even when no component was called — e.g. validate-order that only returns)
|
|
1614
|
+
if (!step.event) {
|
|
1615
|
+
step.event = step.tag;
|
|
1616
|
+
}
|
|
1617
|
+
if (this._stepResultDependencies.size > 0) {
|
|
1618
|
+
step.depends_on = Array.from(this._stepResultDependencies);
|
|
1619
|
+
}
|
|
1620
|
+
// Apply conditions: scenario (e.g. $Input{type} == 'a') and/or branch override (e.g. $Step{validate}{valid} == true)
|
|
1621
|
+
const condParts = [];
|
|
1622
|
+
if (this._scenarioCondition)
|
|
1623
|
+
condParts.push(`(${this._scenarioCondition})`);
|
|
1624
|
+
if (this._pendingConditionFromOverride) {
|
|
1625
|
+
condParts.push(`(${this._pendingConditionFromOverride})`);
|
|
1626
|
+
this._pendingConditionFromOverride = null;
|
|
1244
1627
|
}
|
|
1628
|
+
if (condParts.length > 0)
|
|
1629
|
+
step.condition = condParts.join(' && ');
|
|
1630
|
+
const overrideForThisStep = this._stepResultOverrides[tag];
|
|
1631
|
+
if (overrideForThisStep !== undefined) {
|
|
1632
|
+
this._pendingConditionFromOverride = buildConditionFromOverride(tag, overrideForThisStep);
|
|
1633
|
+
}
|
|
1634
|
+
this._steps.push(step);
|
|
1245
1635
|
this._currentStepTag = null;
|
|
1246
|
-
//
|
|
1247
|
-
|
|
1636
|
+
// When branchOverrides[tag] is set, return it so the handler continues past if (!result.x) return (records both branches)
|
|
1637
|
+
if (overrideForThisStep !== undefined) {
|
|
1638
|
+
return overrideForThisStep;
|
|
1639
|
+
}
|
|
1640
|
+
// Return step-result proxy so result.field compiles to $Sequence{main}{stepTag}{field}
|
|
1641
|
+
const recordUsage = (depTag) => this._stepResultDependencies.add(depTag);
|
|
1642
|
+
return createStepResultProxy(this._workflowTag, step.tag, '', recordUsage);
|
|
1248
1643
|
}
|
|
1249
1644
|
// ==================== COMPONENT CONTEXTS ====================
|
|
1250
1645
|
get action() {
|
|
@@ -1256,7 +1651,6 @@ class RecordingContext {
|
|
|
1256
1651
|
options: { retries: options.retries, timeout: options.timeout },
|
|
1257
1652
|
});
|
|
1258
1653
|
return {};
|
|
1259
|
-
return {};
|
|
1260
1654
|
},
|
|
1261
1655
|
};
|
|
1262
1656
|
}
|
|
@@ -1280,21 +1674,21 @@ class RecordingContext {
|
|
|
1280
1674
|
insert: async (options) => {
|
|
1281
1675
|
this._updateCurrentStep(productsBuilder_types_1.WorkflowStepType.DATABASE_ACTION, options.event, {
|
|
1282
1676
|
database: options.database,
|
|
1283
|
-
input: { data: options.data },
|
|
1677
|
+
input: { table: options.table, data: options.data },
|
|
1284
1678
|
});
|
|
1285
1679
|
return {};
|
|
1286
1680
|
},
|
|
1287
1681
|
update: async (options) => {
|
|
1288
1682
|
this._updateCurrentStep(productsBuilder_types_1.WorkflowStepType.DATABASE_ACTION, options.event, {
|
|
1289
1683
|
database: options.database,
|
|
1290
|
-
input: { data: options.data, where: options.where },
|
|
1684
|
+
input: { table: options.table, data: options.data, where: options.where },
|
|
1291
1685
|
});
|
|
1292
1686
|
return {};
|
|
1293
1687
|
},
|
|
1294
1688
|
delete: async (options) => {
|
|
1295
1689
|
this._updateCurrentStep(productsBuilder_types_1.WorkflowStepType.DATABASE_ACTION, options.event, {
|
|
1296
1690
|
database: options.database,
|
|
1297
|
-
input: { where: options.where },
|
|
1691
|
+
input: { table: options.table, where: options.where },
|
|
1298
1692
|
});
|
|
1299
1693
|
return true;
|
|
1300
1694
|
},
|
|
@@ -1405,10 +1799,25 @@ class RecordingContext {
|
|
|
1405
1799
|
},
|
|
1406
1800
|
};
|
|
1407
1801
|
}
|
|
1802
|
+
/** Ductape primitive: message broker produce. Records a produce step (event = "broker-tag:topic-tag"). */
|
|
1803
|
+
get messaging() {
|
|
1804
|
+
return {
|
|
1805
|
+
produce: async (options) => {
|
|
1806
|
+
const colon = options.event.indexOf(':');
|
|
1807
|
+
const broker = colon >= 0 ? options.event.slice(0, colon) : options.event;
|
|
1808
|
+
const topic = colon >= 0 ? options.event.slice(colon + 1) : options.event;
|
|
1809
|
+
this._updateCurrentStep(productsBuilder_types_1.WorkflowStepType.PRODUCE, topic, {
|
|
1810
|
+
broker,
|
|
1811
|
+
input: { message: options.message },
|
|
1812
|
+
});
|
|
1813
|
+
},
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
/** @deprecated Prefer ctx.messaging.produce() */
|
|
1408
1817
|
get publish() {
|
|
1409
1818
|
return {
|
|
1410
1819
|
send: async (options) => {
|
|
1411
|
-
this._updateCurrentStep(productsBuilder_types_1.WorkflowStepType.
|
|
1820
|
+
this._updateCurrentStep(productsBuilder_types_1.WorkflowStepType.PRODUCE, options.event, {
|
|
1412
1821
|
broker: options.broker,
|
|
1413
1822
|
input: options.input,
|
|
1414
1823
|
options: { retries: options.retries },
|
|
@@ -1552,17 +1961,24 @@ class RecordingContext {
|
|
|
1552
1961
|
_updateCurrentStep(type, event, data) {
|
|
1553
1962
|
if (!this._currentStepTag)
|
|
1554
1963
|
return;
|
|
1555
|
-
//
|
|
1556
|
-
|
|
1964
|
+
// Update the step we're currently building (one step per ctx.step()), so we don't duplicate
|
|
1965
|
+
const step = this._pendingStep && this._pendingStep.tag === this._currentStepTag
|
|
1966
|
+
? this._pendingStep
|
|
1967
|
+
: this._steps.find((s) => s.tag === this._currentStepTag);
|
|
1557
1968
|
if (!step) {
|
|
1558
|
-
|
|
1969
|
+
const newStep = {
|
|
1559
1970
|
tag: this._currentStepTag,
|
|
1560
1971
|
type,
|
|
1561
1972
|
event,
|
|
1562
1973
|
input: data.input || {},
|
|
1563
1974
|
};
|
|
1564
|
-
this._steps.push(
|
|
1975
|
+
this._steps.push(newStep);
|
|
1976
|
+
this._updateStepProperties(newStep, type, event, data);
|
|
1977
|
+
return;
|
|
1565
1978
|
}
|
|
1979
|
+
this._updateStepProperties(step, type, event, data);
|
|
1980
|
+
}
|
|
1981
|
+
_updateStepProperties(step, type, event, data) {
|
|
1566
1982
|
// Update step properties
|
|
1567
1983
|
step.type = type;
|
|
1568
1984
|
step.event = event;
|
|
@@ -1584,18 +2000,20 @@ class RecordingContext {
|
|
|
1584
2000
|
step.fallback = data.fallback;
|
|
1585
2001
|
if (data.workflow)
|
|
1586
2002
|
step.workflow = data.workflow;
|
|
1587
|
-
if (data.input)
|
|
1588
|
-
step.input = data.input;
|
|
2003
|
+
if (data.input) {
|
|
2004
|
+
step.input = convertToOperatorInput(data.input, this._inputProxy, this._inputSchemaKeys);
|
|
2005
|
+
}
|
|
1589
2006
|
if (data.options)
|
|
1590
2007
|
step.options = Object.assign(Object.assign({}, step.options), data.options);
|
|
1591
2008
|
}
|
|
1592
2009
|
_addControlStep(type, event, data) {
|
|
1593
2010
|
const tag = `${type}-${this._stepOrder++}`;
|
|
2011
|
+
const input = convertToOperatorInput(data, this._inputProxy, this._inputSchemaKeys);
|
|
1594
2012
|
this._steps.push({
|
|
1595
2013
|
tag,
|
|
1596
2014
|
type,
|
|
1597
2015
|
event,
|
|
1598
|
-
input
|
|
2016
|
+
input,
|
|
1599
2017
|
});
|
|
1600
2018
|
}
|
|
1601
2019
|
_parseDuration(duration) {
|
|
@@ -1619,6 +2037,16 @@ class RecordingContext {
|
|
|
1619
2037
|
return value;
|
|
1620
2038
|
}
|
|
1621
2039
|
}
|
|
2040
|
+
/** Convert a value (e.g. handler return) to operator form for workflow output schema */
|
|
2041
|
+
captureOutput(value) {
|
|
2042
|
+
if (value === undefined || value === null)
|
|
2043
|
+
return {};
|
|
2044
|
+
const converted = convertToOperatorInput(value, this._inputProxy, this._inputSchemaKeys);
|
|
2045
|
+
if (typeof converted === 'object' && converted !== null && !Array.isArray(converted)) {
|
|
2046
|
+
return converted;
|
|
2047
|
+
}
|
|
2048
|
+
return { value: converted };
|
|
2049
|
+
}
|
|
1622
2050
|
/** Get collected steps */
|
|
1623
2051
|
getSteps() {
|
|
1624
2052
|
return this._steps;
|
|
@@ -1637,9 +2065,9 @@ class WorkflowCompiler {
|
|
|
1637
2065
|
* Executes the handler with a recording context to capture step definitions
|
|
1638
2066
|
*/
|
|
1639
2067
|
compile() {
|
|
1640
|
-
|
|
1641
|
-
const mockInput = {};
|
|
1642
|
-
const recordingCtx = new RecordingContext(mockInput, this.options.tag);
|
|
2068
|
+
var _a, _b, _c, _d;
|
|
2069
|
+
const mockInput = ((_a = this.options.recordInput) !== null && _a !== void 0 ? _a : {});
|
|
2070
|
+
const recordingCtx = new RecordingContext(mockInput, this.options.tag, this.options.input, this.options.branchOverrides, undefined, ((_b = this.options.recordInput) !== null && _b !== void 0 ? _b : {}));
|
|
1643
2071
|
// Execute handler to trace step definitions
|
|
1644
2072
|
try {
|
|
1645
2073
|
// Run the handler synchronously to capture all step calls
|
|
@@ -1659,8 +2087,8 @@ class WorkflowCompiler {
|
|
|
1659
2087
|
name: this.options.name,
|
|
1660
2088
|
tag: this.options.tag,
|
|
1661
2089
|
description: this.options.description,
|
|
1662
|
-
input: {},
|
|
1663
|
-
output: {},
|
|
2090
|
+
input: (_c = this.options.input) !== null && _c !== void 0 ? _c : {},
|
|
2091
|
+
output: (_d = this.options.output) !== null && _d !== void 0 ? _d : {},
|
|
1664
2092
|
steps: recordingCtx.getSteps(),
|
|
1665
2093
|
signals: this.options.signals
|
|
1666
2094
|
? Object.fromEntries(Object.entries(this.options.signals).map(([name, config]) => [name, { name, input: config.input }]))
|
|
@@ -1680,26 +2108,62 @@ class WorkflowCompiler {
|
|
|
1680
2108
|
}
|
|
1681
2109
|
/**
|
|
1682
2110
|
* Compile the workflow definition asynchronously
|
|
1683
|
-
* Fully awaits the handler to capture all step definitions
|
|
2111
|
+
* Fully awaits the handler to capture all step definitions.
|
|
2112
|
+
* With recordScenarios, runs the handler once per scenario and merges steps (for switch-style branches).
|
|
2113
|
+
* With recordInput, uses that as ctx.input so loops and control flow see real values.
|
|
1684
2114
|
*/
|
|
1685
2115
|
async compileAsync() {
|
|
1686
|
-
|
|
1687
|
-
const
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
2116
|
+
var _a, _b, _c, _d;
|
|
2117
|
+
const scenarios = this.options.recordScenarios && this.options.recordScenarios.length > 0
|
|
2118
|
+
? this.options.recordScenarios
|
|
2119
|
+
: [(_a = this.options.recordInput) !== null && _a !== void 0 ? _a : {}];
|
|
2120
|
+
const stepsByTag = new Map();
|
|
2121
|
+
const stepOrder = [];
|
|
2122
|
+
let handlerOutput = undefined;
|
|
2123
|
+
let lastCtx = null;
|
|
2124
|
+
for (const scenario of scenarios) {
|
|
2125
|
+
const scenarioObj = typeof scenario === 'object' && scenario !== null ? scenario : {};
|
|
2126
|
+
const scenarioCondition = this.options.recordScenarios && Object.keys(scenarioObj).length > 0
|
|
2127
|
+
? buildConditionFromScenario(scenarioObj)
|
|
2128
|
+
: null;
|
|
2129
|
+
const recordInput = Object.keys(scenarioObj).length > 0
|
|
2130
|
+
? scenarioObj
|
|
2131
|
+
: ((_b = this.options.recordInput) !== null && _b !== void 0 ? _b : {});
|
|
2132
|
+
const recordingCtx = new RecordingContext((recordInput !== null && recordInput !== void 0 ? recordInput : {}), this.options.tag, this.options.input, this.options.branchOverrides, scenarioCondition, recordInput);
|
|
2133
|
+
lastCtx = recordingCtx;
|
|
2134
|
+
try {
|
|
2135
|
+
const out = await this.options.handler(recordingCtx);
|
|
2136
|
+
if (out !== undefined && out !== null)
|
|
2137
|
+
handlerOutput = out;
|
|
2138
|
+
}
|
|
2139
|
+
catch (_) { }
|
|
2140
|
+
for (const s of recordingCtx.getSteps()) {
|
|
2141
|
+
const existing = stepsByTag.get(s.tag);
|
|
2142
|
+
if (existing) {
|
|
2143
|
+
const c1 = existing.condition;
|
|
2144
|
+
const c2 = s.condition;
|
|
2145
|
+
if (c1 && c2)
|
|
2146
|
+
existing.condition = `(${c1}) || (${c2})`;
|
|
2147
|
+
else if (c2)
|
|
2148
|
+
existing.condition = c2;
|
|
2149
|
+
}
|
|
2150
|
+
else {
|
|
2151
|
+
stepsByTag.set(s.tag, Object.assign({}, s));
|
|
2152
|
+
stepOrder.push(s.tag);
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
1695
2155
|
}
|
|
2156
|
+
const finalSteps = stepOrder.map((tag) => stepsByTag.get(tag)).filter(Boolean);
|
|
2157
|
+
const output = handlerOutput !== undefined && handlerOutput !== null && lastCtx
|
|
2158
|
+
? lastCtx.captureOutput(handlerOutput)
|
|
2159
|
+
: ((_c = this.options.output) !== null && _c !== void 0 ? _c : {});
|
|
1696
2160
|
return {
|
|
1697
2161
|
name: this.options.name,
|
|
1698
2162
|
tag: this.options.tag,
|
|
1699
2163
|
description: this.options.description,
|
|
1700
|
-
input: {},
|
|
1701
|
-
output:
|
|
1702
|
-
steps:
|
|
2164
|
+
input: (_d = this.options.input) !== null && _d !== void 0 ? _d : {},
|
|
2165
|
+
output: output,
|
|
2166
|
+
steps: finalSteps,
|
|
1703
2167
|
signals: this.options.signals
|
|
1704
2168
|
? Object.fromEntries(Object.entries(this.options.signals).map(([name, config]) => [name, { name, input: config.input }]))
|
|
1705
2169
|
: undefined,
|