@ductape/sdk 0.0.8 → 0.1.0

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 (75) hide show
  1. package/dist/agents/agents.service.js +2 -0
  2. package/dist/agents/agents.service.js.map +1 -1
  3. package/dist/api/services/processorApi.service.d.ts +15 -10
  4. package/dist/api/services/processorApi.service.js +10 -2
  5. package/dist/api/services/processorApi.service.js.map +1 -1
  6. package/dist/api/services/productsApi.service.d.ts +1 -0
  7. package/dist/api/services/productsApi.service.js.map +1 -1
  8. package/dist/api/services/workspaceApi.service.js +4 -1
  9. package/dist/api/services/workspaceApi.service.js.map +1 -1
  10. package/dist/api/urls.js +3 -3
  11. package/dist/api/urls.js.map +1 -1
  12. package/dist/apps/services/app.service.d.ts +2 -1
  13. package/dist/apps/services/app.service.js +4 -1
  14. package/dist/apps/services/app.service.js.map +1 -1
  15. package/dist/brokers/brokers.service.js +1 -0
  16. package/dist/brokers/brokers.service.js.map +1 -1
  17. package/dist/brokers/types/index.d.ts +2 -0
  18. package/dist/cache/cache.service.d.ts +1 -0
  19. package/dist/cache/cache.service.js +2 -0
  20. package/dist/cache/cache.service.js.map +1 -1
  21. package/dist/cache/types/index.d.ts +2 -0
  22. package/dist/database/databases.service.js +2 -0
  23. package/dist/database/databases.service.js.map +1 -1
  24. package/dist/graph/graphs.service.js +2 -0
  25. package/dist/graph/graphs.service.js.map +1 -1
  26. package/dist/imports/imports.service.d.ts +1 -1
  27. package/dist/imports/imports.service.js +2 -2
  28. package/dist/imports/imports.service.js.map +1 -1
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.js +154 -128
  31. package/dist/index.js.map +1 -1
  32. package/dist/logs/logs.service.d.ts +3 -2
  33. package/dist/logs/logs.service.js +20 -5
  34. package/dist/logs/logs.service.js.map +1 -1
  35. package/dist/logs/logs.types.d.ts +6 -0
  36. package/dist/logs/logs.types.js +4 -0
  37. package/dist/logs/logs.types.js.map +1 -1
  38. package/dist/notifications/notifications.service.js +2 -0
  39. package/dist/notifications/notifications.service.js.map +1 -1
  40. package/dist/notifications/types/notifications.types.d.ts +4 -2
  41. package/dist/notifications/types/notifications.types.js +2 -0
  42. package/dist/notifications/types/notifications.types.js.map +1 -1
  43. package/dist/processor/services/processor.service.d.ts +53 -2
  44. package/dist/processor/services/processor.service.js +709 -251
  45. package/dist/processor/services/processor.service.js.map +1 -1
  46. package/dist/processor/utils/processor.utils.js +6 -1
  47. package/dist/processor/utils/processor.utils.js.map +1 -1
  48. package/dist/products/services/products.service.d.ts +26 -0
  49. package/dist/products/services/products.service.js +48 -1
  50. package/dist/products/services/products.service.js.map +1 -1
  51. package/dist/products/validators/joi-validators/create.productFeature.validator.d.ts +2 -0
  52. package/dist/products/validators/joi-validators/create.productFeature.validator.js +15 -1
  53. package/dist/products/validators/joi-validators/create.productFeature.validator.js.map +1 -1
  54. package/dist/resilience/healthcheck.service.d.ts +7 -3
  55. package/dist/resilience/healthcheck.service.js +82 -13
  56. package/dist/resilience/healthcheck.service.js.map +1 -1
  57. package/dist/sessions/sessions.service.js +1 -0
  58. package/dist/sessions/sessions.service.js.map +1 -1
  59. package/dist/sessions/types/index.d.ts +2 -0
  60. package/dist/storage/storage.service.js +2 -0
  61. package/dist/storage/storage.service.js.map +1 -1
  62. package/dist/types/processor.types.d.ts +2 -2
  63. package/dist/types/productsBuilder.types.d.ts +9 -0
  64. package/dist/types/productsBuilder.types.js.map +1 -1
  65. package/dist/utils/index.js +64 -6
  66. package/dist/utils/index.js.map +1 -1
  67. package/dist/vector/vector-database.service.d.ts +2 -0
  68. package/dist/vector/vector-database.service.js +3 -0
  69. package/dist/vector/vector-database.service.js.map +1 -1
  70. package/dist/workflows/workflow-executor.d.ts +2 -0
  71. package/dist/workflows/workflow-executor.js +17 -4
  72. package/dist/workflows/workflow-executor.js.map +1 -1
  73. package/dist/workflows/workflows.service.js +4 -2
  74. package/dist/workflows/workflows.service.js.map +1 -1
  75. package/package.json +3 -1
@@ -75,6 +75,9 @@ const credential_manager_1 = require("../../apps/utils/credential-manager");
75
75
  const oauth_manager_1 = require("../../apps/utils/oauth-manager");
76
76
  const string_utils_2 = require("../../apps/utils/string.utils");
77
77
  const secrets_1 = require("../../secrets");
78
+ /** TTL for action bootstrap cache (same app version = same bootstrap). 5 minutes. */
79
+ const ACTION_BOOTSTRAP_CACHE_TTL_MS = 5 * 60 * 1000;
80
+ const ACTION_BOOTSTRAP_REDIS_PREFIX = 'ductape:action_bootstrap:';
78
81
  async function loadBrokerService() {
79
82
  if (typeof window === 'undefined') {
80
83
  const { loadBrokerService: loadBroker } = await Promise.resolve().then(() => __importStar(require('../../brokers')));
@@ -91,7 +94,9 @@ async function loadJWT() {
91
94
  }
92
95
  /** Only log when DUCTAPE_DEBUG is set to avoid sync I/O and serialization cost in hot path */
93
96
  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');
94
- const debugLog = _processorDebug ? (...args) => console.log(...args) : () => { };
97
+ const debugLog = _processorDebug
98
+ ? (...args) => console.log(...args)
99
+ : () => { };
95
100
  /** Shared mail (SMTP) transporters: one per workspace+product+poolKey. Not exported. */
96
101
  const sharedMailRegistry = new Map();
97
102
  const sharedMailInFlight = new Map();
@@ -111,7 +116,7 @@ function getSharedSmsKey(workspaceId, product, poolKey) {
111
116
  return `sms:${workspaceId}:${product}:${poolKey}`;
112
117
  }
113
118
  class ProcessorService {
114
- constructor({ workspace_id, public_key, user_id, token, env_type, private_key, access_key, redis_client, queues, preInitializedProductBuilder }) {
119
+ constructor({ workspace_id, public_key, user_id, token, env_type, private_key, access_key, redis_client, queues, preInitializedProductBuilder, }) {
115
120
  /** Reuse broker connections when multiple produce steps use the same broker (avoids ~1–3s connection setup per step). Never logged or exposed. */
116
121
  this.brokerServicePool = new Map();
117
122
  /** Reuse SMTP transporter so we don't open a new connection per email (avoids multi-second handshake per send). Never logged or exposed. */
@@ -123,6 +128,14 @@ class ProcessorService {
123
128
  /** Reuse SMS client per config (Twilio/Nexmo/Plivo). Never logged or exposed. */
124
129
  this.smsClientPool = new Map();
125
130
  this.smsPoolKeyToSharedKey = new Map();
131
+ /** Action bootstrap cache (internal tier): key -> { data, storedAt }. Same key = same app version scope. */
132
+ this.actionBootstrapCache = new Map();
133
+ /** Healthcheck worker interval IDs; cleared and repopulated only when the healthcheck set or config changes. */
134
+ this.healthcheckWorkerIntervals = [];
135
+ /** Timer that periodically checks for healthcheck list changes (default 60s). Workers are only recreated when the fingerprint changes. */
136
+ this.healthcheckRefreshTimer = null;
137
+ /** Fingerprint of current worker set (tag:env:interval) so we only clear/recreate when the list or config actually changed. */
138
+ this.healthcheckWorkerFingerprint = null;
126
139
  this.workspace_id = workspace_id;
127
140
  this.public_key = public_key;
128
141
  this.user_id = user_id;
@@ -130,16 +143,17 @@ class ProcessorService {
130
143
  this.accessKey = access_key;
131
144
  this.token = token;
132
145
  this.published = false;
133
- this.productBuilderService = preInitializedProductBuilder !== null && preInitializedProductBuilder !== void 0 ? preInitializedProductBuilder : new products_service_1.default({
134
- workspace_id,
135
- public_key,
136
- user_id,
137
- token,
138
- env_type,
139
- redis_client,
140
- access_key,
141
- workspace_private_key: private_key || undefined,
142
- });
146
+ this.productBuilderService =
147
+ preInitializedProductBuilder !== null && preInitializedProductBuilder !== void 0 ? preInitializedProductBuilder : new products_service_1.default({
148
+ workspace_id,
149
+ public_key,
150
+ user_id,
151
+ token,
152
+ env_type,
153
+ redis_client,
154
+ access_key,
155
+ workspace_private_key: private_key || undefined,
156
+ });
143
157
  this.appBuilderService = new app_service_1.default({
144
158
  workspace_id,
145
159
  public_key,
@@ -147,6 +161,7 @@ class ProcessorService {
147
161
  token,
148
162
  env_type,
149
163
  redis_client,
164
+ access_key,
150
165
  });
151
166
  this.pricingService = new pricing_service_1.default({
152
167
  workspace_id,
@@ -561,50 +576,167 @@ class ProcessorService {
561
576
  }
562
577
  }
563
578
  }
579
+ /**
580
+ * Run a single healthcheck (one env) by dispatching to the correct processor based on probe type.
581
+ * Supports app, database, workflow, graph, storage, message_broker. Falls back to processAction when probe is missing (app/event only).
582
+ * Public so the SDK monitor worker can call it with full healthcheck (including probe).
583
+ */
584
+ async runOneHealthcheck(healthcheck, envSlug, decryptedInput, productTag) {
585
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
586
+ const probe = healthcheck.probe;
587
+ const retries = (_a = healthcheck.retries) !== null && _a !== void 0 ? _a : 0;
588
+ const inferType = () => {
589
+ if (probe === null || probe === void 0 ? void 0 : probe.type)
590
+ return String(probe.type);
591
+ if (probe === null || probe === void 0 ? void 0 : probe.app)
592
+ return 'app';
593
+ if (probe === null || probe === void 0 ? void 0 : probe.database)
594
+ return 'database';
595
+ if (probe === null || probe === void 0 ? void 0 : probe.workflow)
596
+ return 'workflow';
597
+ if (probe === null || probe === void 0 ? void 0 : probe.graph)
598
+ return 'graph';
599
+ if (probe === null || probe === void 0 ? void 0 : probe.storage)
600
+ return 'storage';
601
+ if (probe === null || probe === void 0 ? void 0 : probe.messageBroker)
602
+ return 'message_broker';
603
+ return 'app';
604
+ };
605
+ const type = inferType();
606
+ const event = (_b = probe === null || probe === void 0 ? void 0 : probe.event) !== null && _b !== void 0 ? _b : healthcheck.event;
607
+ switch (type) {
608
+ case 'app': {
609
+ const app = (_d = (_c = healthcheck.app) !== null && _c !== void 0 ? _c : probe === null || probe === void 0 ? void 0 : probe.app) !== null && _d !== void 0 ? _d : '';
610
+ if (!app) {
611
+ throw new Error(`Healthcheck "${healthcheck.tag}" has no app (probe missing or app empty). Ensure healthchecks are fetched with probe from the components API.`);
612
+ }
613
+ return this.processAction({
614
+ env: envSlug,
615
+ product: productTag,
616
+ app,
617
+ action: (_f = (_e = healthcheck.event) !== null && _e !== void 0 ? _e : event) !== null && _f !== void 0 ? _f : '',
618
+ input: decryptedInput !== null && decryptedInput !== void 0 ? decryptedInput : {},
619
+ retries,
620
+ });
621
+ }
622
+ case 'database':
623
+ return this.processDatabaseAction({
624
+ env: envSlug,
625
+ product: productTag,
626
+ database: probe.database,
627
+ event: event !== null && event !== void 0 ? event : 'test_connection',
628
+ input: decryptedInput !== null && decryptedInput !== void 0 ? decryptedInput : {},
629
+ });
630
+ case 'workflow':
631
+ return this.processWorkflow({
632
+ env: envSlug,
633
+ product: productTag,
634
+ workflow: probe.workflow,
635
+ input: decryptedInput !== null && decryptedInput !== void 0 ? decryptedInput : {},
636
+ });
637
+ case 'graph':
638
+ return this.processGraphAction({
639
+ env: envSlug,
640
+ product: productTag,
641
+ graph: probe.graph,
642
+ event: event !== null && event !== void 0 ? event : 'test_connection',
643
+ input: decryptedInput !== null && decryptedInput !== void 0 ? decryptedInput : {},
644
+ });
645
+ case 'storage': {
646
+ const storageTag = probe.storage;
647
+ const op = event !== null && event !== void 0 ? event : 'test_connection';
648
+ return this.processStorage({
649
+ env: envSlug,
650
+ product: productTag,
651
+ event: `${storageTag}:${op}`,
652
+ input: (decryptedInput && typeof decryptedInput === 'object' ? decryptedInput : {}),
653
+ retries,
654
+ });
655
+ }
656
+ case 'message_broker': {
657
+ const brokerTag = probe.messageBroker;
658
+ const topicOrAction = event !== null && event !== void 0 ? event : 'health';
659
+ return this.processMessageBrokerPublish({
660
+ env: envSlug,
661
+ product: productTag,
662
+ event: `${brokerTag}:${topicOrAction}`,
663
+ input: { message: typeof decryptedInput === 'object' && decryptedInput != null ? decryptedInput : {} },
664
+ });
665
+ }
666
+ default:
667
+ return this.processAction({
668
+ env: envSlug,
669
+ product: productTag,
670
+ app: (_g = healthcheck.app) !== null && _g !== void 0 ? _g : '',
671
+ action: (_j = (_h = healthcheck.event) !== null && _h !== void 0 ? _h : event) !== null && _j !== void 0 ? _j : '',
672
+ input: decryptedInput !== null && decryptedInput !== void 0 ? decryptedInput : {},
673
+ retries,
674
+ });
675
+ }
676
+ }
677
+ /**
678
+ * Build a stable fingerprint for the current healthcheck list so we only recreate workers when the set or config changes.
679
+ */
680
+ healthcheckFingerprint(healthchecks) {
681
+ var _a, _b;
682
+ const parts = [];
683
+ for (const h of healthchecks) {
684
+ const intervalMs = (_a = h.interval) !== null && _a !== void 0 ? _a : 60000;
685
+ for (const env of (_b = h.envs) !== null && _b !== void 0 ? _b : []) {
686
+ parts.push(`${h.tag}:${env.slug}:${intervalMs}`);
687
+ }
688
+ }
689
+ parts.sort();
690
+ return parts.join('|');
691
+ }
564
692
  /**
565
693
  * Start healthcheck workers for all products/environments after Redis is connected.
566
694
  * This is called automatically in the constructor if redisClient is present.
695
+ * Dispatches to app, database, workflow, graph, storage, or message_broker processor based on probe type.
696
+ * Every HEALTHCHECK_REFRESH_MS we re-fetch the list and only clear/recreate workers when the fingerprint
697
+ * (tag:env:interval set) has changed, so existing timers are not reset when nothing changed.
567
698
  */
568
699
  async startHealthcheckWorkers() {
569
- // Fetch all products (or the current product if context is single-tenant)
570
- // For demo, we use the current product only
571
700
  await this.productBuilderService.initializeProductByTag(this.productTag);
572
701
  const healthchecks = await this.productBuilderService.fetchProductHealthchecks();
702
+ const newFingerprint = this.healthcheckFingerprint(healthchecks);
703
+ if (this.healthcheckWorkerFingerprint === newFingerprint) {
704
+ return;
705
+ }
706
+ for (const id of this.healthcheckWorkerIntervals) {
707
+ clearInterval(id);
708
+ }
709
+ this.healthcheckWorkerIntervals = [];
710
+ this.healthcheckWorkerFingerprint = newFingerprint;
573
711
  const privateKey = this.productBuilderService.fetchPrivateKey();
574
712
  for (const healthcheck of healthchecks) {
575
713
  for (const env of healthcheck.envs) {
576
- // Each env gets its own worker (setInterval)
577
- const interval = healthcheck.interval || 60000; // default 60s
578
- setInterval(async () => {
714
+ const intervalMs = healthcheck.interval || 60000;
715
+ const id = setInterval(async () => {
579
716
  try {
580
- // Decrypt input for this env
581
717
  let decryptedInput = env.input;
582
718
  if (typeof decryptedInput === 'string') {
583
719
  decryptedInput = JSON.parse((0, processor_utils_1.decrypt)(decryptedInput, privateKey));
584
720
  }
585
- // Prepare action input
586
- const actionInput = {
587
- env: env.slug,
588
- product: this.productTag,
589
- app: healthcheck.app,
590
- input: decryptedInput,
591
- action: healthcheck.event,
592
- retries: healthcheck.retries || 0,
593
- };
594
- // Process the action
595
- const result = await this.processAction(actionInput);
596
- // Log result (success/failure)
721
+ const result = await this.runOneHealthcheck(healthcheck, env.slug, decryptedInput, this.productTag);
597
722
  this.logService.add(Object.assign(Object.assign({}, this.baseLogs), { message: `Healthcheck processed for ${healthcheck.tag} in env ${env.slug}`, data: { result }, status: types_1.LogEventStatus.SUCCESS }));
598
723
  }
599
724
  catch (e) {
600
725
  this.logService.add(Object.assign(Object.assign({}, this.baseLogs), { message: `Healthcheck failed for ${healthcheck.tag} in env ${env.slug}`, data: { error: e.toString() }, status: types_1.LogEventStatus.FAIL }));
601
726
  }
602
- }, interval);
727
+ }, intervalMs);
728
+ this.healthcheckWorkerIntervals.push(id);
603
729
  }
604
730
  }
731
+ if (this.healthcheckRefreshTimer == null) {
732
+ this.healthcheckRefreshTimer = setInterval(() => {
733
+ this.startHealthcheckWorkers();
734
+ }, ProcessorService.HEALTHCHECK_REFRESH_MS);
735
+ }
605
736
  }
606
737
  /**
607
- * Manually trigger healthcheck processing for all healthchecks (can be called externally if needed)
738
+ * Manually trigger healthcheck processing for all healthchecks (can be called externally if needed).
739
+ * Dispatches to app, database, workflow, graph, storage, or message_broker processor based on probe type.
608
740
  */
609
741
  async processAllHealthchecksForProduct(productTag) {
610
742
  await this.productBuilderService.initializeProductByTag(productTag);
@@ -617,15 +749,7 @@ class ProcessorService {
617
749
  if (typeof decryptedInput === 'string') {
618
750
  decryptedInput = JSON.parse((0, processor_utils_1.decrypt)(decryptedInput, privateKey));
619
751
  }
620
- const actionInput = {
621
- env: env.slug,
622
- product: productTag,
623
- app: healthcheck.app,
624
- input: decryptedInput,
625
- action: healthcheck.event,
626
- retries: healthcheck.retries || 0,
627
- };
628
- const result = await this.processAction(actionInput);
752
+ const result = await this.runOneHealthcheck(healthcheck, env.slug, decryptedInput, productTag);
629
753
  this.logService.add(Object.assign(Object.assign({}, this.baseLogs), { message: `Manual healthcheck processed for ${healthcheck.tag} in env ${env.slug}`, data: { result }, status: types_1.LogEventStatus.SUCCESS }));
630
754
  }
631
755
  catch (e) {
@@ -845,6 +969,7 @@ class ProcessorService {
845
969
  //return res.link;
846
970
  }
847
971
  async intializeProduct(additional_logs) {
972
+ var _a;
848
973
  if (!this.logService) {
849
974
  this.logService = new logs_service_1.default({
850
975
  product_id: this.productId,
@@ -853,6 +978,7 @@ class ProcessorService {
853
978
  user_id: this.user_id,
854
979
  token: this.token,
855
980
  env_type: this.environment,
981
+ workspace_private_key: (_a = this._privateKey) !== null && _a !== void 0 ? _a : undefined,
856
982
  });
857
983
  }
858
984
  try {
@@ -881,6 +1007,7 @@ class ProcessorService {
881
1007
  }
882
1008
  }
883
1009
  async initializePricing(additional_logs, access_tag) {
1010
+ var _a, _b;
884
1011
  if (!this.logService) {
885
1012
  this.logService = new logs_service_1.default({
886
1013
  product_id: this.productId,
@@ -889,6 +1016,7 @@ class ProcessorService {
889
1016
  user_id: this.user_id,
890
1017
  token: this.token,
891
1018
  env_type: this.environment,
1019
+ workspace_private_key: (_a = this._privateKey) !== null && _a !== void 0 ? _a : undefined,
892
1020
  });
893
1021
  }
894
1022
  try {
@@ -897,11 +1025,12 @@ class ProcessorService {
897
1025
  debugLog(`Found product app: ${JSON.stringify(product_app)}`);
898
1026
  const app = await this.productBuilderService.fetchThirdPartyAppByAccessTag(product_app.access_tag);
899
1027
  await this.pricingService.initializePricingByTag(product_app.pricing_tag, app._id);
900
- const { pricing_tag } = this.pricingService.fetchPricing();
901
- this.pricingTag = pricing_tag;
1028
+ const res = this.pricingService.fetchPricing();
1029
+ this.pricingTag = (_b = res === null || res === void 0 ? void 0 : res.pricing_tag) !== null && _b !== void 0 ? _b : 'free';
902
1030
  this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Pricing initialize - success', data: { pricing_tag: this.pricingTag }, status: types_1.LogEventStatus.SUCCESS }));
903
1031
  }
904
1032
  catch (e) {
1033
+ console.error('ERROR', e);
905
1034
  this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Pricing initialize - failed', data: e, status: types_1.LogEventStatus.FAIL }));
906
1035
  throw e;
907
1036
  }
@@ -1030,6 +1159,7 @@ class ProcessorService {
1030
1159
  }
1031
1160
  }
1032
1161
  async generateStringValues(value, app, additional_logs, sample = [], index = {}, key = '', loopIndex = null) {
1162
+ var _a, _b;
1033
1163
  value = (0, processor_utils_1.removeWrappingQuotes)(value);
1034
1164
  const stages = this.productBuilderService.extractStages(value);
1035
1165
  const locatorFor$Index = (0, string_utils_1.validateAndLocateTag)(value);
@@ -1081,6 +1211,16 @@ class ProcessorService {
1081
1211
  else if (value === '$Date') {
1082
1212
  return new Date().toISOString();
1083
1213
  }
1214
+ else if ((0, secrets_1.containsSecretReferences)(value)) {
1215
+ // Resolve $Secret{key} or $secret{key} in action templates (headers, body, params, query)
1216
+ const secretsService = (0, secrets_1.getSecretsService)();
1217
+ if (!secretsService) {
1218
+ throw new Error('Action template contains secret references ($secret{...}) but secrets service is not initialized. Ensure secrets are configured for this environment.');
1219
+ }
1220
+ const envSlug = (_b = (_a = this.processEnv) === null || _a === void 0 ? void 0 : _a.slug) !== null && _b !== void 0 ? _b : '';
1221
+ const resolved = await secretsService.resolve(value, { env: envSlug });
1222
+ return resolved.value;
1223
+ }
1084
1224
  else if (!value.startsWith('$')) {
1085
1225
  // allow hardcoded values
1086
1226
  return value;
@@ -1652,7 +1792,7 @@ class ProcessorService {
1652
1792
  }
1653
1793
  }
1654
1794
  async runJobs(job, additional_logs = {}) {
1655
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
1795
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
1656
1796
  const jobId = (_a = job.data) === null || _a === void 0 ? void 0 : _a._job_id;
1657
1797
  const jobType = job.name;
1658
1798
  const startedAt = Date.now();
@@ -1674,6 +1814,7 @@ class ProcessorService {
1674
1814
  user_id: this.user_id,
1675
1815
  token: this.token,
1676
1816
  env_type: this.environment,
1817
+ workspace_private_key: (_g = this._privateKey) !== null && _g !== void 0 ? _g : undefined,
1677
1818
  });
1678
1819
  }
1679
1820
  if (this.logService) {
@@ -1681,8 +1822,8 @@ class ProcessorService {
1681
1822
  product_tag: productTag,
1682
1823
  product_id: this.productId,
1683
1824
  workspace_id: this.workspace_id,
1684
- env: (_h = (_g = job.data) === null || _g === void 0 ? void 0 : _g.env) !== null && _h !== void 0 ? _h : '',
1685
- process_id: jobId !== null && jobId !== void 0 ? jobId : (0, processor_utils_1.generateObjectId)(),
1825
+ env: (_j = (_h = job.data) === null || _h === void 0 ? void 0 : _h.env) !== null && _j !== void 0 ? _j : '',
1826
+ process_id: jobId !== null && jobId !== void 0 ? jobId : (0, uuid_1.v4)(),
1686
1827
  type: types_1.LogEventTypes.JOB,
1687
1828
  parent_tag: jobParentTag,
1688
1829
  child_tag: jobChildTag,
@@ -1690,8 +1831,8 @@ class ProcessorService {
1690
1831
  data: {
1691
1832
  job_id: jobId,
1692
1833
  job_type: jobType,
1693
- event: (_j = job.data) === null || _j === void 0 ? void 0 : _j.event,
1694
- env: (_k = job.data) === null || _k === void 0 ? void 0 : _k.env,
1834
+ event: (_k = job.data) === null || _k === void 0 ? void 0 : _k.event,
1835
+ env: (_l = job.data) === null || _l === void 0 ? void 0 : _l.env,
1695
1836
  },
1696
1837
  status: types_1.LogEventStatus.PROCESSING,
1697
1838
  start: startedAt,
@@ -1765,12 +1906,27 @@ class ProcessorService {
1765
1906
  console.warn('[runJobs] Updating job execution phase (completed) without access_key', { jobId });
1766
1907
  const operation = typeof job.event === 'string' && job.event.includes(':')
1767
1908
  ? job.event.split(':').pop()
1768
- : (_l = job.event) !== null && _l !== void 0 ? _l : undefined;
1909
+ : (_m = job.event) !== null && _m !== void 0 ? _m : undefined;
1769
1910
  const outputPayload = result != null
1770
1911
  ? typeof result === 'object' && result !== null && !Array.isArray(result)
1771
1912
  ? result
1772
1913
  : { value: result }
1773
1914
  : undefined;
1915
+ const resultMetadataPayload = result != null ? { result: typeof result === 'object' ? result : { value: result } } : undefined;
1916
+ let encryptedOutput;
1917
+ let encryptedResultMetadata;
1918
+ try {
1919
+ const privateKey = this.productBuilderService.fetchPrivateKey();
1920
+ if (outputPayload)
1921
+ encryptedOutput = (0, processor_utils_1.encrypt)(JSON.stringify(outputPayload), privateKey);
1922
+ if (resultMetadataPayload)
1923
+ encryptedResultMetadata = (0, processor_utils_1.encrypt)(JSON.stringify(resultMetadataPayload), privateKey);
1924
+ }
1925
+ catch (e) {
1926
+ if (process.env.NODE_ENV !== 'production') {
1927
+ console.warn('[runJobs] Skipping job execution output/result_metadata (encrypt failed)', { jobId, error: e });
1928
+ }
1929
+ }
1774
1930
  void this.processorApiService
1775
1931
  .updateJobExecutionPhase({
1776
1932
  workspace_id: this.workspace_id,
@@ -1778,8 +1934,8 @@ class ProcessorService {
1778
1934
  phase: 'completed',
1779
1935
  completed_at: completedAt,
1780
1936
  duration_ms: durationMs,
1781
- result_metadata: result != null ? { result: typeof result === 'object' ? result : { value: result } } : undefined,
1782
- output: outputPayload,
1937
+ result_metadata: encryptedResultMetadata,
1938
+ output: encryptedOutput,
1783
1939
  operation,
1784
1940
  }, auth)
1785
1941
  .catch((err) => console.error('[runJobs] job execution phase completed failed', { jobId, error: err }));
@@ -1787,10 +1943,10 @@ class ProcessorService {
1787
1943
  // Log job execution completed so it shows in logs
1788
1944
  if (this.logService) {
1789
1945
  this.logService.add({
1790
- product_tag: (_m = this.productTag) !== null && _m !== void 0 ? _m : (_o = job.data) === null || _o === void 0 ? void 0 : _o.product,
1946
+ product_tag: (_o = this.productTag) !== null && _o !== void 0 ? _o : (_p = job.data) === null || _p === void 0 ? void 0 : _p.product,
1791
1947
  product_id: this.productId,
1792
1948
  workspace_id: this.workspace_id,
1793
- env: (_q = (_p = job.data) === null || _p === void 0 ? void 0 : _p.env) !== null && _q !== void 0 ? _q : '',
1949
+ env: (_r = (_q = job.data) === null || _q === void 0 ? void 0 : _q.env) !== null && _r !== void 0 ? _r : '',
1794
1950
  process_id: jobId !== null && jobId !== void 0 ? jobId : this.process_id,
1795
1951
  type: types_1.LogEventTypes.JOB,
1796
1952
  parent_tag: jobParentTag,
@@ -1823,7 +1979,10 @@ class ProcessorService {
1823
1979
  if (jobId && this.workspace_id) {
1824
1980
  const auth = Object.assign(Object.assign({}, this.getUserAccess()), { access_key: this.accessKey });
1825
1981
  if (!this.accessKey) {
1826
- console.warn('[runJobs] Updating job execution phase without access_key — backend may return 401', { jobId, phase: 'retry_scheduled' });
1982
+ console.warn('[runJobs] Updating job execution phase without access_key — backend may return 401', {
1983
+ jobId,
1984
+ phase: 'retry_scheduled',
1985
+ });
1827
1986
  }
1828
1987
  void this.processorApiService
1829
1988
  .updateJobExecutionPhase({
@@ -1865,12 +2024,14 @@ class ProcessorService {
1865
2024
  if (jobId && this.workspace_id) {
1866
2025
  const auth = Object.assign(Object.assign({}, this.getUserAccess()), { access_key: this.accessKey });
1867
2026
  if (!this.accessKey) {
1868
- console.warn('[runJobs] Updating job execution phase (failed) without access_key — backend may return 401', { jobId });
2027
+ console.warn('[runJobs] Updating job execution phase (failed) without access_key — backend may return 401', {
2028
+ jobId,
2029
+ });
1869
2030
  }
1870
2031
  const durationMs = (jobData === null || jobData === void 0 ? void 0 : jobData.started_at) != null ? failedAt - jobData.started_at : failedAt - startedAt;
1871
2032
  const operation = typeof job.event === 'string' && job.event.includes(':')
1872
2033
  ? job.event.split(':').pop()
1873
- : (_r = job.event) !== null && _r !== void 0 ? _r : undefined;
2034
+ : (_s = job.event) !== null && _s !== void 0 ? _s : undefined;
1874
2035
  void this.processorApiService
1875
2036
  .updateJobExecutionPhase({
1876
2037
  workspace_id: this.workspace_id,
@@ -1887,10 +2048,10 @@ class ProcessorService {
1887
2048
  // Log job execution failed so it shows in logs
1888
2049
  if (this.logService) {
1889
2050
  this.logService.add({
1890
- product_tag: (_s = this.productTag) !== null && _s !== void 0 ? _s : (_t = job.data) === null || _t === void 0 ? void 0 : _t.product,
2051
+ product_tag: (_t = this.productTag) !== null && _t !== void 0 ? _t : (_u = job.data) === null || _u === void 0 ? void 0 : _u.product,
1891
2052
  product_id: this.productId,
1892
2053
  workspace_id: this.workspace_id,
1893
- env: (_v = (_u = job.data) === null || _u === void 0 ? void 0 : _u.env) !== null && _v !== void 0 ? _v : '',
2054
+ env: (_w = (_v = job.data) === null || _v === void 0 ? void 0 : _v.env) !== null && _w !== void 0 ? _w : '',
1894
2055
  process_id: jobId !== null && jobId !== void 0 ? jobId : this.process_id,
1895
2056
  type: types_1.LogEventTypes.JOB,
1896
2057
  parent_tag: jobParentTag,
@@ -1962,9 +2123,7 @@ class ProcessorService {
1962
2123
  return;
1963
2124
  const jobData = JSON.parse(data);
1964
2125
  const oldStatus = jobData.status;
1965
- const updatedJob = Object.assign(Object.assign(Object.assign({}, jobData), updates), { status, updated_at: Date.now(), execution_count: status === 'completed' || status === 'failed'
1966
- ? (jobData.execution_count || 0) + 1
1967
- : jobData.execution_count });
2126
+ const updatedJob = Object.assign(Object.assign(Object.assign({}, jobData), updates), { status, updated_at: Date.now(), execution_count: status === 'completed' || status === 'failed' ? (jobData.execution_count || 0) + 1 : jobData.execution_count });
1968
2127
  // Update job data
1969
2128
  await redis.setex(jobKey, 90 * 24 * 60 * 60, JSON.stringify(updatedJob));
1970
2129
  // Update status indices
@@ -1975,6 +2134,58 @@ class ProcessorService {
1975
2134
  await redis.sadd(newStatusKey, jobId);
1976
2135
  }
1977
2136
  }
2137
+ /**
2138
+ * Cache key for action bootstrap. Same app + env + action = same version scope on backend.
2139
+ */
2140
+ getActionBootstrapCacheKey(product_tag, app, env, action_tag) {
2141
+ return `${ACTION_BOOTSTRAP_REDIS_PREFIX}${this.workspace_id}:${product_tag || ''}:${app}:${env}:${action_tag}`;
2142
+ }
2143
+ /**
2144
+ * Get cached action bootstrap (internal cache first, then Redis). Returns null on miss or error.
2145
+ */
2146
+ async getCachedActionBootstrap(key) {
2147
+ const now = Date.now();
2148
+ const entry = this.actionBootstrapCache.get(key);
2149
+ if (entry && now - entry.storedAt < ACTION_BOOTSTRAP_CACHE_TTL_MS) {
2150
+ return entry.data;
2151
+ }
2152
+ if (entry) {
2153
+ this.actionBootstrapCache.delete(key);
2154
+ }
2155
+ if (!this.redisClient || !this._privateKey)
2156
+ return null;
2157
+ try {
2158
+ const redis = this.redisClient;
2159
+ const raw = await redis.get(key);
2160
+ if (!raw)
2161
+ return null;
2162
+ const decrypted = (0, processor_utils_1.decrypt)(raw, this._privateKey);
2163
+ const data = JSON.parse(decrypted);
2164
+ this.actionBootstrapCache.set(key, { data, storedAt: now });
2165
+ return data;
2166
+ }
2167
+ catch (_a) {
2168
+ return null;
2169
+ }
2170
+ }
2171
+ /**
2172
+ * Store action bootstrap in internal cache and Redis (fire-and-forget for Redis). Encrypts with workspace key.
2173
+ */
2174
+ setCachedActionBootstrap(key, data) {
2175
+ const now = Date.now();
2176
+ this.actionBootstrapCache.set(key, { data, storedAt: now });
2177
+ if (!this.redisClient || !this._privateKey)
2178
+ return;
2179
+ const ttlSeconds = Math.ceil(ACTION_BOOTSTRAP_CACHE_TTL_MS / 1000);
2180
+ try {
2181
+ const redis = this.redisClient;
2182
+ const encrypted = (0, processor_utils_1.encrypt)(JSON.stringify(data), this._privateKey);
2183
+ redis.setex(key, ttlSeconds, encrypted).catch(() => { });
2184
+ }
2185
+ catch (_a) {
2186
+ // ignore
2187
+ }
2188
+ }
1978
2189
  /**
1979
2190
  * Add job execution record to history
1980
2191
  */
@@ -2387,7 +2598,7 @@ class ProcessorService {
2387
2598
  token: this.token,
2388
2599
  env_type: this.environment,
2389
2600
  private_key: this._privateKey,
2390
- access_key: this.accessKey
2601
+ access_key: this.accessKey,
2391
2602
  });
2392
2603
  // Execute the workflow
2393
2604
  const result = await workflowService.execute({
@@ -2532,7 +2743,7 @@ class ProcessorService {
2532
2743
  return (0, processor_utils_1.generateIndexes)(operator, iter, init, valueValue);
2533
2744
  }
2534
2745
  async runAction(event, additional_logs, returnValue = true, bootstrapData) {
2535
- var _a, _b, _c;
2746
+ var _a, _b, _c, _d;
2536
2747
  try {
2537
2748
  const { event: action_tag, app: access_tag, condition, cache: cache_tag } = event;
2538
2749
  let indexes = [];
@@ -2563,6 +2774,8 @@ class ProcessorService {
2563
2774
  app_active = bootstrapData.app_active;
2564
2775
  app_env_slug = env.slug;
2565
2776
  envMapping = (_a = bootstrapData.product_env_mapping) !== null && _a !== void 0 ? _a : null;
2777
+ // app_id is set in processAction on baseLogs from bootstrap; use it so logs/pricing get valid app_id
2778
+ app_id = (_b = this.baseLogs.app_id) !== null && _b !== void 0 ? _b : '';
2566
2779
  additional_logs.app_env = app_env_slug;
2567
2780
  }
2568
2781
  else {
@@ -2571,7 +2784,7 @@ class ProcessorService {
2571
2784
  const { actions, envs: appEnvs, retries: appRetries, workspace_id: appWorkspaceId, active } = appData;
2572
2785
  const productApp = await this.productBuilderService.fetchApp(access_tag);
2573
2786
  const { envs: productEnvs } = productApp;
2574
- envMapping = (_b = productEnvs.find((item) => item.product_env_slug === this.processEnv.slug)) !== null && _b !== void 0 ? _b : null;
2787
+ envMapping = (_c = productEnvs.find((item) => item.product_env_slug === this.processEnv.slug)) !== null && _c !== void 0 ? _c : null;
2575
2788
  app_env_slug = (envMapping === null || envMapping === void 0 ? void 0 : envMapping.app_env_slug) || '';
2576
2789
  additional_logs.app_env = app_env_slug;
2577
2790
  env = appEnvs.find((item) => item.slug === app_env_slug);
@@ -2602,7 +2815,7 @@ class ProcessorService {
2602
2815
  }
2603
2816
  }
2604
2817
  // Resolve {{variable}} and :variable in base_url with product env variables
2605
- if ((_c = envMapping === null || envMapping === void 0 ? void 0 : envMapping.variables) === null || _c === void 0 ? void 0 : _c.length) {
2818
+ if ((_d = envMapping === null || envMapping === void 0 ? void 0 : envMapping.variables) === null || _d === void 0 ? void 0 : _d.length) {
2606
2819
  request_base_url = (0, string_utils_2.resolveBaseUrlVariables)(request_base_url, envMapping.variables);
2607
2820
  }
2608
2821
  const samples = {
@@ -2629,7 +2842,7 @@ class ProcessorService {
2629
2842
  }, additional_logs);
2630
2843
  if (check) {
2631
2844
  result = JSON.parse(check);
2632
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Run action - response from cache', data: { result: (0, processor_utils_1.anonymizeObject)(result) }, status: types_1.LogEventStatus.SUCCESS, cache_tag, action: event.event }));
2845
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Run action - response from cache', data: { result }, status: types_1.LogEventStatus.SUCCESS, cache_tag, action: event.event }));
2633
2846
  if (returnValue) {
2634
2847
  return result;
2635
2848
  }
@@ -2690,12 +2903,14 @@ class ProcessorService {
2690
2903
  const end = Date.now();
2691
2904
  this.requestTime += end - start;
2692
2905
  this.totalRequests += 1;
2693
- const { pricing_tag, pricing_cost, is_overage, currency } = await this.processPricingCost(Object.assign(Object.assign({}, additional_logs), { app_id, workspace_id: this.workspace_id }));
2694
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { pricing_tag,
2695
- pricing_cost,
2696
- currency,
2697
- is_overage, message: 'Process http request - success', successful_execution: true, data: { response: (0, processor_utils_1.anonymizeObject)(results) }, status: types_1.LogEventStatus.SUCCESS, app_id, action: event.event, start,
2698
- end }));
2906
+ const pricing = await this.processPricingCost(Object.assign(Object.assign({}, additional_logs), { app_id, workspace_id: this.workspace_id }));
2907
+ const log = Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Process http request - success', successful_execution: true, data: { response: results }, status: types_1.LogEventStatus.SUCCESS, app_id, action: event.event, start,
2908
+ end });
2909
+ if (pricing) {
2910
+ const { pricing_tag, pricing_cost, is_overage, currency } = pricing;
2911
+ Object.assign(log, { pricing_tag, pricing_cost, is_overage, currency });
2912
+ }
2913
+ this.logService.add(log);
2699
2914
  await this.addToSuccessOutput(event, results, additional_logs);
2700
2915
  if (returnValue) {
2701
2916
  return { process_id: this.process_id, status: true, data: results };
@@ -2712,7 +2927,7 @@ class ProcessorService {
2712
2927
  }
2713
2928
  this.requestTime += end - start;
2714
2929
  this.totalRequests += 1;
2715
- 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,
2930
+ 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: payloads }, status: types_1.LogEventStatus.FAIL, app_id, action: event.event, start,
2716
2931
  end }));
2717
2932
  try {
2718
2933
  debugLog(e);
@@ -2798,7 +3013,7 @@ class ProcessorService {
2798
3013
  }
2799
3014
  catch (e) {
2800
3015
  this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Process Pricing Cost - failed', data: { error: e }, status: types_1.LogEventStatus.FAIL }));
2801
- throw e;
3016
+ return null;
2802
3017
  }
2803
3018
  }
2804
3019
  async addToSuccessOutput(event, output, additional_logs) {
@@ -2882,7 +3097,7 @@ class ProcessorService {
2882
3097
  }
2883
3098
  if (retries_left > 0) {
2884
3099
  setTimeout(() => {
2885
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Retrying Request', data: Object.assign(Object.assign({}, output), { payload: (0, processor_utils_1.anonymizeObject)(output.payload) }), status: types_1.LogEventStatus.PROCESSING }));
3100
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Retrying Request', data: Object.assign(Object.assign({}, output), { payload: output.payload }), status: types_1.LogEventStatus.PROCESSING }));
2886
3101
  if (event.type === types_1.FeatureEventTypes.ACTION) {
2887
3102
  this.processRequest(payload, event, policy, additional_logs);
2888
3103
  }
@@ -2893,7 +3108,7 @@ class ProcessorService {
2893
3108
  }
2894
3109
  if (allow_fail === false && retries_left === 0) {
2895
3110
  this.published = true;
2896
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Ran out of retries - failed', data: Object.assign(Object.assign({}, output), { payload: (0, processor_utils_1.anonymizeObject)(output.payload) }), status: types_1.LogEventStatus.FAIL }));
3111
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Ran out of retries - failed', data: Object.assign({}, output), status: types_1.LogEventStatus.FAIL }));
2897
3112
  //throw new Error("Run out of retries")
2898
3113
  this.end = Date.now();
2899
3114
  await this.writeResult(types_1.LogEventStatus.FAIL, retryable);
@@ -2946,13 +3161,13 @@ class ProcessorService {
2946
3161
  return response.data;
2947
3162
  }
2948
3163
  catch (e) {
2949
- //console.error("LOG ERROR", e);
3164
+ //// console.error("LOG ERROR", e);
2950
3165
  throw e;
2951
3166
  }
2952
3167
  }
2953
3168
  async processStorage(action) {
2954
3169
  //TODO: schema validation
2955
- var _a, _b, _c, _d, _e, _f, _g;
3170
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2956
3171
  const { env, input, retries, event, product: product_tag, session, cache, preloadedBootstrap } = action;
2957
3172
  // event is "storage_tag:operation" (e.g. gcp-storage:upload); backend looks up storage by tag only
2958
3173
  const storageTag = event.includes(':') ? event.split(':')[0] : event;
@@ -2973,7 +3188,7 @@ class ProcessorService {
2973
3188
  this.clone = (0, processor_utils_1.structuredClone)(input);
2974
3189
  (0, processor_utils_1.cleanBlob)(this.clone);
2975
3190
  this.productTag = product_tag;
2976
- const process_id = (0, processor_utils_1.generateObjectId)();
3191
+ const process_id = (0, uuid_1.v4)();
2977
3192
  this.baseLogs = Object.assign({ product_tag: this.productTag, product_id: this.productId, workspace_id: this.workspace_id, env,
2978
3193
  process_id, data: this.clone }, additional_logs);
2979
3194
  // Use preloaded bootstrap when provided (e.g. workflow batch prefetch), otherwise fetch
@@ -3011,6 +3226,7 @@ class ProcessorService {
3011
3226
  user_id: this.user_id,
3012
3227
  token: this.token,
3013
3228
  env_type: this.environment,
3229
+ workspace_private_key: (_a = this._privateKey) !== null && _a !== void 0 ? _a : undefined,
3014
3230
  });
3015
3231
  }
3016
3232
  this.process_id = process_id;
@@ -3045,10 +3261,10 @@ class ProcessorService {
3045
3261
  }
3046
3262
  catch (e) {
3047
3263
  const err = e;
3048
- 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;
3264
+ const apiReason = (_c = (_b = err === null || err === void 0 ? void 0 : err.response) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.errors;
3049
3265
  const reason = typeof apiReason === 'string'
3050
3266
  ? apiReason
3051
- : (_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);
3267
+ : (_h = (_g = (_d = apiReason === null || apiReason === void 0 ? void 0 : apiReason.message) !== null && _d !== void 0 ? _d : (_f = (_e = err === null || err === void 0 ? void 0 : err.response) === null || _e === void 0 ? void 0 : _e.data) === null || _f === void 0 ? void 0 : _f.message) !== null && _g !== void 0 ? _g : err === null || err === void 0 ? void 0 : err.message) !== null && _h !== void 0 ? _h : String(e);
3052
3268
  const message = `Storing file - failed: ${reason}`;
3053
3269
  this.end = Date.now();
3054
3270
  if (this.logService) {
@@ -3074,7 +3290,7 @@ class ProcessorService {
3074
3290
  await this.validateActionDataMappingInput(data.input, types_1.FeatureEventTypes.STORAGE);
3075
3291
  this.start = Date.now();
3076
3292
  this.productTag = data.product;
3077
- const process_id = (0, processor_utils_1.generateObjectId)();
3293
+ const process_id = (0, uuid_1.v4)();
3078
3294
  this.input = data;
3079
3295
  this.baseLogs = Object.assign({ product_tag: this.productTag, product_id: this.productId, workspace_id: this.workspace_id, env: data.env, process_id, data: data.input }, additional_logs);
3080
3296
  await this.intializeProduct(additional_logs);
@@ -3109,7 +3325,7 @@ class ProcessorService {
3109
3325
  }
3110
3326
  }
3111
3327
  async processMessageBrokerPublish(data) {
3112
- var _a, _b, _c, _d;
3328
+ var _a, _b, _c, _d, _e;
3113
3329
  const [brokerTag, topicTag] = data.event.split(':');
3114
3330
  if (!brokerTag || !topicTag) {
3115
3331
  throw new Error(`message broker events should be in the format broker_tag:event_tag`);
@@ -3130,7 +3346,7 @@ class ProcessorService {
3130
3346
  this.clone = (0, processor_utils_1.structuredClone)(data.input);
3131
3347
  this.input = data;
3132
3348
  this.productTag = data.product;
3133
- const process_id = (0, processor_utils_1.generateObjectId)();
3349
+ const process_id = (0, uuid_1.v4)();
3134
3350
  this.component = types_1.LogEventTypes.MESSAGEBROKER;
3135
3351
  this.baseLogs = Object.assign({ product_tag: this.productTag, workspace_id: this.workspace_id, env: data.env, process_id, data: this.clone }, additional_logs);
3136
3352
  await this.intializeProduct(additional_logs);
@@ -3144,6 +3360,7 @@ class ProcessorService {
3144
3360
  user_id: this.user_id,
3145
3361
  token: this.token,
3146
3362
  env_type: this.environment,
3363
+ workspace_private_key: (_a = this._privateKey) !== null && _a !== void 0 ? _a : undefined,
3147
3364
  });
3148
3365
  }
3149
3366
  // Process session if provided - verify and resolve $Session{} references
@@ -3180,7 +3397,7 @@ class ProcessorService {
3180
3397
  };
3181
3398
  const result = await this.runBrokerPublish(payload);
3182
3399
  this.end = Date.now();
3183
- 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 }));
3400
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Produce to topic - success', data: { input: this.clone, result: result !== null && result !== void 0 ? result : {} }, status: types_1.LogEventStatus.SUCCESS }));
3184
3401
  await this.writeResult(types_1.LogEventStatus.SUCCESS);
3185
3402
  // Fire-and-forget so step latency isn't dominated by log upload (20–50x slower otherwise)
3186
3403
  this.logService.publish().catch(() => { });
@@ -3188,10 +3405,8 @@ class ProcessorService {
3188
3405
  }
3189
3406
  catch (e) {
3190
3407
  const err = e;
3191
- 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;
3192
- const reason = typeof apiReason === 'string'
3193
- ? apiReason
3194
- : (_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);
3408
+ const apiReason = (_c = (_b = err === null || err === void 0 ? void 0 : err.response) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.errors;
3409
+ const reason = typeof apiReason === 'string' ? apiReason : (_e = (_d = apiReason === null || apiReason === void 0 ? void 0 : apiReason.message) !== null && _d !== void 0 ? _d : err === null || err === void 0 ? void 0 : err.message) !== null && _e !== void 0 ? _e : String(e);
3195
3410
  const message = `Publishing to topic - failed: ${reason}`;
3196
3411
  this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message, data: { e, reason }, status: types_1.LogEventStatus.FAIL }));
3197
3412
  this.end = Date.now();
@@ -3201,7 +3416,7 @@ class ProcessorService {
3201
3416
  }
3202
3417
  }
3203
3418
  async processJob(job, additional_logs = {}) {
3204
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
3419
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
3205
3420
  await this.productBuilderService.initializeProductByTag(job.product);
3206
3421
  const productId = this.productBuilderService.fetchProductId();
3207
3422
  if (productId)
@@ -3219,6 +3434,7 @@ class ProcessorService {
3219
3434
  user_id: this.user_id,
3220
3435
  token: this.token,
3221
3436
  env_type: this.environment,
3437
+ workspace_private_key: (_a = this._privateKey) !== null && _a !== void 0 ? _a : undefined,
3222
3438
  });
3223
3439
  }
3224
3440
  await this.validateActionDataMappingInput(job.input, productJob.type);
@@ -3230,13 +3446,16 @@ class ProcessorService {
3230
3446
  let jobInput;
3231
3447
  let namespace = productJob.type;
3232
3448
  if (productJob.type === types_1.JobEventTypes.ACTION) {
3449
+ const actionName = typeof job.event === 'string' && job.event.includes(':')
3450
+ ? job.event.split(':').pop()
3451
+ : job.event;
3233
3452
  const input = {
3234
3453
  env: job.env,
3235
3454
  product: job.product,
3236
3455
  app: productJob.app,
3237
3456
  cache: job.cache,
3238
3457
  input: job.input,
3239
- action: job.event,
3458
+ action: actionName,
3240
3459
  session: job.session,
3241
3460
  };
3242
3461
  jobInput = input;
@@ -3351,7 +3570,7 @@ class ProcessorService {
3351
3570
  throw new Error(`Job type ${productJob.type} not supported`);
3352
3571
  }
3353
3572
  // Determine if this is a recurring job
3354
- const isRecurring = !!(((_a = job.repeat) === null || _a === void 0 ? void 0 : _a.cron) || ((_b = job.repeat) === null || _b === void 0 ? void 0 : _b.every));
3573
+ const isRecurring = !!(((_b = job.repeat) === null || _b === void 0 ? void 0 : _b.cron) || ((_c = job.repeat) === null || _c === void 0 ? void 0 : _c.every));
3355
3574
  // Generate a unique job ID
3356
3575
  const jobId = `job_${(0, uuid_1.v4)().replace(/-/g, '').substring(0, 16)}`;
3357
3576
  // Build queue options
@@ -3359,7 +3578,7 @@ class ProcessorService {
3359
3578
  jobId,
3360
3579
  };
3361
3580
  // Handle `delay` only if repeat.every is not defined
3362
- if (!((_c = job.repeat) === null || _c === void 0 ? void 0 : _c.every) && delay > 0) {
3581
+ if (!((_d = job.repeat) === null || _d === void 0 ? void 0 : _d.every) && delay > 0) {
3363
3582
  options.delay = delay;
3364
3583
  }
3365
3584
  // Add repeat config if defined
@@ -3408,17 +3627,17 @@ class ProcessorService {
3408
3627
  app: productJob.app,
3409
3628
  scheduled_at,
3410
3629
  recurring: isRecurring,
3411
- cron: (_d = job.repeat) === null || _d === void 0 ? void 0 : _d.cron,
3412
- every: (_e = job.repeat) === null || _e === void 0 ? void 0 : _e.every,
3630
+ cron: (_e = job.repeat) === null || _e === void 0 ? void 0 : _e.cron,
3631
+ every: (_f = job.repeat) === null || _f === void 0 ? void 0 : _f.every,
3413
3632
  next_run_at,
3414
3633
  execution_count: 0,
3415
- limit: (_f = job.repeat) === null || _f === void 0 ? void 0 : _f.limit,
3416
- end_date: ((_g = job.repeat) === null || _g === void 0 ? void 0 : _g.endDate)
3634
+ limit: (_g = job.repeat) === null || _g === void 0 ? void 0 : _g.limit,
3635
+ end_date: ((_h = job.repeat) === null || _h === void 0 ? void 0 : _h.endDate)
3417
3636
  ? typeof job.repeat.endDate === 'string'
3418
3637
  ? new Date(job.repeat.endDate).getTime()
3419
3638
  : job.repeat.endDate
3420
3639
  : undefined,
3421
- tz: (_h = job.repeat) === null || _h === void 0 ? void 0 : _h.tz,
3640
+ tz: (_j = job.repeat) === null || _j === void 0 ? void 0 : _j.tz,
3422
3641
  retries: job.retries || 0,
3423
3642
  retry_count: 0,
3424
3643
  input: jobInput,
@@ -3442,11 +3661,11 @@ class ProcessorService {
3442
3661
  // Add job input with the job ID for tracking
3443
3662
  jobInput._job_id = jobId;
3444
3663
  // Add job to queue
3445
- if (!((_j = this.queues) === null || _j === void 0 ? void 0 : _j.jobs)) {
3664
+ if (!((_k = this.queues) === null || _k === void 0 ? void 0 : _k.jobs)) {
3446
3665
  throw new Error('Queues not configured. dispatch() requires a queue connection.');
3447
3666
  }
3448
3667
  await this.queues.jobs.add(productJob.type, jobInput, options);
3449
- // Record job execution in integrations (so jobexecutiontrackers table is populated)
3668
+ // Record job execution in integrations (so jobexecutiontrackers table is populated). Sensitive fields encrypted with product key.
3450
3669
  if (this.workspace_id && this.productId) {
3451
3670
  const auth = Object.assign(Object.assign({}, this.getUserAccess()), { access_key: this.accessKey });
3452
3671
  if (!this.accessKey) {
@@ -3454,7 +3673,20 @@ class ProcessorService {
3454
3673
  }
3455
3674
  const operation = typeof job.event === 'string' && job.event.includes(':')
3456
3675
  ? job.event.split(':').pop()
3457
- : (_k = job.event) !== null && _k !== void 0 ? _k : undefined;
3676
+ : (_l = job.event) !== null && _l !== void 0 ? _l : undefined;
3677
+ let encryptedInput;
3678
+ if (job.input != null && typeof job.input === 'object') {
3679
+ try {
3680
+ const privateKey = this.productBuilderService.fetchPrivateKey();
3681
+ const inputObj = (0, processor_utils_1.truncateInputForApi)(job.input);
3682
+ encryptedInput = (0, processor_utils_1.encrypt)(JSON.stringify(inputObj), privateKey);
3683
+ }
3684
+ catch (e) {
3685
+ if (process.env.NODE_ENV !== 'production') {
3686
+ console.warn('[processJob] Skipping job execution input (encrypt failed)', { jobId, error: e });
3687
+ }
3688
+ }
3689
+ }
3458
3690
  void this.processorApiService
3459
3691
  .createJobExecution({
3460
3692
  job_id: jobId,
@@ -3467,9 +3699,7 @@ class ProcessorService {
3467
3699
  phase: delay > 0 ? 'scheduled' : 'queued',
3468
3700
  scheduled_at: delay > 0 ? scheduled_at : undefined,
3469
3701
  triggered_by: job.triggered_by,
3470
- input: job.input != null && typeof job.input === 'object'
3471
- ? (0, processor_utils_1.truncateInputForApi)(job.input)
3472
- : undefined,
3702
+ input: encryptedInput,
3473
3703
  operation,
3474
3704
  }, auth)
3475
3705
  .catch((err) => console.error('[processJob] job execution create failed', { jobId, error: err }));
@@ -3554,7 +3784,10 @@ class ProcessorService {
3554
3784
  (0, processor_utils_1.validateNotification)(template, payload);
3555
3785
  debugLog('[ProcessExpoNotification] Validation passed');
3556
3786
  const { title, body, data } = (0, processor_utils_1.generateNotificationTemplate)(template, payload);
3557
- 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 });
3787
+ debugLog('[ProcessExpoNotification] Template generated', {
3788
+ title: (_b = title === null || title === void 0 ? void 0 : title.slice) === null || _b === void 0 ? void 0 : _b.call(title, 0, 40),
3789
+ bodyLength: body === null || body === void 0 ? void 0 : body.length,
3790
+ });
3558
3791
  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 }));
3559
3792
  debugLog('[ProcessExpoNotification] Sending to Expo');
3560
3793
  await this.sendExpoNotification({ title, body, data }, payload.device_tokens);
@@ -3566,14 +3799,17 @@ class ProcessorService {
3566
3799
  (0, processor_utils_1.validateNotification)(template, payload);
3567
3800
  debugLog('[ProcessFirebaseNotification] Validation passed');
3568
3801
  const { title, body, data } = (0, processor_utils_1.generateNotificationTemplate)(template, payload);
3569
- 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 });
3802
+ debugLog('[ProcessFirebaseNotification] Template generated', {
3803
+ title: (_b = title === null || title === void 0 ? void 0 : title.slice) === null || _b === void 0 ? void 0 : _b.call(title, 0, 40),
3804
+ bodyLength: body === null || body === void 0 ? void 0 : body.length,
3805
+ });
3570
3806
  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 }));
3571
3807
  debugLog('[ProcessFirebaseNotification] Sending to Firebase');
3572
3808
  await this.sendFirebaseNotification({ title, body, data }, payload.device_tokens, notification.credentials, scope);
3573
3809
  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 }));
3574
3810
  }
3575
3811
  async runNotification(notification, additional_logs, bootstrapData) {
3576
- 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, _1, _2, _3;
3812
+ 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, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23;
3577
3813
  const { event } = notification;
3578
3814
  const input = notification.input;
3579
3815
  const logMessageLog = (channelType, status, err) => {
@@ -3581,7 +3817,12 @@ class ProcessorService {
3581
3817
  return;
3582
3818
  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) })));
3583
3819
  };
3584
- debugLog('[runNotification] ENTRY', { event, env: (_a = notification.env) === null || _a === void 0 ? void 0 : _a.slug, hasBootstrap: !!bootstrapData, inputKeys: input ? Object.keys(input) : [] });
3820
+ debugLog('[runNotification] ENTRY', {
3821
+ event,
3822
+ env: (_a = notification.env) === null || _a === void 0 ? void 0 : _a.slug,
3823
+ hasBootstrap: !!bootstrapData,
3824
+ inputKeys: input ? Object.keys(input) : [],
3825
+ });
3585
3826
  try {
3586
3827
  let notificationEvent;
3587
3828
  let message;
@@ -3607,13 +3848,15 @@ class ProcessorService {
3607
3848
  debugLog('[runNotification] ERROR: env config not found', { envSlug: (_c = notification.env) === null || _c === void 0 ? void 0 : _c.slug });
3608
3849
  throw new Error(`Notification env config for ${notification.env.slug} not found`);
3609
3850
  }
3610
- let { push_notifications: notifications, emails, callbacks, sms: smses, } = envConfig;
3851
+ let { push_notifications: notifications, emails, callbacks, sms: smses, slack: slackConfig, discord: discordConfig } = envConfig;
3611
3852
  debugLog('[runNotification] Env config channels', {
3612
3853
  hasPush: !!notifications,
3613
3854
  pushType: notifications === null || notifications === void 0 ? void 0 : notifications.type,
3614
3855
  hasEmails: !!emails,
3615
3856
  hasCallbacks: !!callbacks,
3616
3857
  hasSms: !!smses,
3858
+ hasSlack: !!slackConfig,
3859
+ hasDiscord: !!discordConfig,
3617
3860
  });
3618
3861
  // Resolve any $Secret{} references in notification configs
3619
3862
  const secretsService = (0, secrets_1.getSecretsService)();
@@ -3634,21 +3877,41 @@ class ProcessorService {
3634
3877
  const resolved = await secretsService.resolve(smses, { env: notification.env.slug });
3635
3878
  smses = resolved.value;
3636
3879
  }
3880
+ if (slackConfig && (0, secrets_1.mightContainSecrets)(slackConfig)) {
3881
+ const resolved = await secretsService.resolve(slackConfig, { env: notification.env.slug });
3882
+ slackConfig = resolved.value;
3883
+ }
3884
+ if (discordConfig && (0, secrets_1.mightContainSecrets)(discordConfig)) {
3885
+ const resolved = await secretsService.resolve(discordConfig, { env: notification.env.slug });
3886
+ discordConfig = resolved.value;
3887
+ }
3637
3888
  }
3638
- const { push_notification: push, email, callback, sms } = message;
3889
+ const { push_notification: push, email, callback, sms, slack: slackMessage, discord: discordMessage } = message;
3639
3890
  const notifScope = {
3640
3891
  workspaceId: (_d = this.workspace_id) !== null && _d !== void 0 ? _d : '',
3641
3892
  product: (_f = (_e = bootstrapData === null || bootstrapData === void 0 ? void 0 : bootstrapData.product_tag) !== null && _e !== void 0 ? _e : this.productTag) !== null && _f !== void 0 ? _f : '',
3642
3893
  };
3643
- debugLog('[runNotification] Message template flags', { push: !!push, email: !!email, callback: !!callback, sms: !!sms });
3894
+ debugLog('[runNotification] Message template flags', {
3895
+ push: !!push,
3896
+ email: !!email,
3897
+ callback: !!callback,
3898
+ sms: !!sms,
3899
+ slack: !!slackMessage,
3900
+ discord: !!discordMessage,
3901
+ });
3644
3902
  debugLog('[runNotification] Input channels present', {
3645
3903
  push_notification: !!input.push_notification,
3646
3904
  email: !!input.email,
3647
3905
  callback: !!input.callback,
3648
3906
  sms: !!input.sms,
3907
+ slack: !!input.slack,
3908
+ discord: !!input.discord,
3649
3909
  });
3650
3910
  if (!push && (input.push_notification || notifications)) {
3651
- debugLog('[runNotification] PUSH: skipped (message has no push template)', { hasInputPush: !!input.push_notification, hasNotifications: !!notifications });
3911
+ debugLog('[runNotification] PUSH: skipped (message has no push template)', {
3912
+ hasInputPush: !!input.push_notification,
3913
+ hasNotifications: !!notifications,
3914
+ });
3652
3915
  }
3653
3916
  if (push && !input.push_notification) {
3654
3917
  debugLog('[runNotification] PUSH: skipped (no input.push_notification)');
@@ -3666,7 +3929,10 @@ class ProcessorService {
3666
3929
  }));
3667
3930
  //await this.inputService.validateInput(validationPayload, message.push_notification_data, "Push Notifications");
3668
3931
  }
3669
- 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) {
3932
+ if (push &&
3933
+ input.push_notification &&
3934
+ (notifications === null || notifications === void 0 ? void 0 : notifications.type) !== types_1.Notifiers.EXPO &&
3935
+ (notifications === null || notifications === void 0 ? void 0 : notifications.type) !== types_1.Notifiers.FIREBASE) {
3670
3936
  debugLog('[runNotification] PUSH: skipped (not Expo or Firebase)', { notificationsType: notifications === null || notifications === void 0 ? void 0 : notifications.type });
3671
3937
  this.lastNotificationFailureType = types_1.LogEventTypes.PUSH;
3672
3938
  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 }));
@@ -3731,7 +3997,10 @@ class ProcessorService {
3731
3997
  subject,
3732
3998
  template,
3733
3999
  };
3734
- debugLog('[runNotification] EMAIL: sending mail', { to: (_g = mailOptions.to) === null || _g === void 0 ? void 0 : _g.length, subject: (_j = (_h = mailOptions.subject) === null || _h === void 0 ? void 0 : _h.slice) === null || _j === void 0 ? void 0 : _j.call(_h, 0, 50) });
4000
+ debugLog('[runNotification] EMAIL: sending mail', {
4001
+ to: (_g = mailOptions.to) === null || _g === void 0 ? void 0 : _g.length,
4002
+ subject: (_j = (_h = mailOptions.subject) === null || _h === void 0 ? void 0 : _h.slice) === null || _j === void 0 ? void 0 : _j.call(_h, 0, 50),
4003
+ });
3735
4004
  try {
3736
4005
  const transporter = await this.getMailTransporter(auth, notifScope);
3737
4006
  await transporter.sendMail(mailOptions);
@@ -3771,7 +4040,11 @@ class ProcessorService {
3771
4040
  //this.inputService.validateInput(validationPayload, message.callback_data);
3772
4041
  const callbackUrl = callbacks === null || callbacks === void 0 ? void 0 : callbacks.url;
3773
4042
  if (callbackUrl == null || callbackUrl === '') {
3774
- 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) : [] })}`);
4043
+ throw new Error(`Callback config has no url. Env callback config: ${JSON.stringify({
4044
+ url: callbacks === null || callbacks === void 0 ? void 0 : callbacks.url,
4045
+ method: callbacks === null || callbacks === void 0 ? void 0 : callbacks.method,
4046
+ keys: callbacks ? Object.keys(callbacks) : [],
4047
+ })}`);
3775
4048
  }
3776
4049
  const url = new URL(callbackUrl);
3777
4050
  const requestPayload = {
@@ -3821,7 +4094,97 @@ class ProcessorService {
3821
4094
  logMessageLog('sms', 'failed', e);
3822
4095
  }
3823
4096
  }
3824
- debugLog('[runNotification] DONE: all channels processed', { lastChannelType: (_2 = this.lastNotificationFailureType) !== null && _2 !== void 0 ? _2 : 'NOTIFICATIONS' });
4097
+ if (slackMessage && slackConfig && !input.slack) {
4098
+ debugLog('[runNotification] SLACK: skipped (no input.slack)');
4099
+ }
4100
+ if (slackMessage && slackConfig && input.slack) {
4101
+ const webhookUrl = typeof slackConfig === 'object' && slackConfig !== null && 'webhook_url' in slackConfig ? slackConfig.webhook_url : undefined;
4102
+ if (!webhookUrl) {
4103
+ debugLog('[runNotification] SLACK: skipped (no webhook_url in config)');
4104
+ }
4105
+ else {
4106
+ this.lastNotificationFailureType = types_1.LogEventTypes.SLACK;
4107
+ try {
4108
+ const slackData = message.slack_data;
4109
+ let text;
4110
+ let blocks = input.slack.blocks;
4111
+ if (slackData === null || slackData === void 0 ? void 0 : slackData.length) {
4112
+ const templateText = (_2 = (typeof slackMessage === 'object' && slackMessage !== null && 'text' in slackMessage ? slackMessage.text : null)) !== null && _2 !== void 0 ? _2 : '';
4113
+ const textInput = input.slack.text !== undefined ? input.slack.text : templateText;
4114
+ const textPayload = await this.generatePayload((typeof textInput === 'object' && textInput !== null ? textInput : { text: textInput }), notification, additional_logs, slackData.filter((d) => d.parent_key === 'text'));
4115
+ text = typeof textPayload === 'object' && textPayload !== null && 'text' in textPayload ? String((_3 = textPayload.text) !== null && _3 !== void 0 ? _3 : '') : String(textPayload !== null && textPayload !== void 0 ? textPayload : '');
4116
+ if (((_4 = input.slack.blocks) === null || _4 === void 0 ? void 0 : _4.length) && slackData.some((d) => d.parent_key === 'blocks')) {
4117
+ blocks = (await this.generatePayload({ blocks: input.slack.blocks }, notification, additional_logs, slackData.filter((d) => d.parent_key === 'blocks')));
4118
+ if (blocks && typeof blocks === 'object' && !Array.isArray(blocks) && 'blocks' in blocks)
4119
+ blocks = blocks.blocks;
4120
+ }
4121
+ }
4122
+ else {
4123
+ const textResolved = await (0, processor_utils_1.replacePlaceholderString)((_7 = (_5 = (typeof slackMessage === 'object' && slackMessage !== null && 'text' in slackMessage ? slackMessage.text : null)) !== null && _5 !== void 0 ? _5 : (_6 = input.slack) === null || _6 === void 0 ? void 0 : _6.text) !== null && _7 !== void 0 ? _7 : '', ((_8 = input.slack) !== null && _8 !== void 0 ? _8 : {}));
4124
+ text = typeof textResolved === 'string' ? textResolved : String((_10 = (_9 = input.slack) === null || _9 === void 0 ? void 0 : _9.text) !== null && _10 !== void 0 ? _10 : '');
4125
+ }
4126
+ const body = (blocks === null || blocks === void 0 ? void 0 : blocks.length) ? { blocks: blocks } : { text: text || '' };
4127
+ if (input.slack.channel)
4128
+ body.channel = input.slack.channel;
4129
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.SLACK, name: 'Send Slack - initiated', data: { hasText: !!text, hasBlocks: !!((_11 = input.slack.blocks) === null || _11 === void 0 ? void 0 : _11.length) }, status: types_1.LogEventStatus.SUCCESS }));
4130
+ await axios_1.default.post(webhookUrl, body, { headers: { 'Content-Type': 'application/json' }, timeout: 10000 });
4131
+ debugLog('[runNotification] SLACK: success');
4132
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.SLACK, name: 'Send Slack - success', successful_execution: true, data: {}, status: types_1.LogEventStatus.SUCCESS }));
4133
+ logMessageLog('slack', 'sent');
4134
+ }
4135
+ catch (e) {
4136
+ debugLog('[runNotification] SLACK: failed', e);
4137
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.SLACK, failed_execution: true, message: 'Send Slack - failed', data: { e }, status: types_1.LogEventStatus.FAIL }));
4138
+ logMessageLog('slack', 'failed', e);
4139
+ }
4140
+ }
4141
+ }
4142
+ if (discordMessage && discordConfig && !input.discord) {
4143
+ debugLog('[runNotification] DISCORD: skipped (no input.discord)');
4144
+ }
4145
+ if (discordMessage && discordConfig && input.discord) {
4146
+ const webhookUrl = typeof discordConfig === 'object' && discordConfig !== null && 'webhook_url' in discordConfig ? discordConfig.webhook_url : undefined;
4147
+ if (!webhookUrl) {
4148
+ debugLog('[runNotification] DISCORD: skipped (no webhook_url in config)');
4149
+ }
4150
+ else {
4151
+ this.lastNotificationFailureType = types_1.LogEventTypes.DISCORD;
4152
+ try {
4153
+ const discordData = message.discord_data;
4154
+ let content;
4155
+ let embeds = input.discord.embeds;
4156
+ if (discordData === null || discordData === void 0 ? void 0 : discordData.length) {
4157
+ const templateContent = (_12 = (typeof discordMessage === 'object' && discordMessage !== null && 'content' in discordMessage ? discordMessage.content : null)) !== null && _12 !== void 0 ? _12 : '';
4158
+ const contentInput = input.discord.content !== undefined ? input.discord.content : templateContent;
4159
+ const contentPayload = await this.generatePayload((typeof contentInput === 'object' && contentInput !== null ? contentInput : { content: contentInput }), notification, additional_logs, discordData.filter((d) => d.parent_key === 'content'));
4160
+ content = typeof contentPayload === 'object' && contentPayload !== null && 'content' in contentPayload ? String((_13 = contentPayload.content) !== null && _13 !== void 0 ? _13 : '') : String(contentPayload !== null && contentPayload !== void 0 ? contentPayload : '');
4161
+ if (((_14 = input.discord.embeds) === null || _14 === void 0 ? void 0 : _14.length) && discordData.some((d) => d.parent_key === 'embeds')) {
4162
+ const embedsPayload = await this.generatePayload({ embeds: input.discord.embeds }, notification, additional_logs, discordData.filter((d) => d.parent_key === 'embeds'));
4163
+ if (embedsPayload && typeof embedsPayload === 'object' && 'embeds' in embedsPayload)
4164
+ embeds = embedsPayload.embeds;
4165
+ }
4166
+ }
4167
+ else {
4168
+ const contentResolved = await (0, processor_utils_1.replacePlaceholderString)((_17 = (_15 = (typeof discordMessage === 'object' && discordMessage !== null && 'content' in discordMessage ? discordMessage.content : null)) !== null && _15 !== void 0 ? _15 : (_16 = input.discord) === null || _16 === void 0 ? void 0 : _16.content) !== null && _17 !== void 0 ? _17 : '', ((_18 = input.discord) !== null && _18 !== void 0 ? _18 : {}));
4169
+ content = typeof contentResolved === 'string' ? contentResolved : String((_20 = (_19 = input.discord) === null || _19 === void 0 ? void 0 : _19.content) !== null && _20 !== void 0 ? _20 : '');
4170
+ }
4171
+ const body = (embeds === null || embeds === void 0 ? void 0 : embeds.length) ? { embeds: embeds } : { content: content || '' };
4172
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.DISCORD, name: 'Send Discord - initiated', data: { hasContent: !!content, hasEmbeds: !!((_21 = input.discord.embeds) === null || _21 === void 0 ? void 0 : _21.length) }, status: types_1.LogEventStatus.SUCCESS }));
4173
+ await axios_1.default.post(webhookUrl, body, { headers: { 'Content-Type': 'application/json' }, timeout: 10000 });
4174
+ debugLog('[runNotification] DISCORD: success');
4175
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.DISCORD, name: 'Send Discord - success', successful_execution: true, data: {}, status: types_1.LogEventStatus.SUCCESS }));
4176
+ logMessageLog('discord', 'sent');
4177
+ }
4178
+ catch (e) {
4179
+ debugLog('[runNotification] DISCORD: failed', e);
4180
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { type: types_1.LogEventTypes.DISCORD, failed_execution: true, message: 'Send Discord - failed', data: { e }, status: types_1.LogEventStatus.FAIL }));
4181
+ logMessageLog('discord', 'failed', e);
4182
+ }
4183
+ }
4184
+ }
4185
+ debugLog('[runNotification] DONE: all channels processed', {
4186
+ lastChannelType: (_22 = this.lastNotificationFailureType) !== null && _22 !== void 0 ? _22 : 'NOTIFICATIONS',
4187
+ });
3825
4188
  // Only add aggregate success log when we have a subtype (no NOTIFICATIONS-typed logs)
3826
4189
  /*if (this.lastNotificationFailureType != null) {
3827
4190
  this.logService.add({
@@ -3835,7 +4198,10 @@ class ProcessorService {
3835
4198
  }*/
3836
4199
  }
3837
4200
  catch (e) {
3838
- debugLog('[runNotification] ERROR', { error: e, lastChannelType: (_3 = this.lastNotificationFailureType) !== null && _3 !== void 0 ? _3 : 'NOTIFICATIONS' });
4201
+ debugLog('[runNotification] ERROR', {
4202
+ error: e,
4203
+ lastChannelType: (_23 = this.lastNotificationFailureType) !== null && _23 !== void 0 ? _23 : 'NOTIFICATIONS',
4204
+ });
3839
4205
  // Only add aggregate failure log when we have a subtype (no NOTIFICATIONS-typed logs)
3840
4206
  if (this.lastNotificationFailureType != null) {
3841
4207
  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 }));
@@ -3845,98 +4211,99 @@ class ProcessorService {
3845
4211
  }
3846
4212
  }
3847
4213
  /*async runFunction(data: IFeatureEvent, additional_logs: Partial<ILogData>): Promise<any> {
3848
- const { product_id, env } = data;
3849
- const input = data.input as IFunctionRequest;
3850
-
3851
- this.productId = product_id;
3852
-
3853
- this.logService = new LogsService({
3854
- product_id,
3855
- workspace_id: this.workspace_id,
3856
- public_key: this.public_key,
3857
- user_id: this.user_id,
3858
- token: this.token,
3859
- env_type: this.environment,
4214
+ const { product_id, env } = data;
4215
+ const input = data.input as IFunctionRequest;
4216
+
4217
+ this.productId = product_id;
4218
+
4219
+ this.logService = new LogsService({
4220
+ product_id,
4221
+ workspace_id: this.workspace_id,
4222
+ public_key: this.public_key,
4223
+ user_id: this.user_id,
4224
+ token: this.token,
4225
+ env_type: this.environment,
4226
+ workspace_private_key: this._privateKey ?? undefined,
4227
+ });
4228
+
4229
+ const process_id = uuidv4();
4230
+ this.process_id = process_id;
4231
+
4232
+
4233
+ try {
4234
+ await this.intializeProduct(additional_logs);
4235
+ this.logService.add({
4236
+ ...this.baseLogs,
4237
+ ...additional_logs,
4238
+ message: 'Attempt function - initiated',
4239
+ data,
4240
+ status: LogEventStatus.PROCESSING,
3860
4241
  });
3861
-
3862
- const process_id = generateObjectId();
3863
- this.process_id = process_id;
3864
-
3865
-
3866
- try {
3867
- await this.intializeProduct(additional_logs);
3868
- this.logService.add({
3869
- ...this.baseLogs,
3870
- ...additional_logs,
3871
- message: 'Attempt function - initiated',
3872
- data,
3873
- status: LogEventStatus.PROCESSING,
3874
- });
3875
-
3876
- this.logService.add({
3877
- ...this.baseLogs,
3878
- ...additional_logs,
3879
- message: 'Fetch function - initiated',
3880
- data: data,
3881
- status: LogEventStatus.PROCESSING,
3882
- });
3883
-
3884
- const cloudFunction = await this.productBuilderService.fetchFunction(data.event);
3885
-
3886
- this.logService.add({
3887
- ...this.baseLogs,
3888
- ...additional_logs,
3889
- message: 'Fetch function - success',
3890
- data: data,
3891
- status: LogEventStatus.SUCCESS,
3892
- });
3893
-
3894
- this.logService.add({
3895
- ...this.baseLogs,
3896
- ...additional_logs,
3897
- message: 'Validate function payload - initiated',
3898
- data: { data, payload: input.payload },
3899
- status: LogEventStatus.PROCESSING,
3900
- });
3901
-
3902
- validateFunctionInputKeys(cloudFunction.inputs, input.payload);
3903
-
3904
- this.logService.add({
3905
- ...this.baseLogs,
3906
- ...additional_logs,
3907
- message: 'Validate function payload - success',
3908
- data: { data, payload: input.payload },
3909
- status: LogEventStatus.SUCCESS,
3910
- });
3911
-
3912
- this.logService.add({
3913
- ...this.baseLogs,
3914
- ...additional_logs,
3915
- message: 'Run function - initiated',
3916
- data: { data, payload: input.payload },
3917
- status: LogEventStatus.PROCESSING,
3918
- });
3919
-
3920
- const response = await makeFunctionsRequest(cloudFunction, input.payload);
3921
-
3922
- this.logService.add({
3923
- ...this.baseLogs,
3924
- ...additional_logs,
3925
- message: 'Run function - success',
3926
- data: { data, payload: input.payload },
3927
- status: LogEventStatus.SUCCESS,
3928
- });
3929
- } catch (e) {
3930
- this.logService.add({
3931
- ...this.baseLogs,
3932
- ...additional_logs,
3933
- message: 'Run function - failed',
3934
- data: e,
3935
- status: LogEventStatus.FAIL,
3936
- });
3937
- await this.logService.publish();
3938
- }
3939
- }*/
4242
+
4243
+ this.logService.add({
4244
+ ...this.baseLogs,
4245
+ ...additional_logs,
4246
+ message: 'Fetch function - initiated',
4247
+ data: data,
4248
+ status: LogEventStatus.PROCESSING,
4249
+ });
4250
+
4251
+ const cloudFunction = await this.productBuilderService.fetchFunction(data.event);
4252
+
4253
+ this.logService.add({
4254
+ ...this.baseLogs,
4255
+ ...additional_logs,
4256
+ message: 'Fetch function - success',
4257
+ data: data,
4258
+ status: LogEventStatus.SUCCESS,
4259
+ });
4260
+
4261
+ this.logService.add({
4262
+ ...this.baseLogs,
4263
+ ...additional_logs,
4264
+ message: 'Validate function payload - initiated',
4265
+ data: { data, payload: input.payload },
4266
+ status: LogEventStatus.PROCESSING,
4267
+ });
4268
+
4269
+ validateFunctionInputKeys(cloudFunction.inputs, input.payload);
4270
+
4271
+ this.logService.add({
4272
+ ...this.baseLogs,
4273
+ ...additional_logs,
4274
+ message: 'Validate function payload - success',
4275
+ data: { data, payload: input.payload },
4276
+ status: LogEventStatus.SUCCESS,
4277
+ });
4278
+
4279
+ this.logService.add({
4280
+ ...this.baseLogs,
4281
+ ...additional_logs,
4282
+ message: 'Run function - initiated',
4283
+ data: { data, payload: input.payload },
4284
+ status: LogEventStatus.PROCESSING,
4285
+ });
4286
+
4287
+ const response = await makeFunctionsRequest(cloudFunction, input.payload);
4288
+
4289
+ this.logService.add({
4290
+ ...this.baseLogs,
4291
+ ...additional_logs,
4292
+ message: 'Run function - success',
4293
+ data: { data, payload: input.payload },
4294
+ status: LogEventStatus.SUCCESS,
4295
+ });
4296
+ } catch (e) {
4297
+ this.logService.add({
4298
+ ...this.baseLogs,
4299
+ ...additional_logs,
4300
+ message: 'Run function - failed',
4301
+ data: e,
4302
+ status: LogEventStatus.FAIL,
4303
+ });
4304
+ await this.logService.publish();
4305
+ }
4306
+ }*/
3940
4307
  async runStorage(data, additional_logs = {}, bootstrapData) {
3941
4308
  const { product_id, env, event, cache: cache_tag } = data;
3942
4309
  const input = data.input;
@@ -4106,12 +4473,12 @@ class ProcessorService {
4106
4473
  url = queueUrl.url;
4107
4474
  }
4108
4475
  /* this.logService.add({
4109
- ...this.baseLogs,
4110
- ...additional_logs,
4111
- message: 'Fetch broker details - success',
4112
- data: { event, broker },
4113
- status: LogEventStatus.SUCCESS,
4114
- });*/
4476
+ ...this.baseLogs,
4477
+ ...additional_logs,
4478
+ message: 'Fetch broker details - success',
4479
+ data: { event, broker },
4480
+ status: LogEventStatus.SUCCESS,
4481
+ });*/
4115
4482
  let brokerConfig = brokerEnv.config;
4116
4483
  if (brokerConfig && (0, secrets_1.mightContainSecrets)(brokerConfig)) {
4117
4484
  const secretsService = (0, secrets_1.getSecretsService)();
@@ -4137,9 +4504,7 @@ class ProcessorService {
4137
4504
  catch (e) {
4138
4505
  const err = e;
4139
4506
  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;
4140
- const reason = typeof apiReason === 'string'
4141
- ? apiReason
4142
- : (_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);
4507
+ const reason = typeof apiReason === 'string' ? apiReason : (_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);
4143
4508
  const message = `Attempt publish to broker topic - failed: ${reason}`;
4144
4509
  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 }));
4145
4510
  throw e;
@@ -4223,6 +4588,8 @@ class ProcessorService {
4223
4588
  }
4224
4589
  }
4225
4590
  async writeResult(status, retryable = true) {
4591
+ var _a, _b, _c, _d, _e, _f;
4592
+ const envSlug = (_f = (_d = (_b = (_a = this.processEnv) === null || _a === void 0 ? void 0 : _a.slug) !== null && _b !== void 0 ? _b : (_c = this.input) === null || _c === void 0 ? void 0 : _c.env) !== null && _d !== void 0 ? _d : (_e = this.baseLogs) === null || _e === void 0 ? void 0 : _e.env) !== null && _f !== void 0 ? _f : '';
4226
4593
  this.processorApiService.saveResult({
4227
4594
  status,
4228
4595
  component: this.component,
@@ -4233,7 +4600,7 @@ class ProcessorService {
4233
4600
  process_id: this.process_id,
4234
4601
  feature_id: null,
4235
4602
  product_id: this.productId,
4236
- env: this.processEnv.slug,
4603
+ env: envSlug,
4237
4604
  input: (0, processor_utils_1.encrypt)(JSON.stringify(this.input), this.productBuilderService.fetchPrivateKey()),
4238
4605
  }, this.getUserAccess());
4239
4606
  }
@@ -4246,8 +4613,10 @@ class ProcessorService {
4246
4613
  const prefixed = {};
4247
4614
  const nonPrefixed = {};
4248
4615
  for (const [key, value] of Object.entries(credentials)) {
4249
- if (key.startsWith('headers:') || key.startsWith('body:') ||
4250
- key.startsWith('params:') || key.startsWith('query:')) {
4616
+ if (key.startsWith('headers:') ||
4617
+ key.startsWith('body:') ||
4618
+ key.startsWith('params:') ||
4619
+ key.startsWith('query:')) {
4251
4620
  prefixed[key] = value;
4252
4621
  }
4253
4622
  else {
@@ -4267,7 +4636,7 @@ class ProcessorService {
4267
4636
  if (!sectionSchema || !sectionSchema.data)
4268
4637
  return false;
4269
4638
  // Check if the key exists in the schema's data array
4270
- return sectionSchema.data.some(item => item.key === key);
4639
+ return sectionSchema.data.some((item) => item.key === key);
4271
4640
  }
4272
4641
  /**
4273
4642
  * Apply prefixed credentials (e.g., 'headers:Authorization') to resolved input.
@@ -4334,7 +4703,7 @@ class ProcessorService {
4334
4703
  async validateActionDataMappingInput(input, type) {
4335
4704
  try {
4336
4705
  if (type === types_1.FeatureEventTypes.ACTION || type === types_1.WebhookEventTypes.WEBHOOK_REGISTER) {
4337
- await create_productFeature_validator_1.ActionInputSchema.validateAsync(input);
4706
+ //await ActionInputSchema.validateAsync(input);
4338
4707
  }
4339
4708
  if (type === types_1.FeatureEventTypes.DB_ACTION) {
4340
4709
  await create_productFeature_validator_1.DBActionInputSchema.validateAsync(input);
@@ -4349,8 +4718,15 @@ class ProcessorService {
4349
4718
  }
4350
4719
  }
4351
4720
  async processAction(action) {
4352
- //TODO: schema validation
4353
- const { env, input, retries, action: event, app, product: product_tag, session, cache, preloadedBootstrap } = action;
4721
+ var _a, _b, _c;
4722
+ await create_productFeature_validator_1.ActionProcessorInputSchema.validateAsync(action, { abortEarly: true }).catch((err) => {
4723
+ var _a, _b, _c, _d;
4724
+ throw new Error((_d = (_c = (_b = (_a = err.details) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.message) !== null && _c !== void 0 ? _c : err.message) !== null && _d !== void 0 ? _d : 'Invalid action input');
4725
+ });
4726
+ const { env, input, retries, action: event, app, product: product_tag, session, cache, preloadedBootstrap, } = action;
4727
+ // Backend bootstrap looks up action by short tag (e.g. list_countries). Normalize so both
4728
+ // "action:ductape:paystack:list_countries" (legacy/retry payloads) and "list_countries" work.
4729
+ const actionTagForBootstrap = typeof event === 'string' && event.includes(':') ? event.split(':').pop() : event;
4354
4730
  const additional_logs = {
4355
4731
  parent_tag: (0, string_utils_1.extractOriginAndTag)(app),
4356
4732
  child_tag: event,
@@ -4364,12 +4740,14 @@ class ProcessorService {
4364
4740
  try {
4365
4741
  this.input = action;
4366
4742
  this.start = Date.now();
4367
- const process_id = (0, processor_utils_1.generateObjectId)();
4743
+ const process_id = (0, uuid_1.v4)();
4368
4744
  if (product_tag) {
4369
4745
  this.productTag = product_tag;
4370
4746
  }
4371
4747
  this.baseLogs = {
4372
4748
  product_tag: this.productTag || '',
4749
+ parent_tag: app,
4750
+ child_tag: event,
4373
4751
  workspace_id: this.workspace_id,
4374
4752
  env,
4375
4753
  type: types_1.LogEventTypes.ACTION,
@@ -4386,21 +4764,59 @@ class ProcessorService {
4386
4764
  user_id: this.user_id,
4387
4765
  token: this.token,
4388
4766
  env_type: this.environment,
4767
+ workspace_private_key: (_a = this._privateKey) !== null && _a !== void 0 ? _a : undefined,
4389
4768
  });
4390
4769
  }
4391
- // Use preloaded bootstrap when provided (e.g. workflow batch prefetch), otherwise fetch
4392
- const bootstrapData = preloadedBootstrap
4393
- ? preloadedBootstrap
4394
- : await this.productBuilderService.bootstrapAction({
4395
- product_tag,
4396
- env_slug: env,
4397
- access_tag: app,
4398
- action_tag: event,
4399
- });
4770
+ // Use preloaded bootstrap when provided (e.g. workflow batch prefetch), otherwise fetch or read from cache
4771
+ let bootstrapData;
4772
+ if (preloadedBootstrap) {
4773
+ bootstrapData = preloadedBootstrap;
4774
+ }
4775
+ else {
4776
+ const bootstrapCacheKey = this.getActionBootstrapCacheKey(product_tag !== null && product_tag !== void 0 ? product_tag : '', app, env, actionTagForBootstrap);
4777
+ const cached = await this.getCachedActionBootstrap(bootstrapCacheKey);
4778
+ if (cached) {
4779
+ bootstrapData = cached;
4780
+ this.productBuilderService.applyBootstrapActionResult(bootstrapData, product_tag !== null && product_tag !== void 0 ? product_tag : undefined);
4781
+ }
4782
+ else {
4783
+ bootstrapData = (await this.productBuilderService.bootstrapAction({
4784
+ product_tag,
4785
+ env_slug: env,
4786
+ access_tag: app,
4787
+ action_tag: actionTagForBootstrap,
4788
+ }));
4789
+ this.setCachedActionBootstrap(bootstrapCacheKey, bootstrapData);
4790
+ }
4791
+ }
4400
4792
  // Initialize from bootstrap data
4401
4793
  if (bootstrapData.product_id) {
4402
4794
  this.productId = bootstrapData.product_id;
4403
4795
  }
4796
+ // console.log("BOOTSTRAP DATA", bootstrapData);
4797
+ if (!bootstrapData) {
4798
+ throw new Error('App not fetched');
4799
+ }
4800
+ // Only set app_id when valid (24-char hex); empty string would fail logs service ObjectId cast
4801
+ const appId = bootstrapData.app_id;
4802
+ if (appId && typeof appId === 'string') {
4803
+ this.baseLogs.app_id = appId;
4804
+ }
4805
+ this.baseLogs.app_tag = app;
4806
+ this.processEnv = {
4807
+ slug: (_b = bootstrapData.product_env_mapping) === null || _b === void 0 ? void 0 : _b.product_env_slug,
4808
+ app_slug: (_c = bootstrapData.product_env_mapping) === null || _c === void 0 ? void 0 : _c.app_env_slug,
4809
+ };
4810
+ // Ensure product is loaded so fetchPrivateKey() works (writeResult, cache, etc.)
4811
+ // Bootstrap may not set product when backend returns no private_key (e.g. access-key path); fallback to full init
4812
+ if (product_tag) {
4813
+ try {
4814
+ this.productBuilderService.fetchPrivateKey();
4815
+ }
4816
+ catch (_d) {
4817
+ await this.productBuilderService.initializeProductByTag(product_tag);
4818
+ }
4819
+ }
4404
4820
  // Early cache check - after bootstrap so productBuilderService.product (and fetchPrivateKey) are set
4405
4821
  if (cache && this.redisClient) {
4406
4822
  const productCache = await this.productBuilderService.fetchCache(cache);
@@ -4414,7 +4830,7 @@ class ProcessorService {
4414
4830
  }, additional_logs);
4415
4831
  if (cachedResult) {
4416
4832
  const result = JSON.parse(cachedResult);
4417
- 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 }));
4833
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Action response from cache (early check)', data: { result }, status: types_1.LogEventStatus.SUCCESS, cache_tag: cache, action: event }));
4418
4834
  this.end = Date.now();
4419
4835
  await this.logService.publish();
4420
4836
  return result;
@@ -4524,7 +4940,7 @@ class ProcessorService {
4524
4940
  product_env_mapping: bootstrapData.product_env_mapping,
4525
4941
  });
4526
4942
  this.end = Date.now();
4527
- this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Execute action - success', data: { input: (0, processor_utils_1.anonymizeObject)(input), result: (0, processor_utils_1.anonymizeObject)(result) }, status: types_1.LogEventStatus.SUCCESS }));
4943
+ this.logService.add(Object.assign(Object.assign(Object.assign({}, this.baseLogs), additional_logs), { message: 'Execute action - success', data: { input, result }, status: types_1.LogEventStatus.SUCCESS }));
4528
4944
  await this.writeResult(types_1.LogEventStatus.SUCCESS);
4529
4945
  await this.logService.publish();
4530
4946
  return result;
@@ -4541,9 +4957,16 @@ class ProcessorService {
4541
4957
  }
4542
4958
  async processNotification(action) {
4543
4959
  //TODO: schema validation
4544
- var _a, _b, _c, _d, _e;
4960
+ var _a, _b, _c, _d, _e, _f;
4545
4961
  const { env, input, retries, event, product: product_tag, session, cache, preloadedBootstrap } = action;
4546
- debugLog('[processNotification] ENTRY', { product: product_tag, env, event, inputKeys: input ? Object.keys(input) : [], hasSession: !!session, hasCache: !!cache });
4962
+ debugLog('[processNotification] ENTRY', {
4963
+ product: product_tag,
4964
+ env,
4965
+ event,
4966
+ inputKeys: input ? Object.keys(input) : [],
4967
+ hasSession: !!session,
4968
+ hasCache: !!cache,
4969
+ });
4547
4970
  const [parent_tag, child_tag] = event.split(':');
4548
4971
  if (!parent_tag || !child_tag) {
4549
4972
  debugLog('[processNotification] ERROR: invalid event format', { event });
@@ -4569,7 +4992,7 @@ class ProcessorService {
4569
4992
  await this.validateActionDataMappingInput(input, types_1.FeatureEventTypes.NOTIFICATION);
4570
4993
  this.input = action;
4571
4994
  this.start = Date.now();
4572
- const process_id = (0, processor_utils_1.generateObjectId)();
4995
+ const process_id = (0, uuid_1.v4)();
4573
4996
  debugLog('[processNotification] process_id', process_id);
4574
4997
  this.baseLogs = Object.assign({ product_tag: this.productTag, workspace_id: this.workspace_id, env,
4575
4998
  process_id, data: input }, additional_logs);
@@ -4583,7 +5006,12 @@ class ProcessorService {
4583
5006
  notification_tag: parent_tag,
4584
5007
  message_tag: child_tag,
4585
5008
  });
4586
- 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 });
5009
+ debugLog('[processNotification] Bootstrap result', {
5010
+ product_id: bootstrapData === null || bootstrapData === void 0 ? void 0 : bootstrapData.product_id,
5011
+ hasNotification: !!(bootstrapData === null || bootstrapData === void 0 ? void 0 : bootstrapData.notification),
5012
+ hasMessage: !!(bootstrapData === null || bootstrapData === void 0 ? void 0 : bootstrapData.message),
5013
+ envActive: (_a = bootstrapData === null || bootstrapData === void 0 ? void 0 : bootstrapData.env) === null || _a === void 0 ? void 0 : _a.active,
5014
+ });
4587
5015
  // Initialize from bootstrap data
4588
5016
  this.productId = bootstrapData.product_id;
4589
5017
  this.processEnv = bootstrapData.env;
@@ -4596,6 +5024,7 @@ class ProcessorService {
4596
5024
  user_id: this.user_id,
4597
5025
  token: this.token,
4598
5026
  env_type: this.environment,
5027
+ workspace_private_key: (_b = this._privateKey) !== null && _b !== void 0 ? _b : undefined,
4599
5028
  });
4600
5029
  }
4601
5030
  this.process_id = process_id;
@@ -4631,8 +5060,11 @@ class ProcessorService {
4631
5060
  allow_fail: false,
4632
5061
  };
4633
5062
  // Find the env config for the notification
4634
- const envConfig = (_b = bootstrapData.notification.envs) === null || _b === void 0 ? void 0 : _b.find((data) => data.slug === env);
4635
- debugLog('[processNotification] Calling runNotification', { event, resolvedInputKeys: resolvedInput ? Object.keys(resolvedInput) : [] });
5063
+ const envConfig = (_c = bootstrapData.notification.envs) === null || _c === void 0 ? void 0 : _c.find((data) => data.slug === env);
5064
+ debugLog('[processNotification] Calling runNotification', {
5065
+ event,
5066
+ resolvedInputKeys: resolvedInput ? Object.keys(resolvedInput) : [],
5067
+ });
4636
5068
  const result = await this.runNotification(payload, additional_logs, {
4637
5069
  notification: bootstrapData.notification,
4638
5070
  message: bootstrapData.message,
@@ -4644,7 +5076,11 @@ class ProcessorService {
4644
5076
  cache,
4645
5077
  });
4646
5078
  this.end = Date.now();
4647
- debugLog('[processNotification] SUCCESS', { process_id, lastChannelType: (_c = this.lastNotificationFailureType) !== null && _c !== void 0 ? _c : 'NOTIFICATIONS', durationMs: this.end - this.start });
5079
+ debugLog('[processNotification] SUCCESS', {
5080
+ process_id,
5081
+ lastChannelType: (_d = this.lastNotificationFailureType) !== null && _d !== void 0 ? _d : 'NOTIFICATIONS',
5082
+ durationMs: this.end - this.start,
5083
+ });
4648
5084
  // Only add success log when we have a subtype (no NOTIFICATIONS-typed logs)
4649
5085
  /* if (this.lastNotificationFailureType != null) {
4650
5086
  this.logService.add({
@@ -4664,8 +5100,11 @@ class ProcessorService {
4664
5100
  }
4665
5101
  catch (e) {
4666
5102
  if (this.logService) {
4667
- debugLog('[processNotification] FAILED', { error: e, lastChannelType: (_d = this.lastNotificationFailureType) !== null && _d !== void 0 ? _d : 'NOTIFICATIONS' });
4668
- console.error(e);
5103
+ debugLog('[processNotification] FAILED', {
5104
+ error: e,
5105
+ lastChannelType: (_e = this.lastNotificationFailureType) !== null && _e !== void 0 ? _e : 'NOTIFICATIONS',
5106
+ });
5107
+ // console.error(e);
4669
5108
  // Only add failure log when we have a subtype (no NOTIFICATIONS-typed logs)
4670
5109
  if (this.lastNotificationFailureType != null) {
4671
5110
  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 }));
@@ -4675,14 +5114,26 @@ class ProcessorService {
4675
5114
  }
4676
5115
  // Fire-and-forget: log failed notification for reprocessing (only when we have productId from bootstrap). Use actual channel type when known.
4677
5116
  if (this.productId && this.workspace_id) {
4678
- 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';
5117
+ const channelType = this.lastNotificationFailureType === types_1.LogEventTypes.PUSH
5118
+ ? 'push'
5119
+ : this.lastNotificationFailureType === types_1.LogEventTypes.EMAIL
5120
+ ? 'email'
5121
+ : this.lastNotificationFailureType === types_1.LogEventTypes.SMS
5122
+ ? 'sms'
5123
+ : this.lastNotificationFailureType === types_1.LogEventTypes.CALLBACKS
5124
+ ? 'callback'
5125
+ : this.lastNotificationFailureType === types_1.LogEventTypes.SLACK
5126
+ ? 'slack'
5127
+ : this.lastNotificationFailureType === types_1.LogEventTypes.DISCORD
5128
+ ? 'discord'
5129
+ : 'notification';
4679
5130
  this.fireAndForgetLogNotificationMessage({
4680
5131
  workspace_id: this.workspace_id,
4681
5132
  product_id: this.productId,
4682
5133
  product_tag,
4683
5134
  env,
4684
5135
  notification_tag: event,
4685
- input: ((_e = resolvedInput !== null && resolvedInput !== void 0 ? resolvedInput : input) !== null && _e !== void 0 ? _e : {}),
5136
+ input: ((_f = resolvedInput !== null && resolvedInput !== void 0 ? resolvedInput : input) !== null && _f !== void 0 ? _f : {}),
4686
5137
  type: channelType,
4687
5138
  status: 'failed',
4688
5139
  process_id: this.process_id,
@@ -4729,7 +5180,10 @@ class ProcessorService {
4729
5180
  void this.processorApiService
4730
5181
  .logNotificationMessage(Object.assign(Object.assign({}, payload), { input: inputToSend }), Object.assign(Object.assign({}, this.getUserAccess()), { access_key: this.accessKey }))
4731
5182
  .then(() => debugLog('[fireAndForgetLogNotificationMessage] POST success', { process_id: payload.process_id }))
4732
- .catch((err) => console.error('[fireAndForgetLogNotificationMessage] POST failed', { process_id: payload.process_id, error: err }));
5183
+ .catch((err) => console.error('[fireAndForgetLogNotificationMessage] POST failed', {
5184
+ process_id: payload.process_id,
5185
+ error: err,
5186
+ }));
4733
5187
  }
4734
5188
  /**
4735
5189
  * Fetch notification message logs (send history) with time filters. Secured via user auth.
@@ -4811,7 +5265,8 @@ class ProcessorService {
4811
5265
  expiresAt = new Date(timestamp + expiry);
4812
5266
  }
4813
5267
  // Use CacheService to store the value (fire-and-forget)
4814
- this.cacheService.set({
5268
+ this.cacheService
5269
+ .set({
4815
5270
  product: product_tag,
4816
5271
  cache: cache_tag,
4817
5272
  key,
@@ -4819,9 +5274,11 @@ class ProcessorService {
4819
5274
  componentTag: component_tag,
4820
5275
  componentType: component_type,
4821
5276
  expiry: expiresAt,
4822
- }).then(() => {
5277
+ })
5278
+ .then(() => {
4823
5279
  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 }));
4824
- }).catch((error) => {
5280
+ })
5281
+ .catch((error) => {
4825
5282
  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 }));
4826
5283
  });
4827
5284
  }
@@ -4882,5 +5339,6 @@ class ProcessorService {
4882
5339
  return this.productBuilderService.updateHealthcheck(productTag, { envs });
4883
5340
  }
4884
5341
  }
5342
+ ProcessorService.HEALTHCHECK_REFRESH_MS = 60000;
4885
5343
  exports.default = ProcessorService;
4886
5344
  //# sourceMappingURL=processor.service.js.map