React Native mobile application for SAPIENS news platform. Consolidated all previous history into single commit. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1969 lines
85 KiB
TypeScript
1969 lines
85 KiB
TypeScript
import {
|
|
type User,
|
|
type InsertUser,
|
|
type MediaOutlet,
|
|
type InsertMediaOutlet,
|
|
type Article,
|
|
type InsertArticle,
|
|
type Comment,
|
|
type InsertComment,
|
|
type CommentReaction,
|
|
type InsertCommentReaction,
|
|
type Bookmark,
|
|
type InsertBookmark,
|
|
type PredictionMarket,
|
|
type InsertPredictionMarket,
|
|
users,
|
|
mediaOutlets,
|
|
articles,
|
|
comments,
|
|
commentReactions,
|
|
bookmarks,
|
|
predictionMarkets
|
|
} from "@shared/schema";
|
|
import { randomUUID } from "crypto";
|
|
import { drizzle } from "drizzle-orm/neon-http";
|
|
import { neon } from "@neondatabase/serverless";
|
|
import { eq, desc, asc, and, or, sql, like, count } from "drizzle-orm";
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
// Initialize database connection
|
|
if (!process.env.DATABASE_URL) {
|
|
throw new Error("DATABASE_URL environment variable is required");
|
|
}
|
|
|
|
const sqlClient = neon(process.env.DATABASE_URL);
|
|
const db = drizzle(sqlClient);
|
|
|
|
// Storage interface for the news platform
|
|
export interface IStorage {
|
|
// User methods
|
|
getUser(id: string): Promise<User | undefined>;
|
|
getUserByUsername(username: string): Promise<User | undefined>;
|
|
createUser(user: InsertUser): Promise<User>;
|
|
|
|
// Media outlet methods
|
|
getAllOutlets(): Promise<MediaOutlet[]>;
|
|
getOutletsByCategory(category: string): Promise<MediaOutlet[]>;
|
|
getOutletById(id: string): Promise<MediaOutlet | undefined>;
|
|
createOutlet(outlet: InsertMediaOutlet): Promise<MediaOutlet>;
|
|
deleteOutlet(id: string): Promise<boolean>;
|
|
updateOutlet(id: string, updates: Partial<InsertMediaOutlet>): Promise<MediaOutlet | undefined>;
|
|
mergeOutlets(fromOutletId: string, toOutletId: string): Promise<{ success: boolean; movedArticles: number }>;
|
|
|
|
// Article methods
|
|
getAllArticles(): Promise<Article[]>;
|
|
getArticlesByOutlet(outletId: string): Promise<Article[]>;
|
|
getArticleById(id: string): Promise<Article | undefined>;
|
|
getFeaturedArticles(limit?: number): Promise<Article[]>;
|
|
searchArticles(query: string): Promise<Article[]>;
|
|
createArticle(article: InsertArticle): Promise<Article>;
|
|
deleteArticle(id: string): Promise<boolean>;
|
|
|
|
// Scraped article methods
|
|
createScrapedArticle(article: Omit<InsertArticle, 'id'> & {
|
|
sourceUrl: string;
|
|
author?: string;
|
|
originalImageUrl?: string;
|
|
isScraped?: number;
|
|
}): Promise<Article>;
|
|
getScrapedArticles(limit?: number): Promise<Article[]>;
|
|
updateArticleWithScrapedData(id: string, data: {
|
|
sourceUrl?: string;
|
|
author?: string;
|
|
originalImageUrl?: string;
|
|
}): Promise<Article | undefined>;
|
|
|
|
// Thumbnail generation methods
|
|
updateArticleThumbnail(id: string, thumbnailPath: string): Promise<Article | undefined>;
|
|
|
|
// YouTube-style feed methods (enriched with outlet data)
|
|
listFeed(params: { cursor?: string; limit?: number; filter?: 'all' | 'people' | 'topics' | 'companies' }): Promise<{ items: (Article & { outletName: string; outletAvatar: string; category: string })[]; nextCursor?: string }>;
|
|
incrementView(id: string): Promise<void>;
|
|
|
|
// Comment system methods
|
|
getCommentsByArticle(articleId: string, params: { limit?: number; offset?: number }): Promise<{ comments: Comment[]; total: number }>;
|
|
getCommentReplies(parentId: string, params: { limit?: number; offset?: number }): Promise<{ comments: Comment[]; total: number }>;
|
|
getCommentById(id: string): Promise<Comment | undefined>;
|
|
createComment(comment: InsertComment): Promise<Comment>;
|
|
updateComment(id: string, content: string): Promise<Comment | undefined>;
|
|
deleteComment(id: string): Promise<boolean>;
|
|
|
|
// Comment reaction methods (atomic operations)
|
|
toggleCommentReaction(commentId: string, userIdentifier: string, reactionType: 'like' | 'dislike'): Promise<{ action: 'added' | 'removed' | 'changed'; reaction: CommentReaction | null }>;
|
|
getUserCommentReaction(commentId: string, userIdentifier: string): Promise<CommentReaction | undefined>;
|
|
|
|
// Bookmark methods
|
|
toggleBookmark(articleId: string, userIdentifier: string): Promise<{ action: 'added' | 'removed'; bookmark: Bookmark | null }>;
|
|
isBookmarked(articleId: string, userIdentifier: string): Promise<boolean>;
|
|
getUserBookmarks(userIdentifier: string): Promise<Bookmark[]>;
|
|
|
|
// Article stats methods
|
|
getArticleCommentCount(articleId: string): Promise<number>;
|
|
|
|
// Article deduplication methods
|
|
removeDuplicateArticles(): Promise<{ removedCount: number; details: { outletId: string; duplicatesRemoved: number }[] }>;
|
|
|
|
// Prediction Market methods
|
|
getPredictionMarketsByArticle(articleId: string, params: { limit?: number; offset?: number }): Promise<PredictionMarket[]>;
|
|
getPredictionMarketById(id: string): Promise<PredictionMarket | undefined>;
|
|
createPredictionMarket(market: InsertPredictionMarket): Promise<PredictionMarket>;
|
|
}
|
|
|
|
export class DbStorage implements IStorage {
|
|
// In-memory Maps for hybrid storage approach
|
|
private outlets = new Map<string, MediaOutlet>();
|
|
private users = new Map<string, User>();
|
|
private articles = new Map<string, Article>();
|
|
private comments = new Map<string, Comment>();
|
|
private commentReactions = new Map<string, CommentReaction>();
|
|
private bookmarks = new Map<string, Bookmark>();
|
|
|
|
constructor() {
|
|
this.logDatabaseStats();
|
|
this.initializeDefaultData();
|
|
}
|
|
|
|
private async logDatabaseStats() {
|
|
try {
|
|
const outletCount = await db.select({ count: count() }).from(mediaOutlets);
|
|
const articleCount = await db.select({ count: count() }).from(articles);
|
|
console.log(`[DbStorage] Connected to database with ${outletCount[0].count} outlets and ${articleCount[0].count} articles`);
|
|
} catch (error) {
|
|
console.error('[DbStorage] Failed to connect to database:', error);
|
|
}
|
|
}
|
|
|
|
private async initializeDefaultData() {
|
|
// Initialize with new outlet structure based on requirements
|
|
const defaultOutlets = [
|
|
// People Category (4 outlets)
|
|
{
|
|
id: 'jacob-robert-steeves',
|
|
name: 'Jacob Robert Steeves',
|
|
description: 'Co-founder of Bittensor and primary architect of decentralized AI',
|
|
category: 'people',
|
|
focusSubject: 'Jacob Robert Steeves',
|
|
avatar: '/api/assets/jacob-steeves_1758526589973.png',
|
|
profileImage: '/api/assets/steeves thumbnail_1758526589975.png',
|
|
bio: 'Co-founder of Bittensor and a primary architect of its decentralized AI network.',
|
|
fullBio: [
|
|
'Co-founder of Bittensor and primary architect of the decentralized AI network protocol.',
|
|
'Visionary leader advocating for open, permissionless intelligence markets and AI democratization.',
|
|
'Technical expert directing core research in AI consensus mechanisms and protocol development.'
|
|
]
|
|
},
|
|
{
|
|
id: 'ala-shaabana',
|
|
name: 'Ala Shaabana',
|
|
description: 'Co-founder and key technical architect of Bittensor',
|
|
category: 'people',
|
|
focusSubject: 'Ala Shaabana',
|
|
avatar: '/api/assets/Ala Shaabana_1758526589971.jpeg',
|
|
profileImage: '/api/assets/ala thumbnail_1758526589972.png',
|
|
bio: 'A co-founder of Bittensor and a key technical architect of its decentralized AI network.',
|
|
fullBio: [
|
|
'Co-founder of Bittensor with a Ph.D. in Computer Science specializing in advanced AI and machine learning.',
|
|
'Primary architect of the Bittensor protocol\'s complex incentive and consensus mechanisms.',
|
|
'Known for technical precision and focus on scalability in decentralized AI network design.'
|
|
]
|
|
},
|
|
{
|
|
id: 'joseph-jacks',
|
|
name: 'Joseph Jacks',
|
|
description: 'Founder of Open Source Capital and Bittensor advocate',
|
|
category: 'people',
|
|
focusSubject: 'Joseph Jacks',
|
|
avatar: '/api/assets/Joseph Jacks_1758526589973.jpeg',
|
|
profileImage: '/api/assets/joseph thumbnail_1758526589974.png',
|
|
bio: 'Founder and General Partner of OSS Capital, a venture capital firm with a strong focus on open-source software.',
|
|
fullBio: [
|
|
'Founder and General Partner of OSS Capital, the first venture capital fund exclusively focused on commercial open-source software (COSS). Since 2018, has led over 40 funding rounds representing $200+ million in investments.',
|
|
'Entrepreneurial background includes founding Kismatic (first enterprise Kubernetes company, acquired by Apprenda), co-founding Aljabr cloud data management startup, and creating KubeCon conference now run by Linux Foundation.',
|
|
'Previously held strategic roles at Mesosphere (D2IQ), Enstratius (acquired by Dell), TIBCO Software, and Talend. Served as Entrepreneur in Residence at Quantum Corporation supporting the Rook project.',
|
|
'Visionary behind Open Core Summit, the global vendor-neutral conference for the COSS ecosystem, bringing together 1,000+ attendees from 29 countries, 40+ sponsors, and 100+ speakers annually.',
|
|
'Investment portfolio includes notable successes like Remix (acquired by Shopify), OpenBB (Bloomberg Terminal alternative), and dozens of open-source alternatives to major enterprise software platforms.',
|
|
'Limited partners include tech luminaries: WordPress co-creator Matt Mullenweg, Red Hat co-founder Bob Young, YouTube founders Chad Hurley and Steve Chen, GitHub co-founder Tom Preston-Werner, and Shopify founder Tobias Lütke.',
|
|
'Core investment philosophy: "Open source is eating software faster than software is eating the world" - believes open core approach will replace closed core SaaS companies entirely.',
|
|
'Serves on boards of multiple portfolio companies including Plane, OpenBB, DeSci Labs, and Liquid AI, actively guiding the next generation of open-source commercial enterprises.'
|
|
]
|
|
},
|
|
{
|
|
id: 'robert-myers',
|
|
name: 'Robert Myers',
|
|
description: 'CEO of Manifold Labs and former Opentensor Foundation co-founder',
|
|
category: 'people',
|
|
focusSubject: 'Robert Myers',
|
|
avatar: '/api/assets/Robert Myers_1758526589974.jpg',
|
|
profileImage: '/api/assets/robert thumbnail_1758526589974.png',
|
|
bio: 'Co-founder and former Marketing Director of Opentensor Foundation, currently CEO of Manifold Labs.',
|
|
fullBio: [
|
|
'Co-founder and former Marketing Director of Opentensor Foundation behind Bittensor.',
|
|
'Current CEO of Manifold Labs, AI infrastructure company funded by OSS Capital.',
|
|
'Focus on building critical tools and infrastructure for decentralized AI networks.'
|
|
]
|
|
},
|
|
// Topics Category (3 outlets)
|
|
{
|
|
id: 'alt-coin',
|
|
name: 'Alt Coin',
|
|
description: 'Coverage of alternative cryptocurrencies and emerging tokens',
|
|
category: 'topics',
|
|
focusSubject: 'Alt Coin',
|
|
avatar: '/api/assets/altcoin_1758526589973.jpeg',
|
|
profileImage: '/api/assets/alt coin news_1758526589972.png',
|
|
bio: 'A term for any cryptocurrency other than Bitcoin (BTC).',
|
|
fullBio: [
|
|
'Any cryptocurrency other than Bitcoin, built to solve problems like scalability, privacy, or smart contracts.',
|
|
'Highly volatile and speculative market with potential for massive gains and significant losses.',
|
|
'Success depends on community strength, network utility, and technological innovation.'
|
|
]
|
|
},
|
|
{
|
|
id: 'stable-coin',
|
|
name: 'Stable Coin',
|
|
description: 'Analysis of stablecoins and price-stable digital assets',
|
|
category: 'topics',
|
|
focusSubject: 'Stable Coin',
|
|
avatar: '/api/assets/stable coin_1758526589975.jpeg',
|
|
profileImage: '/api/assets/stable coin news_1758526589975.png',
|
|
bio: 'A class of cryptocurrencies designed to minimize price volatility, often pegged to a fiat currency like the US Dollar.',
|
|
fullBio: [
|
|
'Cryptocurrency designed to minimize price volatility, usually pegged to fiat currencies like USD.',
|
|
'Collateralized by fiat, other cryptocurrencies, or algorithmic mechanisms to maintain price stability.',
|
|
'Essential for cross-border transactions and DeFi by providing stable store of value.'
|
|
]
|
|
},
|
|
{
|
|
id: 'bittensor',
|
|
name: 'Bittensor',
|
|
description: 'Comprehensive coverage of the Bittensor network and ecosystem',
|
|
category: 'topics',
|
|
focusSubject: 'Bittensor',
|
|
avatar: '/api/assets/Bittensor_1758526589973.jpg',
|
|
profileImage: '/api/assets/Bittensor_1758526589973.jpg',
|
|
bio: 'A decentralized blockchain network focused on creating a global, open marketplace for artificial intelligence.',
|
|
fullBio: [
|
|
'Decentralized blockchain network creating a global marketplace for artificial intelligence.',
|
|
'Uses "Yuma Consensus" mechanism and specialized "Subnets" for AI tasks like language processing.',
|
|
'Native TAO token incentivizes participation and democratizes AI away from centralized corporate control.'
|
|
]
|
|
},
|
|
{
|
|
id: 'dat',
|
|
name: 'DAT',
|
|
description: 'Digital Asset Treasury strategies and corporate cryptocurrency adoption',
|
|
category: 'topics',
|
|
focusSubject: 'DAT',
|
|
avatar: '/api/assets/dat_default.jpeg',
|
|
profileImage: '/api/assets/dat_news_default.png',
|
|
bio: 'Digital Asset Treasury strategies helping corporations integrate cryptocurrency into their treasury management.',
|
|
fullBio: [
|
|
'Digital Asset Treasury strategies transforming corporate treasury management through cryptocurrency integration.',
|
|
'Comprehensive framework for institutional digital asset adoption including custody, compliance, and risk management.',
|
|
'Leading the transition from traditional corporate treasuries to multi-asset digital strategies.'
|
|
]
|
|
},
|
|
// Additional Topics Category outlets
|
|
{
|
|
id: 'blockchain',
|
|
name: 'Blockchain',
|
|
description: 'Comprehensive blockchain technology news and analysis',
|
|
category: 'topics',
|
|
focusSubject: 'Blockchain',
|
|
avatar: '/api/assets/blockchain_1758526589973.jpeg',
|
|
profileImage: '/api/assets/blockchain_news_1758526589972.png',
|
|
bio: 'The foundational technology behind cryptocurrencies and decentralized applications.',
|
|
fullBio: [
|
|
'Distributed ledger technology that maintains a continuously growing list of records.',
|
|
'Enables trustless transactions and smart contracts without central authority.',
|
|
'Revolutionary technology transforming finance, supply chain, and digital identity.'
|
|
]
|
|
},
|
|
{
|
|
id: 'defi',
|
|
name: 'DeFi',
|
|
description: 'Decentralized Finance protocols and innovations',
|
|
category: 'topics',
|
|
focusSubject: 'DeFi',
|
|
avatar: '/api/assets/defi_1758526589973.jpeg',
|
|
profileImage: '/api/assets/defi_news_1758526589972.png',
|
|
bio: 'Decentralized Financial services built on blockchain technology.',
|
|
fullBio: [
|
|
'Financial services using smart contracts instead of traditional intermediaries.',
|
|
'Includes lending, borrowing, trading, and yield farming protocols.',
|
|
'Democratizes access to financial services globally without traditional barriers.'
|
|
]
|
|
},
|
|
{
|
|
id: 'nft',
|
|
name: 'NFT',
|
|
description: 'Non-Fungible Tokens and digital collectibles market',
|
|
category: 'topics',
|
|
focusSubject: 'NFT',
|
|
avatar: '/api/assets/nft_1758526589973.jpeg',
|
|
profileImage: '/api/assets/nft_news_1758526589972.png',
|
|
bio: 'Unique digital assets representing ownership of digital or physical items.',
|
|
fullBio: [
|
|
'Non-fungible tokens that represent unique ownership of digital assets.',
|
|
'Revolutionizing art, gaming, music, and digital collectibles markets.',
|
|
'Enables creators to monetize digital content with verified scarcity.'
|
|
]
|
|
},
|
|
{
|
|
id: 'dao',
|
|
name: 'DAO',
|
|
description: 'Decentralized Autonomous Organizations and governance',
|
|
category: 'topics',
|
|
focusSubject: 'DAO',
|
|
avatar: '/api/assets/dao_1758526589973.jpeg',
|
|
profileImage: '/api/assets/dao_news_1758526589972.png',
|
|
bio: 'Organizations governed by smart contracts and community voting.',
|
|
fullBio: [
|
|
'Organizations governed entirely by smart contracts and token holder voting.',
|
|
'Enables transparent, democratic decision-making without traditional management.',
|
|
'Revolutionary organizational structure for the decentralized economy.'
|
|
]
|
|
},
|
|
{
|
|
id: 'metaverse',
|
|
name: 'Metaverse',
|
|
description: 'Virtual worlds and immersive digital experiences',
|
|
category: 'topics',
|
|
focusSubject: 'Metaverse',
|
|
avatar: '/api/assets/metaverse_1758526589973.jpeg',
|
|
profileImage: '/api/assets/metaverse_news_1758526589972.png',
|
|
bio: 'Persistent virtual worlds where users interact in immersive digital environments.',
|
|
fullBio: [
|
|
'Persistent virtual worlds enabling social interaction and economic activity.',
|
|
'Combines VR, AR, blockchain, and AI to create immersive digital experiences.',
|
|
'The future of social media, gaming, and digital commerce.'
|
|
]
|
|
},
|
|
{
|
|
id: 'ai-crypto',
|
|
name: 'AI Crypto',
|
|
description: 'Artificial Intelligence and cryptocurrency convergence',
|
|
category: 'topics',
|
|
focusSubject: 'AI Crypto',
|
|
avatar: '/api/assets/ai_crypto_1758526589973.jpeg',
|
|
profileImage: '/api/assets/ai_crypto_news_1758526589972.png',
|
|
bio: 'The intersection of artificial intelligence and cryptocurrency technologies.',
|
|
fullBio: [
|
|
'Intersection of artificial intelligence and cryptocurrency technologies.',
|
|
'AI-powered trading, predictive analytics, and automated market making.',
|
|
'Decentralized AI networks incentivized by cryptocurrency tokens.'
|
|
]
|
|
},
|
|
{
|
|
id: 'layer2',
|
|
name: 'Layer 2',
|
|
description: 'Blockchain scaling solutions and second-layer protocols',
|
|
category: 'topics',
|
|
focusSubject: 'Layer 2',
|
|
avatar: '/api/assets/layer2_1758526589973.jpeg',
|
|
profileImage: '/api/assets/layer2_news_1758526589972.png',
|
|
bio: 'Scaling solutions built on top of existing blockchain networks.',
|
|
fullBio: [
|
|
'Scaling solutions that process transactions off the main blockchain.',
|
|
'Reduces fees and increases transaction throughput significantly.',
|
|
'Critical infrastructure for blockchain mass adoption and usability.'
|
|
]
|
|
},
|
|
{
|
|
id: 'privacy-coins',
|
|
name: 'Privacy Coins',
|
|
description: 'Privacy-focused cryptocurrencies and anonymous transactions',
|
|
category: 'topics',
|
|
focusSubject: 'Privacy Coins',
|
|
avatar: '/api/assets/privacy_coins_1758526589973.jpeg',
|
|
profileImage: '/api/assets/privacy_coins_news_1758526589972.png',
|
|
bio: 'Cryptocurrencies designed to provide enhanced privacy and anonymity.',
|
|
fullBio: [
|
|
'Cryptocurrencies using advanced cryptography to ensure transaction privacy.',
|
|
'Protects user financial privacy from surveillance and data mining.',
|
|
'Essential for financial freedom and protection of personal information.'
|
|
]
|
|
},
|
|
{
|
|
id: 'gamefi',
|
|
name: 'GameFi',
|
|
description: 'Gaming and decentralized finance integration',
|
|
category: 'topics',
|
|
focusSubject: 'GameFi',
|
|
avatar: '/api/assets/gamefi_1758526589973.jpeg',
|
|
profileImage: '/api/assets/gamefi_news_1758526589972.png',
|
|
bio: 'Games that integrate DeFi elements and play-to-earn mechanics.',
|
|
fullBio: [
|
|
'Games that integrate DeFi elements and blockchain-based ownership.',
|
|
'Players earn cryptocurrency rewards for gameplay and participation.',
|
|
'Revolutionizing gaming economics through true digital asset ownership.'
|
|
]
|
|
},
|
|
{
|
|
id: 'socialfi',
|
|
name: 'SocialFi',
|
|
description: 'Social media platforms with financial incentives',
|
|
category: 'topics',
|
|
focusSubject: 'SocialFi',
|
|
avatar: '/api/assets/socialfi_1758526589973.jpeg',
|
|
profileImage: '/api/assets/socialfi_news_1758526589972.png',
|
|
bio: 'Social media platforms that reward users with cryptocurrency.',
|
|
fullBio: [
|
|
'Social media platforms that reward content creation and engagement.',
|
|
'Users earn tokens for creating quality content and building communities.',
|
|
'Aligns incentives between platforms, creators, and audiences.'
|
|
]
|
|
},
|
|
{
|
|
id: 'cbdc',
|
|
name: 'CBDC',
|
|
description: 'Central Bank Digital Currencies and government crypto',
|
|
category: 'topics',
|
|
focusSubject: 'CBDC',
|
|
avatar: '/api/assets/cbdc_1758526589973.jpeg',
|
|
profileImage: '/api/assets/cbdc_news_1758526589972.png',
|
|
bio: 'Digital versions of national currencies issued by central banks.',
|
|
fullBio: [
|
|
'Digital versions of fiat currencies issued and controlled by central banks.',
|
|
'Combines benefits of digital payments with government backing.',
|
|
'Represents governments adoption of blockchain technology for monetary policy.'
|
|
]
|
|
},
|
|
{
|
|
id: 'cross-chain',
|
|
name: 'Cross-Chain',
|
|
description: 'Blockchain interoperability and cross-chain protocols',
|
|
category: 'topics',
|
|
focusSubject: 'Cross-Chain',
|
|
avatar: '/api/assets/cross_chain_1758526589973.jpeg',
|
|
profileImage: '/api/assets/cross_chain_news_1758526589972.png',
|
|
bio: 'Technologies enabling communication and value transfer between different blockchains.',
|
|
fullBio: [
|
|
'Technologies enabling communication between different blockchain networks.',
|
|
'Allows assets and data to move freely across multiple chains.',
|
|
'Critical for blockchain ecosystem maturity and user experience.'
|
|
]
|
|
},
|
|
{
|
|
id: 'yield-farming',
|
|
name: 'Yield Farming',
|
|
description: 'DeFi yield generation strategies and liquidity mining',
|
|
category: 'topics',
|
|
focusSubject: 'Yield Farming',
|
|
avatar: '/api/assets/yield_farming_1758526589973.jpeg',
|
|
profileImage: '/api/assets/yield_farming_news_1758526589972.png',
|
|
bio: 'Strategies to maximize returns by providing liquidity to DeFi protocols.',
|
|
fullBio: [
|
|
'Strategies to maximize returns by providing liquidity to DeFi protocols.',
|
|
'Users lend or stake tokens to earn high yields and bonus rewards.',
|
|
'Core economic activity driving DeFi protocol growth and adoption.'
|
|
]
|
|
},
|
|
{
|
|
id: 'tokenomics',
|
|
name: 'Tokenomics',
|
|
description: 'Cryptocurrency token economics and design principles',
|
|
category: 'topics',
|
|
focusSubject: 'Tokenomics',
|
|
avatar: '/api/assets/tokenomics_1758526589973.jpeg',
|
|
profileImage: '/api/assets/tokenomics_news_1758526589972.png',
|
|
bio: 'The economic design and incentive structures of cryptocurrency tokens.',
|
|
fullBio: [
|
|
'Economic design and incentive structures behind cryptocurrency tokens.',
|
|
'Determines how tokens are distributed, used, and valued over time.',
|
|
'Critical factor in the long-term success of blockchain projects.'
|
|
]
|
|
},
|
|
{
|
|
id: 'regulation',
|
|
name: 'Regulation',
|
|
description: 'Cryptocurrency regulation and government policy',
|
|
category: 'topics',
|
|
focusSubject: 'Regulation',
|
|
avatar: '/api/assets/regulation_1758526589973.jpeg',
|
|
profileImage: '/api/assets/regulation_news_1758526589972.png',
|
|
bio: 'Government policies and regulations affecting the cryptocurrency industry.',
|
|
fullBio: [
|
|
'Government policies and regulations shaping the cryptocurrency industry.',
|
|
'Balances innovation, consumer protection, and financial stability.',
|
|
'Critical factor determining mainstream adoption and institutional investment.'
|
|
]
|
|
},
|
|
{
|
|
id: 'mining',
|
|
name: 'Mining',
|
|
description: 'Cryptocurrency mining and proof-of-work consensus',
|
|
category: 'topics',
|
|
focusSubject: 'Mining',
|
|
avatar: '/api/assets/mining_1758526589973.jpeg',
|
|
profileImage: '/api/assets/mining_news_1758526589972.png',
|
|
bio: 'The process of validating transactions and securing blockchain networks.',
|
|
fullBio: [
|
|
'Process of validating transactions and securing proof-of-work blockchains.',
|
|
'Miners compete to solve cryptographic puzzles for block rewards.',
|
|
'Essential infrastructure maintaining decentralization and network security.'
|
|
]
|
|
},
|
|
{
|
|
id: 'staking',
|
|
name: 'Staking',
|
|
description: 'Proof-of-stake validation and staking rewards',
|
|
category: 'topics',
|
|
focusSubject: 'Staking',
|
|
avatar: '/api/assets/staking_1758526589973.jpeg',
|
|
profileImage: '/api/assets/staking_news_1758526589972.png',
|
|
bio: 'Locking tokens to help secure proof-of-stake networks and earn rewards.',
|
|
fullBio: [
|
|
'Locking tokens to help validate transactions on proof-of-stake networks.',
|
|
'More energy-efficient alternative to proof-of-work mining.',
|
|
'Allows token holders to earn passive income while securing networks.'
|
|
]
|
|
},
|
|
{
|
|
id: 'institutional',
|
|
name: 'Institutional',
|
|
description: 'Institutional cryptocurrency adoption and investment',
|
|
category: 'topics',
|
|
focusSubject: 'Institutional',
|
|
avatar: '/api/assets/institutional_1758526589973.jpeg',
|
|
profileImage: '/api/assets/institutional_news_1758526589972.png',
|
|
bio: 'Large institutions and corporations adopting cryptocurrency.',
|
|
fullBio: [
|
|
'Large institutions and corporations adopting cryptocurrency investments.',
|
|
'Banks, hedge funds, and public companies adding crypto to portfolios.',
|
|
'Driving mainstream adoption and market maturation.'
|
|
]
|
|
},
|
|
{
|
|
id: 'derivatives',
|
|
name: 'Derivatives',
|
|
description: 'Cryptocurrency derivatives and financial instruments',
|
|
category: 'topics',
|
|
focusSubject: 'Derivatives',
|
|
avatar: '/api/assets/derivatives_1758526589973.jpeg',
|
|
profileImage: '/api/assets/derivatives_news_1758526589972.png',
|
|
bio: 'Financial instruments derived from cryptocurrency underlying assets.',
|
|
fullBio: [
|
|
'Financial instruments like futures, options, and swaps on cryptocurrencies.',
|
|
'Enables sophisticated trading strategies and risk management.',
|
|
'Critical infrastructure for institutional participation in crypto markets.'
|
|
]
|
|
},
|
|
// Additional People Category outlets
|
|
{
|
|
id: 'vitalik-buterin',
|
|
name: 'Vitalik Buterin',
|
|
description: 'Ethereum founder and blockchain visionary',
|
|
category: 'people',
|
|
focusSubject: 'Vitalik Buterin',
|
|
avatar: '/api/assets/vitalik_1758526589973.jpeg',
|
|
profileImage: '/api/assets/vitalik_news_1758526589972.png',
|
|
bio: 'Co-founder of Ethereum and one of the most influential figures in blockchain.',
|
|
fullBio: [
|
|
'Co-founder of Ethereum, the worlds second-largest cryptocurrency platform.',
|
|
'Visionary programmer who conceptualized smart contracts and decentralized applications.',
|
|
'Leading voice in blockchain scalability, governance, and decentralization.'
|
|
]
|
|
},
|
|
{
|
|
id: 'satoshi-nakamoto',
|
|
name: 'Satoshi Nakamoto',
|
|
description: 'Anonymous creator of Bitcoin and blockchain technology',
|
|
category: 'people',
|
|
focusSubject: 'Satoshi Nakamoto',
|
|
avatar: '/api/assets/satoshi_1758526589973.jpeg',
|
|
profileImage: '/api/assets/satoshi_news_1758526589972.png',
|
|
bio: 'Pseudonymous creator of Bitcoin, the first and most famous cryptocurrency.',
|
|
fullBio: [
|
|
'Pseudonymous creator of Bitcoin and inventor of blockchain technology.',
|
|
'Published the Bitcoin whitepaper in 2008, launching the cryptocurrency revolution.',
|
|
'Mysterious figure who disappeared from public view in 2011.'
|
|
]
|
|
},
|
|
{
|
|
id: 'changpeng-zhao',
|
|
name: 'Changpeng Zhao',
|
|
description: 'Former CEO of Binance and crypto exchange pioneer',
|
|
category: 'people',
|
|
focusSubject: 'Changpeng Zhao',
|
|
avatar: '/api/assets/cz_1758526589973.jpeg',
|
|
profileImage: '/api/assets/cz_news_1758526589972.png',
|
|
bio: 'Former CEO of Binance, the worlds largest cryptocurrency exchange.',
|
|
fullBio: [
|
|
'Former CEO of Binance, building it into the worlds largest crypto exchange.',
|
|
'Pioneered many innovations in cryptocurrency trading and DeFi.',
|
|
'Influential leader in global cryptocurrency adoption and regulation.'
|
|
]
|
|
},
|
|
{
|
|
id: 'brian-armstrong',
|
|
name: 'Brian Armstrong',
|
|
description: 'CEO of Coinbase and cryptocurrency adoption advocate',
|
|
category: 'people',
|
|
focusSubject: 'Brian Armstrong',
|
|
avatar: '/api/assets/brian_armstrong_1758526589973.jpeg',
|
|
profileImage: '/api/assets/brian_armstrong_news_1758526589972.png',
|
|
bio: 'CEO and co-founder of Coinbase, the largest US cryptocurrency exchange.',
|
|
fullBio: [
|
|
'CEO and co-founder of Coinbase, Americas leading cryptocurrency platform.',
|
|
'Advocate for clear cryptocurrency regulation and mainstream adoption.',
|
|
'Leading voice in bringing cryptocurrency to traditional financial institutions.'
|
|
]
|
|
},
|
|
{
|
|
id: 'andreas-antonopoulos',
|
|
name: 'Andreas Antonopoulos',
|
|
description: 'Bitcoin educator and blockchain technology advocate',
|
|
category: 'people',
|
|
focusSubject: 'Andreas Antonopoulos',
|
|
avatar: '/api/assets/andreas_1758526589973.jpeg',
|
|
profileImage: '/api/assets/andreas_news_1758526589972.png',
|
|
bio: 'Renowned Bitcoin educator and author of "Mastering Bitcoin."',
|
|
fullBio: [
|
|
'Renowned Bitcoin educator and author of "Mastering Bitcoin" and "Mastering Ethereum."',
|
|
'Passionate advocate for decentralization and financial sovereignty.',
|
|
'Influential speaker educating millions about cryptocurrency technology.'
|
|
]
|
|
},
|
|
{
|
|
id: 'michael-saylor',
|
|
name: 'Michael Saylor',
|
|
description: 'MicroStrategy CEO and Bitcoin maximalist',
|
|
category: 'people',
|
|
focusSubject: 'Michael Saylor',
|
|
avatar: '/api/assets/saylor_1758526589973.jpeg',
|
|
profileImage: '/api/assets/saylor_news_1758526589972.png',
|
|
bio: 'CEO of MicroStrategy and prominent Bitcoin advocate.',
|
|
fullBio: [
|
|
'Born February 4, 1965 in military family, graduated first in class from high school, earned full ROTC scholarship to MIT where he double-majored in aeronautical engineering and history of science, graduating with highest honors in 1987.',
|
|
'Founded MicroStrategy in 1989 with MIT fraternity brother Sanju Bansal, initially focused on business intelligence software. Won $10 million McDonald\'s contract in 1992, took company public in 1998.',
|
|
'Survived dot-com crash devastation when stock plummeted from $333 to $120 in single day (March 2000). Paid $350,000 SEC penalty plus $8.3 million disgorgement for financial reporting issues.',
|
|
'Prolific inventor holding 48+ patents, credited as inventor of relational analytics. Founded multiple companies including Alarm.com (NASDAQ: ALRM) and Angel.com (sold for $110M).',
|
|
'Author of "The Mobile Wave" (NYT/WSJ bestseller), founded Saylor Academy providing free education to 1.8+ million students. MIT Technology Review "Innovator Under 35" (1999).',
|
|
'Executive Chairman of MicroStrategy since 2022, previously CEO for 33 years. Led corporate Bitcoin adoption strategy purchasing 639,835+ bitcoins worth billions, making MSTR largest corporate Bitcoin holder.',
|
|
'Bitcoin maximalist advocate promoting cryptocurrency as superior store of value and inflation hedge. His Bitcoin strategy transformed MicroStrategy from traditional software company to Bitcoin proxy investment vehicle.'
|
|
]
|
|
},
|
|
{
|
|
id: 'elon-musk',
|
|
name: 'Elon Musk',
|
|
description: 'Tesla CEO and influential cryptocurrency commentator',
|
|
category: 'people',
|
|
focusSubject: 'Elon Musk',
|
|
avatar: '/api/assets/elon_1758526589973.jpeg',
|
|
profileImage: '/api/assets/elon_news_1758526589972.png',
|
|
bio: 'CEO of Tesla and SpaceX, influential voice in cryptocurrency markets.',
|
|
fullBio: [
|
|
'World\'s wealthiest person (net worth $384-$487 billion as of 2025), born June 28, 1971 in Pretoria, South Africa. Emigrated to avoid apartheid military service, studied at Queen\'s University and University of Pennsylvania (Economics + Physics degrees).',
|
|
'Early entrepreneur: Created and sold video game at age 12, co-founded Zip2 (sold for $307M), then X.com which merged to become PayPal (sold to eBay for $1.5B, Musk received $176M).',
|
|
'Founded SpaceX in 2002 with vision of Mars colonization, now leading private space company. First private company to send astronauts to ISS (2020), pioneered reusable rockets, operates Starlink satellite constellation.',
|
|
'CEO of Tesla since 2008, driving global electric vehicle revolution. Transformed company from startup to world\'s most valuable automaker with Model S, 3, X lineup and autonomous driving technology.',
|
|
'Acquired Twitter for $44 billion in 2022, rebranded to X as part of vision for "everything app." Also founded Neuralink (brain-machine interfaces), The Boring Company (tunnel infrastructure), and xAI (AI competitor to ChatGPT).',
|
|
'Briefly served as co-head of Department of Government Efficiency (DOGE) under Trump administration (January-May 2025) before returning focus to business ventures.',
|
|
'Known for 80-hour work weeks, visionary leadership in sustainable transport, space exploration, and artificial intelligence. His social media presence significantly impacts cryptocurrency and stock markets globally.'
|
|
]
|
|
},
|
|
{
|
|
id: 'gavin-wood',
|
|
name: 'Gavin Wood',
|
|
description: 'Polkadot founder and Ethereum co-founder',
|
|
category: 'people',
|
|
focusSubject: 'Gavin Wood',
|
|
avatar: '/api/assets/gavin_wood_1758526589973.jpeg',
|
|
profileImage: '/api/assets/gavin_wood_news_1758526589972.png',
|
|
bio: 'Co-founder of Ethereum and founder of Polkadot blockchain.',
|
|
fullBio: [
|
|
'Co-founder of Ethereum and creator of the Solidity programming language.',
|
|
'Founder of Polkadot, pioneering blockchain interoperability solutions.',
|
|
'Visionary technologist advancing multi-chain blockchain ecosystem.'
|
|
]
|
|
},
|
|
{
|
|
id: 'charles-hoskinson',
|
|
name: 'Charles Hoskinson',
|
|
description: 'Cardano founder and blockchain researcher',
|
|
category: 'people',
|
|
focusSubject: 'Charles Hoskinson',
|
|
avatar: '/api/assets/charles_1758526589973.jpeg',
|
|
profileImage: '/api/assets/charles_news_1758526589972.png',
|
|
bio: 'Founder of Cardano and co-founder of Ethereum.',
|
|
fullBio: [
|
|
'Founder of Cardano blockchain and co-founder of Ethereum.',
|
|
'Academic approach to blockchain development with peer-reviewed research.',
|
|
'Advocate for formal verification and scientific methodology in crypto.'
|
|
]
|
|
},
|
|
{
|
|
id: 'sergey-nazarov',
|
|
name: 'Sergey Nazarov',
|
|
description: 'Chainlink co-founder and oracle technology pioneer',
|
|
category: 'people',
|
|
focusSubject: 'Sergey Nazarov',
|
|
avatar: '/api/assets/sergey_1758526589973.jpeg',
|
|
profileImage: '/api/assets/sergey_news_1758526589972.png',
|
|
bio: 'Co-founder of Chainlink, the leading blockchain oracle network.',
|
|
fullBio: [
|
|
'Co-founder of Chainlink, providing real-world data to smart contracts.',
|
|
'Pioneer in blockchain oracle technology and decentralized data feeds.',
|
|
'Enabling smart contracts to interact with external data and systems.'
|
|
]
|
|
},
|
|
{
|
|
id: 'arthur-hayes',
|
|
name: 'Arthur Hayes',
|
|
description: 'Former BitMEX CEO and crypto derivatives pioneer',
|
|
category: 'people',
|
|
focusSubject: 'Arthur Hayes',
|
|
avatar: '/api/assets/arthur_hayes_1758526589973.jpeg',
|
|
profileImage: '/api/assets/arthur_hayes_news_1758526589972.png',
|
|
bio: 'Former CEO of BitMEX and pioneer in cryptocurrency derivatives.',
|
|
fullBio: [
|
|
'Former CEO of BitMEX, pioneering cryptocurrency derivatives trading.',
|
|
'Influential voice in crypto markets and monetary policy analysis.',
|
|
'Advocate for Bitcoin as alternative to traditional financial systems.'
|
|
]
|
|
},
|
|
{
|
|
id: 'elizabeth-stark',
|
|
name: 'Elizabeth Stark',
|
|
description: 'Lightning Labs CEO and Bitcoin Lightning Network advocate',
|
|
category: 'people',
|
|
focusSubject: 'Elizabeth Stark',
|
|
avatar: '/api/assets/elizabeth_stark_1758526589973.jpeg',
|
|
profileImage: '/api/assets/elizabeth_stark_news_1758526589972.png',
|
|
bio: 'CEO of Lightning Labs, developing Bitcoin Lightning Network scaling.',
|
|
fullBio: [
|
|
'CEO of Lightning Labs, building Bitcoin Lightning Network infrastructure.',
|
|
'Advocate for Bitcoin scalability and instant payment solutions.',
|
|
'Pioneer in layer-2 blockchain scaling technology and Bitcoin innovation.'
|
|
]
|
|
},
|
|
{
|
|
id: 'cathie-wood',
|
|
name: 'Cathie Wood',
|
|
description: 'ARK Invest CEO and innovation investor',
|
|
category: 'people',
|
|
focusSubject: 'Cathie Wood',
|
|
avatar: '/api/assets/cathie_wood_1758526589973.jpeg',
|
|
profileImage: '/api/assets/cathie_wood_news_1758526589972.png',
|
|
bio: 'CEO of ARK Invest, prominent investor in disruptive technologies.',
|
|
fullBio: [
|
|
'CEO of ARK Invest, focusing on disruptive innovation investments.',
|
|
'Strong advocate for Bitcoin and cryptocurrency adoption.',
|
|
'Influential voice connecting traditional investing with crypto markets.'
|
|
]
|
|
},
|
|
{
|
|
id: 'jack-dorsey',
|
|
name: 'Jack Dorsey',
|
|
description: 'Former Twitter CEO and Bitcoin advocate',
|
|
category: 'people',
|
|
focusSubject: 'Jack Dorsey',
|
|
avatar: '/api/assets/jack_dorsey_1758526589973.jpeg',
|
|
profileImage: '/api/assets/jack_dorsey_news_1758526589972.png',
|
|
bio: 'Former CEO of Twitter and Square, passionate Bitcoin advocate.',
|
|
fullBio: [
|
|
'Former CEO of Twitter and Square, passionate about Bitcoin adoption.',
|
|
'Building decentralized social media and Bitcoin infrastructure.',
|
|
'Advocate for Bitcoin as tool for global financial inclusion.'
|
|
]
|
|
},
|
|
{
|
|
id: 'dan-larimer',
|
|
name: 'Dan Larimer',
|
|
description: 'Blockchain developer and EOS creator',
|
|
category: 'people',
|
|
focusSubject: 'Dan Larimer',
|
|
avatar: '/api/assets/dan_larimer_1758526589973.jpeg',
|
|
profileImage: '/api/assets/dan_larimer_news_1758526589972.png',
|
|
bio: 'Creator of EOS, Steemit, and BitShares blockchain platforms.',
|
|
fullBio: [
|
|
'Creator of multiple blockchain platforms including EOS and BitShares.',
|
|
'Pioneer in delegated proof-of-stake consensus mechanisms.',
|
|
'Innovative developer focused on blockchain scalability and user experience.'
|
|
]
|
|
},
|
|
{
|
|
id: 'cameron-winklevoss',
|
|
name: 'Cameron Winklevoss',
|
|
description: 'Gemini co-founder and crypto entrepreneur',
|
|
category: 'people',
|
|
focusSubject: 'Cameron Winklevoss',
|
|
avatar: '/api/assets/cameron_1758526589973.jpeg',
|
|
profileImage: '/api/assets/cameron_news_1758526589972.png',
|
|
bio: 'Co-founder of Gemini cryptocurrency exchange.',
|
|
fullBio: [
|
|
'Co-founder of Gemini cryptocurrency exchange with twin brother Tyler.',
|
|
'Early Bitcoin investor and advocate for cryptocurrency regulation.',
|
|
'Entrepreneur bridging traditional finance with digital assets.'
|
|
]
|
|
},
|
|
{
|
|
id: 'tyler-winklevoss',
|
|
name: 'Tyler Winklevoss',
|
|
description: 'Gemini co-founder and digital asset advocate',
|
|
category: 'people',
|
|
focusSubject: 'Tyler Winklevoss',
|
|
avatar: '/api/assets/tyler_1758526589973.jpeg',
|
|
profileImage: '/api/assets/tyler_news_1758526589972.png',
|
|
bio: 'Co-founder of Gemini cryptocurrency exchange.',
|
|
fullBio: [
|
|
'Co-founder of Gemini cryptocurrency exchange with twin brother Cameron.',
|
|
'Pioneer in cryptocurrency compliance and regulatory engagement.',
|
|
'Advocate for institutional-grade cryptocurrency infrastructure.'
|
|
]
|
|
},
|
|
{
|
|
id: 'roger-ver',
|
|
name: 'Roger Ver',
|
|
description: 'Bitcoin Cash advocate and early Bitcoin investor',
|
|
category: 'people',
|
|
focusSubject: 'Roger Ver',
|
|
avatar: '/api/assets/roger_ver_1758526589973.jpeg',
|
|
profileImage: '/api/assets/roger_ver_news_1758526589972.png',
|
|
bio: 'Early Bitcoin investor and advocate, known as "Bitcoin Jesus."',
|
|
fullBio: [
|
|
'Early Bitcoin investor and evangelist, known as "Bitcoin Jesus."',
|
|
'Prominent advocate for Bitcoin Cash and cryptocurrency adoption.',
|
|
'Entrepreneur focused on peer-to-peer electronic cash systems.'
|
|
]
|
|
},
|
|
{
|
|
id: 'palmer-luckey',
|
|
name: 'Palmer Luckey',
|
|
description: 'Oculus VR founder and Anduril Industries CEO, pioneering VR/AR and defense tech',
|
|
category: 'people',
|
|
focusSubject: 'Palmer Luckey',
|
|
avatar: '/api/assets/palmer_luckey_1758526589973.jpeg',
|
|
profileImage: '/api/assets/palmer_luckey_profile_1758526589973.jpeg',
|
|
bio: 'Founder of Oculus VR and current CEO of Anduril Industries, pioneering virtual reality and defense technology.',
|
|
fullBio: [
|
|
'Founded Oculus VR at age 20, revolutionizing virtual reality technology before selling to Facebook for $2 billion.',
|
|
'Currently CEO of Anduril Industries, developing AI-powered defense systems and autonomous weapons platforms.',
|
|
'Visionary entrepreneur bridging gaming technology, military applications, and next-generation computing interfaces.'
|
|
]
|
|
},
|
|
{
|
|
id: 'mike-novogratz',
|
|
name: 'Mike Novogratz',
|
|
description: 'CEO of Galaxy Digital and crypto investment pioneer',
|
|
category: 'people',
|
|
focusSubject: 'Mike Novogratz',
|
|
avatar: '/api/assets/mike novogratz_1759136098707.jpg',
|
|
profileImage: '/api/assets/mike novogratz_1759136098707.jpg',
|
|
bio: 'CEO and founder of Galaxy Digital, a leading cryptocurrency investment firm.',
|
|
fullBio: [
|
|
'CEO and founder of Galaxy Digital, one of the largest cryptocurrency investment firms.',
|
|
'Former Goldman Sachs partner and Fortress Investment Group principal with 20+ years Wall Street experience.',
|
|
'Early Bitcoin advocate and institutional crypto adoption pioneer, managing billions in digital assets.'
|
|
]
|
|
},
|
|
{
|
|
id: 'michael-j-saylor',
|
|
name: 'Michael J. Saylor',
|
|
description: 'MicroStrategy CEO and Bitcoin maximalist',
|
|
category: 'people',
|
|
focusSubject: 'Michael J. Saylor',
|
|
avatar: '/api/assets/michael j. saylor_1759136096272.jpg',
|
|
profileImage: '/api/assets/michael j. saylor_1759136096272.jpg',
|
|
bio: 'CEO of MicroStrategy and leading advocate for Bitcoin as a treasury reserve asset.',
|
|
fullBio: [
|
|
'CEO of MicroStrategy, the first major corporation to adopt Bitcoin as primary treasury reserve asset.',
|
|
'Led MicroStrategy to purchase over $5 billion worth of Bitcoin, pioneering corporate crypto adoption.',
|
|
'Prominent Bitcoin maximalist and advocate for digital asset treasury strategies among corporations.'
|
|
]
|
|
},
|
|
// Companies Category (additional outlets)
|
|
{
|
|
id: 'coinbase',
|
|
name: 'Coinbase',
|
|
description: 'Leading cryptocurrency exchange and platform',
|
|
category: 'companies',
|
|
focusSubject: 'Coinbase',
|
|
avatar: '/api/assets/coinbase_1758526589973.jpeg',
|
|
profileImage: '/api/assets/coinbase_news_1758526589972.png',
|
|
bio: 'Leading cryptocurrency exchange and platform in the United States.',
|
|
fullBio: [
|
|
'Largest cryptocurrency exchange in the United States, publicly traded.',
|
|
'Provides easy-to-use platform for buying, selling, and storing cryptocurrencies.',
|
|
'Pioneer in regulatory compliance and institutional cryptocurrency services.'
|
|
]
|
|
},
|
|
{
|
|
id: 'binance',
|
|
name: 'Binance',
|
|
description: 'Worlds largest cryptocurrency exchange by volume',
|
|
category: 'companies',
|
|
focusSubject: 'Binance',
|
|
avatar: '/api/assets/binance_1758526589973.jpeg',
|
|
profileImage: '/api/assets/binance_news_1758526589972.png',
|
|
bio: 'The worlds largest cryptocurrency exchange by trading volume.',
|
|
fullBio: [
|
|
'Worlds largest cryptocurrency exchange by trading volume and users.',
|
|
'Comprehensive ecosystem including spot trading, futures, staking, and DeFi.',
|
|
'Global platform serving millions of users in over 100 countries.'
|
|
]
|
|
},
|
|
{
|
|
id: 'galaxy-digital',
|
|
name: 'Galaxy Digital',
|
|
description: 'Leading cryptocurrency investment and trading firm',
|
|
category: 'companies',
|
|
focusSubject: 'Galaxy Digital',
|
|
avatar: '/api/assets/galaxy_1759136096271.jpeg',
|
|
profileImage: '/api/assets/galaxy_1759136096271.jpeg',
|
|
bio: 'Leading cryptocurrency investment firm and digital asset merchant bank.',
|
|
fullBio: [
|
|
'Leading cryptocurrency investment firm and digital asset merchant bank founded by Mike Novogratz.',
|
|
'Provides institutional-grade cryptocurrency trading, investment management, and advisory services.',
|
|
'Publicly traded company (TSX: GLXY) serving institutions and high-net-worth investors in digital assets.'
|
|
]
|
|
},
|
|
{
|
|
id: 'microstrategy',
|
|
name: 'MicroStrategy',
|
|
description: 'Business intelligence company with major Bitcoin holdings',
|
|
category: 'companies',
|
|
focusSubject: 'MicroStrategy',
|
|
avatar: '/api/assets/microstrategy_1759136096272.webp',
|
|
profileImage: '/api/assets/microstrategy_1759136096272.webp',
|
|
bio: 'Business intelligence company with one of the largest corporate Bitcoin treasuries.',
|
|
fullBio: [
|
|
'Business intelligence software company with massive Bitcoin treasury.',
|
|
'First major corporation to adopt Bitcoin as primary reserve asset.',
|
|
'Pioneer in corporate Bitcoin adoption and treasury diversification strategy.'
|
|
]
|
|
},
|
|
{
|
|
id: 'tesla',
|
|
name: 'Tesla',
|
|
description: 'Electric vehicle company with cryptocurrency investments',
|
|
category: 'companies',
|
|
focusSubject: 'Tesla',
|
|
avatar: '/api/assets/tesla_1758526589973.jpeg',
|
|
profileImage: '/api/assets/tesla_news_1758526589972.png',
|
|
bio: 'Electric vehicle manufacturer with significant cryptocurrency holdings.',
|
|
fullBio: [
|
|
'Electric vehicle and clean energy company with Bitcoin investments.',
|
|
'Pioneered corporate cryptocurrency adoption and payment acceptance.',
|
|
'Leading voice in sustainable Bitcoin mining and renewable energy.'
|
|
]
|
|
},
|
|
{
|
|
id: 'paypal',
|
|
name: 'PayPal',
|
|
description: 'Digital payments company offering cryptocurrency services',
|
|
category: 'companies',
|
|
focusSubject: 'PayPal',
|
|
avatar: '/api/assets/paypal_1758526589973.jpeg',
|
|
profileImage: '/api/assets/paypal_news_1758526589972.png',
|
|
bio: 'Digital payments company providing cryptocurrency buying and selling services.',
|
|
fullBio: [
|
|
'Global digital payments leader offering cryptocurrency services.',
|
|
'Enables millions of users to buy, sell, and hold cryptocurrencies.',
|
|
'Bridging traditional payments with digital asset adoption.'
|
|
]
|
|
},
|
|
{
|
|
id: 'square',
|
|
name: 'Square',
|
|
description: 'Financial services company with Bitcoin integration',
|
|
category: 'companies',
|
|
focusSubject: 'Square',
|
|
avatar: '/api/assets/square_1758526589973.jpeg',
|
|
profileImage: '/api/assets/square_news_1758526589972.png',
|
|
bio: 'Financial services and mobile payment company with Bitcoin integration.',
|
|
fullBio: [
|
|
'Financial services company integrating Bitcoin into payment solutions.',
|
|
'Cash App provides easy Bitcoin buying and selling for consumers.',
|
|
'Advocate for Bitcoin adoption and Lightning Network development.'
|
|
]
|
|
},
|
|
{
|
|
id: 'grayscale',
|
|
name: 'Grayscale',
|
|
description: 'Digital asset investment management company',
|
|
category: 'companies',
|
|
focusSubject: 'Grayscale',
|
|
avatar: '/api/assets/grayscale_1758526589973.jpeg',
|
|
profileImage: '/api/assets/grayscale_news_1758526589972.png',
|
|
bio: 'Leading digital asset investment management company.',
|
|
fullBio: [
|
|
'Leading digital asset investment manager with billions under management.',
|
|
'Provides institutional and accredited investor access to cryptocurrencies.',
|
|
'Pioneer in cryptocurrency investment products and regulatory compliance.'
|
|
]
|
|
},
|
|
{
|
|
id: 'chainlink',
|
|
name: 'Chainlink',
|
|
description: 'Decentralized oracle network connecting blockchains to real world',
|
|
category: 'companies',
|
|
focusSubject: 'Chainlink',
|
|
avatar: '/api/assets/chainlink_1758526589973.jpeg',
|
|
profileImage: '/api/assets/chainlink_news_1758526589972.png',
|
|
bio: 'Decentralized oracle network providing real-world data to smart contracts.',
|
|
fullBio: [
|
|
'Leading decentralized oracle network connecting blockchains to real-world data.',
|
|
'Enables smart contracts to securely interact with external data feeds.',
|
|
'Critical infrastructure powering DeFi and blockchain applications.'
|
|
]
|
|
},
|
|
{
|
|
id: 'ethereum-foundation',
|
|
name: 'Ethereum Foundation',
|
|
description: 'Non-profit supporting Ethereum blockchain development',
|
|
category: 'companies',
|
|
focusSubject: 'Ethereum Foundation',
|
|
avatar: '/api/assets/ethereum_foundation_1758526589973.jpeg',
|
|
profileImage: '/api/assets/ethereum_foundation_news_1758526589972.png',
|
|
bio: 'Non-profit organization supporting Ethereum blockchain development.',
|
|
fullBio: [
|
|
'Non-profit organization supporting Ethereum blockchain development and research.',
|
|
'Funds core protocol development and ecosystem growth initiatives.',
|
|
'Steward of the Ethereum networks evolution and decentralization.'
|
|
]
|
|
},
|
|
{
|
|
id: 'consensys',
|
|
name: 'ConsenSys',
|
|
description: 'Ethereum software company and blockchain infrastructure',
|
|
category: 'companies',
|
|
focusSubject: 'ConsenSys',
|
|
avatar: '/api/assets/consensys_1758526589973.jpeg',
|
|
profileImage: '/api/assets/consensys_news_1758526589972.png',
|
|
bio: 'Leading Ethereum software company building blockchain infrastructure.',
|
|
fullBio: [
|
|
'Leading Ethereum software company building decentralized applications.',
|
|
'Creates tools and infrastructure for Web3 and DeFi applications.',
|
|
'MetaMask wallet provider serving millions of Ethereum users globally.'
|
|
]
|
|
},
|
|
{
|
|
id: 'ripple',
|
|
name: 'Ripple',
|
|
description: 'Digital payment protocol for global financial institutions',
|
|
category: 'companies',
|
|
focusSubject: 'Ripple',
|
|
avatar: '/api/assets/ripple_1758526589973.jpeg',
|
|
profileImage: '/api/assets/ripple_news_1758526589972.png',
|
|
bio: 'Digital payment protocol company serving global financial institutions.',
|
|
fullBio: [
|
|
'Digital payment protocol company serving banks and financial institutions.',
|
|
'Enables fast, low-cost cross-border payments using XRP cryptocurrency.',
|
|
'Bridging traditional banking with modern blockchain payment solutions.'
|
|
]
|
|
},
|
|
{
|
|
id: 'circle',
|
|
name: 'Circle',
|
|
description: 'Financial technology company behind USDC stablecoin',
|
|
category: 'companies',
|
|
focusSubject: 'Circle',
|
|
avatar: '/api/assets/circle_1758526589973.jpeg',
|
|
profileImage: '/api/assets/circle_news_1758526589972.png',
|
|
bio: 'Financial technology company behind USDC stablecoin.',
|
|
fullBio: [
|
|
'Financial technology company issuing USDC, second-largest stablecoin.',
|
|
'Provides institutional-grade digital asset infrastructure and services.',
|
|
'Pioneer in regulated stablecoin issuance and digital dollar adoption.'
|
|
]
|
|
},
|
|
{
|
|
id: 'kraken',
|
|
name: 'Kraken',
|
|
description: 'Veteran cryptocurrency exchange and trading platform',
|
|
category: 'companies',
|
|
focusSubject: 'Kraken',
|
|
avatar: '/api/assets/kraken_1758526589973.jpeg',
|
|
profileImage: '/api/assets/kraken_news_1758526589972.png',
|
|
bio: 'Veteran cryptocurrency exchange known for security and advanced trading.',
|
|
fullBio: [
|
|
'Long-standing cryptocurrency exchange known for security and reliability.',
|
|
'Offers advanced trading features and institutional cryptocurrency services.',
|
|
'Pioneer in cryptocurrency market analysis and regulatory compliance.'
|
|
]
|
|
},
|
|
{
|
|
id: 'ftx',
|
|
name: 'FTX',
|
|
description: 'Former major cryptocurrency exchange and derivatives platform',
|
|
category: 'companies',
|
|
focusSubject: 'FTX',
|
|
avatar: '/api/assets/ftx_1758526589973.jpeg',
|
|
profileImage: '/api/assets/ftx_news_1758526589972.png',
|
|
bio: 'Former major cryptocurrency exchange that collapsed amid fraud allegations.',
|
|
fullBio: [
|
|
'Former major cryptocurrency exchange that collapsed in November 2022.',
|
|
'Once a leading platform for crypto derivatives and institutional trading.',
|
|
'Bankruptcy and fraud case serving as cautionary tale for crypto industry.'
|
|
]
|
|
},
|
|
{
|
|
id: 'alameda-research',
|
|
name: 'Alameda Research',
|
|
description: 'Former quantitative trading firm in cryptocurrency markets',
|
|
category: 'companies',
|
|
focusSubject: 'Alameda Research',
|
|
avatar: '/api/assets/alameda_1758526589973.jpeg',
|
|
profileImage: '/api/assets/alameda_news_1758526589972.png',
|
|
bio: 'Former quantitative trading firm associated with FTX collapse.',
|
|
fullBio: [
|
|
'Former quantitative cryptocurrency trading firm founded by Sam Bankman-Fried.',
|
|
'Involved in the FTX collapse and subsequent fraud investigations.',
|
|
'Case study in risk management and conflicts of interest in crypto trading.'
|
|
]
|
|
},
|
|
{
|
|
id: 'celsius',
|
|
name: 'Celsius',
|
|
description: 'Former cryptocurrency lending platform that filed for bankruptcy',
|
|
category: 'companies',
|
|
focusSubject: 'Celsius',
|
|
avatar: '/api/assets/celsius_1758526589973.jpeg',
|
|
profileImage: '/api/assets/celsius_news_1758526589972.png',
|
|
bio: 'Former cryptocurrency lending platform that filed for bankruptcy.',
|
|
fullBio: [
|
|
'Former cryptocurrency lending platform offering high yields to depositors.',
|
|
'Filed for bankruptcy in 2022 amid liquidity crisis and regulatory issues.',
|
|
'Cautionary tale about risks in unregulated cryptocurrency lending.'
|
|
]
|
|
},
|
|
{
|
|
id: 'three-arrows-capital',
|
|
name: 'Three Arrows Capital',
|
|
description: 'Former cryptocurrency hedge fund that collapsed',
|
|
category: 'companies',
|
|
focusSubject: 'Three Arrows Capital',
|
|
avatar: '/api/assets/3ac_1758526589973.jpeg',
|
|
profileImage: '/api/assets/3ac_news_1758526589972.png',
|
|
bio: 'Former prominent cryptocurrency hedge fund that collapsed in 2022.',
|
|
fullBio: [
|
|
'Former prominent cryptocurrency hedge fund managing billions in assets.',
|
|
'Collapsed in 2022 due to excessive leverage and poor risk management.',
|
|
'Bankruptcy had widespread impacts across cryptocurrency markets and DeFi.'
|
|
]
|
|
},
|
|
// Companies Category (4 outlets)
|
|
{
|
|
id: 'xtao',
|
|
name: 'xTAO',
|
|
description: 'Publicly traded infrastructure company for the Bittensor ecosystem',
|
|
category: 'companies',
|
|
focusSubject: 'xTAO',
|
|
avatar: '/api/assets/xtao_logo_1758526589976.jpg',
|
|
profileImage: '/api/assets/xTAO news_1758526589976.png',
|
|
bio: 'A publicly traded company listed on the TSX Venture Exchange, focused on building infrastructure for the Bittensor ecosystem.',
|
|
fullBio: [
|
|
'Publicly traded company on TSX Venture Exchange building infrastructure for Bittensor ecosystem.',
|
|
'High-performance validator holding significant TAO token treasury for staking and network security.',
|
|
'Provides regulated entry point for institutional investors seeking decentralized AI exposure.'
|
|
]
|
|
},
|
|
{
|
|
id: 'yuma',
|
|
name: 'YUMA',
|
|
description: 'Leading accelerator and investment firm for the Bittensor ecosystem',
|
|
category: 'companies',
|
|
focusSubject: 'YUMA',
|
|
avatar: '/api/assets/yuma_1758526589977.png',
|
|
profileImage: '/api/assets/yuma news_1758526589976.png',
|
|
bio: 'A leading accelerator and investment firm focused exclusively on the Bittensor ecosystem.',
|
|
fullBio: [
|
|
'Leading accelerator and investment firm focused exclusively on the Bittensor ecosystem.',
|
|
'Provides capital, technical resources, and community connections for building new Subnets.',
|
|
'Known for strong due diligence and nurturing successful high-performing Subnet projects.'
|
|
]
|
|
},
|
|
{
|
|
id: 'taox',
|
|
name: 'TAOX',
|
|
description: 'Public investment vehicle for Bittensor ecosystem exposure',
|
|
category: 'companies',
|
|
focusSubject: 'TAOX',
|
|
avatar: '/api/assets/taox_1758526589975.jpeg',
|
|
profileImage: '/api/assets/taox news_1758526589975.png',
|
|
bio: 'Public investment vehicle focused on providing exposure to the Bittensor ecosystem.',
|
|
fullBio: [
|
|
'Public investment vehicle focused on providing exposure to the Bittensor ecosystem.',
|
|
'Specializes in acquiring, holding, and staking TAO tokens for institutional investors.',
|
|
'Bridges conventional financial markets with decentralized AI sector opportunities.'
|
|
]
|
|
},
|
|
{
|
|
id: 'oblong',
|
|
name: 'Oblong',
|
|
description: 'Spatial computing and collaborative interface technology company',
|
|
category: 'companies',
|
|
focusSubject: 'Oblong',
|
|
avatar: '/api/assets/oblong_1758526589974.png',
|
|
profileImage: '/api/assets/oblong_1758526589974.png',
|
|
bio: 'An innovative technology company focused on spatial computing and collaborative interfaces.',
|
|
fullBio: [
|
|
'Technology company pioneering spatial computing and gesture-based collaborative interfaces.',
|
|
'Develops enterprise visualization solutions and intuitive human-computer interaction technologies.',
|
|
'Focus on immersive workspace solutions and next-generation user interface design.'
|
|
]
|
|
},
|
|
// Football Clubs - Topics Category (2 outlets)
|
|
{
|
|
id: 'manchester-city',
|
|
name: 'Manchester City F.C.',
|
|
description: 'English professional football club based in Manchester',
|
|
category: 'topics',
|
|
focusSubject: 'Manchester City',
|
|
avatar: '/api/assets/Manchester City F.C. _1759157887061.png',
|
|
profileImage: '/api/assets/Manchester City F.C. _1759157887061.png',
|
|
bio: 'English professional football club competing in the Premier League.',
|
|
fullBio: [
|
|
'One of the most successful English clubs in recent years with multiple Premier League titles.',
|
|
'Known for their attacking style of play under manager Pep Guardiola.',
|
|
'Regular competitors in UEFA Champions League with state-of-the-art training facilities.'
|
|
]
|
|
},
|
|
{
|
|
id: 'liverpool-fc',
|
|
name: 'Liverpool F.C.',
|
|
description: 'English professional football club based in Liverpool',
|
|
category: 'topics',
|
|
focusSubject: 'Liverpool',
|
|
avatar: '/api/assets/Liverpool F.C. _1759157885432.png',
|
|
profileImage: '/api/assets/Liverpool F.C. _1759157885432.png',
|
|
bio: 'English professional football club competing in the Premier League.',
|
|
fullBio: [
|
|
'One of the most successful clubs in English and European football history.',
|
|
'Known for their passionate supporters and the famous "You\'ll Never Walk Alone" anthem.',
|
|
'Six-time European Cup/Champions League winners with a rich footballing heritage.'
|
|
]
|
|
},
|
|
// Football Players - People Category (5 outlets)
|
|
{
|
|
id: 'erling-haaland',
|
|
name: 'Erling Haaland',
|
|
description: 'Norwegian professional footballer playing for Manchester City',
|
|
category: 'people',
|
|
focusSubject: 'Erling Haaland',
|
|
avatar: '/api/assets/default-player.png',
|
|
profileImage: '/api/assets/default-player.png',
|
|
bio: 'Norwegian striker for Manchester City and the Norway national team.',
|
|
fullBio: [
|
|
'Prolific goalscorer known for his speed, strength, and clinical finishing ability.',
|
|
'Record-breaking striker who has dominated every league he has played in.',
|
|
'One of the most promising young talents in world football with incredible goal-scoring records.'
|
|
]
|
|
},
|
|
{
|
|
id: 'mohamed-salah',
|
|
name: 'Mohamed Salah',
|
|
description: 'Egyptian professional footballer playing for Liverpool',
|
|
category: 'people',
|
|
focusSubject: 'Mohamed Salah',
|
|
avatar: '/api/assets/default-player.png',
|
|
profileImage: '/api/assets/default-player.png',
|
|
bio: 'Egyptian winger and forward for Liverpool and the Egypt national team.',
|
|
fullBio: [
|
|
'Prolific winger and forward known for his pace, dribbling, and goal-scoring ability.',
|
|
'Liverpool legend and one of the Premier League\'s all-time leading scorers.',
|
|
'Egyptian icon and captain of the national team with numerous individual awards.'
|
|
]
|
|
},
|
|
{
|
|
id: 'alexis-mac-allister',
|
|
name: 'Alexis Mac Allister',
|
|
description: 'Argentine professional footballer playing for Liverpool',
|
|
category: 'people',
|
|
focusSubject: 'Alexis Mac Allister',
|
|
avatar: '/api/assets/default-player.png',
|
|
profileImage: '/api/assets/default-player.png',
|
|
bio: 'Argentine central midfielder for Liverpool and the Argentina national team.',
|
|
fullBio: [
|
|
'Versatile midfielder known for his passing ability, work rate, and tactical intelligence.',
|
|
'World Cup winner with Argentina and key player in their recent international successes.',
|
|
'Adaptable player capable of playing multiple midfield roles with excellent technical skills.'
|
|
]
|
|
}
|
|
];
|
|
|
|
for (const outlet of defaultOutlets) {
|
|
const mediaOutlet: MediaOutlet = {
|
|
...outlet,
|
|
avatar: outlet.avatar || null,
|
|
profileImage: outlet.profileImage || null,
|
|
fullBio: (outlet as any).fullBio || null,
|
|
wikiProfile: null
|
|
};
|
|
this.outlets.set(outlet.id, mediaOutlet);
|
|
}
|
|
|
|
console.log(`[MemStorage] Initialized with ${defaultOutlets.length} outlets`);
|
|
|
|
// Load articles from articles_final.json
|
|
try {
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
const articlesPath = path.join(__dirname, '../articles_final.json');
|
|
const articlesRaw = fs.readFileSync(articlesPath, 'utf-8');
|
|
const articlesData = JSON.parse(articlesRaw);
|
|
|
|
for (const article of articlesData) {
|
|
const articleWithDate: Article = {
|
|
...article,
|
|
publishedAt: typeof article.publishedAt === 'string' ? new Date(article.publishedAt) : article.publishedAt
|
|
};
|
|
this.articles.set(article.id, articleWithDate);
|
|
}
|
|
|
|
console.log(`[MemStorage] Loaded ${this.articles.size} articles`);
|
|
} catch (error) {
|
|
console.error('[MemStorage] Failed to load articles:', error);
|
|
}
|
|
}
|
|
|
|
// User methods
|
|
async getUser(id: string): Promise<User | undefined> {
|
|
return this.users.get(id);
|
|
}
|
|
|
|
async getUserByUsername(username: string): Promise<User | undefined> {
|
|
return Array.from(this.users.values()).find(user => user.username === username);
|
|
}
|
|
|
|
async createUser(user: InsertUser): Promise<User> {
|
|
const newUser: User = {
|
|
id: randomUUID(),
|
|
...user,
|
|
avatar: user.avatar || null,
|
|
preferredLanguage: user.preferredLanguage || null
|
|
};
|
|
this.users.set(newUser.id, newUser);
|
|
return newUser;
|
|
}
|
|
|
|
// Media outlet methods
|
|
async getAllOutlets(): Promise<MediaOutlet[]> {
|
|
return Array.from(this.outlets.values()).sort((a, b) => a.name.localeCompare(b.name));
|
|
}
|
|
|
|
async getOutletsByCategory(category: string): Promise<MediaOutlet[]> {
|
|
return Array.from(this.outlets.values())
|
|
.filter(outlet => outlet.category === category)
|
|
.sort((a, b) => a.name.localeCompare(b.name));
|
|
}
|
|
|
|
async getOutletById(id: string): Promise<MediaOutlet | undefined> {
|
|
return this.outlets.get(id);
|
|
}
|
|
|
|
async createOutlet(outlet: InsertMediaOutlet): Promise<MediaOutlet> {
|
|
const newOutlet: MediaOutlet = {
|
|
id: randomUUID(),
|
|
...outlet,
|
|
avatar: outlet.avatar || null,
|
|
profileImage: outlet.profileImage || null,
|
|
fullBio: outlet.fullBio || null,
|
|
wikiProfile: outlet.wikiProfile || null
|
|
};
|
|
|
|
try {
|
|
await db.insert(mediaOutlets).values(newOutlet);
|
|
return newOutlet;
|
|
} catch (error) {
|
|
console.error('Error inserting outlet into database:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async deleteOutlet(id: string): Promise<boolean> {
|
|
try {
|
|
const result = await db.delete(mediaOutlets).where(eq(mediaOutlets.id, id));
|
|
return result.rowCount !== undefined && result.rowCount > 0;
|
|
} catch (error) {
|
|
console.error('Error deleting outlet from database:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async updateOutlet(id: string, updates: Partial<InsertMediaOutlet>): Promise<MediaOutlet | undefined> {
|
|
try {
|
|
// First check if outlet exists
|
|
const existing = await db.select().from(mediaOutlets).where(eq(mediaOutlets.id, id));
|
|
if (existing.length === 0) return undefined;
|
|
|
|
// Update the outlet
|
|
const result = await db.update(mediaOutlets)
|
|
.set(updates)
|
|
.where(eq(mediaOutlets.id, id))
|
|
.returning();
|
|
|
|
return result[0] || undefined;
|
|
} catch (error) {
|
|
console.error('Error updating outlet in database:', error);
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
async mergeOutlets(fromOutletId: string, toOutletId: string): Promise<{ success: boolean; movedArticles: number }> {
|
|
const fromOutlet = this.outlets.get(fromOutletId);
|
|
const toOutlet = this.outlets.get(toOutletId);
|
|
|
|
if (!fromOutlet || !toOutlet) {
|
|
return { success: false, movedArticles: 0 };
|
|
}
|
|
|
|
// Move all articles from source outlet to target outlet
|
|
let movedArticles = 0;
|
|
for (const [articleId, article] of Array.from(this.articles.entries())) {
|
|
if (article.outletId === fromOutletId) {
|
|
this.articles.set(articleId, { ...article, outletId: toOutletId });
|
|
movedArticles++;
|
|
}
|
|
}
|
|
|
|
// Delete the source outlet
|
|
this.outlets.delete(fromOutletId);
|
|
|
|
return { success: true, movedArticles };
|
|
}
|
|
|
|
// Article methods
|
|
async getAllArticles(): Promise<Article[]> {
|
|
const result = await db.select().from(articles).orderBy(desc(articles.publishedAt));
|
|
return result;
|
|
}
|
|
|
|
async getArticlesByOutlet(outletId: string): Promise<Article[]> {
|
|
return Array.from(this.articles.values())
|
|
.filter(article => article.outletId === outletId)
|
|
.sort((a, b) => {
|
|
const dateA = typeof a.publishedAt === 'string' ? new Date(a.publishedAt) : a.publishedAt;
|
|
const dateB = typeof b.publishedAt === 'string' ? new Date(b.publishedAt) : b.publishedAt;
|
|
return dateB.getTime() - dateA.getTime();
|
|
});
|
|
}
|
|
|
|
async getArticleCountsByOutlets(): Promise<Record<string, number>> {
|
|
const counts: Record<string, number> = {};
|
|
for (const article of this.articles.values()) {
|
|
counts[article.outletId] = (counts[article.outletId] || 0) + 1;
|
|
}
|
|
return counts;
|
|
}
|
|
|
|
async getArticleById(id: string): Promise<Article | undefined> {
|
|
return this.articles.get(id);
|
|
}
|
|
|
|
async getFeaturedArticles(limit: number = 10): Promise<Article[]> {
|
|
const result = await db.select().from(articles).orderBy(desc(articles.publishedAt)).limit(limit);
|
|
return result;
|
|
}
|
|
|
|
async searchArticles(query: string): Promise<Article[]> {
|
|
const searchTerm = `%${query.toLowerCase()}%`;
|
|
const result = await db.select().from(articles)
|
|
.where(
|
|
or(
|
|
like(sql`lower(${articles.title})`, searchTerm),
|
|
like(sql`lower(${articles.summary})`, searchTerm),
|
|
like(sql`lower(${articles.body})`, searchTerm)
|
|
)
|
|
)
|
|
.orderBy(desc(articles.publishedAt));
|
|
return result;
|
|
}
|
|
|
|
async createArticle(article: InsertArticle): Promise<Article> {
|
|
const newArticle: Article = {
|
|
id: randomUUID(),
|
|
viewCount: 0,
|
|
sourceUrl: null,
|
|
author: null,
|
|
originalImageUrl: null,
|
|
scrapedAt: null,
|
|
isScraped: 0,
|
|
...article,
|
|
tags: article.tags || null
|
|
};
|
|
|
|
try {
|
|
await db.insert(articles).values(newArticle);
|
|
return newArticle;
|
|
} catch (error) {
|
|
console.error('Error inserting article into database:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async deleteArticle(id: string): Promise<boolean> {
|
|
try {
|
|
const result = await db.delete(articles).where(eq(articles.id, id));
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error deleting article from database:', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async createScrapedArticle(article: Omit<InsertArticle, 'id'> & {
|
|
sourceUrl: string;
|
|
author?: string;
|
|
originalImageUrl?: string;
|
|
isScraped?: number;
|
|
}): Promise<Article> {
|
|
const newArticle: Article = {
|
|
id: randomUUID(),
|
|
viewCount: 0,
|
|
scrapedAt: new Date(),
|
|
isScraped: 1,
|
|
...article,
|
|
tags: article.tags || null,
|
|
author: article.author || null,
|
|
originalImageUrl: article.originalImageUrl || null
|
|
};
|
|
this.articles.set(newArticle.id, newArticle);
|
|
return newArticle;
|
|
}
|
|
|
|
async getScrapedArticles(limit: number = 50): Promise<Article[]> {
|
|
return Array.from(this.articles.values())
|
|
.filter(article => article.isScraped === 1)
|
|
.sort((a, b) => b.publishedAt.getTime() - a.publishedAt.getTime())
|
|
.slice(0, limit);
|
|
}
|
|
|
|
async updateArticleWithScrapedData(id: string, data: {
|
|
sourceUrl?: string;
|
|
author?: string;
|
|
originalImageUrl?: string;
|
|
}): Promise<Article | undefined> {
|
|
const article = this.articles.get(id);
|
|
if (!article) return undefined;
|
|
|
|
const updatedArticle = { ...article, ...data };
|
|
this.articles.set(id, updatedArticle);
|
|
return updatedArticle;
|
|
}
|
|
|
|
async updateArticleThumbnail(id: string, thumbnail: string): Promise<Article | undefined> {
|
|
try {
|
|
const result = await db
|
|
.update(articles)
|
|
.set({ thumbnail })
|
|
.where(eq(articles.id, id))
|
|
.returning();
|
|
|
|
return result[0] || undefined;
|
|
} catch (error) {
|
|
console.error('Error updating article thumbnail in database:', error);
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
async listFeed(params: { cursor?: string; limit?: number; filter?: 'all' | 'people' | 'topics' | 'companies' }): Promise<{ items: (Article & { outletName: string; outletAvatar: string; category: string })[]; nextCursor?: string }> {
|
|
try {
|
|
const limit = params.limit || 20;
|
|
|
|
// Query from database with joins
|
|
let query = db
|
|
.select({
|
|
article: articles,
|
|
outlet: mediaOutlets
|
|
})
|
|
.from(articles)
|
|
.leftJoin(mediaOutlets, eq(articles.outletId, mediaOutlets.id))
|
|
.orderBy(desc(articles.publishedAt));
|
|
|
|
// Apply filter if specified
|
|
if (params.filter && params.filter !== 'all') {
|
|
query = query.where(eq(mediaOutlets.category, params.filter)) as any;
|
|
}
|
|
|
|
// Execute query with limit + 1 to check for next page
|
|
const results = await query.limit(limit + 1);
|
|
|
|
// Apply cursor pagination if provided
|
|
let filteredResults = results;
|
|
if (params.cursor) {
|
|
const cursorIndex = results.findIndex(r => r.article.id === params.cursor);
|
|
if (cursorIndex !== -1) {
|
|
filteredResults = results.slice(cursorIndex + 1);
|
|
}
|
|
}
|
|
|
|
const hasNext = filteredResults.length > limit;
|
|
const items = filteredResults.slice(0, limit);
|
|
|
|
// Enrich with outlet data
|
|
const enrichedItems = items.map(({ article, outlet }) => ({
|
|
...article,
|
|
outletName: outlet?.name || 'Unknown Outlet',
|
|
outletAvatar: outlet?.avatar || '',
|
|
category: outlet?.category || 'unknown'
|
|
}));
|
|
|
|
const nextCursor = hasNext ? enrichedItems[enrichedItems.length - 1]?.id : undefined;
|
|
return { items: enrichedItems, nextCursor };
|
|
} catch (error) {
|
|
console.error('[DbStorage] Error in listFeed:', error);
|
|
return { items: [] };
|
|
}
|
|
}
|
|
|
|
async incrementView(id: string): Promise<void> {
|
|
const article = this.articles.get(id);
|
|
if (article) {
|
|
const currentViewCount = article.viewCount || 0;
|
|
const updatedArticle = {
|
|
...article,
|
|
viewCount: currentViewCount + 1
|
|
};
|
|
this.articles.set(id, updatedArticle);
|
|
}
|
|
}
|
|
|
|
async removeDuplicateArticles(): Promise<{ removedCount: number; details: { outletId: string; duplicatesRemoved: number }[] }> {
|
|
const outletGroups = new Map<string, Map<string, Article[]>>();
|
|
|
|
// Group articles by outlet and title
|
|
for (const article of Array.from(this.articles.values())) {
|
|
if (!outletGroups.has(article.outletId)) {
|
|
outletGroups.set(article.outletId, new Map());
|
|
}
|
|
const titleGroups = outletGroups.get(article.outletId)!;
|
|
if (!titleGroups.has(article.title)) {
|
|
titleGroups.set(article.title, []);
|
|
}
|
|
titleGroups.get(article.title)!.push(article);
|
|
}
|
|
|
|
let totalRemoved = 0;
|
|
const outletDetails = new Map<string, number>();
|
|
|
|
// Process each outlet
|
|
for (const [outletId, titleGroups] of Array.from(outletGroups.entries())) {
|
|
let outletRemoved = 0;
|
|
|
|
for (const [title, articles] of Array.from(titleGroups.entries())) {
|
|
if (articles.length > 1) {
|
|
// Sort by publishedAt desc to keep the most recent
|
|
articles.sort((a: Article, b: Article) => b.publishedAt.getTime() - a.publishedAt.getTime());
|
|
|
|
// Keep the first (most recent) and remove the rest
|
|
const [keep, ...toRemove] = articles;
|
|
|
|
for (const article of toRemove) {
|
|
this.articles.delete(article.id);
|
|
totalRemoved++;
|
|
outletRemoved++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (outletRemoved > 0) {
|
|
outletDetails.set(outletId, outletRemoved);
|
|
}
|
|
}
|
|
|
|
const details = Array.from(outletDetails.entries()).map(([outletId, duplicatesRemoved]) => ({
|
|
outletId,
|
|
duplicatesRemoved
|
|
}));
|
|
|
|
return {
|
|
removedCount: totalRemoved,
|
|
details
|
|
};
|
|
}
|
|
|
|
// Comment system methods
|
|
async getCommentsByArticle(articleId: string, params: { limit?: number; offset?: number }): Promise<{ comments: Comment[]; total: number }> {
|
|
const limit = params.limit || 20;
|
|
const offset = params.offset || 0;
|
|
|
|
const allComments = Array.from(this.comments.values())
|
|
.filter(comment => comment.articleId === articleId && !comment.parentId)
|
|
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
|
|
const total = allComments.length;
|
|
const comments = allComments.slice(offset, offset + limit);
|
|
|
|
return { comments, total };
|
|
}
|
|
|
|
async getCommentReplies(parentId: string, params: { limit?: number; offset?: number }): Promise<{ comments: Comment[]; total: number }> {
|
|
const limit = params.limit || 20;
|
|
const offset = params.offset || 0;
|
|
|
|
const allReplies = Array.from(this.comments.values())
|
|
.filter(comment => comment.parentId === parentId)
|
|
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
|
|
const total = allReplies.length;
|
|
const comments = allReplies.slice(offset, offset + limit);
|
|
|
|
return { comments, total };
|
|
}
|
|
|
|
async getCommentById(id: string): Promise<Comment | undefined> {
|
|
return this.comments.get(id);
|
|
}
|
|
|
|
async createComment(comment: InsertComment): Promise<Comment> {
|
|
const newComment: Comment = {
|
|
id: randomUUID(),
|
|
likesCount: 0,
|
|
dislikesCount: 0,
|
|
repliesCount: 0,
|
|
createdAt: new Date(),
|
|
updatedAt: new Date(),
|
|
...comment,
|
|
avatar: comment.avatar || null,
|
|
parentId: comment.parentId || null
|
|
};
|
|
this.comments.set(newComment.id, newComment);
|
|
return newComment;
|
|
}
|
|
|
|
async updateComment(id: string, content: string): Promise<Comment | undefined> {
|
|
const comment = this.comments.get(id);
|
|
if (!comment) return undefined;
|
|
|
|
const updatedComment = {
|
|
...comment,
|
|
content,
|
|
updatedAt: new Date()
|
|
};
|
|
this.comments.set(id, updatedComment);
|
|
return updatedComment;
|
|
}
|
|
|
|
async deleteComment(id: string): Promise<boolean> {
|
|
return this.comments.delete(id);
|
|
}
|
|
|
|
async toggleCommentReaction(commentId: string, userIdentifier: string, reactionType: 'like' | 'dislike'): Promise<{ action: 'added' | 'removed' | 'changed'; reaction: CommentReaction | null }> {
|
|
const reactionKey = `${commentId}:${userIdentifier}`;
|
|
const existingReaction = this.commentReactions.get(reactionKey);
|
|
|
|
if (existingReaction) {
|
|
if (existingReaction.reactionType === reactionType) {
|
|
// Remove the reaction
|
|
this.commentReactions.delete(reactionKey);
|
|
return { action: 'removed', reaction: null };
|
|
} else {
|
|
// Change the reaction
|
|
const updatedReaction = { ...existingReaction, reactionType };
|
|
this.commentReactions.set(reactionKey, updatedReaction);
|
|
return { action: 'changed', reaction: updatedReaction };
|
|
}
|
|
} else {
|
|
// Add new reaction
|
|
const newReaction: CommentReaction = {
|
|
id: randomUUID(),
|
|
commentId,
|
|
reactionType,
|
|
userIdentifier,
|
|
createdAt: new Date()
|
|
};
|
|
this.commentReactions.set(reactionKey, newReaction);
|
|
return { action: 'added', reaction: newReaction };
|
|
}
|
|
}
|
|
|
|
async getUserCommentReaction(commentId: string, userIdentifier: string): Promise<CommentReaction | undefined> {
|
|
const reactionKey = `${commentId}:${userIdentifier}`;
|
|
return this.commentReactions.get(reactionKey);
|
|
}
|
|
|
|
async toggleBookmark(articleId: string, userIdentifier: string): Promise<{ action: 'added' | 'removed'; bookmark: Bookmark | null }> {
|
|
const bookmarkKey = `${articleId}:${userIdentifier}`;
|
|
const existingBookmark = this.bookmarks.get(bookmarkKey);
|
|
|
|
if (existingBookmark) {
|
|
this.bookmarks.delete(bookmarkKey);
|
|
try {
|
|
await db.delete(bookmarks)
|
|
.where(
|
|
and(
|
|
eq(bookmarks.articleId, articleId),
|
|
eq(bookmarks.userIdentifier, userIdentifier)
|
|
)
|
|
);
|
|
} catch (error) {
|
|
console.error('[DbStorage] Error removing bookmark:', error);
|
|
}
|
|
return { action: 'removed', bookmark: null };
|
|
} else {
|
|
const newBookmark: Bookmark = {
|
|
id: randomUUID(),
|
|
articleId,
|
|
userIdentifier,
|
|
createdAt: new Date()
|
|
};
|
|
this.bookmarks.set(bookmarkKey, newBookmark);
|
|
try {
|
|
await db.insert(bookmarks).values(newBookmark);
|
|
} catch (error) {
|
|
console.error('[DbStorage] Error adding bookmark:', error);
|
|
}
|
|
return { action: 'added', bookmark: newBookmark };
|
|
}
|
|
}
|
|
|
|
async isBookmarked(articleId: string, userIdentifier: string): Promise<boolean> {
|
|
const bookmarkKey = `${articleId}:${userIdentifier}`;
|
|
return this.bookmarks.has(bookmarkKey);
|
|
}
|
|
|
|
async getUserBookmarks(userIdentifier: string): Promise<Bookmark[]> {
|
|
return Array.from(this.bookmarks.values())
|
|
.filter(bookmark => bookmark.userIdentifier === userIdentifier);
|
|
}
|
|
|
|
async getArticleCommentCount(articleId: string): Promise<number> {
|
|
try {
|
|
const result = await db
|
|
.select({ count: count() })
|
|
.from(comments)
|
|
.where(eq(comments.articleId, articleId));
|
|
return result[0]?.count || 0;
|
|
} catch (error) {
|
|
console.error('[DbStorage] Error getting comment count:', error);
|
|
return Array.from(this.comments.values())
|
|
.filter(comment => comment.articleId === articleId).length;
|
|
}
|
|
}
|
|
|
|
// Prediction Market methods
|
|
async getPredictionMarketsByArticle(articleId: string, params: { limit?: number; offset?: number }): Promise<PredictionMarket[]> {
|
|
const limit = params.limit || 3;
|
|
const offset = params.offset || 0;
|
|
|
|
// Generate diverse prediction markets (binary and multiple choice)
|
|
const mockMarkets: PredictionMarket[] = [
|
|
// Binary markets (Yes/No)
|
|
{
|
|
id: `pm-${articleId}-1`,
|
|
articleId,
|
|
question: "Will this prediction come true by end of year?",
|
|
description: "Market resolves YES if the main prediction in this article occurs by December 31st",
|
|
marketType: "binary",
|
|
yesPrice: 65,
|
|
noPrice: 35,
|
|
options: null,
|
|
totalVolume: 421000,
|
|
endDate: new Date('2025-12-31'),
|
|
category: "Politics",
|
|
isLive: 1,
|
|
isResolved: 0,
|
|
createdAt: new Date(),
|
|
},
|
|
// Multiple choice market - Election
|
|
{
|
|
id: `pm-${articleId}-2`,
|
|
articleId,
|
|
question: "Who will win the mayoral election?",
|
|
description: "Market on the winner of upcoming mayoral election",
|
|
marketType: "multiple_choice",
|
|
yesPrice: null,
|
|
noPrice: null,
|
|
options: JSON.stringify([
|
|
{ name: "John Smith", price: 86 },
|
|
{ name: "Sarah Johnson", price: 14 },
|
|
]),
|
|
totalVolume: 108000,
|
|
endDate: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000),
|
|
category: "Politics",
|
|
isLive: 0,
|
|
isResolved: 0,
|
|
createdAt: new Date(),
|
|
},
|
|
// Multiple choice market - Sports match
|
|
{
|
|
id: `pm-${articleId}-3`,
|
|
articleId,
|
|
question: "Match Winner",
|
|
description: "Which team will win the upcoming match",
|
|
marketType: "multiple_choice",
|
|
yesPrice: null,
|
|
noPrice: null,
|
|
options: JSON.stringify([
|
|
{ name: "Team A", price: 60 },
|
|
{ name: "Draw", price: 22 },
|
|
{ name: "Team B", price: 18 },
|
|
]),
|
|
totalVolume: 421000,
|
|
endDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
|
|
category: "Sports",
|
|
isLive: 1,
|
|
isResolved: 0,
|
|
createdAt: new Date(),
|
|
},
|
|
// Binary market
|
|
{
|
|
id: `pm-${articleId}-4`,
|
|
articleId,
|
|
question: "Will stock price increase by 10% in next quarter?",
|
|
description: "Resolves YES if the mentioned company's stock rises 10%+ within 90 days",
|
|
marketType: "binary",
|
|
yesPrice: 55,
|
|
noPrice: 45,
|
|
options: null,
|
|
totalVolume: 221000,
|
|
endDate: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000),
|
|
category: "Business",
|
|
isLive: 0,
|
|
isResolved: 0,
|
|
createdAt: new Date(),
|
|
},
|
|
// Multiple choice market - Company acquisition
|
|
{
|
|
id: `pm-${articleId}-5`,
|
|
articleId,
|
|
question: "Which company will acquire XYZ Corp?",
|
|
description: "Market on potential acquirer of XYZ Corporation",
|
|
marketType: "multiple_choice",
|
|
yesPrice: null,
|
|
noPrice: null,
|
|
options: JSON.stringify([
|
|
{ name: "Microsoft", price: 45 },
|
|
{ name: "Google", price: 32 },
|
|
{ name: "Amazon", price: 23 },
|
|
]),
|
|
totalVolume: 457000,
|
|
endDate: new Date(Date.now() + 180 * 24 * 60 * 60 * 1000),
|
|
category: "Business",
|
|
isLive: 0,
|
|
isResolved: 0,
|
|
createdAt: new Date(),
|
|
},
|
|
];
|
|
|
|
return mockMarkets.slice(offset, offset + limit);
|
|
}
|
|
|
|
async getPredictionMarketById(id: string): Promise<PredictionMarket | undefined> {
|
|
// Mock implementation - would query database in production
|
|
return undefined;
|
|
}
|
|
|
|
async createPredictionMarket(market: InsertPredictionMarket): Promise<PredictionMarket> {
|
|
const newMarket: PredictionMarket = {
|
|
id: randomUUID(),
|
|
...market,
|
|
options: market.options ?? null,
|
|
description: market.description ?? null,
|
|
category: market.category ?? null,
|
|
yesPrice: market.yesPrice ?? null,
|
|
noPrice: market.noPrice ?? null,
|
|
createdAt: new Date(),
|
|
};
|
|
return newMarket;
|
|
}
|
|
}
|
|
|
|
// Create and export storage instance
|
|
export const storage = new DbStorage(); |