This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

lint and formatting

+80 -43
+1
eslint.config.mjs
··· 78 78 setImmediate: 'readonly', 79 79 setInterval: 'readonly', 80 80 clearInterval: 'readonly', 81 + URL: 'readonly', 81 82 }, 82 83 }, 83 84 rules: {
+8 -3
src/modules/search/domain/services/ConstellationLeafletSearchService.ts
··· 3 3 import { IMetadataService } from '../../../cards/domain/services/IMetadataService'; 4 4 import { UrlMetadata } from '../../../cards/domain/value-objects/UrlMetadata'; 5 5 import { URL } from '../../../cards/domain/value-objects/URL'; 6 - import { ILeafletSearchService, LeafletDocumentResult } from './ILeafletSearchService'; 6 + import { 7 + ILeafletSearchService, 8 + LeafletDocumentResult, 9 + } from './ILeafletSearchService'; 7 10 const atpi = require('atpi'); 8 11 9 12 export interface LeafletLinkingRecord { ··· 36 39 preferences?: any; 37 40 } 38 41 39 - export class ConstellationLeafletSearchService implements ILeafletSearchService { 42 + export class ConstellationLeafletSearchService 43 + implements ILeafletSearchService 44 + { 40 45 private readonly CONSTELLATION_BASE_URL = 41 46 'https://constellation.microcosm.blue'; 42 47 ··· 77 82 }); 78 83 79 84 const documentResults = await Promise.all(documentPromises); 80 - 85 + 81 86 // Filter out null results 82 87 for (const result of documentResults) { 83 88 if (result !== null) {
+17 -6
src/modules/search/infrastructure/CachedLeafletSearchService.ts
··· 1 1 import Redis from 'ioredis'; 2 - import { ILeafletSearchService, LeafletDocumentResult } from '../domain/services/ILeafletSearchService'; 2 + import { 3 + ILeafletSearchService, 4 + LeafletDocumentResult, 5 + } from '../domain/services/ILeafletSearchService'; 3 6 import { Result, ok } from '../../../shared/core/Result'; 4 7 import { AppError } from '../../../shared/core/AppError'; 5 8 ··· 74 77 } 75 78 } 76 79 77 - private getCacheKey(targetUrl: string, limit?: number, cursor?: string): string { 80 + private getCacheKey( 81 + targetUrl: string, 82 + limit?: number, 83 + cursor?: string, 84 + ): string { 78 85 // Create a deterministic cache key that includes all parameters 79 86 const params = [ 80 87 targetUrl, 81 88 limit?.toString() || 'no_limit', 82 89 cursor || 'no_cursor', 83 90 ].join('|'); 84 - 91 + 85 92 return `${this.CACHE_KEY_PREFIX}${params}`; 86 93 } 87 94 ··· 94 101 // we'll use a pattern to delete all keys for this URL 95 102 const pattern = `${this.CACHE_KEY_PREFIX}${targetUrl}|*`; 96 103 const keys = await this.redis.keys(pattern); 97 - 104 + 98 105 if (keys.length > 0) { 99 106 await this.redis.del(...keys); 100 107 } ··· 113 120 try { 114 121 const pattern = `${this.CACHE_KEY_PREFIX}*`; 115 122 const keys = await this.redis.keys(pattern); 116 - 123 + 117 124 if (keys.length > 0) { 118 125 await this.redis.del(...keys); 119 126 } ··· 125 132 /** 126 133 * Warm the cache by pre-fetching results for a URL 127 134 */ 128 - async warmCache(targetUrl: string, limit?: number, cursor?: string): Promise<void> { 135 + async warmCache( 136 + targetUrl: string, 137 + limit?: number, 138 + cursor?: string, 139 + ): Promise<void> { 129 140 await this.searchLeafletDocsForUrl(targetUrl, limit, cursor); 130 141 } 131 142 }
+46 -28
src/modules/search/infrastructure/FakeLeafletSearchService.ts
··· 1 1 import { Result, ok } from '../../../shared/core/Result'; 2 2 import { AppError } from '../../../shared/core/AppError'; 3 - import { ILeafletSearchService, LeafletDocumentResult } from '../domain/services/ILeafletSearchService'; 3 + import { 4 + ILeafletSearchService, 5 + LeafletDocumentResult, 6 + } from '../domain/services/ILeafletSearchService'; 4 7 import { UrlMetadata } from '../../cards/domain/value-objects/UrlMetadata'; 5 8 import { UrlType } from '../../cards/domain/value-objects/UrlType'; 6 9 7 10 export class FakeLeafletSearchService implements ILeafletSearchService { 8 - private readonly mockResults: Map<string, LeafletDocumentResult[]> = new Map(); 11 + private readonly mockResults: Map<string, LeafletDocumentResult[]> = 12 + new Map(); 9 13 10 14 constructor() { 11 15 // Pre-populate with some mock data ··· 18 22 cursor?: string, 19 23 ): Promise<Result<LeafletDocumentResult[], AppError.UnexpectedError>> { 20 24 // Simulate some processing time 21 - await new Promise(resolve => setTimeout(resolve, 100)); 25 + await new Promise((resolve) => setTimeout(resolve, 100)); 26 + 27 + const results = 28 + this.mockResults.get(targetUrl) || this.generateMockResults(targetUrl); 22 29 23 - const results = this.mockResults.get(targetUrl) || this.generateMockResults(targetUrl); 24 - 25 30 // Apply limit if specified 26 31 const limitedResults = limit ? results.slice(0, limit) : results; 27 - 32 + 28 33 return ok(limitedResults); 29 34 } 30 35 ··· 46 51 url: 'https://academic.leaflet.com/document-456', 47 52 }, 48 53 ]); 49 - 54 + 50 55 this.mockResults.set('https://example.com', exampleResults); 51 56 52 57 // Mock results for science.org URL (commonly used in tests) 53 - const scienceResults = this.createMockResults('https://www.science.org/doi/10.1126/science.adt7790', [ 54 - { 55 - title: 'Commentary on Climate Research', 56 - author: 'Dr. Climate Researcher', 57 - description: 'Analysis of the latest climate science findings', 58 - siteName: 'Climate Leaflet', 59 - url: 'https://climate.leaflet.com/commentary-789', 60 - }, 61 - ]); 62 - 63 - this.mockResults.set('https://www.science.org/doi/10.1126/science.adt7790', scienceResults); 58 + const scienceResults = this.createMockResults( 59 + 'https://www.science.org/doi/10.1126/science.adt7790', 60 + [ 61 + { 62 + title: 'Commentary on Climate Research', 63 + author: 'Dr. Climate Researcher', 64 + description: 'Analysis of the latest climate science findings', 65 + siteName: 'Climate Leaflet', 66 + url: 'https://climate.leaflet.com/commentary-789', 67 + }, 68 + ], 69 + ); 70 + 71 + this.mockResults.set( 72 + 'https://www.science.org/doi/10.1126/science.adt7790', 73 + scienceResults, 74 + ); 64 75 } 65 76 66 77 private generateMockResults(targetUrl: string): LeafletDocumentResult[] { ··· 83 94 return results; 84 95 } 85 96 86 - private createMockResults(targetUrl: string, mockData: Array<{ 87 - title: string; 88 - author: string; 89 - description: string; 90 - siteName: string; 91 - url: string; 92 - }>): LeafletDocumentResult[] { 93 - return mockData.map(data => { 97 + private createMockResults( 98 + targetUrl: string, 99 + mockData: Array<{ 100 + title: string; 101 + author: string; 102 + description: string; 103 + siteName: string; 104 + url: string; 105 + }>, 106 + ): LeafletDocumentResult[] { 107 + return mockData.map((data) => { 94 108 const metadataResult = UrlMetadata.create({ 95 109 url: data.url, 96 110 title: data.title, ··· 98 112 description: data.description, 99 113 siteName: data.siteName, 100 114 type: UrlType.ARTICLE, 101 - publishedDate: new Date(Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000), // Random date within last year 115 + publishedDate: new Date( 116 + Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000, 117 + ), // Random date within last year 102 118 retrievedAt: new Date(), 103 119 }); 104 120 105 121 if (metadataResult.isErr()) { 106 - throw new Error(`Failed to create mock metadata: ${metadataResult.error.message}`); 122 + throw new Error( 123 + `Failed to create mock metadata: ${metadataResult.error.message}`, 124 + ); 107 125 } 108 126 109 127 return {
+8 -6
src/shared/infrastructure/http/factories/ServiceFactory.ts
··· 61 61 import { InMemoryVectorDatabase } from '../../../../modules/search/infrastructure/InMemoryVectorDatabase'; 62 62 import { UpstashVectorDatabase } from '../../../../modules/search/infrastructure/UpstashVectorDatabase'; 63 63 import { NotificationService } from '../../../../modules/notifications/domain/services/NotificationService'; 64 + import { FakeLeafletSearchService } from 'src/modules/search/infrastructure/FakeLeafletSearchService'; 65 + import { ILeafletSearchService } from 'src/modules/search/domain/services/ILeafletSearchService'; 66 + import { ConstellationLeafletSearchService } from 'src/modules/search/domain/services/ConstellationLeafletSearchService'; 67 + import { CachedLeafletSearchService } from 'src/modules/search/infrastructure/CachedLeafletSearchService'; 64 68 65 69 // Shared services needed by both web app and workers 66 70 export interface SharedServices { ··· 358 362 359 363 // Create LeafletSearchService with caching 360 364 let leafletSearchService: ILeafletSearchService; 361 - 365 + 362 366 if (useMockPersistence) { 363 367 // Use fake implementation for mock persistence 364 368 leafletSearchService = new FakeLeafletSearchService(); 365 369 } else { 366 370 // Use real Constellation service with caching 367 - const baseLeafletSearchService = new ConstellationLeafletSearchService(metadataService); 371 + const baseLeafletSearchService = new ConstellationLeafletSearchService( 372 + metadataService, 373 + ); 368 374 const redisConfig = configService.getRedisConfig(); 369 375 const redis = RedisFactory.createConnection(redisConfig); 370 376 leafletSearchService = new CachedLeafletSearchService( ··· 436 442 }; 437 443 } 438 444 } 439 - import { ConstellationLeafletSearchService } from '../../../../modules/search/domain/services/LeafletSearchService'; 440 - import { FakeLeafletSearchService } from '../../../../modules/search/infrastructure/FakeLeafletSearchService'; 441 - import { CachedLeafletSearchService } from '../../../../modules/search/infrastructure/CachedLeafletSearchService'; 442 - import { ILeafletSearchService } from '../../../../modules/search/domain/services/ILeafletSearchService';