stevensDemoREADME.md1 match
8## Migrations
910In `backend/database/migrations.ts`, this app creates a new SQLite table `reactHonoStarter_messages` to store messages.
1112This "migration" runs once on every app startup because it's imported in `index.ts`. You can comment this line out for a slight (30ms) performance improvement on cold starts. It's left in so that users who fork this project will have the migration run correctly.
stevensDemopopulateDemo.ts1 match
274createMemory(
275"2025-04-13",
276"Lucas allergic to peanuts - mild reaction only, not anaphylactic.",
277"telegram",
278"telegram",
stevensDemoNotebookView.tsx5 matches
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import React, {
3useState,
4useEffect,
5useCallback,
6useMemo,
7} from "https://esm.sh/react@18.2.0";
8import { type Memory } from "../../shared/types.ts";
989}, [fetchMemories]);
9091const handleAddMemory = async (e: React.FormEvent) => {
92e.preventDefault();
93if (!newMemoryText.trim()) return;
144};
145146const handleUpdateMemory = async (e: React.FormEvent) => {
147e.preventDefault();
148if (!editingMemory || !editingMemory.text.trim()) return;
stevensDemoindex.tsx2 matches
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import { createRoot } from "https://esm.sh/react-dom@18.2.0/client";
3import { App } from "./components/App.tsx";
4
stevensDemoindex.ts1 match
1/**
2* @jsxImportSource https://esm.sh/react@18.2.0
3*/
4import { blob } from "https://esm.town/v/std/blob";
155- Current health goals and any medication reminders needed?
156157Your goal is to collect this information naturally through conversation and store it as memories (as undated memories). Once you've gathered sufficient background information, you can conclude the intake process and transition to normal reactive chat.
158159If the conversation is already past the intake stage, then analyze the message content and think about which memories might be worth creating based on the information provided.
stevensDemo.cursorrules9 matches
199- **Storage Strategy:** Only use backend storage if explicitly required; prefer simple static client-side sites
200- For persistence, use Val Town SQLite or Blob storage with `import.meta.url` for keys/table names
201- **React Configuration:** When using React libraries, pin versions with `?deps=react@18.2.0,react-dom@18.2.0` and include the `@jsxImportSource` pragma
202- When facing client-side render issues, check if all React dependencies are pinned to the same version
203- **Styling:** Default to using TailwindCSS via `<script src="https://cdn.twind.style" crossorigin></script>` unless otherwise specified
204262263### Frontend Best Practices
264- Structure as a standard client-side React app
265- Use SVG for favicons (Val Town only supports text files)
266- Separate components into individual files
267- Access bootstrapped data from `window.__INITIAL_DATA__`
268- Use React 18.2.0 consistently in all imports and the `@jsxImportSource` pragma
269- Follow the React component pattern from the example project
270- Handle API calls properly with proper error catching
271289- Always run table creation before querying
2902913. **React Configuration:**
292- All React dependencies must be pinned to 18.2.0
293- Always include `@jsxImportSource https://esm.sh/react@18.2.0` at the top of React files
294- Rendering issues often come from mismatched React versions
2952964. **File Handling:**
stevensDemoApp.tsx5 matches
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import React, {
3useState,
4useEffect,
5useCallback,
6useMemo,
7} from "https://esm.sh/react@18.2.0";
8import { type Memory } from "../../shared/types.ts";
9import { ASSETS, SCENE_POSITIONS, SOURCE_TYPES } from "./assets.ts";
165}, [fetchMemories]);
166167const handleAddMemory = async (e: React.FormEvent) => {
168e.preventDefault();
169if (!newMemoryText.trim()) return;
220};
221222const handleUpdateMemory = async (e: React.FormEvent) => {
223e.preventDefault();
224if (!editingMemory || !editingMemory.text.trim()) return;
1/** @jsxImportSource https://esm.sh/react@18.2.0 */
2import { sqlite } from "https://esm.town/v/std/sqlite";
3import { renderToString } from "npm:react-dom@18.2.0/server";
45interface Appointment {
1// Map Vote Tallying Function with Rate Limit Service Integration
2// This function counts emoji reactions and announces winners in a Hell Let Loose map vote
3import seedrandom from "https://esm.sh/seedrandom";
4import { DiscordRateLimitService } from "https://esm.town/v/ktodaz/Discord_Bot_Services/discord-rate-limit-service.tsx";
103}
104105// Get emoji mapping to decode emoji reactions
106function getEmojiMapping() {
107return {
219}
220221// Get reactions for a specific message with rate limiting
222async function getMessageReactions(channelId: string, messageId: string, emoji: string) {
223try {
224const encodedEmoji = encodeURIComponent(emoji);
225const routeKey = `/channels/${channelId}/messages/${messageId}/reactions`;
226227return rateLimitService.executeWithRateLimit(routeKey, async () => {
228const endpoint = `/channels/${channelId}/messages/${messageId}/reactions/${encodedEmoji}?limit=100`;
229const reactions = await discordRequest(endpoint);
230return reactions;
231});
232} catch (error) {
233console.error(`Error getting reactions for message ${messageId}:`, error);
234return []; // Return empty array on error to continue processing
235}
578}
579580// Get all reactions on this message
581const reactions = msg.reactions || [];
582583// Process each reaction type
584for (const reaction of Object.values(reactions)) {
585const emoji = reaction.emoji.name;
586587// Skip if this emoji is not in our mapping
592593const variant = emojiMapping[emoji];
594console.log(`Processing: Embed: ${mapName} (${variant}), Reactions: ${reaction.count}`);
595596// Get users who reacted with this emoji - using rate limited function
597const reactedUsers = await getMessageReactions(channelId, msg.id, emoji);
598console.log(`Emote key ${variant}: ${reactedUsers.length} users`);
599600// Process each user's reaction
601for (const user of reactedUsers) {
602// Skip bot reactions
603if (user.bot) continue;
604623const random = seedrandom(Date.now().toString());
624const userVotes: UserVote[] = [];
625const embedVariantReactionCounts: Record<string, number> = {};
626627// Process users in smaller batches to manage rate limits better
673for (const vote of votes) {
674const key = `${vote.embed.title} ${vote.variant}`;
675embedVariantReactionCounts[key] = (embedVariantReactionCounts[key] || 0) + 1;
676}
677}
682683// Convert to array of MapVote objects
684for (const [key, count] of Object.entries(embedVariantReactionCounts)) {
685const [mapName, variant] = key.split(/\s(?=[^\s]+$)/); // Split at the last space
686mapVotes.push({
695// Handle ties with random shuffle (match C# implementation)
696const randomVariants = seedrandom(Date.now().toString());
697const sortedVotes = Object.entries(embedVariantReactionCounts)
698.map(([key, count]) => {
699const [mapName, variant] = key.split(/\s(?=[^\s]+$)/);