create-varity-app 2.0.0-beta.2 → 2.0.0-beta.22

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/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![npm](https://img.shields.io/npm/v/create-varity-app)](https://www.npmjs.com/package/create-varity-app)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/varity-labs/varity-sdk/blob/main/LICENSE)
5
5
 
6
- Create production-ready apps with auth, database, and payments built in.
6
+ Create production-ready apps with auth and database built in. Payments coming soon.
7
7
 
8
8
  ## Quick Start
9
9
 
@@ -23,12 +23,12 @@ yarn create varity-app my-app
23
23
  ## What You Get
24
24
 
25
25
  - **Next.js 15** app with TypeScript and Tailwind CSS
26
- - **Authentication** email, social login, and more (zero config)
27
- - **Database** ready-to-use collections with typed queries
28
- - **Dashboard** professional layout with sidebar navigation
29
- - **Landing page** hero, features, pricing, testimonials
30
- - **Settings** profile, preferences, security, billing sections
31
- - **6 pages** dashboard, projects, tasks, team, settings, login
26
+ - **Authentication** -- email, social login, and more (zero config)
27
+ - **Database** -- ready-to-use collections with typed queries
28
+ - **Dashboard** -- professional layout with sidebar navigation
29
+ - **Landing page** -- hero, features, pricing, how it works, testimonials, CTA
30
+ - **Settings** -- General, Security, Billing, and Account tabs
31
+ - **8 pages** -- landing, login, dashboard, projects, tasks, team, settings, 404
32
32
 
33
33
  ## Project Structure
34
34
 
@@ -36,15 +36,16 @@ yarn create varity-app my-app
36
36
  my-app/
37
37
  ├── src/
38
38
  │ └── app/
39
- │ ├── (auth)/login/ # Login page
40
- │ ├── (dashboard)/ # Protected dashboard pages
41
- │ │ ├── dashboard/ # Overview with KPIs
39
+ │ ├── login/ # Login page
40
+ │ ├── dashboard/ # Protected dashboard pages
41
+ │ │ ├── page.tsx # Overview with KPIs
42
42
  │ │ ├── projects/ # Project management
43
43
  │ │ ├── tasks/ # Task tracking
44
44
  │ │ ├── team/ # Team members
45
- │ │ └── settings/ # App settings (6 sections)
45
+ │ │ └── settings/ # App settings (4 tabs)
46
+ │ ├── not-found.tsx # 404 page
46
47
  │ └── page.tsx # Landing page
47
- ├── tailwind.config.ts
48
+ ├── tailwind.config.js
48
49
  ├── next.config.js
49
50
  └── package.json
50
51
  ```
@@ -60,26 +61,26 @@ varitykit app deploy
60
61
 
61
62
  Your app will be live in under 60 seconds.
62
63
 
63
- Or deploy from your AI editor with the [Varity MCP server](../../cli/varity-mcp/) (`@varity-labs/mcp`) just ask "deploy this project".
64
+ Or deploy from your AI editor with the [Varity MCP server](https://www.npmjs.com/package/@varity-labs/mcp) -- just ask "deploy this project".
64
65
 
65
66
  ## Related Packages
66
67
 
67
- - **[@varity-labs/sdk](../../core/varity-sdk/)** Core SDK (database, credentials)
68
- - **[@varity-labs/ui-kit](../../ui/varity-ui-kit/)** React UI components
69
- - **[@varity-labs/mcp](../../cli/varity-mcp/)** MCP server for AI editors (Cursor, Claude Code, VS Code)
68
+ - **[@varity-labs/sdk](https://www.npmjs.com/package/@varity-labs/sdk)** -- Core SDK (database, credentials)
69
+ - **[@varity-labs/ui-kit](https://www.npmjs.com/package/@varity-labs/ui-kit)** -- React UI components
70
+ - **[@varity-labs/mcp](https://www.npmjs.com/package/@varity-labs/mcp)** -- MCP server for AI editors (Cursor, Claude Code, VS Code)
70
71
 
71
72
  ## Learn More
72
73
 
73
74
  - [Documentation](https://docs.varity.so)
74
75
  - [GitHub](https://github.com/varity-labs/varity-sdk)
75
- - [Discord](https://discord.gg/varity)
76
+ - [Discord](https://discord.gg/7vWsdwa2Bg)
76
77
 
77
78
  ---
78
79
 
79
- **Part of the [Varity SDK](https://github.com/varity-labs/varity-sdk)** Build, deploy, and monetize apps 70% cheaper than AWS.
80
+ **Part of the [Varity SDK](https://github.com/varity-labs/varity-sdk)** -- Build, deploy, and monetize apps 70% cheaper than AWS.
80
81
 
81
- [Documentation](https://docs.varity.so) · [GitHub](https://github.com/varity-labs/varity-sdk) · [Discord](https://discord.gg/varity)
82
+ [Documentation](https://docs.varity.so) | [GitHub](https://github.com/varity-labs/varity-sdk) | [Discord](https://discord.gg/7vWsdwa2Bg)
82
83
 
83
84
  ## License
84
85
 
85
- MIT [Varity Labs](https://varity.so)
86
+ MIT -- [Varity Labs](https://www.varity.so)
package/dist/create.js CHANGED
@@ -7,11 +7,10 @@ import ora from "ora";
7
7
  import { getInstallCommand } from "./utils.js";
8
8
  const __filename = fileURLToPath(import.meta.url);
9
9
  const __dirname = path.dirname(__filename);
10
- const VARITY_PACKAGE_VERSION = "^2.0.0-beta.2";
11
10
  const WORKSPACE_DEPS = {
12
- "@varity-labs/sdk": VARITY_PACKAGE_VERSION,
13
- "@varity-labs/types": VARITY_PACKAGE_VERSION,
14
- "@varity-labs/ui-kit": VARITY_PACKAGE_VERSION,
11
+ "@varity-labs/sdk": "2.0.0-beta.6",
12
+ "@varity-labs/types": "2.0.0-beta.4",
13
+ "@varity-labs/ui-kit": "2.0.0-beta.7",
15
14
  };
16
15
  const EXCLUDED_FILES = new Set([
17
16
  ".env.local",
@@ -33,7 +32,7 @@ function rewritePackageJson(content, projectName) {
33
32
  for (const [name, version] of Object.entries(deps)) {
34
33
  if (typeof version === "string" &&
35
34
  version.startsWith("workspace:")) {
36
- deps[name] = WORKSPACE_DEPS[name] || VARITY_PACKAGE_VERSION;
35
+ deps[name] = WORKSPACE_DEPS[name] || "2.0.0-beta.4";
37
36
  }
38
37
  }
39
38
  }
@@ -136,6 +135,6 @@ export async function createApp(projectName, packageManager) {
136
135
  console.log(chalk.cyan(" varitykit app deploy"));
137
136
  console.log();
138
137
  console.log(` Docs: ${chalk.underline("https://docs.varity.so")}`);
139
- console.log(` Help: ${chalk.underline("https://discord.gg/varity")}`);
138
+ console.log(` Help: ${chalk.underline("https://discord.gg/7vWsdwa2Bg")}`);
140
139
  console.log();
141
140
  }
package/dist/index.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-varity-app",
3
- "version": "2.0.0-beta.2",
3
+ "version": "2.0.0-beta.22",
4
4
  "description": "Create production-ready apps with auth, database, and payments built in",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -38,6 +38,11 @@
38
38
  "LICENSE"
39
39
  ],
40
40
  "type": "module",
41
+ "scripts": {
42
+ "prebuild": "node scripts/copy-template.mjs",
43
+ "build": "tsc",
44
+ "clean": "rm -rf dist template"
45
+ },
41
46
  "dependencies": {
42
47
  "chalk": "^5.3.0",
43
48
  "commander": "^12.1.0",
@@ -52,10 +57,5 @@
52
57
  "@types/prompts": "^2.4.9",
53
58
  "@types/validate-npm-package-name": "^4.0.2",
54
59
  "typescript": "^5.5.0"
55
- },
56
- "scripts": {
57
- "prebuild": "node scripts/copy-template.mjs",
58
- "build": "tsc",
59
- "clean": "rm -rf dist template"
60
60
  }
61
- }
61
+ }
@@ -6,7 +6,7 @@
6
6
  # For production: `varitykit app deploy` injects all credentials automatically.
7
7
  # You never need to manually set these values.
8
8
 
9
- # Auth provider configuration (managed by Varity)
9
+ # Auth (optional dev credentials used automatically when blank)
10
10
  NEXT_PUBLIC_PRIVY_APP_ID=
11
11
 
12
12
  # Database (optional — dev database used automatically when blank)
@@ -1,5 +1,5 @@
1
1
 
2
- > my-saas-app@0.1.0 build /home/macoding/varity-workspace/varity-sdk-impl/templates/saas-starter
2
+ > my-saas-app@0.1.0 build /home/macoding/varity-workspace/varity-sdk-private/templates/saas-starter
3
3
  > next build
4
4
 
5
5
  ⚠ Warning: Next.js inferred your workspace root, but it may not be correct.
@@ -7,43 +7,9 @@
7
7
  To silence this warning, set `outputFileTracingRoot` in your Next.js config, or consider removing one of the lockfiles if it's not needed.
8
8
  See https://nextjs.org/docs/app/api-reference/config/next-config-js/output#caveats for more information.
9
9
  Detected additional lockfiles:
10
- * /home/macoding/varity-workspace/varity-sdk-impl/pnpm-lock.yaml
10
+ * /home/macoding/varity-workspace/varity-sdk-private/pnpm-lock.yaml
11
11
 
12
12
  ▲ Next.js 15.5.11
13
13
 
14
14
  Creating an optimized production build ...
15
15
  ⚠ Mismatching @next/swc version, detected: 15.5.7 while Next.js is on 15.5.11. Please ensure these match
16
- ✓ Compiled successfully in 27.8s
17
- Linting and checking validity of types ...
18
- Collecting page data ...
19
- Generating static pages (0/11) ...
20
- [Varity Database] Using shared development database. Data is stored in an isolated dev schema.
21
- Deploy with `varitykit app deploy` to get your own private database.
22
- Generating static pages (2/11)
23
- Generating static pages (5/11)
24
- Generating static pages (8/11)
25
- ✓ Generating static pages (11/11)
26
- Finalizing page optimization ...
27
- Collecting build traces ...
28
- Exporting (0/2) ...
29
- ✓ Exporting (2/2)
30
-
31
- Route (app) Size First Load JS
32
- ┌ ○ / 5.69 kB 125 kB
33
- ├ ○ /_not-found 132 B 116 kB
34
- ├ ○ /dashboard 3.75 kB 1.33 MB
35
- ├ ○ /dashboard/projects 4.95 kB 1.33 MB
36
- ├ ○ /dashboard/settings 5.88 kB 1.33 MB
37
- ├ ○ /dashboard/tasks 3.17 kB 1.33 MB
38
- ├ ○ /dashboard/team 3.06 kB 1.33 MB
39
- ├ ○ /icon.svg 0 B 0 B
40
- └ ○ /login 1.31 kB 1.33 MB
41
- + First Load JS shared by all 116 kB
42
- ├ chunks/79135-4ac590d187e38d6f.js 45.3 kB
43
- ├ chunks/f0439f7a-76e885cef8778491.js 54.3 kB
44
- ├ chunks/webpack-ea5a8e6ec96b5a02.js 16.1 kB
45
- └ other shared chunks (total) 241 B
46
-
47
-
48
- ○ (Static) prerendered as static content
49
-
@@ -1,6 +1,6 @@
1
- # Known Issues -- SaaS Starter Template
1
+ # Known Issues SaaS Starter Template
2
2
 
3
- > **Last Updated:** March 4, 2026
3
+ > **Last Updated:** March 8, 2026
4
4
  > **Template:** `saas-starter` (TaskFlow)
5
5
  > **Status:** All features functional, builds with 0 errors (8 routes + _not-found)
6
6
 
@@ -10,60 +10,50 @@
10
10
 
11
11
  | Feature | Status | Notes |
12
12
  |---------|--------|-------|
13
- | Landing Page | Working | 6 sections, scroll animations, social proof, testimonials, dashboard mockup |
14
- | Login | Working | Email/Google auth, zero-config with dev credentials, auto-redirect |
15
- | Dashboard | Working | KPI cards, getting started checklist, recent activity feed |
16
- | Projects CRUD | Working | Master-detail, nested tasks, CSV export, validation, optimistic updates |
17
- | Tasks CRUD | Working | Status cycling (click to advance), filtering, CSV export, cross-references projects |
18
- | Team CRUD | Working | Invite members, role management, email validation, role badges |
19
- | Settings | Working | 4 tabs (General, Security, Billing, Account), backend persistence, skeleton loading |
20
- | Command Palette | Working | Cmd+K / Ctrl+K, searches pages and actions |
21
- | Toast Notifications | Working | Success/error/info with progress bar, exit animation, max 3 stack |
22
- | Protected Routes | Working | Automatic redirect for unauthenticated users |
23
- | Color Themes | Working | 4 built-in presets (Blue, Purple, Green, Orange) via CSS variables |
24
- | Static Export | Working | `output: 'export'` for static hosting deployment |
25
- | Mobile Nav | Working | Hamburger menu with responsive sidebar |
26
- | CSV Export | Working | One-click export for tasks and projects |
27
- | SEO | Working | OpenGraph, Twitter cards, robots.txt, sitemap template |
13
+ | Landing Page | Working | 6 sections, scroll animations, social proof |
14
+ | Auth (Login) | Working | Email/Google via Privy, zero-config dev credentials |
15
+ | Dashboard | Working | KPI cards, checklist, activity feed |
16
+ | Projects/Tasks/Team CRUD | Working | Full create, read, update, delete with validation |
17
+ | Settings | Working | 4 tabs with backend persistence via DB Proxy |
18
+ | Command Palette | Working | Cmd+K / Ctrl+K |
19
+ | Color Themes | Working | 4 presets (Blue, Purple, Green, Orange) |
20
+ | Static Export | Working | `output: 'export'` for static hosting (global CDN) |
21
+ | Mobile Nav | Working | Responsive sidebar with hamburger menu |
28
22
 
29
23
  ## Known Issues
30
24
 
31
- ### 1. Navigation Flash (UI-Kit Limitation)
32
- Brief "Initializing Dashboard" screen when navigating between dashboard pages. Caused by the auth guard in UI-Kit re-checking auth state on each route change. Resolves in <1 second. This is a UI-Kit issue, not template-side.
25
+ ### 1. Auth Uses Privy Directly (Abstraction Coming Post-Beta)
26
+ The template uses `usePrivy()` and `NEXT_PUBLIC_PRIVY_APP_ID`. The planned `useAuth()` hook and `NEXT_PUBLIC_VARITY_AUTH_ID` env var are post-beta tasks. No action required -- current auth works correctly.
33
27
 
34
- ### 2. DashboardLayout Mobile Support
35
- The `DashboardLayout` from `@varity-labs/ui-kit` does not include mobile navigation. The template provides its own responsive sidebar in `src/app/dashboard/layout.tsx` as a workaround. UI-Kit mobile improvements are planned.
28
+ ### 2. Payments Section is Placeholder
29
+ Settings > Billing shows mock UI. Credit card payment integration (on/off ramp) is coming soon. Wire your own billing provider (Stripe, etc.) if needed now.
36
30
 
37
- ### 3. Billing Section is Mock
38
- The Settings > Billing tab shows a mock UI (plan name, usage bars, payment method). Developers should wire their own billing provider (Stripe, etc.).
31
+ ### 3. No Server-Side Rendering
32
+ All pages are statically exported. No SSR, API routes, or middleware. Do not use dynamic routes (`[id]` patterns) -- use client-side state for detail views instead.
39
33
 
40
- ### 4. Sessions Are Mock
41
- The Settings > Security tab shows active sessions with a "Revoke" button. Session data is client-side mock -- real session management is handled by the auth provider.
34
+ ### 4. Navigation Flash
35
+ Brief "Initializing Dashboard" screen when navigating between pages. Caused by `PrivyReadyGate` re-checking auth state. Resolves in under 1 second.
42
36
 
43
- ### 5. Password & Profile Managed by Auth Provider
44
- "Change password" and profile photo are managed by the authentication provider. The Settings page shows informational dialogs explaining this.
37
+ ### 5. Team Email Invites Are Local Only
38
+ No SMTP integration. Team members are added to the database but no invitation email is sent. Integrate your own email service if needed.
45
39
 
46
- ### 6. No Server-Side Rendering
47
- All pages are statically exported (`output: 'export'`). No server-side rendering, API routes, or middleware. Data fetching happens client-side via the SDK.
48
-
49
- ### 7. Team Email Invites
50
- No SMTP integration -- team members are added to the database only. No invitation email is sent. Developers should integrate their own email service.
40
+ ### 6. Sessions and Password Are Auth-Provider Managed
41
+ Settings > Security shows mock session data. Password changes and profile photos are managed by the auth provider (Privy), not the template.
51
42
 
52
43
  ## Environment
53
44
 
54
45
  ### Development (Zero Config)
55
46
  ```bash
56
- npm install
57
- npm run dev
47
+ npm install && npm run dev
58
48
  ```
59
- No `.env` file, API keys, or accounts needed. Shared development credentials are built in.
49
+ No `.env` file, API keys, or accounts needed.
60
50
 
61
51
  ### Production
62
52
  ```bash
63
53
  varitykit app deploy
64
54
  ```
65
- The CLI provisions a private database, injects production credentials, and deploys automatically.
66
55
 
67
56
  ## Reporting Issues
68
57
 
69
- Please report issues at: https://github.com/varity-labs/varity-sdk/issues
58
+ - GitHub: https://github.com/varity-labs/varity-sdk/issues
59
+ - Discord: https://discord.gg/7vWsdwa2Bg
@@ -1,8 +1,8 @@
1
- # TaskFlow -- SaaS Starter Template
1
+ # TaskFlow SaaS Starter Template
2
2
 
3
- [![Built with Varity](https://img.shields.io/badge/built%20with-Varity-7C3AED)](https://varity.so)
3
+ [![Built with Varity](https://img.shields.io/badge/built%20with-Varity-7C3AED)](https://www.varity.so)
4
4
 
5
- A full-featured project management app built with [Varity](https://varity.so). Everything works immediately -- no configuration, no API keys, no setup.
5
+ A full-featured project management app built with [Varity](https://www.varity.so). Everything works immediately no configuration, no API keys, no setup.
6
6
 
7
7
  ## Quick Start
8
8
 
@@ -23,12 +23,12 @@ No `.env` file needed. No accounts to create. No credentials to configure.
23
23
 
24
24
  Transform this into your own branded SaaS app:
25
25
 
26
- 1. **App name** -- Edit `APP_NAME` in `src/lib/constants.ts`
27
- 2. **Logo** -- Replace `public/logo.svg` with your logo
28
- 3. **Colors** -- Open `src/app/globals.css` and uncomment a color preset (Purple, Green, or Orange) or set your own
29
- 4. **Meta title** -- Update the `title` and `description` in `src/app/layout.tsx`
30
- 5. **Navigation** -- Edit `NAVIGATION_ITEMS` in `src/lib/constants.ts` to rename or add sidebar links
31
- 6. **Landing page** -- Edit the sections in `src/components/landing/` (Hero, Features, Pricing, etc.)
26
+ 1. **App name** Edit `APP_NAME` in `src/lib/constants.ts`
27
+ 2. **Logo** Replace `public/logo.svg` with your logo
28
+ 3. **Colors** Open `src/app/globals.css` and uncomment a color preset (Purple, Green, or Orange) or set your own
29
+ 4. **Meta title** Update the `title` and `description` in `src/app/layout.tsx`
30
+ 5. **Navigation** Edit `NAVIGATION_ITEMS` in `src/lib/constants.ts` to rename or add sidebar links
31
+ 6. **Landing page** Edit the sections in `src/components/landing/` (Hero, Features, Pricing, etc.)
32
32
 
33
33
  ## Built-in Color Themes
34
34
 
@@ -44,53 +44,71 @@ Switch your entire app's color scheme by editing `src/app/globals.css`:
44
44
 
45
45
  ## What's Included
46
46
 
47
- - **Zero-Config Auth** -- Email and social login works out of the box
48
- - **Zero-Config Database** -- Data persistence with isolated dev environment
49
- - **Dashboard** -- KPI cards, data tables, status badges, getting started guide
50
- - **Full CRUD** -- Create, read, update, delete for projects, tasks, and team members
51
- - **Command Palette** -- Cmd+K search across all data
52
- - **Protected Routes** -- Automatic redirect for unauthenticated users
53
- - **Landing Page** -- Professional marketing page with hero, features, pricing, testimonials
54
- - **Mobile Responsive** -- Hamburger menu, responsive layouts, touch-friendly
55
- - **TypeScript** -- Full type safety throughout
56
- - **Tailwind CSS** -- Utility-first styling with CSS variable theming
47
+ - **Zero-Config Auth** Email and social login works out of the box
48
+ - **Zero-Config Database** Data persistence with isolated dev environment
49
+ - **Dashboard** KPI cards, data tables, status badges, getting started guide
50
+ - **Full CRUD** Create, read, update, delete for projects, tasks, and team members
51
+ - **Command Palette** Cmd+K search across all data
52
+ - **Protected Routes** Automatic redirect for unauthenticated users
53
+ - **Landing Page** Professional marketing page with hero, features, pricing, testimonials
54
+ - **Mobile Responsive** Hamburger menu, responsive layouts, touch-friendly
55
+ - **TypeScript** Full type safety throughout
56
+ - **Tailwind CSS** Utility-first styling with CSS variable theming
57
57
 
58
- ## Zero Configuration Required
58
+ ## Zero Configuration Required
59
59
 
60
60
  This template works immediately with **zero setup**:
61
61
 
62
62
  ### Instant Auth
63
- - Email login (email + Google)
64
- - Social login support
65
- - Dev credentials built-in
66
- - No env vars needed
63
+ - Email login (built-in)
64
+ - Google/Apple social login
65
+ - Dev credentials built-in
66
+ - No env vars needed
67
67
 
68
68
  ### Instant Database
69
- - Create, read, update, delete data
70
- - Dev token built-in
71
- - Production-ready
72
- - No credentials needed
69
+ - Create, read, update, delete data
70
+ - Dev token built-in
71
+ - Production-ready proxy
72
+ - No credentials needed
73
73
 
74
74
  ### Instant Deploy
75
75
  ```bash
76
- varitykit app deploy
76
+ npm run deploy
77
77
  ```
78
- - Deploys to production
79
- - Auto-configures credentials
80
- - No accounts needed
78
+ - Deploys to production
79
+ - Auto-fetches credentials
80
+ - No extra accounts needed
81
81
 
82
82
  ---
83
83
 
84
+ ## 🏗️ Architecture
85
+
86
+ ### Workspace Dependencies
87
+ This template uses `workspace:^` protocol for Varity packages:
88
+ ```json
89
+ {
90
+ "dependencies": {
91
+ "@varity-labs/sdk": "workspace:^",
92
+ "@varity-labs/ui-kit": "workspace:^",
93
+ "@varity-labs/types": "workspace:^"
94
+ }
95
+ }
96
+ ```
97
+
98
+ **Why?** Ensures you always use the latest local package versions during development.
99
+
100
+ **Publishing:** When published to npm, `workspace:^` converts to `^2.0.0-alpha.1` automatically.
101
+
84
102
  ### Static Export Ready
85
- - `output: 'export'` in next.config.js
86
- - All pages pre-rendered to static HTML
87
- - No server-side dependencies
88
- - CDN deployable
103
+ - `output: 'export'` in next.config.js
104
+ - All pages pre-rendered to static HTML
105
+ - No server-side dependencies
106
+ - CDN deployable
89
107
 
90
108
  ### Type Safety
91
- - TypeScript strict mode enabled
92
- - All errors surface during build
93
- - No `ignoreBuildErrors` flag
109
+ - TypeScript strict mode enabled
110
+ - All errors surface during build
111
+ - No `ignoreBuildErrors` flag
94
112
 
95
113
  ## Project Structure
96
114
 
@@ -187,17 +205,17 @@ export function useInvoices(): UseCollectionReturn<Invoice> {
187
205
  const { data, loading, create, update, remove } = useInvoices();
188
206
  ```
189
207
 
190
- The database collection is created automatically on first use -- no migrations needed.
208
+ The database collection is created automatically on first use no migrations needed.
191
209
 
192
210
  ## Environment Variables
193
211
 
194
212
  **For development:** Leave everything blank. Shared development credentials are used automatically.
195
213
 
196
- **For production:** Run `varitykit app deploy` -- it injects all credentials into your build automatically. You never need to manually set API keys.
214
+ **For production:** Run `varitykit app deploy` it injects all credentials into your build automatically. You never need to manually set API keys.
197
215
 
198
216
  | Variable | Required | Notes |
199
217
  |----------|----------|-------|
200
- | `NEXT_PUBLIC_PRIVY_APP_ID` | No | Auth provider (auto-configured) |
218
+ | `NEXT_PUBLIC_VARITY_AUTH_ID` | No | Auth provider (auto-configured) |
201
219
  | `NEXT_PUBLIC_VARITY_APP_TOKEN` | No | Database token (auto-configured) |
202
220
  | `NEXT_PUBLIC_VARITY_APP_ID` | No | App ID (auto-configured) |
203
221
 
@@ -211,7 +229,7 @@ varitykit app deploy
211
229
  varitykit app deploy --submit-to-store
212
230
  ```
213
231
 
214
- The CLI builds your app, provisions a private database, injects production credentials, and deploys -- all in one command.
232
+ The CLI builds your app, provisions a private database, injects production credentials, and deploys all in one command.
215
233
 
216
234
  **Deploy from your AI editor:** Set up the [Varity MCP server](https://docs.varity.so/mcp) (`npx @varity-labs/mcp`) and ask your AI to "deploy this project".
217
235
 
@@ -5,15 +5,9 @@ const nextConfig = {
5
5
  trailingSlash: true,
6
6
  productionBrowserSourceMaps: false,
7
7
  webpack: (config, { isServer, dev }) => {
8
- // Suppress async-storage warning from auth provider dependencies
9
- config.resolve.fallback = {
10
- ...config.resolve.fallback,
11
- '@react-native-async-storage/async-storage': false,
12
- };
13
- // Force production devtool to avoid 35MB eval-source-map chunks
14
- if (!dev && !isServer) {
15
- config.devtool = false;
16
- }
8
+ // Suppress unused optional peer dependencies from UI Kit internals
9
+ ['@react-native-async-storage/async-storage', 'viem', 'viem/chains', 'thirdweb', 'thirdweb/chains', 'thirdweb/react', 'thirdweb/deploys', 'thirdweb/storage', 'thirdweb/wallets', 'thirdweb/wallets/in-app', 'thirdweb/extensions/erc20', 'wagmi', '@solana/kit', '@solana/sysvars', '@solana-program/token-2022', 'x402', '@coinbase/wallet-sdk', '@walletconnect/ethereum-provider'].forEach(pkg => { config.resolve.alias[pkg] = false; });
10
+ if (!dev && !isServer) config.devtool = false;
17
11
  return config;
18
12
  },
19
13
  };
@@ -17,6 +17,7 @@
17
17
  "deploy": "varitykit app deploy"
18
18
  },
19
19
  "dependencies": {
20
+ "@tanstack/react-query": "^5.0.0",
20
21
  "@varity-labs/sdk": "workspace:^",
21
22
  "@varity-labs/types": "workspace:^",
22
23
  "@varity-labs/ui-kit": "workspace:^",
@@ -7,7 +7,11 @@ import { useProjects, useTasks, useTeam } from '@/lib/hooks';
7
7
  import { CommandPalette } from '@varity-labs/ui-kit';
8
8
  import { Menu, X } from 'lucide-react';
9
9
 
10
- // Conditionally import Privy/UI-Kit components
10
+ // Defensively import Privy/UI-Kit components at runtime (not statically) so the
11
+ // dashboard renders gracefully even if @varity-labs/ui-kit hasn't been installed
12
+ // yet (e.g. during local scaffolding before `npm install` completes).
13
+ // This is intentional — it is NOT a sign that something is broken.
14
+ // See KNOWN_ISSUES.md for details on this pattern.
11
15
  let DashboardLayout: any = null;
12
16
  let PrivyProtectedRoute: any = null;
13
17
  let PrivyStackComponent: any = null;
@@ -19,7 +23,9 @@ try {
19
23
  PrivyProtectedRoute = uiKit.PrivyProtectedRoute;
20
24
  PrivyStackComponent = uiKit.PrivyStack;
21
25
  usePrivyHook = uiKit.usePrivy;
22
- } catch {}
26
+ } catch {
27
+ // ui-kit not installed or not yet available — DashboardShell fallback renders below
28
+ }
23
29
 
24
30
  function RedirectToLogin() {
25
31
  const router = useRouter();
@@ -255,7 +261,7 @@ function DashboardShell({ children }: { children: React.ReactNode }) {
255
261
  showSidebar={!isMobile}
256
262
  user={{
257
263
  name: userName,
258
- address: userEmail,
264
+ email: userEmail,
259
265
  }}
260
266
  onLogout={handleLogout}
261
267
  onNavigateToProfile={() => router.push('/dashboard/settings')}
@@ -556,7 +556,7 @@ export default function SettingsPage() {
556
556
  )}
557
557
  </div>
558
558
 
559
- {/* Privy Account Settings */}
559
+ {/* Account Settings */}
560
560
  {privyAppId && PrivyUserProfile && (
561
561
  <div className="rounded-xl border border-gray-200 bg-white p-6 shadow-sm">
562
562
  <h2 className="mb-4 text-lg font-semibold text-gray-900 flex items-center gap-2">
@@ -5,7 +5,7 @@ import './globals.css';
5
5
  export const metadata: Metadata = {
6
6
  title: 'TaskFlow - Project Management',
7
7
  description: 'Manage projects, track tasks, and collaborate with your team.',
8
- metadataBase: new URL('https://varity.so'),
8
+ metadataBase: new URL('https://example.com'),
9
9
  openGraph: {
10
10
  title: 'TaskFlow - Project Management',
11
11
  description: 'Manage projects, track tasks, and collaborate with your team.',
@@ -31,7 +31,7 @@ export function Footer() {
31
31
  <div className="mt-8 border-t border-gray-100 pt-6 text-center text-sm text-gray-400">
32
32
  &copy; {year} {APP_NAME}. Built with{' '}
33
33
  <a
34
- href="https://varity.so"
34
+ href="https://www.varity.so"
35
35
  target="_blank"
36
36
  rel="noopener noreferrer"
37
37
  className="inline-flex items-center gap-1 text-primary-500 hover:text-primary-600 transition-colors"
@@ -0,0 +1,589 @@
1
+ /**
2
+ * Dashboard Service
3
+ *
4
+ * Centralized service for dashboard-related API calls.
5
+ * Provides type-safe interfaces and error handling.
6
+ */
7
+
8
+ import type { Project, Task, TeamMember } from '@/types';
9
+
10
+ // ============================================================================
11
+ // Type Definitions
12
+ // ============================================================================
13
+
14
+ export interface KPIMetric {
15
+ title: string;
16
+ value: string | number;
17
+ change?: {
18
+ value: number;
19
+ period: string;
20
+ };
21
+ trend?: 'up' | 'down' | 'neutral';
22
+ sparklineData?: number[];
23
+ }
24
+
25
+ export interface KPIResponse {
26
+ kpis: KPIMetric[];
27
+ has_data: boolean;
28
+ last_updated: string;
29
+ }
30
+
31
+ export interface Activity {
32
+ id: string;
33
+ type: 'project_created' | 'task_completed' | 'member_added' | 'comment_added';
34
+ title: string;
35
+ description: string;
36
+ timestamp: string;
37
+ user?: {
38
+ name: string;
39
+ avatar?: string;
40
+ };
41
+ metadata?: Record<string, any>;
42
+ }
43
+
44
+ export interface ActivityResponse {
45
+ activities: Activity[];
46
+ total_count: number;
47
+ has_more: boolean;
48
+ }
49
+
50
+ export interface ProjectResponse {
51
+ projects: Project[];
52
+ total_count: number;
53
+ active_count: number;
54
+ }
55
+
56
+ export interface TaskResponse {
57
+ tasks: Task[];
58
+ total_count: number;
59
+ completed_count: number;
60
+ by_status: {
61
+ todo: number;
62
+ in_progress: number;
63
+ done: number;
64
+ };
65
+ }
66
+
67
+ export interface TeamMemberResponse {
68
+ members: TeamMember[];
69
+ total_count: number;
70
+ roles: {
71
+ owner: number;
72
+ admin: number;
73
+ member: number;
74
+ viewer: number;
75
+ };
76
+ }
77
+
78
+ export interface DashboardOverviewResponse {
79
+ kpis: KPIResponse;
80
+ recent_activity: Activity[];
81
+ projects_summary: {
82
+ active: number;
83
+ total: number;
84
+ recent: Project[];
85
+ };
86
+ tasks_summary: {
87
+ open: number;
88
+ completed: number;
89
+ completion_rate: number;
90
+ };
91
+ team_summary: {
92
+ total: number;
93
+ active: number;
94
+ };
95
+ }
96
+
97
+ // ============================================================================
98
+ // Error Handling
99
+ // ============================================================================
100
+
101
+ export class DashboardServiceError extends Error {
102
+ constructor(
103
+ message: string,
104
+ public statusCode?: number,
105
+ public originalError?: Error
106
+ ) {
107
+ super(message);
108
+ this.name = 'DashboardServiceError';
109
+ }
110
+ }
111
+
112
+ async function handleResponse<T>(response: Response): Promise<T> {
113
+ if (!response.ok) {
114
+ const errorText = await response.text().catch(() => 'Unknown error');
115
+ throw new DashboardServiceError(
116
+ `API request failed: ${response.statusText}`,
117
+ response.status,
118
+ new Error(errorText)
119
+ );
120
+ }
121
+
122
+ try {
123
+ return await response.json();
124
+ } catch (error) {
125
+ throw new DashboardServiceError(
126
+ 'Failed to parse API response',
127
+ response.status,
128
+ error instanceof Error ? error : undefined
129
+ );
130
+ }
131
+ }
132
+
133
+ // ============================================================================
134
+ // API Client
135
+ // ============================================================================
136
+
137
+ const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || '/api';
138
+
139
+ /**
140
+ * Fetch dashboard KPIs
141
+ */
142
+ export async function getKPIs(userId: string): Promise<KPIResponse> {
143
+ try {
144
+ const response = await fetch(
145
+ `${API_BASE_URL}/dashboard/kpis?userId=${encodeURIComponent(userId)}`,
146
+ {
147
+ method: 'GET',
148
+ headers: {
149
+ 'Content-Type': 'application/json',
150
+ },
151
+ cache: 'no-store', // Always fetch fresh data
152
+ }
153
+ );
154
+
155
+ return await handleResponse<KPIResponse>(response);
156
+ } catch (error) {
157
+ if (error instanceof DashboardServiceError) {
158
+ throw error;
159
+ }
160
+ throw new DashboardServiceError(
161
+ 'Failed to fetch KPIs',
162
+ undefined,
163
+ error instanceof Error ? error : undefined
164
+ );
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Fetch recent activity
170
+ */
171
+ export async function getRecentActivity(
172
+ userId: string,
173
+ limit: number = 10
174
+ ): Promise<Activity[]> {
175
+ try {
176
+ const response = await fetch(
177
+ `${API_BASE_URL}/dashboard/activity?userId=${encodeURIComponent(userId)}&limit=${limit}`,
178
+ {
179
+ method: 'GET',
180
+ headers: {
181
+ 'Content-Type': 'application/json',
182
+ },
183
+ cache: 'no-store',
184
+ }
185
+ );
186
+
187
+ const data = await handleResponse<ActivityResponse>(response);
188
+ return data.activities;
189
+ } catch (error) {
190
+ if (error instanceof DashboardServiceError) {
191
+ throw error;
192
+ }
193
+ throw new DashboardServiceError(
194
+ 'Failed to fetch recent activity',
195
+ undefined,
196
+ error instanceof Error ? error : undefined
197
+ );
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Fetch all projects for a user
203
+ */
204
+ export async function getProjects(userId: string): Promise<Project[]> {
205
+ try {
206
+ const response = await fetch(
207
+ `${API_BASE_URL}/projects?userId=${encodeURIComponent(userId)}`,
208
+ {
209
+ method: 'GET',
210
+ headers: {
211
+ 'Content-Type': 'application/json',
212
+ },
213
+ cache: 'no-store',
214
+ }
215
+ );
216
+
217
+ const data = await handleResponse<ProjectResponse>(response);
218
+ return data.projects;
219
+ } catch (error) {
220
+ if (error instanceof DashboardServiceError) {
221
+ throw error;
222
+ }
223
+ throw new DashboardServiceError(
224
+ 'Failed to fetch projects',
225
+ undefined,
226
+ error instanceof Error ? error : undefined
227
+ );
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Fetch tasks, optionally filtered by project
233
+ */
234
+ export async function getTasks(
235
+ userId: string,
236
+ projectId?: string
237
+ ): Promise<Task[]> {
238
+ try {
239
+ const url = projectId
240
+ ? `${API_BASE_URL}/tasks?userId=${encodeURIComponent(userId)}&projectId=${encodeURIComponent(projectId)}`
241
+ : `${API_BASE_URL}/tasks?userId=${encodeURIComponent(userId)}`;
242
+
243
+ const response = await fetch(url, {
244
+ method: 'GET',
245
+ headers: {
246
+ 'Content-Type': 'application/json',
247
+ },
248
+ cache: 'no-store',
249
+ });
250
+
251
+ const data = await handleResponse<TaskResponse>(response);
252
+ return data.tasks;
253
+ } catch (error) {
254
+ if (error instanceof DashboardServiceError) {
255
+ throw error;
256
+ }
257
+ throw new DashboardServiceError(
258
+ 'Failed to fetch tasks',
259
+ undefined,
260
+ error instanceof Error ? error : undefined
261
+ );
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Fetch team members
267
+ */
268
+ export async function getTeamMembers(userId: string): Promise<TeamMember[]> {
269
+ try {
270
+ const response = await fetch(
271
+ `${API_BASE_URL}/team?userId=${encodeURIComponent(userId)}`,
272
+ {
273
+ method: 'GET',
274
+ headers: {
275
+ 'Content-Type': 'application/json',
276
+ },
277
+ cache: 'no-store',
278
+ }
279
+ );
280
+
281
+ const data = await handleResponse<TeamMemberResponse>(response);
282
+ return data.members;
283
+ } catch (error) {
284
+ if (error instanceof DashboardServiceError) {
285
+ throw error;
286
+ }
287
+ throw new DashboardServiceError(
288
+ 'Failed to fetch team members',
289
+ undefined,
290
+ error instanceof Error ? error : undefined
291
+ );
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Fetch complete dashboard overview
297
+ */
298
+ export async function getDashboardOverview(
299
+ userId: string
300
+ ): Promise<DashboardOverviewResponse> {
301
+ try {
302
+ const response = await fetch(
303
+ `${API_BASE_URL}/dashboard/overview?userId=${encodeURIComponent(userId)}`,
304
+ {
305
+ method: 'GET',
306
+ headers: {
307
+ 'Content-Type': 'application/json',
308
+ },
309
+ cache: 'no-store',
310
+ }
311
+ );
312
+
313
+ return await handleResponse<DashboardOverviewResponse>(response);
314
+ } catch (error) {
315
+ if (error instanceof DashboardServiceError) {
316
+ throw error;
317
+ }
318
+ throw new DashboardServiceError(
319
+ 'Failed to fetch dashboard overview',
320
+ undefined,
321
+ error instanceof Error ? error : undefined
322
+ );
323
+ }
324
+ }
325
+
326
+ /**
327
+ * Create a new project
328
+ */
329
+ export async function createProject(
330
+ userId: string,
331
+ data: Omit<Project, 'id' | 'createdAt' | 'updatedAt'>
332
+ ): Promise<Project> {
333
+ try {
334
+ const response = await fetch(`${API_BASE_URL}/projects`, {
335
+ method: 'POST',
336
+ headers: {
337
+ 'Content-Type': 'application/json',
338
+ },
339
+ body: JSON.stringify({ userId, ...data }),
340
+ });
341
+
342
+ return await handleResponse<Project>(response);
343
+ } catch (error) {
344
+ if (error instanceof DashboardServiceError) {
345
+ throw error;
346
+ }
347
+ throw new DashboardServiceError(
348
+ 'Failed to create project',
349
+ undefined,
350
+ error instanceof Error ? error : undefined
351
+ );
352
+ }
353
+ }
354
+
355
+ /**
356
+ * Update an existing project
357
+ */
358
+ export async function updateProject(
359
+ projectId: string,
360
+ data: Partial<Project>
361
+ ): Promise<Project> {
362
+ try {
363
+ const response = await fetch(`${API_BASE_URL}/projects/${projectId}`, {
364
+ method: 'PATCH',
365
+ headers: {
366
+ 'Content-Type': 'application/json',
367
+ },
368
+ body: JSON.stringify(data),
369
+ });
370
+
371
+ return await handleResponse<Project>(response);
372
+ } catch (error) {
373
+ if (error instanceof DashboardServiceError) {
374
+ throw error;
375
+ }
376
+ throw new DashboardServiceError(
377
+ 'Failed to update project',
378
+ undefined,
379
+ error instanceof Error ? error : undefined
380
+ );
381
+ }
382
+ }
383
+
384
+ /**
385
+ * Delete a project
386
+ */
387
+ export async function deleteProject(projectId: string): Promise<void> {
388
+ try {
389
+ const response = await fetch(`${API_BASE_URL}/projects/${projectId}`, {
390
+ method: 'DELETE',
391
+ headers: {
392
+ 'Content-Type': 'application/json',
393
+ },
394
+ });
395
+
396
+ if (!response.ok) {
397
+ throw new DashboardServiceError(
398
+ `Failed to delete project: ${response.statusText}`,
399
+ response.status
400
+ );
401
+ }
402
+ } catch (error) {
403
+ if (error instanceof DashboardServiceError) {
404
+ throw error;
405
+ }
406
+ throw new DashboardServiceError(
407
+ 'Failed to delete project',
408
+ undefined,
409
+ error instanceof Error ? error : undefined
410
+ );
411
+ }
412
+ }
413
+
414
+ /**
415
+ * Create a new task
416
+ */
417
+ export async function createTask(
418
+ userId: string,
419
+ data: Omit<Task, 'id' | 'createdAt' | 'updatedAt'>
420
+ ): Promise<Task> {
421
+ try {
422
+ const response = await fetch(`${API_BASE_URL}/tasks`, {
423
+ method: 'POST',
424
+ headers: {
425
+ 'Content-Type': 'application/json',
426
+ },
427
+ body: JSON.stringify({ userId, ...data }),
428
+ });
429
+
430
+ return await handleResponse<Task>(response);
431
+ } catch (error) {
432
+ if (error instanceof DashboardServiceError) {
433
+ throw error;
434
+ }
435
+ throw new DashboardServiceError(
436
+ 'Failed to create task',
437
+ undefined,
438
+ error instanceof Error ? error : undefined
439
+ );
440
+ }
441
+ }
442
+
443
+ /**
444
+ * Update an existing task
445
+ */
446
+ export async function updateTask(
447
+ taskId: string,
448
+ data: Partial<Task>
449
+ ): Promise<Task> {
450
+ try {
451
+ const response = await fetch(`${API_BASE_URL}/tasks/${taskId}`, {
452
+ method: 'PATCH',
453
+ headers: {
454
+ 'Content-Type': 'application/json',
455
+ },
456
+ body: JSON.stringify(data),
457
+ });
458
+
459
+ return await handleResponse<Task>(response);
460
+ } catch (error) {
461
+ if (error instanceof DashboardServiceError) {
462
+ throw error;
463
+ }
464
+ throw new DashboardServiceError(
465
+ 'Failed to update task',
466
+ undefined,
467
+ error instanceof Error ? error : undefined
468
+ );
469
+ }
470
+ }
471
+
472
+ /**
473
+ * Delete a task
474
+ */
475
+ export async function deleteTask(taskId: string): Promise<void> {
476
+ try {
477
+ const response = await fetch(`${API_BASE_URL}/tasks/${taskId}`, {
478
+ method: 'DELETE',
479
+ headers: {
480
+ 'Content-Type': 'application/json',
481
+ },
482
+ });
483
+
484
+ if (!response.ok) {
485
+ throw new DashboardServiceError(
486
+ `Failed to delete task: ${response.statusText}`,
487
+ response.status
488
+ );
489
+ }
490
+ } catch (error) {
491
+ if (error instanceof DashboardServiceError) {
492
+ throw error;
493
+ }
494
+ throw new DashboardServiceError(
495
+ 'Failed to delete task',
496
+ undefined,
497
+ error instanceof Error ? error : undefined
498
+ );
499
+ }
500
+ }
501
+
502
+ /**
503
+ * Invite a team member
504
+ */
505
+ export async function inviteTeamMember(
506
+ userId: string,
507
+ email: string,
508
+ role: TeamMember['role']
509
+ ): Promise<TeamMember> {
510
+ try {
511
+ const response = await fetch(`${API_BASE_URL}/team/invite`, {
512
+ method: 'POST',
513
+ headers: {
514
+ 'Content-Type': 'application/json',
515
+ },
516
+ body: JSON.stringify({ userId, email, role }),
517
+ });
518
+
519
+ return await handleResponse<TeamMember>(response);
520
+ } catch (error) {
521
+ if (error instanceof DashboardServiceError) {
522
+ throw error;
523
+ }
524
+ throw new DashboardServiceError(
525
+ 'Failed to invite team member',
526
+ undefined,
527
+ error instanceof Error ? error : undefined
528
+ );
529
+ }
530
+ }
531
+
532
+ /**
533
+ * Remove a team member
534
+ */
535
+ export async function removeTeamMember(memberId: string): Promise<void> {
536
+ try {
537
+ const response = await fetch(`${API_BASE_URL}/team/${memberId}`, {
538
+ method: 'DELETE',
539
+ headers: {
540
+ 'Content-Type': 'application/json',
541
+ },
542
+ });
543
+
544
+ if (!response.ok) {
545
+ throw new DashboardServiceError(
546
+ `Failed to remove team member: ${response.statusText}`,
547
+ response.status
548
+ );
549
+ }
550
+ } catch (error) {
551
+ if (error instanceof DashboardServiceError) {
552
+ throw error;
553
+ }
554
+ throw new DashboardServiceError(
555
+ 'Failed to remove team member',
556
+ undefined,
557
+ error instanceof Error ? error : undefined
558
+ );
559
+ }
560
+ }
561
+
562
+ /**
563
+ * Update team member role
564
+ */
565
+ export async function updateTeamMemberRole(
566
+ memberId: string,
567
+ role: TeamMember['role']
568
+ ): Promise<TeamMember> {
569
+ try {
570
+ const response = await fetch(`${API_BASE_URL}/team/${memberId}`, {
571
+ method: 'PATCH',
572
+ headers: {
573
+ 'Content-Type': 'application/json',
574
+ },
575
+ body: JSON.stringify({ role }),
576
+ });
577
+
578
+ return await handleResponse<TeamMember>(response);
579
+ } catch (error) {
580
+ if (error instanceof DashboardServiceError) {
581
+ throw error;
582
+ }
583
+ throw new DashboardServiceError(
584
+ 'Failed to update team member role',
585
+ undefined,
586
+ error instanceof Error ? error : undefined
587
+ );
588
+ }
589
+ }