67- `index.ts` - Main entry point for the HTTP API
8- `cron.ts` - Cron job for periodically fetching and updating tweets
9- `database/` - Database schema and queries
10- `routes/` - API routes and static file serving
17- `GET /api/tweets/:id/metrics` - Get metrics history for a tweet
18- `GET /api/top-tweets` - Get top tweets by engagement
19- `GET /api/fetch/:username` - Fetch tweets for a specific user
20- `GET /api/search?q=query` - Search tweets by keyword
21
21searchButton: document.getElementById('searchButton'),
22usernameInput: document.getElementById('usernameInput'),
23fetchButton: document.getElementById('fetchButton'),
24latestTweetsBtn: document.getElementById('latestTweetsBtn'),
25topTweetsBtn: document.getElementById('topTweetsBtn'),
3738// API Functions
39async function fetchTweets(page = 0, pageSize = 10) {
40showLoading();
41try {
42const response = await fetch(`/api/tweets?offset=${page * pageSize}&limit=${pageSize}`);
43if (!response.ok) throw new Error('Failed to fetch tweets');
44const data = await response.json();
45hideLoading();
52}
5354async function fetchTopTweets(limit = 10) {
55showLoading();
56try {
57const response = await fetch(`/api/top-tweets?limit=${limit}`);
58if (!response.ok) throw new Error('Failed to fetch top tweets');
59const data = await response.json();
60hideLoading();
70showLoading();
71try {
72const response = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
73if (!response.ok) throw new Error('Failed to search tweets');
74const data = await response.json();
82}
8384async function fetchUserTweets(username) {
85showLoading();
86try {
87const response = await fetch(`/api/fetch/${encodeURIComponent(username)}`);
88if (!response.ok) throw new Error('Failed to fetch user tweets');
89const data = await response.json();
90hideLoading();
97}
9899async function fetchTweetMetrics(tweetId) {
100showLoading();
101try {
102const response = await fetch(`/api/tweets/${tweetId}/metrics`);
103if (!response.ok) throw new Error('Failed to fetch tweet metrics');
104const data = await response.json();
105hideLoading();
254`;
255
256// Fetch metrics history
257const metrics = await fetchTweetMetrics(tweetId);
258
259// Show modal
372state.hasMore = true;
373
374const tweets = await fetchTweets(state.currentPage, state.pageSize);
375state.tweets = tweets;
376renderTweets(tweets);
384async function loadMoreTweets() {
385state.currentPage++;
386const tweets = await fetchTweets(state.currentPage, state.pageSize);
387
388if (tweets.length > 0) {
398399async function loadTopTweets() {
400const tweets = await fetchTopTweets(20);
401state.tweets = tweets;
402renderTweets(tweets);
414}
415416async function handleFetchUser() {
417const username = elements.usernameInput.value.trim();
418if (!username) return;
419
420const tweets = await fetchUserTweets(username);
421state.tweets = tweets;
422renderTweets(tweets);
464if (e.key === 'Enter') handleSearch();
465});
466elements.fetchButton.addEventListener('click', handleFetchUser);
467elements.usernameInput.addEventListener('keypress', e => {
468if (e.key === 'Enter') handleFetchUser();
469});
470elements.closeModalBtn.addEventListener('click', closeMetricsModal);
firstindex.html3 matches
34</div>
35<div class="flex-1">
36<h2 class="text-xl font-semibold mb-2">Fetch User Tweets</h2>
37<div class="flex">
38<input type="text" id="usernameInput" placeholder="Enter Twitter username..."
39class="flex-1 px-4 py-2 border border-gray-300 rounded-l-md focus:outline-none focus:ring-2 focus:ring-blue-500">
40<button id="fetchButton" class="bg-blue-500 text-white px-4 py-2 rounded-r-md hover:bg-blue-600">
41Fetch
42</button>
43</div>
24return c.json({ success: true, data: tweets });
25} catch (error) {
26console.error("Error fetching tweets:", error);
27return c.json({ success: false, error: "Failed to fetch tweets" }, 500);
28}
29});
40return c.json({ success: true, data: tweet });
41} catch (error) {
42console.error(`Error fetching tweet ${id}:`, error);
43return c.json({ success: false, error: "Failed to fetch tweet" }, 500);
44}
45});
53return c.json({ success: true, data: metrics });
54} catch (error) {
55console.error(`Error fetching metrics for tweet ${id}:`, error);
56return c.json({ success: false, error: "Failed to fetch metrics" }, 500);
57}
58});
66return c.json({ success: true, data: tweets });
67} catch (error) {
68console.error("Error fetching top tweets:", error);
69return c.json({ success: false, error: "Failed to fetch top tweets" }, 500);
70}
71});
7273// Fetch tweets for a specific user
74api.get("/fetch/:username", async (c) => {
75const username = c.req.param("username");
76const count = parseInt(c.req.query("count") || "10");
81return c.json({ success: true, data: tweets });
82} catch (error) {
83console.error(`Error fetching tweets for ${username}:`, error);
84return c.json({ success: false, error: "Failed to fetch tweets" }, 500);
85}
86});
56/**
7* Cron job to fetch and update tweets
8*/
9export default async function() {
16const twitterClient = new TwitterClient();
17
18// 1. Fetch new tweets from specified accounts
19const accounts = ["valtown", "stevekrouse", "twitter"];
20for (const account of accounts) {
21console.log(`Fetching tweets for ${account}...`);
22await twitterClient.getUserTweets(account, 20);
23}
firsttwitter.ts2 matches
29});
3031const response = await fetch(url.toString(), {
32headers: {
33Authorization: `Bearer ${this.bearerToken}`,
4445/**
46* Fetch tweets from a user
47*/
48async getUserTweets(username: string, count = 10): Promise<Tweet[]> {
5## Features
67- Fetches tweets and metrics from Twitter/X API
8- Stores data in SQLite database
9- Periodically updates data using a cron job
23โ โ โโโ api.ts # API routes
24โ โ โโโ static.ts # Static file serving
25โ โโโ cron.ts # Cron job for data fetching
26โ โโโ index.ts # Main entry point
27โโโ frontend/
mcpmcp-server.ts5 matches
8384// Create project
85const createProjectResponse = await fetch("https://api.val.town/v1/projects", {
86method: "POST",
87headers: {
119// Function to create a file in a project
120async function createProjectFile(projectId: string, path: string, content: string, apiKey: string) {
121const response = await fetch(`https://api.val.town/v1/projects/${projectId}/files`, {
122method: "POST",
123headers: {
141// Function to set a file as HTTP handler
142async function setFileAsHttpHandler(projectId: string, path: string, apiKey: string) {
143const response = await fetch(`https://api.val.town/v1/projects/${projectId}/http-handler`, {
144method: "PUT",
145headers: {
173174// Get current main.tsx content
175const getMainFileResponse = await fetch(`https://api.val.town/v1/projects/${projectId}/files/main.tsx`, {
176headers: {
177Authorization: `Bearer ${apiKey}`,
218// Function to update a file in a project
219async function updateProjectFile(projectId: string, path: string, content: string, apiKey: string) {
220const response = await fetch(`https://api.val.town/v1/projects/${projectId}/files/${path}`, {
221method: "PUT",
222headers: {
18ReadResourceResult,
19} from "npm:@modelcontextprotocol/sdk/types.js";
20import { toFetchResponse, toReqRes } from "npm:fetch-to-node";
21import { Hono } from "npm:hono";
22import { z } from "npm:zod";
157});
158159return toFetchResponse(res);
160} catch (e) {
161console.error(e);
229});
230231return toFetchResponse(res);
232} catch (e) {
233console.error(e);
246});
247248export default app.fetch;