ultra-dex 3.6.0 → 3.7.3
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/assets/hooks/pre-push +26 -0
- package/assets/live-templates/astro-sanity/.env.example +3 -0
- package/assets/live-templates/astro-sanity/README.md +14 -0
- package/assets/live-templates/astro-sanity/package.json +23 -0
- package/assets/live-templates/astro-sanity/src/pages/index.astro +14 -0
- package/assets/live-templates/ecommerce-next/package.json +32 -0
- package/assets/live-templates/ecommerce-next/src/app/products/page.tsx +117 -0
- package/assets/live-templates/ecommerce-next/src/lib/store.ts +63 -0
- package/assets/live-templates/fastapi-api/README.md +36 -0
- package/assets/live-templates/fastapi-api/main.py +147 -0
- package/assets/live-templates/fastapi-api/package.json +15 -0
- package/assets/live-templates/fastapi-api/requirements.txt +15 -0
- package/assets/live-templates/next15-saas/.env.example +28 -0
- package/assets/live-templates/next15-saas/README.md +46 -0
- package/assets/live-templates/next15-saas/middleware.ts +9 -0
- package/assets/live-templates/next15-saas/next.config.js +11 -0
- package/assets/live-templates/next15-saas/package.json +46 -0
- package/assets/live-templates/next15-saas/postcss.config.js +6 -0
- package/assets/live-templates/next15-saas/prisma/schema.prisma +112 -0
- package/assets/live-templates/next15-saas/src/app/admin/page.tsx +89 -0
- package/assets/live-templates/next15-saas/src/app/api/stripe/checkout/route.ts +37 -0
- package/assets/live-templates/next15-saas/src/app/api/webhooks/stripe/route.ts +103 -0
- package/assets/live-templates/next15-saas/src/app/dashboard/page.tsx +78 -0
- package/assets/live-templates/next15-saas/src/app/globals.css +3 -0
- package/assets/live-templates/next15-saas/src/app/layout.tsx +25 -0
- package/assets/live-templates/next15-saas/src/app/page.tsx +57 -0
- package/assets/live-templates/next15-saas/src/components/ui/button.tsx +48 -0
- package/assets/live-templates/next15-saas/src/components/ui/card.tsx +44 -0
- package/assets/live-templates/next15-saas/src/lib/db.ts +9 -0
- package/assets/live-templates/next15-saas/src/lib/email/resend.ts +28 -0
- package/assets/live-templates/next15-saas/src/lib/stripe/client.ts +3 -0
- package/assets/live-templates/next15-saas/src/lib/stripe/server.ts +50 -0
- package/assets/live-templates/next15-saas/src/lib/upload/s3.ts +39 -0
- package/assets/live-templates/next15-saas/src/lib/utils.ts +6 -0
- package/assets/live-templates/next15-saas/tailwind.config.js +19 -0
- package/assets/live-templates/next15-saas/tsconfig.json +39 -0
- package/assets/live-templates/next15-saas/types/index.ts +65 -0
- package/assets/live-templates/nuxt3-supabase/.env.example +2 -0
- package/assets/live-templates/nuxt3-supabase/README.md +14 -0
- package/assets/live-templates/nuxt3-supabase/app.vue +5 -0
- package/assets/live-templates/nuxt3-supabase/package.json +22 -0
- package/assets/live-templates/remix-saas/README.md +38 -0
- package/assets/live-templates/remix-saas/app/lib/db.server.ts +18 -0
- package/assets/live-templates/remix-saas/app/lib/payments/stripe.server.ts +45 -0
- package/assets/live-templates/remix-saas/app/root.tsx +38 -0
- package/assets/live-templates/remix-saas/app/routes/_index.tsx +70 -0
- package/assets/live-templates/remix-saas/app/routes/api.webhooks.stripe.tsx +71 -0
- package/assets/live-templates/remix-saas/app/routes/dashboard.tsx +84 -0
- package/assets/live-templates/remix-saas/app/tailwind.css +16 -0
- package/assets/live-templates/remix-saas/package.json +43 -0
- package/assets/live-templates/remix-saas/prisma/schema.prisma +94 -0
- package/assets/live-templates/solid-drizzle/.env.example +1 -0
- package/assets/live-templates/solid-drizzle/README.md +15 -0
- package/assets/live-templates/solid-drizzle/drizzle.config.ts +10 -0
- package/assets/live-templates/solid-drizzle/package.json +27 -0
- package/assets/live-templates/solid-drizzle/src/routes/index.tsx +10 -0
- package/assets/live-templates/sveltekit-saas/README.md +36 -0
- package/assets/live-templates/sveltekit-saas/package.json +36 -0
- package/assets/live-templates/sveltekit-saas/prisma/schema.prisma +68 -0
- package/assets/live-templates/sveltekit-saas/src/app.css +15 -0
- package/assets/live-templates/sveltekit-saas/src/lib/server/db.ts +9 -0
- package/assets/live-templates/sveltekit-saas/src/lib/server/stripe.ts +17 -0
- package/assets/live-templates/sveltekit-saas/src/routes/+layout.svelte +36 -0
- package/assets/live-templates/sveltekit-saas/src/routes/+page.svelte +38 -0
- package/assets/live-templates/sveltekit-saas/src/routes/dashboard/+page.server.ts +27 -0
- package/assets/live-templates/sveltekit-saas/src/routes/dashboard/+page.svelte +51 -0
- package/assets/live-templates/tauri-desktop/README.md +13 -0
- package/assets/live-templates/tauri-desktop/package.json +18 -0
- package/assets/live-templates/tauri-desktop/src-tauri/tauri.conf.json +39 -0
- package/bin/ultra-dex.js +91 -13
- package/lib/agents/vision.js +280 -0
- package/lib/analytics/index.js +165 -0
- package/lib/analytics/storage.js +45 -0
- package/lib/api/auth.js +122 -0
- package/lib/api/gateway.js +97 -0
- package/lib/api/websocket.js +28 -0
- package/lib/auth/api-keys.js +277 -0
- package/lib/auth/audit.js +321 -0
- package/lib/auth/rbac.js +89 -0
- package/lib/auth/sso.js +277 -0
- package/lib/auth/token-storage.js +247 -0
- package/lib/auto-context/index.js +222 -0
- package/lib/autonomous-mode/index.js +71 -0
- package/lib/cache/index.js +280 -0
- package/lib/commands/agents.js +392 -202
- package/lib/commands/api.js +37 -0
- package/lib/commands/audit.js +22 -1
- package/lib/commands/auth.js +338 -37
- package/lib/commands/brain.js +52 -2
- package/lib/commands/browser-auto.js +499 -0
- package/lib/commands/browser.js +1 -376
- package/lib/commands/check.js +379 -0
- package/lib/commands/config.js +24 -12
- package/lib/commands/dashboard.js +34 -4
- package/lib/commands/diff.js +478 -298
- package/lib/commands/doctor.js +10 -2
- package/lib/commands/exec.js +116 -192
- package/lib/commands/export.js +313 -112
- package/lib/commands/fix.js +69 -51
- package/lib/commands/generate.js +69 -17
- package/lib/commands/hooks.js +113 -1
- package/lib/commands/init.js +93 -921
- package/lib/commands/memory.js +33 -2
- package/lib/commands/plugin.js +195 -73
- package/lib/commands/rag.js +213 -0
- package/lib/commands/review.js +177 -165
- package/lib/commands/run.js +51 -0
- package/lib/commands/scaffold-plan-new.js +433 -0
- package/lib/commands/scaffold-plan.js +436 -0
- package/lib/commands/scaffold.js +120 -6
- package/lib/commands/search.js +6 -20
- package/lib/commands/serve.js +24 -7
- package/lib/commands/setup.js +206 -193
- package/lib/commands/state.js +15 -3
- package/lib/commands/suggest.js +10 -2
- package/lib/commands/swarm-advanced.js +206 -0
- package/lib/commands/swarm.js +72 -22
- package/lib/commands/sync.js +181 -31
- package/lib/commands/team.js +218 -2
- package/lib/commands/undo.js +123 -0
- package/lib/commands/validate.js +37 -37
- package/lib/commands/vector-search.js +4 -15
- package/lib/commands/verify.js +76 -2
- package/lib/commands/watch.js +82 -39
- package/lib/enterprise/agent-access.js +129 -0
- package/lib/enterprise/usage.js +139 -0
- package/lib/governance/audit.js +54 -0
- package/lib/governance/index.js +251 -183
- package/lib/graph/semantic-graph.js +292 -0
- package/lib/history/tracker.js +371 -0
- package/lib/history/undo.js +240 -0
- package/lib/integrations/discord.js +32 -0
- package/lib/integrations/github-projects.js +32 -0
- package/lib/integrations/index.js +25 -0
- package/lib/integrations/jira.js +37 -0
- package/lib/integrations/linear.js +32 -0
- package/lib/integrations/notion.js +32 -0
- package/lib/integrations/segment.js +32 -0
- package/lib/integrations/slack.js +32 -0
- package/lib/integrations/stripe.js +32 -0
- package/lib/integrations/supabase.js +32 -0
- package/lib/integrations/utils.js +29 -0
- package/lib/integrations/vercel.js +32 -0
- package/lib/kernel/agent.js +49 -0
- package/lib/kernel/editor.js +23 -0
- package/lib/marketplace/index.js +157 -0
- package/lib/marketplace/registry.js +100 -0
- package/lib/mcp/host.js +179 -0
- package/lib/mcp/index.js +11 -0
- package/lib/mcp/memory.js +10 -0
- package/lib/mcp/resources.js +28 -2
- package/lib/mcp/server.js +13 -4
- package/lib/mcp/tools.js +32 -1
- package/lib/mcp/websocket.js +6 -4
- package/lib/mcp/wizard.js +314 -0
- package/lib/memory/memex.js +65 -0
- package/lib/migration/index.js +63 -0
- package/lib/multi-repo/index.js +52 -0
- package/lib/nl-pipeline/index.js +92 -0
- package/lib/nlp/router.js +227 -36
- package/lib/orchestration/index.js +151 -0
- package/lib/pair-programming/index.js +78 -0
- package/lib/plugins/ai-tools.js +272 -0
- package/lib/plugins/guide.js +115 -0
- package/lib/plugins/index.js +482 -0
- package/lib/plugins/integration.js +129 -0
- package/lib/predictive-architecture/index.js +73 -0
- package/lib/providers/index.js +82 -1
- package/lib/providers/streaming.js +83 -0
- package/lib/providers/vercel-ai.js +204 -0
- package/lib/quality/checklist.js +175 -0
- package/lib/quality/gates.js +111 -0
- package/lib/quality/hooks.js +42 -0
- package/lib/quality/index.js +3 -0
- package/lib/rag/embeddings.js +160 -0
- package/lib/rag/graph.js +513 -0
- package/lib/rag/neo4j.js +163 -0
- package/lib/repl/commands.js +429 -0
- package/lib/repl/index.js +149 -194
- package/lib/repl/session.js +272 -0
- package/lib/router/model-router.js +119 -0
- package/lib/sandbox/Dockerfile +16 -0
- package/lib/sandbox/docker.js +165 -0
- package/lib/sandbox/permissions.js +42 -0
- package/lib/security/audit-layer.js +185 -0
- package/lib/self-improve/index.js +100 -0
- package/lib/server/middleware/auth.js +211 -0
- package/lib/server/middleware/rate-limit.js +222 -0
- package/lib/server/websocket.js +56 -0
- package/lib/swarm/orchestrator.js +541 -0
- package/lib/team/collaboration.js +275 -0
- package/lib/templates/ultra.js +36 -0
- package/lib/time-travel/index.js +56 -0
- package/lib/training/index.js +166 -0
- package/lib/ui/adaptive.js +224 -0
- package/lib/utils/config-manager.js +8 -1
- package/lib/utils/error-handler.js +12 -0
- package/lib/utils/performance.js +17 -18
- package/lib/utils/progress.js +147 -5
- package/lib/utils/stream.js +370 -0
- package/lib/utils/token-forecast.js +201 -0
- package/lib/visual/index.js +36 -0
- package/lib/voice/command.js +61 -0
- package/lib/voice/index.js +6 -0
- package/lib/voice/whisper.js +245 -0
- package/package.json +12 -4
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Ultra-Dex Pre-Push Hook v1.0
|
|
3
|
+
# Auto-updates CONTEXT.md from git diff + runs live verification
|
|
4
|
+
# Install with: npx ultra-dex hooks install
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
echo ""
|
|
9
|
+
echo "🚀 Ultra-Dex: Running pre-push verification..."
|
|
10
|
+
echo ""
|
|
11
|
+
|
|
12
|
+
# Check if ultra-dex is available
|
|
13
|
+
if ! command -v ultra-dex >/dev/null 2>&1 && ! npx ultra-dex --version >/dev/null 2>&1; then
|
|
14
|
+
echo "⚠️ Ultra-Dex not found. Skipping pre-push verification."
|
|
15
|
+
echo " Install with: npm install -g ultra-dex"
|
|
16
|
+
exit 0
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
# Update CONTEXT.md based on diff + run live verification
|
|
20
|
+
npx ultra-dex verify --live --pre-push
|
|
21
|
+
|
|
22
|
+
echo ""
|
|
23
|
+
echo "✅ Ultra-Dex pre-push checks passed"
|
|
24
|
+
echo ""
|
|
25
|
+
|
|
26
|
+
exit 0
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Astro + Sanity CMS Template
|
|
2
|
+
|
|
3
|
+
Starter template for building high-performance websites with Astro and Sanity CMS.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
- Astro 4.x
|
|
7
|
+
- Sanity Client integration
|
|
8
|
+
- TypeScript support
|
|
9
|
+
- SEO optimized
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
1. `npm install`
|
|
13
|
+
2. Update `.env` with your Sanity credentials
|
|
14
|
+
3. `npm run dev`
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ultra-dex-astro-sanity",
|
|
3
|
+
"description": "Astro and Sanity CMS starter template",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"private": true,
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "astro dev",
|
|
8
|
+
"start": "astro dev",
|
|
9
|
+
"build": "astro build",
|
|
10
|
+
"preview": "astro preview",
|
|
11
|
+
"astro": "astro"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"astro": "^4.10.0",
|
|
15
|
+
"@sanity/client": "^6.21.0",
|
|
16
|
+
"@sanity/astro": "^3.1.0",
|
|
17
|
+
"react": "^18.3.0",
|
|
18
|
+
"react-dom": "^18.3.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"typescript": "^5.4.0"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
---
|
|
3
|
+
<html lang="en">
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
7
|
+
<meta name="viewport" content="width=device-width" />
|
|
8
|
+
<meta name="generator" content={Astro.generator} />
|
|
9
|
+
<title>Astro + Sanity</title>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<h1>Astro + Sanity</h1>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ecommerce-next",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "next dev",
|
|
7
|
+
"build": "next build",
|
|
8
|
+
"start": "next start",
|
|
9
|
+
"lint": "next lint"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"next": "^15.0.0",
|
|
13
|
+
"react": "^19.0.0",
|
|
14
|
+
"react-dom": "^19.0.0",
|
|
15
|
+
"@clerk/nextjs": "^5.0.0",
|
|
16
|
+
"@prisma/client": "^6.0.0",
|
|
17
|
+
"stripe": "^14.0.0",
|
|
18
|
+
"@stripe/stripe-js": "^2.0.0",
|
|
19
|
+
"zustand": "^4.5.0",
|
|
20
|
+
"tailwindcss": "^3.4.0",
|
|
21
|
+
"clsx": "^2.1.0",
|
|
22
|
+
"lucide-react": "^0.300.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^20.0.0",
|
|
26
|
+
"@types/react": "^18.0.0",
|
|
27
|
+
"typescript": "^5.0.0",
|
|
28
|
+
"prisma": "^6.0.0",
|
|
29
|
+
"postcss": "^8.0.0",
|
|
30
|
+
"autoprefixer": "^10.0.0"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { ShoppingCart, Star, Filter } from 'lucide-react';
|
|
5
|
+
import { useCart } from '../lib/store';
|
|
6
|
+
|
|
7
|
+
interface Product {
|
|
8
|
+
id: string;
|
|
9
|
+
name: string;
|
|
10
|
+
price: number;
|
|
11
|
+
image: string;
|
|
12
|
+
rating: number;
|
|
13
|
+
category: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const PRODUCTS: Product[] = [
|
|
17
|
+
{ id: '1', name: 'Premium Headphones', price: 299, image: '/headphones.jpg', rating: 4.8, category: 'Electronics' },
|
|
18
|
+
{ id: '2', name: 'Wireless Keyboard', price: 149, image: '/keyboard.jpg', rating: 4.5, category: 'Electronics' },
|
|
19
|
+
{ id: '3', name: 'Smart Watch Pro', price: 399, image: '/watch.jpg', rating: 4.9, category: 'Wearables' },
|
|
20
|
+
{ id: '4', name: 'Minimalist Backpack', price: 89, image: '/backpack.jpg', rating: 4.6, category: 'Accessories' },
|
|
21
|
+
{ id: '5', name: 'Bluetooth Speaker', price: 79, image: '/speaker.jpg', rating: 4.4, category: 'Electronics' },
|
|
22
|
+
{ id: '6', name: 'USB-C Hub', price: 49, image: '/hub.jpg', rating: 4.3, category: 'Accessories' },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
export default function ProductsPage() {
|
|
26
|
+
const [selectedCategory, setSelectedCategory] = useState<string | null>(null);
|
|
27
|
+
const { addItem, items } = useCart();
|
|
28
|
+
|
|
29
|
+
const categories = [...new Set(PRODUCTS.map(p => p.category))];
|
|
30
|
+
const filteredProducts = selectedCategory
|
|
31
|
+
? PRODUCTS.filter(p => p.category === selectedCategory)
|
|
32
|
+
: PRODUCTS;
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
|
|
36
|
+
{/* Header */}
|
|
37
|
+
<header className="bg-white dark:bg-gray-800 shadow-sm sticky top-0 z-10">
|
|
38
|
+
<div className="max-w-7xl mx-auto px-4 py-4 flex justify-between items-center">
|
|
39
|
+
<h1 className="text-2xl font-bold bg-gradient-to-r from-purple-600 to-pink-600 bg-clip-text text-transparent">
|
|
40
|
+
ShopNext
|
|
41
|
+
</h1>
|
|
42
|
+
<button className="relative p-2 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700">
|
|
43
|
+
<ShoppingCart className="w-6 h-6" />
|
|
44
|
+
{items.length > 0 && (
|
|
45
|
+
<span className="absolute -top-1 -right-1 bg-purple-600 text-white text-xs w-5 h-5 rounded-full flex items-center justify-center">
|
|
46
|
+
{items.length}
|
|
47
|
+
</span>
|
|
48
|
+
)}
|
|
49
|
+
</button>
|
|
50
|
+
</div>
|
|
51
|
+
</header>
|
|
52
|
+
|
|
53
|
+
<main className="max-w-7xl mx-auto px-4 py-8">
|
|
54
|
+
{/* Filter */}
|
|
55
|
+
<div className="flex items-center gap-4 mb-8">
|
|
56
|
+
<Filter className="w-5 h-5 text-gray-500" />
|
|
57
|
+
<div className="flex gap-2">
|
|
58
|
+
<button
|
|
59
|
+
onClick={() => setSelectedCategory(null)}
|
|
60
|
+
className={`px-4 py-2 rounded-full text-sm transition-colors ${!selectedCategory
|
|
61
|
+
? 'bg-purple-600 text-white'
|
|
62
|
+
: 'bg-gray-200 dark:bg-gray-700 hover:bg-gray-300'
|
|
63
|
+
}`}
|
|
64
|
+
>
|
|
65
|
+
All
|
|
66
|
+
</button>
|
|
67
|
+
{categories.map(cat => (
|
|
68
|
+
<button
|
|
69
|
+
key={cat}
|
|
70
|
+
onClick={() => setSelectedCategory(cat)}
|
|
71
|
+
className={`px-4 py-2 rounded-full text-sm transition-colors ${selectedCategory === cat
|
|
72
|
+
? 'bg-purple-600 text-white'
|
|
73
|
+
: 'bg-gray-200 dark:bg-gray-700 hover:bg-gray-300'
|
|
74
|
+
}`}
|
|
75
|
+
>
|
|
76
|
+
{cat}
|
|
77
|
+
</button>
|
|
78
|
+
))}
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
{/* Products Grid */}
|
|
83
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
84
|
+
{filteredProducts.map(product => (
|
|
85
|
+
<div
|
|
86
|
+
key={product.id}
|
|
87
|
+
className="bg-white dark:bg-gray-800 rounded-2xl shadow-lg overflow-hidden hover:shadow-xl transition-shadow group"
|
|
88
|
+
>
|
|
89
|
+
<div className="aspect-square bg-gray-100 dark:bg-gray-700 relative">
|
|
90
|
+
<div className="absolute inset-0 flex items-center justify-center text-gray-400">
|
|
91
|
+
{product.name}
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
<div className="p-6">
|
|
95
|
+
<div className="flex items-center gap-1 mb-2">
|
|
96
|
+
<Star className="w-4 h-4 fill-yellow-400 text-yellow-400" />
|
|
97
|
+
<span className="text-sm text-gray-600 dark:text-gray-300">{product.rating}</span>
|
|
98
|
+
</div>
|
|
99
|
+
<h3 className="font-semibold text-lg mb-1">{product.name}</h3>
|
|
100
|
+
<p className="text-gray-500 text-sm mb-4">{product.category}</p>
|
|
101
|
+
<div className="flex items-center justify-between">
|
|
102
|
+
<span className="text-2xl font-bold">${product.price}</span>
|
|
103
|
+
<button
|
|
104
|
+
onClick={() => addItem(product)}
|
|
105
|
+
className="px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition-colors"
|
|
106
|
+
>
|
|
107
|
+
Add to Cart
|
|
108
|
+
</button>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
))}
|
|
113
|
+
</div>
|
|
114
|
+
</main>
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
import { persist } from 'zustand/middleware';
|
|
3
|
+
|
|
4
|
+
interface CartItem {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
price: number;
|
|
8
|
+
quantity: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface CartStore {
|
|
12
|
+
items: CartItem[];
|
|
13
|
+
addItem: (product: { id: string; name: string; price: number }) => void;
|
|
14
|
+
removeItem: (id: string) => void;
|
|
15
|
+
updateQuantity: (id: string, quantity: number) => void;
|
|
16
|
+
clearCart: () => void;
|
|
17
|
+
total: () => number;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const useCart = create<CartStore>()(
|
|
21
|
+
persist(
|
|
22
|
+
(set, get) => ({
|
|
23
|
+
items: [],
|
|
24
|
+
|
|
25
|
+
addItem: (product) => {
|
|
26
|
+
set((state) => {
|
|
27
|
+
const existing = state.items.find(i => i.id === product.id);
|
|
28
|
+
if (existing) {
|
|
29
|
+
return {
|
|
30
|
+
items: state.items.map(i =>
|
|
31
|
+
i.id === product.id ? { ...i, quantity: i.quantity + 1 } : i
|
|
32
|
+
)
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
items: [...state.items, { ...product, quantity: 1 }]
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
removeItem: (id) => {
|
|
42
|
+
set((state) => ({
|
|
43
|
+
items: state.items.filter(i => i.id !== id)
|
|
44
|
+
}));
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
updateQuantity: (id, quantity) => {
|
|
48
|
+
set((state) => ({
|
|
49
|
+
items: state.items.map(i =>
|
|
50
|
+
i.id === id ? { ...i, quantity: Math.max(0, quantity) } : i
|
|
51
|
+
).filter(i => i.quantity > 0)
|
|
52
|
+
}));
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
clearCart: () => set({ items: [] }),
|
|
56
|
+
|
|
57
|
+
total: () => {
|
|
58
|
+
return get().items.reduce((sum, item) => sum + item.price * item.quantity, 0);
|
|
59
|
+
}
|
|
60
|
+
}),
|
|
61
|
+
{ name: 'cart-storage' }
|
|
62
|
+
)
|
|
63
|
+
);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# FastAPI SaaS API
|
|
2
|
+
|
|
3
|
+
Production-ready API template with:
|
|
4
|
+
- **Auth**: JWT tokens with HTTPBearer
|
|
5
|
+
- **Database**: SQLAlchemy + PostgreSQL
|
|
6
|
+
- **Payments**: Stripe integration
|
|
7
|
+
- **API Keys**: Self-service key management
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
python -m venv venv
|
|
13
|
+
source venv/bin/activate
|
|
14
|
+
pip install -r requirements.txt
|
|
15
|
+
uvicorn main:app --reload
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Environment Variables
|
|
19
|
+
|
|
20
|
+
```env
|
|
21
|
+
DATABASE_URL=postgresql://user:pass@localhost/db
|
|
22
|
+
STRIPE_SECRET_KEY=sk_...
|
|
23
|
+
JWT_SECRET=your-secret
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## API Endpoints
|
|
27
|
+
|
|
28
|
+
- `POST /auth/register` - Register user
|
|
29
|
+
- `GET /auth/me` - Get current user
|
|
30
|
+
- `GET /subscriptions` - List subscriptions
|
|
31
|
+
- `POST /subscriptions/checkout` - Create checkout
|
|
32
|
+
- `GET /api-keys` - List API keys
|
|
33
|
+
- `POST /api-keys` - Create API key
|
|
34
|
+
- `POST /webhooks/stripe` - Stripe webhook
|
|
35
|
+
|
|
36
|
+
Generated with [Ultra-Dex CLI](https://github.com/Srujan0798/Ultra-Dex)
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FastAPI SaaS API Template
|
|
3
|
+
Production-ready API with auth, database, and payments
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from fastapi import FastAPI, Depends, HTTPException, status
|
|
7
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
8
|
+
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
from typing import Optional, List
|
|
11
|
+
import os
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
|
|
14
|
+
app = FastAPI(
|
|
15
|
+
title="FastAPI SaaS API",
|
|
16
|
+
description="Production-ready API template",
|
|
17
|
+
version="1.0.0"
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
# CORS
|
|
21
|
+
app.add_middleware(
|
|
22
|
+
CORSMiddleware,
|
|
23
|
+
allow_origins=["*"],
|
|
24
|
+
allow_credentials=True,
|
|
25
|
+
allow_methods=["*"],
|
|
26
|
+
allow_headers=["*"],
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# Security
|
|
30
|
+
security = HTTPBearer()
|
|
31
|
+
|
|
32
|
+
# Models
|
|
33
|
+
class User(BaseModel):
|
|
34
|
+
id: str
|
|
35
|
+
email: str
|
|
36
|
+
name: Optional[str] = None
|
|
37
|
+
role: str = "user"
|
|
38
|
+
created_at: datetime = datetime.now()
|
|
39
|
+
|
|
40
|
+
class UserCreate(BaseModel):
|
|
41
|
+
email: str
|
|
42
|
+
password: str
|
|
43
|
+
name: Optional[str] = None
|
|
44
|
+
|
|
45
|
+
class Subscription(BaseModel):
|
|
46
|
+
id: str
|
|
47
|
+
user_id: str
|
|
48
|
+
plan: str
|
|
49
|
+
status: str
|
|
50
|
+
stripe_customer_id: Optional[str] = None
|
|
51
|
+
current_period_end: Optional[datetime] = None
|
|
52
|
+
|
|
53
|
+
class APIKey(BaseModel):
|
|
54
|
+
id: str
|
|
55
|
+
user_id: str
|
|
56
|
+
key: str
|
|
57
|
+
name: str
|
|
58
|
+
created_at: datetime
|
|
59
|
+
|
|
60
|
+
# In-memory store (replace with database)
|
|
61
|
+
users_db = {}
|
|
62
|
+
subscriptions_db = {}
|
|
63
|
+
api_keys_db = {}
|
|
64
|
+
|
|
65
|
+
# Auth dependency
|
|
66
|
+
async def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
|
|
67
|
+
token = credentials.credentials
|
|
68
|
+
# Verify JWT token (simplified)
|
|
69
|
+
if token.startswith("user_"):
|
|
70
|
+
user_id = token.replace("user_", "")
|
|
71
|
+
if user_id in users_db:
|
|
72
|
+
return users_db[user_id]
|
|
73
|
+
raise HTTPException(status_code=401, detail="Invalid token")
|
|
74
|
+
|
|
75
|
+
# Routes
|
|
76
|
+
@app.get("/")
|
|
77
|
+
async def root():
|
|
78
|
+
return {"message": "FastAPI SaaS API", "version": "1.0.0"}
|
|
79
|
+
|
|
80
|
+
@app.get("/health")
|
|
81
|
+
async def health():
|
|
82
|
+
return {"status": "healthy", "timestamp": datetime.now().isoformat()}
|
|
83
|
+
|
|
84
|
+
# Auth routes
|
|
85
|
+
@app.post("/auth/register", response_model=User)
|
|
86
|
+
async def register(user: UserCreate):
|
|
87
|
+
user_id = f"user_{len(users_db) + 1}"
|
|
88
|
+
new_user = User(id=user_id, email=user.email, name=user.name)
|
|
89
|
+
users_db[user_id] = new_user
|
|
90
|
+
return new_user
|
|
91
|
+
|
|
92
|
+
@app.get("/auth/me", response_model=User)
|
|
93
|
+
async def get_me(user: User = Depends(get_current_user)):
|
|
94
|
+
return user
|
|
95
|
+
|
|
96
|
+
# Subscription routes
|
|
97
|
+
@app.get("/subscriptions", response_model=List[Subscription])
|
|
98
|
+
async def list_subscriptions(user: User = Depends(get_current_user)):
|
|
99
|
+
return [s for s in subscriptions_db.values() if s.user_id == user.id]
|
|
100
|
+
|
|
101
|
+
@app.post("/subscriptions/checkout")
|
|
102
|
+
async def create_checkout(plan: str, user: User = Depends(get_current_user)):
|
|
103
|
+
# Integrate with Stripe
|
|
104
|
+
return {
|
|
105
|
+
"checkout_url": f"https://checkout.stripe.com/pay/{plan}",
|
|
106
|
+
"plan": plan
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
# API Key routes
|
|
110
|
+
@app.get("/api-keys", response_model=List[APIKey])
|
|
111
|
+
async def list_api_keys(user: User = Depends(get_current_user)):
|
|
112
|
+
return [k for k in api_keys_db.values() if k.user_id == user.id]
|
|
113
|
+
|
|
114
|
+
@app.post("/api-keys", response_model=APIKey)
|
|
115
|
+
async def create_api_key(name: str, user: User = Depends(get_current_user)):
|
|
116
|
+
import secrets
|
|
117
|
+
key_id = f"key_{len(api_keys_db) + 1}"
|
|
118
|
+
api_key = APIKey(
|
|
119
|
+
id=key_id,
|
|
120
|
+
user_id=user.id,
|
|
121
|
+
key=f"sk_{secrets.token_hex(16)}",
|
|
122
|
+
name=name,
|
|
123
|
+
created_at=datetime.now()
|
|
124
|
+
)
|
|
125
|
+
api_keys_db[key_id] = api_key
|
|
126
|
+
return api_key
|
|
127
|
+
|
|
128
|
+
# Webhook handler
|
|
129
|
+
@app.post("/webhooks/stripe")
|
|
130
|
+
async def stripe_webhook(payload: dict):
|
|
131
|
+
event_type = payload.get("type")
|
|
132
|
+
|
|
133
|
+
if event_type == "checkout.session.completed":
|
|
134
|
+
# Handle successful checkout
|
|
135
|
+
pass
|
|
136
|
+
elif event_type == "customer.subscription.updated":
|
|
137
|
+
# Handle subscription update
|
|
138
|
+
pass
|
|
139
|
+
elif event_type == "customer.subscription.deleted":
|
|
140
|
+
# Handle cancellation
|
|
141
|
+
pass
|
|
142
|
+
|
|
143
|
+
return {"received": True}
|
|
144
|
+
|
|
145
|
+
if __name__ == "__main__":
|
|
146
|
+
import uvicorn
|
|
147
|
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fastapi-api",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "uvicorn main:app --reload --port 8000",
|
|
7
|
+
"start": "uvicorn main:app --host 0.0.0.0 --port 8000",
|
|
8
|
+
"test": "pytest",
|
|
9
|
+
"lint": "ruff check .",
|
|
10
|
+
"format": "black ."
|
|
11
|
+
},
|
|
12
|
+
"engines": {
|
|
13
|
+
"python": ">=3.11"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
fastapi>=0.109.0
|
|
2
|
+
uvicorn[standard]>=0.27.0
|
|
3
|
+
pydantic>=2.5.0
|
|
4
|
+
python-jose[cryptography]>=3.3.0
|
|
5
|
+
passlib[bcrypt]>=1.7.4
|
|
6
|
+
python-multipart>=0.0.6
|
|
7
|
+
sqlalchemy>=2.0.0
|
|
8
|
+
alembic>=1.13.0
|
|
9
|
+
asyncpg>=0.29.0
|
|
10
|
+
redis>=5.0.0
|
|
11
|
+
stripe>=7.0.0
|
|
12
|
+
pytest>=8.0.0
|
|
13
|
+
httpx>=0.26.0
|
|
14
|
+
ruff>=0.1.0
|
|
15
|
+
black>=24.0.0
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Next.js
|
|
2
|
+
NEXT_PUBLIC_APP_URL=http://localhost:3000
|
|
3
|
+
|
|
4
|
+
# Clerk Auth
|
|
5
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_
|
|
6
|
+
CLERK_SECRET_KEY=sk_test_
|
|
7
|
+
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
|
|
8
|
+
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
|
|
9
|
+
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/dashboard
|
|
10
|
+
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/dashboard
|
|
11
|
+
|
|
12
|
+
# Database
|
|
13
|
+
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"
|
|
14
|
+
|
|
15
|
+
# Stripe
|
|
16
|
+
STRIPE_SECRET_KEY=sk_test_
|
|
17
|
+
STRIPE_WEBHOOK_SECRET=whsec_
|
|
18
|
+
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_
|
|
19
|
+
|
|
20
|
+
# Email (Resend)
|
|
21
|
+
RESEND_API_KEY=re_
|
|
22
|
+
EMAIL_FROM=onboarding@yourdomain.com
|
|
23
|
+
|
|
24
|
+
# AWS S3 (File Upload)
|
|
25
|
+
AWS_ACCESS_KEY_ID=AKIA...
|
|
26
|
+
AWS_SECRET_ACCESS_KEY=...
|
|
27
|
+
AWS_REGION=us-east-1
|
|
28
|
+
AWS_S3_BUCKET_NAME=your-bucket-name
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Next.js SaaS Starter
|
|
2
|
+
|
|
3
|
+
Production-ready SaaS template with:
|
|
4
|
+
- **Authentication**: Clerk
|
|
5
|
+
- **Payments**: Stripe (checkout, webhooks, subscriptions)
|
|
6
|
+
- **Database**: Prisma + PostgreSQL
|
|
7
|
+
- **Email**: Resend
|
|
8
|
+
- **File Upload**: AWS S3
|
|
9
|
+
- **Styling**: Tailwind CSS
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install
|
|
15
|
+
cp .env.example .env.local
|
|
16
|
+
# Add your API keys to .env.local
|
|
17
|
+
npx prisma migrate dev
|
|
18
|
+
npm run dev
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Environment Variables
|
|
22
|
+
|
|
23
|
+
See `.env.example` for all required variables.
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- ✅ User authentication with Clerk
|
|
28
|
+
- ✅ Subscription management with Stripe
|
|
29
|
+
- ✅ Admin dashboard with analytics
|
|
30
|
+
- ✅ User dashboard with usage stats
|
|
31
|
+
- ✅ Webhook handlers for Stripe events
|
|
32
|
+
- ✅ Transactional emails with Resend
|
|
33
|
+
- ✅ File upload with S3 presigned URLs
|
|
34
|
+
- ✅ TypeScript types for all models
|
|
35
|
+
- ✅ Reusable UI components
|
|
36
|
+
|
|
37
|
+
## Stack
|
|
38
|
+
|
|
39
|
+
- Next.js 15
|
|
40
|
+
- React 19
|
|
41
|
+
- Prisma ORM
|
|
42
|
+
- PostgreSQL
|
|
43
|
+
- Tailwind CSS
|
|
44
|
+
- TypeScript
|
|
45
|
+
|
|
46
|
+
Generated with [Ultra-Dex CLI](https://github.com/Srujan0798/Ultra-Dex)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nextjs-saas",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "next dev",
|
|
7
|
+
"build": "next build",
|
|
8
|
+
"start": "next start",
|
|
9
|
+
"lint": "next lint",
|
|
10
|
+
"db:generate": "prisma generate",
|
|
11
|
+
"db:migrate": "prisma migrate dev",
|
|
12
|
+
"db:studio": "prisma studio",
|
|
13
|
+
"db:seed": "tsx prisma/seed.ts"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"next": "15.0.0",
|
|
17
|
+
"react": "^19.0.0",
|
|
18
|
+
"react-dom": "^19.0.0",
|
|
19
|
+
"@clerk/nextjs": "^5.0.0",
|
|
20
|
+
"@prisma/client": "^5.0.0",
|
|
21
|
+
"stripe": "^15.0.0",
|
|
22
|
+
"@stripe/stripe-js": "^3.0.0",
|
|
23
|
+
"@stripe/react-stripe-js": "^2.0.0",
|
|
24
|
+
"resend": "^3.0.0",
|
|
25
|
+
"@aws-sdk/client-s3": "^3.0.0",
|
|
26
|
+
"@aws-sdk/s3-presigned-post": "^3.0.0",
|
|
27
|
+
"zod": "^3.0.0",
|
|
28
|
+
"tailwindcss": "^3.0.0",
|
|
29
|
+
"autoprefixer": "^10.0.0",
|
|
30
|
+
"postcss": "^8.0.0",
|
|
31
|
+
"lucide-react": "^0.400.0",
|
|
32
|
+
"class-variance-authority": "^0.7.0",
|
|
33
|
+
"clsx": "^2.0.0",
|
|
34
|
+
"tailwind-merge": "^2.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"typescript": "^5.0.0",
|
|
38
|
+
"@types/node": "^20.0.0",
|
|
39
|
+
"@types/react": "^19.0.0",
|
|
40
|
+
"@types/react-dom": "^19.0.0",
|
|
41
|
+
"prisma": "^5.0.0",
|
|
42
|
+
"tsx": "^4.0.0",
|
|
43
|
+
"eslint": "^8.0.0",
|
|
44
|
+
"eslint-config-next": "15.0.0"
|
|
45
|
+
}
|
|
46
|
+
}
|