bulltrackers-module 1.0.104 → 1.0.106

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 (33) hide show
  1. package/README.MD +222 -222
  2. package/functions/appscript-api/helpers/errors.js +19 -19
  3. package/functions/appscript-api/index.js +58 -58
  4. package/functions/computation-system/helpers/orchestration_helpers.js +647 -113
  5. package/functions/computation-system/utils/data_loader.js +191 -191
  6. package/functions/computation-system/utils/utils.js +149 -254
  7. package/functions/core/utils/firestore_utils.js +433 -433
  8. package/functions/core/utils/pubsub_utils.js +53 -53
  9. package/functions/dispatcher/helpers/dispatch_helpers.js +47 -47
  10. package/functions/dispatcher/index.js +52 -52
  11. package/functions/etoro-price-fetcher/helpers/handler_helpers.js +124 -124
  12. package/functions/fetch-insights/helpers/handler_helpers.js +91 -91
  13. package/functions/generic-api/helpers/api_helpers.js +379 -379
  14. package/functions/generic-api/index.js +150 -150
  15. package/functions/invalid-speculator-handler/helpers/handler_helpers.js +75 -75
  16. package/functions/orchestrator/helpers/discovery_helpers.js +226 -226
  17. package/functions/orchestrator/helpers/update_helpers.js +92 -92
  18. package/functions/orchestrator/index.js +147 -147
  19. package/functions/price-backfill/helpers/handler_helpers.js +116 -123
  20. package/functions/social-orchestrator/helpers/orchestrator_helpers.js +61 -61
  21. package/functions/social-task-handler/helpers/handler_helpers.js +288 -288
  22. package/functions/task-engine/handler_creator.js +78 -78
  23. package/functions/task-engine/helpers/discover_helpers.js +125 -125
  24. package/functions/task-engine/helpers/update_helpers.js +118 -118
  25. package/functions/task-engine/helpers/verify_helpers.js +162 -162
  26. package/functions/task-engine/utils/firestore_batch_manager.js +258 -258
  27. package/index.js +105 -113
  28. package/package.json +45 -45
  29. package/functions/computation-system/computation_dependencies.json +0 -120
  30. package/functions/computation-system/helpers/worker_helpers.js +0 -340
  31. package/functions/computation-system/utils/computation_state_manager.js +0 -178
  32. package/functions/computation-system/utils/dependency_graph.js +0 -191
  33. package/functions/speculator-cleanup-orchestrator/helpers/cleanup_helpers.js +0 -160
@@ -1,192 +1,192 @@
1
- /**
2
- * @fileoverview Data loader sub-pipes for the Computation System.
3
- * REFACTORED: Now stateless and receive dependencies.
4
- */
5
-
6
- // <<< FIX: REMOVED all top-level 'require' and 'dependencies' lines >>>
7
-
8
- /**
9
- * Sub-pipe: pipe.computationSystem.dataLoader.getPortfolioPartRefs
10
- * @param {object} config - The computation system configuration object.
11
- * @param {object} dependencies - Contains db, logger, calculationUtils.
12
- * @param {string} dateString - The date in YYYY-MM-DD format.
13
- * @returns {Promise<Firestore.DocumentReference[]>} An array of DocumentReferences.
14
- */
15
- async function getPortfolioPartRefs(config, dependencies, dateString) {
16
- // <<< FIX: Destructure all dependencies here, inside the function >>>
17
- const { db, logger, calculationUtils } = dependencies;
18
- const { withRetry } = calculationUtils;
19
- // <<< END FIX >>>
20
-
21
- logger.log('INFO', `Getting portfolio part references for date: ${dateString}`);
22
- const allPartRefs = [];
23
- const collectionsToQuery = [config.normalUserPortfolioCollection, config.speculatorPortfolioCollection];
24
-
25
- for (const collectionName of collectionsToQuery) {
26
- const blockDocsQuery = db.collection(collectionName); // Use db
27
- const blockDocRefs = await withRetry(
28
- () => blockDocsQuery.listDocuments(),
29
- `listDocuments(${collectionName})`
30
- );
31
-
32
- if (blockDocRefs.length === 0) {
33
- logger.log('WARN', `No block documents found in collection: ${collectionName}`);
34
- continue;
35
- }
36
-
37
- for (const blockDocRef of blockDocRefs) {
38
- const partsCollectionRef = blockDocRef.collection(config.snapshotsSubcollection).doc(dateString).collection(config.partsSubcollection);
39
- const partDocs = await withRetry(
40
- () => partsCollectionRef.listDocuments(),
41
- `listDocuments(${partsCollectionRef.path})`
42
- );
43
- allPartRefs.push(...partDocs);
44
- }
45
- }
46
-
47
- logger.log('INFO', `Found ${allPartRefs.length} part document references for ${dateString}.`);
48
- return allPartRefs;
49
- }
50
-
51
- /**
52
- * Sub-pipe: pipe.computationSystem.dataLoader.loadDataByRefs
53
- * @param {object} config - The computation system configuration object.
54
- * @param {object} dependencies - Contains db, logger, calculationUtils.
55
- * @param {Firestore.DocumentReference[]} refs - An array of DocumentReferences to load.
56
- * @returns {Promise<object>} A single map of { [userId]: portfolioData }.
57
- */
58
- async function loadDataByRefs(config, dependencies, refs) {
59
- // <<< FIX: Destructure all dependencies here, inside the function >>>
60
- const { db, logger, calculationUtils } = dependencies;
61
- const { withRetry } = calculationUtils;
62
- // <<< END FIX >>>
63
-
64
- if (!refs || refs.length === 0) { return {}; }
65
- const mergedPortfolios = {};
66
- const batchSize = config.partRefBatchSize || 50;
67
-
68
- for (let i = 0; i < refs.length; i += batchSize) {
69
- const batchRefs = refs.slice(i, i + batchSize);
70
- // Use db from dependencies
71
- const snapshots = await withRetry(
72
- () => db.getAll(...batchRefs),
73
- `getAll(batch ${Math.floor(i / batchSize)})`
74
- );
75
- for (const doc of snapshots) {
76
- if (doc.exists) {
77
- const data = doc.data();
78
- if (data && typeof data === 'object') {
79
- Object.assign(mergedPortfolios, data);
80
- } else {
81
- logger.log('WARN', `Document ${doc.id} exists but data is not an object. Data:`, data);
82
- }
83
- }
84
- }
85
- }
86
- return mergedPortfolios;
87
- }
88
-
89
- /**
90
- * Sub-pipe: pipe.computationSystem.dataLoader.loadFullDayMap
91
- * @param {object} config - The computation system configuration object.
92
- * @param {object} dependencies - Contains db, logger.
93
- * @param {Firestore.DocumentReference[]} partRefs - Array of part document references.
94
- * @returns {Promise<object>} A single map of { [userId]: portfolioData }.
95
- */
96
- async function loadFullDayMap(config, dependencies, partRefs) {
97
- // <<< FIX: Destructure only what's needed for this specific function >>>
98
- const { logger } = dependencies;
99
- // <<< END FIX >>>
100
-
101
- if (partRefs.length === 0) return {};
102
- logger.log('TRACE', `Loading full day map from ${partRefs.length} references...`);
103
-
104
- // Pass config and dependencies to sub-pipe
105
- const fullMap = await loadDataByRefs(config, dependencies, partRefs);
106
- logger.log('TRACE', `Full day map loaded with ${Object.keys(fullMap).length} users.`);
107
- return fullMap;
108
- }
109
-
110
- /**
111
- * Sub-pipe: pipe.computationSystem.dataLoader.loadDailyInsights
112
- * Fetches the daily instrument insights document for a specific date.
113
- * @param {object} config - The computation system configuration object.
114
- * @param {object} dependencies - Contains db, logger, calculationUtils.
115
- * @param {string} dateString - The date in YYYY-MM-DD format.
116
- * @returns {Promise<object|null>} The insights data object or null if not found/error.
117
- */
118
- async function loadDailyInsights(config, dependencies, dateString) {
119
- // <<< FIX: Destructure all dependencies here, inside the function >>>
120
- const { db, logger, calculationUtils } = dependencies;
121
- const { withRetry } = calculationUtils;
122
- // <<< END FIX >>>
123
-
124
- const insightsCollectionName = config.insightsCollectionName || 'daily_instrument_insights'; // Use config or default
125
- logger.log('INFO', `Loading daily insights for date: ${dateString} from ${insightsCollectionName}`);
126
- try {
127
- const docRef = db.collection(insightsCollectionName).doc(dateString);
128
- const docSnap = await withRetry(() => docRef.get(), `getInsights(${dateString})`);
129
-
130
- if (!docSnap.exists) {
131
- logger.log('WARN', `Daily insights document not found for ${dateString}`);
132
- return null;
133
- }
134
- logger.log('TRACE', `Successfully loaded insights for ${dateString}.`);
135
- return docSnap.data();
136
- } catch (error) {
137
- logger.log('ERROR', `Failed to load daily insights for ${dateString}`, { errorMessage: error.message });
138
- return null; // Return null on error to allow computations to proceed partially if possible
139
- }
140
- }
141
-
142
- /**
143
- * --- NEW ---
144
- * Sub-pipe: pipe.computationSystem.dataLoader.loadDailySocialPostInsights
145
- * Fetches all analyzed social post documents for a specific date.
146
- * @param {object} config - The computation system configuration object.
147
- * @param {object} dependencies - Contains db, logger, calculationUtils.
148
- * @param {string} dateString - The date in YYYY-MM-DD format.
149
- * @returns {Promise<object|null>} An object map of { [postId]: postData } or null.
150
- */
151
- async function loadDailySocialPostInsights(config, dependencies, dateString) {
152
- // <<< FIX: Destructure all dependencies here, inside the function >>>
153
- const { db, logger, calculationUtils } = dependencies;
154
- const { withRetry } = calculationUtils;
155
- // <<< END FIX >>>
156
-
157
- // Use the new config property, or fall back to a default
158
- const socialInsightsCollectionName = config.socialInsightsCollectionName || 'daily_social_insights';
159
- logger.log('INFO', `Loading social post insights for date: ${dateString} from ${socialInsightsCollectionName}`);
160
-
161
- try {
162
- const postsCollectionRef = db.collection(socialInsightsCollectionName).doc(dateString).collection('posts');
163
- const querySnapshot = await withRetry(() => postsCollectionRef.get(), `getSocialPosts(${dateString})`);
164
-
165
- if (querySnapshot.empty) {
166
- logger.log('WARN', `No social post insights found for ${dateString}.`);
167
- return null;
168
- }
169
-
170
- const postsMap = {};
171
- querySnapshot.forEach(doc => {
172
- postsMap[doc.id] = doc.data();
173
- });
174
-
175
- logger.log('TRACE', `Successfully loaded ${Object.keys(postsMap).length} social post insights for ${dateString}.`);
176
- return postsMap;
177
-
178
- } catch (error) {
179
- logger.log('ERROR', `Failed to load social post insights for ${dateString}`, { errorMessage: error.message });
180
- return null;
181
- }
182
- }
183
- // --- END NEW ---
184
-
185
-
186
- module.exports = {
187
- getPortfolioPartRefs,
188
- loadDataByRefs,
189
- loadFullDayMap,
190
- loadDailyInsights,
191
- loadDailySocialPostInsights,
1
+ /**
2
+ * @fileoverview Data loader sub-pipes for the Computation System.
3
+ * REFACTORED: Now stateless and receive dependencies.
4
+ */
5
+
6
+ // <<< FIX: REMOVED all top-level 'require' and 'dependencies' lines >>>
7
+
8
+ /**
9
+ * Sub-pipe: pipe.computationSystem.dataLoader.getPortfolioPartRefs
10
+ * @param {object} config - The computation system configuration object.
11
+ * @param {object} dependencies - Contains db, logger, calculationUtils.
12
+ * @param {string} dateString - The date in YYYY-MM-DD format.
13
+ * @returns {Promise<Firestore.DocumentReference[]>} An array of DocumentReferences.
14
+ */
15
+ async function getPortfolioPartRefs(config, dependencies, dateString) {
16
+ // <<< FIX: Destructure all dependencies here, inside the function >>>
17
+ const { db, logger, calculationUtils } = dependencies;
18
+ const { withRetry } = calculationUtils;
19
+ // <<< END FIX >>>
20
+
21
+ logger.log('INFO', `Getting portfolio part references for date: ${dateString}`);
22
+ const allPartRefs = [];
23
+ const collectionsToQuery = [config.normalUserPortfolioCollection, config.speculatorPortfolioCollection];
24
+
25
+ for (const collectionName of collectionsToQuery) {
26
+ const blockDocsQuery = db.collection(collectionName); // Use db
27
+ const blockDocRefs = await withRetry(
28
+ () => blockDocsQuery.listDocuments(),
29
+ `listDocuments(${collectionName})`
30
+ );
31
+
32
+ if (blockDocRefs.length === 0) {
33
+ logger.log('WARN', `No block documents found in collection: ${collectionName}`);
34
+ continue;
35
+ }
36
+
37
+ for (const blockDocRef of blockDocRefs) {
38
+ const partsCollectionRef = blockDocRef.collection(config.snapshotsSubcollection).doc(dateString).collection(config.partsSubcollection);
39
+ const partDocs = await withRetry(
40
+ () => partsCollectionRef.listDocuments(),
41
+ `listDocuments(${partsCollectionRef.path})`
42
+ );
43
+ allPartRefs.push(...partDocs);
44
+ }
45
+ }
46
+
47
+ logger.log('INFO', `Found ${allPartRefs.length} part document references for ${dateString}.`);
48
+ return allPartRefs;
49
+ }
50
+
51
+ /**
52
+ * Sub-pipe: pipe.computationSystem.dataLoader.loadDataByRefs
53
+ * @param {object} config - The computation system configuration object.
54
+ * @param {object} dependencies - Contains db, logger, calculationUtils.
55
+ * @param {Firestore.DocumentReference[]} refs - An array of DocumentReferences to load.
56
+ * @returns {Promise<object>} A single map of { [userId]: portfolioData }.
57
+ */
58
+ async function loadDataByRefs(config, dependencies, refs) {
59
+ // <<< FIX: Destructure all dependencies here, inside the function >>>
60
+ const { db, logger, calculationUtils } = dependencies;
61
+ const { withRetry } = calculationUtils;
62
+ // <<< END FIX >>>
63
+
64
+ if (!refs || refs.length === 0) { return {}; }
65
+ const mergedPortfolios = {};
66
+ const batchSize = config.partRefBatchSize || 50;
67
+
68
+ for (let i = 0; i < refs.length; i += batchSize) {
69
+ const batchRefs = refs.slice(i, i + batchSize);
70
+ // Use db from dependencies
71
+ const snapshots = await withRetry(
72
+ () => db.getAll(...batchRefs),
73
+ `getAll(batch ${Math.floor(i / batchSize)})`
74
+ );
75
+ for (const doc of snapshots) {
76
+ if (doc.exists) {
77
+ const data = doc.data();
78
+ if (data && typeof data === 'object') {
79
+ Object.assign(mergedPortfolios, data);
80
+ } else {
81
+ logger.log('WARN', `Document ${doc.id} exists but data is not an object. Data:`, data);
82
+ }
83
+ }
84
+ }
85
+ }
86
+ return mergedPortfolios;
87
+ }
88
+
89
+ /**
90
+ * Sub-pipe: pipe.computationSystem.dataLoader.loadFullDayMap
91
+ * @param {object} config - The computation system configuration object.
92
+ * @param {object} dependencies - Contains db, logger.
93
+ * @param {Firestore.DocumentReference[]} partRefs - Array of part document references.
94
+ * @returns {Promise<object>} A single map of { [userId]: portfolioData }.
95
+ */
96
+ async function loadFullDayMap(config, dependencies, partRefs) {
97
+ // <<< FIX: Destructure only what's needed for this specific function >>>
98
+ const { logger } = dependencies;
99
+ // <<< END FIX >>>
100
+
101
+ if (partRefs.length === 0) return {};
102
+ logger.log('TRACE', `Loading full day map from ${partRefs.length} references...`);
103
+
104
+ // Pass config and dependencies to sub-pipe
105
+ const fullMap = await loadDataByRefs(config, dependencies, partRefs);
106
+ logger.log('TRACE', `Full day map loaded with ${Object.keys(fullMap).length} users.`);
107
+ return fullMap;
108
+ }
109
+
110
+ /**
111
+ * Sub-pipe: pipe.computationSystem.dataLoader.loadDailyInsights
112
+ * Fetches the daily instrument insights document for a specific date.
113
+ * @param {object} config - The computation system configuration object.
114
+ * @param {object} dependencies - Contains db, logger, calculationUtils.
115
+ * @param {string} dateString - The date in YYYY-MM-DD format.
116
+ * @returns {Promise<object|null>} The insights data object or null if not found/error.
117
+ */
118
+ async function loadDailyInsights(config, dependencies, dateString) {
119
+ // <<< FIX: Destructure all dependencies here, inside the function >>>
120
+ const { db, logger, calculationUtils } = dependencies;
121
+ const { withRetry } = calculationUtils;
122
+ // <<< END FIX >>>
123
+
124
+ const insightsCollectionName = config.insightsCollectionName || 'daily_instrument_insights'; // Use config or default
125
+ logger.log('INFO', `Loading daily insights for date: ${dateString} from ${insightsCollectionName}`);
126
+ try {
127
+ const docRef = db.collection(insightsCollectionName).doc(dateString);
128
+ const docSnap = await withRetry(() => docRef.get(), `getInsights(${dateString})`);
129
+
130
+ if (!docSnap.exists) {
131
+ logger.log('WARN', `Daily insights document not found for ${dateString}`);
132
+ return null;
133
+ }
134
+ logger.log('TRACE', `Successfully loaded insights for ${dateString}.`);
135
+ return docSnap.data();
136
+ } catch (error) {
137
+ logger.log('ERROR', `Failed to load daily insights for ${dateString}`, { errorMessage: error.message });
138
+ return null; // Return null on error to allow computations to proceed partially if possible
139
+ }
140
+ }
141
+
142
+ /**
143
+ * --- NEW ---
144
+ * Sub-pipe: pipe.computationSystem.dataLoader.loadDailySocialPostInsights
145
+ * Fetches all analyzed social post documents for a specific date.
146
+ * @param {object} config - The computation system configuration object.
147
+ * @param {object} dependencies - Contains db, logger, calculationUtils.
148
+ * @param {string} dateString - The date in YYYY-MM-DD format.
149
+ * @returns {Promise<object|null>} An object map of { [postId]: postData } or null.
150
+ */
151
+ async function loadDailySocialPostInsights(config, dependencies, dateString) {
152
+ // <<< FIX: Destructure all dependencies here, inside the function >>>
153
+ const { db, logger, calculationUtils } = dependencies;
154
+ const { withRetry } = calculationUtils;
155
+ // <<< END FIX >>>
156
+
157
+ // Use the new config property, or fall back to a default
158
+ const socialInsightsCollectionName = config.socialInsightsCollectionName || 'daily_social_insights';
159
+ logger.log('INFO', `Loading social post insights for date: ${dateString} from ${socialInsightsCollectionName}`);
160
+
161
+ try {
162
+ const postsCollectionRef = db.collection(socialInsightsCollectionName).doc(dateString).collection('posts');
163
+ const querySnapshot = await withRetry(() => postsCollectionRef.get(), `getSocialPosts(${dateString})`);
164
+
165
+ if (querySnapshot.empty) {
166
+ logger.log('WARN', `No social post insights found for ${dateString}.`);
167
+ return null;
168
+ }
169
+
170
+ const postsMap = {};
171
+ querySnapshot.forEach(doc => {
172
+ postsMap[doc.id] = doc.data();
173
+ });
174
+
175
+ logger.log('TRACE', `Successfully loaded ${Object.keys(postsMap).length} social post insights for ${dateString}.`);
176
+ return postsMap;
177
+
178
+ } catch (error) {
179
+ logger.log('ERROR', `Failed to load social post insights for ${dateString}`, { errorMessage: error.message });
180
+ return null;
181
+ }
182
+ }
183
+ // --- END NEW ---
184
+
185
+
186
+ module.exports = {
187
+ getPortfolioPartRefs,
188
+ loadDataByRefs,
189
+ loadFullDayMap,
190
+ loadDailyInsights,
191
+ loadDailySocialPostInsights,
192
192
  };