// Generated by scripts/generate-manifest.mjs. Do not edit by hand. import type { AddOnCompiled } from '../../../../../types.js' type TemplateRecord = Record type TemplateAddOn = TemplateRecord & { integrations?: Array routes?: Array } type TemplateRenderContext = { [key: string]: any packageManager: any projectName: any typescript: any tailwind: any blank: any js: any jsx: any fileRouter: any codeRouter: any routerOnly: any includeExamples: any addOnEnabled: Record addOnOption: Record addOns: Array integrations: Array routes: Array getPackageManagerAddScript: (...args: Array) => string getPackageManagerRunScript: (...args: Array) => string getPackageManagerExecuteScript: (...args: Array) => string relativePath: (...args: Array) => string integrationImportContent: (...args: Array) => string integrationImportCode: (...args: Array) => string | undefined renderTemplate: (content: string) => string ignoreFile: () => never } type TemplateRenderer = (context: TemplateRenderContext) => string | undefined function __escapeXML(value: unknown) { if (value === undefined || value === null) { return '' } return String(value).replace(/[&<>'"]/g, (character) => { switch (character) { case '&': return '&' case '<': return '<' case '>': return '>' case '"': return '"' case "'": return ''' default: return character } }) } export function getManifestTemplateKey(template: string) { let hash = 0x811c9dc5 for (let i = 0; i < template.length; i++) { hash ^= template.charCodeAt(i) hash = Math.imul(hash, 0x01000193) >>> 0 } return `${hash.toString(16).padStart(8, '0')}:${template.length}` } const templateRenderers: Record = { } export function hasManifestTemplate(template: string) { return getManifestTemplateKey(template) in templateRenderers } export function renderManifestTemplate( template: string, context: TemplateRenderContext, ) { const key = getManifestTemplateKey(template) const renderer = templateRenderers[key] if (!renderer) { throw new Error(`Template ${key} was not precompiled into the manifest`) } return renderer(context) ?? '' } export const addOn = { "name": "Neon", "description": "Serverless Postgres (auto-scales to zero, branchable per environment).", "link": "https://neon.com", "phase": "add-on", "type": "add-on", "category": "database", "exclusive": [ "database" ], "color": "#00E599", "modes": [ "file-router" ], "routes": [ { "icon": "Database", "url": "/demo/neon", "name": "Neon", "path": "src/routes/demo.neon.tsx", "jsName": "NeonDemo" } ], "integrations": [ { "type": "vite-plugin", "jsName": "neon", "path": "neon-vite-plugin.ts" } ], "id": "neon", "version": "0.0.0", "packageAdditions": { "dependencies": { "@neondatabase/serverless": "^1.0.2", "vite-plugin-neon-new": "^0.8.0" } }, "readme": "## Setting up Neon\n\nWhen running the `dev` command, `vite-plugin-neon-new` will identify there is not a database setup. It will then create and seed a claimable database.\n\nIt is the same process as [Neon Launchpad](https://neon.new).\n\n> [!IMPORTANT] \n> Claimable databases expire in 72 hours.\n", "readmeIsEjs": false, "files": { "_dot_env.example.append": "# These will be automatically created by Neon Launchpad (https://neon.new).\n# You will also need to \nDATABASE_URL=\nDATABASE_URL_POOLER=\n", "db/init.sql": "-- Schema for a simple to-do list\nCREATE TABLE IF NOT EXISTS todos (\n id SERIAL PRIMARY KEY,\n title VARCHAR(255) NOT NULL,\n description TEXT,\n is_completed BOOLEAN DEFAULT FALSE,\n created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP\n);\n\n-- Initial data for the to-do list\nINSERT INTO todos (title, description, is_completed) VALUES\n('Buy groceries', 'Milk, Bread, Eggs, and Butter', FALSE),\n('Read a book', 'Finish reading \"The Great Gatsby\"', FALSE),\n('Workout', 'Go for a 30-minute run', FALSE);\n", "neon-vite-plugin.ts": "import { postgres } from 'vite-plugin-neon-new'\n\nexport default postgres({\n seed: {\n type: 'sql-script',\n path: 'db/init.sql',\n },\n referrer: 'create-tanstack',\n dotEnvKey: 'DATABASE_URL',\n})\n", "public/demo-neon.svg": "base64::PHN2ZyB2aWV3Qm94PSIwIDAgMjU2IDI1NiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMjU2IiBoZWlnaHQ9IjI1NiIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiPjxkZWZzPjxsaW5lYXJHcmFkaWVudCBpZD0iYSIgeDE9IjEwMCUiIHgyPSIxMi4wNjklIiB5MT0iMTAwJSIgeTI9IjAlIj48c3RvcCBvZmZzZXQ9IjAlIiBzdG9wLWNvbG9yPSIjNjJGNzU1Ii8+PHN0b3Agb2Zmc2V0PSIxMDAlIiBzdG9wLWNvbG9yPSIjOEZGOTg2IiBzdG9wLW9wYWNpdHk9IjAiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iYiIgeDE9IjEwMCUiIHgyPSI0MC42MDMlIiB5MT0iMTAwJSIgeTI9Ijc2Ljg5NyUiPjxzdG9wIG9mZnNldD0iMCUiIHN0b3Atb3BhY2l0eT0iLjkiLz48c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMxQTFBMUEiIHN0b3Atb3BhY2l0eT0iMCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxwYXRoIGZpbGw9IiMwMEUwRDkiIGQ9Ik0wIDQ0LjEzOUMwIDE5Ljc2MiAxOS43NjIgMCA0NC4xMzkgMEgyMTEuODZDMjM2LjIzOCAwIDI1NiAxOS43NjIgMjU2IDQ0LjEzOXYxNDIuNjQ5YzAgMjUuMjE2LTMxLjkxNSAzNi4xNi00Ny4zODggMTYuMjU2bC00OC4zOTItNjIuMjUxdjc1LjQ4NGMwIDIxLjkzOS0xNy43ODQgMzkuNzIzLTM5LjcyMiAzOS43MjNoLTc2LjM2QzE5Ljc2MyAyNTYgMCAyMzYuMjM4IDAgMjExLjg2MVY0NC4xNFptNDQuMTM5LTguODI1Yy00Ljg3OSAwLTguODI1IDMuOTQ2LTguODI1IDguODE4djE2Ny43M2MwIDQuODc4IDMuOTQ2IDguODMxIDguODE4IDguODMxaDc3LjY4OGMyLjQ0IDAgMy4wODctMS45NzcgMy4wODctNC40MTZ2LTEwMS4yMmMwLTI1LjIyMiAzMS45MTQtMzYuMTY2IDQ3LjM5NS0xNi4yNTVsNDguMzkxIDYyLjI0M1Y0NC4xNGMwLTQuODc5LjQ1NS04LjgyNS00LjQxNi04LjgyNUg0NC4xNFoiLz48cGF0aCBmaWxsPSJ1cmwoI2EpIiBkPSJNMCA0NC4xMzlDMCAxOS43NjIgMTkuNzYyIDAgNDQuMTM5IDBIMjExLjg2QzIzNi4yMzggMCAyNTYgMTkuNzYyIDI1NiA0NC4xMzl2MTQyLjY0OWMwIDI1LjIxNi0zMS45MTUgMzYuMTYtNDcuMzg4IDE2LjI1NmwtNDguMzkyLTYyLjI1MXY3NS40ODRjMCAyMS45MzktMTcuNzg0IDM5LjcyMy0zOS43MjIgMzkuNzIzaC03Ni4zNkMxOS43NjMgMjU2IDAgMjM2LjIzOCAwIDIxMS44NjFWNDQuMTRabTQ0LjEzOS04LjgyNWMtNC44NzkgMC04LjgyNSAzLjk0Ni04LjgyNSA4LjgxOHYxNjcuNzNjMCA0Ljg3OCAzLjk0NiA4LjgzMSA4LjgxOCA4LjgzMWg3Ny42ODhjMi40NCAwIDMuMDg3LTEuOTc3IDMuMDg3LTQuNDE2di0xMDEuMjJjMC0yNS4yMjIgMzEuOTE0LTM2LjE2NiA0Ny4zOTUtMTYuMjU1bDQ4LjM5MSA2Mi4yNDNWNDQuMTRjMC00Ljg3OS40NTUtOC44MjUtNC40MTYtOC44MjVINDQuMTRaIi8+PHBhdGggZmlsbD0idXJsKCNiKSIgZmlsbC1vcGFjaXR5PSIuNCIgZD0iTTAgNDQuMTM5QzAgMTkuNzYyIDE5Ljc2MiAwIDQ0LjEzOSAwSDIxMS44NkMyMzYuMjM4IDAgMjU2IDE5Ljc2MiAyNTYgNDQuMTM5djE0Mi42NDljMCAyNS4yMTYtMzEuOTE1IDM2LjE2LTQ3LjM4OCAxNi4yNTZsLTQ4LjM5Mi02Mi4yNTF2NzUuNDg0YzAgMjEuOTM5LTE3Ljc4NCAzOS43MjMtMzkuNzIyIDM5LjcyM2gtNzYuMzZDMTkuNzYzIDI1NiAwIDIzNi4yMzggMCAyMTEuODYxVjQ0LjE0Wm00NC4xMzktOC44MjVjLTQuODc5IDAtOC44MjUgMy45NDYtOC44MjUgOC44MTh2MTY3LjczYzAgNC44NzggMy45NDYgOC44MzEgOC44MTggOC44MzFoNzcuNjg4YzIuNDQgMCAzLjA4Ny0xLjk3NyAzLjA4Ny00LjQxNnYtMTAxLjIyYzAtMjUuMjIyIDMxLjkxNC0zNi4xNjYgNDcuMzk1LTE2LjI1NWw0OC4zOTEgNjIuMjQzVjQ0LjE0YzAtNC44NzkuNDU1LTguODI1LTQuNDE2LTguODI1SDQ0LjE0WiIvPjxwYXRoIGZpbGw9IiM2M0Y2NTUiIGQ9Ik0yMTEuODYxIDBDMjM2LjIzOCAwIDI1NiAxOS43NjIgMjU2IDQ0LjEzOXYxNDIuNjQ5YzAgMjUuMjE2LTMxLjkxNSAzNi4xNi00Ny4zODggMTYuMjU2bC00OC4zOTItNjIuMjUxdjc1LjQ4NGMwIDIxLjkzOS0xNy43ODQgMzkuNzIzLTM5LjcyMiAzOS43MjNhNC40MDkgNC40MDkgMCAwIDAgNC40MDktNC40MDlWMTE1LjA1OGMwLTI1LjIyMyAzMS45MTQtMzYuMTY3IDQ3LjM5NS0xNi4yNTZsNDguMzkxIDYyLjI0M1Y4LjgyNWMwLTQuODcxLTMuOTUzLTguODI1LTguODMyLTguODI1WiIvPjwvc3ZnPg==", "src/db.ts": "import { neon } from '@neondatabase/serverless'\n\nlet client: ReturnType\n\nexport async function getClient() {\n if (!process.env.DATABASE_URL) {\n return undefined\n }\n if (!client) {\n client = await neon(process.env.DATABASE_URL!)\n }\n return client\n}\n", "src/routes/demo/neon.tsx": "import { createServerFn } from '@tanstack/react-start'\nimport { createFileRoute, useRouter } from '@tanstack/react-router'\n\nimport { getClient } from '#/db'\n\nconst getTodos = createServerFn({\n method: 'GET',\n}).handler(async () => {\n const client = await getClient()\n if (!client) {\n return undefined\n }\n return (await client.query(`SELECT * FROM todos`)) as Array<{\n id: number\n title: string\n }>\n})\n\nconst insertTodo = createServerFn({\n method: 'POST',\n})\n .inputValidator((d: { title: string }) => d)\n .handler(async ({ data }) => {\n const client = await getClient()\n if (!client) {\n return undefined\n }\n await client.query(`INSERT INTO todos (title) VALUES ($1)`, [data.title])\n })\n\nexport const Route = createFileRoute('/demo/neon')({\n component: App,\n loader: async () => {\n const todos = await getTodos()\n return { todos }\n },\n})\n\nfunction App() {\n const { todos } = Route.useLoaderData()\n const router = useRouter()\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault()\n const formData = new FormData(e.target as HTMLFormElement)\n const data = Object.fromEntries(formData)\n await insertTodo({ data: { title: data.title as string } })\n router.invalidate()\n }\n\n if (!todos) {\n return (\n
\n
\n \n
\n
\n )\n }\n\n return (\n
\n
\n
\n \n \"Neon\n \n
\n

Database

\n

Neon Demo

\n
\n
\n {todos && (\n <>\n

Todos

\n
    \n {todos.map((todo: { id: number; title: string }) => (\n
  • \n
    \n {todo.title}\n #{todo.id}\n
    \n
  • \n ))}\n
\n \n \n \n \n \n )}\n
\n
\n )\n}\n\nfunction DBConnectionError() {\n return (\n
\n
\n \n \n \n
\n

Database Connection Issue

\n
\n The Neon database is not connected.\n
\n
\n

Required Steps to Fix:

\n
    \n
  • \n 1\n
    \n Use the db/init.sql file to create the database\n
    \n
  • \n
  • \n 2\n
    \n Set the DATABASE_URL environment variable to the\n connection string of your Neon database\n
    \n
  • \n
\n
\n
\n )\n}\n" }, "deletedFiles": [], "smallLogo": "" } satisfies AddOnCompiled