@ductape/sdk 0.1.110 → 0.1.113

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 (41) hide show
  1. package/dist/features/feature-executor.d.ts +9 -0
  2. package/dist/features/feature-executor.js +224 -70
  3. package/dist/features/feature-executor.js.map +1 -1
  4. package/dist/features/features.service.d.ts +5 -0
  5. package/dist/features/features.service.js +49 -7
  6. package/dist/features/features.service.js.map +1 -1
  7. package/dist/features/index.d.ts +2 -1
  8. package/dist/features/index.js +3 -1
  9. package/dist/features/index.js.map +1 -1
  10. package/dist/features/types/features.types.d.ts +9 -0
  11. package/dist/features/types/features.types.js.map +1 -1
  12. package/dist/functions/functions.runtime.d.ts +25 -0
  13. package/dist/functions/functions.runtime.js +254 -0
  14. package/dist/functions/functions.runtime.js.map +1 -0
  15. package/dist/functions/http-handler.d.ts +17 -0
  16. package/dist/functions/http-handler.js +51 -0
  17. package/dist/functions/http-handler.js.map +1 -0
  18. package/dist/functions/index.d.ts +3 -0
  19. package/dist/functions/index.js +20 -0
  20. package/dist/functions/index.js.map +1 -0
  21. package/dist/functions/types.d.ts +94 -0
  22. package/dist/functions/types.js +15 -0
  23. package/dist/functions/types.js.map +1 -0
  24. package/dist/graph/graphs.service.d.ts +1 -1
  25. package/dist/graph/graphs.service.js +73 -43
  26. package/dist/graph/graphs.service.js.map +1 -1
  27. package/dist/graph/types/traversal.interface.d.ts +2 -0
  28. package/dist/index.d.ts +16 -1
  29. package/dist/index.js +23 -3
  30. package/dist/index.js.map +1 -1
  31. package/dist/processor/services/processor.service.d.ts +6 -0
  32. package/dist/processor/services/processor.service.js +8 -13
  33. package/dist/processor/services/processor.service.js.map +1 -1
  34. package/dist/tsconfig.tsbuildinfo +1 -1
  35. package/dist/types/productsBuilder.types.d.ts +3 -0
  36. package/dist/types/productsBuilder.types.js +2 -0
  37. package/dist/types/productsBuilder.types.js.map +1 -1
  38. package/dist/vector/vector-database.service.d.ts +2 -0
  39. package/dist/vector/vector-database.service.js +21 -12
  40. package/dist/vector/vector-database.service.js.map +1 -1
  41. package/package.json +1 -1
@@ -32,6 +32,7 @@ const inputs_types_1 = require("../types/inputs.types");
32
32
  const processor_utils_1 = require("../processor/utils/processor.utils");
33
33
  const productsBuilder_types_1 = require("../types/productsBuilder.types");
34
34
  const date_fns_1 = require("date-fns");
35
+ const functions_1 = require("../functions");
35
36
  /** Only log when DUCTAPE_DEBUG is set to avoid sync I/O and serialization cost in hot path */
36
37
  const debugLog = 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')
37
38
  ? (...args) => console.log(...args)
@@ -47,6 +48,39 @@ const stepLog = typeof process !== 'undefined'
47
48
  }
48
49
  }
49
50
  : () => { };
51
+ const SENSITIVE_LOG_KEY = /(?:authorization|cookie|password|passwd|secret|token|api[_-]?key|access[_-]?key|private[_-]?key|client[_-]?secret|session)/i;
52
+ const MAX_LOG_STRING_LENGTH = 2000;
53
+ /** Produce useful payload traces without leaking credentials or exploding logs. */
54
+ const sanitizeForLog = (value, key = '', seen = new WeakSet()) => {
55
+ if (key !== 'has_session' && SENSITIVE_LOG_KEY.test(key))
56
+ return '[REDACTED]';
57
+ if (value == null || typeof value === 'number' || typeof value === 'boolean')
58
+ return value;
59
+ if (typeof value === 'bigint')
60
+ return value.toString();
61
+ if (typeof value === 'string') {
62
+ return value.length > MAX_LOG_STRING_LENGTH
63
+ ? `${value.slice(0, MAX_LOG_STRING_LENGTH)}...[truncated ${value.length - MAX_LOG_STRING_LENGTH} chars]`
64
+ : value;
65
+ }
66
+ if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
67
+ return `[Buffer ${value.length} bytes]`;
68
+ }
69
+ if (value instanceof Error)
70
+ return { name: value.name, message: value.message, stack: value.stack };
71
+ if (Array.isArray(value))
72
+ return value.map((item) => sanitizeForLog(item, key, seen));
73
+ if (typeof value === 'object') {
74
+ if (seen.has(value))
75
+ return '[Circular]';
76
+ seen.add(value);
77
+ return Object.fromEntries(Object.entries(value).map(([nestedKey, nestedValue]) => [
78
+ nestedKey,
79
+ sanitizeForLog(nestedValue, nestedKey, seen),
80
+ ]));
81
+ }
82
+ return String(value);
83
+ };
50
84
  /** Observability must not disappear because a successful result contains BigInt or cycles. */
51
85
  const stringifyProcessorValue = (value) => {
52
86
  const seen = new WeakSet();
@@ -115,6 +149,7 @@ class FeatureExecutor {
115
149
  this.graphConnectionUsed = false;
116
150
  /** Pre-fetched bootstrap data per step tag (feature batch prefetch). */
117
151
  this.stepBootstrapCache = new Map();
152
+ this.functionInvocations = new Map();
118
153
  debugLog('[FeatureExecutor] constructor ENTRY', {
119
154
  feature_tag: feature.tag,
120
155
  product: options.product,
@@ -123,6 +158,7 @@ class FeatureExecutor {
123
158
  });
124
159
  this.config = config;
125
160
  this.feature = feature;
161
+ this.inheritedSession = options.session;
126
162
  this.sessionLogFields = sessionLogFields || {};
127
163
  this._privateKey = private_key || '';
128
164
  this.preInitializedProduct = Boolean(preInitializedBuilder);
@@ -158,8 +194,26 @@ class FeatureExecutor {
158
194
  feature_id: this.state.feature_id,
159
195
  feature_tag: this.state.feature_tag,
160
196
  steps_count: (_b = (_a = feature.steps) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0,
197
+ has_session: Boolean(this.inheritedSession),
198
+ input: sanitizeForLog(options.input),
161
199
  });
162
200
  }
201
+ /** Debug-only structured execution trace. Payloads are recursively redacted. */
202
+ trace(stage, payload = {}) {
203
+ debugLog('[FeatureExecutor][trace]', sanitizeForLog(Object.assign({ stage, feature_id: this.state.feature_id, feature_tag: this.state.feature_tag, product: this.state.product, env: this.state.env, has_session: Boolean(this.inheritedSession) }, payload)));
204
+ }
205
+ /** Brokers expose the same session as separate tag/token fields. */
206
+ inheritedBrokerSession() {
207
+ if (!this.inheritedSession)
208
+ return undefined;
209
+ const separator = this.inheritedSession.indexOf(':');
210
+ if (separator < 1)
211
+ return undefined;
212
+ return {
213
+ tag: this.inheritedSession.slice(0, separator),
214
+ token: this.inheritedSession.slice(separator + 1),
215
+ };
216
+ }
163
217
  /**
164
218
  * Get auth payload for API calls
165
219
  */
@@ -190,6 +244,10 @@ class FeatureExecutor {
190
244
  access_key: this.config.access_key,
191
245
  preInitializedProductBuilder: this.productBuilder,
192
246
  });
247
+ this._processorService.setFeatureExecutionContext({
248
+ feature_id: this.state.feature_id,
249
+ feature_tag: this.state.feature_tag,
250
+ });
193
251
  }
194
252
  return this._processorService;
195
253
  }
@@ -338,7 +396,9 @@ class FeatureExecutor {
338
396
  product_tag: this.state.product,
339
397
  workspace_id: this.config.workspace_id,
340
398
  };
399
+ this.trace('execution.persistence.sent', { status, payload: resultData });
341
400
  await this.processorApiService.saveResult(processorResult, this.getAuthPayload());
401
+ this.trace('execution.persistence.acknowledged', { status, process_id: this.state.feature_id });
342
402
  debugLog('[FeatureExecutor] persistExecutionResult SUCCESS', { feature_id: this.state.feature_id, status });
343
403
  }
344
404
  catch (err) {
@@ -374,6 +434,7 @@ class FeatureExecutor {
374
434
  * Processor results for steps always have component: 'feature_step' and step_type set to the step kind.
375
435
  */
376
436
  async persistStepResult(step, status, output, error, duration, input) {
437
+ var _a;
377
438
  const resolvedInput = input !== null && input !== void 0 ? input : step.input;
378
439
  const stepType = this.getStepTypeForResult(step);
379
440
  debugLog('[FeatureExecutor] persistStepResult ENTRY', {
@@ -394,27 +455,17 @@ class FeatureExecutor {
394
455
  const resultStr = stringifyProcessorValue(value);
395
456
  const inputStr = stringifyProcessorValue(resolvedInput);
396
457
  const encKey = this.getProcessorResultEncryptionKey();
397
- const stepResult = {
398
- process_id: stepProcessId,
399
- product_id: this.productId || null,
400
- env: this.state.env,
401
- component: types_1.LogEventTypes.FEATURE_STEP, // step results always feature_step
402
- status,
403
- start: Date.now() - (duration || 0),
404
- end: Date.now(),
405
- retryable: true,
406
- result: encKey ? (0, processor_utils_1.encrypt)(resultStr, encKey) : resultStr,
407
- input: encKey ? (0, processor_utils_1.encrypt)(inputStr, encKey) : inputStr,
408
- feature_id: this.state.feature_id,
409
- feature_tag: this.state.feature_tag,
410
- product_tag: this.state.product,
411
- workspace_id: this.config.workspace_id,
458
+ const stepResult = Object.assign({ process_id: stepProcessId, product_id: this.productId || null, env: this.state.env, component: types_1.LogEventTypes.FEATURE_STEP, // step results always feature_step
459
+ status, start: Date.now() - (duration || 0), end: Date.now(), retryable: true, result: encKey ? (0, processor_utils_1.encrypt)(resultStr, encKey) : resultStr, input: encKey ? (0, processor_utils_1.encrypt)(inputStr, encKey) : inputStr, feature_id: this.state.feature_id, feature_tag: this.state.feature_tag, product_tag: this.state.product, workspace_id: this.config.workspace_id, step_tag: step.tag, step_type: stepType, step_error: error, step_duration_ms: duration }, ((_a = this.functionInvocations.get(step.tag)) !== null && _a !== void 0 ? _a : {}));
460
+ this.trace('step.persistence.sent', {
412
461
  step_tag: step.tag,
413
- step_type: stepType, // action | notification | storage | produce | database_action | graph | vector | quota | fallback | child_feature | sleep | wait_for_signal | checkpoint
414
- step_error: error,
415
- step_duration_ms: duration,
416
- };
462
+ step_type: stepType,
463
+ status,
464
+ input: resolvedInput,
465
+ output: value,
466
+ });
417
467
  await this.processorApiService.saveResult(stepResult, this.getAuthPayload());
468
+ this.trace('step.persistence.acknowledged', { step_tag: step.tag, status, process_id: stepProcessId });
418
469
  debugLog('[FeatureExecutor] persistStepResult SUCCESS', { feature_id: this.state.feature_id, step_tag: step.tag });
419
470
  }
420
471
  catch (err) {
@@ -467,7 +518,7 @@ class FeatureExecutor {
467
518
  * Execute the feature
468
519
  */
469
520
  async execute() {
470
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
521
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
471
522
  const startTime = Date.now();
472
523
  debugLog('[FeatureExecutor] execute ENTRY', {
473
524
  feature_id: this.state.feature_id,
@@ -475,6 +526,10 @@ class FeatureExecutor {
475
526
  product: this.state.product,
476
527
  env: this.state.env,
477
528
  });
529
+ this.trace('execution.started', {
530
+ input: this.state.input,
531
+ configured_steps: (_a = this.feature.steps) === null || _a === void 0 ? void 0 : _a.map((step) => ({ tag: step.tag, type: step.type, input: step.input })),
532
+ });
478
533
  try {
479
534
  // Track phase so failures before first step are reported as (initialization)
480
535
  this.state.current_step = '(initialization)';
@@ -487,6 +542,7 @@ class FeatureExecutor {
487
542
  this.productId = this.productBuilder.fetchProductId();
488
543
  }
489
544
  debugLog('[FeatureExecutor] execute product initialized', { feature_id: this.state.feature_id, product_id: this.productId });
545
+ this.trace('product.fetched', { product_id: this.productId, preinitialized: this.preInitializedProduct });
490
546
  // Initialize logging after we have product ID
491
547
  this.initializeLogging();
492
548
  this.state.status = types_1.FeatureStatus.RUNNING;
@@ -507,14 +563,17 @@ class FeatureExecutor {
507
563
  }
508
564
  catch (prefetchErr) {
509
565
  stepLog('Bootstrap prefetch failed (continuing without prefetch)', {
510
- error: (_a = prefetchErr === null || prefetchErr === void 0 ? void 0 : prefetchErr.message) !== null && _a !== void 0 ? _a : String(prefetchErr),
566
+ error: (_b = prefetchErr === null || prefetchErr === void 0 ? void 0 : prefetchErr.message) !== null && _b !== void 0 ? _b : String(prefetchErr),
511
567
  });
512
568
  this.stepBootstrapCache.clear();
513
569
  }
514
570
  // Execute each step
515
571
  for (const step of orderedSteps) {
516
572
  // Check step condition if present
517
- if (step.condition && !(await this.evaluateCondition(step.condition))) {
573
+ const conditionMet = step.condition ? await this.evaluateCondition(step.condition) : true;
574
+ if (step.condition)
575
+ this.trace('step.condition.evaluated', { step_tag: step.tag, condition: step.condition, result: conditionMet });
576
+ if (!conditionMet) {
518
577
  debugLog('[FeatureExecutor] execute step SKIPPED (condition)', { feature_id: this.state.feature_id, step_tag: step.tag });
519
578
  this.logStepEvent(step, `Step ${step.tag} - skipped (condition not met)`, logs_types_1.LogEventStatus.SUCCESS, { skipped: true });
520
579
  continue; // Skip step if condition not met
@@ -535,8 +594,8 @@ class FeatureExecutor {
535
594
  success: result.success,
536
595
  durationMs: result.duration,
537
596
  hasError: !!result.error,
538
- input: result.input,
539
- output: result.output,
597
+ input: sanitizeForLog(result.input),
598
+ output: sanitizeForLog(result.output),
540
599
  });
541
600
  // Log step completion
542
601
  this.logStepEvent(step, result.success ? `Step ${step.tag} - completed` : `Step ${step.tag} - failed`, result.success ? logs_types_1.LogEventStatus.SUCCESS : logs_types_1.LogEventStatus.FAIL, { duration: result.duration, error: result.error });
@@ -548,7 +607,7 @@ class FeatureExecutor {
548
607
  try {
549
608
  stepReturnValue = await this.resolveInput(outputSchema, result.output);
550
609
  }
551
- catch (_p) {
610
+ catch (_q) {
552
611
  stepReturnValue = result.output;
553
612
  }
554
613
  }
@@ -565,22 +624,22 @@ class FeatureExecutor {
565
624
  });
566
625
  if (!result.success) {
567
626
  this.state.failed_step = step.tag;
568
- stepLog('Step failed', { tag: step.tag, error: result.error, allow_fail: (_b = step.options) === null || _b === void 0 ? void 0 : _b.allow_fail, optional: (_c = step.options) === null || _c === void 0 ? void 0 : _c.optional });
627
+ stepLog('Step failed', { tag: step.tag, error: result.error, allow_fail: (_c = step.options) === null || _c === void 0 ? void 0 : _c.allow_fail, optional: (_d = step.options) === null || _d === void 0 ? void 0 : _d.optional });
569
628
  debugLog('[FeatureExecutor] execute step FAILED', {
570
629
  feature_id: this.state.feature_id,
571
630
  step_tag: step.tag,
572
631
  error: result.error,
573
- allow_fail: (_d = step.options) === null || _d === void 0 ? void 0 : _d.allow_fail,
574
- optional: (_e = step.options) === null || _e === void 0 ? void 0 : _e.optional,
632
+ allow_fail: (_e = step.options) === null || _e === void 0 ? void 0 : _e.allow_fail,
633
+ optional: (_f = step.options) === null || _f === void 0 ? void 0 : _f.optional,
575
634
  });
576
635
  // Check if step allows failure
577
- if ((_f = step.options) === null || _f === void 0 ? void 0 : _f.allow_fail) {
636
+ if ((_g = step.options) === null || _g === void 0 ? void 0 : _g.allow_fail) {
578
637
  // Store error but continue
579
638
  this.state.steps[step.tag] = { error: result.error };
580
639
  continue;
581
640
  }
582
641
  // Check if step is optional
583
- if ((_g = step.options) === null || _g === void 0 ? void 0 : _g.optional) {
642
+ if ((_h = step.options) === null || _h === void 0 ? void 0 : _h.optional) {
584
643
  // Don't trigger rollback, just continue
585
644
  continue;
586
645
  }
@@ -592,7 +651,7 @@ class FeatureExecutor {
592
651
  feature_id: this.state.feature_id,
593
652
  success: rollbackResult.success,
594
653
  rolled_back_steps: rollbackResult.rolled_back_steps,
595
- failed_rollbacks: (_j = (_h = rollbackResult.failed_steps) === null || _h === void 0 ? void 0 : _h.length) !== null && _j !== void 0 ? _j : 0,
654
+ failed_rollbacks: (_k = (_j = rollbackResult.failed_steps) === null || _j === void 0 ? void 0 : _j.length) !== null && _k !== void 0 ? _k : 0,
596
655
  });
597
656
  // Persist failed feature result
598
657
  await this.persistExecutionResult(types_1.LogEventStatus.FAIL, undefined, result.error);
@@ -603,7 +662,7 @@ class FeatureExecutor {
603
662
  completed_steps: this.state.completed_steps,
604
663
  step_timings: this.state.step_timings,
605
664
  });
606
- await ((_k = this.logService) === null || _k === void 0 ? void 0 : _k.publish());
665
+ await ((_l = this.logService) === null || _l === void 0 ? void 0 : _l.publish());
607
666
  if (this.graphConnectionUsed) {
608
667
  await this.getGraphService().disconnect().catch(() => { });
609
668
  await this.getProcessorService().disconnectBrokerConnections().catch(() => { });
@@ -637,6 +696,7 @@ class FeatureExecutor {
637
696
  this.state.ended_at = Date.now();
638
697
  // Determine output - use last step output or aggregate (resolves $ operators)
639
698
  const output = await this.determineWorkflowOutput();
699
+ this.trace('execution.output.resolved', { output, completed_steps: this.state.completed_steps });
640
700
  stepLog('Run finished (completed)', {
641
701
  status: types_1.FeatureStatus.COMPLETED,
642
702
  completed_steps: this.state.completed_steps,
@@ -652,7 +712,7 @@ class FeatureExecutor {
652
712
  // Persist successful feature result
653
713
  await this.persistExecutionResult(types_1.LogEventStatus.SUCCESS, output);
654
714
  // Fire-and-forget log publish on success so we don't block on log upload
655
- (_l = this.logService) === null || _l === void 0 ? void 0 : _l.publish().catch(() => { });
715
+ (_m = this.logService) === null || _m === void 0 ? void 0 : _m.publish().catch(() => { });
656
716
  if (this.graphConnectionUsed) {
657
717
  await this.getGraphService().disconnect().catch(() => { });
658
718
  await this.getProcessorService().disconnectBrokerConnections().catch(() => { });
@@ -675,8 +735,9 @@ class FeatureExecutor {
675
735
  this.state.status = types_1.FeatureStatus.FAILED;
676
736
  this.state.ended_at = Date.now();
677
737
  const details = formatErrorDetails(error);
678
- const failedAt = (_m = this.state.current_step) !== null && _m !== void 0 ? _m : '(unknown)';
679
- debugLog('[FeatureExecutor] execute FAILED (exception)', Object.assign(Object.assign({ feature_id: this.state.feature_id, feature_tag: this.state.feature_tag, failed_at: failedAt, completed_steps: this.state.completed_steps, error: details.message }, (details.status != null && { http_status: details.status })), (details.responseBody != null && { response_body: details.responseBody })));
738
+ const failedAt = (_o = this.state.current_step) !== null && _o !== void 0 ? _o : '(unknown)';
739
+ debugLog('[FeatureExecutor] execute FAILED (exception)', Object.assign(Object.assign({ feature_id: this.state.feature_id, feature_tag: this.state.feature_tag, failed_at: failedAt, completed_steps: this.state.completed_steps, error: details.message }, (details.status != null && { http_status: details.status })), (details.responseBody != null && { response_body: sanitizeForLog(details.responseBody) })));
740
+ this.trace('execution.failed', { failed_at: failedAt, error: details, completed_steps: this.state.completed_steps });
680
741
  if (details.stack) {
681
742
  debugLog('[FeatureExecutor] execute FAILED stack', details.stack);
682
743
  }
@@ -686,7 +747,7 @@ class FeatureExecutor {
686
747
  : `Failed at ${failedAt}: ${details.message}`;
687
748
  stepLog('Run finished (failed - exception)', Object.assign({ status: types_1.FeatureStatus.FAILED, failed_step: failedAt, error: errorSummary, completed_steps: this.state.completed_steps, step_timings: this.state.step_timings }, (details.reason && { reason: details.reason })));
688
749
  await this.persistExecutionResult(types_1.LogEventStatus.FAIL, undefined, errorSummary);
689
- await ((_o = this.logService) === null || _o === void 0 ? void 0 : _o.publish());
750
+ await ((_p = this.logService) === null || _p === void 0 ? void 0 : _p.publish());
690
751
  if (this.graphConnectionUsed) {
691
752
  await this.getGraphService().disconnect().catch(() => { });
692
753
  await this.getProcessorService().disconnectBrokerConnections().catch(() => { });
@@ -719,12 +780,14 @@ class FeatureExecutor {
719
780
  });
720
781
  let resolvedInput = {};
721
782
  try {
783
+ this.trace('step.input.supplied', { step_tag: step.tag, step_type: step.type, payload: step.input || {} });
722
784
  // Resolve input with data references and all $ operators
723
785
  resolvedInput = (await this.resolveInput(step.input || {}));
786
+ this.trace('step.input.resolved', { step_tag: step.tag, step_type: step.type, payload: resolvedInput });
724
787
  debugLog('[FeatureExecutor] executeStep input', {
725
788
  feature_id: this.state.feature_id,
726
789
  step_tag: step.tag,
727
- input: resolvedInput,
790
+ input: sanitizeForLog(resolvedInput),
728
791
  });
729
792
  let output;
730
793
  // Route steps to dedicated services; only action and notification use ProcessorService.
@@ -751,6 +814,9 @@ class FeatureExecutor {
751
814
  case types_1.FeatureStepType.VECTOR:
752
815
  output = await this.executeVectorStep(step, resolvedInput);
753
816
  break;
817
+ case types_1.FeatureStepType.FUNCTION:
818
+ output = await this.executeFunctionStep(step, resolvedInput);
819
+ break;
754
820
  case types_1.FeatureStepType.QUOTA:
755
821
  output = await this.executeQuotaStep(step, resolvedInput);
756
822
  break;
@@ -792,15 +858,16 @@ class FeatureExecutor {
792
858
  }
793
859
  }
794
860
  const duration = Date.now() - startTime;
861
+ this.trace('step.response.received', { step_tag: step.tag, step_type: step.type, payload: output, duration_ms: duration });
795
862
  debugLog('[FeatureExecutor] executeStep output', {
796
863
  feature_id: this.state.feature_id,
797
864
  step_tag: step.tag,
798
- output,
865
+ output: sanitizeForLog(output),
799
866
  durationMs: duration,
800
867
  });
801
868
  return {
802
869
  success: true,
803
- input: resolvedInput,
870
+ input: sanitizeForLog(resolvedInput),
804
871
  output,
805
872
  duration,
806
873
  };
@@ -812,7 +879,14 @@ class FeatureExecutor {
812
879
  const stepErrorMsg = details.reason != null
813
880
  ? (details.status != null ? `${details.reason} (HTTP ${details.status})` : details.reason)
814
881
  : (details.status != null ? `${details.message} (HTTP ${details.status})` : details.message);
815
- debugLog('[FeatureExecutor] executeStep FAILED', Object.assign(Object.assign({ feature_id: this.state.feature_id, step_tag: step.tag, step_type: step.type, durationMs: duration, input: resolvedInput, error: stepErrorMsg }, (details.status != null && { http_status: details.status })), (details.responseBody != null && { response_body: details.responseBody })));
882
+ debugLog('[FeatureExecutor] executeStep FAILED', Object.assign(Object.assign({ feature_id: this.state.feature_id, step_tag: step.tag, step_type: step.type, durationMs: duration, input: resolvedInput, error: stepErrorMsg }, (details.status != null && { http_status: details.status })), (details.responseBody != null && { response_body: sanitizeForLog(details.responseBody) })));
883
+ this.trace('step.failed', {
884
+ step_tag: step.tag,
885
+ step_type: step.type,
886
+ payload: resolvedInput,
887
+ error: details,
888
+ duration_ms: duration,
889
+ });
816
890
  return {
817
891
  success: false,
818
892
  input: resolvedInput,
@@ -829,9 +903,10 @@ class FeatureExecutor {
829
903
  debugLog('[FeatureExecutor] executeActionStep', { feature_id: this.state.feature_id, step_tag: step.tag, app: step.app });
830
904
  // Step that only returns (no component call): no app → passthrough, output = resolved input
831
905
  if (!step.app) {
906
+ this.trace('action.passthrough', { step_tag: step.tag, payload: input });
832
907
  return input;
833
908
  }
834
- return this.getProcessorService().processAction({
909
+ const payload = {
835
910
  product: this.state.product,
836
911
  env: this.state.env,
837
912
  app: step.app,
@@ -839,25 +914,30 @@ class FeatureExecutor {
839
914
  input: input,
840
915
  retries: ((_a = step.options) === null || _a === void 0 ? void 0 : _a.retries) || 0,
841
916
  cache: (_b = step.options) === null || _b === void 0 ? void 0 : _b.cache,
917
+ session: this.inheritedSession,
842
918
  preloadedBootstrap: this.stepBootstrapCache.get(step.tag),
843
- });
919
+ };
920
+ this.trace('action.request.sent', { step_tag: step.tag, payload });
921
+ return this.getProcessorService().processAction(payload);
844
922
  }
845
923
  /**
846
924
  * Execute a database step: use query/insert/update/delete/upsert for DB operations, execute() for named actions.
847
925
  */
848
926
  async executeDatabaseStep(step, input) {
927
+ var _a;
849
928
  const database = step.database;
850
929
  const product = this.state.product;
851
930
  const env = this.state.env;
852
931
  const event = (step.event || '').toLowerCase();
853
932
  const db = this.getDatabaseService();
854
- const opts = Object.assign({ product, env, database }, input);
933
+ const opts = Object.assign(Object.assign({ product, env, database }, input), { session: (_a = input.session) !== null && _a !== void 0 ? _a : this.inheritedSession });
855
934
  debugLog('[FeatureExecutor] executeDatabaseStep', {
856
935
  feature_id: this.state.feature_id,
857
936
  step_tag: step.tag,
858
937
  database,
859
938
  event,
860
939
  });
940
+ this.trace('database.request.sent', { step_tag: step.tag, event, payload: opts });
861
941
  switch (event) {
862
942
  case 'query':
863
943
  return db.query(opts);
@@ -876,6 +956,7 @@ class FeatureExecutor {
876
956
  database,
877
957
  action: step.event,
878
958
  input: input,
959
+ session: this.inheritedSession,
879
960
  });
880
961
  }
881
962
  }
@@ -886,14 +967,17 @@ class FeatureExecutor {
886
967
  var _a;
887
968
  const event = `${step.notification}:${step.event}`;
888
969
  debugLog('[FeatureExecutor] executeNotificationStep', { feature_id: this.state.feature_id, step_tag: step.tag, event });
889
- return this.getProcessorService().processNotification({
970
+ const payload = {
890
971
  product: this.state.product,
891
972
  env: this.state.env,
892
973
  event,
893
974
  input: input,
894
975
  retries: ((_a = step.options) === null || _a === void 0 ? void 0 : _a.retries) || 0,
976
+ session: this.inheritedSession,
895
977
  preloadedBootstrap: this.stepBootstrapCache.get(step.tag),
896
- });
978
+ };
979
+ this.trace('notification.request.sent', { step_tag: step.tag, payload });
980
+ return this.getProcessorService().processNotification(payload);
897
981
  }
898
982
  /**
899
983
  * Execute a storage step using StorageService (upload, download, or delete by input shape).
@@ -903,9 +987,10 @@ class FeatureExecutor {
903
987
  const product = this.state.product;
904
988
  const env = this.state.env;
905
989
  const storage = step.storage;
906
- const opts = { product, env, storage };
990
+ const opts = { product, env, storage, session: this.inheritedSession };
907
991
  debugLog('[FeatureExecutor] executeStorageStep', { feature_id: this.state.feature_id, step_tag: step.tag, storage, event: step.event });
908
992
  const inp = input;
993
+ this.trace('storage.request.sent', { step_tag: step.tag, event: step.event, payload: Object.assign(Object.assign({}, opts), inp) });
909
994
  if (inp.buffer != null && inp.fileName != null) {
910
995
  return this.getStorageService().upload(Object.assign(Object.assign({}, opts), { fileName: String(inp.fileName), buffer: inp.buffer, mimeType: inp.mimeType != null ? String(inp.mimeType) : undefined }));
911
996
  }
@@ -922,12 +1007,15 @@ class FeatureExecutor {
922
1007
  const event = `${step.broker}:${step.event}`;
923
1008
  const message = (input && input.message != null) ? input.message : (input || {});
924
1009
  debugLog('[FeatureExecutor] executeProduceStep', { feature_id: this.state.feature_id, step_tag: step.tag, event });
925
- return this.getBrokersService().publish({
1010
+ const payload = {
926
1011
  product: this.state.product,
927
1012
  env: this.state.env,
928
1013
  event,
929
1014
  message: message,
930
- });
1015
+ session: this.inheritedBrokerSession(),
1016
+ };
1017
+ this.trace('event.request.sent', { step_tag: step.tag, payload });
1018
+ return this.getBrokersService().publish(payload);
931
1019
  }
932
1020
  /**
933
1021
  * Execute a graph step
@@ -938,6 +1026,7 @@ class FeatureExecutor {
938
1026
  const graphTag = step.graph;
939
1027
  const action = step.event;
940
1028
  debugLog('[FeatureExecutor] executeGraphStep', { feature_id: this.state.feature_id, step_tag: step.tag, graph: graphTag, action });
1029
+ this.trace('graph.request.preparing', { step_tag: step.tag, action, graph: graphTag, payload: input });
941
1030
  this.graphConnectionUsed = true;
942
1031
  await this.getGraphService().connect({
943
1032
  env: this.state.env,
@@ -951,6 +1040,7 @@ class FeatureExecutor {
951
1040
  const result = await this.getGraphService().createNode({
952
1041
  labels: input.labels,
953
1042
  properties: input.properties,
1043
+ session: this.inheritedSession,
954
1044
  });
955
1045
  return result;
956
1046
  }
@@ -958,6 +1048,7 @@ class FeatureExecutor {
958
1048
  const result = await this.getGraphService().updateNode({
959
1049
  id: input.id,
960
1050
  properties: input.properties,
1051
+ session: this.inheritedSession,
961
1052
  });
962
1053
  return result;
963
1054
  }
@@ -965,6 +1056,7 @@ class FeatureExecutor {
965
1056
  const result = await this.getGraphService().deleteNode({
966
1057
  id: input.id,
967
1058
  detach: input.detach,
1059
+ session: this.inheritedSession,
968
1060
  });
969
1061
  return result;
970
1062
  }
@@ -974,17 +1066,19 @@ class FeatureExecutor {
974
1066
  endNodeId: input.endNodeId || input.to,
975
1067
  type: input.type,
976
1068
  properties: input.properties,
1069
+ session: this.inheritedSession,
977
1070
  });
978
1071
  return result;
979
1072
  }
980
1073
  case 'deleteRelationship': {
981
1074
  const result = await this.getGraphService().deleteRelationship({
982
1075
  id: input.id,
1076
+ session: this.inheritedSession,
983
1077
  });
984
1078
  return result;
985
1079
  }
986
1080
  case 'query': {
987
- const result = await this.getGraphService().query(input.query, input.params);
1081
+ const result = await this.getGraphService().query(input.query, input.params, undefined, this.inheritedSession);
988
1082
  return result;
989
1083
  }
990
1084
  case 'findNodes': {
@@ -993,6 +1087,7 @@ class FeatureExecutor {
993
1087
  where: input.where,
994
1088
  limit: input.limit,
995
1089
  skip: input.skip,
1090
+ session: this.inheritedSession,
996
1091
  });
997
1092
  return result;
998
1093
  }
@@ -1002,6 +1097,7 @@ class FeatureExecutor {
1002
1097
  relationshipTypes: input.relationshipTypes,
1003
1098
  direction: input.direction,
1004
1099
  maxDepth: input.maxDepth,
1100
+ session: this.inheritedSession,
1005
1101
  });
1006
1102
  return result;
1007
1103
  }
@@ -1013,6 +1109,7 @@ class FeatureExecutor {
1013
1109
  graph: graphTag,
1014
1110
  action,
1015
1111
  input,
1112
+ session: this.inheritedSession,
1016
1113
  });
1017
1114
  return result;
1018
1115
  }
@@ -1026,7 +1123,7 @@ class FeatureExecutor {
1026
1123
  * Execute a vector step (query, upsert, deleteVectors, or custom action via execute).
1027
1124
  */
1028
1125
  async executeVectorStep(step, input) {
1029
- var _a;
1126
+ var _a, _b, _c, _d, _e;
1030
1127
  const vectorTag = step.vector;
1031
1128
  if (!vectorTag) {
1032
1129
  throw new Error(`Vector step "${step.tag}" has no vector tag`);
@@ -1041,21 +1138,22 @@ class FeatureExecutor {
1041
1138
  vector: vectorTag,
1042
1139
  event,
1043
1140
  });
1141
+ this.trace('vector.request.preparing', { step_tag: step.tag, event, vector: vectorTag, payload: input });
1044
1142
  switch (event) {
1045
1143
  case 'query': {
1046
- const result = await svc.query(Object.assign({ product,
1047
- env, tag: vectorTag }, input));
1144
+ const result = await svc.query(Object.assign(Object.assign({ product,
1145
+ env, tag: vectorTag }, input), { session: (_a = input.session) !== null && _a !== void 0 ? _a : this.inheritedSession }));
1048
1146
  return result;
1049
1147
  }
1050
1148
  case 'upsert': {
1051
- const result = await svc.upsert(Object.assign({ product,
1052
- env, tag: vectorTag }, input));
1149
+ const result = await svc.upsert(Object.assign(Object.assign({ product,
1150
+ env, tag: vectorTag }, input), { session: (_b = input.session) !== null && _b !== void 0 ? _b : this.inheritedSession }));
1053
1151
  return result;
1054
1152
  }
1055
1153
  case 'delete':
1056
1154
  case 'deletevectors': {
1057
- const result = await svc.deleteVectors(Object.assign({ product,
1058
- env, tag: vectorTag }, input));
1155
+ const result = await svc.deleteVectors(Object.assign(Object.assign({ product,
1156
+ env, tag: vectorTag }, input), { session: (_c = input.session) !== null && _c !== void 0 ? _c : this.inheritedSession }));
1059
1157
  return result;
1060
1158
  }
1061
1159
  default: {
@@ -1066,9 +1164,10 @@ class FeatureExecutor {
1066
1164
  vector: vectorTag,
1067
1165
  action: step.event,
1068
1166
  input: input,
1167
+ session: this.inheritedSession,
1069
1168
  });
1070
- const op = (_a = resolved === null || resolved === void 0 ? void 0 : resolved._operation) !== null && _a !== void 0 ? _a : resolved === null || resolved === void 0 ? void 0 : resolved.operation;
1071
- const opts = Object.assign({ product, env, tag: vectorTag }, resolved);
1169
+ const op = (_d = resolved === null || resolved === void 0 ? void 0 : resolved._operation) !== null && _d !== void 0 ? _d : resolved === null || resolved === void 0 ? void 0 : resolved.operation;
1170
+ const opts = Object.assign(Object.assign({ product, env, tag: vectorTag }, resolved), { session: (_e = resolved.session) !== null && _e !== void 0 ? _e : this.inheritedSession });
1072
1171
  if (op === 'query' || !op) {
1073
1172
  return svc.query(opts);
1074
1173
  }
@@ -1082,6 +1181,46 @@ class FeatureExecutor {
1082
1181
  }
1083
1182
  }
1084
1183
  }
1184
+ /** Execute a portable application function through a local handler or signed HTTP transport. */
1185
+ async executeFunctionStep(step, input) {
1186
+ const reference = step.function_ref;
1187
+ if (!reference) {
1188
+ throw new Error(`Function step "${step.tag}" has no function_ref. Recompile the feature with ctx.functions.`);
1189
+ }
1190
+ const invocationId = (0, crypto_1.randomUUID)();
1191
+ this.functionInvocations.set(step.tag, {
1192
+ invocation_id: invocationId,
1193
+ namespace: reference.namespace,
1194
+ operation: reference.operation,
1195
+ version: reference.version,
1196
+ });
1197
+ const deadlineAt = reference.timeout_ms ? Date.now() + reference.timeout_ms : undefined;
1198
+ this.trace('function.resolution.started', {
1199
+ step_tag: step.tag,
1200
+ invocation_id: invocationId,
1201
+ function: `${reference.namespace}.${reference.operation}@${reference.version}`,
1202
+ transports: reference.transports.map(transport => transport.type),
1203
+ payload: input,
1204
+ });
1205
+ const output = await functions_1.portableFunctions.invoke(reference, input, {
1206
+ product: this.state.product,
1207
+ env: this.state.env,
1208
+ workspace_id: this.config.workspace_id,
1209
+ feature_id: this.state.feature_id,
1210
+ feature_tag: this.state.feature_tag,
1211
+ step_tag: step.tag,
1212
+ invocation_id: invocationId,
1213
+ session: this.inheritedSession,
1214
+ deadline_at: deadlineAt,
1215
+ }, this.config.access_key);
1216
+ this.trace('function.response.received', {
1217
+ step_tag: step.tag,
1218
+ invocation_id: invocationId,
1219
+ function: `${reference.namespace}.${reference.operation}@${reference.version}`,
1220
+ payload: output,
1221
+ });
1222
+ return output;
1223
+ }
1085
1224
  /**
1086
1225
  * Execute a quota step
1087
1226
  */
@@ -1092,6 +1231,7 @@ class FeatureExecutor {
1092
1231
  env: this.state.env,
1093
1232
  tag: step.quota,
1094
1233
  input,
1234
+ session: this.inheritedSession,
1095
1235
  });
1096
1236
  }
1097
1237
  /**
@@ -1104,6 +1244,7 @@ class FeatureExecutor {
1104
1244
  env: this.state.env,
1105
1245
  tag: step.fallback,
1106
1246
  input,
1247
+ session: this.inheritedSession,
1107
1248
  });
1108
1249
  }
1109
1250
  /**
@@ -1130,7 +1271,8 @@ class FeatureExecutor {
1130
1271
  env: this.state.env,
1131
1272
  tag: childTag,
1132
1273
  input,
1133
- }, this._privateKey);
1274
+ session: this.inheritedSession,
1275
+ }, this._privateKey, this.sessionLogFields, this.productBuilder);
1134
1276
  const result = await childExecutor.execute();
1135
1277
  debugLog('[FeatureExecutor] executeChildWorkflowStep result', {
1136
1278
  feature_id: this.state.feature_id,
@@ -1405,12 +1547,13 @@ class FeatureExecutor {
1405
1547
  * Execute a rollback handler
1406
1548
  */
1407
1549
  async executeRollbackHandler(rollback, stepOutput) {
1408
- var _a, _b, _c, _d, _e, _f, _g;
1550
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
1409
1551
  if (!rollback)
1410
1552
  return;
1411
1553
  debugLog('[FeatureExecutor] executeRollbackHandler', { feature_id: this.state.feature_id, rollback_type: rollback.type });
1412
1554
  // Resolve rollback input, including step output references
1413
1555
  const resolvedInput = await this.resolveInput(rollback.input || {}, stepOutput);
1556
+ this.trace('rollback.input.resolved', { rollback_type: rollback.type, payload: resolvedInput });
1414
1557
  switch (rollback.type) {
1415
1558
  case types_1.FeatureStepType.ACTION:
1416
1559
  await this.getProcessorService().processAction({
@@ -1420,6 +1563,7 @@ class FeatureExecutor {
1420
1563
  action: rollback.event,
1421
1564
  input: resolvedInput,
1422
1565
  retries: (_a = rollback.retries) !== null && _a !== void 0 ? _a : 0,
1566
+ session: this.inheritedSession,
1423
1567
  });
1424
1568
  break;
1425
1569
  case types_1.FeatureStepType.DATABASE_ACTION: {
@@ -1428,7 +1572,7 @@ class FeatureExecutor {
1428
1572
  const env = this.state.env;
1429
1573
  const database = rollback.database;
1430
1574
  const event = ((_b = rollback.event) !== null && _b !== void 0 ? _b : '').toLowerCase();
1431
- const opts = Object.assign({ product, env, database }, resolvedInput);
1575
+ const opts = Object.assign(Object.assign({ product, env, database }, resolvedInput), { session: (_c = resolvedInput.session) !== null && _c !== void 0 ? _c : this.inheritedSession });
1432
1576
  if (event === 'query')
1433
1577
  await db.query(opts);
1434
1578
  else if (event === 'insert')
@@ -1446,6 +1590,7 @@ class FeatureExecutor {
1446
1590
  database,
1447
1591
  action: rollback.event,
1448
1592
  input: resolvedInput,
1593
+ session: this.inheritedSession,
1449
1594
  });
1450
1595
  break;
1451
1596
  }
@@ -1456,14 +1601,15 @@ class FeatureExecutor {
1456
1601
  env: this.state.env,
1457
1602
  event: notifEvent,
1458
1603
  input: resolvedInput,
1459
- retries: (_c = rollback.retries) !== null && _c !== void 0 ? _c : 0,
1604
+ retries: (_d = rollback.retries) !== null && _d !== void 0 ? _d : 0,
1605
+ session: this.inheritedSession,
1460
1606
  });
1461
1607
  break;
1462
1608
  case types_1.FeatureStepType.STORAGE: {
1463
1609
  const product = this.state.product;
1464
1610
  const env = this.state.env;
1465
1611
  const storage = rollback.storage;
1466
- const opts = { product, env, storage };
1612
+ const opts = { product, env, storage, session: this.inheritedSession };
1467
1613
  const inp = resolvedInput;
1468
1614
  if (inp.buffer != null && inp.fileName != null) {
1469
1615
  await this.getStorageService().upload(Object.assign(Object.assign({}, opts), { fileName: String(inp.fileName), buffer: inp.buffer, mimeType: inp.mimeType != null ? String(inp.mimeType) : undefined }));
@@ -1472,7 +1618,7 @@ class FeatureExecutor {
1472
1618
  await this.getStorageService().delete(Object.assign(Object.assign({}, opts), { fileName: String(inp.file_key) }));
1473
1619
  }
1474
1620
  else {
1475
- await this.getStorageService().download(Object.assign(Object.assign({}, opts), { fileName: String((_e = (_d = inp.fileName) !== null && _d !== void 0 ? _d : inp.file_key) !== null && _e !== void 0 ? _e : '') }));
1621
+ await this.getStorageService().download(Object.assign(Object.assign({}, opts), { fileName: String((_f = (_e = inp.fileName) !== null && _e !== void 0 ? _e : inp.file_key) !== null && _f !== void 0 ? _f : '') }));
1476
1622
  }
1477
1623
  break;
1478
1624
  }
@@ -1481,16 +1627,16 @@ class FeatureExecutor {
1481
1627
  const env = this.state.env;
1482
1628
  const vectorTag = rollback.vector;
1483
1629
  const inp = resolvedInput;
1484
- const event = ((_f = rollback.event) !== null && _f !== void 0 ? _f : '').toLowerCase();
1630
+ const event = ((_g = rollback.event) !== null && _g !== void 0 ? _g : '').toLowerCase();
1485
1631
  const svc = this.getVectorService();
1486
1632
  if (event === 'query') {
1487
- await svc.query(Object.assign({ product, env, tag: vectorTag }, inp));
1633
+ await svc.query(Object.assign(Object.assign({ product, env, tag: vectorTag }, inp), { session: (_h = inp.session) !== null && _h !== void 0 ? _h : this.inheritedSession }));
1488
1634
  }
1489
1635
  else if (event === 'upsert') {
1490
- await svc.upsert(Object.assign({ product, env, tag: vectorTag }, inp));
1636
+ await svc.upsert(Object.assign(Object.assign({ product, env, tag: vectorTag }, inp), { session: (_j = inp.session) !== null && _j !== void 0 ? _j : this.inheritedSession }));
1491
1637
  }
1492
1638
  else if (event === 'delete' || event === 'deletevectors') {
1493
- await svc.deleteVectors(Object.assign({ product, env, tag: vectorTag }, inp));
1639
+ await svc.deleteVectors(Object.assign(Object.assign({ product, env, tag: vectorTag }, inp), { session: (_k = inp.session) !== null && _k !== void 0 ? _k : this.inheritedSession }));
1494
1640
  }
1495
1641
  else {
1496
1642
  const resolved = await svc.actions.resolve({
@@ -1499,9 +1645,10 @@ class FeatureExecutor {
1499
1645
  vector: vectorTag,
1500
1646
  action: rollback.event,
1501
1647
  input: inp,
1648
+ session: this.inheritedSession,
1502
1649
  });
1503
- const op = (_g = resolved === null || resolved === void 0 ? void 0 : resolved._operation) !== null && _g !== void 0 ? _g : resolved === null || resolved === void 0 ? void 0 : resolved.operation;
1504
- const opts = Object.assign({ product, env, tag: vectorTag }, resolved);
1650
+ const op = (_l = resolved === null || resolved === void 0 ? void 0 : resolved._operation) !== null && _l !== void 0 ? _l : resolved === null || resolved === void 0 ? void 0 : resolved.operation;
1651
+ const opts = Object.assign(Object.assign({ product, env, tag: vectorTag }, resolved), { session: (_m = resolved.session) !== null && _m !== void 0 ? _m : this.inheritedSession });
1505
1652
  if (op === 'upsert')
1506
1653
  await svc.upsert(opts);
1507
1654
  else if (op === 'delete' || op === 'deleteVectors')
@@ -1519,6 +1666,7 @@ class FeatureExecutor {
1519
1666
  env: this.state.env,
1520
1667
  event: pubEvent,
1521
1668
  input: resolvedInput,
1669
+ session: this.inheritedSession,
1522
1670
  });
1523
1671
  break;
1524
1672
  }
@@ -1848,6 +1996,7 @@ class FeatureExecutor {
1848
1996
  env_slug: env,
1849
1997
  steps: workflowSteps,
1850
1998
  });
1999
+ this.trace('bootstrap.response.fetched', { requested_steps: workflowSteps, payload: bootstraps });
1851
2000
  stepLog('Bootstrap feature API response', {
1852
2001
  received_keys: Object.keys(bootstraps),
1853
2002
  keys_count: Object.keys(bootstraps).length,
@@ -1871,6 +2020,7 @@ class FeatureExecutor {
1871
2020
  var _a;
1872
2021
  try {
1873
2022
  const broker = await this.productBuilder.fetchMessageBroker(tag);
2023
+ this.trace('resource.fetched', { resource_type: 'event', resource_tag: tag, payload: broker });
1874
2024
  return { tag, found: !!broker };
1875
2025
  }
1876
2026
  catch (e) {
@@ -1892,6 +2042,7 @@ class FeatureExecutor {
1892
2042
  var _a;
1893
2043
  try {
1894
2044
  const db = await this.productBuilder.fetchDatabase(tag);
2045
+ this.trace('resource.fetched', { resource_type: 'database', resource_tag: tag, payload: db });
1895
2046
  return { tag, found: !!db };
1896
2047
  }
1897
2048
  catch (e) {
@@ -1913,6 +2064,7 @@ class FeatureExecutor {
1913
2064
  var _a;
1914
2065
  try {
1915
2066
  const graph = await this.productBuilder.fetchGraph(tag);
2067
+ this.trace('resource.fetched', { resource_type: 'graph', resource_tag: tag, payload: graph });
1916
2068
  return { tag, found: !!graph };
1917
2069
  }
1918
2070
  catch (e) {
@@ -1933,6 +2085,7 @@ class FeatureExecutor {
1933
2085
  var _a;
1934
2086
  try {
1935
2087
  const vec = await this.productBuilder.fetchVector(tag);
2088
+ this.trace('resource.fetched', { resource_type: 'vector', resource_tag: tag, payload: vec });
1936
2089
  return { tag, found: !!vec };
1937
2090
  }
1938
2091
  catch (e) {
@@ -1954,6 +2107,7 @@ class FeatureExecutor {
1954
2107
  var _a;
1955
2108
  try {
1956
2109
  const quota = await this.productBuilder.fetchQuota(tag);
2110
+ this.trace('resource.fetched', { resource_type: 'quota', resource_tag: tag, payload: quota });
1957
2111
  return { tag, found: !!quota };
1958
2112
  }
1959
2113
  catch (e) {