bulltrackers-module 1.0.498 → 1.0.500

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.
@@ -95,12 +95,23 @@ exports.runRootDataIndexer = async (config, dependencies) => {
95
95
  logger.log('INFO', `[RootDataIndexer] Starting Root Data Availability Scan... Mode: ${scanMode}`, { targetDate });
96
96
 
97
97
  // 1. Price Availability - Read from date tracking documents
98
- // Find the latest pricedatastoreddates document and extract available dates
98
+ // Find the latest price tracking document and extract available dates
99
99
  const priceAvailabilitySet = new Set();
100
100
 
101
+ // Get price tracking collection name from registry if available
102
+ let priceTrackingCollectionName = 'pricedatastoreddates';
103
+ if (dependencies.collectionRegistry && dependencies.collectionRegistry.getCollectionPath) {
104
+ try {
105
+ const trackingPath = dependencies.collectionRegistry.getCollectionPath('rootData', 'priceTracking', { fetchDate: '2025-01-01' });
106
+ priceTrackingCollectionName = trackingPath.split('/')[0];
107
+ } catch (e) {
108
+ logger.log('WARN', `[RootDataIndexer] Failed to get price tracking collection from registry, using default: ${e.message}`);
109
+ }
110
+ }
111
+
101
112
  try {
102
113
  // Get the latest price date tracking document
103
- const dateTrackingRef = db.collection('pricedatastoreddates')
114
+ const dateTrackingRef = db.collection(priceTrackingCollectionName)
104
115
  .orderBy('fetchDate', 'desc')
105
116
  .limit(1);
106
117
 
@@ -109,6 +120,7 @@ exports.runRootDataIndexer = async (config, dependencies) => {
109
120
  if (!dateTrackingSnapshot.empty) {
110
121
  const latestTrackingDoc = dateTrackingSnapshot.docs[0].data();
111
122
  const datesAvailable = latestTrackingDoc.datesAvailable || [];
123
+ const fetchDate = latestTrackingDoc.fetchDate;
112
124
 
113
125
  // Add all dates from the tracking document
114
126
  datesAvailable.forEach(dateKey => {
@@ -117,7 +129,22 @@ exports.runRootDataIndexer = async (config, dependencies) => {
117
129
  }
118
130
  });
119
131
 
120
- logger.log('INFO', `[RootDataIndexer] Loaded ${priceAvailabilitySet.size} price dates from tracking document (fetchDate: ${latestTrackingDoc.fetchDate})`);
132
+ // IMPORTANT: If the tracking document was written for today (fetchDate matches targetDate),
133
+ // we should consider prices available for that date even if the API didn't return that exact date.
134
+ // This is because the price fetcher ran for that date and stored prices (even if they're historical).
135
+ if (targetDate && fetchDate === targetDate) {
136
+ priceAvailabilitySet.add(targetDate);
137
+ logger.log('INFO', `[RootDataIndexer] Added fetchDate (${fetchDate}) to price availability set for target date check`);
138
+ }
139
+
140
+ logger.log('INFO', `[RootDataIndexer] Loaded ${priceAvailabilitySet.size} price dates from tracking document (fetchDate: ${fetchDate})`);
141
+
142
+ // Debug: Log a sample of dates and check if target date is present
143
+ if (targetDate) {
144
+ const sampleDates = Array.from(priceAvailabilitySet).slice(0, 5);
145
+ const hasTargetDate = priceAvailabilitySet.has(targetDate);
146
+ logger.log('INFO', `[RootDataIndexer] Price availability check for ${targetDate}: ${hasTargetDate ? 'FOUND' : 'NOT FOUND'}. Sample dates: ${sampleDates.join(', ')}`);
147
+ }
121
148
  } else {
122
149
  logger.log('WARN', '[RootDataIndexer] No price date tracking documents found. Falling back to empty set.');
123
150
  }
@@ -266,11 +293,11 @@ exports.runRootDataIndexer = async (config, dependencies) => {
266
293
  // Single tracking documents at root level:
267
294
  // - PopularInvestorSocialPostData/_dates -> fetchedDates.{date}
268
295
  // - SignedInUserSocialPostData/_dates -> fetchedDates.{date}
269
- // For generic social (InstrumentFeedSocialPostData), check the collection directly
296
+ // For generic social (InstrumentFeedSocialPostData), check the posts subcollection
270
297
  const [piSocialTrackingDoc, signedInSocialTrackingDoc, genericSocialSnap] = await Promise.all([
271
298
  db.collection('PopularInvestorSocialPostData').doc('_dates').get(),
272
299
  db.collection('SignedInUserSocialPostData').doc('_dates').get(),
273
- db.collection('InstrumentFeedSocialPostData').doc(dateStr).limit(1).get()
300
+ db.collection('InstrumentFeedSocialPostData').doc(dateStr).collection('posts').limit(1).get()
274
301
  ]);
275
302
 
276
303
  // Check if date exists in tracking documents
@@ -326,7 +353,7 @@ exports.runRootDataIndexer = async (config, dependencies) => {
326
353
  const [
327
354
  normPortExists, specPortExists,
328
355
  normHistExists, specHistExists,
329
- insightsSnap, socialQuerySnap,
356
+ insightsSnap, genericSocialExists,
330
357
  piRankingsSnap,
331
358
  piPortExists,
332
359
  piDeepExists,
@@ -339,7 +366,7 @@ exports.runRootDataIndexer = async (config, dependencies) => {
339
366
  checkAnyPartExists(normHistPartsRef),
340
367
  checkAnyPartExists(specHistPartsRef),
341
368
  insightsRef.get(),
342
- genericSocialSnap.empty ? Promise.resolve(false) : Promise.resolve(true),
369
+ Promise.resolve(!genericSocialSnap.empty),
343
370
  piRankingsRef.get(),
344
371
  // Check new structure first, fallback to legacy
345
372
  checkDateCollectionHasDocs(piPortfoliosCollectionRef).then(exists => exists || checkAnyPartExists(piPortfoliosPartsRef)),
@@ -392,20 +419,16 @@ exports.runRootDataIndexer = async (config, dependencies) => {
392
419
  availability.hasPortfolio = normPortExists || specPortExists || piPortExists || signedInPortExists;
393
420
  availability.hasHistory = normHistExists || specHistExists || piHistExists || signedInHistExists;
394
421
  availability.hasInsights = insightsSnap.exists;
395
- availability.hasSocial = !socialQuerySnap.empty;
422
+ availability.hasSocial = foundPISocial || foundSignedInSocial || genericSocialExists;
396
423
 
397
424
  // Price Check
398
- if (targetDate) {
399
- // In single-date mode, we do a quick check on the shard if we don't have the full set loaded
400
- // For performance, we default hasPrices to false unless we implement a specific single-date shard check.
401
- // However, since this is usually called right after fetching, we can leave it as a secondary concern
402
- // or assume the Global Sync will catch it later.
403
- // OPTIONAL: Implementation of specific shard check for single date:
404
- // For now, we reuse the set if available (it won't be) or default false.
405
- // NOTE: The Global Scan at 01:00 UTC will strictly verify prices.
406
- availability.hasPrices = priceAvailabilitySet.has(dateStr);
407
- } else {
408
- availability.hasPrices = priceAvailabilitySet.has(dateStr);
425
+ // Check if the target date exists in the price availability set
426
+ // The set is populated from the price tracking document's datesAvailable array
427
+ const hasPriceForDate = priceAvailabilitySet.has(dateStr);
428
+ availability.hasPrices = hasPriceForDate;
429
+
430
+ if (targetDate && !hasPriceForDate) {
431
+ logger.log('WARN', `[RootDataIndexer/${dateStr}] Price data not found in tracking document. Set size: ${priceAvailabilitySet.size}, Date checked: ${dateStr}`);
409
432
  }
410
433
 
411
434
  await db.collection(availabilityCollection).doc(dateStr).set(availability);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.498",
3
+ "version": "1.0.500",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [