A social knowledge tool for researchers built on ATProto
at development 78 lines 1.8 kB view raw
1import { ValueObject } from '../../../../shared/domain/ValueObject'; 2import { Result, ok, err } from '../../../../shared/core/Result'; 3 4interface UrlMetadataProps { 5 url: string; 6 title?: string; 7 description?: string; 8 author?: string; 9 publishedDate?: Date; 10 siteName?: string; 11 imageUrl?: string; 12 type?: string; 13 retrievedAt?: Date; 14} 15 16export class UrlMetadata extends ValueObject<UrlMetadataProps> { 17 get url(): string { 18 return this.props.url; 19 } 20 21 get title(): string | undefined { 22 return this.props.title; 23 } 24 25 get description(): string | undefined { 26 return this.props.description; 27 } 28 29 get author(): string | undefined { 30 return this.props.author; 31 } 32 33 get publishedDate(): Date | undefined { 34 return this.props.publishedDate; 35 } 36 37 get siteName(): string | undefined { 38 return this.props.siteName; 39 } 40 41 get imageUrl(): string | undefined { 42 return this.props.imageUrl; 43 } 44 45 get type(): string | undefined { 46 return this.props.type; 47 } 48 49 get retrievedAt(): Date | undefined { 50 return this.props.retrievedAt; 51 } 52 53 private constructor(props: UrlMetadataProps) { 54 super(props); 55 } 56 57 public static create(props: UrlMetadataProps): Result<UrlMetadata, Error> { 58 if (!props.url || props.url.trim().length === 0) { 59 return err(new Error('URL is required for metadata')); 60 } 61 62 return ok( 63 new UrlMetadata({ 64 ...props, 65 retrievedAt: props.retrievedAt || new Date(), 66 }), 67 ); 68 } 69 70 public isStale(maxAgeHours: number = 24): boolean { 71 if (!this.retrievedAt) { 72 return true; // If no retrievedAt, consider it stale 73 } 74 const ageInHours = 75 (Date.now() - this.retrievedAt.getTime()) / (1000 * 60 * 60); 76 return ageInHours > maxAgeHours; 77 } 78}