@ductape/sdk 0.1.108 → 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.
- package/dist/api/services/processorApi.service.js +23 -9
- package/dist/api/services/processorApi.service.js.map +1 -1
- package/dist/features/feature-executor.d.ts +9 -0
- package/dist/features/feature-executor.js +246 -74
- package/dist/features/feature-executor.js.map +1 -1
- package/dist/features/features.service.d.ts +5 -0
- package/dist/features/features.service.js +49 -7
- package/dist/features/features.service.js.map +1 -1
- package/dist/features/index.d.ts +2 -1
- package/dist/features/index.js +3 -1
- package/dist/features/index.js.map +1 -1
- package/dist/features/types/features.types.d.ts +9 -0
- package/dist/features/types/features.types.js.map +1 -1
- package/dist/functions/functions.runtime.d.ts +25 -0
- package/dist/functions/functions.runtime.js +254 -0
- package/dist/functions/functions.runtime.js.map +1 -0
- package/dist/functions/http-handler.d.ts +17 -0
- package/dist/functions/http-handler.js +51 -0
- package/dist/functions/http-handler.js.map +1 -0
- package/dist/functions/index.d.ts +3 -0
- package/dist/functions/index.js +20 -0
- package/dist/functions/index.js.map +1 -0
- package/dist/functions/types.d.ts +94 -0
- package/dist/functions/types.js +15 -0
- package/dist/functions/types.js.map +1 -0
- package/dist/graph/graphs.service.d.ts +1 -1
- package/dist/graph/graphs.service.js +73 -43
- package/dist/graph/graphs.service.js.map +1 -1
- package/dist/graph/types/traversal.interface.d.ts +2 -0
- package/dist/index.d.ts +16 -1
- package/dist/index.js +23 -3
- package/dist/index.js.map +1 -1
- package/dist/processor/services/processor.service.d.ts +6 -0
- package/dist/processor/services/processor.service.js +8 -13
- package/dist/processor/services/processor.service.js.map +1 -1
- package/dist/sessions/sessions.service.d.ts +2 -0
- package/dist/sessions/sessions.service.js +15 -5
- package/dist/sessions/sessions.service.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/productsBuilder.types.d.ts +3 -0
- package/dist/types/productsBuilder.types.js +2 -0
- package/dist/types/productsBuilder.types.js.map +1 -1
- package/dist/vector/vector-database.service.d.ts +2 -0
- package/dist/vector/vector-database.service.js +21 -12
- package/dist/vector/vector-database.service.js.map +1 -1
- 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,56 @@ 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
|
+
};
|
|
84
|
+
/** Observability must not disappear because a successful result contains BigInt or cycles. */
|
|
85
|
+
const stringifyProcessorValue = (value) => {
|
|
86
|
+
const seen = new WeakSet();
|
|
87
|
+
return JSON.stringify(value, (_key, nested) => {
|
|
88
|
+
if (typeof nested === 'bigint')
|
|
89
|
+
return nested.toString();
|
|
90
|
+
if (nested instanceof Error) {
|
|
91
|
+
return { name: nested.name, message: nested.message, stack: nested.stack };
|
|
92
|
+
}
|
|
93
|
+
if (nested && typeof nested === 'object') {
|
|
94
|
+
if (seen.has(nested))
|
|
95
|
+
return '[Circular]';
|
|
96
|
+
seen.add(nested);
|
|
97
|
+
}
|
|
98
|
+
return nested;
|
|
99
|
+
});
|
|
100
|
+
};
|
|
50
101
|
/** Normalize error to a string and extract HTTP details when present (e.g. Axios) */
|
|
51
102
|
function formatErrorDetails(error) {
|
|
52
103
|
var _a, _b, _c, _d;
|
|
@@ -98,6 +149,7 @@ class FeatureExecutor {
|
|
|
98
149
|
this.graphConnectionUsed = false;
|
|
99
150
|
/** Pre-fetched bootstrap data per step tag (feature batch prefetch). */
|
|
100
151
|
this.stepBootstrapCache = new Map();
|
|
152
|
+
this.functionInvocations = new Map();
|
|
101
153
|
debugLog('[FeatureExecutor] constructor ENTRY', {
|
|
102
154
|
feature_tag: feature.tag,
|
|
103
155
|
product: options.product,
|
|
@@ -106,6 +158,7 @@ class FeatureExecutor {
|
|
|
106
158
|
});
|
|
107
159
|
this.config = config;
|
|
108
160
|
this.feature = feature;
|
|
161
|
+
this.inheritedSession = options.session;
|
|
109
162
|
this.sessionLogFields = sessionLogFields || {};
|
|
110
163
|
this._privateKey = private_key || '';
|
|
111
164
|
this.preInitializedProduct = Boolean(preInitializedBuilder);
|
|
@@ -141,8 +194,26 @@ class FeatureExecutor {
|
|
|
141
194
|
feature_id: this.state.feature_id,
|
|
142
195
|
feature_tag: this.state.feature_tag,
|
|
143
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),
|
|
144
199
|
});
|
|
145
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
|
+
}
|
|
146
217
|
/**
|
|
147
218
|
* Get auth payload for API calls
|
|
148
219
|
*/
|
|
@@ -152,6 +223,7 @@ class FeatureExecutor {
|
|
|
152
223
|
workspace_id: this.config.workspace_id,
|
|
153
224
|
public_key: this.config.public_key,
|
|
154
225
|
token: this.config.token,
|
|
226
|
+
access_key: this.config.access_key,
|
|
155
227
|
};
|
|
156
228
|
}
|
|
157
229
|
/** Product private key for processor result encryption; must always match backend decryption key. No fallback to workspace key. */
|
|
@@ -172,6 +244,10 @@ class FeatureExecutor {
|
|
|
172
244
|
access_key: this.config.access_key,
|
|
173
245
|
preInitializedProductBuilder: this.productBuilder,
|
|
174
246
|
});
|
|
247
|
+
this._processorService.setFeatureExecutionContext({
|
|
248
|
+
feature_id: this.state.feature_id,
|
|
249
|
+
feature_tag: this.state.feature_tag,
|
|
250
|
+
});
|
|
175
251
|
}
|
|
176
252
|
return this._processorService;
|
|
177
253
|
}
|
|
@@ -301,8 +377,8 @@ class FeatureExecutor {
|
|
|
301
377
|
error,
|
|
302
378
|
};
|
|
303
379
|
const inputPayload = { product: this.state.product, env: this.state.env, event: this.state.feature_tag, input: this.state.input };
|
|
304
|
-
const resultStr =
|
|
305
|
-
const inputStr =
|
|
380
|
+
const resultStr = stringifyProcessorValue(resultData);
|
|
381
|
+
const inputStr = stringifyProcessorValue(inputPayload);
|
|
306
382
|
const encKey = this.getProcessorResultEncryptionKey();
|
|
307
383
|
const processorResult = {
|
|
308
384
|
process_id: this.state.feature_id,
|
|
@@ -320,7 +396,9 @@ class FeatureExecutor {
|
|
|
320
396
|
product_tag: this.state.product,
|
|
321
397
|
workspace_id: this.config.workspace_id,
|
|
322
398
|
};
|
|
399
|
+
this.trace('execution.persistence.sent', { status, payload: resultData });
|
|
323
400
|
await this.processorApiService.saveResult(processorResult, this.getAuthPayload());
|
|
401
|
+
this.trace('execution.persistence.acknowledged', { status, process_id: this.state.feature_id });
|
|
324
402
|
debugLog('[FeatureExecutor] persistExecutionResult SUCCESS', { feature_id: this.state.feature_id, status });
|
|
325
403
|
}
|
|
326
404
|
catch (err) {
|
|
@@ -356,6 +434,7 @@ class FeatureExecutor {
|
|
|
356
434
|
* Processor results for steps always have component: 'feature_step' and step_type set to the step kind.
|
|
357
435
|
*/
|
|
358
436
|
async persistStepResult(step, status, output, error, duration, input) {
|
|
437
|
+
var _a;
|
|
359
438
|
const resolvedInput = input !== null && input !== void 0 ? input : step.input;
|
|
360
439
|
const stepType = this.getStepTypeForResult(step);
|
|
361
440
|
debugLog('[FeatureExecutor] persistStepResult ENTRY', {
|
|
@@ -373,30 +452,20 @@ class FeatureExecutor {
|
|
|
373
452
|
? output
|
|
374
453
|
: {}
|
|
375
454
|
: { error: error !== null && error !== void 0 ? error : 'Step failed' };
|
|
376
|
-
const resultStr =
|
|
377
|
-
const inputStr =
|
|
455
|
+
const resultStr = stringifyProcessorValue(value);
|
|
456
|
+
const inputStr = stringifyProcessorValue(resolvedInput);
|
|
378
457
|
const encKey = this.getProcessorResultEncryptionKey();
|
|
379
|
-
const stepResult = {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
env: this.state.env,
|
|
383
|
-
component: types_1.LogEventTypes.FEATURE_STEP, // step results always feature_step
|
|
384
|
-
status,
|
|
385
|
-
start: Date.now() - (duration || 0),
|
|
386
|
-
end: Date.now(),
|
|
387
|
-
retryable: true,
|
|
388
|
-
result: encKey ? (0, processor_utils_1.encrypt)(resultStr, encKey) : resultStr,
|
|
389
|
-
input: encKey ? (0, processor_utils_1.encrypt)(inputStr, encKey) : inputStr,
|
|
390
|
-
feature_id: this.state.feature_id,
|
|
391
|
-
feature_tag: this.state.feature_tag,
|
|
392
|
-
product_tag: this.state.product,
|
|
393
|
-
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', {
|
|
394
461
|
step_tag: step.tag,
|
|
395
|
-
step_type: stepType,
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
462
|
+
step_type: stepType,
|
|
463
|
+
status,
|
|
464
|
+
input: resolvedInput,
|
|
465
|
+
output: value,
|
|
466
|
+
});
|
|
399
467
|
await this.processorApiService.saveResult(stepResult, this.getAuthPayload());
|
|
468
|
+
this.trace('step.persistence.acknowledged', { step_tag: step.tag, status, process_id: stepProcessId });
|
|
400
469
|
debugLog('[FeatureExecutor] persistStepResult SUCCESS', { feature_id: this.state.feature_id, step_tag: step.tag });
|
|
401
470
|
}
|
|
402
471
|
catch (err) {
|
|
@@ -449,7 +518,7 @@ class FeatureExecutor {
|
|
|
449
518
|
* Execute the feature
|
|
450
519
|
*/
|
|
451
520
|
async execute() {
|
|
452
|
-
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;
|
|
453
522
|
const startTime = Date.now();
|
|
454
523
|
debugLog('[FeatureExecutor] execute ENTRY', {
|
|
455
524
|
feature_id: this.state.feature_id,
|
|
@@ -457,6 +526,10 @@ class FeatureExecutor {
|
|
|
457
526
|
product: this.state.product,
|
|
458
527
|
env: this.state.env,
|
|
459
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
|
+
});
|
|
460
533
|
try {
|
|
461
534
|
// Track phase so failures before first step are reported as (initialization)
|
|
462
535
|
this.state.current_step = '(initialization)';
|
|
@@ -469,6 +542,7 @@ class FeatureExecutor {
|
|
|
469
542
|
this.productId = this.productBuilder.fetchProductId();
|
|
470
543
|
}
|
|
471
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 });
|
|
472
546
|
// Initialize logging after we have product ID
|
|
473
547
|
this.initializeLogging();
|
|
474
548
|
this.state.status = types_1.FeatureStatus.RUNNING;
|
|
@@ -489,14 +563,17 @@ class FeatureExecutor {
|
|
|
489
563
|
}
|
|
490
564
|
catch (prefetchErr) {
|
|
491
565
|
stepLog('Bootstrap prefetch failed (continuing without prefetch)', {
|
|
492
|
-
error: (
|
|
566
|
+
error: (_b = prefetchErr === null || prefetchErr === void 0 ? void 0 : prefetchErr.message) !== null && _b !== void 0 ? _b : String(prefetchErr),
|
|
493
567
|
});
|
|
494
568
|
this.stepBootstrapCache.clear();
|
|
495
569
|
}
|
|
496
570
|
// Execute each step
|
|
497
571
|
for (const step of orderedSteps) {
|
|
498
572
|
// Check step condition if present
|
|
499
|
-
|
|
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) {
|
|
500
577
|
debugLog('[FeatureExecutor] execute step SKIPPED (condition)', { feature_id: this.state.feature_id, step_tag: step.tag });
|
|
501
578
|
this.logStepEvent(step, `Step ${step.tag} - skipped (condition not met)`, logs_types_1.LogEventStatus.SUCCESS, { skipped: true });
|
|
502
579
|
continue; // Skip step if condition not met
|
|
@@ -517,8 +594,8 @@ class FeatureExecutor {
|
|
|
517
594
|
success: result.success,
|
|
518
595
|
durationMs: result.duration,
|
|
519
596
|
hasError: !!result.error,
|
|
520
|
-
input: result.input,
|
|
521
|
-
output: result.output,
|
|
597
|
+
input: sanitizeForLog(result.input),
|
|
598
|
+
output: sanitizeForLog(result.output),
|
|
522
599
|
});
|
|
523
600
|
// Log step completion
|
|
524
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 });
|
|
@@ -530,7 +607,7 @@ class FeatureExecutor {
|
|
|
530
607
|
try {
|
|
531
608
|
stepReturnValue = await this.resolveInput(outputSchema, result.output);
|
|
532
609
|
}
|
|
533
|
-
catch (
|
|
610
|
+
catch (_q) {
|
|
534
611
|
stepReturnValue = result.output;
|
|
535
612
|
}
|
|
536
613
|
}
|
|
@@ -547,22 +624,22 @@ class FeatureExecutor {
|
|
|
547
624
|
});
|
|
548
625
|
if (!result.success) {
|
|
549
626
|
this.state.failed_step = step.tag;
|
|
550
|
-
stepLog('Step failed', { tag: step.tag, error: result.error, allow_fail: (
|
|
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 });
|
|
551
628
|
debugLog('[FeatureExecutor] execute step FAILED', {
|
|
552
629
|
feature_id: this.state.feature_id,
|
|
553
630
|
step_tag: step.tag,
|
|
554
631
|
error: result.error,
|
|
555
|
-
allow_fail: (
|
|
556
|
-
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,
|
|
557
634
|
});
|
|
558
635
|
// Check if step allows failure
|
|
559
|
-
if ((
|
|
636
|
+
if ((_g = step.options) === null || _g === void 0 ? void 0 : _g.allow_fail) {
|
|
560
637
|
// Store error but continue
|
|
561
638
|
this.state.steps[step.tag] = { error: result.error };
|
|
562
639
|
continue;
|
|
563
640
|
}
|
|
564
641
|
// Check if step is optional
|
|
565
|
-
if ((
|
|
642
|
+
if ((_h = step.options) === null || _h === void 0 ? void 0 : _h.optional) {
|
|
566
643
|
// Don't trigger rollback, just continue
|
|
567
644
|
continue;
|
|
568
645
|
}
|
|
@@ -574,7 +651,7 @@ class FeatureExecutor {
|
|
|
574
651
|
feature_id: this.state.feature_id,
|
|
575
652
|
success: rollbackResult.success,
|
|
576
653
|
rolled_back_steps: rollbackResult.rolled_back_steps,
|
|
577
|
-
failed_rollbacks: (
|
|
654
|
+
failed_rollbacks: (_k = (_j = rollbackResult.failed_steps) === null || _j === void 0 ? void 0 : _j.length) !== null && _k !== void 0 ? _k : 0,
|
|
578
655
|
});
|
|
579
656
|
// Persist failed feature result
|
|
580
657
|
await this.persistExecutionResult(types_1.LogEventStatus.FAIL, undefined, result.error);
|
|
@@ -585,7 +662,7 @@ class FeatureExecutor {
|
|
|
585
662
|
completed_steps: this.state.completed_steps,
|
|
586
663
|
step_timings: this.state.step_timings,
|
|
587
664
|
});
|
|
588
|
-
await ((
|
|
665
|
+
await ((_l = this.logService) === null || _l === void 0 ? void 0 : _l.publish());
|
|
589
666
|
if (this.graphConnectionUsed) {
|
|
590
667
|
await this.getGraphService().disconnect().catch(() => { });
|
|
591
668
|
await this.getProcessorService().disconnectBrokerConnections().catch(() => { });
|
|
@@ -619,6 +696,7 @@ class FeatureExecutor {
|
|
|
619
696
|
this.state.ended_at = Date.now();
|
|
620
697
|
// Determine output - use last step output or aggregate (resolves $ operators)
|
|
621
698
|
const output = await this.determineWorkflowOutput();
|
|
699
|
+
this.trace('execution.output.resolved', { output, completed_steps: this.state.completed_steps });
|
|
622
700
|
stepLog('Run finished (completed)', {
|
|
623
701
|
status: types_1.FeatureStatus.COMPLETED,
|
|
624
702
|
completed_steps: this.state.completed_steps,
|
|
@@ -634,7 +712,7 @@ class FeatureExecutor {
|
|
|
634
712
|
// Persist successful feature result
|
|
635
713
|
await this.persistExecutionResult(types_1.LogEventStatus.SUCCESS, output);
|
|
636
714
|
// Fire-and-forget log publish on success so we don't block on log upload
|
|
637
|
-
(
|
|
715
|
+
(_m = this.logService) === null || _m === void 0 ? void 0 : _m.publish().catch(() => { });
|
|
638
716
|
if (this.graphConnectionUsed) {
|
|
639
717
|
await this.getGraphService().disconnect().catch(() => { });
|
|
640
718
|
await this.getProcessorService().disconnectBrokerConnections().catch(() => { });
|
|
@@ -657,8 +735,9 @@ class FeatureExecutor {
|
|
|
657
735
|
this.state.status = types_1.FeatureStatus.FAILED;
|
|
658
736
|
this.state.ended_at = Date.now();
|
|
659
737
|
const details = formatErrorDetails(error);
|
|
660
|
-
const failedAt = (
|
|
661
|
-
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 });
|
|
662
741
|
if (details.stack) {
|
|
663
742
|
debugLog('[FeatureExecutor] execute FAILED stack', details.stack);
|
|
664
743
|
}
|
|
@@ -668,7 +747,7 @@ class FeatureExecutor {
|
|
|
668
747
|
: `Failed at ${failedAt}: ${details.message}`;
|
|
669
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 })));
|
|
670
749
|
await this.persistExecutionResult(types_1.LogEventStatus.FAIL, undefined, errorSummary);
|
|
671
|
-
await ((
|
|
750
|
+
await ((_p = this.logService) === null || _p === void 0 ? void 0 : _p.publish());
|
|
672
751
|
if (this.graphConnectionUsed) {
|
|
673
752
|
await this.getGraphService().disconnect().catch(() => { });
|
|
674
753
|
await this.getProcessorService().disconnectBrokerConnections().catch(() => { });
|
|
@@ -701,12 +780,14 @@ class FeatureExecutor {
|
|
|
701
780
|
});
|
|
702
781
|
let resolvedInput = {};
|
|
703
782
|
try {
|
|
783
|
+
this.trace('step.input.supplied', { step_tag: step.tag, step_type: step.type, payload: step.input || {} });
|
|
704
784
|
// Resolve input with data references and all $ operators
|
|
705
785
|
resolvedInput = (await this.resolveInput(step.input || {}));
|
|
786
|
+
this.trace('step.input.resolved', { step_tag: step.tag, step_type: step.type, payload: resolvedInput });
|
|
706
787
|
debugLog('[FeatureExecutor] executeStep input', {
|
|
707
788
|
feature_id: this.state.feature_id,
|
|
708
789
|
step_tag: step.tag,
|
|
709
|
-
input: resolvedInput,
|
|
790
|
+
input: sanitizeForLog(resolvedInput),
|
|
710
791
|
});
|
|
711
792
|
let output;
|
|
712
793
|
// Route steps to dedicated services; only action and notification use ProcessorService.
|
|
@@ -733,6 +814,9 @@ class FeatureExecutor {
|
|
|
733
814
|
case types_1.FeatureStepType.VECTOR:
|
|
734
815
|
output = await this.executeVectorStep(step, resolvedInput);
|
|
735
816
|
break;
|
|
817
|
+
case types_1.FeatureStepType.FUNCTION:
|
|
818
|
+
output = await this.executeFunctionStep(step, resolvedInput);
|
|
819
|
+
break;
|
|
736
820
|
case types_1.FeatureStepType.QUOTA:
|
|
737
821
|
output = await this.executeQuotaStep(step, resolvedInput);
|
|
738
822
|
break;
|
|
@@ -774,15 +858,16 @@ class FeatureExecutor {
|
|
|
774
858
|
}
|
|
775
859
|
}
|
|
776
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 });
|
|
777
862
|
debugLog('[FeatureExecutor] executeStep output', {
|
|
778
863
|
feature_id: this.state.feature_id,
|
|
779
864
|
step_tag: step.tag,
|
|
780
|
-
output,
|
|
865
|
+
output: sanitizeForLog(output),
|
|
781
866
|
durationMs: duration,
|
|
782
867
|
});
|
|
783
868
|
return {
|
|
784
869
|
success: true,
|
|
785
|
-
input: resolvedInput,
|
|
870
|
+
input: sanitizeForLog(resolvedInput),
|
|
786
871
|
output,
|
|
787
872
|
duration,
|
|
788
873
|
};
|
|
@@ -794,7 +879,14 @@ class FeatureExecutor {
|
|
|
794
879
|
const stepErrorMsg = details.reason != null
|
|
795
880
|
? (details.status != null ? `${details.reason} (HTTP ${details.status})` : details.reason)
|
|
796
881
|
: (details.status != null ? `${details.message} (HTTP ${details.status})` : details.message);
|
|
797
|
-
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
|
+
});
|
|
798
890
|
return {
|
|
799
891
|
success: false,
|
|
800
892
|
input: resolvedInput,
|
|
@@ -811,9 +903,10 @@ class FeatureExecutor {
|
|
|
811
903
|
debugLog('[FeatureExecutor] executeActionStep', { feature_id: this.state.feature_id, step_tag: step.tag, app: step.app });
|
|
812
904
|
// Step that only returns (no component call): no app → passthrough, output = resolved input
|
|
813
905
|
if (!step.app) {
|
|
906
|
+
this.trace('action.passthrough', { step_tag: step.tag, payload: input });
|
|
814
907
|
return input;
|
|
815
908
|
}
|
|
816
|
-
|
|
909
|
+
const payload = {
|
|
817
910
|
product: this.state.product,
|
|
818
911
|
env: this.state.env,
|
|
819
912
|
app: step.app,
|
|
@@ -821,25 +914,30 @@ class FeatureExecutor {
|
|
|
821
914
|
input: input,
|
|
822
915
|
retries: ((_a = step.options) === null || _a === void 0 ? void 0 : _a.retries) || 0,
|
|
823
916
|
cache: (_b = step.options) === null || _b === void 0 ? void 0 : _b.cache,
|
|
917
|
+
session: this.inheritedSession,
|
|
824
918
|
preloadedBootstrap: this.stepBootstrapCache.get(step.tag),
|
|
825
|
-
}
|
|
919
|
+
};
|
|
920
|
+
this.trace('action.request.sent', { step_tag: step.tag, payload });
|
|
921
|
+
return this.getProcessorService().processAction(payload);
|
|
826
922
|
}
|
|
827
923
|
/**
|
|
828
924
|
* Execute a database step: use query/insert/update/delete/upsert for DB operations, execute() for named actions.
|
|
829
925
|
*/
|
|
830
926
|
async executeDatabaseStep(step, input) {
|
|
927
|
+
var _a;
|
|
831
928
|
const database = step.database;
|
|
832
929
|
const product = this.state.product;
|
|
833
930
|
const env = this.state.env;
|
|
834
931
|
const event = (step.event || '').toLowerCase();
|
|
835
932
|
const db = this.getDatabaseService();
|
|
836
|
-
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 });
|
|
837
934
|
debugLog('[FeatureExecutor] executeDatabaseStep', {
|
|
838
935
|
feature_id: this.state.feature_id,
|
|
839
936
|
step_tag: step.tag,
|
|
840
937
|
database,
|
|
841
938
|
event,
|
|
842
939
|
});
|
|
940
|
+
this.trace('database.request.sent', { step_tag: step.tag, event, payload: opts });
|
|
843
941
|
switch (event) {
|
|
844
942
|
case 'query':
|
|
845
943
|
return db.query(opts);
|
|
@@ -858,6 +956,7 @@ class FeatureExecutor {
|
|
|
858
956
|
database,
|
|
859
957
|
action: step.event,
|
|
860
958
|
input: input,
|
|
959
|
+
session: this.inheritedSession,
|
|
861
960
|
});
|
|
862
961
|
}
|
|
863
962
|
}
|
|
@@ -868,14 +967,17 @@ class FeatureExecutor {
|
|
|
868
967
|
var _a;
|
|
869
968
|
const event = `${step.notification}:${step.event}`;
|
|
870
969
|
debugLog('[FeatureExecutor] executeNotificationStep', { feature_id: this.state.feature_id, step_tag: step.tag, event });
|
|
871
|
-
|
|
970
|
+
const payload = {
|
|
872
971
|
product: this.state.product,
|
|
873
972
|
env: this.state.env,
|
|
874
973
|
event,
|
|
875
974
|
input: input,
|
|
876
975
|
retries: ((_a = step.options) === null || _a === void 0 ? void 0 : _a.retries) || 0,
|
|
976
|
+
session: this.inheritedSession,
|
|
877
977
|
preloadedBootstrap: this.stepBootstrapCache.get(step.tag),
|
|
878
|
-
}
|
|
978
|
+
};
|
|
979
|
+
this.trace('notification.request.sent', { step_tag: step.tag, payload });
|
|
980
|
+
return this.getProcessorService().processNotification(payload);
|
|
879
981
|
}
|
|
880
982
|
/**
|
|
881
983
|
* Execute a storage step using StorageService (upload, download, or delete by input shape).
|
|
@@ -885,9 +987,10 @@ class FeatureExecutor {
|
|
|
885
987
|
const product = this.state.product;
|
|
886
988
|
const env = this.state.env;
|
|
887
989
|
const storage = step.storage;
|
|
888
|
-
const opts = { product, env, storage };
|
|
990
|
+
const opts = { product, env, storage, session: this.inheritedSession };
|
|
889
991
|
debugLog('[FeatureExecutor] executeStorageStep', { feature_id: this.state.feature_id, step_tag: step.tag, storage, event: step.event });
|
|
890
992
|
const inp = input;
|
|
993
|
+
this.trace('storage.request.sent', { step_tag: step.tag, event: step.event, payload: Object.assign(Object.assign({}, opts), inp) });
|
|
891
994
|
if (inp.buffer != null && inp.fileName != null) {
|
|
892
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 }));
|
|
893
996
|
}
|
|
@@ -904,12 +1007,15 @@ class FeatureExecutor {
|
|
|
904
1007
|
const event = `${step.broker}:${step.event}`;
|
|
905
1008
|
const message = (input && input.message != null) ? input.message : (input || {});
|
|
906
1009
|
debugLog('[FeatureExecutor] executeProduceStep', { feature_id: this.state.feature_id, step_tag: step.tag, event });
|
|
907
|
-
|
|
1010
|
+
const payload = {
|
|
908
1011
|
product: this.state.product,
|
|
909
1012
|
env: this.state.env,
|
|
910
1013
|
event,
|
|
911
1014
|
message: message,
|
|
912
|
-
|
|
1015
|
+
session: this.inheritedBrokerSession(),
|
|
1016
|
+
};
|
|
1017
|
+
this.trace('event.request.sent', { step_tag: step.tag, payload });
|
|
1018
|
+
return this.getBrokersService().publish(payload);
|
|
913
1019
|
}
|
|
914
1020
|
/**
|
|
915
1021
|
* Execute a graph step
|
|
@@ -920,6 +1026,7 @@ class FeatureExecutor {
|
|
|
920
1026
|
const graphTag = step.graph;
|
|
921
1027
|
const action = step.event;
|
|
922
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 });
|
|
923
1030
|
this.graphConnectionUsed = true;
|
|
924
1031
|
await this.getGraphService().connect({
|
|
925
1032
|
env: this.state.env,
|
|
@@ -933,6 +1040,7 @@ class FeatureExecutor {
|
|
|
933
1040
|
const result = await this.getGraphService().createNode({
|
|
934
1041
|
labels: input.labels,
|
|
935
1042
|
properties: input.properties,
|
|
1043
|
+
session: this.inheritedSession,
|
|
936
1044
|
});
|
|
937
1045
|
return result;
|
|
938
1046
|
}
|
|
@@ -940,6 +1048,7 @@ class FeatureExecutor {
|
|
|
940
1048
|
const result = await this.getGraphService().updateNode({
|
|
941
1049
|
id: input.id,
|
|
942
1050
|
properties: input.properties,
|
|
1051
|
+
session: this.inheritedSession,
|
|
943
1052
|
});
|
|
944
1053
|
return result;
|
|
945
1054
|
}
|
|
@@ -947,6 +1056,7 @@ class FeatureExecutor {
|
|
|
947
1056
|
const result = await this.getGraphService().deleteNode({
|
|
948
1057
|
id: input.id,
|
|
949
1058
|
detach: input.detach,
|
|
1059
|
+
session: this.inheritedSession,
|
|
950
1060
|
});
|
|
951
1061
|
return result;
|
|
952
1062
|
}
|
|
@@ -956,17 +1066,19 @@ class FeatureExecutor {
|
|
|
956
1066
|
endNodeId: input.endNodeId || input.to,
|
|
957
1067
|
type: input.type,
|
|
958
1068
|
properties: input.properties,
|
|
1069
|
+
session: this.inheritedSession,
|
|
959
1070
|
});
|
|
960
1071
|
return result;
|
|
961
1072
|
}
|
|
962
1073
|
case 'deleteRelationship': {
|
|
963
1074
|
const result = await this.getGraphService().deleteRelationship({
|
|
964
1075
|
id: input.id,
|
|
1076
|
+
session: this.inheritedSession,
|
|
965
1077
|
});
|
|
966
1078
|
return result;
|
|
967
1079
|
}
|
|
968
1080
|
case 'query': {
|
|
969
|
-
const result = await this.getGraphService().query(input.query, input.params);
|
|
1081
|
+
const result = await this.getGraphService().query(input.query, input.params, undefined, this.inheritedSession);
|
|
970
1082
|
return result;
|
|
971
1083
|
}
|
|
972
1084
|
case 'findNodes': {
|
|
@@ -975,6 +1087,7 @@ class FeatureExecutor {
|
|
|
975
1087
|
where: input.where,
|
|
976
1088
|
limit: input.limit,
|
|
977
1089
|
skip: input.skip,
|
|
1090
|
+
session: this.inheritedSession,
|
|
978
1091
|
});
|
|
979
1092
|
return result;
|
|
980
1093
|
}
|
|
@@ -984,6 +1097,7 @@ class FeatureExecutor {
|
|
|
984
1097
|
relationshipTypes: input.relationshipTypes,
|
|
985
1098
|
direction: input.direction,
|
|
986
1099
|
maxDepth: input.maxDepth,
|
|
1100
|
+
session: this.inheritedSession,
|
|
987
1101
|
});
|
|
988
1102
|
return result;
|
|
989
1103
|
}
|
|
@@ -995,6 +1109,7 @@ class FeatureExecutor {
|
|
|
995
1109
|
graph: graphTag,
|
|
996
1110
|
action,
|
|
997
1111
|
input,
|
|
1112
|
+
session: this.inheritedSession,
|
|
998
1113
|
});
|
|
999
1114
|
return result;
|
|
1000
1115
|
}
|
|
@@ -1008,7 +1123,7 @@ class FeatureExecutor {
|
|
|
1008
1123
|
* Execute a vector step (query, upsert, deleteVectors, or custom action via execute).
|
|
1009
1124
|
*/
|
|
1010
1125
|
async executeVectorStep(step, input) {
|
|
1011
|
-
var _a;
|
|
1126
|
+
var _a, _b, _c, _d, _e;
|
|
1012
1127
|
const vectorTag = step.vector;
|
|
1013
1128
|
if (!vectorTag) {
|
|
1014
1129
|
throw new Error(`Vector step "${step.tag}" has no vector tag`);
|
|
@@ -1023,21 +1138,22 @@ class FeatureExecutor {
|
|
|
1023
1138
|
vector: vectorTag,
|
|
1024
1139
|
event,
|
|
1025
1140
|
});
|
|
1141
|
+
this.trace('vector.request.preparing', { step_tag: step.tag, event, vector: vectorTag, payload: input });
|
|
1026
1142
|
switch (event) {
|
|
1027
1143
|
case 'query': {
|
|
1028
|
-
const result = await svc.query(Object.assign({ product,
|
|
1029
|
-
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 }));
|
|
1030
1146
|
return result;
|
|
1031
1147
|
}
|
|
1032
1148
|
case 'upsert': {
|
|
1033
|
-
const result = await svc.upsert(Object.assign({ product,
|
|
1034
|
-
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 }));
|
|
1035
1151
|
return result;
|
|
1036
1152
|
}
|
|
1037
1153
|
case 'delete':
|
|
1038
1154
|
case 'deletevectors': {
|
|
1039
|
-
const result = await svc.deleteVectors(Object.assign({ product,
|
|
1040
|
-
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 }));
|
|
1041
1157
|
return result;
|
|
1042
1158
|
}
|
|
1043
1159
|
default: {
|
|
@@ -1048,9 +1164,10 @@ class FeatureExecutor {
|
|
|
1048
1164
|
vector: vectorTag,
|
|
1049
1165
|
action: step.event,
|
|
1050
1166
|
input: input,
|
|
1167
|
+
session: this.inheritedSession,
|
|
1051
1168
|
});
|
|
1052
|
-
const op = (
|
|
1053
|
-
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 });
|
|
1054
1171
|
if (op === 'query' || !op) {
|
|
1055
1172
|
return svc.query(opts);
|
|
1056
1173
|
}
|
|
@@ -1064,6 +1181,46 @@ class FeatureExecutor {
|
|
|
1064
1181
|
}
|
|
1065
1182
|
}
|
|
1066
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
|
+
}
|
|
1067
1224
|
/**
|
|
1068
1225
|
* Execute a quota step
|
|
1069
1226
|
*/
|
|
@@ -1074,6 +1231,7 @@ class FeatureExecutor {
|
|
|
1074
1231
|
env: this.state.env,
|
|
1075
1232
|
tag: step.quota,
|
|
1076
1233
|
input,
|
|
1234
|
+
session: this.inheritedSession,
|
|
1077
1235
|
});
|
|
1078
1236
|
}
|
|
1079
1237
|
/**
|
|
@@ -1086,6 +1244,7 @@ class FeatureExecutor {
|
|
|
1086
1244
|
env: this.state.env,
|
|
1087
1245
|
tag: step.fallback,
|
|
1088
1246
|
input,
|
|
1247
|
+
session: this.inheritedSession,
|
|
1089
1248
|
});
|
|
1090
1249
|
}
|
|
1091
1250
|
/**
|
|
@@ -1112,7 +1271,8 @@ class FeatureExecutor {
|
|
|
1112
1271
|
env: this.state.env,
|
|
1113
1272
|
tag: childTag,
|
|
1114
1273
|
input,
|
|
1115
|
-
|
|
1274
|
+
session: this.inheritedSession,
|
|
1275
|
+
}, this._privateKey, this.sessionLogFields, this.productBuilder);
|
|
1116
1276
|
const result = await childExecutor.execute();
|
|
1117
1277
|
debugLog('[FeatureExecutor] executeChildWorkflowStep result', {
|
|
1118
1278
|
feature_id: this.state.feature_id,
|
|
@@ -1387,12 +1547,13 @@ class FeatureExecutor {
|
|
|
1387
1547
|
* Execute a rollback handler
|
|
1388
1548
|
*/
|
|
1389
1549
|
async executeRollbackHandler(rollback, stepOutput) {
|
|
1390
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
1550
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
1391
1551
|
if (!rollback)
|
|
1392
1552
|
return;
|
|
1393
1553
|
debugLog('[FeatureExecutor] executeRollbackHandler', { feature_id: this.state.feature_id, rollback_type: rollback.type });
|
|
1394
1554
|
// Resolve rollback input, including step output references
|
|
1395
1555
|
const resolvedInput = await this.resolveInput(rollback.input || {}, stepOutput);
|
|
1556
|
+
this.trace('rollback.input.resolved', { rollback_type: rollback.type, payload: resolvedInput });
|
|
1396
1557
|
switch (rollback.type) {
|
|
1397
1558
|
case types_1.FeatureStepType.ACTION:
|
|
1398
1559
|
await this.getProcessorService().processAction({
|
|
@@ -1402,6 +1563,7 @@ class FeatureExecutor {
|
|
|
1402
1563
|
action: rollback.event,
|
|
1403
1564
|
input: resolvedInput,
|
|
1404
1565
|
retries: (_a = rollback.retries) !== null && _a !== void 0 ? _a : 0,
|
|
1566
|
+
session: this.inheritedSession,
|
|
1405
1567
|
});
|
|
1406
1568
|
break;
|
|
1407
1569
|
case types_1.FeatureStepType.DATABASE_ACTION: {
|
|
@@ -1410,7 +1572,7 @@ class FeatureExecutor {
|
|
|
1410
1572
|
const env = this.state.env;
|
|
1411
1573
|
const database = rollback.database;
|
|
1412
1574
|
const event = ((_b = rollback.event) !== null && _b !== void 0 ? _b : '').toLowerCase();
|
|
1413
|
-
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 });
|
|
1414
1576
|
if (event === 'query')
|
|
1415
1577
|
await db.query(opts);
|
|
1416
1578
|
else if (event === 'insert')
|
|
@@ -1428,6 +1590,7 @@ class FeatureExecutor {
|
|
|
1428
1590
|
database,
|
|
1429
1591
|
action: rollback.event,
|
|
1430
1592
|
input: resolvedInput,
|
|
1593
|
+
session: this.inheritedSession,
|
|
1431
1594
|
});
|
|
1432
1595
|
break;
|
|
1433
1596
|
}
|
|
@@ -1438,14 +1601,15 @@ class FeatureExecutor {
|
|
|
1438
1601
|
env: this.state.env,
|
|
1439
1602
|
event: notifEvent,
|
|
1440
1603
|
input: resolvedInput,
|
|
1441
|
-
retries: (
|
|
1604
|
+
retries: (_d = rollback.retries) !== null && _d !== void 0 ? _d : 0,
|
|
1605
|
+
session: this.inheritedSession,
|
|
1442
1606
|
});
|
|
1443
1607
|
break;
|
|
1444
1608
|
case types_1.FeatureStepType.STORAGE: {
|
|
1445
1609
|
const product = this.state.product;
|
|
1446
1610
|
const env = this.state.env;
|
|
1447
1611
|
const storage = rollback.storage;
|
|
1448
|
-
const opts = { product, env, storage };
|
|
1612
|
+
const opts = { product, env, storage, session: this.inheritedSession };
|
|
1449
1613
|
const inp = resolvedInput;
|
|
1450
1614
|
if (inp.buffer != null && inp.fileName != null) {
|
|
1451
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 }));
|
|
@@ -1454,7 +1618,7 @@ class FeatureExecutor {
|
|
|
1454
1618
|
await this.getStorageService().delete(Object.assign(Object.assign({}, opts), { fileName: String(inp.file_key) }));
|
|
1455
1619
|
}
|
|
1456
1620
|
else {
|
|
1457
|
-
await this.getStorageService().download(Object.assign(Object.assign({}, opts), { fileName: String((
|
|
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 : '') }));
|
|
1458
1622
|
}
|
|
1459
1623
|
break;
|
|
1460
1624
|
}
|
|
@@ -1463,16 +1627,16 @@ class FeatureExecutor {
|
|
|
1463
1627
|
const env = this.state.env;
|
|
1464
1628
|
const vectorTag = rollback.vector;
|
|
1465
1629
|
const inp = resolvedInput;
|
|
1466
|
-
const event = ((
|
|
1630
|
+
const event = ((_g = rollback.event) !== null && _g !== void 0 ? _g : '').toLowerCase();
|
|
1467
1631
|
const svc = this.getVectorService();
|
|
1468
1632
|
if (event === 'query') {
|
|
1469
|
-
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 }));
|
|
1470
1634
|
}
|
|
1471
1635
|
else if (event === 'upsert') {
|
|
1472
|
-
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 }));
|
|
1473
1637
|
}
|
|
1474
1638
|
else if (event === 'delete' || event === 'deletevectors') {
|
|
1475
|
-
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 }));
|
|
1476
1640
|
}
|
|
1477
1641
|
else {
|
|
1478
1642
|
const resolved = await svc.actions.resolve({
|
|
@@ -1481,9 +1645,10 @@ class FeatureExecutor {
|
|
|
1481
1645
|
vector: vectorTag,
|
|
1482
1646
|
action: rollback.event,
|
|
1483
1647
|
input: inp,
|
|
1648
|
+
session: this.inheritedSession,
|
|
1484
1649
|
});
|
|
1485
|
-
const op = (
|
|
1486
|
-
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 });
|
|
1487
1652
|
if (op === 'upsert')
|
|
1488
1653
|
await svc.upsert(opts);
|
|
1489
1654
|
else if (op === 'delete' || op === 'deleteVectors')
|
|
@@ -1501,6 +1666,7 @@ class FeatureExecutor {
|
|
|
1501
1666
|
env: this.state.env,
|
|
1502
1667
|
event: pubEvent,
|
|
1503
1668
|
input: resolvedInput,
|
|
1669
|
+
session: this.inheritedSession,
|
|
1504
1670
|
});
|
|
1505
1671
|
break;
|
|
1506
1672
|
}
|
|
@@ -1830,6 +1996,7 @@ class FeatureExecutor {
|
|
|
1830
1996
|
env_slug: env,
|
|
1831
1997
|
steps: workflowSteps,
|
|
1832
1998
|
});
|
|
1999
|
+
this.trace('bootstrap.response.fetched', { requested_steps: workflowSteps, payload: bootstraps });
|
|
1833
2000
|
stepLog('Bootstrap feature API response', {
|
|
1834
2001
|
received_keys: Object.keys(bootstraps),
|
|
1835
2002
|
keys_count: Object.keys(bootstraps).length,
|
|
@@ -1853,6 +2020,7 @@ class FeatureExecutor {
|
|
|
1853
2020
|
var _a;
|
|
1854
2021
|
try {
|
|
1855
2022
|
const broker = await this.productBuilder.fetchMessageBroker(tag);
|
|
2023
|
+
this.trace('resource.fetched', { resource_type: 'event', resource_tag: tag, payload: broker });
|
|
1856
2024
|
return { tag, found: !!broker };
|
|
1857
2025
|
}
|
|
1858
2026
|
catch (e) {
|
|
@@ -1874,6 +2042,7 @@ class FeatureExecutor {
|
|
|
1874
2042
|
var _a;
|
|
1875
2043
|
try {
|
|
1876
2044
|
const db = await this.productBuilder.fetchDatabase(tag);
|
|
2045
|
+
this.trace('resource.fetched', { resource_type: 'database', resource_tag: tag, payload: db });
|
|
1877
2046
|
return { tag, found: !!db };
|
|
1878
2047
|
}
|
|
1879
2048
|
catch (e) {
|
|
@@ -1895,6 +2064,7 @@ class FeatureExecutor {
|
|
|
1895
2064
|
var _a;
|
|
1896
2065
|
try {
|
|
1897
2066
|
const graph = await this.productBuilder.fetchGraph(tag);
|
|
2067
|
+
this.trace('resource.fetched', { resource_type: 'graph', resource_tag: tag, payload: graph });
|
|
1898
2068
|
return { tag, found: !!graph };
|
|
1899
2069
|
}
|
|
1900
2070
|
catch (e) {
|
|
@@ -1915,6 +2085,7 @@ class FeatureExecutor {
|
|
|
1915
2085
|
var _a;
|
|
1916
2086
|
try {
|
|
1917
2087
|
const vec = await this.productBuilder.fetchVector(tag);
|
|
2088
|
+
this.trace('resource.fetched', { resource_type: 'vector', resource_tag: tag, payload: vec });
|
|
1918
2089
|
return { tag, found: !!vec };
|
|
1919
2090
|
}
|
|
1920
2091
|
catch (e) {
|
|
@@ -1936,6 +2107,7 @@ class FeatureExecutor {
|
|
|
1936
2107
|
var _a;
|
|
1937
2108
|
try {
|
|
1938
2109
|
const quota = await this.productBuilder.fetchQuota(tag);
|
|
2110
|
+
this.trace('resource.fetched', { resource_type: 'quota', resource_tag: tag, payload: quota });
|
|
1939
2111
|
return { tag, found: !!quota };
|
|
1940
2112
|
}
|
|
1941
2113
|
catch (e) {
|