kaddidlehopper 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +104 -208
- package/dist/index.js +1 -31
- package/dist/types/cli.d.ts +1 -8
- package/dist/types/types.d.ts +7 -12
- package/package.json +1 -2
- package/src/cli.ts +129 -271
- package/src/index.ts +1 -47
- package/src/types.ts +7 -13
- package/CONTEXT.md +0 -139
- package/add-ons/ai/README.md +0 -34
- package/add-ons/ai/assets/AGENTS.md.append +0 -24
- package/add-ons/ai/assets/_dot_env.local.append +0 -13
- package/add-ons/ai/assets/src/components/AIAssistant.tsx +0 -149
- package/add-ons/ai/assets/src/lib/ai-hook.ts +0 -21
- package/add-ons/ai/assets/src/lib/weather-tools.ts +0 -30
- package/add-ons/ai/assets/src/routes/api.chat.ts +0 -94
- package/add-ons/ai/assets/src/routes/chat.css +0 -175
- package/add-ons/ai/assets/src/routes/chat.tsx +0 -141
- package/add-ons/ai/info.json +0 -22
- package/add-ons/ai/package.json +0 -17
- package/add-ons/ai/small-logo.svg +0 -8
- package/add-ons/db/assets/AGENTS.md.append +0 -22
- package/add-ons/db/assets/DB-SETUP.md +0 -65
- package/add-ons/db/assets/_dot_env.local.append +0 -2
- package/add-ons/db/assets/drizzle.config.ts +0 -10
- package/add-ons/db/assets/src/db/index.ts +0 -8
- package/add-ons/db/assets/src/db/schema.ts +0 -8
- package/add-ons/db/assets/src/routes/db-example.tsx +0 -118
- package/add-ons/db/assets/src/server/guestbook.functions.ts +0 -23
- package/add-ons/db/info.json +0 -22
- package/add-ons/db/package.json +0 -10
- package/add-ons/forms/assets/AGENTS.md.append +0 -13
- package/add-ons/forms/assets/public/form-example.html +0 -14
- package/add-ons/forms/assets/src/routes/form-example.tsx +0 -76
- package/add-ons/forms/info.json +0 -18
- package/add-ons/forms/package.json +0 -3
- package/examples/ai-chat/README.md +0 -36
- package/examples/ai-chat/assets/AGENTS.md.append +0 -24
- package/examples/ai-chat/assets/src/lib/ai-hook.ts +0 -21
- package/examples/ai-chat/assets/src/lib/weather-tools.ts +0 -30
- package/examples/ai-chat/assets/src/routes/__root.tsx +0 -57
- package/examples/ai-chat/assets/src/routes/api.chat.ts +0 -94
- package/examples/ai-chat/assets/src/routes/index.tsx +0 -141
- package/examples/ai-chat/assets/src/styles.css +0 -165
- package/examples/ai-chat/info.json +0 -25
- package/examples/ai-chat/package.json +0 -14
- package/examples/blog/README.md +0 -60
- package/examples/blog/assets/AGENTS.md.append +0 -18
- package/examples/blog/assets/content/posts/beach.md +0 -12
- package/examples/blog/assets/content/posts/jungle.md.ejs +0 -12
- package/examples/blog/assets/content/posts/mountains.md.ejs +0 -12
- package/examples/blog/assets/content/posts/snorkeling.md.ejs +0 -12
- package/examples/blog/assets/content/posts/waterfall.md.ejs +0 -12
- package/examples/blog/assets/content-collections.ts +0 -30
- package/examples/blog/assets/public/beach.jpg +0 -0
- package/examples/blog/assets/public/jungle.jpg +0 -0
- package/examples/blog/assets/public/mountains.jpg +0 -0
- package/examples/blog/assets/public/snorkeling.jpg +0 -0
- package/examples/blog/assets/public/waterfall.jpg +0 -0
- package/examples/blog/assets/src/components/Header.tsx +0 -52
- package/examples/blog/assets/src/components/VacayAssistant.tsx +0 -205
- package/examples/blog/assets/src/components/blog-posts.tsx +0 -78
- package/examples/blog/assets/src/components/ui/card.tsx +0 -92
- package/examples/blog/assets/src/lib/blog-ai-hook.ts +0 -25
- package/examples/blog/assets/src/lib/blog-tools.ts +0 -111
- package/examples/blog/assets/src/lib/utils.ts +0 -6
- package/examples/blog/assets/src/routes/__root.tsx +0 -57
- package/examples/blog/assets/src/routes/api.blog-chat.ts +0 -117
- package/examples/blog/assets/src/routes/category.$category.tsx +0 -19
- package/examples/blog/assets/src/routes/index.tsx +0 -19
- package/examples/blog/assets/src/routes/posts.$slug.tsx +0 -63
- package/examples/blog/assets/src/styles.css +0 -138
- package/examples/blog/info.json +0 -40
- package/examples/blog/package.json +0 -23
- package/examples/calculator/README.md +0 -16
- package/examples/calculator/assets/AGENTS.md.append +0 -9
- package/examples/calculator/assets/src/components/Calculator.tsx +0 -238
- package/examples/calculator/assets/src/components/Header.tsx +0 -17
- package/examples/calculator/assets/src/routes/__root.tsx +0 -57
- package/examples/calculator/assets/src/routes/index.tsx +0 -14
- package/examples/calculator/info.json +0 -20
- package/examples/calculator/package.json +0 -1
- package/examples/dashboard/README.md +0 -17
- package/examples/dashboard/assets/AGENTS.md.append +0 -12
- package/examples/dashboard/assets/src/components/Header.tsx +0 -17
- package/examples/dashboard/assets/src/routes/__root.tsx +0 -57
- package/examples/dashboard/assets/src/routes/index.tsx +0 -158
- package/examples/dashboard/info.json +0 -19
- package/examples/dashboard/package.json +0 -6
- package/examples/ecommerce/README.md +0 -48
- package/examples/ecommerce/assets/AGENTS.md.append +0 -22
- package/examples/ecommerce/assets/public/logo.png +0 -0
- package/examples/ecommerce/assets/public/motorcycle-scooter.jpg +0 -0
- package/examples/ecommerce/assets/src/components/BuyButton.tsx +0 -35
- package/examples/ecommerce/assets/src/components/Header.tsx +0 -36
- package/examples/ecommerce/assets/src/components/MotorcycleAIAssistant.tsx +0 -162
- package/examples/ecommerce/assets/src/components/MotorcycleRecommendation.tsx +0 -53
- package/examples/ecommerce/assets/src/data/motorcycles.ts +0 -27
- package/examples/ecommerce/assets/src/lib/motorcycle-ai-hook.ts +0 -24
- package/examples/ecommerce/assets/src/lib/motorcycle-tools.ts +0 -42
- package/examples/ecommerce/assets/src/lib/stripe.server.ts +0 -39
- package/examples/ecommerce/assets/src/routes/__root.tsx +0 -57
- package/examples/ecommerce/assets/src/routes/api.motorcycle-chat.ts +0 -78
- package/examples/ecommerce/assets/src/routes/checkout/cancel.tsx +0 -25
- package/examples/ecommerce/assets/src/routes/checkout/success.tsx +0 -25
- package/examples/ecommerce/assets/src/routes/index.tsx +0 -76
- package/examples/ecommerce/assets/src/routes/motorcycles/$motorcycleId.tsx +0 -55
- package/examples/ecommerce/assets/src/store/motorcycle-assistant.ts +0 -3
- package/examples/ecommerce/assets/src/styles.css +0 -212
- package/examples/ecommerce/info.json +0 -38
- package/examples/ecommerce/package.json +0 -13
- package/examples/events/README.md +0 -110
- package/examples/events/assets/AGENTS.md.append +0 -21
- package/examples/events/assets/content/speakers/andre-costa.md +0 -22
- package/examples/events/assets/content/speakers/hans-mueller.md.ejs +0 -22
- package/examples/events/assets/content/speakers/isabella-martinez.md.ejs +0 -22
- package/examples/events/assets/content/speakers/kenji-nakamura.md.ejs +0 -22
- package/examples/events/assets/content/speakers/marie-dubois.md.ejs +0 -20
- package/examples/events/assets/content/speakers/priya-sharma.md.ejs +0 -22
- package/examples/events/assets/content/talks/croissant-lamination-secrets.md +0 -39
- package/examples/events/assets/content/talks/french-macaron-mastery.md.ejs +0 -39
- package/examples/events/assets/content/talks/neapolitan-pizza-tradition-meets-innovation.md.ejs +0 -39
- package/examples/events/assets/content/talks/savory-breads-of-the-mediterranean.md.ejs +0 -39
- package/examples/events/assets/content/talks/sourdough-from-starter-to-masterpiece.md.ejs +0 -36
- package/examples/events/assets/content/talks/the-art-of-the-perfect-tart.md.ejs +0 -32
- package/examples/events/assets/content/talks/the-science-of-sugar.md.ejs +0 -39
- package/examples/events/assets/content/talks/umami-in-pastry-east-meets-west.md.ejs +0 -39
- package/examples/events/assets/content-collections.ts +0 -56
- package/examples/events/assets/public/background-1.jpg +0 -0
- package/examples/events/assets/public/background-2.jpg +0 -0
- package/examples/events/assets/public/background-3.jpg +0 -0
- package/examples/events/assets/public/background-4.jpg +0 -0
- package/examples/events/assets/public/conference-logo.png +0 -0
- package/examples/events/assets/public/favicon.ico +0 -0
- package/examples/events/assets/public/speakers/andre-costa.jpg +0 -0
- package/examples/events/assets/public/speakers/hans-mueller.jpg +0 -0
- package/examples/events/assets/public/speakers/isabella-martinez.jpg +0 -0
- package/examples/events/assets/public/speakers/kenji-nakamura.jpg +0 -0
- package/examples/events/assets/public/speakers/marie-dubois.jpg +0 -0
- package/examples/events/assets/public/speakers/priya-sharma.jpg +0 -0
- package/examples/events/assets/public/talks/croissant-lamination-secrets.jpg +0 -0
- package/examples/events/assets/public/talks/french-macaron-mastery.jpg +0 -0
- package/examples/events/assets/public/talks/neapolitan-pizza-tradition-meets-innovation.jpg +0 -0
- package/examples/events/assets/public/talks/savory-breads-of-the-mediterranean.jpg +0 -0
- package/examples/events/assets/public/talks/sourdough-from-starter-to-masterpiece.jpg +0 -0
- package/examples/events/assets/public/talks/the-art-of-the-perfect-tart.jpg +0 -0
- package/examples/events/assets/public/talks/the-science-of-sugar.jpg +0 -0
- package/examples/events/assets/public/talks/umami-in-pastry-east-meets-west.jpg +0 -0
- package/examples/events/assets/public/tanstack-circle-logo.png +0 -0
- package/examples/events/assets/public/tanstack-word-logo-white.svg +0 -1
- package/examples/events/assets/src/components/Header.tsx +0 -59
- package/examples/events/assets/src/components/HeaderNav.tsx +0 -67
- package/examples/events/assets/src/components/HeroCarousel.tsx +0 -61
- package/examples/events/assets/src/components/RemyAssistant.tsx +0 -207
- package/examples/events/assets/src/components/SpeakerCard.tsx +0 -67
- package/examples/events/assets/src/components/TalkCard.tsx +0 -77
- package/examples/events/assets/src/components/ui/card.tsx +0 -92
- package/examples/events/assets/src/lib/conference-ai-hook.ts +0 -26
- package/examples/events/assets/src/lib/conference-tools.ts +0 -210
- package/examples/events/assets/src/lib/model-selection.ts +0 -1
- package/examples/events/assets/src/lib/utils.ts +0 -6
- package/examples/events/assets/src/routes/__root.tsx +0 -70
- package/examples/events/assets/src/routes/api.remy-chat.ts +0 -119
- package/examples/events/assets/src/routes/index.tsx +0 -192
- package/examples/events/assets/src/routes/schedule.index.tsx +0 -274
- package/examples/events/assets/src/routes/speakers.$slug.tsx +0 -122
- package/examples/events/assets/src/routes/speakers.index.tsx +0 -40
- package/examples/events/assets/src/routes/talks.$slug.tsx +0 -116
- package/examples/events/assets/src/routes/talks.index.tsx +0 -40
- package/examples/events/assets/src/styles.css +0 -182
- package/examples/events/info.json +0 -61
- package/examples/events/package.json +0 -23
- package/examples/marketing/README.md +0 -60
- package/examples/marketing/assets/AGENTS.md.append +0 -15
- package/examples/marketing/assets/public/logo.png +0 -0
- package/examples/marketing/assets/public/motorcycle-adventure.jpg +0 -0
- package/examples/marketing/assets/public/motorcycle-cruiser.jpg +0 -0
- package/examples/marketing/assets/public/motorcycle-scooter.jpg +0 -0
- package/examples/marketing/assets/public/motorcycle-sport.jpg +0 -0
- package/examples/marketing/assets/public/motorcycle-supersport.jpg +0 -0
- package/examples/marketing/assets/src/components/Header.tsx +0 -36
- package/examples/marketing/assets/src/components/MotorcycleAIAssistant.tsx +0 -162
- package/examples/marketing/assets/src/components/MotorcycleRecommendation.tsx +0 -53
- package/examples/marketing/assets/src/data/motorcycles.ts.ejs +0 -77
- package/examples/marketing/assets/src/lib/motorcycle-ai-hook.ts +0 -24
- package/examples/marketing/assets/src/lib/motorcycle-tools.ts +0 -42
- package/examples/marketing/assets/src/routes/__root.tsx +0 -57
- package/examples/marketing/assets/src/routes/api.motorcycle-chat.ts +0 -78
- package/examples/marketing/assets/src/routes/index.tsx +0 -72
- package/examples/marketing/assets/src/routes/motorcycles/$motorcycleId.tsx +0 -56
- package/examples/marketing/assets/src/store/motorcycle-assistant.ts +0 -3
- package/examples/marketing/assets/src/styles.css +0 -212
- package/examples/marketing/info.json +0 -33
- package/examples/marketing/package.json +0 -14
- package/examples/portfolio/README.md +0 -49
- package/examples/portfolio/assets/AGENTS.md.append +0 -21
- package/examples/portfolio/assets/content/blog/getting-started-with-tanstack.md +0 -53
- package/examples/portfolio/assets/content/blog/react-19-features.md +0 -78
- package/examples/portfolio/assets/content/blog/tailwind-css-v4-guide.md +0 -60
- package/examples/portfolio/assets/content/education/code-school.md +0 -17
- package/examples/portfolio/assets/content/jobs/initech-junior.md +0 -20
- package/examples/portfolio/assets/content/projects/portfolio-site.md +0 -15
- package/examples/portfolio/assets/content/projects/task-manager.md +0 -15
- package/examples/portfolio/assets/content-collections.ts +0 -65
- package/examples/portfolio/assets/public/contact.html +0 -6
- package/examples/portfolio/assets/public/headshot-on-white.jpg +0 -0
- package/examples/portfolio/assets/src/components/Header.tsx +0 -33
- package/examples/portfolio/assets/src/components/ResumeAssistant.tsx +0 -193
- package/examples/portfolio/assets/src/components/ui/badge.tsx +0 -46
- package/examples/portfolio/assets/src/components/ui/card.tsx +0 -92
- package/examples/portfolio/assets/src/components/ui/checkbox.tsx +0 -30
- package/examples/portfolio/assets/src/components/ui/hover-card.tsx +0 -44
- package/examples/portfolio/assets/src/components/ui/separator.tsx +0 -26
- package/examples/portfolio/assets/src/lib/resume-ai-hook.ts +0 -21
- package/examples/portfolio/assets/src/lib/resume-tools.ts +0 -165
- package/examples/portfolio/assets/src/lib/utils.ts +0 -6
- package/examples/portfolio/assets/src/routes/__root.tsx +0 -57
- package/examples/portfolio/assets/src/routes/api.resume-chat.ts +0 -116
- package/examples/portfolio/assets/src/routes/blog/$slug.tsx +0 -73
- package/examples/portfolio/assets/src/routes/contact.tsx +0 -121
- package/examples/portfolio/assets/src/routes/index.tsx +0 -55
- package/examples/portfolio/assets/src/routes/projects.tsx +0 -62
- package/examples/portfolio/assets/src/routes/resume.tsx +0 -220
- package/examples/portfolio/assets/src/styles.css +0 -138
- package/examples/portfolio/info.json +0 -50
- package/examples/portfolio/package.json +0 -26
- package/examples/resume/README.md +0 -82
- package/examples/resume/assets/AGENTS.md.append +0 -19
- package/examples/resume/assets/content/education/code-school.md +0 -17
- package/examples/resume/assets/content/jobs/freelance.md.ejs +0 -13
- package/examples/resume/assets/content/jobs/initech-junior.md +0 -20
- package/examples/resume/assets/content/jobs/initech-lead.md.ejs +0 -29
- package/examples/resume/assets/content/jobs/initrode-senior.md.ejs +0 -28
- package/examples/resume/assets/content-collections.ts +0 -36
- package/examples/resume/assets/public/headshot-on-white.jpg +0 -0
- package/examples/resume/assets/src/components/Header.tsx +0 -33
- package/examples/resume/assets/src/components/ResumeAssistant.tsx +0 -193
- package/examples/resume/assets/src/components/ui/badge.tsx +0 -46
- package/examples/resume/assets/src/components/ui/card.tsx +0 -92
- package/examples/resume/assets/src/components/ui/checkbox.tsx +0 -30
- package/examples/resume/assets/src/components/ui/hover-card.tsx +0 -44
- package/examples/resume/assets/src/components/ui/separator.tsx +0 -26
- package/examples/resume/assets/src/lib/resume-ai-hook.ts +0 -21
- package/examples/resume/assets/src/lib/resume-tools.ts +0 -165
- package/examples/resume/assets/src/lib/utils.ts +0 -6
- package/examples/resume/assets/src/routes/api.resume-chat.ts +0 -110
- package/examples/resume/assets/src/routes/index.tsx +0 -220
- package/examples/resume/assets/src/styles.css +0 -138
- package/examples/resume/info.json +0 -35
- package/examples/resume/package.json +0 -26
- package/examples/saas/README.md +0 -16
- package/examples/saas/assets/AGENTS.md.append +0 -9
- package/examples/saas/assets/src/components/Header.tsx +0 -17
- package/examples/saas/assets/src/routes/__root.tsx +0 -57
- package/examples/saas/assets/src/routes/faq.tsx +0 -94
- package/examples/saas/assets/src/routes/index.tsx +0 -197
- package/examples/saas/info.json +0 -23
- package/examples/saas/package.json +0 -1
- package/examples/survey/README.md +0 -20
- package/examples/survey/assets/AGENTS.md.append +0 -9
- package/examples/survey/assets/public/form-survey.html +0 -15
- package/examples/survey/assets/src/components/SurveyForm.tsx +0 -128
- package/examples/survey/assets/src/routes/index.tsx +0 -14
- package/examples/survey/info.json +0 -19
- package/examples/survey/package.json +0 -1
- package/project/base/AGENTS.md +0 -86
- package/project/base/_dot_claude/skills/content-collections/SKILL.md +0 -505
- package/project/base/_dot_claude/skills/netlify-blobs/SKILL.md +0 -410
- package/project/base/_dot_claude/skills/netlify-db/SKILL.md +0 -424
- package/project/base/_dot_claude/skills/netlify-debugging/SKILL.md +0 -419
- package/project/base/_dot_claude/skills/netlify-forms/SKILL.md +0 -243
- package/project/base/_dot_claude/skills/netlify-functions/SKILL.md +0 -372
- package/project/base/_dot_claude/skills/tanstack-start-api-routes/SKILL.md +0 -421
- package/project/base/_dot_claude/skills/tanstack-start-loaders/SKILL.md +0 -426
- package/project/base/_dot_claude/skills/tanstack-start-project-setup/SKILL.md +0 -493
- package/project/base/_dot_claude/skills/tanstack-start-routes/SKILL.md +0 -430
- package/project/base/_dot_claude/skills/tanstack-start-server-functions/SKILL.md +0 -445
- package/project/base/_dot_claude/skills/tanstack-start-typesafe-routing/SKILL.md +0 -494
- package/project/base/_dot_gitignore +0 -8
- package/project/base/netlify.toml +0 -7
- package/project/base/package.json +0 -33
- package/project/base/public/favicon.ico +0 -0
- package/project/base/public/tanstack-circle-logo.png +0 -0
- package/project/base/public/tanstack-word-logo-white.svg +0 -1
- package/project/base/src/components/Header.tsx +0 -17
- package/project/base/src/components/HeaderNav.tsx.ejs +0 -179
- package/project/base/src/router.tsx +0 -15
- package/project/base/src/routes/__root.tsx +0 -57
- package/project/base/src/routes/index.tsx +0 -48
- package/project/base/src/styles.css +0 -15
- package/project/base/tsconfig.json +0 -28
- package/project/base/vite.config.ts.ejs +0 -25
- package/project/info.json +0 -17
- package/project/packages.json +0 -22
- package/scripts/check-outdated-packages.js +0 -421
- package/src/agents-md.ts +0 -139
package/add-ons/ai/info.json
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "AI Chat",
|
|
3
|
-
"phase": "add-on",
|
|
4
|
-
"description": "Add AI chat capabilities with multi-vendor support (OpenAI, Anthropic, Gemini, Ollama). Includes a chat page and pop-up assistant.",
|
|
5
|
-
"link": "https://tanstack.com/ai",
|
|
6
|
-
"modes": ["file-router"],
|
|
7
|
-
"type": "add-on",
|
|
8
|
-
"priority": 20,
|
|
9
|
-
"routes": [{"icon": "MessagesSquare", "url": "/chat", "name": "Chat", "path": "src/routes/chat.tsx", "jsName": "ChatPage"}],
|
|
10
|
-
"features": ["tanstack-ai"],
|
|
11
|
-
"integrations": [{"type": "header-user", "path": "src/components/AIAssistant.tsx", "jsName": "AIAssistant"}],
|
|
12
|
-
"dependsOn": [],
|
|
13
|
-
"variables": [],
|
|
14
|
-
"packageFileDescriptions": {
|
|
15
|
-
"src/lib/ai-hook.ts": "useAIChat hook: useChat with fetchServerSentEvents connection to /api/chat.",
|
|
16
|
-
"src/routes/chat.tsx": "Chat page route (/chat): Weather Chat UI with messages, input form, send/stop.",
|
|
17
|
-
"src/routes/api.chat.ts": "POST handler for /api/chat: multi-provider AI (Anthropic, OpenAI, Gemini, Ollama) with getWeather tool and SSE streaming.",
|
|
18
|
-
"src/lib/weather-tools.ts": "TanStack AI getWeather tool definition; server returns mock temperature, condition, humidity for a city.",
|
|
19
|
-
"src/routes/chat.css": "Chat page styles: prose/markdown, scrollbar, message animations.",
|
|
20
|
-
"src/components/AIAssistant.tsx": "Pop-up AI assistant component for header; toggleable chat panel with useAIChat."
|
|
21
|
-
}
|
|
22
|
-
}
|
package/add-ons/ai/package.json
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"dependencies": {
|
|
3
|
-
"@tanstack/ai": "0.2.2",
|
|
4
|
-
"@tanstack/ai-anthropic": "0.2.0",
|
|
5
|
-
"@tanstack/ai-client": "0.2.2",
|
|
6
|
-
"@tanstack/ai-gemini": "0.3.2",
|
|
7
|
-
"@tanstack/ai-ollama": "0.3.0",
|
|
8
|
-
"@tanstack/ai-openai": "0.3.0",
|
|
9
|
-
"@tanstack/ai-react": "0.2.2",
|
|
10
|
-
"@tanstack/react-store": "^0.8.0",
|
|
11
|
-
"@tanstack/store": "^0.8.0",
|
|
12
|
-
"highlight.js": "^11.11.1",
|
|
13
|
-
"streamdown": "^2.1.0",
|
|
14
|
-
"lucide-react": "^0.563.0",
|
|
15
|
-
"zod": "^4.3.5"
|
|
16
|
-
}
|
|
17
|
-
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2
|
-
<path d="M12 8V4H8"/>
|
|
3
|
-
<rect width="16" height="12" x="4" y="8" rx="2"/>
|
|
4
|
-
<path d="M2 14h2"/>
|
|
5
|
-
<path d="M20 14h2"/>
|
|
6
|
-
<path d="M15 13v2"/>
|
|
7
|
-
<path d="M9 13v2"/>
|
|
8
|
-
</svg>
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
### Netlify DB Integration
|
|
2
|
-
|
|
3
|
-
Guestbook demo powered by Netlify DB (Neon Postgres) with Drizzle ORM.
|
|
4
|
-
|
|
5
|
-
**Setup:**
|
|
6
|
-
1. Link project: `netlify login` then `netlify init`
|
|
7
|
-
2. Provision database: `netlify db init` (creates Neon Postgres, sets `DATABASE_URL`)
|
|
8
|
-
3. Push schema: `npx drizzle-kit push` (creates `guestbook` table from `src/db/schema.ts`)
|
|
9
|
-
4. Run locally: `netlify dev` (visit `/db-example`)
|
|
10
|
-
|
|
11
|
-
**Key files:**
|
|
12
|
-
- `src/db/schema.ts` - Guestbook table (id, name, message, createdAt)
|
|
13
|
-
- `src/server/guestbook.functions.ts` - Server functions: `getEntries`, `addEntry`
|
|
14
|
-
- `drizzle.config.ts` - Drizzle Kit config for migrations
|
|
15
|
-
|
|
16
|
-
**Dependencies:** drizzle-orm, @neondatabase/serverless, drizzle-kit
|
|
17
|
-
|
|
18
|
-
## Environment Variables
|
|
19
|
-
|
|
20
|
-
```
|
|
21
|
-
DATABASE_URL=... # Auto-set by netlify db init; pull with netlify env:pull
|
|
22
|
-
```
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# Netlify DB Setup
|
|
2
|
-
|
|
3
|
-
After scaffolding your project with the DB add-on, follow these steps to get Netlify DB running.
|
|
4
|
-
|
|
5
|
-
## Prerequisites
|
|
6
|
-
|
|
7
|
-
- A [Netlify](https://www.netlify.com/) account
|
|
8
|
-
- The [Netlify CLI](https://docs.netlify.com/cli/get-started/) installed (`npm install -g netlify-cli`)
|
|
9
|
-
|
|
10
|
-
## 1. Link Your Project to Netlify
|
|
11
|
-
|
|
12
|
-
If you haven't already, link your local project to a Netlify site:
|
|
13
|
-
|
|
14
|
-
```sh
|
|
15
|
-
netlify login
|
|
16
|
-
netlify init
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Follow the prompts to create a new site or link to an existing one.
|
|
20
|
-
|
|
21
|
-
## 2. Initialize the Database
|
|
22
|
-
|
|
23
|
-
Run the Netlify DB initialization command to provision a Postgres database for your site:
|
|
24
|
-
|
|
25
|
-
```sh
|
|
26
|
-
netlify db init
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
This creates a Neon Postgres database attached to your Netlify site and sets the `DATABASE_URL` environment variable automatically.
|
|
30
|
-
|
|
31
|
-
## 3. Push the Schema to the Database
|
|
32
|
-
|
|
33
|
-
Use Drizzle Kit to push your schema to the database:
|
|
34
|
-
|
|
35
|
-
```sh
|
|
36
|
-
npx drizzle-kit push
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
This creates the `guestbook` table defined in `src/db/schema.ts`.
|
|
40
|
-
|
|
41
|
-
## 4. Run the Dev Server
|
|
42
|
-
|
|
43
|
-
Start local development via the Netlify CLI:
|
|
44
|
-
|
|
45
|
-
```sh
|
|
46
|
-
netlify dev
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
Then visit [http://localhost:8888/db-example](http://localhost:8888/db-example) to see the guestbook demo.
|
|
50
|
-
|
|
51
|
-
## 5. Deploy
|
|
52
|
-
|
|
53
|
-
When you're ready, deploy to Netlify:
|
|
54
|
-
|
|
55
|
-
```sh
|
|
56
|
-
netlify deploy --build --prod
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Or push to your git remote and Netlify will build and deploy automatically if continuous deployment is configured.
|
|
60
|
-
|
|
61
|
-
## Troubleshooting
|
|
62
|
-
|
|
63
|
-
- **`DATABASE_URL` not set** — Make sure you've run `netlify db:init` and `netlify env:pull`.
|
|
64
|
-
- **Table not found errors** — Run `npx drizzle-kit push` to ensure the schema is applied.
|
|
65
|
-
- **Connection errors locally** — Confirm `.env.local` has the correct `DATABASE_URL` and that your IP is not blocked by the Neon project settings.
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core";
|
|
2
|
-
|
|
3
|
-
export const guestbook = pgTable("guestbook", {
|
|
4
|
-
id: serial("id").primaryKey(),
|
|
5
|
-
name: text("name").notNull(),
|
|
6
|
-
message: text("message").notNull(),
|
|
7
|
-
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
8
|
-
});
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
-
import { useRouter } from "@tanstack/react-router";
|
|
3
|
-
import { useState } from "react";
|
|
4
|
-
import { getEntries, addEntry } from "@/server/guestbook.functions";
|
|
5
|
-
|
|
6
|
-
export const Route = createFileRoute("/db-example")({
|
|
7
|
-
loader: async () => {
|
|
8
|
-
const entries = await getEntries();
|
|
9
|
-
return { entries };
|
|
10
|
-
},
|
|
11
|
-
component: DBExample,
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
function DBExample() {
|
|
15
|
-
const { entries } = Route.useLoaderData();
|
|
16
|
-
const router = useRouter();
|
|
17
|
-
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
18
|
-
|
|
19
|
-
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
|
20
|
-
e.preventDefault();
|
|
21
|
-
const form = e.currentTarget;
|
|
22
|
-
setIsSubmitting(true);
|
|
23
|
-
|
|
24
|
-
const formData = new FormData(form);
|
|
25
|
-
const name = formData.get("name") as string;
|
|
26
|
-
const message = formData.get("message") as string;
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
await addEntry({ data: { name, message } });
|
|
30
|
-
form.reset();
|
|
31
|
-
await router.invalidate();
|
|
32
|
-
} catch (error) {
|
|
33
|
-
console.error("Failed to add entry:", error);
|
|
34
|
-
} finally {
|
|
35
|
-
setIsSubmitting(false);
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
return (
|
|
40
|
-
<div className="min-h-screen bg-linear-to-br from-teal-900 via-emerald-800 to-cyan-900 flex items-center justify-center">
|
|
41
|
-
<div className="w-full max-w-lg px-4 py-12">
|
|
42
|
-
<h1 className="text-4xl md:text-5xl font-black text-white mb-2 tracking-tight">
|
|
43
|
-
Guestbook
|
|
44
|
-
</h1>
|
|
45
|
-
<p className="text-teal-100/80 mb-8">
|
|
46
|
-
Sign the guestbook — powered by Netlify DB with Drizzle ORM.
|
|
47
|
-
</p>
|
|
48
|
-
|
|
49
|
-
<form onSubmit={handleSubmit} className="space-y-6 mb-12">
|
|
50
|
-
<div>
|
|
51
|
-
<label
|
|
52
|
-
htmlFor="name"
|
|
53
|
-
className="block text-sm font-medium text-teal-200 mb-2"
|
|
54
|
-
>
|
|
55
|
-
Name
|
|
56
|
-
</label>
|
|
57
|
-
<input
|
|
58
|
-
type="text"
|
|
59
|
-
id="name"
|
|
60
|
-
name="name"
|
|
61
|
-
required
|
|
62
|
-
className="w-full px-4 py-3 rounded-lg bg-white/10 border border-white/20 text-white placeholder-teal-300/50 focus:outline-none focus:ring-2 focus:ring-teal-400 focus:border-transparent"
|
|
63
|
-
placeholder="Your name"
|
|
64
|
-
/>
|
|
65
|
-
</div>
|
|
66
|
-
|
|
67
|
-
<div>
|
|
68
|
-
<label
|
|
69
|
-
htmlFor="message"
|
|
70
|
-
className="block text-sm font-medium text-teal-200 mb-2"
|
|
71
|
-
>
|
|
72
|
-
Message
|
|
73
|
-
</label>
|
|
74
|
-
<textarea
|
|
75
|
-
id="message"
|
|
76
|
-
name="message"
|
|
77
|
-
required
|
|
78
|
-
rows={3}
|
|
79
|
-
className="w-full px-4 py-3 rounded-lg bg-white/10 border border-white/20 text-white placeholder-teal-300/50 focus:outline-none focus:ring-2 focus:ring-teal-400 focus:border-transparent resize-none"
|
|
80
|
-
placeholder="Leave a message..."
|
|
81
|
-
/>
|
|
82
|
-
</div>
|
|
83
|
-
|
|
84
|
-
<button
|
|
85
|
-
type="submit"
|
|
86
|
-
disabled={isSubmitting}
|
|
87
|
-
className="w-full px-8 py-3 bg-teal-500 hover:bg-teal-600 disabled:bg-teal-500/50 text-white font-semibold rounded-lg transition-colors shadow-lg shadow-teal-500/30"
|
|
88
|
-
>
|
|
89
|
-
{isSubmitting ? "Signing..." : "Sign Guestbook"}
|
|
90
|
-
</button>
|
|
91
|
-
</form>
|
|
92
|
-
|
|
93
|
-
<div className="space-y-4">
|
|
94
|
-
<h2 className="text-xl font-bold text-white">
|
|
95
|
-
{entries.length === 0
|
|
96
|
-
? "No entries yet — be the first!"
|
|
97
|
-
: `${entries.length} ${entries.length === 1 ? "entry" : "entries"}`}
|
|
98
|
-
</h2>
|
|
99
|
-
|
|
100
|
-
{entries.map((entry) => (
|
|
101
|
-
<div
|
|
102
|
-
key={entry.id}
|
|
103
|
-
className="rounded-lg bg-white/10 border border-white/10 p-4"
|
|
104
|
-
>
|
|
105
|
-
<div className="flex items-baseline justify-between mb-1">
|
|
106
|
-
<span className="font-semibold text-white">{entry.name}</span>
|
|
107
|
-
<span className="text-xs text-teal-300/60">
|
|
108
|
-
{new Date(entry.createdAt).toLocaleDateString()}
|
|
109
|
-
</span>
|
|
110
|
-
</div>
|
|
111
|
-
<p className="text-teal-100/80 text-sm">{entry.message}</p>
|
|
112
|
-
</div>
|
|
113
|
-
))}
|
|
114
|
-
</div>
|
|
115
|
-
</div>
|
|
116
|
-
</div>
|
|
117
|
-
);
|
|
118
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { createServerFn } from "@tanstack/react-start";
|
|
2
|
-
import { db, schema } from "@/db";
|
|
3
|
-
import { desc } from "drizzle-orm";
|
|
4
|
-
|
|
5
|
-
export const getEntries = createServerFn({ method: "POST" }).handler(
|
|
6
|
-
async () => {
|
|
7
|
-
const entries = await db
|
|
8
|
-
.select()
|
|
9
|
-
.from(schema.guestbook)
|
|
10
|
-
.orderBy(desc(schema.guestbook.createdAt));
|
|
11
|
-
return entries;
|
|
12
|
-
}
|
|
13
|
-
);
|
|
14
|
-
|
|
15
|
-
export const addEntry = createServerFn({ method: "POST" })
|
|
16
|
-
.inputValidator((data: { name: string; message: string }) => data)
|
|
17
|
-
.handler(async ({ data }) => {
|
|
18
|
-
const result = await db
|
|
19
|
-
.insert(schema.guestbook)
|
|
20
|
-
.values({ name: data.name, message: data.message })
|
|
21
|
-
.returning();
|
|
22
|
-
return result[0];
|
|
23
|
-
});
|
package/add-ons/db/info.json
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "Netlify DB",
|
|
3
|
-
"phase": "add-on",
|
|
4
|
-
"description": "Add a guestbook demo powered by Netlify DB (Postgres) with Drizzle ORM. Demonstrates full CRUD with a serverless database.",
|
|
5
|
-
"link": "https://docs.netlify.com/database/overview/",
|
|
6
|
-
"modes": ["file-router"],
|
|
7
|
-
"type": "add-on",
|
|
8
|
-
"priority": 20,
|
|
9
|
-
"routes": [{"icon": "Database", "url": "/db-example", "name": "DB Example", "path": "src/routes/db-example.tsx", "jsName": "DBExample"}],
|
|
10
|
-
"features": ["netlify-db"],
|
|
11
|
-
"integrations": [],
|
|
12
|
-
"dependsOn": [],
|
|
13
|
-
"variables": [],
|
|
14
|
-
"packageFileDescriptions": {
|
|
15
|
-
"DB-SETUP.md": "Setup guide: link to Netlify, run netlify db init, configure DATABASE_URL.",
|
|
16
|
-
"src/routes/db-example.tsx": "Guestbook route (/db-example): form to add entries, list from getEntries/addEntry.",
|
|
17
|
-
"src/server/guestbook.functions.ts": "Server functions: getEntries (list), addEntry (create) for guestbook via Drizzle.",
|
|
18
|
-
"src/db/index.ts": "Drizzle + Neon client; exports db and schema.",
|
|
19
|
-
"src/db/schema.ts": "Guestbook table schema: id, name, message, createdAt.",
|
|
20
|
-
"drizzle.config.ts": "Drizzle Kit config for migrations; postgres, schema path, DATABASE_URL."
|
|
21
|
-
}
|
|
22
|
-
}
|
package/add-ons/db/package.json
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
### Netlify Forms Integration
|
|
2
|
-
|
|
3
|
-
Signup form powered by Netlify Forms with honeypot spam protection. No server-side code required.
|
|
4
|
-
|
|
5
|
-
**How it works:**
|
|
6
|
-
- Form submissions are handled by Netlify at build/deploy
|
|
7
|
-
- Add `data-netlify="true"` to the form
|
|
8
|
-
- Spam protection: `netlify-honeypot="bot-field"` + hidden input with `name="bot-field"`
|
|
9
|
-
- `public/form-example.html` declares the form (hidden) so Netlify detects it during build
|
|
10
|
-
|
|
11
|
-
**Route:** `/form-example` - Signup form (name, email)
|
|
12
|
-
|
|
13
|
-
No environment variables required. Works after deploy to Netlify.
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8" />
|
|
5
|
-
<title>Form</title>
|
|
6
|
-
</head>
|
|
7
|
-
<body>
|
|
8
|
-
<form name="signup" method="POST" data-netlify="true" netlify-honeypot="bot-field" hidden>
|
|
9
|
-
<input type="text" name="name" />
|
|
10
|
-
<input type="email" name="email" />
|
|
11
|
-
<input name="bot-field" />
|
|
12
|
-
</form>
|
|
13
|
-
</body>
|
|
14
|
-
</html>
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { createFileRoute } from '@tanstack/react-router'
|
|
2
|
-
|
|
3
|
-
export const Route = createFileRoute('/form-example')({
|
|
4
|
-
component: FormExample,
|
|
5
|
-
})
|
|
6
|
-
|
|
7
|
-
function FormExample() {
|
|
8
|
-
return (
|
|
9
|
-
<div className="min-h-screen bg-linear-to-br from-teal-900 via-emerald-800 to-cyan-900 flex items-center justify-center">
|
|
10
|
-
<div className="w-full max-w-md px-4">
|
|
11
|
-
<h1 className="text-4xl md:text-5xl font-black text-white mb-2 tracking-tight">
|
|
12
|
-
Sign up
|
|
13
|
-
</h1>
|
|
14
|
-
<p className="text-teal-100/80 mb-8">
|
|
15
|
-
Enter your name and email to get started.
|
|
16
|
-
</p>
|
|
17
|
-
|
|
18
|
-
<form
|
|
19
|
-
name="signup"
|
|
20
|
-
method="POST"
|
|
21
|
-
data-netlify="true"
|
|
22
|
-
netlify-honeypot="bot-field"
|
|
23
|
-
className="space-y-6"
|
|
24
|
-
>
|
|
25
|
-
<input type="hidden" name="form-name" value="signup" />
|
|
26
|
-
<p className="hidden" style={{ display: 'none' }}>
|
|
27
|
-
<label>
|
|
28
|
-
Don't fill this out: <input name="bot-field" />
|
|
29
|
-
</label>
|
|
30
|
-
</p>
|
|
31
|
-
|
|
32
|
-
<div>
|
|
33
|
-
<label
|
|
34
|
-
htmlFor="name"
|
|
35
|
-
className="block text-sm font-medium text-teal-200 mb-2"
|
|
36
|
-
>
|
|
37
|
-
Name
|
|
38
|
-
</label>
|
|
39
|
-
<input
|
|
40
|
-
type="text"
|
|
41
|
-
id="name"
|
|
42
|
-
name="name"
|
|
43
|
-
required
|
|
44
|
-
className="w-full px-4 py-3 rounded-lg bg-white/10 border border-white/20 text-white placeholder-teal-300/50 focus:outline-none focus:ring-2 focus:ring-teal-400 focus:border-transparent"
|
|
45
|
-
placeholder="Your name"
|
|
46
|
-
/>
|
|
47
|
-
</div>
|
|
48
|
-
|
|
49
|
-
<div>
|
|
50
|
-
<label
|
|
51
|
-
htmlFor="email"
|
|
52
|
-
className="block text-sm font-medium text-teal-200 mb-2"
|
|
53
|
-
>
|
|
54
|
-
Email
|
|
55
|
-
</label>
|
|
56
|
-
<input
|
|
57
|
-
type="email"
|
|
58
|
-
id="email"
|
|
59
|
-
name="email"
|
|
60
|
-
required
|
|
61
|
-
className="w-full px-4 py-3 rounded-lg bg-white/10 border border-white/20 text-white placeholder-teal-300/50 focus:outline-none focus:ring-2 focus:ring-teal-400 focus:border-transparent"
|
|
62
|
-
placeholder="you@example.com"
|
|
63
|
-
/>
|
|
64
|
-
</div>
|
|
65
|
-
|
|
66
|
-
<button
|
|
67
|
-
type="submit"
|
|
68
|
-
className="w-full px-8 py-3 bg-teal-500 hover:bg-teal-600 text-white font-semibold rounded-lg transition-colors shadow-lg shadow-teal-500/30"
|
|
69
|
-
>
|
|
70
|
-
Submit
|
|
71
|
-
</button>
|
|
72
|
-
</form>
|
|
73
|
-
</div>
|
|
74
|
-
</div>
|
|
75
|
-
)
|
|
76
|
-
}
|
package/add-ons/forms/info.json
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "Netlify Forms",
|
|
3
|
-
"phase": "add-on",
|
|
4
|
-
"description": "Add a signup form powered by Netlify Forms with spam protection via honeypot field. No server-side code required.",
|
|
5
|
-
"link": "https://docs.netlify.com/forms/setup/",
|
|
6
|
-
"modes": ["file-router"],
|
|
7
|
-
"type": "add-on",
|
|
8
|
-
"priority": 20,
|
|
9
|
-
"routes": [{"icon": "FormInput", "url": "/form-example", "name": "Form Example", "path": "src/routes/form-example.tsx", "jsName": "FormExample"}],
|
|
10
|
-
"features": ["netlify-forms"],
|
|
11
|
-
"integrations": [],
|
|
12
|
-
"dependsOn": [],
|
|
13
|
-
"variables": [],
|
|
14
|
-
"packageFileDescriptions": {
|
|
15
|
-
"src/routes/form-example.tsx": "Form example route (/form-example): Netlify Forms signup with honeypot spam protection.",
|
|
16
|
-
"public/form-example.html": "Static HTML form declaration for Netlify Forms; name, email, bot-field."
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# AI Chat Example
|
|
2
|
-
|
|
3
|
-
A weather chat assistant built with TanStack Start and TanStack AI for Netlify deployment.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- **AI Chat Interface**: Conversational weather assistant with streaming responses
|
|
8
|
-
- **Multi-Provider Support**: Works with Anthropic, OpenAI, Gemini, or Ollama
|
|
9
|
-
- **Tool Calling**: AI uses a getWeather tool to fetch weather data
|
|
10
|
-
- **Markdown Rendering**: Rich message formatting with syntax highlighting
|
|
11
|
-
|
|
12
|
-
## Project Structure
|
|
13
|
-
|
|
14
|
-
```
|
|
15
|
-
├── src/
|
|
16
|
-
│ ├── lib/
|
|
17
|
-
│ │ ├── ai-hook.ts # Chat hook setup
|
|
18
|
-
│ │ └── weather-tools.ts # Weather tool definition
|
|
19
|
-
│ └── routes/
|
|
20
|
-
│ ├── __root.tsx # Root layout
|
|
21
|
-
│ ├── index.tsx # Chat UI
|
|
22
|
-
│ └── api.chat.ts # Chat API endpoint
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## Development
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
npm run dev
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Set one of these environment variables to use a cloud provider:
|
|
32
|
-
- `ANTHROPIC_API_KEY`
|
|
33
|
-
- `OPENAI_API_KEY`
|
|
34
|
-
- `GEMINI_API_KEY`
|
|
35
|
-
|
|
36
|
-
Falls back to Ollama (local) if no API key is set.
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
### AI Integration
|
|
2
|
-
|
|
3
|
-
Multi-provider AI chat with fallback chain:
|
|
4
|
-
|
|
5
|
-
1. Anthropic Claude (preferred)
|
|
6
|
-
2. OpenAI GPT-4o
|
|
7
|
-
3. Google Gemini
|
|
8
|
-
4. Ollama (local)
|
|
9
|
-
|
|
10
|
-
**Tools available to AI:**
|
|
11
|
-
- `getWeather` - Get the current weather for a city. Returns temperature, condition, and humidity.
|
|
12
|
-
|
|
13
|
-
## Environment Variables
|
|
14
|
-
|
|
15
|
-
For AI functionality, set one or more:
|
|
16
|
-
|
|
17
|
-
```
|
|
18
|
-
ANTHROPIC_API_KEY=...
|
|
19
|
-
OPENAI_API_KEY=...
|
|
20
|
-
GOOGLE_GENERATIVE_AI_API_KEY=...
|
|
21
|
-
OLLAMA_BASE_URL=...
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
The application uses the first available provider in the fallback chain.
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
fetchServerSentEvents,
|
|
3
|
-
useChat,
|
|
4
|
-
createChatClientOptions,
|
|
5
|
-
} from '@tanstack/ai-react'
|
|
6
|
-
import type { InferChatMessages } from '@tanstack/ai-react'
|
|
7
|
-
|
|
8
|
-
// Default chat options for simple usage
|
|
9
|
-
const defaultChatOptions = createChatClientOptions({
|
|
10
|
-
connection: fetchServerSentEvents('/api/chat'),
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
export type ChatMessages = InferChatMessages<typeof defaultChatOptions>
|
|
14
|
-
|
|
15
|
-
export const useAIChat = () => {
|
|
16
|
-
const chatOptions = createChatClientOptions({
|
|
17
|
-
connection: fetchServerSentEvents('/api/chat'),
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
return useChat(chatOptions)
|
|
21
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { toolDefinition } from '@tanstack/ai'
|
|
2
|
-
import { z } from 'zod'
|
|
3
|
-
|
|
4
|
-
// Tool definition for getting weather
|
|
5
|
-
export const getWeatherToolDef = toolDefinition({
|
|
6
|
-
name: 'getWeather',
|
|
7
|
-
description:
|
|
8
|
-
'Get the current weather for a city. Returns temperature, condition, and humidity.',
|
|
9
|
-
inputSchema: z.object({
|
|
10
|
-
city: z.string().describe('The city to get weather for'),
|
|
11
|
-
}),
|
|
12
|
-
outputSchema: z.object({
|
|
13
|
-
city: z.string(),
|
|
14
|
-
temperature: z.number(),
|
|
15
|
-
condition: z.string(),
|
|
16
|
-
humidity: z.number(),
|
|
17
|
-
}),
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
// Server implementation - mock weather data
|
|
21
|
-
export const getWeather = getWeatherToolDef.server(({ city }) => {
|
|
22
|
-
// Mock weather data - in a real app, call a weather API
|
|
23
|
-
const conditions = ['sunny', 'cloudy', 'rainy', 'partly cloudy', 'windy']
|
|
24
|
-
return {
|
|
25
|
-
city,
|
|
26
|
-
temperature: Math.floor(Math.random() * 30) + 5,
|
|
27
|
-
condition: conditions[Math.floor(Math.random() * conditions.length)],
|
|
28
|
-
humidity: Math.floor(Math.random() * 50) + 30,
|
|
29
|
-
}
|
|
30
|
-
})
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router'
|
|
2
|
-
import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
|
|
3
|
-
import { TanStackDevtools } from '@tanstack/react-devtools'
|
|
4
|
-
|
|
5
|
-
import appCss from '../styles.css?url'
|
|
6
|
-
|
|
7
|
-
export const Route = createRootRoute({
|
|
8
|
-
head: () => ({
|
|
9
|
-
meta: [
|
|
10
|
-
{
|
|
11
|
-
charSet: 'utf-8',
|
|
12
|
-
},
|
|
13
|
-
{
|
|
14
|
-
name: 'viewport',
|
|
15
|
-
content: 'width=device-width, initial-scale=1',
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
title: 'Weather Chat',
|
|
19
|
-
},
|
|
20
|
-
],
|
|
21
|
-
links: [
|
|
22
|
-
{
|
|
23
|
-
rel: 'stylesheet',
|
|
24
|
-
href: appCss,
|
|
25
|
-
},
|
|
26
|
-
],
|
|
27
|
-
}),
|
|
28
|
-
shellComponent: RootDocument,
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
function RootDocument({ children }: { children: React.ReactNode }) {
|
|
32
|
-
return (
|
|
33
|
-
<html lang="en">
|
|
34
|
-
<head>
|
|
35
|
-
<HeadContent />
|
|
36
|
-
</head>
|
|
37
|
-
<body>
|
|
38
|
-
<header className="p-4 flex items-center justify-between bg-gray-800 text-white shadow-lg">
|
|
39
|
-
<h1 className="text-xl font-semibold">Weather Chat</h1>
|
|
40
|
-
</header>
|
|
41
|
-
{children}
|
|
42
|
-
<TanStackDevtools
|
|
43
|
-
config={{
|
|
44
|
-
position: 'bottom-right',
|
|
45
|
-
}}
|
|
46
|
-
plugins={[
|
|
47
|
-
{
|
|
48
|
-
name: 'Tanstack Router',
|
|
49
|
-
render: <TanStackRouterDevtoolsPanel />,
|
|
50
|
-
},
|
|
51
|
-
]}
|
|
52
|
-
/>
|
|
53
|
-
<Scripts />
|
|
54
|
-
</body>
|
|
55
|
-
</html>
|
|
56
|
-
)
|
|
57
|
-
}
|