10โโโ core/ # Shared functionality
11โ โโโ header.js # Shared header component with auth
12โ โโโ db.js # Database utilities
13โ โโโ registry.js # App registry for routing
14โโโ apps/ # Individual applications
56- **Consistent Header**: All apps share the same header with navigation
57- **Independent Styling**: Each app can have its own unique UI/UX
58- **Database Integration**: Built-in SQLite functionality with table prefixing for isolation
59
60## Design Philosophy
7const app = new Hono();
8
9// Initialize database (if needed)
10const db = getDb('template');
11
12// Create schema if needed
13app.use('*', async (c, next) => {
14 // Uncomment and modify if you need database tables
15 /*
16 await db.execute(`
7const app = new Hono();
8
9// Initialize database
10const db = getDb('notes');
11
60 }
61
62 // Get notes from database
63 const result = await db.execute(
64 'SELECT id, title, content, created_at, updated_at FROM {{table}} WHERE email = ? ORDER BY updated_at DESC',
1/**
2 * Shared database utilities
3 * Each app can choose to use this or manage its own database operations
4 */
5
6import { sqlite } from "https://esm.town/v/stevekrouse/sqlite";
7
8// Base key for database tables to avoid conflicts
9const KEY_PREFIX = 'charbuild';
10
11/**
12 * Creates a database interface for a specific app
13 * @param {string} appName - The name of the app (used for table prefixing)
14 * @param {number} schemaVersion - The schema version for the app
15 * @returns {Object} Database interface object
16 */
17export function getDb(appName, schemaVersion = 1) {
5const respWithoutError = await vt.projects.files.retrieve(
6 "3fed38fa-00e9-11f0-99ff-569c3dd06744",
7 "backend%2Fdatabase%2Fmigrations.ts", // <-- URI encoded
8 { limit: 10, offset: 0 },
9);
14 const respWithError = await vt.projects.files.retrieve(
15 "3fed38fa-00e9-11f0-99ff-569c3dd06744",
16 "backend/database/migrations.ts", // <-- not URI encoded
17 { limit: 10, offset: 0 },
18 );
28// id: "412a62a6-00e9-11f0-bbde-569c3dd06744",
29// parentId: "ba51ef61-14d6-4805-b94b-9d6c8b42e4e9",
30// path: "backend/database/migrations.ts",
31// version: 27,
32// updatedAt: "2025-03-14T19:26:35.553Z",
33// type: "script",
34// links: {
35// self: "https://api.val.town/v1/projects/3fed38fa-00e9-11f0-99ff-569c3dd06744/files/backend/database/migrations.ts",
36// html: "https://www.val.town/x/shouser/project_updates_webhook/code/backend/database/migrations.ts",
37// module: "https://esm.town/v/shouser/project_updates_webhook/backend/database/migrations.ts"
38// }
39// }
40// ],
41// links: {
42// self: "https://api.val.town/v1/projects/3fed38fa-00e9-11f0-99ff-569c3dd06744/files/backend%2Fdatabase%2Fmigrations.ts?limit=10&offset=0"
43// }
44// }
45// Not URI encoding causes error: Error: 404 Route GET:/v1/projects/3fed38fa-00e9-11f0-99ff-569c3dd06744/files/backend/database/migrations.ts?limit=10&offset=0 not found
46// at Function.generate (file:///opt/render/.cache/deno/npm/registry.npmjs.org/@valtown/sdk/0.36.0/error.mjs:45:20)
47// at ValTown.makeStatusError (file:///opt/render/.cache/deno/npm/registry.npmjs.org/@valtown/sdk/0.36.0/core.mjs:272:25)
57// },
58// error: {
59// message: "Route GET:/v1/projects/3fed38fa-00e9-11f0-99ff-569c3dd06744/files/backend/database/migrations.ts?limit=10&offset=0 not found",
60// error: "Not Found",
61// statusCode: 404
2import { MainLayout } from '../../layouts/MainLayout';
3import { AppConfig, AppContext } from '../registry';
4import { initAppDatabase } from '../../utils/db';
5import { sqlite } from "https://esm.town/v/std/sqlite";
6
80`;
81
82// Setup database schema
83const SCHEMA = `
84CREATE TABLE IF NOT EXISTS questie_quests (
92`;
93
94// Initialize the database
95initAppDatabase('questie', SCHEMA);
96
97// Questie app handler
115 const status = formData.get('status') || 'pending';
116
117 // Save the new quest to database
118 await sqlite.execute(
119 `INSERT INTO questie_quests (email, title, description, status) VALUES (?, ?, ?, ?)`,
8
9export async function QuestieDetail({ email, questId }: QuestieDetailProps) {
10 // Fetch quest details from the database
11 let quest = null;
12
7
8export async function QuestieList({ email }: QuestieListProps) {
9 // Fetch quests from the database
10 let quests = [];
11 try {
1import { sqlite } from "https://esm.town/v/std/sqlite";
2
3// Helper function to initialize an app's database
4export async function initAppDatabase(appName: string, schema: string) {
5 try {
6 await sqlite.execute(schema);
7 console.log(`Initialized database schema for ${appName}`);
8 return true;
9 } catch (error) {
10 console.error(`Error initializing database for ${appName}:`, error);
11 return false;
12 }
1import { generateCode } from "./backend/generate-code";
2import { createTables } from "./database/migrations";
3import { createProject, getCode, getNextVersionNumber, insertVersion } from "./database/queries";
4
5async function servePublicFile(path: string): Promise<Response> {