bulltrackers-module 1.0.731 → 1.0.733

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 (52) hide show
  1. package/functions/orchestrator/index.js +19 -17
  2. package/index.js +8 -29
  3. package/package.json +6 -5
  4. package/functions/computation-system/WorkflowOrchestrator.js +0 -213
  5. package/functions/computation-system/config/monitoring_config.js +0 -31
  6. package/functions/computation-system/config/validation_overrides.js +0 -10
  7. package/functions/computation-system/context/ContextFactory.js +0 -132
  8. package/functions/computation-system/context/ManifestBuilder.js +0 -379
  9. package/functions/computation-system/data/AvailabilityChecker.js +0 -236
  10. package/functions/computation-system/data/CachedDataLoader.js +0 -325
  11. package/functions/computation-system/data/DependencyFetcher.js +0 -455
  12. package/functions/computation-system/executors/MetaExecutor.js +0 -279
  13. package/functions/computation-system/executors/PriceBatchExecutor.js +0 -108
  14. package/functions/computation-system/executors/StandardExecutor.js +0 -465
  15. package/functions/computation-system/helpers/computation_dispatcher.js +0 -750
  16. package/functions/computation-system/helpers/computation_worker.js +0 -375
  17. package/functions/computation-system/helpers/monitor.js +0 -64
  18. package/functions/computation-system/helpers/on_demand_helpers.js +0 -154
  19. package/functions/computation-system/layers/extractors.js +0 -1097
  20. package/functions/computation-system/layers/index.js +0 -40
  21. package/functions/computation-system/layers/mathematics.js +0 -522
  22. package/functions/computation-system/layers/profiling.js +0 -537
  23. package/functions/computation-system/layers/validators.js +0 -170
  24. package/functions/computation-system/legacy/AvailabilityCheckerOld.js +0 -388
  25. package/functions/computation-system/legacy/CachedDataLoaderOld.js +0 -357
  26. package/functions/computation-system/legacy/DependencyFetcherOld.js +0 -478
  27. package/functions/computation-system/legacy/MetaExecutorold.js +0 -364
  28. package/functions/computation-system/legacy/StandardExecutorold.js +0 -476
  29. package/functions/computation-system/legacy/computation_dispatcherold.js +0 -944
  30. package/functions/computation-system/logger/logger.js +0 -297
  31. package/functions/computation-system/persistence/ContractValidator.js +0 -81
  32. package/functions/computation-system/persistence/FirestoreUtils.js +0 -56
  33. package/functions/computation-system/persistence/ResultCommitter.js +0 -283
  34. package/functions/computation-system/persistence/ResultsValidator.js +0 -130
  35. package/functions/computation-system/persistence/RunRecorder.js +0 -142
  36. package/functions/computation-system/persistence/StatusRepository.js +0 -52
  37. package/functions/computation-system/reporter_epoch.js +0 -6
  38. package/functions/computation-system/scripts/UpdateContracts.js +0 -128
  39. package/functions/computation-system/services/SnapshotService.js +0 -148
  40. package/functions/computation-system/simulation/Fabricator.js +0 -285
  41. package/functions/computation-system/simulation/SeededRandom.js +0 -41
  42. package/functions/computation-system/simulation/SimRunner.js +0 -51
  43. package/functions/computation-system/system_epoch.js +0 -2
  44. package/functions/computation-system/tools/BuildReporter.js +0 -531
  45. package/functions/computation-system/tools/ContractDiscoverer.js +0 -144
  46. package/functions/computation-system/tools/DeploymentValidator.js +0 -536
  47. package/functions/computation-system/tools/FinalSweepReporter.js +0 -322
  48. package/functions/computation-system/topology/HashManager.js +0 -55
  49. package/functions/computation-system/topology/ManifestLoader.js +0 -47
  50. package/functions/computation-system/utils/data_loader.js +0 -597
  51. package/functions/computation-system/utils/schema_capture.js +0 -121
  52. package/functions/computation-system/utils/utils.js +0 -188
@@ -1,465 +0,0 @@
1
- /**
2
- * @fileoverview Executor for "Standard" (User-Level) calculations.
3
- * REFACTORED: Hoisted data loading, centralized Series/Root logic.
4
- * UPDATED: Calls getResult() on computations to trigger summary logging.
5
- * FIXED: Removed redundant shard index increment that caused shard gaps (0, 2, 4...).
6
- */
7
- const { normalizeName, getEarliestDataDates } = require('../utils/utils');
8
- const { streamPortfolioData, streamHistoryData, getPortfolioPartRefs, getHistoryPartRefs } = require('../utils/data_loader');
9
- const { CachedDataLoader } = require('../data/CachedDataLoader');
10
- const { ContextFactory } = require('../context/ContextFactory');
11
- const { commitResults } = require('../persistence/ResultCommitter');
12
- const { fetchResultSeries } = require('../data/DependencyFetcher');
13
- const { getManifest } = require('../topology/ManifestLoader');
14
- const mathLayer = require('../layers/index');
15
- const { performance } = require('perf_hooks');
16
- const v8 = require('v8');
17
-
18
- // Helper to get calculations - prefer config.calculations, fallback to direct require
19
- function getCalculations(config) {
20
- if (config && config.calculations) return config.calculations;
21
- try { return require('aiden-shared-calculations-unified').calculations; }
22
- catch (e) { return {}; }
23
- }
24
-
25
- class StandardExecutor {
26
-
27
- // =========================================================================
28
- // ENTRY POINT
29
- // =========================================================================
30
- static async run(date, calcs, passName, config, deps, rootData, fetchedDeps, previousFetchedDeps, skipStatusWrite = false) {
31
- const dStr = date.toISOString().slice(0, 10);
32
- const { logger } = deps;
33
-
34
- // 1. Setup Scope (User Types & Target CID)
35
- const requiredUserTypes = new Set(calcs.map(c => (c.userType || 'ALL').toUpperCase()));
36
- const userTypeArray = requiredUserTypes.has('ALL') ? null : Array.from(requiredUserTypes);
37
-
38
- const targetCid = calcs.find(c => c.targetCid)?.targetCid || calcs.find(c => c.manifest?.targetCid)?.manifest?.targetCid;
39
- if (targetCid) logger.log('INFO', `[StandardExecutor] 🎯 Targeted Mode: CID ${targetCid}`);
40
-
41
- // 2. Prepare History Context (Refs)
42
- const fullRoot = { ...rootData };
43
- if (calcs.some(c => c.isHistorical)) {
44
- const prevStr = new Date(date.getTime() - 86400000).toISOString().slice(0, 10);
45
- let yRefs = await getPortfolioPartRefs(config, deps, prevStr, userTypeArray);
46
-
47
- if (targetCid && yRefs) {
48
- yRefs = yRefs.filter(r => !r.cid || String(r.cid) === String(targetCid));
49
- }
50
- fullRoot.yesterdayPortfolioRefs = yRefs;
51
- }
52
-
53
- // 3. Initialize Instances
54
- const state = {};
55
- for (const c of calcs) {
56
- try {
57
- const inst = new c.class();
58
- inst.manifest = c;
59
- inst.results = {};
60
- state[normalizeName(c.name)] = inst;
61
- } catch (e) { logger.log('WARN', `Failed to init ${c.name}`); }
62
- }
63
-
64
- return await StandardExecutor.streamAndProcess(
65
- dStr, state, passName, config, deps, fullRoot,
66
- rootData.portfolioRefs, rootData.historyRefs,
67
- fetchedDeps, previousFetchedDeps, skipStatusWrite,
68
- userTypeArray, targetCid
69
- );
70
- }
71
-
72
- // =========================================================================
73
- // STREAMING LOOP
74
- // =========================================================================
75
- static async streamAndProcess(dateStr, state, passName, config, deps, rootData, portfolioRefs, historyRefs, fetchedDeps, previousFetchedDeps, skipStatusWrite, requiredUserTypes = null, targetCid = null) {
76
- const { logger } = deps;
77
- const calcs = Object.values(state).filter(c => c?.manifest);
78
- const streamingCalcs = calcs.filter(c => c.manifest.rootDataDependencies.includes('portfolio') || c.manifest.rootDataDependencies.includes('history'));
79
-
80
- if (!streamingCalcs.length) return { successUpdates: {}, failureReport: [] };
81
-
82
- const loader = new CachedDataLoader(config, deps);
83
-
84
- // --- 1. PRE-LOAD GLOBAL DATA (Hoisted) ---
85
- const startSetup = performance.now();
86
-
87
- const [
88
- globalRoots,
89
- seriesData,
90
- earliestDates
91
- ] = await Promise.all([
92
- loadGlobalRoots(loader, dateStr, streamingCalcs, deps),
93
- loadSeriesData(loader, dateStr, streamingCalcs, config, deps),
94
- streamingCalcs.some(c => c.manifest.requiresEarliestDataDate) ? getEarliestDataDates(config, deps) : null
95
- ]);
96
-
97
- const setupDuration = performance.now() - startSetup;
98
-
99
- // --- 2. PREPARE REFS & STATS ---
100
- let effPortRefs = portfolioRefs || await getPortfolioPartRefs(config, deps, dateStr, requiredUserTypes);
101
- let effHistRefs = historyRefs;
102
-
103
- if (targetCid) effPortRefs = effPortRefs?.filter(r => !r.cid || String(r.cid) === String(targetCid));
104
-
105
- const needsHistory = streamingCalcs.some(c => c.manifest.rootDataDependencies.includes('history'));
106
- if (needsHistory) {
107
- effHistRefs = effHistRefs || await getHistoryPartRefs(config, deps, dateStr, requiredUserTypes);
108
- if (targetCid) effHistRefs = effHistRefs?.filter(r => !r.cid || String(r.cid) === String(targetCid));
109
- }
110
-
111
- const stats = {};
112
- const shardMap = {};
113
- calcs.forEach(c => {
114
- stats[normalizeName(c.manifest.name)] = {
115
- processedUsers: 0, skippedUsers: 0, timings: { setup: setupDuration, stream: 0, processing: 0 }
116
- };
117
- shardMap[normalizeName(c.manifest.name)] = 0;
118
- });
119
-
120
- // --- 3. STREAM EXECUTION ---
121
- const tP_iter = streamPortfolioData(config, deps, dateStr, effPortRefs, requiredUserTypes);
122
- const yP_iter = (streamingCalcs.some(c => c.manifest.isHistorical) && rootData.yesterdayPortfolioRefs)
123
- ? streamPortfolioData(config, deps, new Date(new Date(dateStr).getTime() - 86400000).toISOString().slice(0, 10), rootData.yesterdayPortfolioRefs)
124
- : null;
125
- const tH_iter = needsHistory ? streamHistoryData(config, deps, dateStr, effHistRefs, requiredUserTypes) : null;
126
-
127
- let yP_chunk = {}, tH_chunk = {};
128
- let usersSinceFlush = 0;
129
- let hasFlushed = false;
130
- const aggregatedSuccess = {};
131
- const aggregatedFailures = [];
132
-
133
- try {
134
- for await (const tP_chunk of tP_iter) {
135
- const t0 = performance.now();
136
- if (yP_iter) yP_chunk = (await yP_iter.next()).value || {};
137
- if (tH_iter) tH_chunk = (await tH_iter.next()).value || {};
138
- const tStream = performance.now() - t0;
139
-
140
- const t1 = performance.now();
141
-
142
- // Parallelize Calc Execution for this Chunk
143
- await Promise.all(streamingCalcs.map(calc =>
144
- StandardExecutor.executePerUser(
145
- calc, calc.manifest, dateStr, tP_chunk, yP_chunk, tH_chunk,
146
- fetchedDeps, previousFetchedDeps, config, deps,
147
- stats[normalizeName(calc.manifest.name)],
148
- earliestDates,
149
- seriesData,
150
- globalRoots // <--- PASSED DOWN
151
- )
152
- ));
153
-
154
- const tProc = performance.now() - t1;
155
- streamingCalcs.forEach(c => {
156
- const s = stats[normalizeName(c.manifest.name)];
157
- s.timings.stream += tStream;
158
- s.timings.processing += tProc;
159
- });
160
-
161
- usersSinceFlush += Object.keys(tP_chunk).length;
162
- const heap = v8.getHeapStatistics();
163
- if (usersSinceFlush >= 500 || (heap.used_heap_size / heap.heap_size_limit) > 0.7) {
164
- const res = await StandardExecutor.flushBuffer(state, dateStr, passName, config, deps, shardMap, stats, 'INTERMEDIATE', true, !hasFlushed);
165
- StandardExecutor.mergeReports(aggregatedSuccess, aggregatedFailures, res);
166
- hasFlushed = true;
167
- usersSinceFlush = 0;
168
- }
169
- }
170
- } finally {
171
- if (yP_iter?.return) await yP_iter.return();
172
- if (tH_iter?.return) await tH_iter.return();
173
- }
174
-
175
- const finalRes = await StandardExecutor.flushBuffer(state, dateStr, passName, config, deps, shardMap, stats, 'FINAL', skipStatusWrite, !hasFlushed);
176
- StandardExecutor.mergeReports(aggregatedSuccess, aggregatedFailures, finalRes);
177
-
178
- return { successUpdates: aggregatedSuccess, failureReport: aggregatedFailures };
179
- }
180
-
181
- // =========================================================================
182
- // PER-USER EXECUTION (Pure Logic)
183
- // =========================================================================
184
- static async executePerUser(calcInstance, metadata, dateStr, portfolioData, yesterdayPortfolioData, historyData, computedDeps, prevDeps, config, deps, stats, earliestDates, seriesData, globalRoots) {
185
- const { logger } = deps;
186
- const targetUserType = metadata.userType;
187
- const SCHEMAS = mathLayer.SCHEMAS;
188
-
189
- let success = 0, failures = 0;
190
-
191
- for (const [userId, todayPortfolio] of Object.entries(portfolioData)) {
192
- // 1. Filter User
193
- if (metadata.targetCid && String(userId) !== String(metadata.targetCid)) { stats.skippedUsers++; continue; }
194
-
195
- // 2. Determine Type
196
- let actualType = todayPortfolio._userType;
197
- if (!actualType) {
198
- const isRanked = globalRoots.rankings && globalRoots.rankings.some(r => String(r.CustomerId) === String(userId));
199
- actualType = isRanked ? 'POPULAR_INVESTOR' : (todayPortfolio.PublicPositions ? SCHEMAS.USER_TYPES.SPECULATOR : SCHEMAS.USER_TYPES.NORMAL);
200
- }
201
- if (targetUserType && targetUserType !== 'all' && targetUserType !== actualType) { stats.skippedUsers++; continue; }
202
-
203
- // 3. Resolve User Specifics from Global Data
204
- const userRank = globalRoots.rankings?.find(r => String(r.CustomerId) === String(userId)) || null;
205
- const userRankYest = globalRoots.rankingsYesterday?.find(r => String(r.CustomerId) === String(userId)) || null;
206
- const userVerify = globalRoots.verifications?.[userId] || null;
207
-
208
- let social = null;
209
- if (globalRoots.social) {
210
- // Use optional chaining to handle missing sub-objects (pi, signedIn, generic)
211
- social = (actualType === 'POPULAR_INVESTOR' ? globalRoots.social.pi?.[userId] :
212
- (actualType === 'SIGNED_IN_USER' ? globalRoots.social.signedIn?.[userId] : globalRoots.social.generic)) || {};
213
- }
214
-
215
- // 4. Build Context
216
- const context = ContextFactory.buildPerUserContext({
217
- todayPortfolio,
218
- yesterdayPortfolio: yesterdayPortfolioData?.[userId] || null,
219
- todayHistory: historyData?.[userId] || null,
220
- userId, userType: actualType, dateStr, metadata,
221
-
222
- // Injected Global Data
223
- mappings: globalRoots.mappings,
224
- piMasterList: globalRoots.piMasterList,
225
- insights: globalRoots.insights,
226
- socialData: social ? { today: social } : null,
227
-
228
- // Dependency Data
229
- computedDependencies: computedDeps,
230
- previousComputedDependencies: prevDeps,
231
- config, deps,
232
-
233
- // Specific Lookups
234
- verification: userVerify,
235
- rankings: userRank,
236
- yesterdayRankings: userRankYest,
237
-
238
- // Full Access (if needed by calc)
239
- allRankings: globalRoots.rankings,
240
- allRankingsYesterday: globalRoots.rankingsYesterday,
241
- allVerifications: globalRoots.verifications,
242
- ratings: globalRoots.ratings || {},
243
- pageViews: globalRoots.pageViews || {},
244
- watchlistMembership: globalRoots.watchlistMembership || {},
245
- alertHistory: globalRoots.alertHistory || {},
246
-
247
- seriesData
248
- });
249
-
250
- if (metadata.requiresEarliestDataDate && earliestDates) {
251
- if (!context.system) context.system = {};
252
- context.system.earliestHistoryDate = earliestDates.history;
253
- }
254
-
255
- try {
256
- await calcInstance.process(context);
257
- stats.processedUsers++;
258
- success++;
259
- } catch (e) {
260
- logger.log('WARN', `Calc ${metadata.name} failed for user ${userId}: ${e.message}`);
261
- failures++;
262
- }
263
- }
264
- return { success, failures };
265
- }
266
-
267
- // =========================================================================
268
- // HELPERS (Flush & Merge)
269
- // =========================================================================
270
- static async flushBuffer(state, dateStr, passName, config, deps, shardMap, stats, mode, skipStatus, isInitial) {
271
- const transformedState = {};
272
- const activeCalcs = [];
273
-
274
- for (const [name, inst] of Object.entries(state)) {
275
- // [FIX 1] Allow computations to finalize/log summary stats via getResult()
276
- let data;
277
- if (typeof inst.getResult === 'function') {
278
- data = await inst.getResult();
279
- } else {
280
- data = inst.results || {};
281
- }
282
-
283
- // Track active calculations (for debugging/logging only now)
284
- if (Object.keys(data).length > 0) {
285
- activeCalcs.push(name);
286
- }
287
-
288
- // Pivot user-date structure if needed
289
- const first = Object.keys(data)[0];
290
- if (first && data[first] && typeof data[first] === 'object' && /^\d{4}-\d{2}-\d{2}$/.test(Object.keys(data[first])[0])) {
291
- const pivoted = {};
292
- for (const [uid, dMap] of Object.entries(data)) {
293
- for (const [dKey, val] of Object.entries(dMap)) {
294
- if (!pivoted[dKey]) pivoted[dKey] = {};
295
- pivoted[dKey][uid] = val;
296
- }
297
- }
298
- data = pivoted;
299
- }
300
- transformedState[name] = { manifest: inst.manifest, getResult: async () => data, _executionStats: stats[name] };
301
- inst.results = {}; // Clear buffer
302
- }
303
-
304
- const res = await commitResults(transformedState, dateStr, passName, config, deps, skipStatus, { flushMode: mode, shardIndexes: shardMap, isInitialWrite: isInitial });
305
-
306
- // Update shardMap from result.
307
- // ResultCommitter now returns the CORRECT nextShardIndex (e.g. if it wrote shard_0, it returns 1).
308
- if (res.shardIndexes) Object.assign(shardMap, res.shardIndexes);
309
-
310
- return res;
311
- }
312
-
313
- static mergeReports(success, failure, result) {
314
- if (!result) return;
315
- if (result.failureReport) failure.push(...result.failureReport);
316
- for (const [name, update] of Object.entries(result.successUpdates)) {
317
- if (!success[name]) success[name] = update;
318
- else {
319
- const m = success[name].metrics;
320
- const u = update.metrics;
321
- m.storage.sizeBytes += u.storage.sizeBytes;
322
- m.storage.keys += u.storage.keys;
323
- m.storage.shardCount = Math.max(m.storage.shardCount, u.storage.shardCount);
324
- if (u.execution) {
325
- m.execution.timings.stream += u.execution.timings.stream;
326
- m.execution.timings.processing += u.execution.timings.processing;
327
- }
328
- }
329
- }
330
- }
331
- }
332
-
333
- // =============================================================================
334
- // SHARED LOADING HELPERS
335
- // =============================================================================
336
-
337
- /**
338
- * Pre-loads all shared global datasets required by the active calculations.
339
- * Returns a consolidated object of { ratings, rankings, insights, ... }
340
- */
341
- async function loadGlobalRoots(loader, dateStr, calcs, deps) {
342
- const { logger } = deps;
343
- const roots = {};
344
-
345
- // 1. Identify Requirements
346
- const reqs = {
347
- mappings: true,
348
- piMasterList: true,
349
- rankings: false,
350
- rankingsYesterday: false,
351
- verifications: false,
352
- insights: false,
353
- social: false,
354
- ratings: false,
355
- pageViews: false,
356
- watchlist: false,
357
- alerts: false
358
- };
359
-
360
- for (const c of calcs) {
361
- const deps = c.manifest.rootDataDependencies || [];
362
- if (deps.includes('rankings')) reqs.rankings = true;
363
- if (deps.includes('rankings') && c.manifest.isHistorical) reqs.rankingsYesterday = true;
364
- if (deps.includes('verification')) reqs.verifications = true;
365
- if (deps.includes('insights')) reqs.insights = true;
366
- if (deps.includes('social')) reqs.social = true;
367
- if (deps.includes('ratings')) reqs.ratings = true;
368
- if (deps.includes('pageViews')) reqs.pageViews = true;
369
- if (deps.includes('watchlist')) reqs.watchlist = true;
370
- if (deps.includes('alerts')) reqs.alerts = true;
371
- }
372
-
373
- // 2. Fetch Helper
374
- const fetch = async (key, method, dateArg, optional = true) => {
375
- if (!reqs[key]) return;
376
- try {
377
- roots[key] = await loader[method](dateArg);
378
- } catch (e) {
379
- if (!optional) throw e;
380
- logger.log('WARN', `[StandardExecutor] Optional root '${key}' failed to load: ${e.message}`);
381
- roots[key] = null;
382
- }
383
- };
384
-
385
- // 3. Execute Loads
386
- await Promise.all([
387
- fetch('mappings', 'loadMappings', null, false), // Always required
388
- fetch('piMasterList', 'loadPIMasterList', null, false),
389
- fetch('rankings', 'loadRankings', dateStr),
390
- fetch('verifications', 'loadVerifications', dateStr),
391
- fetch('insights', 'loadInsights', dateStr),
392
- fetch('social', 'loadSocial', dateStr),
393
- fetch('ratings', 'loadRatings', dateStr),
394
- fetch('pageViews', 'loadPageViews', dateStr),
395
- fetch('watchlist', 'loadWatchlistMembership', dateStr),
396
- fetch('alerts', 'loadAlertHistory', dateStr)
397
- ]);
398
-
399
- if (reqs.rankingsYesterday) {
400
- const prev = new Date(new Date(dateStr).getTime() - 86400000).toISOString().slice(0, 10);
401
- await fetch('rankingsYesterday', 'loadRankings', prev);
402
- }
403
-
404
- // Map internal names to match loadGlobalRoots structure if needed
405
- roots.watchlistMembership = roots.watchlist;
406
- roots.alertHistory = roots.alerts;
407
-
408
- return roots;
409
- }
410
-
411
- async function loadSeriesData(loader, dateStr, calcs, config, deps) {
412
- const rootReqs = {};
413
- const depReqs = {}; // norm -> { days, originalName, category }
414
-
415
- // [FIX] Calculate User Types here to pass to loadSeries
416
- const requiredUserTypes = new Set(calcs.map(c => (c.userType || 'ALL').toUpperCase()));
417
- const userTypeArray = requiredUserTypes.has('ALL') ? null : Array.from(requiredUserTypes);
418
-
419
- calcs.forEach(c => {
420
- if (c.manifest.rootDataSeries) {
421
- Object.entries(c.manifest.rootDataSeries).forEach(([k, v]) => rootReqs[k] = Math.max(rootReqs[k]||0, v.lookback||v));
422
- }
423
- if (c.manifest.dependencySeries) {
424
- Object.entries(c.manifest.dependencySeries).forEach(([k, v]) => {
425
- const norm = normalizeName(k);
426
- const days = typeof v === 'object' ? v.lookback : v;
427
- if (!depReqs[norm] || depReqs[norm].days < days) {
428
- depReqs[norm] = { days, originalName: k };
429
- }
430
- });
431
- }
432
- });
433
-
434
- const series = { root: {}, results: {} };
435
- const rootMap = {
436
- alerts: 'loadAlertHistory', insights: 'loadInsights', ratings: 'loadRatings',
437
- watchlist: 'loadWatchlistMembership', rankings: 'loadRankings',
438
- // <--- ADDED MAPPING
439
- portfolios: 'loadPortfolios'
440
- };
441
-
442
- await Promise.all(Object.entries(rootReqs).map(async ([key, days]) => {
443
- if (rootMap[key]) {
444
- // [FIX] Pass userTypeArray specifically if loading portfolios
445
- const extraArgs = (key === 'portfolios') ? [userTypeArray] : [];
446
- series.root[key] = (await loader.loadSeries(rootMap[key], dateStr, days, ...extraArgs)).data;
447
- }
448
- }));
449
-
450
- // Build lookup from ALL computations using config.calculations
451
- const depEntries = Object.values(depReqs);
452
- if (depEntries.length) {
453
- const depOriginalNames = depEntries.map(e => e.originalName);
454
- const maxDays = Math.max(...depEntries.map(e => e.days));
455
-
456
- const allManifests = getManifest(config.activeProductLines || [], getCalculations(config), deps);
457
- const lookup = Object.fromEntries(allManifests.map(m => [normalizeName(m.name), m.category]));
458
-
459
- series.results = await fetchResultSeries(dateStr, depOriginalNames, lookup, config, deps, maxDays);
460
- }
461
-
462
- return series;
463
- }
464
-
465
- module.exports = { StandardExecutor };