@donotdev/cli 0.0.15 → 0.0.17

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.
Files changed (83) hide show
  1. package/dependencies-matrix.json +67 -147
  2. package/dist/bin/commands/build.js +69 -52
  3. package/dist/bin/commands/bump.js +15 -14
  4. package/dist/bin/commands/create-app.js +258 -55
  5. package/dist/bin/commands/create-project.js +290 -161
  6. package/dist/bin/commands/deploy.js +146 -63
  7. package/dist/bin/commands/dev.js +43 -24
  8. package/dist/bin/commands/doctor.d.ts +6 -0
  9. package/dist/bin/commands/doctor.d.ts.map +1 -0
  10. package/dist/bin/commands/{lint.js → doctor.js} +1370 -146
  11. package/dist/bin/commands/doctor.js.map +1 -0
  12. package/dist/bin/commands/emu.js +295 -107
  13. package/dist/bin/commands/make-admin.js +77519 -11
  14. package/dist/bin/commands/preview.js +44 -25
  15. package/dist/bin/commands/setup.d.ts +6 -0
  16. package/dist/bin/commands/setup.d.ts.map +1 -0
  17. package/dist/bin/commands/setup.js +12123 -0
  18. package/dist/bin/commands/setup.js.map +1 -0
  19. package/dist/bin/commands/type-check.d.ts.map +1 -1
  20. package/dist/bin/commands/type-check.js +2022 -283
  21. package/dist/bin/commands/type-check.js.map +1 -1
  22. package/dist/bin/dndev.js +54 -58
  23. package/dist/bin/donotdev.js +54 -58
  24. package/dist/index.js +860 -459
  25. package/package.json +2 -2
  26. package/templates/app-expo/.env.example +2 -22
  27. package/templates/app-expo/README.md.example +1 -1
  28. package/templates/app-expo/assets/adaptive-icon.png +0 -0
  29. package/templates/app-expo/assets/favicon.png +0 -0
  30. package/templates/app-expo/assets/icon.png +0 -0
  31. package/templates/app-expo/assets/splash.png +0 -0
  32. package/templates/app-expo/src/config/app.ts.example +46 -0
  33. package/templates/app-expo/src/config/providers.ts.example +7 -0
  34. package/templates/app-next/src/config/providers.ts.example +7 -0
  35. package/templates/app-vite/src/config/providers.ts.example +7 -0
  36. package/templates/app-vite/src/pages/HomePage.tsx.example +1 -1
  37. package/templates/functions-firebase/README.md.example +1 -1
  38. package/templates/functions-firebase/functions-firebase/.env.example.example +1 -1
  39. package/templates/functions-firebase/functions-firebase/README.md.example +1 -1
  40. package/templates/functions-firebase/functions-firebase/tsconfig.json.example +1 -1
  41. package/templates/functions-firebase/functions.config.js.example +1 -1
  42. package/templates/functions-supabase/supabase/config.toml.example +59 -0
  43. package/templates/functions-supabase/supabase/functions/.env.example +13 -0
  44. package/templates/functions-supabase/supabase/functions/deno.json.example +8 -0
  45. package/templates/overlay-firebase/env.fragment.example +1 -1
  46. package/templates/overlay-firebase/env.fragment.expo.example +1 -1
  47. package/templates/overlay-firebase/env.fragment.nextjs.example +1 -1
  48. package/templates/overlay-supabase/env.fragment.example +8 -3
  49. package/templates/overlay-supabase/env.fragment.expo.example +8 -3
  50. package/templates/overlay-supabase/env.fragment.nextjs.example +8 -3
  51. package/templates/overlay-vercel/env.fragment.example +1 -1
  52. package/templates/overlay-vercel/env.fragment.nextjs.example +1 -1
  53. package/templates/root-consumer/AI.md.example +15 -0
  54. package/templates/root-consumer/guides/dndev/AGENT_START_HERE.md.example +2 -2
  55. package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +12 -12
  56. package/templates/root-consumer/guides/dndev/INDEX.md.example +3 -3
  57. package/templates/root-consumer/guides/dndev/SETUP_APP_CONFIG.md.example +3 -3
  58. package/templates/root-consumer/guides/dndev/SETUP_AUTH.md.example +13 -6
  59. package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +149 -988
  60. package/templates/root-consumer/guides/dndev/SETUP_FIREBASE.md.example +72 -20
  61. package/templates/root-consumer/guides/dndev/SETUP_FUNCTIONS.md.example +6 -111
  62. package/templates/root-consumer/guides/dndev/SETUP_OAUTH_PROVIDERS.md.example +60 -0
  63. package/templates/root-consumer/guides/dndev/SETUP_STRIPE.md.example +62 -0
  64. package/templates/root-consumer/guides/dndev/SETUP_SUPABASE.md.example +124 -33
  65. package/templates/root-consumer/guides/dndev/SETUP_VERCEL.md.example +108 -91
  66. package/templates/root-consumer/guides/dndev/advanced/EMULATORS.md.example +2 -2
  67. package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +7 -8
  68. package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +9 -5
  69. package/dist/bin/commands/firebase-setup.d.ts +0 -6
  70. package/dist/bin/commands/firebase-setup.d.ts.map +0 -1
  71. package/dist/bin/commands/firebase-setup.js +0 -7
  72. package/dist/bin/commands/firebase-setup.js.map +0 -1
  73. package/dist/bin/commands/lint.d.ts +0 -11
  74. package/dist/bin/commands/lint.d.ts.map +0 -1
  75. package/dist/bin/commands/lint.js.map +0 -1
  76. package/dist/bin/commands/staging.d.ts +0 -11
  77. package/dist/bin/commands/staging.d.ts.map +0 -1
  78. package/dist/bin/commands/staging.js +0 -12
  79. package/dist/bin/commands/staging.js.map +0 -1
  80. package/dist/bin/commands/supabase-setup.d.ts +0 -6
  81. package/dist/bin/commands/supabase-setup.d.ts.map +0 -1
  82. package/dist/bin/commands/supabase-setup.js +0 -7
  83. package/dist/bin/commands/supabase-setup.js.map +0 -1
@@ -1,13 +1,13 @@
1
1
  # Setup: Firebase
2
2
 
3
- **From zero to deployed in 5 steps.**
3
+ **From zero to deployed in 5 steps. Covers Auth, Firestore, Storage, Cloud Functions, and Hosting.**
4
4
 
5
5
  ---
6
6
 
7
7
  ## Step 1: Run Firebase Setup
8
8
 
9
9
  ```bash
10
- dndev firebase:setup
10
+ dndev setup firebase
11
11
  ```
12
12
 
13
13
  This command:
@@ -60,7 +60,7 @@ dndev emu start
60
60
 
61
61
  Select services: Auth + Firestore + Functions. This starts Firebase emulators so you can develop without touching production.
62
62
 
63
- **Verify:** Open the app (`bun dev`), sign up, create some data. Everything runs locally.
63
+ **Verify:** Open the app (`dndev dev`), sign up, create some data. Everything runs locally.
64
64
 
65
65
  ---
66
66
 
@@ -81,6 +81,66 @@ This handles everything:
81
81
 
82
82
  ---
83
83
 
84
+ ## Cloud Functions
85
+
86
+ Functions are scaffolded in `functions/` and auto-deployed with `dndev deploy`.
87
+
88
+ **Server secrets** (Stripe, OAuth, etc.) go in `functions/.env` — see the [Secrets](#secrets-stripe-oauth-etc) section below.
89
+
90
+ ### CRUD Functions (one line)
91
+
92
+ ```typescript
93
+ // functions/src/index.ts
94
+ import { initializeApp } from 'firebase-admin/app';
95
+ import { createCrudFunctions } from '@donotdev/functions/firebase';
96
+ import * as entities from 'entities';
97
+
98
+ initializeApp();
99
+ export const crud = createCrudFunctions(entities);
100
+ ```
101
+
102
+ **Result:** Auto-generates CRUD handlers for each entity. The export name (camelCase, e.g. `crud`) is what you use client-side: `httpsCallable(functions, 'crud')`. The operation ID (snake_case, e.g. `create_products`) is used internally for logging and rate limiting.
103
+
104
+ ### Custom Functions
105
+
106
+ ```typescript
107
+ import * as v from 'valibot';
108
+ import { createFunction } from '@donotdev/functions/firebase';
109
+ import { getFirebaseAdminFirestore } from '@donotdev/firebase/server';
110
+
111
+ const schema = v.object({ productId: v.string() });
112
+
113
+ export const getProductDetails = createFunction(schema, 'get_product_details', async (data, { uid }) => {
114
+ const db = getFirebaseAdminFirestore();
115
+ const doc = await db.collection('products').doc(data.productId).get();
116
+ return doc.data();
117
+ });
118
+ ```
119
+
120
+ Rate limiting, metrics, auth, schema validation — all included by default.
121
+
122
+ ### Import Rules
123
+
124
+ **Functions run on Node.js — you MUST use `/server` imports:**
125
+
126
+ ```typescript
127
+ // ✅ CORRECT
128
+ import { getFirebaseAdminFirestore } from '@donotdev/firebase/server';
129
+ import { handleError } from '@donotdev/core/server';
130
+
131
+ // ❌ WRONG - crashes on deploy
132
+ import { getFirestore } from '@donotdev/firebase';
133
+ import { handleError } from '@donotdev/core';
134
+ ```
135
+
136
+ ### Cloud Run IAM (Technical Detail)
137
+
138
+ Firebase 2nd gen Cloud Functions run on Cloud Run. By default, Cloud Run blocks unauthenticated OPTIONS requests (CORS preflight). `dndev deploy` automatically runs `gcloud run services update --no-invoker-iam-check` on all deployed functions.
139
+
140
+ If you deploy manually with `firebase deploy`, you'll see `403 Forbidden` on CORS preflight. Use `dndev deploy` instead.
141
+
142
+ ---
143
+
84
144
  ## Environment Variables
85
145
 
86
146
  **Vite loads `.env` from the app directory only. NOT from the repo root.**
@@ -94,17 +154,20 @@ This handles everything:
94
154
  | `functions/.env` | Server secrets: STRIPE_SECRET_KEY, OAuth secrets | Cloud Functions runtime |
95
155
  | Root `.env` | **Not read by Vite.** Reference only. | Nothing |
96
156
 
97
- **`dndev firebase:setup` writes Firebase vars to `apps/<app>/.env` automatically.**
157
+ **`dndev setup firebase` writes Firebase vars to `apps/<app>/.env` automatically.**
98
158
 
99
- **Custom domains:** Framework uses `APP_URL` hostname as `authDomain` in production (not Firebase's `projectId.firebaseapp.com`). Copy/paste `FIREBASE_AUTH_DOMAIN` from Firebase Console in both `.env.local` and `.env.production` — framework handles the rest.
159
+ **Custom domains:** Framework uses `APP_URL` hostname as `authDomain` in production (not Firebase's `projectId.firebaseapp.com`). Set your `FIREBASE_AUTH_DOMAIN` env var (with the appropriate `VITE_` or `NEXT_PUBLIC_` prefix) in `.env.local` and `.env.production` — framework handles the rest.
100
160
 
101
161
  ---
102
162
 
103
163
  ## Staging Environment (Optional)
104
164
 
105
165
  1. Create a second Firebase project (e.g., `my-app-staging`)
106
- 2. Run `dndev firebase:setup` again and select the staging project
107
- 3. Add to `.firebaserc`: `{ "projects": { "staging": "my-app-staging" } }`
166
+ 2. Run `dndev setup firebase` again and select the staging project
167
+ 3. The wizard updates `.firebaserc` add a `"staging"` alias manually if the wizard only sets `"default"`:
168
+ ```json
169
+ { "projects": { "default": "my-app-prod", "staging": "my-app-staging" } }
170
+ ```
108
171
  4. Create `service-account-key.staging.json` (same steps as production)
109
172
  5. Deploy: `dndev staging`
110
173
 
@@ -120,14 +183,13 @@ Server-side secrets go in `functions/.env`, not the app `.env`.
120
183
  # functions/.env
121
184
  STRIPE_SECRET_KEY=sk_live_...
122
185
  STRIPE_WEBHOOK_SECRET=whsec_...
123
- SUPABASE_SERVICE_ROLE_KEY=eyJ... # if using Supabase
124
186
  GITHUB_CLIENT_SECRET=...
125
187
  ```
126
188
 
127
189
  Then sync to your runtime and CI/CD:
128
190
 
129
191
  ```bash
130
- dndev sync-secrets # Firebase Secret Manager / Vercel env
192
+ dndev sync-secrets # Firebase Secret Manager
131
193
  dndev sync-secrets --target github # GitHub Secrets (for CI/CD workflows)
132
194
  ```
133
195
 
@@ -137,16 +199,6 @@ See [ENV_SETUP.md → Secrets Philosophy](./ENV_SETUP.md#secrets-philosophy) for
137
199
 
138
200
  ---
139
201
 
140
- ## Cloud Run IAM (Technical Detail)
141
-
142
- Firebase 2nd gen Cloud Functions run on Cloud Run. By default, Cloud Run blocks unauthenticated OPTIONS requests (CORS preflight). This breaks browser calls to your functions.
143
-
144
- `dndev deploy` automatically runs `gcloud run services update --no-invoker-iam-check` on all deployed functions. Your functions still validate Firebase Auth in code — this only allows the CORS preflight to pass.
145
-
146
- If you deploy manually with `firebase deploy`, you'll need to run this yourself. Use `dndev deploy` instead.
147
-
148
- ---
149
-
150
202
  ## Troubleshooting
151
203
 
152
204
  **"Service account key not found"**
@@ -171,4 +223,4 @@ If you deploy manually with `firebase deploy`, you'll need to run this yourself.
171
223
 
172
224
  ---
173
225
 
174
- **`dndev firebase:setup` → download service account key → enable Auth + Firestore → `dndev emu start` → `dndev deploy`. That's it.**
226
+ **`dndev setup firebase` → download service account key → enable Auth + Firestore → `dndev emu start` → `dndev deploy`. That's it.**
@@ -1,114 +1,9 @@
1
- # Setup: Firebase Functions
1
+ # Setup: Functions
2
2
 
3
- **Most is pre-configured.** Functions scaffolded. Just add config and deploy.
3
+ **This guide has been merged into provider-specific guides.**
4
4
 
5
- ---
5
+ - **Firebase Cloud Functions** → See [SETUP_FIREBASE.md § Cloud Functions](./SETUP_FIREBASE.md#cloud-functions)
6
+ - **Supabase Edge Functions** → See [SETUP_SUPABASE.md § Edge Functions](./SETUP_SUPABASE.md#edge-functions)
7
+ - **Vercel Functions** → See [SETUP_VERCEL.md § Vercel Functions](./SETUP_VERCEL.md#vercel-functions-optional)
6
8
 
7
- ## ⚠️ CRITICAL: Import Rules
8
-
9
- **Functions run on Node.js - you MUST use `/server` imports or your function will crash.**
10
-
11
- ```typescript
12
- // ✅ CORRECT
13
- import { getFirebaseAdminFirestore } from '@donotdev/firebase/server';
14
- import { handleError } from '@donotdev/core/server';
15
-
16
- // ❌ WRONG - crashes on deploy
17
- import { getFirestore } from '@donotdev/firebase';
18
- import { handleError } from '@donotdev/core';
19
- ```
20
-
21
- **Rule:** Always use `/server` suffix for:
22
- - `@donotdev/firebase/server`
23
- - `@donotdev/core/server`
24
- - `@donotdev/utils/server`
25
-
26
- ---
27
-
28
- ## CRUD Functions Setup
29
-
30
- **One line to register all entity functions:**
31
-
32
- ```typescript
33
- // functions/src/index.ts
34
- import { initializeApp } from 'firebase-admin/app';
35
- import { createCrudFunctions } from '@donotdev/functions/firebase';
36
- import * as entities from 'entities';
37
-
38
- initializeApp();
39
- export const crud = createCrudFunctions(entities);
40
- ```
41
-
42
- **Result:** Auto-generates `create_products`, `get_products`, `list_products`, `update_products`, `delete_products` for each entity.
43
-
44
- **Access control:** Configured via `entity.access` (see SETUP_CRUD.md). All functions use `invoker: 'public'` - security enforced via role-based access in code.
45
-
46
- ---
47
-
48
- ## Custom Functions
49
-
50
- **Use `createFunction` — handles config, validation, auth, rate limiting, metrics automatically:**
51
-
52
- ```typescript
53
- import * as v from 'valibot';
54
- import { createFunction } from '@donotdev/functions/firebase';
55
- import { getFirebaseAdminFirestore } from '@donotdev/firebase/server';
56
-
57
- const schema = v.object({ productId: v.string() });
58
-
59
- export const getProductDetails = createFunction(schema, 'get_product_details', async (data, { uid }) => {
60
- const db = getFirebaseAdminFirestore();
61
- const doc = await db.collection('products').doc(data.productId).get();
62
- return doc.data();
63
- });
64
- ```
65
-
66
- **That's it.** Rate limiting, metrics, auth, schema validation — all included by default. No config needed.
67
-
68
- **Advanced:** Use `createBaseFunction` if you need custom config (memory, timeout, region override).
69
-
70
- ---
71
-
72
- ## Post-Deployment: Cloud Run IAM
73
-
74
- **`dndev deploy` handles this automatically.** It runs `gcloud run services update --no-invoker-iam-check` on all deployed functions after each deploy.
75
-
76
- If you deploy manually with `firebase deploy` (not recommended), you'll see `403 Forbidden` on CORS preflight. Fix by using `dndev deploy` instead, or run manually:
77
-
78
- ```bash
79
- gcloud run services update <function-name> --region=<region> --no-invoker-iam-check --project=<project-id>
80
- ```
81
-
82
- **Why?** Cloud Run blocks unauthenticated OPTIONS (CORS preflight) by default. Your function still validates Firebase Auth in code — this only allows the preflight to pass.
83
-
84
- ---
85
-
86
- ## Function Naming
87
-
88
- **Export name (camelCase):**
89
- ```typescript
90
- export const getDashboardMetrics = onCall(...);
91
- // Client: httpsCallable(functions, 'getDashboardMetrics')
92
- ```
93
-
94
- **Operation ID (snake_case):**
95
- ```typescript
96
- createBaseFunction(config, handler, 'get_dashboard_metrics')
97
- // Used for logging, rate limiting
98
- ```
99
-
100
- ---
101
-
102
- ## Environment
103
-
104
- ```bash
105
- # .env.local (local)
106
- STRIPE_SECRET_KEY=sk_test_...
107
-
108
- # .env (production, synced via dndev sync-secrets)
109
- STRIPE_SECRET_KEY=sk_live_...
110
- ```
111
-
112
- ---
113
-
114
- **Add functions, get backend. Framework handles the rest.**
9
+ Each provider guide covers function setup, CRUD registration, custom functions, import rules, and deployment for that stack.
@@ -0,0 +1,60 @@
1
+ # OAuth Provider Setup Guide
2
+
3
+ Each OAuth provider requires manual registration in their developer console.
4
+ `dndev setup oauth` computes the correct redirect URI for you.
5
+
6
+ ## Redirect URIs
7
+
8
+ ### Firebase
9
+ ```
10
+ https://{{PROJECT_ID}}.firebaseapp.com/__/auth/handler
11
+ ```
12
+ > If you use a custom auth domain, replace `{{PROJECT_ID}}.firebaseapp.com` with your custom domain.
13
+
14
+ ### Supabase
15
+ ```
16
+ https://{{PROJECT_ID}}.supabase.co/auth/v1/callback
17
+ ```
18
+
19
+ ---
20
+
21
+ ## Google OAuth
22
+
23
+ 1. Go to https://console.cloud.google.com/apis/credentials
24
+ 2. Create **OAuth 2.0 Client ID** (type: Web application)
25
+ 3. Add **Authorized redirect URI** (see above)
26
+ 4. Copy **Client ID** and **Client Secret**
27
+ 5. Enable in your backend:
28
+ - Firebase: Console > Authentication > Sign-in method > Google
29
+ - Supabase: Dashboard > Authentication > Providers > Google
30
+
31
+ ## GitHub OAuth
32
+
33
+ 1. Go to https://github.com/settings/developers
34
+ 2. Click **New OAuth App**
35
+ 3. Set **Authorization callback URL** (see redirect URI above)
36
+ 4. Copy **Client ID** and **Client Secret**
37
+ 5. Enable in your backend:
38
+ - Firebase: Console > Authentication > Sign-in method > GitHub
39
+ - Supabase: Dashboard > Authentication > Providers > GitHub
40
+
41
+ ## Apple Sign In
42
+
43
+ 1. Go to https://developer.apple.com/account/resources/identifiers/list/serviceId
44
+ 2. Create a **Services ID**
45
+ 3. Enable **Sign In with Apple**
46
+ 4. Add **Redirect URL** (see above)
47
+ 5. Create a **Key** for Sign In with Apple
48
+ 6. Enable in your backend:
49
+ - Firebase: Console > Authentication > Sign-in method > Apple
50
+ - Supabase: Dashboard > Authentication > Providers > Apple
51
+
52
+ > **Note:** Apple requires an Apple Developer Program membership ($99/year).
53
+
54
+ ## Verify
55
+
56
+ ```bash
57
+ dndev doctor
58
+ ```
59
+
60
+ Check that auth providers are detected and backend configuration is referenced.
@@ -0,0 +1,62 @@
1
+ # Stripe Setup Guide
2
+
3
+ ## Prerequisites
4
+ - Stripe account (https://dashboard.stripe.com)
5
+ - `@donotdev/billing` installed
6
+
7
+ ## 1. Get API Keys
8
+
9
+ 1. Go to https://dashboard.stripe.com/apikeys
10
+ 2. Copy your **Publishable key** (`pk_test_...`) → `.env`
11
+ 3. Copy your **Secret key** (`sk_test_...`) → `supabase/functions/.env` or `functions/.env`
12
+
13
+ > **Security:** Never commit secret keys. Stripe also supports restricted keys (`rk_test_...`, `rk_live_...`) for tighter permissions.
14
+
15
+ ## 2. Configure Webhook
16
+
17
+ 1. Go to https://dashboard.stripe.com/webhooks
18
+ 2. Click **Add endpoint**
19
+ 3. Set endpoint URL:
20
+ - Supabase: `https://{{PROJECT_ID}}.supabase.co/functions/v1/stripe-webhook`
21
+ - Firebase: `https://europe-west1-{{PROJECT_ID}}.cloudfunctions.net/stripeWebhook` (replace `europe-west1` with your region if different)
22
+ 4. Select events:
23
+ - `checkout.session.completed`
24
+ - `customer.subscription.created`
25
+ - `customer.subscription.updated`
26
+ - `customer.subscription.deleted`
27
+ - `invoice.payment_succeeded`
28
+ - `invoice.payment_failed`
29
+ 5. Copy the **Signing secret** (`whsec_...`) → `supabase/functions/.env`
30
+
31
+ ## 3. Environment Variables
32
+
33
+ ### App `.env` (public)
34
+ ```
35
+ VITE_STRIPE_PUBLISHABLE_KEY=pk_test_...
36
+ ```
37
+
38
+ ### Functions `.env` (secret)
39
+ ```
40
+ STRIPE_SECRET_KEY=sk_test_...
41
+ STRIPE_WEBHOOK_SECRET=whsec_...
42
+ ```
43
+
44
+ ## 4. Test Clocks (Optional)
45
+
46
+ For subscription testing without waiting for real billing cycles:
47
+ 1. Go to https://dashboard.stripe.com/test/test-clocks
48
+ 2. Create a test clock
49
+ 3. Create customers attached to the test clock
50
+ 4. Advance time to trigger billing events
51
+
52
+ ## 5. Verify
53
+
54
+ ```bash
55
+ dndev setup stripe # Interactive key setup + validation
56
+ dndev doctor # Health check for all providers
57
+ ```
58
+
59
+ Check that:
60
+ - Publishable key format is valid
61
+ - Secret key format is valid
62
+ - Key modes match (both test or both live)
@@ -1,47 +1,44 @@
1
1
  # Setup: Supabase
2
2
 
3
- **From zero to a working Supabase backend: env, tables, RLS, and adapter behavior.**
3
+ **From zero to a working Supabase backend. Covers Auth, PostgreSQL, Storage, Edge Functions, and deployment.**
4
4
 
5
5
  ---
6
6
 
7
7
  ## Step 1: Run Supabase Setup
8
8
 
9
9
  ```bash
10
- dndev supabase:setup
10
+ dndev setup supabase
11
11
  ```
12
12
 
13
13
  This command:
14
14
  - Lets you choose the target app (if you have an `apps/` directory)
15
- - Asks for your **public** Supabase project URL and anon key
16
- - Writes `VITE_SUPABASE_URL` and `VITE_SUPABASE_ANON_KEY` to your app's `.env`
15
+ - Asks for your **public** Supabase project URL and public key
16
+ - Writes `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLIC_KEY` to your app's `.env`
17
17
 
18
18
  **We only ask for public credentials** (safe to ship in your client bundle). We never ask for the service_role key.
19
19
 
20
- Get URL and anon key from: [Supabase Dashboard](https://supabase.com/dashboard) → your project → **Settings → API**.
20
+ Get URL and public key from: [Supabase Dashboard](https://supabase.com/dashboard) → your project → **Settings → API**.
21
21
 
22
22
  ---
23
23
 
24
24
  ## Step 2: Generate Tables from Entities
25
25
 
26
- The framework can generate PostgreSQL migrations from your entity definitions (same source as the schema used by the app).
26
+ The framework generates PostgreSQL migrations from your entity definitions. This runs automatically as part of `dndev setup supabase`, or you can run it separately:
27
27
 
28
28
  ```bash
29
- dn generate sql
29
+ dndev setup supabase
30
30
  ```
31
31
 
32
+ During setup, the wizard detects your entities and generates SQL migrations.
33
+
32
34
  **What it does:**
33
- - Discovers entities (e.g. in `entities/` or your configured `--entity-dir`)
35
+ - Discovers entities (e.g. in `entities/` or your configured entity directory)
34
36
  - For each entity: `CREATE TABLE` with columns mapped from field types (text, number, boolean, timestamptz, uuid, jsonb, etc.)
35
37
  - Adds technical columns: `id` (uuid, default `gen_random_uuid()`), `user_id`, `created_at`, `updated_at` (with `DEFAULT now()`), `created_by_id`, `updated_by_id`, `status`
36
38
  - Enables **Row Level Security (RLS)** and creates policies so rows are scoped by `auth.uid() = user_id`
37
39
  - Adds a trigger so `updated_at` is set automatically on every `UPDATE`
38
40
 
39
- **Options (optional):**
40
- - `--entity-dir <path>` — where to find entity files (default: from app root)
41
- - `--output-dir <path>` — where to write migrations (default: `supabase/migrations`)
42
- - `--no-single-file` — one migration file per entity instead of one combined file
43
-
44
- Output is written to `supabase/migrations/` (or your `--output-dir`) as a timestamped `.sql` file. Apply it with the Supabase CLI or Dashboard SQL editor.
41
+ Output is written to `supabase/migrations/` as a timestamped `.sql` file.
45
42
 
46
43
  ---
47
44
 
@@ -63,7 +60,80 @@ Copy the contents of the generated migration file into the SQL Editor in the Sup
63
60
 
64
61
  ---
65
62
 
66
- ## Step 4: Adapter Behavior (DB-Managed Timestamps)
63
+ ## Step 4: Enable Supabase Services
64
+
65
+ Go to the Supabase Dashboard and configure:
66
+
67
+ **Authentication** (enabled by default on new projects):
68
+ - Authentication → Providers → Verify Email is enabled
69
+ - Add OAuth providers if needed (Google, GitHub, etc.)
70
+
71
+ **Storage** (optional — only if your app uploads files):
72
+ - Storage → Create bucket (e.g. `uploads`)
73
+ - Configure public or RLS policies as needed
74
+
75
+ ---
76
+
77
+ ## Edge Functions
78
+
79
+ Supabase Edge Functions run on Deno at the edge. If you selected functions during scaffolding, they're in `supabase/functions/`.
80
+
81
+ ### CRUD Functions (one line)
82
+
83
+ ```typescript
84
+ // supabase/functions/crud/index.ts
85
+ import * as entities from '../_shared/entities.ts';
86
+ import { createSupabaseCrudFunctions } from '@donotdev/functions/supabase';
87
+
88
+ const { serve } = createSupabaseCrudFunctions(entities);
89
+ Deno.serve(serve);
90
+ ```
91
+
92
+ **Result:** Auto-generates create, get, list, update, delete handlers for each entity. The dispatcher routes via `_functionName` in the request body.
93
+
94
+ ### Custom Functions
95
+
96
+ ```typescript
97
+ // supabase/functions/my-function/index.ts
98
+ import * as v from 'valibot';
99
+ import { createSupabaseHandler } from '@donotdev/functions/supabase';
100
+
101
+ const schema = v.object({ productId: v.string() });
102
+
103
+ export default createSupabaseHandler(
104
+ 'get_product_details',
105
+ schema,
106
+ async (data, ctx) => {
107
+ const { data: product } = await ctx.supabaseAdmin
108
+ .from('products')
109
+ .select('*')
110
+ .eq('id', data.productId)
111
+ .single();
112
+ return product;
113
+ },
114
+ 'user' // requiredRole (default)
115
+ );
116
+ ```
117
+
118
+ **Context available in handler:** `ctx.uid` (authenticated user ID), `ctx.userRole`, `ctx.supabaseAdmin` (admin client with full access).
119
+
120
+ Rate limiting, metrics, auth, schema validation — all included by default.
121
+
122
+ ### Deploy Edge Functions
123
+
124
+ ```bash
125
+ supabase functions deploy
126
+ ```
127
+
128
+ Or deploy everything with:
129
+
130
+ ```bash
131
+ dndev deploy
132
+ ```
133
+
134
+ ---
135
+
136
+ ## Adapter Behavior (DB-Managed Timestamps)
67
137
 
68
138
  Tables use **snake_case** column names and **timestamptz** for `created_at` / `updated_at`. The framework expects **camelCase** and **ISO date strings** in the app.
69
139
 
@@ -74,7 +144,7 @@ The **Supabase CRUD adapter** handles this automatically:
74
144
  | **Read** (get, query, subscribe) | Rows from Supabase are normalized: snake_case → camelCase (e.g. `created_at` → `createdAt`), and timestamp columns are converted to ISO strings. Your UI receives the same shape as with Firebase. |
75
145
  | **Write** (add, set, update) | The adapter does **not** send `createdAt` / `updatedAt` (or snake equivalents). The database sets them via `DEFAULT now()` and the `updated_at` trigger. |
76
146
 
77
- So you never set timestamps in app code when using Supabase — the DB owns them.
147
+ You never set timestamps in app code — the DB owns them.
78
148
 
79
149
  ---
80
150
 
@@ -85,40 +155,61 @@ So you never set timestamps in app code when using Supabase — the DB owns them
85
155
  | Variable | Purpose |
86
156
  |----------|---------|
87
157
  | `VITE_SUPABASE_URL` | Project URL (public) |
88
- | `VITE_SUPABASE_ANON_KEY` | Anon key (public, safe in bundle) |
158
+ | `VITE_SUPABASE_PUBLIC_KEY` | Public key (safe in bundle) |
89
159
 
90
- **Server (e.g. API routes, Edge Functions):** use the same URL and `SUPABASE_SERVICE_ROLE_KEY` for admin operations. Never expose the service_role key to the client. Put it in `functions/.env` or your hosts env (Vercel, etc.).
160
+ **Server (Edge Functions, API routes):** use the same URL and `SUPABASE_SERVICE_ROLE_KEY` for admin operations. Never expose the service_role key to the client. Put it in `functions/.env` or your host's env (Vercel, etc.).
91
161
 
92
- See [ENV_SETUP.md](./ENV_SETUP.md) for where to put secrets.
162
+ See [ENV_SETUP.md](./ENV_SETUP.md) for the full secrets policy.
93
163
 
94
164
  ---
95
165
 
96
- ## Storage (Optional)
166
+ ## Hosting the Frontend
167
+
168
+ Supabase provides **Auth, PostgreSQL, Storage, and Edge Functions**. It does **not** host your built frontend.
169
+
170
+ **We recommend Vercel** — see [SETUP_VERCEL.md](./SETUP_VERCEL.md).
171
+
172
+ ```bash
173
+ dndev deploy
174
+ ```
97
175
 
98
- If your app uploads files, create a storage bucket in the Supabase Dashboard (e.g. `uploads`). The default bucket name used by the framework is `uploads`. Configure public or RLS policies in the Dashboard as needed.
176
+ For Supabase projects, `dndev deploy` deploys frontend to Vercel (via scaffolded `vercel.json`) and Edge Functions to Supabase. Make sure you've set `VITE_SUPABASE_*` in Vercel Dashboard Environment Variables.
99
177
 
100
178
  ---
101
179
 
102
- ## Hosting the frontend
180
+ ## Local Development
181
+
182
+ **Against hosted Supabase:**
103
183
 
104
- Supabase gives you **Auth, Postgres, Storage, and Edge Functions**. It does **not** host your built frontend (Vite/Next SPA). You need a separate host for the `dist/` output.
184
+ ```bash
185
+ dndev dev
186
+ ```
105
187
 
106
- **We recommend:**
188
+ The app talks to your Supabase project directly.
107
189
 
108
- - **Vercel** — Connect your repo, set `VITE_SUPABASE_URL` and `VITE_SUPABASE_ANON_KEY` in the project env, then deploy. Good fit for Next.js or Vite.
109
- - We scaffold **vercel.json**; run `dndev deploy` and choose Frontend (Vercel) or Frontend + Edge Functions. Set `VITE_SUPABASE_*` in Vercel project env.
190
+ **Local emulation:**
110
191
 
111
- **Deploy:** Frontend goes to Vercel (scaffolded vercel.json); Edge Functions to Supabase. It does **not** deploy your Supabase app’s frontend to Vercel/Netlify. For that, use the host’s dashboard or CLI (e.g. `vercel`, `netlify deploy`) after building. See [ENV_SETUP.md](./ENV_SETUP.md) for production env vars on Vercel.
192
+ ```bash
193
+ dndev emu start
194
+ ```
195
+
196
+ Or install the [Supabase CLI](https://supabase.com/docs/guides/cli) and run `supabase start` for a local Postgres + Auth + Storage stack. Point `VITE_SUPABASE_URL` and keys to the local instance.
112
197
 
113
198
  ---
114
199
 
115
- ## Local Development
200
+ ## Troubleshooting
116
201
 
117
- - **Against hosted Supabase:** After `supabase:setup`, run `bun dev` — the app talks to your Supabase project.
118
- - **Local Supabase:** Install the [Supabase CLI](https://supabase.com/docs/guides/cli) and run `supabase start` for a local Postgres + Auth + Storage stack. Point `VITE_SUPABASE_URL` and keys to the local instance.
202
+ **"Table not found" / "relation does not exist"**
203
+ Run `dndev setup supabase` (generates SQL) then apply migrations with `supabase db push`
119
204
 
120
- ---
205
+ **"Permission denied" / RLS errors**
206
+ → Check RLS policies in Supabase Dashboard → Database → Policies
207
+ → Generated migrations include default policies — verify they were applied
121
208
 
122
- ## Summary
209
+ **"Service role key" errors in functions**
210
+ → Put `SUPABASE_SERVICE_ROLE_KEY` in `functions/.env` (never in `VITE_*` vars)
211
+ → Get it from Supabase Dashboard → Settings → API
212
+
213
+ ---
123
214
 
124
- **`dndev supabase:setup`** → paste URL + anon key → **`dn generate sql`** → apply migrations → **`bun dev`**. The adapter normalizes read (snake→camel, ISO) and leaves timestamps to the DB on write.
215
+ **`dndev setup supabase` → paste URL + public key → apply migrations → `dndev dev`. The adapter normalizes everything automatically.**