### Start Development Server Source: https://github.com/ourongxing/newsnow/blob/main/CONTRIBUTING.md Use this command to start the development server and test your changes locally. ```bash npm run dev ``` -------------------------------- ### Development Setup and Execution Source: https://github.com/ourongxing/newsnow/blob/main/README.md Commands to set up the development environment and run the NewsNow project locally. Requires Node.js version 20 or higher. ```sh corepack enable pnpm i pnpm dev ``` -------------------------------- ### Configure MCP Client for NewsNow Source: https://context7.com/ourongxing/newsnow/llms.txt Example configuration for an MCP client, such as Claude Desktop, to connect to the NewsNow MCP server. Ensure the `BASE_URL` environment variable is set correctly. ```json { "mcpServers": { "newsnow": { "command": "npx", "args": ["-y", "newsnow-mcp-server"], "env": { "BASE_URL": "https://your-domain.com" } } } } ``` -------------------------------- ### Docker Compose for Local Deployment Source: https://github.com/ourongxing/newsnow/blob/main/README.md Command to start the NewsNow application using Docker Compose. Environment variables can also be set within the docker-compose.yml file. ```sh docker compose up ``` -------------------------------- ### Environment Variables for Server Configuration Source: https://github.com/ourongxing/newsnow/blob/main/README.md Example environment variables for server configuration, including GitHub OAuth credentials, JWT secret, and database initialization settings. Ensure JWT Secret is usually the same as Client Secret. ```env # Github Client ID G_CLIENT_ID= # Github Client Secret G_CLIENT_SECRET= # JWT Secret, usually the same as Client Secret JWT_SECRET= # Initialize database, must be set to true on first run, can be turned off afterward INIT_TABLE=true # Whether to enable cache ENABLE_CACHE=true ``` -------------------------------- ### GET /api/login — Initiate GitHub OAuth Login Source: https://context7.com/ourongxing/newsnow/llms.txt Redirects the user's browser to GitHub's OAuth authorization page to begin the login process. This endpoint requires the `G_CLIENT_ID` environment variable to be configured. ```APIDOC ## GET /api/login — Initiate GitHub OAuth Login ### Description Redirects the browser to GitHub's OAuth authorization page. No parameters required. Requires `G_CLIENT_ID` to be configured in environment variables. ### Method GET ### Endpoint /api/login ### Request Example ```bash # Redirect user's browser to this URL to begin login curl -L "https://your-domain.com/api/login" # → 302 Redirect to: # https://github.com/login/oauth/authorize?client_id=YOUR_CLIENT_ID ``` ``` -------------------------------- ### Get Current Server Version (Bash) Source: https://context7.com/ourongxing/newsnow/llms.txt Retrieves the current deployed version of the NewsNow application. This endpoint is useful for clients to check for necessary updates. ```bash curl "https://your-domain.com/api/latest" ``` ```json # { "v": "0.0.39" } ``` -------------------------------- ### GET /api/enable-login — Check Login Availability Source: https://context7.com/ourongxing/newsnow/llms.txt Checks if the login functionality is configured on the server and provides the GitHub OAuth URL if it is. This is used by the frontend to conditionally display the login button. ```APIDOC ## GET /api/enable-login — Check Login Availability ### Description Returns whether the server has login configured and provides the GitHub OAuth URL. Used by the frontend to conditionally show the login button. ### Method GET ### Endpoint /api/enable-login ### Response #### Success Response (200) - **enable** (boolean) - True if login is configured, false otherwise. - **url** (string) - The GitHub OAuth authorization URL if login is enabled. #### Response Example (when configured) ```json { "enable": true, "url": "https://github.com/login/oauth/authorize?client_id=YOUR_ID" } ``` #### Response Example (when not configured) ```json { "enable": false } ``` ``` -------------------------------- ### GET /api/me — Get Authenticated User's Saved Layout Source: https://context7.com/ourongxing/newsnow/llms.txt Retrieves the authenticated user's persisted column and source layout data. Requires a valid JWT in the Authorization header. ```APIDOC ## GET /api/me — Get Authenticated User's Saved Layout ### Description Returns the authenticated user's persisted column/source layout data. Requires a valid JWT in the `Authorization` header. ### Method GET ### Endpoint /api/me ### Response #### Success Response (200) - **data** (object) - Contains the user's layout configuration. - **focus** (array[string]) - List of source IDs for the focus column. - **hottest** (array[string]) - List of source IDs for the hottest column. - **realtime** (array[string]) - List of source IDs for the realtime column. - **updatedTime** (integer) - Timestamp of the last update. ### Response Example ```json { "data": { "focus": ["hackernews", "github"], "hottest": ["weibo", "zhihu"], "realtime": ["cls-telegraph", "wallstreetcn-quick"] }, "updatedTime": 1718000000000 } ``` ``` -------------------------------- ### GET /api/latest — Get Current Server Version Source: https://context7.com/ourongxing/newsnow/llms.txt Retrieves the current deployed version of the NewsNow application. This endpoint is useful for clients to determine if an update is available or necessary. ```APIDOC ## GET /api/latest — Get Current Server Version ### Description Returns the current deployed version of NewsNow. Useful for checking if a client-side update is needed. ### Method GET ### Endpoint /api/latest ### Response #### Success Response (200) - **v** (string) - The current version string of the NewsNow application. ### Response Example ```json { "v": "0.0.39" } ``` ``` -------------------------------- ### Define Source via RSSHub Proxy Source: https://context7.com/ourongxing/newsnow/llms.txt Create a news source by fetching data from the RSSHub network using JSON format. Supports sorting and limiting the number of items. The example shows fetching latest V2EX topics. ```typescript // server/sources/v2ex.ts import { defineRSSHubSource } from "#/utils/source" export default defineSource({ "v2ex-share": defineRSSHubSource( "/v2ex/topics/latest", { sorted: true, limit: 20 }, { hiddenDate: false }, ), }) // Fetches from https://rsshub.rssforever.com/v2ex/topics/latest?format=json&sorted=true&limit=20 ``` -------------------------------- ### GET /api/oauth/github — GitHub OAuth Callback Source: https://context7.com/ourongxing/newsnow/llms.txt Handles the callback from GitHub after a user authorizes the application. It exchanges the authorization code for an access token, retrieves the user's profile, creates or updates the user in the database, and issues a JWT for authentication. ```APIDOC ## GET /api/oauth/github — GitHub OAuth Callback ### Description Handles the OAuth callback from GitHub. Exchanges the authorization `code` for an access token, fetches the GitHub user profile, upserts the user in the database, and issues a signed JWT (HS256, 60-day expiry). Redirects back to the app root with the JWT and user info in query params. ### Method GET ### Endpoint /api/oauth/github #### Query Parameters - **code** (string) - Required - The authorization code received from GitHub. ### Response - On successful authentication, the browser is redirected to the application root (`/`) with the following query parameters: - **login** (string): Indicates the login provider, e.g., "github". - **jwt** (string): The signed JSON Web Token for authentication. - **user** (string): A URL-encoded JSON string containing user details (e.g., avatar, name). ### JWT Payload Structure (decoded) ```json { "id": "12345678", // GitHub user ID as string "type": "github", "exp": 1723000000 // 60 days from issue time } ``` ``` -------------------------------- ### Get Authenticated User's Saved Layout Source: https://context7.com/ourongxing/newsnow/llms.txt Use this endpoint to retrieve the user's persisted column and source layout. Requires a valid JWT in the Authorization header. ```bash curl "https://your-domain.com/api/me" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." ``` ```json # Response: # { # "data": { # "focus": ["hackernews", "github"], # "hottest": ["weibo", "zhihu"], # "realtime": ["cls-telegraph", "wallstreetcn-quick"] # }, # "updatedTime": 1718000000000 # } ``` -------------------------------- ### GET /api/s — Fetch News from a Single Source Source: https://context7.com/ourongxing/newsnow/llms.txt Fetches the latest news items for a given source ID. It prioritizes cached data within a 30-minute TTL but can bypass the cache for fresh data if the `latest` query parameter is appended and the user is authenticated. ```APIDOC ## GET /api/s — Fetch News from a Single Source ### Description Fetches the latest news items for a given source ID. Returns cached data when available within the TTL window (30 minutes), or fetches live data. Authenticated users (via `Authorization: Bearer `) can force a cache bypass by appending `?latest`. ### Method GET ### Endpoint /api/s #### Query Parameters - **id** (string) - Required - The unique identifier for the news source. - **latest** (boolean) - Optional - If present, bypasses the cache and fetches fresh data. #### Headers - **Authorization** (string) - Optional - `Bearer ` for authenticated requests, required to use the `latest` parameter. ### Request Example ```bash # Fetch Hacker News top stories (unauthenticated, may return cache) curl "https://your-domain.com/api/s?id=hackernews" # Force fresh fetch as authenticated user curl "https://your-domain.com/api/s?id=weibo&latest" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." # Fetch a sub-source (Weibo real-time hot search) curl "https://your-domain.com/api/s?id=weibo" # Fetch Wall Street CN quick flash news curl "https://your-domain.com/api/s?id=wallstreetcn-quick" ``` ### Response #### Success Response (200) - **status** (string) - Indicates if the data is from 'success' or 'cache'. - **id** (string) - The source ID. - **updatedTime** (integer) - Timestamp of when the data was last updated. - **items** (array) - An array of news items. - **id** (string) - Unique identifier for the news item. - **title** (string) - The headline of the news item. - **url** (string) - The URL to the full news article. - **extra** (object) - Optional additional information about the news item. #### Response Example ```json { "status": "success", "id": "hackernews", "updatedTime": 1718000000000, "items": [ { "id": "40123456", "title": "Show HN: I built a thing", "url": "https://news.ycombinator.com/item?id=40123456", "extra": { "info": "312 points" } }, ... ] } ``` ``` -------------------------------- ### Initiate GitHub OAuth Login (Bash) Source: https://context7.com/ourongxing/newsnow/llms.txt Initiates the GitHub OAuth flow by redirecting the user to GitHub's authorization server. Ensure `G_CLIENT_ID` is configured in your environment variables. ```bash # Redirect user's browser to this URL to begin login curl -L "https://your-domain.com/api/login" # → 302 Redirect to: # https://github.com/login/oauth/authorize?client_id=YOUR_CLIENT_ID ``` -------------------------------- ### Register New Source in Configuration Source: https://github.com/ourongxing/newsnow/blob/main/CONTRIBUTING.md Add new sources to the configuration file, either as a sub-source or a top-level entry. ```json "bilibili": { name: "哔哩哔哩", color: "blue", home: "https://www.bilibili.com", sub: { "hot-search": { title: "热搜", column: "china", type: "hottest" }, "hot-video": { title: "热门视频", column: "china", type: "hottest" } } } ``` ```json "newsource": { name: "New Source", color: "blue", home: "https://www.example.com", column: "tech", type: "hottest" }; ``` -------------------------------- ### Configure MCP Server for NewsNow Source: https://github.com/ourongxing/newsnow/blob/main/README.md This JSON configuration defines settings for the newsnow MCP server, including the command to run, arguments, and the base URL for the service. You can change the BASE_URL to your own domain. ```json { "mcpServers": { "newsnow": { "command": "npx", "args": [ "-y", "newsnow-mcp-server" ], "env": { "BASE_URL": "https://newsnow.busiyi.world" } } } } ``` -------------------------------- ### Regenerate Source Files Source: https://github.com/ourongxing/newsnow/blob/main/CONTRIBUTING.md Run this command after adding or modifying source files to update necessary configurations. ```bash npm run presource ``` -------------------------------- ### Commit Changes Source: https://github.com/ourongxing/newsnow/blob/main/CONTRIBUTING.md Stage and commit your changes using Git. ```bash git add . git commit -m "Add new source: source-name" ``` -------------------------------- ### Create Pull Request Source: https://github.com/ourongxing/newsnow/blob/main/CONTRIBUTING.md Push your local branch to your fork and create a pull request. ```bash git push origin feature-name ``` -------------------------------- ### Create Cloudflare-Compatible Source Proxy Source: https://context7.com/ourongxing/newsnow/llms.txt Wraps a SourceGetter to use an external proxy URL on Cloudflare Pages, falling back to direct implementation otherwise. Useful for circumventing network restrictions. ```typescript import { proxySource, defineRSSSource } from "#/utils/source" // server/sources/sspai.ts const direct = defineRSSSource("https://sspai.com/feed") // On Cloudflare Pages: fetches pre-scraped data from your proxy // Otherwise: scrapes directly from sspai.com export default proxySource("https://proxy.your-domain.com/api/s?id=sspai", direct) ``` -------------------------------- ### Fetch News from a Single Source (Bash) Source: https://context7.com/ourongxing/newsnow/llms.txt Use this endpoint to retrieve news items from a specific source. It serves cached data by default but can be configured to fetch live data. Authentication is required for cache bypass. ```bash # Fetch Hacker News top stories (unauthenticated, may return cache) curl "https://your-domain.com/api/s?id=hackernews" ``` ```bash # Force fresh fetch as authenticated user curl "https://your-domain.com/api/s?id=weibo&latest" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." ``` ```json # Expected response: # { # "status": "success", // or "cache" when serving cached data # "id": "hackernews", # "updatedTime": 1718000000000, # "items": [ # { # "id": "40123456", # "title": "Show HN: I built a thing", # "url": "https://news.ycombinator.com/item?id=40123456", # "extra": { "info": "312 points" } # }, # ... # ] # } ``` ```bash # Fetch a sub-source (Weibo real-time hot search) curl "https://your-domain.com/api/s?id=weibo" ``` ```bash # Fetch Wall Street CN quick flash news curl "https://your-domain.com/api/s?id=wallstreetcn-quick" ``` -------------------------------- ### MCP Server Endpoint for Tool Calls Source: https://context7.com/ourongxing/newsnow/llms.txt Handles Model Context Protocol requests over Streamable HTTP, exposing tools like `get_hotest_latest_news`. Use this to query live news through the NewsNow API. ```bash # MCP tool call: get_hotest_latest_news curl -X POST "https://your-domain.com/api/mcp" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "get_hotest_latest_news", "arguments": { "id": "hackernews", "count": 5 } }, "id": 1 }' ``` ```json # Returns up to `count` news items as MCP text content blocks: # { # "content": [ # { "type": "text", "text": "[Show HN: ...](https://news.ycombinator.com/item?id=...)" }, # ... # ] # } ``` -------------------------------- ### Check Login Availability (Bash) Source: https://context7.com/ourongxing/newsnow/llms.txt Checks if login functionality is configured on the server and retrieves the GitHub OAuth URL. This is used by the frontend to conditionally display the login button. ```bash curl "https://your-domain.com/api/enable-login" ``` ```json # Response when configured: # { "enable": true, "url": "https://github.com/login/oauth/authorize?client_id=YOUR_ID" } ``` -------------------------------- ### Manage User Data and Layout Source: https://context7.com/ourongxing/newsnow/llms.txt Handles GitHub-authenticated users and their serialized layout data. Use to add users, save/retrieve their column mappings, and remove them. ```typescript import { UserTable } from "#/database/user" const userTable = new UserTable(db) await userTable.init() // creates user table + index // Upsert on OAuth login await userTable.addUser("12345678", "user@example.com", "github") // Save user's column layout await userTable.setData( "12345678", JSON.stringify({ focus: ["hackernews"], hottest: ["weibo"] }), Date.now(), ) // Retrieve user's layout const { data, updated } = await userTable.getData("12345678") const layout = JSON.parse(data) // { focus: [...], hottest: [...] } // Remove user await userTable.deleteUser("12345678") ``` -------------------------------- ### Initialize and Use Cache Table Source: https://context7.com/ourongxing/newsnow/llms.txt Manages server-side news caching for serialized NewsItem arrays. Use to store and retrieve news keyed by SourceID. ```typescript import { Cache } from "#/database/cache" // Initialize (called automatically via getCacheTable()) const cache = new Cache(db) await cache.init() // CREATE TABLE IF NOT EXISTS cache (id, updated, data) // Write items to cache await cache.set("hackernews", [ { id: "40123456", title: "Show HN: ...", url: "https://news.ycombinator.com/item?id=40123456" }, ]) // Read single source const entry = await cache.get("hackernews") // → { id: "hackernews", updated: 1718000000000, items: [...] } // Batch read for multiple sources const entries = await cache.getEntire(["hackernews", "weibo", "zhihu"]) // → [{ id: "hackernews", ... }, { id: "weibo", ... }, ...] // Delete a cache entry await cache.delete("hackernews") ``` -------------------------------- ### defineSource Source: https://context7.com/ourongxing/newsnow/llms.txt Wraps a typed async function that returns `NewsItem[]`. This function is used to register a source getter and supports both single-source and multi-source exports. ```APIDOC ## `defineSource` — Register a Source Getter ### Description Wraps a typed async function that returns `NewsItem[]`. Used in every file under `server/sources/`. Supports both single-source and multi-source (sub-source) exports. ### Usage ```typescript import { defineSource } from "#app/utils/source" import type { NewsItem } from "@shared/types" // Single source export export default defineSource(async (): Promise => { // ... fetch and process news items ... return news }) // Multi-sub-source export const subSource1 = defineSource(async () => { /* ... */ }) const subSource2 = defineSource(async () => { /* ... */ }) export default defineSource({ "sub-source-1": subSource1, "sub-source-2": subSource2, }) ``` ### Parameters - **sourceFunction** (Function) - A function that returns a Promise resolving to an array of `NewsItem` objects. - **sourceObject** (Object) - An object where keys are sub-source names and values are functions returning `NewsItem[]`. ``` -------------------------------- ### Registering a New News Source Source: https://context7.com/ourongxing/newsnow/llms.txt Define a new news source by adding an entry to `originSources`. The `genSources()` function automatically flattens `sub` entries into individual source IDs using the `parentId-subId` naming convention. ```typescript // shared/pre-sources.ts — adding a new source export const originSources = { // ... existing sources "mynews": { name: "My News", color: "indigo", column: "tech", // "china" | "world" | "tech" | "finance" type: "realtime", // "hottest" | "realtime" (optional) interval: 5 * 60 * 1000, // refresh interval in ms (default: 10 min) home: "https://mynews.example.com", sub: { latest: { title: "Latest", type: "realtime", interval: 2 * 60 * 1000, }, hot: { title: "Hot", type: "hottest", }, }, }, } as const satisfies Record // Resulting source IDs after genSources(): // "mynews" → redirects to "mynews-latest" // "mynews-latest" → { title: "Latest", type: "realtime", interval: 120000, ... } // "mynews-hot" → { title: "Hot", type: "hottest", interval: 600000, ... } ``` -------------------------------- ### Implement Source Fetcher (TypeScript) Source: https://github.com/ourongxing/newsnow/blob/main/CONTRIBUTING.md Implement the data fetching logic for a new source in TypeScript. This includes defining interfaces for API responses and the source getter function. ```typescript interface HotVideoRes { code: number message: string ttl: number data: { list: { aid: number bvid: string title: string pubdate: number desc: string pic: string owner: { mid: number name: string face: string } stat: { view: number like: number reply: number } }[] } } const hotVideo = defineSource(async () => { const url = "https://api.bilibili.com/x/web-interface/popular" const res: HotVideoRes = await myFetch(url) return res.data.list.map(video => ({ id: video.bvid, title: video.title, url: `https://www.bilibili.com/video/${video.bvid}`, pubDate: video.pubdate * 1000, extra: { info: `${video.owner.name} · ${formatNumber(video.stat.view)}观看 · ${formatNumber(video.stat.like)}点赞`, hover: video.desc, icon: video.pic, }, })) }) ``` ```typescript function formatNumber(num: number): string { if (num >= 10000) { return `${Math.floor(num / 10000)}w+` } return num.toString() } ``` ```typescript export default defineSource({ "bilibili": hotSearch, "bilibili-hot-search": hotSearch, "bilibili-hot-video": hotVideo, }) ``` -------------------------------- ### Create Feature Branch Source: https://github.com/ourongxing/newsnow/blob/main/CONTRIBUTING.md Always create a new branch for your contributions using Git. ```bash git checkout -b feature-name ``` ```bash git checkout -b bilibili-hot-video ``` -------------------------------- ### defineRSSSource Source: https://context7.com/ourongxing/newsnow/llms.txt Creates a data source by fetching and converting an RSS or Atom feed URL into `NewsItem[]` format. It handles both RSS 2.0 and Atom feed types. ```APIDOC ## `defineRSSSource` — Create a Source from any RSS Feed ### Description Helper that fetches an RSS/Atom feed URL and converts it to `NewsItem[]`. Handles both RSS 2.0 and Atom formats. ### Usage ```typescript import { defineRSSSource } from "#app/utils/source" export default defineRSSSource("https://example.com/feed.xml", { hiddenDate: false, // Optional: include pubDate in items }) ``` ### Parameters - **feedUrl** (string) - The URL of the RSS or Atom feed. - **options** (object) - Optional configuration options. - **hiddenDate** (boolean) - If true, the `pubDate` field will not be included in the resulting `NewsItem` objects. Defaults to true. ### Result Items Shape ```json [ { "id": "...", "title": "...", "url": "...", "pubDate": "..." }, ... ] ``` ``` -------------------------------- ### React Hook for Batch Source Hydration Source: https://context7.com/ourongxing/newsnow/llms.txt TanStack Query hook for batch-loading cached news for visible columns on initial render. Triggers individual refetches for sources with stale data. ```typescript import { useEntireQuery } from "@/hooks/query" function NewsPage({ visibleSources }: { visibleSources: SourceID[] }) { // Fires POST /api/s/entire once with all source IDs // Populates individual "source" query cache entries // Triggers re-fetches for sources newer than cached version useEntireQuery(visibleSources) return } // useUpdateQuery: imperatively refetch specific sources function RefreshButton({ sourceId }: { sourceId: SourceID }) { const update = useUpdateQuery() return ( ) } ``` -------------------------------- ### Define Custom Source Getter Source: https://context7.com/ourongxing/newsnow/llms.txt Wraps a typed async function to fetch and return `NewsItem[]`. Used for custom data retrieval logic, supporting single or multi-sub-source exports. Ensure to import `NewsItem` type and use `myFetch` for requests. ```typescript // server/sources/hackernews.ts import * as cheerio from "cheerio" import type { NewsItem } from "@shared/types" export default defineSource(async (): Promise => { const baseURL = "https://news.ycombinator.com" const html: any = await myFetch(baseURL) const $ = cheerio.load(html) const news: NewsItem[] = [] $(".athing").each((_, el) => { const a = $(el).find(".titleline a").first() const id = $(el).attr("id") const score = $("#score_" + id).text() // e.g. "312 points" if (id && a.text()) { news.push({ id, title: a.text(), url: `${baseURL}/item?id=${id}`, extra: { info: score }, }) } }) return news }) // Multi-sub-source export (e.g., server/sources/github.ts) const trending = defineSource(async () => { /* ... */ }) export default defineSource({ "github": trending, "github-trending-today": trending, }) ``` -------------------------------- ### Batch Fetch Cached News (Bash) Source: https://context7.com/ourongxing/newsnow/llms.txt This endpoint allows fetching cached news from multiple sources in a single request, optimizing initial page load performance. It requires a JSON payload specifying the desired source IDs. ```bash curl -X POST "https://your-domain.com/api/s/entire" \ -H "Content-Type: application/json" \ -d '{ "sources": ["hackernews", "github", "weibo", "zhihu", "cls-telegraph"] }' ``` ```json # Expected response (array of SourceResponse): # [ # { # "status": "cache", # "id": "hackernews", # "updatedTime": 1718000000000, # "items": [ { "id": "...", "title": "...", "url": "..." }, ... ] # }, # { # "status": "cache", # "id": "github", # "items": [ { "id": "/trending-repo/path", "title": "org/repo", "url": "https://github.com/...", "extra": { "info": "✰ 1,234" } } ], # ... # } # ] ``` -------------------------------- ### GitHub OAuth Callback Handling (URL) Source: https://context7.com/ourongxing/newsnow/llms.txt This endpoint handles the callback from GitHub after user authorization. It exchanges the authorization code for a token, fetches user data, and issues a JWT. The JWT payload includes user ID, type, and expiration. ```text # GitHub redirects here automatically after user authorizes: # GET /api/oauth/github?code=abc123xyz # After successful auth, browser is redirected to: # /?login=github&jwt=eyJhbGci...&user=%7B%22avatar%22%3A%22...%22%2C%22name%22%3A%22...%22%7D # The JWT payload structure (decoded): # { # "id": "12345678", // GitHub user ID as string # "type": "github", # "exp": 1723000000 // 60 days from issue time # } ``` -------------------------------- ### defineRSSHubSource Source: https://context7.com/ourongxing/newsnow/llms.txt Fetches data from the RSSHub proxy network using JSON format. Supports sorting and limiting the number of items. ```APIDOC ## `defineRSSHubSource` — Create a Source via RSSHub ### Description Fetches data from the [RSSHub](https://rsshub.app/) proxy network using the JSON format. Supports sorting and item count limits. ### Usage ```typescript import { defineSource } from "#app/utils/source" import { defineRSSHubSource } from "#app/utils/source" export default defineSource({ "my-rsshub-feed": defineRSSHubSource( "/some/rsshub/path", { sorted: true, limit: 20 }, { hiddenDate: false } // Optional: options for the resulting NewsItems ) }) ``` ### Parameters - **rsshubPath** (string) - The path for the RSSHub route (e.g., `/v2ex/topics/latest`). - **rsshubOptions** (object) - Optional query parameters for the RSSHub request. - **sorted** (boolean) - If true, sorts the items. - **limit** (integer) - The maximum number of items to retrieve. - **itemOptions** (object) - Optional configuration for the resulting `NewsItem` objects. - **hiddenDate** (boolean) - If true, the `pubDate` field will not be included. Defaults to true. ### Example Fetch URL `https://rsshub.rssforever.com/some/rsshub/path?format=json&sorted=true&limit=20` ``` -------------------------------- ### POST /api/me — Save Authenticated User's Layout Source: https://context7.com/ourongxing/newsnow/llms.txt Persists the user's column layout, specifying which source IDs appear in which columns. The request is validated using Zod before saving. ```APIDOC ## POST /api/me — Save Authenticated User's Layout ### Description Persists the user's column layout (which source IDs appear in which columns). Validated with Zod before writing. Requires a valid JWT in the `Authorization` header. ### Method POST ### Endpoint /api/me ### Request Body - **updatedTime** (integer) - Required - Timestamp of the update. - **data** (object) - Required - Contains the user's layout configuration. - **focus** (array[string]) - List of source IDs for the focus column. - **hottest** (array[string]) - List of source IDs for the hottest column. - **realtime** (array[string]) - List of source IDs for the realtime column. ### Request Example ```json { "updatedTime": 1718000000000, "data": { "focus": ["hackernews", "producthunt"], "hottest": ["weibo", "baidu", "douyin"], "realtime": ["gelonghui", "jin10", "cls-telegraph"] } } ``` ### Response #### Success Response (200) - **success** (boolean) - Indicates if the operation was successful. - **updatedTime** (integer) - Timestamp of the update. ### Response Example ```json { "success": true, "updatedTime": 1718000000000 } ``` ``` -------------------------------- ### NewsItem Interface Structure Source: https://github.com/ourongxing/newsnow/blob/main/CONTRIBUTING.md Defines the structure for news items returned by each source. Ensure your implementation conforms to this interface. ```typescript interface NewsItem { id: string | number title: string url: string mobileUrl?: string pubDate?: number | string extra?: { hover?: string date?: number | string info?: false | string diff?: number icon?: | false | string | { url: string scale: number } } } ``` -------------------------------- ### Save Authenticated User's Layout Source: https://context7.com/ourongxing/newsnow/llms.txt Persist the user's column layout by sending updated source IDs and their column assignments. The data is validated with Zod before saving. Requires a valid JWT. ```bash curl -X POST "https://your-domain.com/api/me" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." \ -H "Content-Type: application/json" \ -d '{ "updatedTime": 1718000000000, "data": { "focus": ["hackernews", "producthunt"], "hottest": ["weibo", "baidu", "douyin"], "realtime": ["gelonghui", "jin10", "cls-telegraph"] } }' ``` ```json # Response: # { "success": true, "updatedTime": 1718000000000 } ``` -------------------------------- ### POST /api/mcp — MCP Server Endpoint Source: https://context7.com/ourongxing/newsnow/llms.txt Handles Model Context Protocol (MCP) requests over Streamable HTTP, exposing the `get_hotest_latest_news` tool for AI assistants to query live news. ```APIDOC ## POST /api/mcp — MCP Server Endpoint ### Description Handles [Model Context Protocol](https://modelcontextprotocol.io/) requests over Streamable HTTP. Exposes the `get_hotest_latest_news` tool so AI assistants can query live news through the NewsNow API. ### Method POST ### Endpoint /api/mcp ### Request Body - **jsonrpc** (string) - Required - The JSON-RPC version, typically "2.0". - **method** (string) - Required - The method to call, e.g., "tools/call". - **params** (object) - Required - Parameters for the method call. - **name** (string) - Required - The name of the tool, e.g., "get_hotest_latest_news". - **arguments** (object) - Required - Arguments for the tool call. - **id** (string) - Required - The ID of the news source. - **count** (integer) - Required - The number of news items to retrieve. - **id** (integer) - Required - The request ID. ### Request Example ```json { "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "get_hotest_latest_news", "arguments": { "id": "hackernews", "count": 5 } }, "id": 1 } ``` ### Response #### Success Response (200) - **content** (array) - A list of content blocks, typically text with links to news items. - **type** (string) - The type of content block, e.g., "text". - **text** (string) - The content of the block, e.g., "[Show HN: ...] (...)". ### Response Example ```json { "content": [ { "type": "text", "text": "[Show HN: ...] (...) " }, ... ] } ``` ``` -------------------------------- ### POST /api/s/entire — Batch Fetch Cached News Source: https://context7.com/ourongxing/newsnow/llms.txt Accepts a list of source IDs in the request body and returns all available cached news entries for those sources in a single response. This is optimized for hydrating the frontend on initial load. ```APIDOC ## POST /api/s/entire — Batch Fetch Cached News ### Description Accepts a JSON body with a list of source IDs and returns all available cached entries in a single request. Used by the frontend to hydrate the initial page load efficiently without making N individual requests. ### Method POST ### Endpoint /api/s/entire #### Request Body - **sources** (array) - Required - A list of source IDs for which to fetch cached news. - Each element should be a string representing a source ID. ### Request Example ```bash curl -X POST "https://your-domain.com/api/s/entire" \ -H "Content-Type: application/json" \ -d '{ "sources": ["hackernews", "github", "weibo", "zhihu", "cls-telegraph"] }' ``` ### Response #### Success Response (200) - Returns an array of `SourceResponse` objects, one for each requested source ID. - **status** (string) - Indicates if the data is from 'success' or 'cache'. - **id** (string) - The source ID. - **updatedTime** (integer) - Timestamp of when the data was last updated (if available). - **items** (array) - An array of news items for the source. #### Response Example ```json [ { "status": "cache", "id": "hackernews", "updatedTime": 1718000000000, "items": [ { "id": "...", "title": "...", "url": "..." }, ... ] }, { "status": "cache", "id": "github", "items": [ { "id": "/trending-repo/path", "title": "org/repo", "url": "https://github.com/...", "extra": { "info": "✰ 1,234" } } ], ... } ] ``` ``` -------------------------------- ### Generate Compiled Sources Map Source: https://context7.com/ourongxing/newsnow/llms.txt Flattens a hierarchical sources definition into a flat map. Filters out disabled sources or those specifically disabled on Cloudflare. ```typescript import { genSources } from "@shared/pre-sources" const sources = genSources() // sources["weibo"] → { name: "微博", type: "hottest", interval: 120000, color: "red", ... } // sources["wallstreetcn"] → { redirect: "wallstreetcn-quick", name: "华尔街见闻", ... } // sources["wallstreetcn-quick"] → { title: "快讯", type: "realtime", interval: 300000, ... } // sources["bilibili-hot-video"] → filtered out on CF_PAGES=1 ``` -------------------------------- ### Define Source from RSS Feed Source: https://context7.com/ourongxing/newsnow/llms.txt Helper function to create a news source by fetching and converting an RSS/Atom feed. Handles both RSS 2.0 and Atom formats. The `hiddenDate` option controls whether `pubDate` is included in the items. ```typescript // server/sources/solidot.ts import { defineRSSSource } from "#/utils/source" export default defineRSSSource("https://www.solidot.org/index.rss", { hiddenDate: false, // include pubDate in items }) // Result items shape: // [ // { id: "https://solidot.org/story/...", title: "...", url: "...", pubDate: "Mon, 10 Jun 2024 ..." }, // ... // ] ``` -------------------------------- ### Parse RSS/Atom Feeds Source: https://context7.com/ourongxing/newsnow/llms.txt Parses raw RSS 2.0 or Atom XML into a structured RSSInfo object. Supports various extensions and handles both array and single-item feeds. ```typescript import { rss2json } from "#/utils/rss2json" const feed = await rss2json("https://solidot.org/index.rss") // feed → { // title: "Solidot", // description: "奇客的信息量", // link: "https://solidot.org/", // updatedTime: "Mon, 10 Jun 2024 ...", // items: [ // { // id: "https://solidot.org/story/24/06/10/...", // title: "Example Article", // link: "https://solidot.org/story/...", // created: "Mon, 10 Jun 2024 08:00:00 +0800", // description: "Article summary..." // }, // ... // ] // } if (!feed?.items.length) throw new Error("Cannot fetch rss data") ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.