create-vexcms 0.0.19 → 0.1.0-alpha.2

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 (154) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +93 -83
  3. package/dist/index.js +246 -81
  4. package/dist/index.mjs +30976 -0
  5. package/package.json +35 -15
  6. package/templates/base-nextjs/README.md +53 -205
  7. package/templates/base-nextjs/_env.example +7 -9
  8. package/templates/base-nextjs/_gitignore +41 -1
  9. package/templates/base-nextjs/convex/_generated/api.d.ts +6 -62
  10. package/templates/base-nextjs/convex/_generated/server.d.ts +19 -0
  11. package/templates/base-nextjs/convex/_generated/server.js +8 -0
  12. package/templates/base-nextjs/convex/auth/api.ts +49 -3
  13. package/templates/base-nextjs/convex/auth/db.ts +42 -300
  14. package/templates/base-nextjs/convex/auth/index.ts +11 -7
  15. package/templates/base-nextjs/convex/auth/options.ts +5 -29
  16. package/templates/base-nextjs/convex/auth/plugins/index.ts +15 -5
  17. package/templates/base-nextjs/convex/auth/sessions.ts +9 -15
  18. package/templates/base-nextjs/convex/http.ts +18 -3
  19. package/templates/base-nextjs/convex/schema.ts +104 -2
  20. package/templates/base-nextjs/convex/vex/firstUser.ts +10 -84
  21. package/templates/base-nextjs/convex/vex/globals.ts +19 -82
  22. package/templates/base-nextjs/convex/vex/media.ts +19 -246
  23. package/templates/base-nextjs/convex/vex.schema.ts +138 -0
  24. package/templates/base-nextjs/convex/vex.ts +19 -0
  25. package/templates/base-nextjs/convex.json +6 -0
  26. package/templates/base-nextjs/eslint.config.mjs +1 -21
  27. package/templates/base-nextjs/next.config.ts +10 -0
  28. package/templates/base-nextjs/package.json +47 -48
  29. package/templates/base-nextjs/src/app/(frontend)/@auth/(...)auth/[pathname]/view.tsx +17 -5
  30. package/templates/base-nextjs/src/app/(frontend)/auth/[pathname]/view.tsx +2 -4
  31. package/templates/base-nextjs/src/app/(frontend)/layout.tsx +12 -2
  32. package/templates/base-nextjs/src/app/(frontend)/page.tsx +2 -113
  33. package/templates/base-nextjs/src/app/(vexcms)/admin/[[...path]]/page.tsx +40 -0
  34. package/templates/base-nextjs/src/app/(vexcms)/admin/clientProviders.tsx +22 -0
  35. package/templates/base-nextjs/src/app/(vexcms)/admin/layout.tsx +19 -0
  36. package/templates/base-nextjs/src/app/globals.css +240 -104
  37. package/templates/base-nextjs/src/app/layout.tsx +23 -13
  38. package/templates/base-nextjs/src/app/unauthorized/page.tsx +24 -0
  39. package/templates/base-nextjs/src/auth/access.ts +46 -0
  40. package/templates/base-nextjs/src/auth/client.tsx +17 -5
  41. package/templates/base-nextjs/src/auth/hasPermission.ts +39 -0
  42. package/templates/base-nextjs/src/auth/serverUtils.ts +15 -22
  43. package/templates/base-nextjs/src/components/WelcomePage.tsx +116 -0
  44. package/templates/base-nextjs/src/components/component-example.tsx +56 -464
  45. package/templates/base-nextjs/src/components/providers/auth.tsx +13 -0
  46. package/templates/base-nextjs/src/components/providers/client.tsx +6 -1
  47. package/templates/base-nextjs/src/components/providers/convex.tsx +53 -21
  48. package/templates/base-nextjs/src/components/providers/server.tsx +10 -7
  49. package/templates/{marketing-site → base-nextjs}/src/components/ui/accordion.tsx +30 -32
  50. package/templates/base-nextjs/src/components/ui/badge.tsx +10 -13
  51. package/templates/base-nextjs/src/components/ui/input.tsx +35 -5
  52. package/templates/base-nextjs/src/context/AuthContext.tsx +29 -0
  53. package/templates/base-nextjs/src/db/constants/auth.ts +0 -1
  54. package/templates/base-nextjs/src/db/constants/index.ts +22 -35
  55. package/templates/base-nextjs/src/lib/utils.ts +0 -12
  56. package/templates/base-nextjs/src/proxy.ts +98 -11
  57. package/templates/base-nextjs/src/vex.config.ts +35 -0
  58. package/templates/base-nextjs/src/vex.types.ts +293 -0
  59. package/templates/base-nextjs/src/vexcms/collections/images.ts +15 -0
  60. package/templates/base-nextjs/src/vexcms/collections/index.ts +2 -1
  61. package/templates/base-nextjs/src/vexcms/collections/users.ts +7 -35
  62. package/templates/base-nextjs/tsconfig.json +3 -0
  63. package/templates/marketing-site/convex/_generated/api.d.ts +81 -0
  64. package/templates/marketing-site/convex/_generated/api.js +23 -0
  65. package/templates/marketing-site/convex/_generated/dataModel.d.ts +60 -0
  66. package/templates/marketing-site/convex/_generated/server.d.ts +162 -0
  67. package/templates/marketing-site/convex/_generated/server.js +101 -0
  68. package/templates/marketing-site/convex/footers.ts +11 -7
  69. package/templates/marketing-site/convex/headers.ts +15 -5
  70. package/templates/marketing-site/convex/pages.ts +20 -35
  71. package/templates/marketing-site/convex/schema.ts +119 -0
  72. package/templates/marketing-site/convex/seed.ts +582 -35
  73. package/templates/marketing-site/convex/siteSettings.ts +19 -5
  74. package/templates/marketing-site/convex/theme.ts +55 -61
  75. package/templates/marketing-site/convex/vex.schema.ts +355 -0
  76. package/templates/marketing-site/src/app/(frontend)/PageContent.tsx +27 -160
  77. package/templates/marketing-site/src/app/(frontend)/[slug]/page.tsx +6 -9
  78. package/templates/marketing-site/src/app/(frontend)/layout.tsx +4 -2
  79. package/templates/marketing-site/src/app/(frontend)/page.tsx +2 -5
  80. package/templates/marketing-site/src/components/SiteFooter.tsx +6 -3
  81. package/templates/marketing-site/src/components/SiteHeader.tsx +6 -3
  82. package/templates/marketing-site/src/components/ThemeLive.tsx +59 -0
  83. package/templates/marketing-site/src/components/ThemeStyle.tsx +45 -89
  84. package/templates/marketing-site/src/components/motion-primitives/animated-group.tsx +2 -2
  85. package/templates/marketing-site/src/lib/metadata.ts +51 -72
  86. package/templates/marketing-site/src/vex.config.ts +35 -0
  87. package/templates/marketing-site/src/vex.types.ts +634 -0
  88. package/templates/marketing-site/src/vexcms/api.ts +23 -0
  89. package/templates/marketing-site/src/vexcms/blocks/CTA/config.ts +3 -3
  90. package/templates/marketing-site/src/vexcms/blocks/CTA/index.tsx +2 -2
  91. package/templates/marketing-site/src/vexcms/blocks/FAQ/config.ts +4 -4
  92. package/templates/marketing-site/src/vexcms/blocks/FAQ/index.tsx +2 -2
  93. package/templates/marketing-site/src/vexcms/blocks/Features/config.ts +4 -8
  94. package/templates/marketing-site/src/vexcms/blocks/Features/index.tsx +2 -2
  95. package/templates/marketing-site/src/vexcms/blocks/Footer/config.ts +7 -11
  96. package/templates/marketing-site/src/vexcms/blocks/Footer/index.tsx +1 -1
  97. package/templates/marketing-site/src/vexcms/blocks/Header/config.ts +9 -9
  98. package/templates/marketing-site/src/vexcms/blocks/Header/index.tsx +4 -5
  99. package/templates/marketing-site/src/vexcms/blocks/Hero/config.ts +3 -4
  100. package/templates/marketing-site/src/vexcms/blocks/Hero/index.tsx +10 -19
  101. package/templates/marketing-site/src/vexcms/blocks/HowItWorks/config.ts +4 -9
  102. package/templates/marketing-site/src/vexcms/blocks/HowItWorks/index.tsx +3 -6
  103. package/templates/marketing-site/src/vexcms/blocks/Roadmap/config.ts +28 -68
  104. package/templates/marketing-site/src/vexcms/blocks/Roadmap/index.tsx +13 -43
  105. package/templates/marketing-site/src/vexcms/blocks/config.ts +7 -22
  106. package/templates/marketing-site/src/vexcms/blocks/constants.ts +2 -3
  107. package/templates/marketing-site/src/vexcms/blocks/index.ts +9 -8
  108. package/templates/marketing-site/src/vexcms/collections/footers.ts +1 -1
  109. package/templates/marketing-site/src/vexcms/collections/headers.ts +1 -1
  110. package/templates/marketing-site/src/vexcms/collections/index.ts +2 -1
  111. package/templates/marketing-site/src/vexcms/collections/pages.ts +12 -21
  112. package/templates/marketing-site/src/vexcms/collections/themeColors.ts +118 -0
  113. package/templates/marketing-site/src/vexcms/collections/themes.ts +29 -111
  114. package/templates/marketing-site/src/vexcms/globals/index.ts +1 -1
  115. package/templates/marketing-site/src/vexcms/globals/siteSettings.ts +43 -27
  116. package/templates/base-nextjs/convex/auth/adapter/index.ts +0 -230
  117. package/templates/base-nextjs/convex/auth/adapter/utils.ts +0 -547
  118. package/templates/base-nextjs/convex/auth/config.ts +0 -10
  119. package/templates/base-nextjs/convex/vex/auth.ts +0 -38
  120. package/templates/base-nextjs/convex/vex/collections.ts +0 -321
  121. package/templates/base-nextjs/convex/vex/helpers.ts +0 -33
  122. package/templates/base-nextjs/convex/vex/impersonation.ts +0 -51
  123. package/templates/base-nextjs/convex/vex/migrate.ts +0 -74
  124. package/templates/base-nextjs/convex/vex/model/collections.ts +0 -196
  125. package/templates/base-nextjs/convex/vex/model/media.ts +0 -87
  126. package/templates/base-nextjs/convex/vex/model/versions.ts +0 -254
  127. package/templates/base-nextjs/convex/vex/previewSnapshot.ts +0 -53
  128. package/templates/base-nextjs/convex/vex/versions.ts +0 -648
  129. package/templates/base-nextjs/src/app/admin/AdminLayoutWrapper.tsx +0 -33
  130. package/templates/base-nextjs/src/app/admin/AdminPageWrapper.tsx +0 -38
  131. package/templates/base-nextjs/src/app/admin/RichTextFieldWithMedia.tsx +0 -101
  132. package/templates/base-nextjs/src/app/admin/[[...path]]/page.tsx +0 -15
  133. package/templates/base-nextjs/src/app/admin/layout.tsx +0 -51
  134. package/templates/base-nextjs/src/app/favicon.ico +0 -0
  135. package/templates/base-nextjs/src/components/providers/theme.tsx +0 -11
  136. package/templates/base-nextjs/src/components/ui/theme-toggle.tsx +0 -67
  137. package/templates/base-nextjs/src/db/types.ts +0 -6
  138. package/templates/base-nextjs/src/vexcms/access.ts +0 -44
  139. package/templates/base-nextjs/src/vexcms/auth.ts +0 -4
  140. package/templates/base-nextjs/src/vexcms/collections/media.ts +0 -15
  141. package/templates/base-nextjs/vex.config.ts +0 -25
  142. package/templates/marketing-site/public/favicons/favicon.ico +0 -0
  143. package/templates/marketing-site/src/app/(frontend)/preview/[slug]/PreviewPageContent.tsx +0 -55
  144. package/templates/marketing-site/src/app/(frontend)/preview/[slug]/page.tsx +0 -27
  145. package/templates/marketing-site/src/app/(frontend)/preview/layout.tsx +0 -18
  146. package/templates/marketing-site/src/app/admin/AdminLayoutWrapper.tsx +0 -71
  147. package/templates/marketing-site/src/components/ThemeInjector.tsx +0 -128
  148. package/templates/marketing-site/src/components/admin/IconPickerField.tsx +0 -134
  149. package/templates/marketing-site/src/components/admin/ThemeImport.tsx +0 -174
  150. package/templates/marketing-site/src/components/admin/ThemeImportField.tsx +0 -33
  151. package/templates/marketing-site/src/db/constants/index.ts +0 -52
  152. package/templates/marketing-site/src/lib/colorConvert.ts +0 -171
  153. package/templates/marketing-site/src/vexcms/access.ts +0 -36
  154. package/templates/marketing-site/vex.config.ts +0 -32
package/package.json CHANGED
@@ -1,6 +1,24 @@
1
1
  {
2
2
  "name": "create-vexcms",
3
- "version": "0.0.19",
3
+ "version": "0.1.0-alpha.2",
4
+ "description": "Scaffold a new VexCMS project",
5
+ "keywords": [
6
+ "cms",
7
+ "headless-cms",
8
+ "convex",
9
+ "typescript",
10
+ "create",
11
+ "scaffold"
12
+ ],
13
+ "license": "Apache-2.0",
14
+ "author": "Isaiah Anyimi",
15
+ "homepage": "https://docs.vexcms.dev",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/ianyimi/vex.git",
19
+ "directory": "packages/create-vexcms"
20
+ },
21
+ "sideEffects": false,
4
22
  "type": "module",
5
23
  "bin": {
6
24
  "create-vexcms": "./dist/index.js"
@@ -10,24 +28,26 @@
10
28
  "templates"
11
29
  ],
12
30
  "publishConfig": {
13
- "access": "public"
31
+ "access": "public",
32
+ "tag": "alpha"
14
33
  },
15
34
  "dependencies": {
16
- "chalk": "^5.3.0",
17
- "commander": "^12.0.0",
18
- "execa": "^9.5.2",
19
- "fs-extra": "^11.2.0",
20
- "@inquirer/prompts": "^7.2.0",
21
- "ora": "^8.1.0",
22
- "sort-package-json": "^2.10.0",
23
- "validate-npm-package-name": "^5.0.0"
35
+ "chalk": "5.3.0",
36
+ "commander": "12.1.0",
37
+ "execa": "9.6.1",
38
+ "fs-extra": "11.3.6",
39
+ "@inquirer/prompts": "7.10.1",
40
+ "ora": "8.1.0",
41
+ "sort-package-json": "2.10.0",
42
+ "validate-npm-package-name": "5.0.0",
43
+ "yaml": "2.9.0"
24
44
  },
25
45
  "devDependencies": {
26
- "@types/fs-extra": "^11.0.4",
27
- "@types/validate-npm-package-name": "^4.0.2",
28
- "tsup": "^8.5.0",
29
- "typescript": "^5.9.3",
30
- "vitest": "^4.0.0"
46
+ "@types/fs-extra": "11.0.4",
47
+ "@types/validate-npm-package-name": "4.0.2",
48
+ "tsup": "8.5.1",
49
+ "typescript": "6.0.3",
50
+ "vitest": "4.1.10"
31
51
  },
32
52
  "scripts": {
33
53
  "build": "tsup src/index.ts --format esm --dts",
@@ -1,256 +1,104 @@
1
- # Next.js + Better Auth + Convex + shadcn/ui Template
1
+ # {{PROJECT_NAME}}
2
2
 
3
- A modern, production-ready SaaS template built with:
4
-
5
- - **[Next.js](https://nextjs.org)** - The React framework for production with App Router
6
- - **[Better Auth](https://www.better-auth.com/)** - Modern authentication with email/password and OAuth providers
7
- - **[Convex](https://convex.dev/)** - Real-time database and backend
8
- - **[shadcn/ui](https://ui.shadcn.com/)** - Beautifully designed components built on Radix UI
9
- - **[Tailwind CSS](https://tailwindcss.com/)** - Utility-first CSS framework
3
+ A VexCMS project built with Next.js, Better Auth, and Convex.
10
4
 
11
5
  ## Getting Started
12
6
 
13
- ### 1. Prerequisites
14
-
15
- - Node.js 18+ and npm/pnpm/yarn installed
16
- - A Convex account (free at [convex.dev](https://convex.dev))
17
-
18
- ### 2. Clone and Install
7
+ ### 1. Install dependencies
19
8
 
20
9
  ```bash
21
- # Clone this template
22
- git clone <your-repo-url>
23
- cd <your-project-name>
24
-
25
- # Install dependencies
26
- npm install
27
- # or
28
10
  pnpm install
29
- # or
30
- yarn install
31
11
  ```
32
12
 
33
- ### 3. Environment Setup
34
-
35
- Copy the example environment file:
36
-
37
- ```bash
38
- cp .env.example .env
39
- ```
40
-
41
- ### 4. Generate Better Auth Secret
42
-
43
- Generate a secure secret for Better Auth:
44
-
45
- ```bash
46
- npm run secret:create
47
- # or
48
- pnpm secret:create
49
- # or
50
- yarn secret:create
51
- ```
52
-
53
- This will generate a random 32-character hex string and copy it to your clipboard.
54
-
55
- ### 5. Configure Convex
56
-
57
- #### Set up Convex project
13
+ ### 2. Start Convex
58
14
 
59
15
  ```bash
60
16
  npx convex dev
61
17
  ```
62
18
 
63
- This will:
64
-
65
- - Create a new Convex project (or link to an existing one)
66
- - Generate your `CONVEX_URL` and `NEXT_PUBLIC_CONVEX_URL`
67
- - Start the Convex development server
68
-
69
- #### Add environment variables to Convex
70
-
71
- You need to add two critical environment variables to your Convex deployment via the [Convex Dashboard](https://dashboard.convex.dev):
19
+ On first run this creates (or links) a Convex project and prints your
20
+ deployment's URL and site URL.
72
21
 
73
- 1. **BETTER_AUTH_SECRET**: Paste the secret you generated in step 4
74
- 2. **SITE_URL**: Set to your application URL
75
- - Development: `http://localhost:3000` (or whatever port your dev server uses)
76
- - Production: Your production domain (e.g., `https://yourdomain.com`)
22
+ ### 3. Fill in your environment variables
77
23
 
78
- To add these in the Convex Dashboard:
79
-
80
- 1. Go to your project at [dashboard.convex.dev](https://dashboard.convex.dev)
81
- 2. Navigate to "Settings" → "Environment Variables"
82
- 3. Add both `BETTER_AUTH_SECRET` and `SITE_URL`
83
-
84
- ### 6. Update Your .env File
85
-
86
- Update your `.env` file with the values from Convex setup:
24
+ `.env.local` already has a generated `BETTER_AUTH_SECRET` and a
25
+ `http://localhost:3010` `SITE_URL`/`NEXT_PUBLIC_SITE_URL` pair, so the app
26
+ builds and typechecks immediately. Replace the placeholder Convex URLs with the
27
+ real ones `npx convex dev` printed:
87
28
 
88
29
  ```env
89
- NODE_ENV=development
90
-
91
- # From Convex setup
92
- CONVEX_URL=https://your-deployment.convex.cloud
93
30
  NEXT_PUBLIC_CONVEX_URL=https://your-deployment.convex.cloud
94
- CONVEX_SITE_URL=https://your-deployment.convex.site
95
31
  NEXT_PUBLIC_CONVEX_SITE_URL=https://your-deployment.convex.site
96
-
97
- # Better Auth (same secret you added to Convex Dashboard)
98
- BETTER_AUTH_SECRET=your-generated-secret-here
99
- NEXT_PUBLIC_SITE_URL=http://localhost:3000
100
32
  ```
101
33
 
102
- ### 7. Start Development
34
+ Then, in the [Convex Dashboard](https://dashboard.convex.dev) → Settings →
35
+ Environment Variables, add `BETTER_AUTH_SECRET` (same value as `.env.local`)
36
+ and `SITE_URL` (`http://localhost:3010` for local dev).
37
+
38
+ ### 4. Run the dev servers
103
39
 
104
40
  ```bash
105
- # Terminal 1: Run Convex dev server
106
- npx convex dev
41
+ # Terminal 1
42
+ pnpm vex:dev
107
43
 
108
- # Terminal 2: Run the application
109
- npm run dev
110
- # or
44
+ # Terminal 2
111
45
  pnpm dev
112
- # or
113
- yarn dev
114
46
  ```
115
47
 
116
- Visit `http://localhost:3000` to see your application running.
117
-
118
- ## Authentication Setup
48
+ ### 5. Create your admin account
119
49
 
120
- This project uses Better Auth for authentication.
50
+ Visit `http://localhost:3010`, click "Create Admin Account", and sign up. The
51
+ first user to sign up on a fresh project is automatically promoted to admin —
52
+ see `convex/vex/firstUser.ts`. From there, "Go to Admin Panel" opens `/admin`.
121
53
 
122
54
  <!-- {{OAUTH_SETUP_GUIDE}} -->
123
55
 
124
- ## Customizing Authentication
125
-
126
- ### Adding OAuth Providers
127
-
128
- To add or modify OAuth providers:
129
-
130
- 1. **Update Better Auth configuration** in `convex/auth/index.ts`:
131
-
132
- ```typescript
133
- export const createAuth = (ctx: GenericActionCtx<DataModel>) => {
134
- return betterAuth({
135
- socialProviders: {
136
- google: {
137
- clientId: process.env.GOOGLE_CLIENT_ID!,
138
- clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
139
- redirectURI: `${process.env.SITE_URL}/api/auth/callback/google`,
140
- },
141
- // Add more providers
142
- github: {
143
- clientId: process.env.GITHUB_CLIENT_ID!,
144
- clientSecret: process.env.GITHUB_CLIENT_SECRET!,
145
- },
146
- },
147
- // ... rest of config
148
- })
149
- }
150
- ```
151
-
152
- 2. **Add credentials to Convex Dashboard** as environment variables
153
-
154
- 3. **Consult the Better Auth documentation** for provider-specific configuration:
155
- - [Better Auth Providers](https://www.better-auth.com/docs/authentication/social-login)
156
-
157
- ### Customizing User Schema
158
-
159
- To add custom fields to your user model:
160
-
161
- 1. Update the `user.additionalFields` in `convex/auth/index.ts`
162
- 2. Update your Convex schema accordingly
163
- 3. See [Better Auth User Management](https://www.better-auth.com/docs/concepts/user-management) for details
164
-
165
- ### Email/Password Configuration
166
-
167
- The template has email/password authentication enabled by default. To customize:
168
-
169
- - [Better Auth Email/Password Docs](https://www.better-auth.com/docs/authentication/email-password)
170
- - [Email Verification Setup](https://www.better-auth.com/docs/authentication/email-verification)
171
-
172
56
  ## Project Structure
173
57
 
174
58
  ```
175
59
  .
176
60
  ├── src/
177
61
  │ ├── app/ # Next.js App Router
178
- │ │ ├── (frontend)/ # Frontend routes group
179
- │ │ ├── api/ # API routes
180
- │ │ └── layout.tsx # Root layout
181
- │ ├── auth/ # Authentication components
182
- │ ├── components/ # React components
183
- │ ├── lib/ # Utilities and helpers
184
- │ └── env.mjs # Typed environment variables
185
- ├── convex/ # Convex backend
186
- │ ├── auth/ # Better Auth integration
187
- │ ├── schema.ts # Database schema
188
- │ └── *.ts # Convex functions (queries, mutations, actions)
189
- ├── public/ # Static assets
190
- └── .env # Environment variables (not committed)
62
+ │ │ ├── (frontend)/ # Public site routes
63
+ │ │ ├── (vexcms)/admin/ # Admin panel routes
64
+ │ │ └── layout.tsx # Root layout
65
+ │ ├── auth/ # Auth client + server helpers, access control
66
+ │ ├── components/ # React components
67
+ │ ├── vexcms/collections/ # Collection definitions
68
+ │ ├── vex.config.ts # VexCMS config
69
+ │ └── env.mjs # Typed environment variables
70
+ ├── convex/ # Convex backend
71
+ │ ├── auth/ # Better Auth config + plugins
72
+ │ ├── vex/ # Bootstrap, media, globals endpoints
73
+ │ └── schema.ts # Database schema
74
+ └── .env.local # Environment variables (not committed)
191
75
  ```
192
76
 
193
- ## Development Scripts
77
+ ## Scripts
194
78
 
195
79
  ```bash
196
- npm run dev # Start development server
197
- npm run build # Build for production
198
- npm run start # Start production server
199
- npm run lint # Lint code
200
- npm run typecheck # Type check without emitting
201
- npm run format # Format code with Prettier
202
- npm run format:check # Check code formatting
203
- npm run secret:create # Generate a Better Auth secret
80
+ pnpm dev # Start the Next.js dev server
81
+ pnpm vex:dev # Start VexCMS's schema watcher + convex dev
82
+ pnpm vex:generate # Regenerate the Convex schema and types once
83
+ pnpm build # Build for production
84
+ pnpm typecheck # Type check without emitting
85
+ pnpm lint # Lint
86
+ pnpm format # Format with Prettier
87
+ pnpm secret:create # Generate a Better Auth secret
204
88
  ```
205
89
 
206
- ## Documentation Resources
207
-
208
- ### Core Technologies
90
+ ## Documentation
209
91
 
92
+ - **VexCMS**: [docs.vexcms.dev](https://docs.vexcms.dev)
210
93
  - **Next.js**: [nextjs.org/docs](https://nextjs.org/docs)
211
94
  - **Better Auth**: [better-auth.com/docs](https://www.better-auth.com/docs)
212
95
  - **Convex**: [docs.convex.dev](https://docs.convex.dev)
213
- - **shadcn/ui**: [ui.shadcn.com](https://ui.shadcn.com)
214
- - **Tailwind CSS**: [tailwindcss.com/docs](https://tailwindcss.com/docs)
215
-
216
- ### Integration Guides
217
-
218
- - **Better Auth + Convex**: [better-auth.com/docs/integrations/convex](https://www.better-auth.com/docs/integrations/convex)
219
- - **Better Auth + Next.js**: [better-auth.com/docs/integrations/nextjs](https://www.better-auth.com/docs/integrations/nextjs)
220
96
 
221
97
  ## Deployment
222
98
 
223
- ### Deploy to Production
224
-
225
- 1. **Deploy Convex Backend**:
226
-
227
- ```bash
228
- npx convex deploy
229
- ```
230
-
231
- 2. **Update Convex environment variables** in production:
232
- - Set `SITE_URL` to your production domain
233
- - Keep `BETTER_AUTH_SECRET` the same (or rotate it)
234
-
235
- 3. **Deploy your application** to your hosting provider (Vercel recommended):
236
-
237
- For Vercel:
238
-
239
- ```bash
240
- npm install -g vercel
241
- vercel
242
- ```
243
-
244
- Or connect your GitHub repository to Vercel for automatic deployments.
245
-
246
- 4. **Update environment variables** in your hosting provider with production values:
247
- - `NEXT_PUBLIC_CONVEX_URL`
248
- - `NEXT_PUBLIC_CONVEX_SITE_URL`
249
- - `NEXT_PUBLIC_SITE_URL`
250
- - `BETTER_AUTH_SECRET`
251
-
252
- See [Next.js Deployment](https://nextjs.org/docs/app/building-your-application/deploying) and [Convex Production Deployment](https://docs.convex.dev/production/hosting) for detailed deployment instructions.
253
-
254
- ## License
255
-
256
- MIT
99
+ 1. `npx convex deploy`
100
+ 2. In the Convex Dashboard, set `SITE_URL` to your production domain (keep
101
+ `BETTER_AUTH_SECRET` the same, or rotate it and update both places).
102
+ 3. Deploy the Next.js app (e.g. Vercel) with `NEXT_PUBLIC_CONVEX_URL`,
103
+ `NEXT_PUBLIC_CONVEX_SITE_URL`, `NEXT_PUBLIC_SITE_URL`, and
104
+ `BETTER_AUTH_SECRET` set to their production values.
@@ -1,18 +1,16 @@
1
- # Since the ".env" file is gitignored, you can use the ".env.example" file to
2
- # build a new ".env" file when you clone the repo. Keep this file up-to-date
3
- # when you add new variables to `.env`.
1
+ # Since the ".env.local" file is gitignored, use this file to build a new one
2
+ # when you clone the repo. Keep it up to date when you add new variables to
3
+ # `.env.local`.
4
4
 
5
- # This file will be committed to version control, so make sure not to have any
6
- # secrets in it. If you are cloning this repo, create a copy of this file named
7
- # ".env" and populate it with your secrets.
5
+ # This file is committed to version control — never put secrets in it.
8
6
 
9
- # When adding additional environment variables, the schema in "/src/env.js"
10
- # should be updated accordingly.
7
+ # When adding new environment variables, update the schema in "src/env.mjs".
11
8
 
12
9
  NEXT_PUBLIC_CONVEX_URL=""
13
10
  NEXT_PUBLIC_CONVEX_SITE_URL=""
14
11
 
15
- NEXT_PUBLIC_SITE_URL="http://localhost:3000"
12
+ NEXT_PUBLIC_SITE_URL="http://localhost:3010"
13
+ SITE_URL="http://localhost:3010"
16
14
  BETTER_AUTH_SECRET=""
17
15
 
18
16
  # {{ENV_OAUTH_VARS}}
@@ -1,2 +1,42 @@
1
+ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
1
2
 
2
- .env.local
3
+ # dependencies
4
+ /node_modules
5
+ /.pnp
6
+ .pnp.*
7
+ .yarn/*
8
+ !.yarn/patches
9
+ !.yarn/plugins
10
+ !.yarn/releases
11
+ !.yarn/versions
12
+
13
+ # testing
14
+ /coverage
15
+
16
+ # next.js
17
+ /.next/
18
+ /out/
19
+
20
+ # production
21
+ /build
22
+
23
+ # misc
24
+ .DS_Store
25
+ *.pem
26
+
27
+ # debug
28
+ npm-debug.log*
29
+ yarn-debug.log*
30
+ yarn-error.log*
31
+ .pnpm-debug.log*
32
+
33
+ # env files
34
+ .env
35
+ .env.*
36
+
37
+ # vercel
38
+ .vercel
39
+
40
+ # typescript
41
+ *.tsbuildinfo
42
+ next-env.d.ts
@@ -8,45 +8,17 @@
8
8
  * @module
9
9
  */
10
10
 
11
- import type * as auth_adapter_index from "../auth/adapter/index.js";
12
- import type * as auth_adapter_utils from "../auth/adapter/utils.js";
13
11
  import type * as auth_api from "../auth/api.js";
14
- import type * as auth_config from "../auth/config.js";
15
12
  import type * as auth_db from "../auth/db.js";
16
13
  import type * as auth_index from "../auth/index.js";
17
14
  import type * as auth_options from "../auth/options.js";
18
15
  import type * as auth_plugins_index from "../auth/plugins/index.js";
19
16
  import type * as auth_sessions from "../auth/sessions.js";
20
17
  import type * as http from "../http.js";
21
- import type * as vex_api_articles from "../vex/api/articles.js";
22
- import type * as vex_api_categories from "../vex/api/categories.js";
23
- import type * as vex_api_footers from "../vex/api/footers.js";
24
- import type * as vex_api_headers from "../vex/api/headers.js";
25
- import type * as vex_api_index from "../vex/api/index.js";
26
- import type * as vex_api_media from "../vex/api/media.js";
27
- import type * as vex_api_pages from "../vex/api/pages.js";
28
- import type * as vex_api_posts from "../vex/api/posts.js";
29
- import type * as vex_api_themes from "../vex/api/themes.js";
30
- import type * as vex_api_user from "../vex/api/user.js";
31
- import type * as vex_auth from "../vex/auth.js";
32
- import type * as vex_collections from "../vex/collections.js";
33
- import type * as vex_impersonation from "../vex/impersonation.js";
18
+ import type * as vex from "../vex.js";
19
+ import type * as vex_firstUser from "../vex/firstUser.js";
20
+ import type * as vex_globals from "../vex/globals.js";
34
21
  import type * as vex_media from "../vex/media.js";
35
- import type * as vex_migrate from "../vex/migrate.js";
36
- import type * as vex_model_api_articles from "../vex/model/api/articles.js";
37
- import type * as vex_model_api_categories from "../vex/model/api/categories.js";
38
- import type * as vex_model_api_footers from "../vex/model/api/footers.js";
39
- import type * as vex_model_api_headers from "../vex/model/api/headers.js";
40
- import type * as vex_model_api_media from "../vex/model/api/media.js";
41
- import type * as vex_model_api_pages from "../vex/model/api/pages.js";
42
- import type * as vex_model_api_posts from "../vex/model/api/posts.js";
43
- import type * as vex_model_api_themes from "../vex/model/api/themes.js";
44
- import type * as vex_model_api_user from "../vex/model/api/user.js";
45
- import type * as vex_model_collections from "../vex/model/collections.js";
46
- import type * as vex_model_media from "../vex/model/media.js";
47
- import type * as vex_model_versions from "../vex/model/versions.js";
48
- import type * as vex_previewSnapshot from "../vex/previewSnapshot.js";
49
- import type * as vex_versions from "../vex/versions.js";
50
22
 
51
23
  import type {
52
24
  ApiFromModules,
@@ -55,45 +27,17 @@ import type {
55
27
  } from "convex/server";
56
28
 
57
29
  declare const fullApi: ApiFromModules<{
58
- "auth/adapter/index": typeof auth_adapter_index;
59
- "auth/adapter/utils": typeof auth_adapter_utils;
60
30
  "auth/api": typeof auth_api;
61
- "auth/config": typeof auth_config;
62
31
  "auth/db": typeof auth_db;
63
32
  "auth/index": typeof auth_index;
64
33
  "auth/options": typeof auth_options;
65
34
  "auth/plugins/index": typeof auth_plugins_index;
66
35
  "auth/sessions": typeof auth_sessions;
67
36
  http: typeof http;
68
- "vex/api/articles": typeof vex_api_articles;
69
- "vex/api/categories": typeof vex_api_categories;
70
- "vex/api/footers": typeof vex_api_footers;
71
- "vex/api/headers": typeof vex_api_headers;
72
- "vex/api/index": typeof vex_api_index;
73
- "vex/api/media": typeof vex_api_media;
74
- "vex/api/pages": typeof vex_api_pages;
75
- "vex/api/posts": typeof vex_api_posts;
76
- "vex/api/themes": typeof vex_api_themes;
77
- "vex/api/user": typeof vex_api_user;
78
- "vex/auth": typeof vex_auth;
79
- "vex/collections": typeof vex_collections;
80
- "vex/impersonation": typeof vex_impersonation;
37
+ vex: typeof vex;
38
+ "vex/firstUser": typeof vex_firstUser;
39
+ "vex/globals": typeof vex_globals;
81
40
  "vex/media": typeof vex_media;
82
- "vex/migrate": typeof vex_migrate;
83
- "vex/model/api/articles": typeof vex_model_api_articles;
84
- "vex/model/api/categories": typeof vex_model_api_categories;
85
- "vex/model/api/footers": typeof vex_model_api_footers;
86
- "vex/model/api/headers": typeof vex_model_api_headers;
87
- "vex/model/api/media": typeof vex_model_api_media;
88
- "vex/model/api/pages": typeof vex_model_api_pages;
89
- "vex/model/api/posts": typeof vex_model_api_posts;
90
- "vex/model/api/themes": typeof vex_model_api_themes;
91
- "vex/model/api/user": typeof vex_model_api_user;
92
- "vex/model/collections": typeof vex_model_collections;
93
- "vex/model/media": typeof vex_model_media;
94
- "vex/model/versions": typeof vex_model_versions;
95
- "vex/previewSnapshot": typeof vex_previewSnapshot;
96
- "vex/versions": typeof vex_versions;
97
41
  }>;
98
42
 
99
43
  /**
@@ -21,6 +21,17 @@ import {
21
21
  } from "convex/server";
22
22
  import type { DataModel } from "./dataModel.js";
23
23
 
24
+ /**
25
+ * Typesafe environment variables.
26
+ *
27
+ * This includes platform-provided env vars and any variables declared in
28
+ * `convex.config.ts`.
29
+ */
30
+ type Env = {
31
+ readonly CONVEX_CLOUD_URL: string;
32
+ readonly CONVEX_SITE_URL: string;
33
+ };
34
+
24
35
  /**
25
36
  * Define a query in this Convex app's public API.
26
37
  *
@@ -95,6 +106,14 @@ export declare const internalAction: ActionBuilder<DataModel, "internal">;
95
106
  */
96
107
  export declare const httpAction: HttpActionBuilder;
97
108
 
109
+ /**
110
+ * Typesafe environment variables.
111
+ *
112
+ * This includes platform-provided env vars and any variables declared in
113
+ * `convex.config.ts`.
114
+ */
115
+ export declare const env: Env;
116
+
98
117
  /**
99
118
  * A set of services for use within Convex query functions.
100
119
  *
@@ -91,3 +91,11 @@ export const internalAction = internalActionGeneric;
91
91
  * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up.
92
92
  */
93
93
  export const httpAction = httpActionGeneric;
94
+
95
+ /**
96
+ * Typesafe environment variables.
97
+ *
98
+ * This includes platform-provided env vars and any variables declared in
99
+ * `convex.config.ts`.
100
+ */
101
+ export const env = process.env;
@@ -1,8 +1,54 @@
1
- import { query } from "../_generated/server"
1
+ import { get } from "@vexcms/core/server";
2
+ import { v } from "convex/values";
3
+
4
+ import {
5
+ type OrganizationID,
6
+ type SessionID,
7
+ TABLE_SLUG_ORGANIZATIONS,
8
+ TABLE_SLUG_SESSIONS,
9
+ TABLE_SLUG_USERS,
10
+ type UserID,
11
+ } from "~/db/constants";
12
+
13
+ import { query } from "../_generated/server";
2
14
 
3
15
  export const identifyCurrentUser = query({
4
16
  args: {},
5
17
  handler: async (ctx) => {
6
- return ctx.auth.getUserIdentity()
18
+ return ctx.auth.getUserIdentity();
19
+ },
20
+ });
21
+
22
+ export const getUserOrg = query({
23
+ args: {
24
+ noOrgs: v.optional(v.boolean()),
25
+ },
26
+ handler: async (ctx, args) => {
27
+ const empty = { user: null, organization: undefined };
28
+ const identity = await ctx.auth.getUserIdentity();
29
+ if (!identity) {
30
+ return empty;
31
+ }
32
+ const session = await get({
33
+ ctx,
34
+ id: identity.sessionId as SessionID,
35
+ collection: TABLE_SLUG_SESSIONS,
36
+ });
37
+ if (!session) {
38
+ return empty;
39
+ }
40
+ const user = await get({ ctx, id: identity.subject as UserID, collection: TABLE_SLUG_USERS });
41
+ if (!user) {
42
+ return empty;
43
+ }
44
+ if (!session.activeOrganizationId || args.noOrgs) {
45
+ return { user, organization: undefined };
46
+ }
47
+ const organization = await get({
48
+ ctx,
49
+ id: session.activeOrganizationId as OrganizationID,
50
+ collection: TABLE_SLUG_ORGANIZATIONS,
51
+ });
52
+ return { user, organization: organization ?? undefined };
7
53
  },
8
- })
54
+ });