@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.
Files changed (295) hide show
  1. package/dist/agents/agent-context.d.ts +3 -1
  2. package/dist/agents/agent-context.js +19 -3
  3. package/dist/agents/agent-context.js.map +1 -1
  4. package/dist/agents/agents.service.js +9 -5
  5. package/dist/agents/agents.service.js.map +1 -1
  6. package/dist/agents/types/agents.types.d.ts +14 -1
  7. package/dist/agents/types/agents.types.js.map +1 -1
  8. package/dist/api/services/appApi.service.js +15 -6
  9. package/dist/api/services/appApi.service.js.map +1 -1
  10. package/dist/api/services/logsApi.service.d.ts +51 -0
  11. package/dist/api/services/logsApi.service.js +19 -2
  12. package/dist/api/services/logsApi.service.js.map +1 -1
  13. package/dist/api/services/processorApi.service.d.ts +568 -2
  14. package/dist/api/services/processorApi.service.js +412 -21
  15. package/dist/api/services/processorApi.service.js.map +1 -1
  16. package/dist/api/services/productsApi.service.d.ts +20 -0
  17. package/dist/api/services/productsApi.service.js +44 -15
  18. package/dist/api/services/productsApi.service.js.map +1 -1
  19. package/dist/api/services/secretsApi.service.js +0 -11
  20. package/dist/api/services/secretsApi.service.js.map +1 -1
  21. package/dist/api/services/webhooksApi.service.js +13 -6
  22. package/dist/api/services/webhooksApi.service.js.map +1 -1
  23. package/dist/api/services/workflowApi.service.js +30 -12
  24. package/dist/api/services/workflowApi.service.js.map +1 -1
  25. package/dist/api/urls.d.ts +26 -0
  26. package/dist/api/urls.js +30 -3
  27. package/dist/api/urls.js.map +1 -1
  28. package/dist/apps/validators/joi-validators/update.appAction.validator.js +12 -1
  29. package/dist/apps/validators/joi-validators/update.appAction.validator.js.map +1 -1
  30. package/dist/brokers/brokers.service.d.ts +140 -2
  31. package/dist/brokers/brokers.service.js +444 -36
  32. package/dist/brokers/brokers.service.js.map +1 -1
  33. package/dist/brokers/types/index.d.ts +251 -0
  34. package/dist/brokers/utils/providers/rabbitmq.service.d.ts +14 -4
  35. package/dist/brokers/utils/providers/rabbitmq.service.js +22 -35
  36. package/dist/brokers/utils/providers/rabbitmq.service.js.map +1 -1
  37. package/dist/cache/cache.manager.d.ts +84 -5
  38. package/dist/cache/cache.manager.js +478 -38
  39. package/dist/cache/cache.manager.js.map +1 -1
  40. package/dist/cache/cache.service.d.ts +5 -0
  41. package/dist/cache/cache.service.js +163 -6
  42. package/dist/cache/cache.service.js.map +1 -1
  43. package/dist/cache/index.d.ts +1 -1
  44. package/dist/cache/index.js +3 -1
  45. package/dist/cache/index.js.map +1 -1
  46. package/dist/cache/types/index.d.ts +4 -0
  47. package/dist/database/databases.service.d.ts +70 -2
  48. package/dist/database/databases.service.js +150 -35
  49. package/dist/database/databases.service.js.map +1 -1
  50. package/dist/database/types/dashboard.interface.d.ts +74 -0
  51. package/dist/database/types/dashboard.interface.js +7 -0
  52. package/dist/database/types/dashboard.interface.js.map +1 -0
  53. package/dist/database/types/index.d.ts +1 -0
  54. package/dist/graph/graphs.service.d.ts +50 -12
  55. package/dist/graph/graphs.service.js +689 -203
  56. package/dist/graph/graphs.service.js.map +1 -1
  57. package/dist/graph/types/connection.interface.d.ts +2 -2
  58. package/dist/index.d.ts +286 -4
  59. package/dist/index.js +370 -21
  60. package/dist/index.js.map +1 -1
  61. package/dist/logs/logs.types.d.ts +16 -3
  62. package/dist/logs/logs.types.js +11 -0
  63. package/dist/logs/logs.types.js.map +1 -1
  64. package/dist/notifications/notifications.service.d.ts +3 -0
  65. package/dist/notifications/notifications.service.js +57 -14
  66. package/dist/notifications/notifications.service.js.map +1 -1
  67. package/dist/notifications/types/notifications.types.d.ts +50 -0
  68. package/dist/processor/services/processor.service.d.ts +132 -8
  69. package/dist/processor/services/processor.service.js +1174 -267
  70. package/dist/processor/services/processor.service.js.map +1 -1
  71. package/dist/processor/utils/processor.utils.d.ts +5 -0
  72. package/dist/processor/utils/processor.utils.js +65 -12
  73. package/dist/processor/utils/processor.utils.js.map +1 -1
  74. package/dist/processor/utils/storage.util.js +11 -2
  75. package/dist/processor/utils/storage.util.js.map +1 -1
  76. package/dist/products/services/products.service.d.ts +19 -2
  77. package/dist/products/services/products.service.js +388 -54
  78. package/dist/products/services/products.service.js.map +1 -1
  79. package/dist/products/validators/joi-validators/create.productFeature.validator.js +1 -1
  80. package/dist/products/validators/joi-validators/create.productJob.validator.js +2 -2
  81. package/dist/products/validators/joi-validators/create.productJob.validator.js.map +1 -1
  82. package/dist/products/validators/joi-validators/create.productMessageBrokerTopic.validator.js +1 -0
  83. package/dist/products/validators/joi-validators/create.productMessageBrokerTopic.validator.js.map +1 -1
  84. package/dist/products/validators/joi-validators/create.productNotification.validator.js +23 -12
  85. package/dist/products/validators/joi-validators/create.productNotification.validator.js.map +1 -1
  86. package/dist/resilience/fallback.service.d.ts +1 -0
  87. package/dist/resilience/fallback.service.js +2 -0
  88. package/dist/resilience/fallback.service.js.map +1 -1
  89. package/dist/resilience/quota.service.d.ts +1 -0
  90. package/dist/resilience/quota.service.js +2 -0
  91. package/dist/resilience/quota.service.js.map +1 -1
  92. package/dist/secrets/secrets.resolver.js +4 -1
  93. package/dist/secrets/secrets.resolver.js.map +1 -1
  94. package/dist/secrets/secrets.service.js +0 -12
  95. package/dist/secrets/secrets.service.js.map +1 -1
  96. package/dist/secrets/secrets.types.d.ts +3 -3
  97. package/dist/secrets/secrets.types.js +5 -5
  98. package/dist/secrets/secrets.types.js.map +1 -1
  99. package/dist/sessions/index.d.ts +1 -1
  100. package/dist/sessions/index.js +4 -1
  101. package/dist/sessions/index.js.map +1 -1
  102. package/dist/sessions/sessions.helper.d.ts +23 -3
  103. package/dist/sessions/sessions.helper.js +20 -3
  104. package/dist/sessions/sessions.helper.js.map +1 -1
  105. package/dist/sessions/sessions.resolver.d.ts +31 -0
  106. package/dist/sessions/sessions.resolver.js +230 -1
  107. package/dist/sessions/sessions.resolver.js.map +1 -1
  108. package/dist/sessions/sessions.service.d.ts +18 -2
  109. package/dist/sessions/sessions.service.js +121 -57
  110. package/dist/sessions/sessions.service.js.map +1 -1
  111. package/dist/sessions/types/index.d.ts +65 -21
  112. package/dist/storage/storage.service.d.ts +3 -0
  113. package/dist/storage/storage.service.js +179 -39
  114. package/dist/storage/storage.service.js.map +1 -1
  115. package/dist/types/index.types.d.ts +2 -0
  116. package/dist/types/inputs.types.d.ts +1 -0
  117. package/dist/types/inputs.types.js +3 -2
  118. package/dist/types/inputs.types.js.map +1 -1
  119. package/dist/types/processor.types.d.ts +72 -6
  120. package/dist/types/processor.types.js.map +1 -1
  121. package/dist/types/productsBuilder.types.d.ts +10 -0
  122. package/dist/types/productsBuilder.types.js +4 -0
  123. package/dist/types/productsBuilder.types.js.map +1 -1
  124. package/dist/vector/adapters/weaviate.adapter.js +22 -6
  125. package/dist/vector/adapters/weaviate.adapter.js.map +1 -1
  126. package/dist/vector/vector-database.service.d.ts +4 -2
  127. package/dist/vector/vector-database.service.js +71 -29
  128. package/dist/vector/vector-database.service.js.map +1 -1
  129. package/dist/workflows/types/workflows.types.d.ts +61 -3
  130. package/dist/workflows/types/workflows.types.js.map +1 -1
  131. package/dist/workflows/workflow-builder.js +17 -2
  132. package/dist/workflows/workflow-builder.js.map +1 -1
  133. package/dist/workflows/workflow-executor.d.ts +97 -18
  134. package/dist/workflows/workflow-executor.js +1449 -244
  135. package/dist/workflows/workflow-executor.js.map +1 -1
  136. package/dist/workflows/workflows.service.d.ts +2 -0
  137. package/dist/workflows/workflows.service.js +538 -74
  138. package/dist/workflows/workflows.service.js.map +1 -1
  139. package/package.json +11 -1
  140. package/dist/processor/services/fallback.service.d.ts +0 -5
  141. package/dist/processor/services/fallback.service.js +0 -43
  142. package/dist/processor/services/fallback.service.js.map +0 -1
  143. package/dist/processor/services/messagebrokers/aws-sqs.service.d.ts +0 -15
  144. package/dist/processor/services/messagebrokers/aws-sqs.service.js +0 -77
  145. package/dist/processor/services/messagebrokers/aws-sqs.service.js.map +0 -1
  146. package/dist/processor/services/messagebrokers/google-pubsub.service.d.ts +0 -16
  147. package/dist/processor/services/messagebrokers/google-pubsub.service.js +0 -34
  148. package/dist/processor/services/messagebrokers/google-pubsub.service.js.map +0 -1
  149. package/dist/processor/services/messagebrokers/index.d.ts +0 -3
  150. package/dist/processor/services/messagebrokers/index.js +0 -26
  151. package/dist/processor/services/messagebrokers/index.js.map +0 -1
  152. package/dist/processor/services/messagebrokers/kafka.service.d.ts +0 -14
  153. package/dist/processor/services/messagebrokers/kafka.service.js +0 -45
  154. package/dist/processor/services/messagebrokers/kafka.service.js.map +0 -1
  155. package/dist/processor/services/messagebrokers/messagebrokers.type.d.ts +0 -6
  156. package/dist/processor/services/messagebrokers/messagebrokers.type.js +0 -3
  157. package/dist/processor/services/messagebrokers/messagebrokers.type.js.map +0 -1
  158. package/dist/processor/services/messagebrokers/rabbitmq.service.d.ts +0 -14
  159. package/dist/processor/services/messagebrokers/rabbitmq.service.js +0 -67
  160. package/dist/processor/services/messagebrokers/rabbitmq.service.js.map +0 -1
  161. package/dist/processor/services/messagebrokers/redis.service.d.ts +0 -18
  162. package/dist/processor/services/messagebrokers/redis.service.js +0 -82
  163. package/dist/processor/services/messagebrokers/redis.service.js.map +0 -1
  164. package/dist/processor/services/quota.service.d.ts +0 -15
  165. package/dist/processor/services/quota.service.js +0 -63
  166. package/dist/processor/services/quota.service.js.map +0 -1
  167. package/dist/test/index.d.ts +0 -3
  168. package/dist/test/index.js +0 -11
  169. package/dist/test/index.js.map +0 -1
  170. package/dist/test/test.appBuilder.d.ts +0 -0
  171. package/dist/test/test.appBuilder.js +0 -1
  172. package/dist/test/test.appBuilder.js.map +0 -1
  173. package/dist/test/test.broker.kafka.d.ts +0 -1
  174. package/dist/test/test.broker.kafka.js +0 -172
  175. package/dist/test/test.broker.kafka.js.map +0 -1
  176. package/dist/test/test.broker.nats.d.ts +0 -1
  177. package/dist/test/test.broker.nats.js +0 -193
  178. package/dist/test/test.broker.nats.js.map +0 -1
  179. package/dist/test/test.broker.pubsub.d.ts +0 -1
  180. package/dist/test/test.broker.pubsub.js +0 -171
  181. package/dist/test/test.broker.pubsub.js.map +0 -1
  182. package/dist/test/test.broker.rabbitmq.d.ts +0 -1
  183. package/dist/test/test.broker.rabbitmq.js +0 -164
  184. package/dist/test/test.broker.rabbitmq.js.map +0 -1
  185. package/dist/test/test.broker.redis.d.ts +0 -1
  186. package/dist/test/test.broker.redis.js +0 -168
  187. package/dist/test/test.broker.redis.js.map +0 -1
  188. package/dist/test/test.broker.sqs.d.ts +0 -1
  189. package/dist/test/test.broker.sqs.js +0 -158
  190. package/dist/test/test.broker.sqs.js.map +0 -1
  191. package/dist/test/test.caches.d.ts +0 -1
  192. package/dist/test/test.caches.js +0 -231
  193. package/dist/test/test.caches.js.map +0 -1
  194. package/dist/test/test.database.d.ts +0 -1
  195. package/dist/test/test.database.dynamo.d.ts +0 -1
  196. package/dist/test/test.database.dynamo.js +0 -265
  197. package/dist/test/test.database.dynamo.js.map +0 -1
  198. package/dist/test/test.database.js +0 -140
  199. package/dist/test/test.database.js.map +0 -1
  200. package/dist/test/test.database.mongo.d.ts +0 -1
  201. package/dist/test/test.database.mongo.js +0 -371
  202. package/dist/test/test.database.mongo.js.map +0 -1
  203. package/dist/test/test.database.mysql.d.ts +0 -1
  204. package/dist/test/test.database.mysql.js +0 -415
  205. package/dist/test/test.database.mysql.js.map +0 -1
  206. package/dist/test/test.database.postgres.d.ts +0 -1
  207. package/dist/test/test.database.postgres.js +0 -412
  208. package/dist/test/test.database.postgres.js.map +0 -1
  209. package/dist/test/test.email.brevo.d.ts +0 -1
  210. package/dist/test/test.email.brevo.js +0 -326
  211. package/dist/test/test.email.brevo.js.map +0 -1
  212. package/dist/test/test.email.mailgun.d.ts +0 -1
  213. package/dist/test/test.email.mailgun.js +0 -352
  214. package/dist/test/test.email.mailgun.js.map +0 -1
  215. package/dist/test/test.email.postmark.d.ts +0 -1
  216. package/dist/test/test.email.postmark.js +0 -316
  217. package/dist/test/test.email.postmark.js.map +0 -1
  218. package/dist/test/test.email.sendgrid.d.ts +0 -1
  219. package/dist/test/test.email.sendgrid.js +0 -365
  220. package/dist/test/test.email.sendgrid.js.map +0 -1
  221. package/dist/test/test.email.smtp.d.ts +0 -1
  222. package/dist/test/test.email.smtp.js +0 -323
  223. package/dist/test/test.email.smtp.js.map +0 -1
  224. package/dist/test/test.graph.arangodb.d.ts +0 -1
  225. package/dist/test/test.graph.arangodb.js +0 -358
  226. package/dist/test/test.graph.arangodb.js.map +0 -1
  227. package/dist/test/test.graph.memgraph.d.ts +0 -1
  228. package/dist/test/test.graph.memgraph.js +0 -320
  229. package/dist/test/test.graph.memgraph.js.map +0 -1
  230. package/dist/test/test.graph.neo4j.d.ts +0 -1
  231. package/dist/test/test.graph.neo4j.js +0 -218
  232. package/dist/test/test.graph.neo4j.js.map +0 -1
  233. package/dist/test/test.graph.neptune.d.ts +0 -1
  234. package/dist/test/test.graph.neptune.js +0 -331
  235. package/dist/test/test.graph.neptune.js.map +0 -1
  236. package/dist/test/test.health.d.ts +0 -0
  237. package/dist/test/test.health.js +0 -1
  238. package/dist/test/test.health.js.map +0 -1
  239. package/dist/test/test.import.d.ts +0 -0
  240. package/dist/test/test.import.js +0 -1
  241. package/dist/test/test.import.js.map +0 -1
  242. package/dist/test/test.import.openapi.d.ts +0 -0
  243. package/dist/test/test.import.openapi.js +0 -1
  244. package/dist/test/test.import.openapi.js.map +0 -1
  245. package/dist/test/test.imports.d.ts +0 -1
  246. package/dist/test/test.imports.js +0 -21
  247. package/dist/test/test.imports.js.map +0 -1
  248. package/dist/test/test.logs.d.ts +0 -0
  249. package/dist/test/test.logs.js +0 -1
  250. package/dist/test/test.logs.js.map +0 -1
  251. package/dist/test/test.notifications.d.ts +0 -1
  252. package/dist/test/test.notifications.js +0 -198
  253. package/dist/test/test.notifications.js.map +0 -1
  254. package/dist/test/test.notifiers.d.ts +0 -0
  255. package/dist/test/test.notifiers.js +0 -1
  256. package/dist/test/test.notifiers.js.map +0 -1
  257. package/dist/test/test.processor.d.ts +0 -0
  258. package/dist/test/test.processor.js +0 -1
  259. package/dist/test/test.processor.js.map +0 -1
  260. package/dist/test/test.productBuilder.d.ts +0 -0
  261. package/dist/test/test.productBuilder.js +0 -1
  262. package/dist/test/test.productBuilder.js.map +0 -1
  263. package/dist/test/test.products.d.ts +0 -0
  264. package/dist/test/test.products.js +0 -1
  265. package/dist/test/test.products.js.map +0 -1
  266. package/dist/test/test.push.expo.d.ts +0 -1
  267. package/dist/test/test.push.expo.js +0 -442
  268. package/dist/test/test.push.expo.js.map +0 -1
  269. package/dist/test/test.push.firebase.d.ts +0 -1
  270. package/dist/test/test.push.firebase.js +0 -409
  271. package/dist/test/test.push.firebase.js.map +0 -1
  272. package/dist/test/test.session.d.ts +0 -1
  273. package/dist/test/test.session.js +0 -299
  274. package/dist/test/test.session.js.map +0 -1
  275. package/dist/test/test.sms.nexmo.d.ts +0 -1
  276. package/dist/test/test.sms.nexmo.js +0 -278
  277. package/dist/test/test.sms.nexmo.js.map +0 -1
  278. package/dist/test/test.sms.twilio.d.ts +0 -1
  279. package/dist/test/test.sms.twilio.js +0 -275
  280. package/dist/test/test.sms.twilio.js.map +0 -1
  281. package/dist/test/test.storage.d.ts +0 -1
  282. package/dist/test/test.storage.js +0 -202
  283. package/dist/test/test.storage.js.map +0 -1
  284. package/dist/test/test.triggers.d.ts +0 -1
  285. package/dist/test/test.triggers.js +0 -314
  286. package/dist/test/test.triggers.js.map +0 -1
  287. package/dist/test/test.vector.pinecone.d.ts +0 -1
  288. package/dist/test/test.vector.pinecone.js +0 -238
  289. package/dist/test/test.vector.pinecone.js.map +0 -1
  290. package/dist/test/test.vector.qdrant.d.ts +0 -1
  291. package/dist/test/test.vector.qdrant.js +0 -307
  292. package/dist/test/test.vector.qdrant.js.map +0 -1
  293. package/dist/test/test.vector.weaviate.d.ts +0 -1
  294. package/dist/test/test.vector.weaviate.js +0 -325
  295. package/dist/test/test.vector.weaviate.js.map +0 -1
@@ -46,6 +46,7 @@ var __rest = (this && this.__rest) || function (s, e) {
46
46
  var __importDefault = (this && this.__importDefault) || function (mod) {
47
47
  return (mod && mod.__esModule) ? mod : { "default": mod };
48
48
  };
49
+ var _a, _b;
49
50
  Object.defineProperty(exports, "__esModule", { value: true });
50
51
  const products_service_1 = __importDefault(require("../../products/services/products.service"));
51
52
  const types_1 = require("../../types");
@@ -54,6 +55,7 @@ const inputs_service_1 = __importDefault(require("../../inputs/inputs.service"))
54
55
  const processor_utils_1 = require("../utils/processor.utils");
55
56
  const axios_1 = __importDefault(require("axios"));
56
57
  const processorApi_service_1 = require("../../api/services/processorApi.service");
58
+ const cache_service_1 = require("../../cache/cache.service");
57
59
  const expo_client_1 = __importDefault(require("../../clients/expo.client"));
58
60
  const handlebars_1 = require("handlebars");
59
61
  const string_utils_1 = require("../../products/utils/string.utils");
@@ -86,8 +88,19 @@ async function loadJWT() {
86
88
  }
87
89
  return null;
88
90
  }
91
+ /** Only log when DUCTAPE_DEBUG is set to avoid sync I/O and serialization cost in hot path */
92
+ const _processorDebug = typeof process !== 'undefined' && (((_a = process.env) === null || _a === void 0 ? void 0 : _a.DUCTAPE_DEBUG) === 'true' || ((_b = process.env) === null || _b === void 0 ? void 0 : _b.DUCTAPE_DEBUG) === '1');
93
+ const debugLog = _processorDebug ? (...args) => console.log(...args) : () => { };
89
94
  class ProcessorService {
90
- constructor({ workspace_id, public_key, user_id, token, env_type, private_key, access_key, redis_client, queues }) {
95
+ constructor({ workspace_id, public_key, user_id, token, env_type, private_key, access_key, redis_client, queues, preInitializedProductBuilder }) {
96
+ /** Reuse broker connections when multiple produce steps use the same broker (avoids ~1–3s connection setup per step). Never logged or exposed. */
97
+ this.brokerServicePool = new Map();
98
+ /** Reuse SMTP transporter so we don't open a new connection per email (avoids multi-second handshake per send). Never logged or exposed. */
99
+ this.mailTransporterPool = new Map();
100
+ /** Reuse Firebase Admin app per project (avoids re-init per push). Never logged or exposed. */
101
+ this.firebaseAppPool = new Map();
102
+ /** Reuse SMS client per config (Twilio/Nexmo/Plivo). Never logged or exposed. */
103
+ this.smsClientPool = new Map();
91
104
  this.workspace_id = workspace_id;
92
105
  this.public_key = public_key;
93
106
  this.user_id = user_id;
@@ -95,13 +108,15 @@ class ProcessorService {
95
108
  this.accessKey = access_key;
96
109
  this.token = token;
97
110
  this.published = false;
98
- this.productBuilderService = new products_service_1.default({
111
+ this.productBuilderService = preInitializedProductBuilder !== null && preInitializedProductBuilder !== void 0 ? preInitializedProductBuilder : new products_service_1.default({
99
112
  workspace_id,
100
113
  public_key,
101
114
  user_id,
102
115
  token,
103
116
  env_type,
104
117
  redis_client,
118
+ access_key,
119
+ workspace_private_key: private_key || undefined,
105
120
  });
106
121
  this.appBuilderService = new app_service_1.default({
107
122
  workspace_id,
@@ -132,9 +147,20 @@ class ProcessorService {
132
147
  this.requestTrackerService = request_service_1.default.getInstance(redis_client);
133
148
  this.processorApiService = new processorApi_service_1.ProcessorApiService(env_type);
134
149
  this.environment = env_type;
135
- // Store redis client for job state management
150
+ // Initialize CacheService
151
+ this.cacheService = new cache_service_1.CacheService({
152
+ workspace_id,
153
+ public_key,
154
+ user_id,
155
+ token,
156
+ env_type,
157
+ });
158
+ // Connect CacheService to Redis if available
136
159
  if (redis_client) {
137
160
  this.redisClient = redis_client;
161
+ // Note: CacheService.connectRedis() requires a URL string, but we have a client instance
162
+ // For now, CacheService will work with remote cache only
163
+ // TODO: Consider adding a method to CacheService to accept an existing Redis client
138
164
  }
139
165
  // Start healthcheck workers only if product tag is available
140
166
  if (redis_client && this.productTag) {
@@ -144,6 +170,192 @@ class ProcessorService {
144
170
  this.queues = queues;
145
171
  }
146
172
  }
173
+ /**
174
+ * Pool key for broker service reuse (same broker type + config => same connection).
175
+ */
176
+ getBrokerPoolKey(type, config) {
177
+ var _a;
178
+ const configKey = (config === null || config === void 0 ? void 0 : config.url) || (config === null || config === void 0 ? void 0 : config.host) || ((_a = config === null || config === void 0 ? void 0 : config.brokers) === null || _a === void 0 ? void 0 : _a[0]) || JSON.stringify(config !== null && config !== void 0 ? config : {});
179
+ return `${type}:${configKey}`;
180
+ }
181
+ /**
182
+ * Get or create a broker service instance so we reuse the same connection for the same broker.
183
+ */
184
+ async getBrokerServiceForPublish(type, config) {
185
+ const poolKey = this.getBrokerPoolKey(type, config);
186
+ const existing = this.brokerServicePool.get(poolKey);
187
+ if (existing)
188
+ return existing;
189
+ const createBrokerService = await loadBrokerService();
190
+ if (!createBrokerService)
191
+ throw new Error('Broker service not loaded (e.g. browser).');
192
+ const service = createBrokerService(type, config);
193
+ this.brokerServicePool.set(poolKey, service);
194
+ return service;
195
+ }
196
+ /**
197
+ * Disconnect all pooled broker connections (e.g. at end of workflow run).
198
+ * Safe to call if pool is empty or a broker has no disconnect().
199
+ */
200
+ async disconnectBrokerConnections() {
201
+ for (const service of this.brokerServicePool.values()) {
202
+ try {
203
+ const disconnect = service.disconnect;
204
+ if (typeof disconnect === 'function')
205
+ await disconnect();
206
+ }
207
+ catch (_a) {
208
+ // Non-fatal
209
+ }
210
+ }
211
+ this.brokerServicePool.clear();
212
+ }
213
+ /**
214
+ * Pool key for mail transporter reuse (host/port/user only; no password). Same SMTP config => same connection.
215
+ */
216
+ getMailTransporterPoolKey(auth) {
217
+ var _a, _b, _c, _d;
218
+ const h = (_a = auth === null || auth === void 0 ? void 0 : auth.host) !== null && _a !== void 0 ? _a : '';
219
+ const p = (_b = auth === null || auth === void 0 ? void 0 : auth.port) !== null && _b !== void 0 ? _b : '';
220
+ const u = (_d = (_c = auth === null || auth === void 0 ? void 0 : auth.auth) === null || _c === void 0 ? void 0 : _c.user) !== null && _d !== void 0 ? _d : '';
221
+ const secure = (auth === null || auth === void 0 ? void 0 : auth.secure) === true ? '1' : '0';
222
+ return `mail:${h}:${p}:${secure}:${u}`;
223
+ }
224
+ /**
225
+ * Get or create a mail transporter so we reuse the same SMTP connection instead of opening a new one per send.
226
+ */
227
+ async getMailTransporter(auth) {
228
+ const key = this.getMailTransporterPoolKey(auth);
229
+ const existing = this.mailTransporterPool.get(key);
230
+ if (existing)
231
+ return existing;
232
+ const transporter = await (0, processor_utils_1.mailerClient)(auth);
233
+ this.mailTransporterPool.set(key, transporter);
234
+ return transporter;
235
+ }
236
+ /**
237
+ * Close all pooled mail transporters (e.g. at end of workflow run). Safe if pool is empty.
238
+ */
239
+ async disconnectMailTransporters() {
240
+ for (const transporter of this.mailTransporterPool.values()) {
241
+ try {
242
+ const close = transporter.close;
243
+ if (typeof close === 'function')
244
+ await close();
245
+ }
246
+ catch (_a) {
247
+ // Non-fatal
248
+ }
249
+ }
250
+ this.mailTransporterPool.clear();
251
+ }
252
+ /**
253
+ * Get or create Firebase Admin app by project_id so we reuse the same app per project (Expo client is already module-level singleton).
254
+ */
255
+ async getFirebaseApp(credentials) {
256
+ var _a, _b;
257
+ const creds = typeof credentials === 'string' ? JSON.parse(credentials) : credentials;
258
+ const projectId = (_a = creds === null || creds === void 0 ? void 0 : creds.project_id) !== null && _a !== void 0 ? _a : `fb-${String((_b = creds === null || creds === void 0 ? void 0 : creds.client_email) !== null && _b !== void 0 ? _b : '').slice(0, 20)}`;
259
+ const existing = this.firebaseAppPool.get(projectId);
260
+ if (existing)
261
+ return existing;
262
+ const admin = require('firebase-admin');
263
+ try {
264
+ const app = admin.app(projectId);
265
+ this.firebaseAppPool.set(projectId, app);
266
+ return app;
267
+ }
268
+ catch (_c) {
269
+ const app = admin.initializeApp({ credential: admin.credential.cert(credentials) }, projectId);
270
+ this.firebaseAppPool.set(projectId, app);
271
+ return app;
272
+ }
273
+ }
274
+ /**
275
+ * Close all pooled Firebase apps (e.g. at end of workflow run). Safe if pool is empty.
276
+ */
277
+ async disconnectFirebaseApps() {
278
+ for (const app of this.firebaseAppPool.values()) {
279
+ try {
280
+ const del = app.delete;
281
+ if (typeof del === 'function')
282
+ await del();
283
+ }
284
+ catch (_a) {
285
+ // Non-fatal
286
+ }
287
+ }
288
+ this.firebaseAppPool.clear();
289
+ }
290
+ /**
291
+ * Pool key for SMS client (provider + identifier + sender; no secrets). Same config => reuse client.
292
+ */
293
+ getSmsClientPoolKey(config) {
294
+ var _a, _b, _c, _d;
295
+ const p = (_a = config === null || config === void 0 ? void 0 : config.provider) !== null && _a !== void 0 ? _a : '';
296
+ const id = (_c = (_b = config === null || config === void 0 ? void 0 : config.accountSid) !== null && _b !== void 0 ? _b : config === null || config === void 0 ? void 0 : config.apiKey) !== null && _c !== void 0 ? _c : '';
297
+ const sender = (_d = config === null || config === void 0 ? void 0 : config.sender) !== null && _d !== void 0 ? _d : '';
298
+ return `sms:${p}:${id}:${sender}`;
299
+ }
300
+ /**
301
+ * Get or create SMS client so we reuse Twilio/Nexmo/Plivo client per config.
302
+ */
303
+ async getSmsClient(config) {
304
+ const key = this.getSmsClientPoolKey(config);
305
+ const existing = this.smsClientPool.get(key);
306
+ if (existing)
307
+ return existing;
308
+ const SmsClientClass = await (0, sms_repo_1.loadSMSClient)();
309
+ if (!SmsClientClass)
310
+ throw new Error('SMS client not loaded (e.g. browser).');
311
+ const client = new SmsClientClass(config);
312
+ this.smsClientPool.set(key, client);
313
+ return client;
314
+ }
315
+ /**
316
+ * Clear pooled SMS clients (e.g. at end of workflow run). Safe if pool is empty.
317
+ */
318
+ async disconnectSmsClients() {
319
+ this.smsClientPool.clear();
320
+ }
321
+ /**
322
+ * Pre-warm broker connections for the given product/env and broker tags.
323
+ * Call this before step execution so the first produce step does not pay connection setup cost.
324
+ * Security: same auth as runBrokerPublish (product + env from caller). Secrets resolved in-memory
325
+ * only; no config/URLs/credentials logged or persisted. Pool is per-processor-instance (one run).
326
+ */
327
+ async warmBrokerConnections(options) {
328
+ const { product, env, brokerTags } = options;
329
+ if (brokerTags.length === 0)
330
+ return;
331
+ await this.productBuilderService.initializeProductByTag(product);
332
+ for (const brokerTag of brokerTags) {
333
+ try {
334
+ const broker = await this.productBuilderService.fetchMessageBroker(brokerTag);
335
+ if (!broker)
336
+ continue;
337
+ const brokerEnv = broker.envs.find((el) => el.slug === env);
338
+ if (!brokerEnv)
339
+ continue;
340
+ let brokerConfig = brokerEnv.config;
341
+ if (brokerConfig && (0, secrets_1.mightContainSecrets)(brokerConfig)) {
342
+ const secretsService = (0, secrets_1.getSecretsService)();
343
+ if (secretsService) {
344
+ const resolved = await secretsService.resolve(brokerConfig, { env });
345
+ brokerConfig = resolved.value;
346
+ }
347
+ }
348
+ const service = await this.getBrokerServiceForPublish(brokerEnv.type, brokerConfig);
349
+ const connect = service.connect;
350
+ if (typeof connect === 'function')
351
+ await connect();
352
+ }
353
+ catch (_a) {
354
+ // Intentionally no log: avoid leaking any error text (could contain URLs or backend details).
355
+ // Step will connect on first use or fail at runtime with same auth.
356
+ }
357
+ }
358
+ }
147
359
  /**
148
360
  * Start healthcheck workers for all products/environments after Redis is connected.
149
361
  * This is called automatically in the constructor if redisClient is present.
@@ -303,7 +515,7 @@ class ProcessorService {
303
515
  return res.data;
304
516
  }
305
517
  catch (e) {
306
- console.log(e);
518
+ debugLog(e);
307
519
  throw new Error('Invalid/Expired token');
308
520
  }
309
521
  }
@@ -450,7 +662,13 @@ class ProcessorService {
450
662
  if (workspace_id !== this.workspace_id) {
451
663
  throw new Error('Access Denied');
452
664
  }
453
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Product initialize - success', data: { product_id: this.productId }, status: types_1.LogEventStatus.SUCCESS }));
665
+ /*this.logService.add({
666
+ ...this.baseLogs,
667
+ ...additional_logs,
668
+ message: 'Product initialize - success',
669
+ data: { product_id: this.productId },
670
+ status: LogEventStatus.SUCCESS,
671
+ } as unknown as ILogData);*/
454
672
  }
455
673
  catch (e) {
456
674
  this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Product initialize - failed', data: e, status: types_1.LogEventStatus.FAIL }));
@@ -469,9 +687,9 @@ class ProcessorService {
469
687
  });
470
688
  }
471
689
  try {
472
- console.log(`Initializing pricing for access tag: ${access_tag}`);
690
+ debugLog(`Initializing pricing for access tag: ${access_tag}`);
473
691
  const product_app = await this.productBuilderService.fetchApp(access_tag); // validate app exists
474
- console.log(`Found product app: ${JSON.stringify(product_app)}`);
692
+ debugLog(`Found product app: ${JSON.stringify(product_app)}`);
475
693
  const app = await this.productBuilderService.fetchThirdPartyAppByAccessTag(product_app.access_tag);
476
694
  await this.pricingService.initializePricingByTag(product_app.pricing_tag, app._id);
477
695
  const { pricing_tag } = this.pricingService.fetchPricing();
@@ -489,7 +707,13 @@ class ProcessorService {
489
707
  if (!product_env) {
490
708
  throw new Error(`Env ${env} not found`);
491
709
  }
492
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Fetch environment - success', data: { slug: env, env: product_env }, status: types_1.LogEventStatus.SUCCESS }));
710
+ /*this.logService.add({
711
+ ...this.baseLogs,
712
+ ...additional_logs,
713
+ message: 'Fetch environment - success',
714
+ data: { slug: env, env: product_env },
715
+ status: LogEventStatus.SUCCESS,
716
+ } as unknown as ILogData);*/
493
717
  return product_env;
494
718
  }
495
719
  catch (e) {
@@ -545,7 +769,13 @@ class ProcessorService {
545
769
  params,
546
770
  });
547
771
  }
548
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Construct JSON payloads - success', data: { payload: (0, processor_utils_1.anonymizeObject)(payload) }, status: types_1.LogEventStatus.SUCCESS }));
772
+ /*this.logService.add({
773
+ ...this.baseLogs,
774
+ ...additional_logs,
775
+ message: 'Construct JSON payloads - success',
776
+ data: { payload: anonymizeObject(payload) },
777
+ status: LogEventStatus.SUCCESS,
778
+ } as unknown as ILogData);*/
549
779
  return payload;
550
780
  }
551
781
  catch (e) {
@@ -556,7 +786,6 @@ class ProcessorService {
556
786
  async generatePayload(obj, event, additional_logs, sample = [], index = {}, loopIndex = null) {
557
787
  try {
558
788
  const payload = {};
559
- console.log('Payload Construction', { obj, event, sample, index, loopIndex });
560
789
  const keys = Object.keys(obj);
561
790
  for (let i = 0; i < keys.length; i++) {
562
791
  const key = keys[i];
@@ -588,7 +817,6 @@ class ProcessorService {
588
817
  });
589
818
  }
590
819
  }
591
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Generate payload - success', data: { payload: (0, processor_utils_1.anonymizeObject)(payload) }, status: types_1.LogEventStatus.SUCCESS }));
592
820
  return payload;
593
821
  }
594
822
  catch (e) {
@@ -752,14 +980,14 @@ class ProcessorService {
752
980
  const placeholdersStr = match[1];
753
981
  const separator = match[2];
754
982
  const placeHolders = placeholdersStr.split(',').map((data) => data.trim());
755
- console.log('placeHolders', { placeHolders, separator });
983
+ debugLog('placeHolders', { placeHolders, separator });
756
984
  const values = await Promise.all(placeHolders.map(async (holder) => {
757
985
  return await this.generateStringValues(holder, app, additional_logs, sample, index, key, loopIndex);
758
986
  }));
759
987
  return values.join(separator);
760
988
  }
761
989
  else {
762
- console.log('No match found');
990
+ debugLog('No match found');
763
991
  }
764
992
  }
765
993
  async uppercaseValue(value, app, additional_logs, sample = [], index = {}, key = '', loopIndex = null) {
@@ -772,7 +1000,7 @@ class ProcessorService {
772
1000
  return resolvedValue.toUpperCase();
773
1001
  }
774
1002
  else {
775
- //console.log('No match found');
1003
+ //debugLog('No match found');
776
1004
  }
777
1005
  }
778
1006
  async lowercaseValue(value, app, additional_logs, sample = [], index = {}, key = '', loopIndex = null) {
@@ -785,7 +1013,7 @@ class ProcessorService {
785
1013
  return resolvedValue.toLowerCase();
786
1014
  }
787
1015
  else {
788
- //console.log('No match found');
1016
+ //debugLog('No match found');
789
1017
  }
790
1018
  }
791
1019
  async dateFormatValue(value, app, additional_logs, sample = [], index = {}, key = '', loopIndex = null) {
@@ -801,7 +1029,7 @@ class ProcessorService {
801
1029
  return (0, date_fns_1.format)(parsedDate, formatStr);
802
1030
  }
803
1031
  else {
804
- //console.log('No match found');
1032
+ //debugLog('No match found');
805
1033
  }
806
1034
  }
807
1035
  async replaceValue(value, app, additional_logs, sample = [], index = {}, key = '', loopIndex = null) {
@@ -815,7 +1043,7 @@ class ProcessorService {
815
1043
  return resolvedValue.split(searchStr).join(replaceStr);
816
1044
  }
817
1045
  else {
818
- console.log('No match found');
1046
+ debugLog('No match found');
819
1047
  }
820
1048
  }
821
1049
  async substringValues(value, app, additional_logs, sample = [], index = {}, key = '', loopIndex = null) {
@@ -834,7 +1062,7 @@ class ProcessorService {
834
1062
  return resolvedString.substring(start, end);
835
1063
  }
836
1064
  else {
837
- console.log('No match found');
1065
+ debugLog('No match found');
838
1066
  return '';
839
1067
  }
840
1068
  }
@@ -849,7 +1077,7 @@ class ProcessorService {
849
1077
  return resolvedString.trim();
850
1078
  }
851
1079
  else {
852
- console.log('No match found');
1080
+ debugLog('No match found');
853
1081
  return '';
854
1082
  }
855
1083
  }
@@ -873,7 +1101,7 @@ class ProcessorService {
873
1101
  }
874
1102
  }
875
1103
  else {
876
- console.log('No match found');
1104
+ debugLog('No match found');
877
1105
  }
878
1106
  }
879
1107
  async filterValue(value, app, additional_logs, sample = [], index = {}, key = '', loopIndex = null) {
@@ -892,7 +1120,7 @@ class ProcessorService {
892
1120
  }
893
1121
  return resolvedArray.filter((item) => (0, processor_utils_1.compareValues)(item, operator, resolvedValue));
894
1122
  }
895
- console.log('No $Filter match found');
1123
+ debugLog('No $Filter match found');
896
1124
  return [];
897
1125
  }
898
1126
  async findValue(value, app, additional_logs, sample = [], index = {}, key = '', loopIndex = null) {
@@ -911,7 +1139,7 @@ class ProcessorService {
911
1139
  }
912
1140
  return resolvedArray.find((item) => (0, processor_utils_1.compareValues)(item, operator, resolvedValue));
913
1141
  }
914
- console.log('No $Find match found');
1142
+ debugLog('No $Find match found');
915
1143
  return null;
916
1144
  }
917
1145
  async splitValues(value, app, additional_logs, sample = [], index = {}, key = '', loopIndex = null) {
@@ -926,7 +1154,7 @@ class ProcessorService {
926
1154
  return resolvedString.split(separator);
927
1155
  }
928
1156
  else {
929
- console.log('No match found');
1157
+ debugLog('No match found');
930
1158
  return [];
931
1159
  }
932
1160
  }
@@ -947,7 +1175,7 @@ class ProcessorService {
947
1175
  return mergedArray;
948
1176
  }
949
1177
  else {
950
- console.log('No match found');
1178
+ debugLog('No match found');
951
1179
  }
952
1180
  }
953
1181
  async generateInputValue(input, stages) {
@@ -1071,7 +1299,7 @@ class ProcessorService {
1071
1299
  }
1072
1300
  async generateAuthValue(stages, app, sample, additional_logs) {
1073
1301
  try {
1074
- console.log('Generate Auth Data', { stages, app, sample });
1302
+ debugLog('Generate Auth Data', { stages, app, sample });
1075
1303
  let auth_data = await this.fetchAuthData(app, additional_logs); //TODO: should use stages[0]
1076
1304
  // take the app tag in index 0..
1077
1305
  if (!auth_data) {
@@ -1098,7 +1326,7 @@ class ProcessorService {
1098
1326
  if (!env.auth) {
1099
1327
  throw new Error(`App ${app_tag} in auth needs to have a definition for auth in env: ${this.processEnv.slug}`);
1100
1328
  }
1101
- console.log('Envroment', env.auth);
1329
+ debugLog('Envroment', env.auth);
1102
1330
  let values = env.auth.values;
1103
1331
  if (!values) {
1104
1332
  // no auth values
@@ -1106,7 +1334,7 @@ class ProcessorService {
1106
1334
  }
1107
1335
  if (!env.auth.expiry || (env.auth.expiry && Date.now() > new Date(env.auth.expiry).getTime())) {
1108
1336
  // refresh
1109
- console.log('REFRESH DATA', env, app_tag);
1337
+ debugLog('REFRESH DATA', env, app_tag);
1110
1338
  values = await this.getAndStoreAuth(env, app_tag);
1111
1339
  }
1112
1340
  const decrypted = (0, processor_utils_1.decrypt)(values, this.productBuilderService.fetchPrivateKey());
@@ -1219,12 +1447,68 @@ class ProcessorService {
1219
1447
  }
1220
1448
  }
1221
1449
  async runJobs(job, additional_logs = {}) {
1222
- var _a;
1450
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
1223
1451
  const jobId = (_a = job.data) === null || _a === void 0 ? void 0 : _a._job_id;
1224
1452
  const jobType = job.name;
1453
+ const startedAt = Date.now();
1454
+ const eventStr = ((_c = (_b = job.data) === null || _b === void 0 ? void 0 : _b.event) !== null && _c !== void 0 ? _c : job.event);
1455
+ const eventParts = typeof eventStr === 'string' ? eventStr.split(':') : [];
1456
+ const jobParentTag = (_e = (_d = eventParts[0]) !== null && _d !== void 0 ? _d : eventStr) !== null && _e !== void 0 ? _e : undefined;
1457
+ const jobChildTag = eventParts.length >= 2 ? eventParts.slice(1).join(':') : undefined;
1458
+ // Resolve product and ensure logService is initialized so job lifecycle is always logged
1459
+ const productTag = (_f = job.data) === null || _f === void 0 ? void 0 : _f.product;
1460
+ if (productTag && this.workspace_id) {
1461
+ try {
1462
+ await this.productBuilderService.initializeProductByTag(productTag);
1463
+ this.productId = this.productBuilderService.fetchProductId();
1464
+ if (this.productId && !this.logService) {
1465
+ this.logService = new logs_service_1.default({
1466
+ product_id: this.productId,
1467
+ workspace_id: this.workspace_id,
1468
+ public_key: this.public_key,
1469
+ user_id: this.user_id,
1470
+ token: this.token,
1471
+ env_type: this.environment,
1472
+ });
1473
+ }
1474
+ if (this.logService) {
1475
+ this.logService.add({
1476
+ product_tag: productTag,
1477
+ product_id: this.productId,
1478
+ workspace_id: this.workspace_id,
1479
+ env: (_h = (_g = job.data) === null || _g === void 0 ? void 0 : _g.env) !== null && _h !== void 0 ? _h : '',
1480
+ process_id: jobId !== null && jobId !== void 0 ? jobId : (0, processor_utils_1.generateObjectId)(),
1481
+ type: types_1.LogEventTypes.JOB,
1482
+ parent_tag: jobParentTag,
1483
+ child_tag: jobChildTag,
1484
+ message: 'Job picked up for execution',
1485
+ data: {
1486
+ job_id: jobId,
1487
+ job_type: jobType,
1488
+ event: (_j = job.data) === null || _j === void 0 ? void 0 : _j.event,
1489
+ env: (_k = job.data) === null || _k === void 0 ? void 0 : _k.env,
1490
+ },
1491
+ status: types_1.LogEventStatus.PROCESSING,
1492
+ start: startedAt,
1493
+ });
1494
+ }
1495
+ }
1496
+ catch (e) {
1497
+ // Non-fatal: continue without job-level logging if product init fails
1498
+ }
1499
+ }
1225
1500
  // Update job status to running
1226
1501
  if (jobId && this.redisClient) {
1227
- await this.updateJobStatus(jobId, 'running', { started_at: Date.now() });
1502
+ await this.updateJobStatus(jobId, 'running', { started_at: startedAt });
1503
+ }
1504
+ // Fire-and-forget: record running phase (do not await)
1505
+ if (jobId && this.workspace_id) {
1506
+ const auth = Object.assign(Object.assign({}, this.getUserAccess()), { access_key: this.accessKey });
1507
+ if (!this.accessKey)
1508
+ console.warn('[runJobs] Updating job execution phase (running) without access_key', { jobId });
1509
+ void this.processorApiService
1510
+ .updateJobExecutionPhase({ workspace_id: this.workspace_id, job_id: jobId, phase: 'running', started_at: startedAt }, auth)
1511
+ .catch((err) => console.error('[runJobs] job execution phase running failed', { jobId, error: err }));
1228
1512
  }
1229
1513
  try {
1230
1514
  let result;
@@ -1260,56 +1544,193 @@ class ProcessorService {
1260
1544
  else {
1261
1545
  throw new Error(`Unknown job type: ${jobType}`);
1262
1546
  }
1547
+ const completedAt = Date.now();
1548
+ const durationMs = completedAt - startedAt;
1263
1549
  // Update job status to completed
1264
1550
  if (jobId && this.redisClient) {
1265
1551
  await this.updateJobStatus(jobId, 'completed', {
1266
- completed_at: Date.now(),
1552
+ completed_at: completedAt,
1267
1553
  result,
1268
1554
  });
1269
1555
  }
1556
+ // Fire-and-forget: record completed phase (do not await)
1557
+ if (jobId && this.workspace_id) {
1558
+ const auth = Object.assign(Object.assign({}, this.getUserAccess()), { access_key: this.accessKey });
1559
+ if (!this.accessKey)
1560
+ console.warn('[runJobs] Updating job execution phase (completed) without access_key', { jobId });
1561
+ const operation = typeof job.event === 'string' && job.event.includes(':')
1562
+ ? job.event.split(':').pop()
1563
+ : (_l = job.event) !== null && _l !== void 0 ? _l : undefined;
1564
+ const outputPayload = result != null
1565
+ ? typeof result === 'object' && result !== null && !Array.isArray(result)
1566
+ ? result
1567
+ : { value: result }
1568
+ : undefined;
1569
+ void this.processorApiService
1570
+ .updateJobExecutionPhase({
1571
+ workspace_id: this.workspace_id,
1572
+ job_id: jobId,
1573
+ phase: 'completed',
1574
+ completed_at: completedAt,
1575
+ duration_ms: durationMs,
1576
+ result_metadata: result != null ? { result: typeof result === 'object' ? result : { value: result } } : undefined,
1577
+ output: outputPayload,
1578
+ operation,
1579
+ }, auth)
1580
+ .catch((err) => console.error('[runJobs] job execution phase completed failed', { jobId, error: err }));
1581
+ }
1582
+ // Log job execution completed so it shows in logs
1583
+ if (this.logService) {
1584
+ this.logService.add({
1585
+ product_tag: (_m = this.productTag) !== null && _m !== void 0 ? _m : (_o = job.data) === null || _o === void 0 ? void 0 : _o.product,
1586
+ product_id: this.productId,
1587
+ workspace_id: this.workspace_id,
1588
+ env: (_q = (_p = job.data) === null || _p === void 0 ? void 0 : _p.env) !== null && _q !== void 0 ? _q : '',
1589
+ process_id: jobId !== null && jobId !== void 0 ? jobId : this.process_id,
1590
+ type: types_1.LogEventTypes.JOB,
1591
+ parent_tag: jobParentTag,
1592
+ child_tag: jobChildTag,
1593
+ message: 'Job execution completed',
1594
+ data: { job_id: jobId, job_type: jobType, duration_ms: durationMs, result },
1595
+ status: types_1.LogEventStatus.SUCCESS,
1596
+ start: startedAt,
1597
+ end: completedAt,
1598
+ });
1599
+ await this.logService.publish();
1600
+ }
1270
1601
  return result;
1271
1602
  }
1272
1603
  catch (error) {
1273
- // Update job status to failed or schedule retry
1274
- if (jobId && this.redisClient) {
1275
- const jobData = await this.getJobData(jobId);
1276
- if (jobData) {
1277
- const { shouldRetry, delay } = this.calculateJobRetry(jobData, error.code);
1278
- if (shouldRetry) {
1279
- await this.updateJobStatus(jobId, 'scheduled', {
1280
- retry_count: (jobData.retry_count || 0) + 1,
1281
- last_error: error.message,
1282
- last_error_code: error.code,
1283
- scheduled_at: Date.now() + delay,
1284
- });
1285
- // Re-queue the job with delay
1286
- await this.queues.jobs.add(jobType, job.data, {
1287
- jobId: `${jobId}_retry_${jobData.retry_count + 1}`,
1288
- delay,
1289
- });
1290
- }
1291
- else {
1292
- await this.updateJobStatus(jobId, 'failed', {
1293
- completed_at: Date.now(),
1294
- last_error: error.message,
1295
- last_error_code: error.code,
1296
- });
1604
+ const failedAt = Date.now();
1605
+ const jobData = jobId && this.redisClient ? await this.getJobData(jobId) : null;
1606
+ // Update job status to failed or schedule retry (when we have Redis job data)
1607
+ if (jobId && this.redisClient && jobData) {
1608
+ const { shouldRetry, delay } = this.calculateJobRetry(jobData, error.code);
1609
+ if (shouldRetry) {
1610
+ const retryCount = (jobData.retry_count || 0) + 1;
1611
+ await this.updateJobStatus(jobId, 'scheduled', {
1612
+ retry_count: retryCount,
1613
+ last_error: error.message,
1614
+ last_error_code: error.code,
1615
+ scheduled_at: Date.now() + delay,
1616
+ });
1617
+ // Fire-and-forget: record retry_scheduled phase (do not await)
1618
+ if (jobId && this.workspace_id) {
1619
+ const auth = Object.assign(Object.assign({}, this.getUserAccess()), { access_key: this.accessKey });
1620
+ if (!this.accessKey) {
1621
+ console.warn('[runJobs] Updating job execution phase without access_key — backend may return 401', { jobId, phase: 'retry_scheduled' });
1622
+ }
1623
+ void this.processorApiService
1624
+ .updateJobExecutionPhase({
1625
+ workspace_id: this.workspace_id,
1626
+ job_id: jobId,
1627
+ phase: 'retry_scheduled',
1628
+ error: error.message,
1629
+ error_code: error === null || error === void 0 ? void 0 : error.code,
1630
+ retry_count: retryCount,
1631
+ }, auth)
1632
+ .catch((err) => console.error('[runJobs] job execution phase retry_scheduled failed', { jobId, error: err }));
1297
1633
  }
1298
- // Add to execution history
1299
- await this.addJobExecution(jobId, {
1300
- number: (jobData.execution_count || 0) + 1,
1301
- started_at: jobData.started_at || Date.now(),
1302
- completed_at: Date.now(),
1303
- duration_ms: Date.now() - (jobData.started_at || Date.now()),
1304
- status: 'failed',
1305
- error: error.message,
1306
- error_code: error.code,
1634
+ // Re-queue the job with delay
1635
+ await this.queues.jobs.add(jobType, job.data, {
1636
+ jobId: `${jobId}_retry_${jobData.retry_count + 1}`,
1637
+ delay,
1307
1638
  });
1308
1639
  }
1640
+ else {
1641
+ await this.updateJobStatus(jobId, 'failed', {
1642
+ completed_at: failedAt,
1643
+ last_error: error.message,
1644
+ last_error_code: error.code,
1645
+ });
1646
+ }
1647
+ // Add to execution history
1648
+ await this.addJobExecution(jobId, {
1649
+ number: (jobData.execution_count || 0) + 1,
1650
+ started_at: jobData.started_at || Date.now(),
1651
+ completed_at: Date.now(),
1652
+ duration_ms: Date.now() - (jobData.started_at || Date.now()),
1653
+ status: 'failed',
1654
+ error: error.message,
1655
+ error_code: error.code,
1656
+ });
1657
+ }
1658
+ // Always record failed phase on JobExecutionTracker when we have jobId + workspace_id
1659
+ // (even when Redis job data is missing, so failures are visible in the tracker)
1660
+ if (jobId && this.workspace_id) {
1661
+ const auth = Object.assign(Object.assign({}, this.getUserAccess()), { access_key: this.accessKey });
1662
+ if (!this.accessKey) {
1663
+ console.warn('[runJobs] Updating job execution phase (failed) without access_key — backend may return 401', { jobId });
1664
+ }
1665
+ const durationMs = (jobData === null || jobData === void 0 ? void 0 : jobData.started_at) != null ? failedAt - jobData.started_at : failedAt - startedAt;
1666
+ const operation = typeof job.event === 'string' && job.event.includes(':')
1667
+ ? job.event.split(':').pop()
1668
+ : (_r = job.event) !== null && _r !== void 0 ? _r : undefined;
1669
+ void this.processorApiService
1670
+ .updateJobExecutionPhase({
1671
+ workspace_id: this.workspace_id,
1672
+ job_id: jobId,
1673
+ phase: 'failed',
1674
+ completed_at: failedAt,
1675
+ duration_ms: durationMs,
1676
+ error: (error === null || error === void 0 ? void 0 : error.message) != null ? String(error.message) : undefined,
1677
+ error_code: (error === null || error === void 0 ? void 0 : error.code) != null ? String(error.code) : undefined,
1678
+ operation,
1679
+ }, auth)
1680
+ .catch((err) => console.error('[runJobs] job execution phase failed (tracker update)', { jobId, error: err }));
1681
+ }
1682
+ // Log job execution failed so it shows in logs
1683
+ if (this.logService) {
1684
+ this.logService.add({
1685
+ product_tag: (_s = this.productTag) !== null && _s !== void 0 ? _s : (_t = job.data) === null || _t === void 0 ? void 0 : _t.product,
1686
+ product_id: this.productId,
1687
+ workspace_id: this.workspace_id,
1688
+ env: (_v = (_u = job.data) === null || _u === void 0 ? void 0 : _u.env) !== null && _v !== void 0 ? _v : '',
1689
+ process_id: jobId !== null && jobId !== void 0 ? jobId : this.process_id,
1690
+ type: types_1.LogEventTypes.JOB,
1691
+ parent_tag: jobParentTag,
1692
+ child_tag: jobChildTag,
1693
+ message: 'Job execution failed',
1694
+ data: {
1695
+ job_id: jobId,
1696
+ job_type: jobType,
1697
+ error: (error === null || error === void 0 ? void 0 : error.message) != null ? String(error.message) : undefined,
1698
+ error_code: (error === null || error === void 0 ? void 0 : error.code) != null ? String(error.code) : undefined,
1699
+ },
1700
+ status: types_1.LogEventStatus.FAIL,
1701
+ start: startedAt,
1702
+ end: failedAt,
1703
+ });
1704
+ await this.logService.publish();
1309
1705
  }
1310
1706
  throw error;
1311
1707
  }
1312
1708
  }
1709
+ /**
1710
+ * Record a failed phase on the job execution tracker (e.g. from BullMQ 'failed' handler).
1711
+ * Call when the worker job fails so the tracker is updated even if runJobs' catch didn't run.
1712
+ */
1713
+ async recordJobExecutionPhaseFailed(jobId, errorMessage, errorCode) {
1714
+ if (!jobId || !this.workspace_id)
1715
+ return;
1716
+ const auth = Object.assign(Object.assign({}, this.getUserAccess()), { access_key: this.accessKey });
1717
+ if (!this.accessKey)
1718
+ console.warn('[recordJobExecutionPhaseFailed] No access_key — backend may return 401', { jobId });
1719
+ const failedAt = Date.now();
1720
+ try {
1721
+ await this.processorApiService.updateJobExecutionPhase({
1722
+ workspace_id: this.workspace_id,
1723
+ job_id: jobId,
1724
+ phase: 'failed',
1725
+ completed_at: failedAt,
1726
+ error: errorMessage,
1727
+ error_code: errorCode,
1728
+ }, auth);
1729
+ }
1730
+ catch (err) {
1731
+ console.error('[recordJobExecutionPhaseFailed] tracker update failed', { jobId, error: err });
1732
+ }
1733
+ }
1313
1734
  /**
1314
1735
  * Get job data from Redis
1315
1736
  */
@@ -1785,7 +2206,7 @@ class ProcessorService {
1785
2206
  const payload = JSON.parse((0, processor_utils_1.decrypt)(String(appEnv.auth.data), this.productBuilderService.fetchPrivateKey()));
1786
2207
  let app = await this.fetchThirdPartyApp(access_tag);
1787
2208
  const auth = app.auths.find((item) => item.tag === appEnv.auth.auth_tag);
1788
- console.log('JAMESY', auth);
2209
+ debugLog('JAMESY', auth);
1789
2210
  if (!auth) {
1790
2211
  // throw an error
1791
2212
  throw new Error(`Cannot find auth ${appEnv.auth.auth_tag} on environment ${appEnv.product_env_slug}`);
@@ -1806,7 +2227,7 @@ class ProcessorService {
1806
2227
  request_base_url = env.base_url;
1807
2228
  }
1808
2229
  }
1809
- console.log('payloadabi!!!!', payload);
2230
+ debugLog('payloadabi!!!!', payload);
1810
2231
  const results = await this.sendActionRequest(request_base_url, url, payload, method, appEnv.app_env_slug);
1811
2232
  const values = (0, processor_utils_1.encrypt)(JSON.stringify(results), this.productBuilderService.fetchPrivateKey());
1812
2233
  const productApp = await this.productBuilderService.fetchApp(access_tag);
@@ -1980,7 +2401,8 @@ class ProcessorService {
1980
2401
  let payloads;
1981
2402
  let result;
1982
2403
  //const product = this.productBuilderService.fetchProduct();
1983
- if (cache_tag && this.redisClient) {
2404
+ // Check cache for existing result (skip if early cache check already done)
2405
+ if (cache_tag && this.redisClient && !event.skipCacheFetch) {
1984
2406
  const productCache = await this.productBuilderService.fetchCache(cache_tag);
1985
2407
  if (!productCache) {
1986
2408
  throw new Error('Invalid cache tag ');
@@ -2024,7 +2446,8 @@ class ProcessorService {
2024
2446
  throw new Error('Invalid cache tag ');
2025
2447
  }
2026
2448
  const inputString = JSON.stringify(event.input);
2027
- await this.addToCache({
2449
+ // Fire-and-forget cache store
2450
+ this.addToCache({
2028
2451
  input: inputString,
2029
2452
  privateKey: this.productBuilderService.fetchPrivateKey(),
2030
2453
  data: JSON.stringify(result),
@@ -2079,7 +2502,7 @@ class ProcessorService {
2079
2502
  this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Process http request - failed', failed_execution: true, data: { e: error, input: (0, processor_utils_1.anonymizeObject)(payloads) }, status: types_1.LogEventStatus.FAIL, app_id, action: event.event, start,
2080
2503
  end }));
2081
2504
  try {
2082
- console.log(e);
2505
+ debugLog(e);
2083
2506
  const value = await this.addToFailureOutput(e, event, {
2084
2507
  request_base_url,
2085
2508
  resource,
@@ -2305,7 +2728,7 @@ class ProcessorService {
2305
2728
  timeout: 15000,
2306
2729
  withCredentials: false,
2307
2730
  };
2308
- console.log('REQUEST!!!!', request);
2731
+ debugLog('REQUEST!!!!', request);
2309
2732
  const response = await axios_1.default.request(request);
2310
2733
  return response.data;
2311
2734
  }
@@ -2316,7 +2739,10 @@ class ProcessorService {
2316
2739
  }
2317
2740
  async processStorage(action) {
2318
2741
  //TODO: schema validation
2319
- const { env, input, retries, event, product: product_tag, session, cache } = action;
2742
+ var _a, _b, _c, _d, _e, _f, _g;
2743
+ const { env, input, retries, event, product: product_tag, session, cache, preloadedBootstrap } = action;
2744
+ // event is "storage_tag:operation" (e.g. gcp-storage:upload); backend looks up storage by tag only
2745
+ const storageTag = event.includes(':') ? event.split(':')[0] : event;
2320
2746
  const additional_logs = {
2321
2747
  parent_tag: event,
2322
2748
  type: types_1.LogEventTypes.STORAGE,
@@ -2337,19 +2763,26 @@ class ProcessorService {
2337
2763
  const process_id = (0, processor_utils_1.generateObjectId)();
2338
2764
  this.baseLogs = Object.assign({ product_tag: this.productTag, product_id: this.productId, workspace_id: this.workspace_id, env,
2339
2765
  process_id, data: this.clone }, additional_logs);
2340
- // Single bootstrap call to fetch all storage data
2341
- const bootstrapData = await this.productBuilderService.bootstrapStorage({
2342
- product_tag,
2343
- env_slug: env,
2344
- storage_tag: event,
2345
- });
2766
+ // Use preloaded bootstrap when provided (e.g. workflow batch prefetch), otherwise fetch
2767
+ const bootstrapData = preloadedBootstrap
2768
+ ? preloadedBootstrap
2769
+ : await this.productBuilderService.bootstrapStorage({
2770
+ product_tag,
2771
+ env_slug: env,
2772
+ storage_tag: storageTag,
2773
+ });
2346
2774
  // Initialize from bootstrap data
2347
2775
  this.productId = bootstrapData.product_id;
2348
2776
  this.processEnv = bootstrapData.env;
2349
2777
  // Process session if provided - verify and resolve $Session{} references
2350
2778
  if (session && bootstrapData.private_key) {
2351
2779
  const { processSessionForExecution } = await Promise.resolve().then(() => __importStar(require('../../sessions')));
2352
- const sessionResult = await processSessionForExecution(session, bootstrapData.private_key, input, env);
2780
+ const sessionResult = await processSessionForExecution(session, bootstrapData.private_key, input, env, {
2781
+ fetchSessionSelector: async (sessionTag) => {
2782
+ const sessionConfig = await this.productBuilderService.fetchSession(sessionTag);
2783
+ return sessionConfig === null || sessionConfig === void 0 ? void 0 : sessionConfig.selector;
2784
+ },
2785
+ });
2353
2786
  if (sessionResult.error) {
2354
2787
  throw new Error(`Session validation failed: ${sessionResult.error}`);
2355
2788
  }
@@ -2387,18 +2820,30 @@ class ProcessorService {
2387
2820
  const result = await this.runStorage(payload, additional_logs, {
2388
2821
  storage: bootstrapData.storage,
2389
2822
  storage_env: bootstrapData.storage_env,
2823
+ private_key: bootstrapData.private_key,
2390
2824
  });
2391
2825
  this.end = Date.now();
2392
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Storing file - success', data: { input: this.clone, result }, status: types_1.LogEventStatus.SUCCESS }));
2393
- await this.writeResult(types_1.LogEventStatus.SUCCESS);
2394
- await this.logService.publish();
2395
- return Object.assign(Object.assign({}, result), { process_id: this.process_id });
2826
+ if (this.logService) {
2827
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Storing file - success', data: { input: this.clone, result }, status: types_1.LogEventStatus.SUCCESS }));
2828
+ await this.writeResult(types_1.LogEventStatus.SUCCESS);
2829
+ await this.logService.publish();
2830
+ }
2831
+ return { process_id: this.process_id, output: result !== null && result !== void 0 ? result : {} };
2396
2832
  }
2397
2833
  catch (e) {
2398
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Storing file - failed', data: { e }, status: types_1.LogEventStatus.FAIL }));
2834
+ const err = e;
2835
+ const apiReason = (_b = (_a = err === null || err === void 0 ? void 0 : err.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.errors;
2836
+ const reason = typeof apiReason === 'string'
2837
+ ? apiReason
2838
+ : (_g = (_f = (_c = apiReason === null || apiReason === void 0 ? void 0 : apiReason.message) !== null && _c !== void 0 ? _c : (_e = (_d = err === null || err === void 0 ? void 0 : err.response) === null || _d === void 0 ? void 0 : _d.data) === null || _e === void 0 ? void 0 : _e.message) !== null && _f !== void 0 ? _f : err === null || err === void 0 ? void 0 : err.message) !== null && _g !== void 0 ? _g : String(e);
2839
+ const message = `Storing file - failed: ${reason}`;
2399
2840
  this.end = Date.now();
2400
- await this.logService.publish();
2401
- return { process_id: this.process_id };
2841
+ if (this.logService) {
2842
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message, data: { e, reason }, status: types_1.LogEventStatus.FAIL }));
2843
+ await this.logService.publish();
2844
+ }
2845
+ // Rethrow so the workflow step is marked failed and the executor can persist the error reason
2846
+ throw e;
2402
2847
  }
2403
2848
  }
2404
2849
  async processMessageBrokerSubscribe(data) {
@@ -2451,6 +2896,7 @@ class ProcessorService {
2451
2896
  }
2452
2897
  }
2453
2898
  async processMessageBrokerPublish(data) {
2899
+ var _a, _b, _c, _d;
2454
2900
  const [brokerTag, topicTag] = data.event.split(':');
2455
2901
  if (!brokerTag || !topicTag) {
2456
2902
  throw new Error(`message broker events should be in the format broker_tag:event_tag`);
@@ -2477,11 +2923,26 @@ class ProcessorService {
2477
2923
  await this.intializeProduct(additional_logs);
2478
2924
  this.baseLogs.product_id = this.productId;
2479
2925
  this.process_id = process_id;
2926
+ if (!this.logService) {
2927
+ this.logService = new logs_service_1.default({
2928
+ product_id: this.productId,
2929
+ workspace_id: this.workspace_id,
2930
+ public_key: this.public_key,
2931
+ user_id: this.user_id,
2932
+ token: this.token,
2933
+ env_type: this.environment,
2934
+ });
2935
+ }
2480
2936
  // Process session if provided - verify and resolve $Session{} references
2481
2937
  const privateKey = this.productBuilderService.fetchPrivateKey();
2482
2938
  if (data.session && privateKey) {
2483
2939
  const { processSessionForExecution } = await Promise.resolve().then(() => __importStar(require('../../sessions')));
2484
- const sessionResult = await processSessionForExecution(data.session, privateKey, data.input, data.env);
2940
+ const sessionResult = await processSessionForExecution(data.session, privateKey, data.input, data.env, {
2941
+ fetchSessionSelector: async (sessionTag) => {
2942
+ const sessionConfig = await this.productBuilderService.fetchSession(sessionTag);
2943
+ return sessionConfig === null || sessionConfig === void 0 ? void 0 : sessionConfig.selector;
2944
+ },
2945
+ });
2485
2946
  if (sessionResult.error) {
2486
2947
  throw new Error(`Session validation failed: ${sessionResult.error}`);
2487
2948
  }
@@ -2506,24 +2967,47 @@ class ProcessorService {
2506
2967
  };
2507
2968
  const result = await this.runBrokerPublish(payload);
2508
2969
  this.end = Date.now();
2509
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Publishing to topic - success', data: { input: (0, processor_utils_1.anonymizeObject)(this.clone), result }, status: types_1.LogEventStatus.SUCCESS }));
2970
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Produce to topic - success', data: { input: (0, processor_utils_1.anonymizeObject)(this.clone), result: (0, processor_utils_1.anonymizeObject)(result !== null && result !== void 0 ? result : {}) }, status: types_1.LogEventStatus.SUCCESS }));
2510
2971
  await this.writeResult(types_1.LogEventStatus.SUCCESS);
2511
- await this.logService.publish();
2512
- return result;
2972
+ // Fire-and-forget so step latency isn't dominated by log upload (20–50x slower otherwise)
2973
+ this.logService.publish().catch(() => { });
2974
+ return { process_id: this.process_id, output: Object.assign(Object.assign({}, (result !== null && result !== void 0 ? result : {})), { published: true }) };
2513
2975
  }
2514
2976
  catch (e) {
2515
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Publishing to topic - failed', data: { e }, status: types_1.LogEventStatus.FAIL }));
2977
+ const err = e;
2978
+ const apiReason = (_b = (_a = err === null || err === void 0 ? void 0 : err.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.errors;
2979
+ const reason = typeof apiReason === 'string'
2980
+ ? apiReason
2981
+ : (_d = (_c = apiReason === null || apiReason === void 0 ? void 0 : apiReason.message) !== null && _c !== void 0 ? _c : err === null || err === void 0 ? void 0 : err.message) !== null && _d !== void 0 ? _d : String(e);
2982
+ const message = `Publishing to topic - failed: ${reason}`;
2983
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message, data: { e, reason }, status: types_1.LogEventStatus.FAIL }));
2516
2984
  this.end = Date.now();
2517
2985
  await this.logService.publish();
2518
- return { process_id: this.process_id };
2986
+ // Rethrow so the workflow step is marked failed and the executor can persist the error reason
2987
+ throw e;
2519
2988
  }
2520
2989
  }
2521
2990
  async processJob(job, additional_logs = {}) {
2522
- var _a, _b, _c, _d, _e, _f, _g, _h;
2991
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
2992
+ await this.productBuilderService.initializeProductByTag(job.product);
2993
+ const productId = this.productBuilderService.fetchProductId();
2994
+ if (productId)
2995
+ this.productId = productId;
2523
2996
  const productJob = await this.productBuilderService.fetchJob(job.event);
2524
2997
  if (!productJob) {
2525
2998
  throw new Error(`Job ${job.event} not found`);
2526
2999
  }
3000
+ // Ensure logService exists so dispatch event is logged
3001
+ if (!this.logService && this.productId && this.workspace_id) {
3002
+ this.logService = new logs_service_1.default({
3003
+ product_id: this.productId,
3004
+ workspace_id: this.workspace_id,
3005
+ public_key: this.public_key,
3006
+ user_id: this.user_id,
3007
+ token: this.token,
3008
+ env_type: this.environment,
3009
+ });
3010
+ }
2527
3011
  await this.validateActionDataMappingInput(job.input, productJob.type);
2528
3012
  const NOW = Date.now();
2529
3013
  // Treat anything above Jan 1, 2023 as a timestamp (to be safe and future-proof)
@@ -2745,15 +3229,79 @@ class ProcessorService {
2745
3229
  // Add job input with the job ID for tracking
2746
3230
  jobInput._job_id = jobId;
2747
3231
  // Add job to queue
3232
+ if (!((_j = this.queues) === null || _j === void 0 ? void 0 : _j.jobs)) {
3233
+ throw new Error('Queues not configured. dispatch() requires a queue connection.');
3234
+ }
2748
3235
  await this.queues.jobs.add(productJob.type, jobInput, options);
3236
+ // Record job execution in integrations (so jobexecutiontrackers table is populated)
3237
+ if (this.workspace_id && this.productId) {
3238
+ const auth = Object.assign(Object.assign({}, this.getUserAccess()), { access_key: this.accessKey });
3239
+ if (!this.accessKey) {
3240
+ console.warn('[processJob] Creating job execution without access_key — backend may return 401', { jobId });
3241
+ }
3242
+ const operation = typeof job.event === 'string' && job.event.includes(':')
3243
+ ? job.event.split(':').pop()
3244
+ : (_k = job.event) !== null && _k !== void 0 ? _k : undefined;
3245
+ void this.processorApiService
3246
+ .createJobExecution({
3247
+ job_id: jobId,
3248
+ workspace_id: this.workspace_id,
3249
+ product_id: this.productId,
3250
+ product_tag: job.product,
3251
+ env: job.env,
3252
+ job_tag: job.event,
3253
+ job_type: productJob.type,
3254
+ phase: delay > 0 ? 'scheduled' : 'queued',
3255
+ scheduled_at: delay > 0 ? scheduled_at : undefined,
3256
+ triggered_by: job.triggered_by,
3257
+ input: job.input != null && typeof job.input === 'object'
3258
+ ? (0, processor_utils_1.truncateInputForApi)(job.input)
3259
+ : undefined,
3260
+ operation,
3261
+ }, auth)
3262
+ .catch((err) => console.error('[processJob] job execution create failed', { jobId, error: err }));
3263
+ }
3264
+ else {
3265
+ const missing = [];
3266
+ if (!this.workspace_id)
3267
+ missing.push('workspace_id');
3268
+ if (!this.productId)
3269
+ missing.push('productId');
3270
+ console.warn('[processJob] Skipping job execution create — missing:', missing.join(', '), { jobId });
3271
+ }
3272
+ // Log dispatch event so it shows in logs
3273
+ const dispatchStatus = delay > 0 ? 'scheduled' : 'queued';
3274
+ if (this.logService) {
3275
+ this.logService.add({
3276
+ product_tag: job.product,
3277
+ product_id: this.productId,
3278
+ workspace_id: this.workspace_id,
3279
+ env: job.env,
3280
+ process_id: jobId,
3281
+ type: types_1.LogEventTypes.JOB,
3282
+ message: 'Job dispatched',
3283
+ data: {
3284
+ job_id: jobId,
3285
+ job_type: productJob.type,
3286
+ event: job.event,
3287
+ status: dispatchStatus,
3288
+ scheduled_at,
3289
+ recurring: isRecurring,
3290
+ next_run_at,
3291
+ },
3292
+ status: types_1.LogEventStatus.SUCCESS,
3293
+ });
3294
+ await this.logService.publish();
3295
+ }
2749
3296
  return {
2750
3297
  job_id: jobId,
2751
- status: delay > 0 ? 'scheduled' : 'queued',
3298
+ status: dispatchStatus,
2752
3299
  scheduled_at,
2753
3300
  recurring: isRecurring,
2754
3301
  next_run_at,
2755
3302
  };
2756
3303
  }
3304
+ /** Expo: expoClient() is already a module-level singleton (one axios instance), so no per-run pool needed. */
2757
3305
  async sendExpoNotification(payload, device_tokens) {
2758
3306
  const message = {
2759
3307
  to: device_tokens,
@@ -2778,12 +3326,8 @@ class ProcessorService {
2778
3326
  tokens: device_tokens,
2779
3327
  };
2780
3328
  try {
2781
- const admin = require('firebase-admin');
2782
- const serviceAccount = credentials;
2783
- admin.initializeApp({
2784
- credential: admin.credential.cert(serviceAccount),
2785
- });
2786
- await admin.messaging().sendMulticast(message);
3329
+ const app = await this.getFirebaseApp(credentials);
3330
+ await app.messaging().sendEachForMulticast(message);
2787
3331
  }
2788
3332
  catch (e) {
2789
3333
  if (this.environment === types_1.EnvType.PRODUCTION) {
@@ -2791,49 +3335,73 @@ class ProcessorService {
2791
3335
  }
2792
3336
  }
2793
3337
  }
2794
- async ProcessExpoNotification(notification, template, payload, additional_logs) {
3338
+ async ProcessExpoNotification(notification, template, payload, additional_logs, logType = types_1.LogEventTypes.PUSH) {
3339
+ var _a, _b;
3340
+ debugLog('[ProcessExpoNotification] ENTRY', { deviceTokens: (_a = payload === null || payload === void 0 ? void 0 : payload.device_tokens) === null || _a === void 0 ? void 0 : _a.length, logType });
2795
3341
  (0, processor_utils_1.validateNotification)(template, payload);
2796
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Validate notification payload - success', data: {}, status: types_1.LogEventStatus.SUCCESS }));
3342
+ debugLog('[ProcessExpoNotification] Validation passed');
2797
3343
  const { title, body, data } = (0, processor_utils_1.generateNotificationTemplate)(template, payload);
2798
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Generate notification template - success', data: { title, body, data: (0, processor_utils_1.anonymizeObject)(data) }, status: types_1.LogEventStatus.SUCCESS }));
3344
+ debugLog('[ProcessExpoNotification] Template generated', { title: (_b = title === null || title === void 0 ? void 0 : title.slice) === null || _b === void 0 ? void 0 : _b.call(title, 0, 40), bodyLength: body === null || body === void 0 ? void 0 : body.length });
3345
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: logType, message: 'Generate notification template - success', data: { title, body, data }, status: types_1.LogEventStatus.SUCCESS }));
3346
+ debugLog('[ProcessExpoNotification] Sending to Expo');
2799
3347
  await this.sendExpoNotification({ title, body, data }, payload.device_tokens);
2800
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Send Expo notification - success', data: { title, body, data: (0, processor_utils_1.anonymizeObject)(data) }, status: types_1.LogEventStatus.SUCCESS }));
3348
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: logType, message: 'Send Expo notification - success', data: { title, body, data }, status: types_1.LogEventStatus.SUCCESS }));
2801
3349
  }
2802
- async ProcessFirebaseNotification(notification, template, payload, additional_logs) {
3350
+ async ProcessFirebaseNotification(notification, template, payload, additional_logs, logType = types_1.LogEventTypes.PUSH) {
3351
+ var _a, _b;
3352
+ debugLog('[ProcessFirebaseNotification] ENTRY', { deviceTokens: (_a = payload === null || payload === void 0 ? void 0 : payload.device_tokens) === null || _a === void 0 ? void 0 : _a.length, logType });
2803
3353
  (0, processor_utils_1.validateNotification)(template, payload);
2804
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Validate Firebase notification payload - success', data: {}, status: types_1.LogEventStatus.SUCCESS }));
3354
+ debugLog('[ProcessFirebaseNotification] Validation passed');
2805
3355
  const { title, body, data } = (0, processor_utils_1.generateNotificationTemplate)(template, payload);
2806
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Generate Firebase notification template - success', data: { title, body: (0, processor_utils_1.anonymizeObject)(data), data: (0, processor_utils_1.anonymizeObject)(data) }, status: types_1.LogEventStatus.SUCCESS }));
3356
+ debugLog('[ProcessFirebaseNotification] Template generated', { title: (_b = title === null || title === void 0 ? void 0 : title.slice) === null || _b === void 0 ? void 0 : _b.call(title, 0, 40), bodyLength: body === null || body === void 0 ? void 0 : body.length });
3357
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: logType, message: 'Generate Firebase notification template - success', data: { title, body, data }, status: types_1.LogEventStatus.SUCCESS }));
3358
+ debugLog('[ProcessFirebaseNotification] Sending to Firebase');
2807
3359
  await this.sendFirebaseNotification({ title, body, data }, payload.device_tokens, notification.credentials);
2808
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Send Firebase notification - success', data: { title, body: (0, processor_utils_1.anonymizeObject)(data), data: (0, processor_utils_1.anonymizeObject)(data) }, status: types_1.LogEventStatus.SUCCESS }));
3360
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: logType, message: 'Send Firebase notification - success', data: { title, body, data }, status: types_1.LogEventStatus.SUCCESS }));
2809
3361
  }
2810
3362
  async runNotification(notification, additional_logs, bootstrapData) {
2811
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
3363
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
2812
3364
  const { event } = notification;
2813
3365
  const input = notification.input;
3366
+ const logMessageLog = (channelType, status, err) => {
3367
+ if (!this.productId || !this.workspace_id || (bootstrapData === null || bootstrapData === void 0 ? void 0 : bootstrapData.product_tag) == null || (bootstrapData === null || bootstrapData === void 0 ? void 0 : bootstrapData.env) == null)
3368
+ return;
3369
+ this.fireAndForgetLogNotificationMessage(Object.assign({ workspace_id: this.workspace_id, product_id: this.productId, product_tag: bootstrapData.product_tag, env: bootstrapData.env, notification_tag: event, input: (input !== null && input !== void 0 ? input : {}), type: channelType, status, process_id: bootstrapData.process_id, retries: 0, session: bootstrapData.session, cache: bootstrapData.cache }, (status === 'failed' && err !== undefined && { error: err instanceof Error ? err.message : String(err) })));
3370
+ };
3371
+ debugLog('[runNotification] ENTRY', { event, env: (_a = notification.env) === null || _a === void 0 ? void 0 : _a.slug, hasBootstrap: !!bootstrapData, inputKeys: input ? Object.keys(input) : [] });
2814
3372
  try {
2815
3373
  let notificationEvent;
2816
3374
  let message;
2817
3375
  let envConfig;
2818
3376
  // Use bootstrap data if provided, otherwise fetch via API
2819
3377
  if (bootstrapData) {
3378
+ debugLog('[runNotification] Using bootstrap data');
2820
3379
  notificationEvent = bootstrapData.notification;
2821
3380
  message = bootstrapData.message;
2822
3381
  envConfig = bootstrapData.env_config;
2823
3382
  }
2824
3383
  else {
3384
+ debugLog('[runNotification] Fetching notification via API');
2825
3385
  // Fallback to original API-based fetching
2826
3386
  notificationEvent = (await this.productBuilderService.fetchNotification(event.split(':')[0]));
2827
3387
  message = await this.productBuilderService.fetchNotificationMessage(event);
2828
3388
  if (!message) {
2829
3389
  throw new Error(`Message ${event} not found`);
2830
3390
  }
2831
- envConfig = (_a = notificationEvent.envs) === null || _a === void 0 ? void 0 : _a.find((data) => data.slug === notification.env.slug);
3391
+ envConfig = (_b = notificationEvent.envs) === null || _b === void 0 ? void 0 : _b.find((data) => data.slug === notification.env.slug);
2832
3392
  }
2833
3393
  if (!envConfig) {
3394
+ debugLog('[runNotification] ERROR: env config not found', { envSlug: (_c = notification.env) === null || _c === void 0 ? void 0 : _c.slug });
2834
3395
  throw new Error(`Notification env config for ${notification.env.slug} not found`);
2835
3396
  }
2836
3397
  let { push_notifications: notifications, emails, callbacks, sms: smses, } = envConfig;
3398
+ debugLog('[runNotification] Env config channels', {
3399
+ hasPush: !!notifications,
3400
+ pushType: notifications === null || notifications === void 0 ? void 0 : notifications.type,
3401
+ hasEmails: !!emails,
3402
+ hasCallbacks: !!callbacks,
3403
+ hasSms: !!smses,
3404
+ });
2837
3405
  // Resolve any $Secret{} references in notification configs
2838
3406
  const secretsService = (0, secrets_1.getSecretsService)();
2839
3407
  if (secretsService) {
@@ -2855,36 +3423,73 @@ class ProcessorService {
2855
3423
  }
2856
3424
  }
2857
3425
  const { push_notification: push, email, callback, sms } = message;
2858
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Fetching notification', data: notificationEvent, status: types_1.LogEventStatus.SUCCESS }));
2859
- if (push) {
3426
+ debugLog('[runNotification] Message template flags', { push: !!push, email: !!email, callback: !!callback, sms: !!sms });
3427
+ debugLog('[runNotification] Input channels present', {
3428
+ push_notification: !!input.push_notification,
3429
+ email: !!input.email,
3430
+ callback: !!input.callback,
3431
+ sms: !!input.sms,
3432
+ });
3433
+ if (!push && (input.push_notification || notifications)) {
3434
+ debugLog('[runNotification] PUSH: skipped (message has no push template)', { hasInputPush: !!input.push_notification, hasNotifications: !!notifications });
3435
+ }
3436
+ if (push && !input.push_notification) {
3437
+ debugLog('[runNotification] PUSH: skipped (no input.push_notification)');
3438
+ }
3439
+ if (push && input.push_notification) {
3440
+ debugLog('[runNotification] PUSH: resolving title/body/data');
2860
3441
  input.push_notification.title = (0, processor_utils_1.replacePlaceholderString)(push.title, input.push_notification.title || {});
2861
3442
  input.push_notification.body = await this.generatePayload(input.push_notification.body || {}, notification, additional_logs, message.push_notification_data.filter((data) => data.parent_key === 'body') || []);
2862
3443
  input.push_notification.data = await this.generatePayload(input.push_notification.data || {}, notification, additional_logs, message.push_notification_data.filter((data) => data.parent_key === 'data') || []);
2863
3444
  }
2864
- const validationPayload = (await this.inputService.parseJson({
2865
- data: Object.assign(Object.assign({}, input.push_notification.title), input.push_notification.body),
2866
- expected: types_1.ExpectedValues.PARSEINPUT,
2867
- }));
2868
- //await this.inputService.validateInput(validationPayload, message.push_notification_data, "Push Notifications");
2869
- if (push && notifications.type === types_1.Notifiers.EXPO) {
3445
+ if (push && input.push_notification) {
3446
+ const validationPayload = (await this.inputService.parseJson({
3447
+ data: Object.assign(Object.assign({}, input.push_notification.title), input.push_notification.body),
3448
+ expected: types_1.ExpectedValues.PARSEINPUT,
3449
+ }));
3450
+ //await this.inputService.validateInput(validationPayload, message.push_notification_data, "Push Notifications");
3451
+ }
3452
+ if (push && input.push_notification && (notifications === null || notifications === void 0 ? void 0 : notifications.type) !== types_1.Notifiers.EXPO && (notifications === null || notifications === void 0 ? void 0 : notifications.type) !== types_1.Notifiers.FIREBASE) {
3453
+ debugLog('[runNotification] PUSH: skipped (not Expo or Firebase)', { notificationsType: notifications === null || notifications === void 0 ? void 0 : notifications.type });
3454
+ this.lastNotificationFailureType = types_1.LogEventTypes.PUSH;
3455
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.PUSH, message: 'Push skipped - no Expo or Firebase provider configured', data: { push_type: notifications === null || notifications === void 0 ? void 0 : notifications.type }, status: types_1.LogEventStatus.SUCCESS }));
3456
+ }
3457
+ if (push && input.push_notification && (notifications === null || notifications === void 0 ? void 0 : notifications.type) === types_1.Notifiers.EXPO) {
3458
+ debugLog('[runNotification] PUSH: processing Expo');
3459
+ this.lastNotificationFailureType = types_1.LogEventTypes.PUSH;
2870
3460
  try {
2871
3461
  await this.ProcessExpoNotification(notifications, message, input.push_notification, additional_logs);
2872
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { successful_execution: true, message: 'Processing Expo notification - success', data: {}, status: types_1.LogEventStatus.SUCCESS }));
3462
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.PUSH, successful_execution: true, message: 'Processing Expo notification - success', data: {}, status: types_1.LogEventStatus.SUCCESS }));
3463
+ logMessageLog('push', 'sent');
3464
+ debugLog('[runNotification] PUSH (Expo): success');
2873
3465
  }
2874
3466
  catch (e) {
2875
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { failed_execution: true, message: 'Processing Expo notification - failed', data: {}, status: types_1.LogEventStatus.SUCCESS }));
3467
+ debugLog('[runNotification] PUSH (Expo): failed', e);
3468
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.PUSH, failed_execution: true, message: 'Processing Expo notification - failed', data: {}, status: types_1.LogEventStatus.FAIL }));
3469
+ logMessageLog('push', 'failed', e);
2876
3470
  }
2877
3471
  }
2878
- if (push && notifications.type === types_1.Notifiers.FIREBASE) {
3472
+ if (push && input.push_notification && (notifications === null || notifications === void 0 ? void 0 : notifications.type) === types_1.Notifiers.FIREBASE) {
3473
+ debugLog('[runNotification] PUSH: processing Firebase');
3474
+ this.lastNotificationFailureType = types_1.LogEventTypes.PUSH;
2879
3475
  try {
2880
3476
  await this.ProcessFirebaseNotification(notifications, message, input.push_notification, additional_logs);
2881
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { successful_execution: true, message: 'Processing Firebase notification - success', data: { notification, input: (0, processor_utils_1.anonymizeObject)(input.push_notification) }, status: types_1.LogEventStatus.SUCCESS }));
3477
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.PUSH, successful_execution: true, message: 'Processing Firebase notification - success', data: { notification }, status: types_1.LogEventStatus.SUCCESS }));
3478
+ logMessageLog('push', 'sent');
3479
+ debugLog('[runNotification] PUSH (Firebase): success');
2882
3480
  }
2883
3481
  catch (e) {
2884
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { failed_execution: true, message: 'Processing Firebase notification - failed', data: { notification, input: (0, processor_utils_1.anonymizeObject)(input.push_notification) }, status: types_1.LogEventStatus.FAIL }));
3482
+ debugLog('[runNotification] PUSH (Firebase): failed', e);
3483
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.PUSH, failed_execution: true, message: 'Processing Firebase notification - failed', data: { notification, input: input.push_notification }, status: types_1.LogEventStatus.FAIL }));
3484
+ logMessageLog('push', 'failed', e);
2885
3485
  }
2886
3486
  }
2887
- if (email && emails) {
3487
+ if (email && emails && !input.email) {
3488
+ debugLog('[runNotification] EMAIL: skipped (no input.email)');
3489
+ }
3490
+ if (email && emails && input.email) {
3491
+ debugLog('[runNotification] EMAIL: processing (subject, template, recipients)');
3492
+ this.lastNotificationFailureType = types_1.LogEventTypes.EMAIL;
2888
3493
  input.email.subject = await this.generatePayload(input.email.subject, notification, additional_logs, message.email_data.filter((data) => data.parent_key === 'subject'));
2889
3494
  input.email.template = await this.generatePayload(input.email.template, notification, additional_logs, message.email_data.filter((data) => data.parent_key === 'template'));
2890
3495
  input.email.recipients = await Promise.all(input.email.recipients.map(async (email) => await this.generateStringValues(email, notification.event, additional_logs)));
@@ -2895,14 +3500,13 @@ class ProcessorService {
2895
3500
  //await this.inputService.validateInput(validationPayload, message.email_data);
2896
3501
  input.email.recipients.map((email) => this.inputService.validateEmailString({ key: 'to', value: email }));
2897
3502
  const { sender_email: from } = emails, auth = __rest(emails, ["sender_email"]);
2898
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Attempt email auth fetch - success', data: { from: (0, processor_utils_1.anonymizeValue)(from), host: (0, processor_utils_1.anonymizeValue)(auth.host), port: (0, processor_utils_1.anonymizeValue)(auth.port) }, status: types_1.LogEventStatus.SUCCESS }));
2899
3503
  const templateMaker = (0, handlebars_1.compile)(email.template);
2900
3504
  const template = templateMaker(input.email.template);
2901
3505
  const subject = (0, processor_utils_1.replacePlaceholderString)(email.subject, input.email.subject || {});
2902
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Generate email template - success', data: {
2903
- template: (0, processor_utils_1.anonymizeValue)(template),
2904
- subject: (0, processor_utils_1.anonymizeValue)(subject),
2905
- input: (0, processor_utils_1.anonymizeObject)(input.email),
3506
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.EMAIL, message: 'Generate email template - success', data: {
3507
+ template,
3508
+ subject,
3509
+ input: input.email,
2906
3510
  }, status: types_1.LogEventStatus.SUCCESS }));
2907
3511
  const mailOptions = {
2908
3512
  from,
@@ -2910,57 +3514,115 @@ class ProcessorService {
2910
3514
  subject,
2911
3515
  template,
2912
3516
  };
3517
+ debugLog('[runNotification] EMAIL: sending mail', { to: (_d = mailOptions.to) === null || _d === void 0 ? void 0 : _d.length, subject: (_f = (_e = mailOptions.subject) === null || _e === void 0 ? void 0 : _e.slice) === null || _f === void 0 ? void 0 : _f.call(_e, 0, 50) });
2913
3518
  try {
2914
- const transporter = await (0, processor_utils_1.mailerClient)(auth);
2915
- const response = await transporter.sendMail(mailOptions);
2916
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Send email - success', successful_execution: true, data: { response }, status: types_1.LogEventStatus.SUCCESS }));
3519
+ const transporter = await this.getMailTransporter(auth);
3520
+ await transporter.sendMail(mailOptions);
3521
+ logMessageLog('email', 'sent');
2917
3522
  }
2918
3523
  catch (e) {
2919
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { failed_execution: true, message: 'Send email - failed', data: { e }, status: types_1.LogEventStatus.FAIL }));
3524
+ debugLog('[runNotification] EMAIL: send failed', e);
3525
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.EMAIL, failed_execution: true, message: 'Send email - failed', data: { e }, status: types_1.LogEventStatus.FAIL }));
3526
+ logMessageLog('email', 'failed', e);
2920
3527
  }
2921
3528
  }
2922
- if (callback && callbacks) {
3529
+ if (callback && !callbacks) {
3530
+ debugLog('[runNotification] CALLBACK: skipped (no callback config in env)');
3531
+ this.lastNotificationFailureType = types_1.LogEventTypes.CALLBACKS;
3532
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.CALLBACKS, message: 'Callback skipped - no callback config in env', data: {}, status: types_1.LogEventStatus.SUCCESS }));
3533
+ }
3534
+ if (callback && callbacks && !input.callback) {
3535
+ debugLog('[runNotification] CALLBACK: skipped (no input.callback)');
3536
+ }
3537
+ if (callback && callbacks && input.callback) {
3538
+ debugLog('[runNotification] CALLBACK: processing', { url: callbacks.url, method: callbacks.method });
3539
+ this.lastNotificationFailureType = types_1.LogEventTypes.CALLBACKS;
2923
3540
  const payload = {
2924
- query: Object.assign(Object.assign({}, (_b = input.callback) === null || _b === void 0 ? void 0 : _b.query), (_c = callbacks.auth) === null || _c === void 0 ? void 0 : _c.query),
2925
- headers: Object.assign(Object.assign({}, (_d = input.callback) === null || _d === void 0 ? void 0 : _d.headers), (_e = callbacks.auth) === null || _e === void 0 ? void 0 : _e.headers),
2926
- params: Object.assign(Object.assign({}, (_f = input.callback) === null || _f === void 0 ? void 0 : _f.params), (_g = callbacks.auth) === null || _g === void 0 ? void 0 : _g.params),
2927
- body: Object.assign(Object.assign({}, (_h = input.callback) === null || _h === void 0 ? void 0 : _h.body), (_j = callbacks.auth) === null || _j === void 0 ? void 0 : _j.body),
3541
+ query: Object.assign(Object.assign({}, (_g = input.callback) === null || _g === void 0 ? void 0 : _g.query), (_h = callbacks.auth) === null || _h === void 0 ? void 0 : _h.query),
3542
+ headers: Object.assign(Object.assign({}, (_j = input.callback) === null || _j === void 0 ? void 0 : _j.headers), (_k = callbacks.auth) === null || _k === void 0 ? void 0 : _k.headers),
3543
+ params: Object.assign(Object.assign({}, (_l = input.callback) === null || _l === void 0 ? void 0 : _l.params), (_m = callbacks.auth) === null || _m === void 0 ? void 0 : _m.params),
3544
+ body: Object.assign(Object.assign({}, (_o = input.callback) === null || _o === void 0 ? void 0 : _o.body), (_p = callbacks.auth) === null || _p === void 0 ? void 0 : _p.body),
2928
3545
  };
2929
3546
  input.callback.body = await this.generatePayload(payload.body, notification, additional_logs, message.callback_data.filter((data) => data.parent_key === 'body'));
2930
3547
  input.callback.query = await this.generatePayload(payload.query, notification, additional_logs, message.callback_data.filter((data) => data.parent_key === 'query'));
2931
- input.callback.params = await this.generatePayload(payload.body, notification, additional_logs, message.callback_data.filter((data) => data.parent_key === 'params'));
2932
- input.callback.headers = await this.generatePayload(payload.body, notification, additional_logs, message.callback_data.filter((data) => data.parent_key === 'headers'));
3548
+ input.callback.params = await this.generatePayload(payload.params, notification, additional_logs, message.callback_data.filter((data) => data.parent_key === 'params'));
3549
+ input.callback.headers = await this.generatePayload(payload.headers, notification, additional_logs, message.callback_data.filter((data) => data.parent_key === 'headers'));
2933
3550
  const validationPayload = (await this.inputService.parseJson({
2934
3551
  data: input.callback,
2935
3552
  expected: types_1.ExpectedValues.PARSEINPUT,
2936
3553
  }));
2937
3554
  //this.inputService.validateInput(validationPayload, message.callback_data);
2938
- const url = new URL(callbacks.url);
3555
+ const callbackUrl = callbacks === null || callbacks === void 0 ? void 0 : callbacks.url;
3556
+ if (callbackUrl == null || callbackUrl === '') {
3557
+ throw new Error(`Callback config has no url. Env callback config: ${JSON.stringify({ url: callbacks === null || callbacks === void 0 ? void 0 : callbacks.url, method: callbacks === null || callbacks === void 0 ? void 0 : callbacks.method, keys: callbacks ? Object.keys(callbacks) : [] })}`);
3558
+ }
3559
+ const url = new URL(callbackUrl);
3560
+ const requestPayload = {
3561
+ query: Object.assign(Object.assign({}, (_q = input.callback) === null || _q === void 0 ? void 0 : _q.query), (_r = callbacks.auth) === null || _r === void 0 ? void 0 : _r.query),
3562
+ headers: Object.assign(Object.assign({}, (_s = input.callback) === null || _s === void 0 ? void 0 : _s.headers), (_t = callbacks.auth) === null || _t === void 0 ? void 0 : _t.headers),
3563
+ params: Object.assign(Object.assign({}, (_u = input.callback) === null || _u === void 0 ? void 0 : _u.params), (_v = callbacks.auth) === null || _v === void 0 ? void 0 : _v.params),
3564
+ body: Object.assign(Object.assign({}, (_w = input.callback) === null || _w === void 0 ? void 0 : _w.body), (_x = callbacks.auth) === null || _x === void 0 ? void 0 : _x.body),
3565
+ };
2939
3566
  try {
2940
- await this.sendActionRequest(url.origin, url.pathname, payload, callbacks.method, '');
2941
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { successful_execution: true, name: 'Send callback - success', data: {}, status: types_1.LogEventStatus.SUCCESS }));
3567
+ await this.sendActionRequest(url.origin, url.pathname, requestPayload, callbacks.method, '');
3568
+ debugLog('[runNotification] CALLBACK: success');
3569
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.CALLBACKS, successful_execution: true, name: 'Send callback - success', data: {}, status: types_1.LogEventStatus.SUCCESS }));
3570
+ logMessageLog('callback', 'sent');
2942
3571
  }
2943
3572
  catch (e) {
2944
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { failed_execution: true, message: 'Send callback - failed', data: { e }, status: types_1.LogEventStatus.FAIL }));
3573
+ debugLog('[runNotification] CALLBACK: failed', e);
3574
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.CALLBACKS, failed_execution: true, message: 'Send callback - failed', data: { e }, status: types_1.LogEventStatus.FAIL }));
3575
+ logMessageLog('callback', 'failed', e);
2945
3576
  }
2946
3577
  }
2947
- if (sms && smses) {
3578
+ if (sms && !smses) {
3579
+ debugLog('[runNotification] SMS: skipped (no SMS config in env)');
3580
+ this.lastNotificationFailureType = types_1.LogEventTypes.SMS;
3581
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.SMS, message: 'SMS skipped - no SMS config in env', data: {}, status: types_1.LogEventStatus.SUCCESS }));
3582
+ }
3583
+ if (sms && smses && !input.sms) {
3584
+ debugLog('[runNotification] SMS: skipped (no input.sms)');
3585
+ }
3586
+ if (sms && smses && input.sms) {
3587
+ debugLog('[runNotification] SMS: processing', { recipients: (_y = input.sms.recipients) === null || _y === void 0 ? void 0 : _y.length });
3588
+ this.lastNotificationFailureType = types_1.LogEventTypes.SMS;
2948
3589
  try {
2949
3590
  input.sms.body = (await (0, processor_utils_1.replacePlaceholderString)(sms, input.sms.body));
2950
- const SmsClient = await (0, sms_repo_1.loadSMSClient)();
2951
- const smsClient = new SmsClient(smses);
2952
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { name: 'Send sms - initiated', data: { message: input.sms.body, config: (0, processor_utils_1.anonymizeObject)(smses) }, status: types_1.LogEventStatus.SUCCESS }));
3591
+ const smsClient = await this.getSmsClient(smses);
3592
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.SMS, name: 'Send sms - initiated', data: { message: input.sms.body, config: smses }, status: types_1.LogEventStatus.SUCCESS }));
2953
3593
  const res = await smsClient.sendMessage(input.sms.body, input.sms.recipients);
2954
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { name: 'Send sms - success', successful_execution: true, data: res, status: types_1.LogEventStatus.SUCCESS }));
3594
+ if (res && res.success !== undefined && !res.success) {
3595
+ throw new Error(res.error);
3596
+ }
3597
+ debugLog('[runNotification] SMS: success', { res: typeof res });
3598
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.SMS, name: 'Send sms - success', successful_execution: true, data: res, status: types_1.LogEventStatus.SUCCESS }));
3599
+ logMessageLog('sms', 'sent');
2955
3600
  }
2956
3601
  catch (e) {
2957
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { failed_execution: true, message: 'Process sms - failed', data: { e }, status: types_1.LogEventStatus.FAIL }));
3602
+ debugLog('[runNotification] SMS: failed', e);
3603
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.SMS, failed_execution: true, message: 'Process sms - failed', data: { e }, status: types_1.LogEventStatus.FAIL }));
3604
+ logMessageLog('sms', 'failed', e);
2958
3605
  }
2959
3606
  }
2960
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Attempt notification - success', data: notification, status: types_1.LogEventStatus.SUCCESS }));
3607
+ debugLog('[runNotification] DONE: all channels processed', { lastChannelType: (_z = this.lastNotificationFailureType) !== null && _z !== void 0 ? _z : 'NOTIFICATIONS' });
3608
+ // Only add aggregate success log when we have a subtype (no NOTIFICATIONS-typed logs)
3609
+ /*if (this.lastNotificationFailureType != null) {
3610
+ this.logService.add({
3611
+ ...this.baseLogs,
3612
+ ...additional_logs,
3613
+ type: this.lastNotificationFailureType,
3614
+ message: 'Attempt notification - success',
3615
+ data: notification,
3616
+ status: LogEventStatus.SUCCESS,
3617
+ });
3618
+ }*/
2961
3619
  }
2962
3620
  catch (e) {
2963
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { failed_execution: true, message: 'Attempt notification - failed', data: { e: e.toString() }, status: types_1.LogEventStatus.FAIL }));
3621
+ debugLog('[runNotification] ERROR', { error: e, lastChannelType: (_0 = this.lastNotificationFailureType) !== null && _0 !== void 0 ? _0 : 'NOTIFICATIONS' });
3622
+ // Only add aggregate failure log when we have a subtype (no NOTIFICATIONS-typed logs)
3623
+ if (this.lastNotificationFailureType != null) {
3624
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: this.lastNotificationFailureType, failed_execution: true, message: 'Attempt notification - failed', data: { e: e.toString() }, status: types_1.LogEventStatus.FAIL }));
3625
+ }
2964
3626
  //await this.logService.publish();
2965
3627
  throw e;
2966
3628
  }
@@ -3070,9 +3732,10 @@ class ProcessorService {
3070
3732
  storageEnv = bootstrapData.storage_env;
3071
3733
  }
3072
3734
  else {
3073
- // Fallback to original API-based fetching
3735
+ // Fallback to original API-based fetching (event may be "storage_tag:operation", lookup by storage tag only)
3736
+ const storageTag = event.includes(':') ? event.split(':')[0] : event;
3074
3737
  await this.intializeProduct(additional_logs);
3075
- storage = await this.productBuilderService.fetchStorage(event);
3738
+ storage = await this.productBuilderService.fetchStorage(storageTag);
3076
3739
  storageEnv = storage.envs.find((el) => el.slug === env.slug);
3077
3740
  }
3078
3741
  if (!storageEnv) {
@@ -3105,14 +3768,15 @@ class ProcessorService {
3105
3768
  input.mimeType = input.mimeType
3106
3769
  ? await this.generateStringValues(input.mimeType, '', additional_logs, [])
3107
3770
  : undefined;
3108
- result = await this.processStorageRequest(data, input, storageEnv, additional_logs);
3771
+ result = await this.processStorageRequest(data, input, storageEnv, additional_logs, bootstrapData === null || bootstrapData === void 0 ? void 0 : bootstrapData.private_key);
3109
3772
  if (cache_tag && this.redisClient) {
3110
3773
  const productCache = await this.productBuilderService.fetchCache(cache_tag);
3111
3774
  if (!productCache) {
3112
3775
  throw new Error('Invalid cache tag ');
3113
3776
  }
3114
3777
  const inputString = JSON.stringify(input);
3115
- await this.addToCache({
3778
+ // Fire-and-forget cache store
3779
+ this.addToCache({
3116
3780
  input: inputString,
3117
3781
  privateKey: this.productBuilderService.fetchPrivateKey(),
3118
3782
  data: JSON.stringify(result),
@@ -3158,10 +3822,25 @@ class ProcessorService {
3158
3822
  }
3159
3823
  url = queueUrl.url;
3160
3824
  }
3161
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Fetch broker details - success', data: { event, broker }, status: types_1.LogEventStatus.SUCCESS }));
3825
+ /*this.logService.add({
3826
+ ...this.baseLogs,
3827
+ ...additional_logs,
3828
+ message: 'Fetch broker details - success',
3829
+ data: { event, broker },
3830
+ status: LogEventStatus.SUCCESS,
3831
+ });*/
3832
+ let brokerConfig = brokerEnv.config;
3833
+ if (brokerConfig && (0, secrets_1.mightContainSecrets)(brokerConfig)) {
3834
+ const secretsService = (0, secrets_1.getSecretsService)();
3835
+ if (!secretsService) {
3836
+ throw new Error('Broker configuration contains secret references ($secret{...}) but secrets service is not initialized. Ensure secrets are configured for this environment.');
3837
+ }
3838
+ const resolved = await secretsService.resolve(brokerConfig, { env: env.slug });
3839
+ brokerConfig = resolved.value;
3840
+ }
3162
3841
  const createBrokerService = await loadBrokerService();
3163
3842
  if (createBrokerService) {
3164
- const brokerService = createBrokerService(brokerEnv.type, brokerEnv.config);
3843
+ const brokerService = createBrokerService(brokerEnv.type, brokerConfig);
3165
3844
  await brokerService.subscribe(url, input.callback);
3166
3845
  this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { successful_execution: true, message: 'Subscribe to broker topic - success', data: { event }, status: types_1.LogEventStatus.SUCCESS }));
3167
3846
  return;
@@ -3177,10 +3856,14 @@ class ProcessorService {
3177
3856
  }
3178
3857
  }
3179
3858
  async runBrokerPublish(data, additional_logs = {}) {
3859
+ var _a, _b, _c, _d;
3180
3860
  const { env, event } = data;
3181
3861
  const input = data.input;
3182
3862
  try {
3183
- await this.intializeProduct(additional_logs);
3863
+ // Skip redundant init when already initialized (e.g. same workflow run / same product)
3864
+ if (!this.productId) {
3865
+ await this.intializeProduct(additional_logs);
3866
+ }
3184
3867
  const [brokerTag, topicTag] = event.split(':');
3185
3868
  const broker = await this.productBuilderService.fetchMessageBroker(brokerTag);
3186
3869
  if (!broker) {
@@ -3205,25 +3888,48 @@ class ProcessorService {
3205
3888
  }
3206
3889
  url = queueUrl.url;
3207
3890
  }
3208
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Fetch broker details - success', data: { event, broker }, status: types_1.LogEventStatus.SUCCESS }));
3209
- const createBrokerService = await loadBrokerService();
3210
- if (createBrokerService) {
3211
- const brokerService = createBrokerService(brokerEnv.type, brokerEnv.config);
3212
- await brokerService.publish(url, input.message);
3213
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Publish to broker topic - success', successful_execution: true, data: { event }, status: types_1.LogEventStatus.SUCCESS }));
3214
- return;
3215
- }
3216
- else {
3217
- throw new Error(`Running in browser, broker service not loaded.`);
3218
- }
3891
+ /* this.logService.add({
3892
+ ...this.baseLogs,
3893
+ ...additional_logs,
3894
+ message: 'Fetch broker details - success',
3895
+ data: { event, broker },
3896
+ status: LogEventStatus.SUCCESS,
3897
+ });*/
3898
+ let brokerConfig = brokerEnv.config;
3899
+ if (brokerConfig && (0, secrets_1.mightContainSecrets)(brokerConfig)) {
3900
+ const secretsService = (0, secrets_1.getSecretsService)();
3901
+ if (!secretsService) {
3902
+ throw new Error('Broker configuration contains secret references ($secret{...}) but secrets service is not initialized. Ensure secrets are configured for this environment.');
3903
+ }
3904
+ const resolved = await secretsService.resolve(brokerConfig, { env: env.slug });
3905
+ brokerConfig = resolved.value;
3906
+ }
3907
+ const brokerService = await this.getBrokerServiceForPublish(brokerEnv.type, brokerConfig);
3908
+ await brokerService.publish(url, input.message);
3909
+ /*this.logService.add({
3910
+ ...this.baseLogs,
3911
+ ...additional_logs,
3912
+ message: 'Publish to broker topic - success',
3913
+ successful_execution: true,
3914
+ data: { event },
3915
+ status: LogEventStatus.SUCCESS,
3916
+ });*/
3917
+ return { published: true };
3219
3918
  //return this.processStorageRequest(data, input, storageEnv, additional_logs);
3220
3919
  }
3221
3920
  catch (e) {
3222
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { failed_execution: true, message: 'Attempt publish to broker topic - failed', data: { e }, status: types_1.LogEventStatus.FAIL }));
3921
+ const err = e;
3922
+ const apiReason = (_b = (_a = err === null || err === void 0 ? void 0 : err.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.errors;
3923
+ const reason = typeof apiReason === 'string'
3924
+ ? apiReason
3925
+ : (_d = (_c = apiReason === null || apiReason === void 0 ? void 0 : apiReason.message) !== null && _c !== void 0 ? _c : err === null || err === void 0 ? void 0 : err.message) !== null && _d !== void 0 ? _d : String(e);
3926
+ const message = `Attempt publish to broker topic - failed: ${reason}`;
3927
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { failed_execution: true, message, data: { e, reason }, status: types_1.LogEventStatus.FAIL }));
3223
3928
  throw e;
3224
3929
  }
3225
3930
  }
3226
- async processStorageRequest(data, input, storageEnv, additional_logs) {
3931
+ async processStorageRequest(data, input, storageEnv, additional_logs, decryptionKey) {
3932
+ var _a, _b, _c, _d, _e, _f, _g;
3227
3933
  try {
3228
3934
  /*const result = await this.processorApiService.processProduct(
3229
3935
  this.productId,
@@ -3236,7 +3942,23 @@ class ProcessorService {
3236
3942
  },
3237
3943
  this.getUserAccess(),
3238
3944
  );*/
3239
- const cloudConfig = storageEnv.config;
3945
+ // Bootstrap returns raw storage_env; config may be encrypted - decrypt before use
3946
+ // Prefer decryptionKey from bootstrap (workflow path) so we use the exact key the backend returned
3947
+ let cloudConfig = storageEnv.config;
3948
+ if (typeof cloudConfig === 'string') {
3949
+ const privateKey = decryptionKey !== null && decryptionKey !== void 0 ? decryptionKey : this.productBuilderService.fetchPrivateKey();
3950
+ if (!privateKey)
3951
+ throw new Error('Storage config is encrypted but private_key is not available');
3952
+ cloudConfig = JSON.parse((0, processor_utils_1.decrypt)(cloudConfig, privateKey));
3953
+ }
3954
+ // Resolve $Secret{...} references in config (e.g. GCP private_key) so upload receives real credentials
3955
+ if (cloudConfig && typeof cloudConfig === 'object' && (0, secrets_1.mightContainSecrets)(cloudConfig)) {
3956
+ const secretsService = (0, secrets_1.getSecretsService)();
3957
+ if (secretsService) {
3958
+ const resolved = await secretsService.resolve(cloudConfig, { env: storageEnv.slug });
3959
+ cloudConfig = resolved.value;
3960
+ }
3961
+ }
3240
3962
  const config = {
3241
3963
  provider: storageEnv.type,
3242
3964
  };
@@ -3246,8 +3968,8 @@ class ProcessorService {
3246
3968
  if (storageEnv.type === types_1.StorageProviders.GCP) {
3247
3969
  Object.assign(config, { gcpConfig: cloudConfig });
3248
3970
  }
3249
- if (storageEnv.type === types_1.StorageProviders.AWS) {
3250
- Object.assign(config, { awsConfig: cloudConfig });
3971
+ if (storageEnv.type === types_1.StorageProviders.AZURE) {
3972
+ Object.assign(config, { azureConfig: cloudConfig });
3251
3973
  }
3252
3974
  const result = { url: await (0, storage_util_1.uploadBlobToCloud)({ data: input.buffer, destinationPath: input.fileName, config }) };
3253
3975
  try {
@@ -3269,7 +3991,13 @@ class ProcessorService {
3269
3991
  return result;
3270
3992
  }
3271
3993
  catch (e) {
3272
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { failed_execution: true, message: 'Run storage request - failed', data: { e }, status: types_1.LogEventStatus.FAIL }));
3994
+ const err = e;
3995
+ const apiReason = (_b = (_a = err === null || err === void 0 ? void 0 : err.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.errors;
3996
+ const reason = typeof apiReason === 'string'
3997
+ ? apiReason
3998
+ : (_g = (_f = (_c = apiReason === null || apiReason === void 0 ? void 0 : apiReason.message) !== null && _c !== void 0 ? _c : (_e = (_d = err === null || err === void 0 ? void 0 : err.response) === null || _d === void 0 ? void 0 : _d.data) === null || _e === void 0 ? void 0 : _e.message) !== null && _f !== void 0 ? _f : err === null || err === void 0 ? void 0 : err.message) !== null && _g !== void 0 ? _g : String(e);
3999
+ const message = `Run storage request - failed: ${reason}`;
4000
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { failed_execution: true, message, data: { e, reason }, status: types_1.LogEventStatus.FAIL }));
3273
4001
  const value = await this.addToFailureOutput(e, data, { storageEnv }, additional_logs);
3274
4002
  if (value) {
3275
4003
  return value;
@@ -3405,7 +4133,7 @@ class ProcessorService {
3405
4133
  }
3406
4134
  async processAction(action) {
3407
4135
  //TODO: schema validation
3408
- const { env, input, retries, action: event, app, product: product_tag, session, cache } = action;
4136
+ const { env, input, retries, action: event, app, product: product_tag, session, cache, preloadedBootstrap } = action;
3409
4137
  const additional_logs = {
3410
4138
  parent_tag: (0, string_utils_1.extractOriginAndTag)(app),
3411
4139
  child_tag: event,
@@ -3431,13 +4159,47 @@ class ProcessorService {
3431
4159
  process_id,
3432
4160
  data: input,
3433
4161
  };
3434
- // Single ultra-lightweight bootstrap call - returns action data directly
3435
- const bootstrapData = await this.productBuilderService.bootstrapAction({
3436
- product_tag,
3437
- env_slug: env,
3438
- access_tag: app,
3439
- action_tag: event,
3440
- });
4162
+ this.process_id = process_id;
4163
+ // Initialize log service early to ensure error handling works
4164
+ if (!this.logService) {
4165
+ this.logService = new logs_service_1.default({
4166
+ product_id: this.productId,
4167
+ workspace_id: this.workspace_id,
4168
+ public_key: this.public_key,
4169
+ user_id: this.user_id,
4170
+ token: this.token,
4171
+ env_type: this.environment,
4172
+ });
4173
+ }
4174
+ // Early cache check - before expensive bootstrap/API calls
4175
+ if (cache && this.redisClient) {
4176
+ const productCache = await this.productBuilderService.fetchCache(cache);
4177
+ if (productCache) {
4178
+ const inputString = JSON.stringify(input);
4179
+ const cachedResult = await this.fetchFromCache({
4180
+ cache_tag: cache,
4181
+ input: inputString,
4182
+ privateKey: this.productBuilderService.fetchPrivateKey(),
4183
+ expiry: productCache.expiry,
4184
+ }, additional_logs);
4185
+ if (cachedResult) {
4186
+ const result = JSON.parse(cachedResult);
4187
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Action response from cache (early check)', data: { result: (0, processor_utils_1.anonymizeObject)(result) }, status: types_1.LogEventStatus.SUCCESS, cache_tag: cache, action: event }));
4188
+ this.end = Date.now();
4189
+ await this.logService.publish();
4190
+ return result;
4191
+ }
4192
+ }
4193
+ }
4194
+ // Use preloaded bootstrap when provided (e.g. workflow batch prefetch), otherwise fetch
4195
+ const bootstrapData = preloadedBootstrap
4196
+ ? preloadedBootstrap
4197
+ : await this.productBuilderService.bootstrapAction({
4198
+ product_tag,
4199
+ env_slug: env,
4200
+ access_tag: app,
4201
+ action_tag: event,
4202
+ });
3441
4203
  // Initialize from bootstrap data
3442
4204
  if (bootstrapData.product_id) {
3443
4205
  this.productId = bootstrapData.product_id;
@@ -3508,25 +4270,19 @@ class ProcessorService {
3508
4270
  // Process session if provided - verify and resolve $Session{} references
3509
4271
  if (session && bootstrapData.private_key) {
3510
4272
  const { processSessionForExecution } = await Promise.resolve().then(() => __importStar(require('../../sessions')));
3511
- const sessionResult = await processSessionForExecution(session, bootstrapData.private_key, resolvedInput, env);
4273
+ const sessionResult = await processSessionForExecution(session, bootstrapData.private_key, resolvedInput, env, {
4274
+ fetchSessionSelector: async (sessionTag) => {
4275
+ const sessionConfig = await this.productBuilderService.fetchSession(sessionTag);
4276
+ return sessionConfig === null || sessionConfig === void 0 ? void 0 : sessionConfig.selector;
4277
+ },
4278
+ });
3512
4279
  if (sessionResult.error) {
3513
4280
  throw new Error(`Session validation failed: ${sessionResult.error}`);
3514
4281
  }
3515
4282
  resolvedInput = sessionResult.input;
3516
4283
  sessionLogFields = sessionResult.logFields;
3517
4284
  }
3518
- // Initialize log service if needed
3519
- if (!this.logService) {
3520
- this.logService = new logs_service_1.default({
3521
- product_id: this.productId,
3522
- workspace_id: this.workspace_id,
3523
- public_key: this.public_key,
3524
- user_id: this.user_id,
3525
- token: this.token,
3526
- env_type: this.environment,
3527
- });
3528
- }
3529
- this.process_id = process_id;
4285
+ // Update log service with product_id from bootstrap
3530
4286
  this.baseLogs.product_id = this.productId;
3531
4287
  // Add session fields to base logs
3532
4288
  this.baseLogs = Object.assign(Object.assign({}, this.baseLogs), sessionLogFields);
@@ -3535,6 +4291,7 @@ class ProcessorService {
3535
4291
  type: types_1.FeatureEventTypes.ACTION,
3536
4292
  event,
3537
4293
  cache: cache,
4294
+ skipCacheFetch: true, // Early cache check already done above, skip duplicate fetch
3538
4295
  app,
3539
4296
  input: resolvedInput,
3540
4297
  env: this.processEnv,
@@ -3555,20 +4312,23 @@ class ProcessorService {
3555
4312
  return result;
3556
4313
  }
3557
4314
  catch (e) {
3558
- console.log('ERRRRROORRRRR!!!!!!', e);
3559
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Execute action - failed', data: { e: e.toString() }, status: types_1.LogEventStatus.FAIL }));
3560
- this.end = Date.now();
3561
- await this.writeResult(types_1.LogEventStatus.FAIL);
3562
- await this.logService.publish();
3563
- return { process_id: this.process_id };
4315
+ if (this.logService) {
4316
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Execute action - failed', data: { e: e.toString() }, status: types_1.LogEventStatus.FAIL }));
4317
+ this.end = Date.now();
4318
+ await this.writeResult(types_1.LogEventStatus.FAIL);
4319
+ await this.logService.publish();
4320
+ }
4321
+ throw e;
3564
4322
  }
3565
4323
  }
3566
4324
  async processNotification(action) {
3567
4325
  //TODO: schema validation
3568
- var _a;
3569
- const { env, input, retries, event, product: product_tag, session, cache } = action;
4326
+ var _a, _b, _c, _d, _e;
4327
+ const { env, input, retries, event, product: product_tag, session, cache, preloadedBootstrap } = action;
4328
+ debugLog('[processNotification] ENTRY', { product: product_tag, env, event, inputKeys: input ? Object.keys(input) : [], hasSession: !!session, hasCache: !!cache });
3570
4329
  const [parent_tag, child_tag] = event.split(':');
3571
4330
  if (!parent_tag || !child_tag) {
4331
+ debugLog('[processNotification] ERROR: invalid event format', { event });
3572
4332
  throw new Error(`database action events should be in the format notification_tag:message_tag`);
3573
4333
  }
3574
4334
  this.component = types_1.LogEventTypes.NOTIFICATIONS;
@@ -3582,34 +4342,34 @@ class ProcessorService {
3582
4342
  let sessionLogFields = {};
3583
4343
  let resolvedInput = input;
3584
4344
  try {
4345
+ this.productTag = product_tag;
4346
+ if (!preloadedBootstrap) {
4347
+ debugLog('[processNotification] Initializing product by tag', { product_tag });
4348
+ await this.productBuilderService.initializeProductByTag(product_tag);
4349
+ }
4350
+ debugLog('[processNotification] Validating input');
3585
4351
  await this.validateActionDataMappingInput(input, types_1.FeatureEventTypes.NOTIFICATION);
3586
4352
  this.input = action;
3587
4353
  this.start = Date.now();
3588
- this.productTag = product_tag;
3589
4354
  const process_id = (0, processor_utils_1.generateObjectId)();
4355
+ debugLog('[processNotification] process_id', process_id);
3590
4356
  this.baseLogs = Object.assign({ product_tag: this.productTag, workspace_id: this.workspace_id, env,
3591
4357
  process_id, data: input }, additional_logs);
3592
- // Single bootstrap call to fetch all notification data
3593
- const bootstrapData = await this.productBuilderService.bootstrapNotification({
3594
- product_tag,
3595
- env_slug: env,
3596
- notification_tag: parent_tag,
3597
- message_tag: child_tag,
3598
- });
4358
+ this.lastNotificationFailureType = undefined;
4359
+ // Use preloaded bootstrap when provided (e.g. workflow batch prefetch), otherwise fetch
4360
+ const bootstrapData = preloadedBootstrap
4361
+ ? preloadedBootstrap
4362
+ : await this.productBuilderService.bootstrapNotification({
4363
+ product_tag,
4364
+ env_slug: env,
4365
+ notification_tag: parent_tag,
4366
+ message_tag: child_tag,
4367
+ });
4368
+ debugLog('[processNotification] Bootstrap result', { product_id: bootstrapData === null || bootstrapData === void 0 ? void 0 : bootstrapData.product_id, hasNotification: !!(bootstrapData === null || bootstrapData === void 0 ? void 0 : bootstrapData.notification), hasMessage: !!(bootstrapData === null || bootstrapData === void 0 ? void 0 : bootstrapData.message), envActive: (_a = bootstrapData === null || bootstrapData === void 0 ? void 0 : bootstrapData.env) === null || _a === void 0 ? void 0 : _a.active });
3599
4369
  // Initialize from bootstrap data
3600
4370
  this.productId = bootstrapData.product_id;
3601
4371
  this.processEnv = bootstrapData.env;
3602
- // Process session if provided - verify and resolve $Session{} references
3603
- if (session && bootstrapData.private_key) {
3604
- const { processSessionForExecution } = await Promise.resolve().then(() => __importStar(require('../../sessions')));
3605
- const sessionResult = await processSessionForExecution(session, bootstrapData.private_key, input, env);
3606
- if (sessionResult.error) {
3607
- throw new Error(`Session validation failed: ${sessionResult.error}`);
3608
- }
3609
- resolvedInput = sessionResult.input;
3610
- sessionLogFields = sessionResult.logFields;
3611
- }
3612
- // Initialize log service if needed
4372
+ // Initialize log service as soon as we have productId so the catch block can record failures
3613
4373
  if (!this.logService) {
3614
4374
  this.logService = new logs_service_1.default({
3615
4375
  product_id: this.productId,
@@ -3621,6 +4381,21 @@ class ProcessorService {
3621
4381
  });
3622
4382
  }
3623
4383
  this.process_id = process_id;
4384
+ // Process session if provided - verify and resolve $Session{} references
4385
+ if (session && bootstrapData.private_key) {
4386
+ const { processSessionForExecution } = await Promise.resolve().then(() => __importStar(require('../../sessions')));
4387
+ const sessionResult = await processSessionForExecution(session, bootstrapData.private_key, input, env, {
4388
+ fetchSessionSelector: async (sessionTag) => {
4389
+ const sessionConfig = await this.productBuilderService.fetchSession(sessionTag);
4390
+ return sessionConfig === null || sessionConfig === void 0 ? void 0 : sessionConfig.selector;
4391
+ },
4392
+ });
4393
+ if (sessionResult.error) {
4394
+ throw new Error(`Session validation failed: ${sessionResult.error}`);
4395
+ }
4396
+ resolvedInput = sessionResult.input;
4397
+ sessionLogFields = sessionResult.logFields;
4398
+ }
3624
4399
  this.baseLogs.product_id = this.productId;
3625
4400
  // Add session fields to base logs
3626
4401
  this.baseLogs = Object.assign(Object.assign({}, this.baseLogs), sessionLogFields);
@@ -3638,25 +4413,152 @@ class ProcessorService {
3638
4413
  allow_fail: false,
3639
4414
  };
3640
4415
  // Find the env config for the notification
3641
- const envConfig = (_a = bootstrapData.notification.envs) === null || _a === void 0 ? void 0 : _a.find((data) => data.slug === env);
4416
+ const envConfig = (_b = bootstrapData.notification.envs) === null || _b === void 0 ? void 0 : _b.find((data) => data.slug === env);
4417
+ debugLog('[processNotification] Calling runNotification', { event, resolvedInputKeys: resolvedInput ? Object.keys(resolvedInput) : [] });
3642
4418
  const result = await this.runNotification(payload, additional_logs, {
3643
4419
  notification: bootstrapData.notification,
3644
4420
  message: bootstrapData.message,
3645
4421
  env_config: envConfig,
4422
+ product_tag,
4423
+ env,
4424
+ process_id,
4425
+ session,
4426
+ cache,
3646
4427
  });
3647
4428
  this.end = Date.now();
3648
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Send notification - success', data: { input: (0, processor_utils_1.anonymizeObject)(input), result: (0, processor_utils_1.anonymizeObject)(result) }, status: types_1.LogEventStatus.SUCCESS }));
4429
+ debugLog('[processNotification] SUCCESS', { process_id, lastChannelType: (_c = this.lastNotificationFailureType) !== null && _c !== void 0 ? _c : 'NOTIFICATIONS', durationMs: this.end - this.start });
4430
+ // Only add success log when we have a subtype (no NOTIFICATIONS-typed logs)
4431
+ /* if (this.lastNotificationFailureType != null) {
4432
+ this.logService.add({
4433
+ ...this.baseLogs,
4434
+ ...additional_logs,
4435
+ type: this.lastNotificationFailureType,
4436
+ message: 'Send notification - success',
4437
+ data: { input, result },
4438
+ status: LogEventStatus.SUCCESS,
4439
+ });
4440
+ }*/
3649
4441
  await this.writeResult(types_1.LogEventStatus.SUCCESS);
3650
- await this.logService.publish();
3651
- return { process_id };
4442
+ // Fire-and-forget so step latency isn't dominated by log upload
4443
+ this.logService.publish().catch(() => { });
4444
+ // Per-channel message logs are emitted inside runNotification (type: email | push | sms | callback).
4445
+ return { process_id, output: { sent: true } };
3652
4446
  }
3653
4447
  catch (e) {
3654
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Send notification - failed', data: { e }, status: types_1.LogEventStatus.FAIL }));
3655
- this.end = Date.now();
3656
- await this.logService.publish();
3657
- return { process_id: this.process_id };
4448
+ if (this.logService) {
4449
+ debugLog('[processNotification] FAILED', { error: e, lastChannelType: (_d = this.lastNotificationFailureType) !== null && _d !== void 0 ? _d : 'NOTIFICATIONS' });
4450
+ console.error(e);
4451
+ // Only add failure log when we have a subtype (no NOTIFICATIONS-typed logs)
4452
+ if (this.lastNotificationFailureType != null) {
4453
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: this.lastNotificationFailureType, message: 'Send notification - failed', data: { e: e.toString() }, status: types_1.LogEventStatus.FAIL }));
4454
+ }
4455
+ this.end = Date.now();
4456
+ this.logService.publish().catch(() => { });
4457
+ }
4458
+ // Fire-and-forget: log failed notification for reprocessing (only when we have productId from bootstrap). Use actual channel type when known.
4459
+ if (this.productId && this.workspace_id) {
4460
+ const channelType = this.lastNotificationFailureType === types_1.LogEventTypes.PUSH ? 'push' : this.lastNotificationFailureType === types_1.LogEventTypes.EMAIL ? 'email' : this.lastNotificationFailureType === types_1.LogEventTypes.SMS ? 'sms' : this.lastNotificationFailureType === types_1.LogEventTypes.CALLBACKS ? 'callback' : 'notification';
4461
+ this.fireAndForgetLogNotificationMessage({
4462
+ workspace_id: this.workspace_id,
4463
+ product_id: this.productId,
4464
+ product_tag,
4465
+ env,
4466
+ notification_tag: event,
4467
+ input: ((_e = resolvedInput !== null && resolvedInput !== void 0 ? resolvedInput : input) !== null && _e !== void 0 ? _e : {}),
4468
+ type: channelType,
4469
+ status: 'failed',
4470
+ process_id: this.process_id,
4471
+ retries: retries !== null && retries !== void 0 ? retries : 0,
4472
+ session,
4473
+ cache,
4474
+ error: e instanceof Error ? e.message : String(e),
4475
+ });
4476
+ }
4477
+ // Rethrow so workflow/callers see the step as failed (e.g. bootstrap "Notification not found" or runNotification failure)
4478
+ throw e;
3658
4479
  }
3659
4480
  }
4481
+ /**
4482
+ * Fire-and-forget log of notification message send to integrations backend (for reprocessing).
4483
+ * Input is encrypted with the product private key before sending. Does not block or affect latency; errors are swallowed.
4484
+ */
4485
+ fireAndForgetLogNotificationMessage(payload) {
4486
+ debugLog('[fireAndForgetLogNotificationMessage] ENTRY', {
4487
+ workspace_id: payload.workspace_id,
4488
+ product_tag: payload.product_tag,
4489
+ env: payload.env,
4490
+ notification_tag: payload.notification_tag,
4491
+ type: payload.type,
4492
+ status: payload.status,
4493
+ process_id: payload.process_id,
4494
+ inputKeys: payload.input ? Object.keys(payload.input) : [],
4495
+ });
4496
+ let inputToSend = payload.input;
4497
+ try {
4498
+ const privateKey = this.productBuilderService.fetchPrivateKey();
4499
+ if (privateKey) {
4500
+ inputToSend = (0, processor_utils_1.encrypt)(JSON.stringify(payload.input), privateKey);
4501
+ debugLog('[fireAndForgetLogNotificationMessage] input encrypted', { inputLength: String(inputToSend).length });
4502
+ }
4503
+ else {
4504
+ debugLog('[fireAndForgetLogNotificationMessage] no private key, sending input as plain object');
4505
+ }
4506
+ }
4507
+ catch (e) {
4508
+ debugLog('[fireAndForgetLogNotificationMessage] encrypt failed, sending input as-is', e);
4509
+ // No private key or encrypt failed: send input as-is (e.g. legacy or edge case)
4510
+ }
4511
+ void this.processorApiService
4512
+ .logNotificationMessage(Object.assign(Object.assign({}, payload), { input: inputToSend }), Object.assign(Object.assign({}, this.getUserAccess()), { access_key: this.accessKey }))
4513
+ .then(() => debugLog('[fireAndForgetLogNotificationMessage] POST success', { process_id: payload.process_id }))
4514
+ .catch((err) => console.error('[fireAndForgetLogNotificationMessage] POST failed', { process_id: payload.process_id, error: err }));
4515
+ }
4516
+ /**
4517
+ * Fetch notification message logs (send history) with time filters. Secured via user auth.
4518
+ * Each item's input is decrypted with the product private key when stored as an encrypted string.
4519
+ */
4520
+ async getNotificationMessageLogs(options) {
4521
+ const result = await this.processorApiService.queryNotificationMessageLogs(Object.assign({ workspace_id: this.workspace_id }, options), this.getUserAccess());
4522
+ // Initialize product so productBuilderService has private_key for decryption
4523
+ const productRef = options.product_tag || options.product_id;
4524
+ if (productRef) {
4525
+ try {
4526
+ if (options.product_id) {
4527
+ await this.productBuilderService.initializeProduct(options.product_id);
4528
+ }
4529
+ else {
4530
+ await this.productBuilderService.initializeProductByTag(options.product_tag);
4531
+ }
4532
+ }
4533
+ catch (_a) {
4534
+ // Return result without decryption if product init fails
4535
+ return result;
4536
+ }
4537
+ }
4538
+ let privateKey;
4539
+ try {
4540
+ privateKey = this.productBuilderService.fetchPrivateKey();
4541
+ }
4542
+ catch (_b) {
4543
+ return result;
4544
+ }
4545
+ if (!privateKey) {
4546
+ return result;
4547
+ }
4548
+ const items = result.items.map((item) => {
4549
+ if (typeof item.input !== 'string') {
4550
+ return item;
4551
+ }
4552
+ try {
4553
+ const decrypted = (0, processor_utils_1.decrypt)(item.input, privateKey);
4554
+ return Object.assign(Object.assign({}, item), { input: JSON.parse(decrypted) });
4555
+ }
4556
+ catch (_a) {
4557
+ return item;
4558
+ }
4559
+ });
4560
+ return Object.assign(Object.assign({}, result), { items });
4561
+ }
3660
4562
  async fetchRemoteCaches(payload) {
3661
4563
  try {
3662
4564
  const data = await this.processorApiService.fetchRemoteCaches(payload, this.getUserAccess());
@@ -3677,57 +4579,62 @@ class ProcessorService {
3677
4579
  public_key: this.public_key,
3678
4580
  };
3679
4581
  }
3680
- async addToCache(payload, additional_logs) {
3681
- if (!this.redisClient) {
3682
- throw 'redis client not setup';
3683
- }
4582
+ /**
4583
+ * Add data to cache - fire-and-forget pattern.
4584
+ * Does not block the main operation.
4585
+ */
4586
+ addToCache(payload, additional_logs) {
3684
4587
  const { input, privateKey, data, cache_tag, timestamp, expiry, product_tag, component_tag, component_type } = payload;
3685
4588
  // sha-512 instead of md5, private key is fetch product.privatekey
3686
4589
  const key = `${cache_tag}-${CryptoJS.SHA512(input)}`;
3687
4590
  const encryptedData = (0, processor_utils_1.encrypt)(data, privateKey);
3688
- let expiresAt = null;
4591
+ let expiresAt = undefined;
3689
4592
  if (expiry) {
3690
- expiresAt = timestamp + expiry;
3691
- }
3692
- await this.processorApiService.addToRemoteCache(Object.assign(Object.assign({}, (expiresAt && { expiry: new Date(expiresAt) })), { key, value: encryptedData, cache_tag,
3693
- product_tag,
3694
- component_tag,
3695
- component_type }), this.getUserAccess());
3696
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Renewing expired Cache Value', data: { key }, successful_execution: true, status: types_1.LogEventStatus.SUCCESS, cache_tag }));
3697
- await this.redisClient.hSet(key, 'data', encryptedData);
3698
- await this.redisClient.hSet(key, 'lastUpdated', timestamp);
4593
+ expiresAt = new Date(timestamp + expiry);
4594
+ }
4595
+ // Use CacheService to store the value (fire-and-forget)
4596
+ this.cacheService.set({
4597
+ product: product_tag,
4598
+ cache: cache_tag,
4599
+ key,
4600
+ value: encryptedData,
4601
+ componentTag: component_tag,
4602
+ componentType: component_type,
4603
+ expiry: expiresAt,
4604
+ }).then(() => {
4605
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Cache value stored', data: { key }, successful_execution: true, status: types_1.LogEventStatus.SUCCESS, cache_tag, cache_key: key }));
4606
+ }).catch((error) => {
4607
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Cache store failed (non-blocking)', data: { key, error: String(error) }, status: types_1.LogEventStatus.FAIL, cache_tag, cache_key: key }));
4608
+ });
3699
4609
  }
3700
4610
  async fetchFromCache(payload, additional_logs) {
3701
- var _a;
3702
4611
  const { input, privateKey, cache_tag, expiry } = payload;
3703
4612
  const key = `${cache_tag}-${CryptoJS.SHA512(input)}`;
3704
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Fetching from Cache', data: { key }, status: types_1.LogEventStatus.PROCESSING, cache_tag }));
3705
- if (!this.redisClient) {
3706
- return null;
3707
- }
3708
- let record = await this.redisClient.hGetAll(key);
3709
- if (!record || !record.data || !record.lastUpdated) {
3710
- const checkRemote = await this.processorApiService.fetchRemoteCacheByKey(key, this.getUserAccess());
3711
- if (!checkRemote) {
3712
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Remote Cache Not Found', data: { key }, successful_execution: true, status: types_1.LogEventStatus.FAIL, cache_tag }));
4613
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Fetching from Cache', data: { key }, status: types_1.LogEventStatus.PROCESSING, cache_tag, cache_key: key }));
4614
+ try {
4615
+ // Use CacheService to fetch the value
4616
+ const cacheValue = await this.cacheService.get({ key });
4617
+ if (!cacheValue) {
4618
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Remote Cache Not Found', data: { key }, successful_execution: true, status: types_1.LogEventStatus.FAIL, cache_tag, cache_key: key, cache_status: false }));
3713
4619
  return null;
3714
4620
  }
3715
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Remote Cache Found', data: { key }, successful_execution: true, status: types_1.LogEventStatus.SUCCESS, cache_tag }));
3716
- record = { data: checkRemote.value, expiresAt: (_a = checkRemote.expiry) === null || _a === void 0 ? void 0 : _a.getTime().toString() };
3717
- }
3718
- if (record.lastUpdated) {
3719
- const lastUpdated = Number(record.lastUpdated);
3720
- if (expiry) {
3721
- const expiryTime = lastUpdated + expiry;
4621
+ // Check expiry if provided
4622
+ if (expiry && cacheValue.expiry) {
4623
+ const expiryTime = new Date(cacheValue.expiry).getTime();
3722
4624
  if (Date.now() > expiryTime) {
3723
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Deleting expired Cache Value', data: { key }, successful_execution: true, status: types_1.LogEventStatus.SUCCESS, cache_tag }));
3724
- await this.redisClient.del(key);
4625
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Deleting expired Cache Value', data: { key }, successful_execution: true, status: types_1.LogEventStatus.SUCCESS, cache_tag, cache_key: key }));
4626
+ await this.cacheService.clear({ key });
3725
4627
  return null;
3726
4628
  }
3727
4629
  }
4630
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Cache Found', data: { key }, successful_execution: true, status: types_1.LogEventStatus.SUCCESS, cache_tag, cache_key: key, cache_status: true }));
4631
+ // Decrypt the value (CacheService returns encrypted value)
4632
+ return (0, processor_utils_1.decrypt)(cacheValue.value, privateKey);
4633
+ }
4634
+ catch (error) {
4635
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Cache fetch error', data: { key, error: String(error) }, successful_execution: false, status: types_1.LogEventStatus.FAIL, cache_tag, cache_key: key, cache_status: false }));
4636
+ return null;
3728
4637
  }
3729
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Cache Found', data: { key }, successful_execution: true, status: types_1.LogEventStatus.SUCCESS, cache_tag }));
3730
- return (0, processor_utils_1.decrypt)(record.data, privateKey);
3731
4638
  }
3732
4639
  /**
3733
4640
  * Writes the healthcheck result to Redis cache for fast status retrieval.
@@ -3736,9 +4643,9 @@ class ProcessorService {
3736
4643
  if (!this.redisClient)
3737
4644
  return;
3738
4645
  const key = `healthcheck:${data.product}:${data.healthcheck}:${data.env}`;
3739
- console.log('LOG TO CACHE', key, JSON.stringify(result));
4646
+ debugLog('LOG TO CACHE', key, JSON.stringify(result));
3740
4647
  await this.redisClient.set(key, JSON.stringify(result));
3741
- console.log();
4648
+ debugLog();
3742
4649
  }
3743
4650
  /**
3744
4651
  * Fetches the latest healthcheck status for a product/env from Redis cache.