create-authhero 0.15.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,9 +18,10 @@ The CLI will guide you through:
18
18
 
19
19
  1. **Project name** - Name of your project directory
20
20
  2. **Setup type** - Choose between Local, Cloudflare Simple, or Cloudflare Multi-Tenant
21
- 3. **Admin credentials** - Email and password for the initial admin user
22
- 4. **Install dependencies** - Optionally install packages with your preferred package manager
23
- 5. **Start server** - Optionally run migrations, seed the database, and start the dev server
21
+ 3. **GitHub CI** - (Cloudflare only) Optionally include GitHub Actions workflows with semantic versioning
22
+ 4. **Admin credentials** - Email and password for the initial admin user
23
+ 5. **Install dependencies** - Optionally install packages with your preferred package manager
24
+ 6. **Start server** - Optionally run migrations, seed the database, and start the dev server
24
25
 
25
26
  ## Setup Types
26
27
 
@@ -68,27 +69,38 @@ npm run dev
68
69
  ```
69
70
  my-auth-project/
70
71
  ├── src/
71
- │ ├── index.ts # Worker entry point
72
- │ ├── app.ts # AuthHero configuration
73
- │ └── types.ts # TypeScript types
74
- ├── wrangler.toml # Cloudflare configuration
75
- ├── seed.sql # Database seeding (generated)
72
+ │ ├── index.ts # Worker entry point
73
+ │ ├── app.ts # AuthHero configuration
74
+ │ └── types.ts # TypeScript types
75
+ ├── wrangler.toml # Base Cloudflare config (safe for git)
76
+ ├── wrangler.local.toml # Your private IDs (gitignored)
77
+ ├── .dev.vars # Local secrets (gitignored)
78
+ ├── .dev.vars.example # Template for .dev.vars
79
+ ├── seed.sql # Database seeding (generated)
76
80
  ├── package.json
77
81
  └── tsconfig.json
78
82
  ```
79
83
 
80
- **Quick Start:**
84
+ **Quick Start (Local Development):**
81
85
 
82
86
  ```sh
83
87
  cd my-auth-project
84
88
  npm install
85
- wrangler d1 create authhero-db
86
- # Update wrangler.toml with database_id
87
- npm run db:migrate
88
- npm run seed
89
+ npm run migrate
90
+ ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed
89
91
  npm run dev
90
92
  ```
91
93
 
94
+ **Remote Development (Your Cloudflare Account):**
95
+
96
+ ```sh
97
+ # Create a D1 database
98
+ npx wrangler d1 create authhero-db
99
+ # Copy the database_id to wrangler.local.toml
100
+ npm run db:migrate:remote
101
+ npm run dev:remote
102
+ ```
103
+
92
104
  ### 3. Cloudflare Multi-Tenant (Production)
93
105
 
94
106
  **Best for:** SaaS platforms, agencies, enterprise deployments
@@ -103,13 +115,15 @@ npm run dev
103
115
  ```
104
116
  my-auth-project/
105
117
  ├── src/
106
- │ ├── index.ts # Worker entry point
107
- │ ├── app.ts # AuthHero configuration
108
- │ ├── types.ts # TypeScript types
118
+ │ ├── index.ts # Worker entry point
119
+ │ ├── app.ts # AuthHero configuration
120
+ │ ├── types.ts # TypeScript types
109
121
  │ └── database-factory.ts # Multi-tenant DB factory
110
- ├── wrangler.toml # Cloudflare configuration
111
- ├── .dev.vars.example # Environment variables template
112
- ├── seed.sql # Database seeding (generated)
122
+ ├── wrangler.toml # Base Cloudflare config (safe for git)
123
+ ├── wrangler.local.toml # Your private IDs (gitignored)
124
+ ├── .dev.vars # Local secrets (gitignored)
125
+ ├── .dev.vars.example # Environment variables template
126
+ ├── seed.sql # Database seeding (generated)
113
127
  ├── package.json
114
128
  └── tsconfig.json
115
129
  ```
@@ -138,20 +152,51 @@ my-auth-project/
138
152
  └─────────────┘ └─────────────┘ └─────────────┘
139
153
  ```
140
154
 
141
- **Quick Start:**
155
+ **Quick Start (Local Development):**
142
156
 
143
157
  ```sh
144
158
  cd my-auth-project
145
159
  npm install
146
- wrangler d1 create authhero-main-db
147
- # Update wrangler.toml with database_id
148
- cp .dev.vars.example .dev.vars
149
- # Add your Cloudflare credentials to .dev.vars
150
- npm run db:migrate
151
- npm run seed
160
+ npm run migrate
161
+ ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed
152
162
  npm run dev
153
163
  ```
154
164
 
165
+ **Remote Development (Your Cloudflare Account):**
166
+
167
+ ```sh
168
+ # Create a D1 database
169
+ npx wrangler d1 create authhero-db
170
+ # Copy the database_id to wrangler.local.toml
171
+ # Optionally add CLOUDFLARE_ACCOUNT_ID to .dev.vars
172
+ npm run db:migrate:remote
173
+ npm run dev:remote
174
+ ```
175
+
176
+ ## Security & Privacy
177
+
178
+ Cloudflare projects are designed to be **open-source friendly**:
179
+
180
+ | File | Purpose | In Git? |
181
+ | --------------------- | ---------------------------------- | ------- |
182
+ | `wrangler.toml` | Base config (safe for public repo) | ✅ Yes |
183
+ | `wrangler.local.toml` | Your private IDs (database_id) | ❌ No |
184
+ | `.dev.vars` | Local secrets (API tokens, etc.) | ❌ No |
185
+ | `.dev.vars.example` | Template for .dev.vars | ✅ Yes |
186
+
187
+ The CLI automatically creates `wrangler.local.toml` and `.dev.vars` from the templates when you create a project. Simply update them with your Cloudflare IDs.
188
+
189
+ ### GitHub Actions / CI Deployment
190
+
191
+ For automated deployments, set these GitHub Secrets:
192
+
193
+ | Secret | Description |
194
+ | ----------------------- | -------------------------------------------------------- |
195
+ | `CLOUDFLARE_API_TOKEN` | API token with Workers permissions |
196
+ | `CLOUDFLARE_ACCOUNT_ID` | Your Cloudflare account ID (optional, for some features) |
197
+
198
+ The wrangler GitHub Action will automatically use these secrets. No need to store IDs in your repo!
199
+
155
200
  ## Example
156
201
 
157
202
  ```sh
@@ -175,6 +220,40 @@ You'll be prompted to:
175
220
  | Complexity | Low | Medium | High |
176
221
  | Best For | Development | Simple Production | Enterprise/SaaS |
177
222
 
223
+ ## GitHub CI with Semantic Versioning
224
+
225
+ For Cloudflare setups, you can optionally include GitHub Actions workflows that provide:
226
+
227
+ - **Unit Tests**: Runs on all pushes to any branch
228
+ - **Deploy to Dev**: Automatically deploys to dev environment on push to `main`, with semantic-release for version management
229
+ - **Deploy to Production**: Deploys to production when a GitHub release is published
230
+
231
+ ### CI/CD Flow
232
+
233
+ ```
234
+ All PRs/Pushes → Unit Tests (type-check + tests)
235
+ Push to main → Semantic Release + Deploy to Dev
236
+ GitHub Release → Deploy to Production
237
+ ```
238
+
239
+ ### Required GitHub Secrets
240
+
241
+ | Secret | Description |
242
+ | --------------------------- | ---------------------------------------- |
243
+ | `CLOUDFLARE_API_TOKEN` | API token for dev deployments |
244
+ | `CLOUDFLARE_ACCOUNT_ID` | Account ID (optional, for some features) |
245
+ | `PROD_CLOUDFLARE_API_TOKEN` | API token for production deployments |
246
+
247
+ > **Note:** You do NOT need to store `database_id` or `zone_id` in your repo or secrets. Wrangler resolves these automatically when deploying with the correct API token.
248
+
249
+ ### Commit Message Conventions
250
+
251
+ Use conventional commits for automatic versioning:
252
+
253
+ - `fix:` → Patch release (1.0.0 → 1.0.1)
254
+ - `feat:` → Minor release (1.0.0 → 1.1.0)
255
+ - `BREAKING CHANGE:` → Major release (1.0.0 → 2.0.0)
256
+
178
257
  ## Documentation
179
258
 
180
259
  For more information, visit [https://authhero.net/docs](https://authhero.net/docs)
@@ -28,15 +28,34 @@ A production-grade multi-tenant AuthHero authentication server using Cloudflare
28
28
  └─────────────┘
29
29
  ```
30
30
 
31
+ ## Security & Privacy
32
+
33
+ This project is designed to be **open-source friendly**. Sensitive Cloudflare IDs are kept out of version control:
34
+
35
+ | File | Purpose | In Git? |
36
+ | --------------------- | ---------------------------------- | ------- |
37
+ | `wrangler.toml` | Base config (safe for public repo) | ✅ Yes |
38
+ | `wrangler.local.toml` | Your private IDs (database_id) | ❌ No |
39
+ | `.dev.vars` | Local secrets (API tokens, etc.) | ❌ No |
40
+ | `.dev.vars.example` | Template for .dev.vars | ✅ Yes |
41
+
42
+ **For GitHub Actions / CI:**
43
+
44
+ - Set `CLOUDFLARE_API_TOKEN` as a GitHub Secret
45
+ - Set `CLOUDFLARE_ACCOUNT_ID` as a GitHub Secret (if needed)
46
+ - The wrangler action will use these automatically
47
+
31
48
  ## Getting Started
32
49
 
50
+ ### Local Development (Quick Start)
51
+
33
52
  1. Install dependencies:
34
53
 
35
54
  ```bash
36
55
  npm install
37
56
  ```
38
57
 
39
- 2. Run local database migrations:
58
+ 2. Run database migrations (uses local SQLite-backed D1):
40
59
 
41
60
  ```bash
42
61
  npm run migrate
@@ -55,29 +74,46 @@ A production-grade multi-tenant AuthHero authentication server using Cloudflare
55
74
 
56
75
  The server will be available at `https://localhost:3000`.
57
76
 
58
- ## Production Deployment
77
+ ### Remote Development (Your Cloudflare Account)
59
78
 
60
79
  1. Create a D1 database:
61
80
 
62
81
  ```bash
63
- wrangler d1 create authhero-db
82
+ npx wrangler d1 create authhero-db
64
83
  ```
65
84
 
66
- 2. Update `wrangler.toml` with your database ID.
85
+ 2. Copy the `database_id` from the output and update `wrangler.local.toml`:
86
+
87
+ ```toml
88
+ [[d1_databases]]
89
+ binding = "AUTH_DB"
90
+ database_name = "authhero-db"
91
+ database_id = "paste-your-database-id-here"
92
+ migrations_dir = "node_modules/@authhero/drizzle/drizzle"
93
+ ```
67
94
 
68
- 3. Run migrations on production:
95
+ 3. Run remote migrations:
69
96
 
70
97
  ```bash
71
98
  npm run db:migrate:remote
72
99
  ```
73
100
 
74
- 4. Seed the production database:
101
+ 4. Seed the remote database:
75
102
 
76
103
  ```bash
77
104
  ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed:remote
78
105
  ```
79
106
 
80
- 5. Deploy:
107
+ 5. Start with remote D1:
108
+ ```bash
109
+ npm run dev:remote
110
+ ```
111
+
112
+ ## Production Deployment
113
+
114
+ 1. Ensure `wrangler.local.toml` has your production `database_id`.
115
+
116
+ 2. Deploy:
81
117
  ```bash
82
118
  npm run deploy
83
119
  ```
@@ -154,6 +190,83 @@ curl https://your-worker.workers.dev/management/tenants \
154
190
 
155
191
  For more information, visit [https://authhero.net/docs](https://authhero.net/docs).
156
192
 
193
+ ## CI/CD with GitHub Actions
194
+
195
+ If you selected GitHub CI during setup, your project includes automated workflows for continuous integration and deployment.
196
+
197
+ ### Workflow Overview
198
+
199
+ ```
200
+ ┌─────────────────────────────────────────────────────────────────────────┐
201
+ │ GitHub Actions │
202
+ ├─────────────────────────────────────────────────────────────────────────┤
203
+ │ │
204
+ │ ┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
205
+ │ │ Any Push │ │ Push to main │ │ GitHub Release │ │
206
+ │ │ │ │ │ │ (released) │ │
207
+ │ └──────┬───────┘ └────────┬─────────┘ └────────┬─────────┘ │
208
+ │ │ │ │ │
209
+ │ ▼ ▼ ▼ │
210
+ │ ┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
211
+ │ │ Unit Tests │ │ Semantic Release │ │ Deploy to │ │
212
+ │ │ Type Check │ │ + Deploy Dev │ │ Production │ │
213
+ │ └──────────────┘ └──────────────────┘ └──────────────────┘ │
214
+ │ │
215
+ └─────────────────────────────────────────────────────────────────────────┘
216
+ ```
217
+
218
+ ### Workflows
219
+
220
+ 1. **Unit Tests** (`.github/workflows/unit-tests.yml`)
221
+ - **Trigger**: All pushes to any branch
222
+ - **Actions**: Runs type checking and tests
223
+
224
+ 2. **Deploy to Dev** (`.github/workflows/deploy-dev.yml`)
225
+ - **Trigger**: Push to `main` branch
226
+ - **Actions**:
227
+ - Runs semantic-release to create version tags
228
+ - Deploys to Cloudflare Workers (dev environment)
229
+
230
+ 3. **Deploy to Production** (`.github/workflows/release.yml`)
231
+ - **Trigger**: GitHub Release (when "released")
232
+ - **Actions**: Deploys to Cloudflare Workers (production environment)
233
+
234
+ ### Required Secrets
235
+
236
+ Configure these secrets in your GitHub repository settings:
237
+
238
+ | Secret | Description |
239
+ | --------------------------- | ----------------------------------------------- |
240
+ | `CLOUDFLARE_API_TOKEN` | Cloudflare API token for dev deployments |
241
+ | `PROD_CLOUDFLARE_API_TOKEN` | Cloudflare API token for production deployments |
242
+
243
+ ### Semantic Versioning
244
+
245
+ Commits to `main` are analyzed to determine version bumps:
246
+
247
+ - `fix:` - Patch release (1.0.0 → 1.0.1)
248
+ - `feat:` - Minor release (1.0.0 → 1.1.0)
249
+ - `BREAKING CHANGE:` - Major release (1.0.0 → 2.0.0)
250
+
251
+ ### Production Deployment
252
+
253
+ To deploy to production:
254
+
255
+ 1. Go to GitHub → Releases → "Draft a new release"
256
+ 2. Create a new tag (e.g., `v1.0.0`)
257
+ 3. Click "Publish release"
258
+ 4. The `release.yml` workflow will deploy to production
259
+
260
+ ### Wrangler Configuration
261
+
262
+ For production deployments, add an environment to `wrangler.toml`:
263
+
264
+ ```toml
265
+ [env.production]
266
+ name = "your-worker-production"
267
+ # Add production-specific settings here
268
+ ```
269
+
157
270
  ## Optional Features
158
271
 
159
272
  ### Analytics Engine (Centralized Logging)
@@ -7,19 +7,21 @@ import {
7
7
  DataAdapters,
8
8
  } from "@authhero/multi-tenancy";
9
9
 
10
- // Main tenant ID - the tenant that manages all other tenants
11
- const MAIN_TENANT_ID = "main";
10
+ // Control plane tenant ID - the tenant that manages all other tenants
11
+ const CONTROL_PLANE_TENANT_ID = "control_plane";
12
12
 
13
13
  export default function createApp(
14
- config: Omit<MultiTenantAuthHeroConfig, "mainTenantId"> & {
14
+ config: Omit<MultiTenantAuthHeroConfig, "controlPlaneTenantId"> & {
15
15
  dataAdapter: DataAdapters;
16
16
  },
17
17
  ) {
18
18
  const { app } = init({
19
19
  ...config,
20
- mainTenantId: MAIN_TENANT_ID,
21
- // Sync resource servers from main tenant to all child tenants
20
+ controlPlaneTenantId: CONTROL_PLANE_TENANT_ID,
21
+ // Sync resource servers from control plane tenant to all child tenants
22
22
  syncResourceServers: true,
23
+ // Sync roles from control plane tenant to all child tenants
24
+ syncRoles: true,
23
25
  });
24
26
 
25
27
  app
@@ -36,7 +38,7 @@ export default function createApp(
36
38
  version: "1.0.0",
37
39
  status: "running",
38
40
  docs: "/docs",
39
- mainTenant: MAIN_TENANT_ID,
41
+ controlPlaneTenant: CONTROL_PLANE_TENANT_ID,
40
42
  });
41
43
  })
42
44
  .get("/docs", swaggerUI({ url: "/api/v2/spec" }));
@@ -1,23 +1,46 @@
1
+ # ════════════════════════════════════════════════════════════════════════════
2
+ # AuthHero Multi-Tenant Cloudflare Worker Configuration
3
+ # ════════════════════════════════════════════════════════════════════════════
4
+ # This file is safe for version control. Sensitive IDs should go in:
5
+ # - wrangler.local.toml (local development - gitignored)
6
+ # - GitHub Secrets / Cloudflare Dashboard (production)
7
+ #
8
+ # For local development with your own Cloudflare resources:
9
+ # cp wrangler.toml wrangler.local.toml
10
+ # # Add your database_id to wrangler.local.toml
11
+ # npm run dev # Uses wrangler.local.toml automatically
12
+ # ════════════════════════════════════════════════════════════════════════════
13
+
1
14
  name = "authhero-multitenant"
2
15
  main = "src/index.ts"
3
16
  compatibility_date = "2024-11-20"
4
17
 
18
+ # ════════════════════════════════════════════════════════════════════════════
5
19
  # D1 Database binding
6
- # Run: wrangler d1 create authhero-db
7
- # Then uncomment and update the database_id below:
8
- # [[d1_databases]]
9
- # binding = "AUTH_DB"
10
- # database_name = "authhero-db"
11
- # database_id = "<YOUR_DATABASE_ID>"
12
- # migrations_dir = "node_modules/@authhero/drizzle/drizzle"
13
-
14
- # For local development, you can use a local D1 database:
20
+ # ════════════════════════════════════════════════════════════════════════════
21
+ # This configuration uses a local D1 database by default.
22
+ # For remote development/production, copy to wrangler.local.toml and update.
23
+ #
24
+ # Setup:
25
+ # 1. Create database: npx wrangler d1 create authhero-db
26
+ # 2. Copy to local config: cp wrangler.toml wrangler.local.toml
27
+ # 3. Update database_id in wrangler.local.toml with the ID from step 1
28
+ #
15
29
  [[d1_databases]]
16
30
  binding = "AUTH_DB"
17
31
  database_name = "authhero-db"
18
- database_id = "local"
32
+ database_id = "local" # Use "local" for local dev, or your actual ID in wrangler.local.toml
19
33
  migrations_dir = "node_modules/@authhero/drizzle/drizzle"
20
34
 
35
+ # ════════════════════════════════════════════════════════════════════════════
36
+ # OPTIONAL: Custom Domain
37
+ # ════════════════════════════════════════════════════════════════════════════
38
+ # To route your worker to a custom domain, use zone_name (not zone_id):
39
+ #
40
+ # [[routes]]
41
+ # pattern = "auth.yourdomain.com/*"
42
+ # zone_name = "yourdomain.com"
43
+
21
44
  # ════════════════════════════════════════════════════════════════════════════
22
45
  # OPTIONAL: Analytics Engine for centralized logging
23
46
  # ════════════════════════════════════════════════════════════════════════════
@@ -7,90 +7,117 @@ A single-tenant AuthHero authentication server using Cloudflare Workers and D1.
7
7
  - [Cloudflare Account](https://dash.cloudflare.com/sign-up)
8
8
  - [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/install-and-update/)
9
9
 
10
+ ## Security & Privacy
11
+
12
+ This project is designed to be **open-source friendly**. Sensitive Cloudflare IDs are kept out of version control:
13
+
14
+ | File | Purpose | In Git? |
15
+ | --------------------- | ---------------------------------- | ------- |
16
+ | `wrangler.toml` | Base config (safe for public repo) | ✅ Yes |
17
+ | `wrangler.local.toml` | Your private IDs (database_id) | ❌ No |
18
+ | `.dev.vars` | Local secrets (API tokens, etc.) | ❌ No |
19
+ | `.dev.vars.example` | Template for .dev.vars | ✅ Yes |
20
+
21
+ **For GitHub Actions / CI:**
22
+
23
+ - Set `CLOUDFLARE_API_TOKEN` as a GitHub Secret
24
+ - Set `CLOUDFLARE_ACCOUNT_ID` as a GitHub Secret (if needed)
25
+ - The wrangler action will use these automatically
26
+
10
27
  ## Getting Started
11
28
 
29
+ ### Local Development (Quick Start)
30
+
12
31
  1. Install dependencies:
13
32
 
14
33
  ```bash
15
34
  npm install
16
35
  ```
17
36
 
18
- 2. Create a D1 database (if not using local mode):
37
+ 2. Run database migrations (uses local SQLite-backed D1):
19
38
 
20
39
  ```bash
21
- wrangler d1 create authhero-db
40
+ npm run migrate
22
41
  ```
23
42
 
24
- Update `wrangler.toml` with your database ID from the output above.
25
-
26
- 3. Run database migrations:
27
-
28
- **For local development:**
43
+ 3. Seed the database with an admin user:
29
44
 
30
45
  ```bash
31
- npm run migrate
46
+ ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed
32
47
  ```
33
48
 
34
- **For production:**
49
+ 4. Start the development server:
35
50
 
36
51
  ```bash
37
- npm run db:migrate:remote
52
+ npm run dev
38
53
  ```
39
54
 
40
- 4. Seed the database with an admin user:
55
+ The server will be available at `https://localhost:3000`.
56
+
57
+ ### Remote Development (Your Cloudflare Account)
41
58
 
42
- **For local development:**
59
+ 1. Create a D1 database:
43
60
 
44
61
  ```bash
45
- ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed:local
62
+ npx wrangler d1 create authhero-db
46
63
  ```
47
64
 
48
- **For production:**
65
+ 2. Copy the `database_id` from the output and update `wrangler.local.toml`:
49
66
 
50
- ```bash
51
- ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed:remote
67
+ ```toml
68
+ [[d1_databases]]
69
+ binding = "AUTH_DB"
70
+ database_name = "authhero-db"
71
+ database_id = "paste-your-database-id-here"
72
+ migrations_dir = "node_modules/@authhero/drizzle/drizzle"
52
73
  ```
53
74
 
54
- 5. Start the development server:
55
-
56
- **For local mode (local D1 database):**
75
+ 3. Run remote migrations:
57
76
 
58
77
  ```bash
59
- npm run dev:local
78
+ npm run db:migrate:remote
60
79
  ```
61
80
 
62
- **For remote mode (production D1 database):**
81
+ 4. Seed the remote database:
63
82
 
83
+ ```bash
84
+ ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed:remote
85
+ ```
86
+
87
+ 5. Start with remote D1:
64
88
  ```bash
65
89
  npm run dev:remote
66
90
  ```
67
91
 
68
92
  ## Available Scripts
69
93
 
70
- - `npm run dev:local` - Start development server with local D1 database
71
- - `npm run dev:remote` - Start development server with remote D1 database
94
+ - `npm run dev` - Start development server with local D1 database
95
+ - `npm run dev:remote` - Start with remote D1 database
72
96
  - `npm run deploy` - Deploy to Cloudflare Workers
73
97
  - `npm run migrate` - Run migrations on local database
74
98
  - `npm run db:migrate:local` - Run migrations on local database (alias)
75
99
  - `npm run db:migrate:remote` - Run migrations on remote database
76
- - `npm run seed:local` - Seed local database with admin user
100
+ - `npm run seed` - Seed local database with admin user
77
101
  - `npm run seed:remote` - Seed remote database with admin user
102
+ - `npm run setup` - Create wrangler.local.toml and .dev.vars from templates
78
103
 
79
104
  ## Deployment
80
105
 
81
- 1. Deploy to Cloudflare:
106
+ 1. Ensure `wrangler.local.toml` has your production `database_id`.
107
+
108
+ 2. Deploy to Cloudflare:
82
109
 
83
110
  ```bash
84
111
  npm run deploy
85
112
  ```
86
113
 
87
- 2. Run production migrations:
114
+ 3. Run production migrations:
88
115
 
89
116
  ```bash
90
117
  npm run db:migrate:remote
91
118
  ```
92
119
 
93
- 3. Seed the production database:
120
+ 4. Seed the production database:
94
121
  ```bash
95
122
  ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed:remote
96
123
  ```
@@ -136,6 +163,83 @@ routes = [
136
163
 
137
164
  For more information, visit [https://authhero.net/docs](https://authhero.net/docs).
138
165
 
166
+ ## CI/CD with GitHub Actions
167
+
168
+ If you selected GitHub CI during setup, your project includes automated workflows for continuous integration and deployment.
169
+
170
+ ### Workflow Overview
171
+
172
+ ```
173
+ ┌─────────────────────────────────────────────────────────────────────────┐
174
+ │ GitHub Actions │
175
+ ├─────────────────────────────────────────────────────────────────────────┤
176
+ │ │
177
+ │ ┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
178
+ │ │ Any Push │ │ Push to main │ │ GitHub Release │ │
179
+ │ │ │ │ │ │ (released) │ │
180
+ │ └──────┬───────┘ └────────┬─────────┘ └────────┬─────────┘ │
181
+ │ │ │ │ │
182
+ │ ▼ ▼ ▼ │
183
+ │ ┌──────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
184
+ │ │ Unit Tests │ │ Semantic Release │ │ Deploy to │ │
185
+ │ │ Type Check │ │ + Deploy Dev │ │ Production │ │
186
+ │ └──────────────┘ └──────────────────┘ └──────────────────┘ │
187
+ │ │
188
+ └─────────────────────────────────────────────────────────────────────────┘
189
+ ```
190
+
191
+ ### Workflows
192
+
193
+ 1. **Unit Tests** (`.github/workflows/unit-tests.yml`)
194
+ - **Trigger**: All pushes to any branch
195
+ - **Actions**: Runs type checking and tests
196
+
197
+ 2. **Deploy to Dev** (`.github/workflows/deploy-dev.yml`)
198
+ - **Trigger**: Push to `main` branch
199
+ - **Actions**:
200
+ - Runs semantic-release to create version tags
201
+ - Deploys to Cloudflare Workers (dev environment)
202
+
203
+ 3. **Deploy to Production** (`.github/workflows/release.yml`)
204
+ - **Trigger**: GitHub Release (when "released")
205
+ - **Actions**: Deploys to Cloudflare Workers (production environment)
206
+
207
+ ### Required Secrets
208
+
209
+ Configure these secrets in your GitHub repository settings:
210
+
211
+ | Secret | Description |
212
+ | --------------------------- | ----------------------------------------------- |
213
+ | `CLOUDFLARE_API_TOKEN` | Cloudflare API token for dev deployments |
214
+ | `PROD_CLOUDFLARE_API_TOKEN` | Cloudflare API token for production deployments |
215
+
216
+ ### Semantic Versioning
217
+
218
+ Commits to `main` are analyzed to determine version bumps:
219
+
220
+ - `fix:` - Patch release (1.0.0 → 1.0.1)
221
+ - `feat:` - Minor release (1.0.0 → 1.1.0)
222
+ - `BREAKING CHANGE:` - Major release (1.0.0 → 2.0.0)
223
+
224
+ ### Production Deployment
225
+
226
+ To deploy to production:
227
+
228
+ 1. Go to GitHub → Releases → "Draft a new release"
229
+ 2. Create a new tag (e.g., `v1.0.0`)
230
+ 3. Click "Publish release"
231
+ 4. The `release.yml` workflow will deploy to production
232
+
233
+ ### Wrangler Configuration
234
+
235
+ For production deployments, add an environment to `wrangler.toml`:
236
+
237
+ ```toml
238
+ [env.production]
239
+ name = "your-worker-production"
240
+ # Add production-specific settings here
241
+ ```
242
+
139
243
  ## Optional Features
140
244
 
141
245
  ### Analytics Engine (Centralized Logging)
@@ -1,23 +1,46 @@
1
+ # ════════════════════════════════════════════════════════════════════════════
2
+ # AuthHero Cloudflare Worker Configuration
3
+ # ════════════════════════════════════════════════════════════════════════════
4
+ # This file is safe for version control. Sensitive IDs should go in:
5
+ # - wrangler.local.toml (local development - gitignored)
6
+ # - GitHub Secrets / Cloudflare Dashboard (production)
7
+ #
8
+ # For local development with your own Cloudflare resources:
9
+ # cp wrangler.toml wrangler.local.toml
10
+ # # Add your database_id to wrangler.local.toml
11
+ # npm run dev # Uses wrangler.local.toml automatically
12
+ # ════════════════════════════════════════════════════════════════════════════
13
+
1
14
  name = "authhero-server"
2
15
  main = "src/index.ts"
3
16
  compatibility_date = "2024-11-20"
4
17
 
18
+ # ════════════════════════════════════════════════════════════════════════════
5
19
  # D1 Database binding
6
- # Run: wrangler d1 create authhero-db
7
- # Then uncomment and update the database_id below:
8
- # [[d1_databases]]
9
- # binding = "AUTH_DB"
10
- # database_name = "authhero-db"
11
- # database_id = "<YOUR_DATABASE_ID>"
12
- # migrations_dir = "node_modules/@authhero/drizzle/drizzle"
13
-
14
- # For local development, you can use a local D1 database:
20
+ # ════════════════════════════════════════════════════════════════════════════
21
+ # This configuration uses a local D1 database by default.
22
+ # For remote development/production, copy to wrangler.local.toml and update.
23
+ #
24
+ # Setup:
25
+ # 1. Create database: npx wrangler d1 create authhero-db
26
+ # 2. Copy to local config: cp wrangler.toml wrangler.local.toml
27
+ # 3. Update database_id in wrangler.local.toml with the ID from step 1
28
+ #
15
29
  [[d1_databases]]
16
30
  binding = "AUTH_DB"
17
31
  database_name = "authhero-db"
18
- database_id = "local"
32
+ database_id = "local" # Use "local" for local dev, or your actual ID in wrangler.local.toml
19
33
  migrations_dir = "node_modules/@authhero/drizzle/drizzle"
20
34
 
35
+ # ════════════════════════════════════════════════════════════════════════════
36
+ # OPTIONAL: Custom Domain
37
+ # ════════════════════════════════════════════════════════════════════════════
38
+ # To route your worker to a custom domain, use zone_name (not zone_id):
39
+ #
40
+ # [[routes]]
41
+ # pattern = "auth.yourdomain.com/*"
42
+ # zone_name = "yourdomain.com"
43
+
21
44
  # ════════════════════════════════════════════════════════════════════════════
22
45
  # OPTIONAL: Analytics Engine for centralized logging
23
46
  # ════════════════════════════════════════════════════════════════════════════
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
- import { Command as x } from "commander";
3
- import c from "inquirer";
4
- import i from "fs";
5
- import f from "path";
6
- import { spawn as D } from "child_process";
7
- const b = new x(), n = {
2
+ import { Command as j } from "commander";
3
+ import m from "inquirer";
4
+ import o from "fs";
5
+ import i from "path";
6
+ import { spawn as b } from "child_process";
7
+ const D = new j(), c = {
8
8
  local: {
9
9
  name: "Local (SQLite)",
10
10
  description: "Local development setup with SQLite database - great for getting started",
11
11
  templateDir: "local",
12
- packageJson: (r) => ({
13
- name: r,
12
+ packageJson: (s) => ({
13
+ name: s,
14
14
  version: "1.0.0",
15
15
  type: "module",
16
16
  scripts: {
@@ -42,21 +42,21 @@ const b = new x(), n = {
42
42
  name: "Cloudflare Simple (Single Tenant)",
43
43
  description: "Single-tenant Cloudflare Workers setup with D1 database",
44
44
  templateDir: "cloudflare-simple",
45
- packageJson: (r) => ({
46
- name: r,
45
+ packageJson: (s) => ({
46
+ name: s,
47
47
  version: "1.0.0",
48
48
  type: "module",
49
49
  scripts: {
50
- "dev:local": "wrangler dev --port 3000 --local-protocol https",
51
- "dev:remote": "wrangler dev --port 3000 --local-protocol https --remote",
52
50
  dev: "wrangler dev --port 3000 --local-protocol https",
53
- deploy: "wrangler deploy",
51
+ "dev:remote": "wrangler dev --port 3000 --local-protocol https --remote --config wrangler.local.toml",
52
+ deploy: "wrangler deploy --config wrangler.local.toml",
54
53
  "db:migrate:local": "wrangler d1 migrations apply AUTH_DB --local",
55
- "db:migrate:remote": "wrangler d1 migrations apply AUTH_DB --remote",
54
+ "db:migrate:remote": "wrangler d1 migrations apply AUTH_DB --remote --config wrangler.local.toml",
56
55
  migrate: "wrangler d1 migrations apply AUTH_DB --local",
57
56
  "seed:local": "node seed-helper.js",
58
57
  "seed:remote": "node seed-helper.js '' '' remote",
59
- seed: "node seed-helper.js"
58
+ seed: "node seed-helper.js",
59
+ setup: "cp wrangler.toml wrangler.local.toml && cp .dev.vars.example .dev.vars && echo '✅ Created wrangler.local.toml and .dev.vars - update with your IDs'"
60
60
  },
61
61
  dependencies: {
62
62
  "@authhero/drizzle": "latest",
@@ -82,21 +82,21 @@ const b = new x(), n = {
82
82
  name: "Cloudflare Multi-Tenant (Production)",
83
83
  description: "Production-grade multi-tenant setup with D1 database and tenant management",
84
84
  templateDir: "cloudflare-multitenant",
85
- packageJson: (r) => ({
86
- name: r,
85
+ packageJson: (s) => ({
86
+ name: s,
87
87
  version: "1.0.0",
88
88
  type: "module",
89
89
  scripts: {
90
- "dev:local": "wrangler dev --port 3000 --local-protocol https",
91
- "dev:remote": "wrangler dev --port 3000 --local-protocol https --remote",
92
90
  dev: "wrangler dev --port 3000 --local-protocol https",
93
- deploy: "wrangler deploy",
91
+ "dev:remote": "wrangler dev --port 3000 --local-protocol https --remote --config wrangler.local.toml",
92
+ deploy: "wrangler deploy --config wrangler.local.toml",
94
93
  "db:migrate:local": "wrangler d1 migrations apply AUTH_DB --local",
95
- "db:migrate:remote": "wrangler d1 migrations apply AUTH_DB --remote",
94
+ "db:migrate:remote": "wrangler d1 migrations apply AUTH_DB --remote --config wrangler.local.toml",
96
95
  migrate: "wrangler d1 migrations apply AUTH_DB --local",
97
96
  "seed:local": "node seed-helper.js",
98
97
  "seed:remote": "node seed-helper.js '' '' remote",
99
- seed: "node seed-helper.js"
98
+ seed: "node seed-helper.js",
99
+ setup: "cp wrangler.toml wrangler.local.toml && cp .dev.vars.example .dev.vars && echo '✅ Created wrangler.local.toml and .dev.vars - update with your IDs'"
100
100
  },
101
101
  dependencies: {
102
102
  "@authhero/drizzle": "latest",
@@ -119,13 +119,13 @@ const b = new x(), n = {
119
119
  seedFile: "seed.ts"
120
120
  }
121
121
  };
122
- function A(r, a) {
123
- i.readdirSync(r).forEach((o) => {
124
- const t = f.join(r, o), e = f.join(a, o);
125
- i.lstatSync(t).isDirectory() ? (i.mkdirSync(e, { recursive: !0 }), A(t, e)) : i.copyFileSync(t, e);
122
+ function A(s, e) {
123
+ o.readdirSync(s).forEach((n) => {
124
+ const a = i.join(s, n), t = i.join(e, n);
125
+ o.lstatSync(a).isDirectory() ? (o.mkdirSync(t, { recursive: !0 }), A(a, t)) : o.copyFileSync(a, t);
126
126
  });
127
127
  }
128
- function $() {
128
+ function I() {
129
129
  return `import { SqliteDialect, Kysely } from "kysely";
130
130
  import Database from "better-sqlite3";
131
131
  import createAdapters from "@authhero/kysely-adapter";
@@ -159,106 +159,236 @@ async function main() {
159
159
  main().catch(console.error);
160
160
  `;
161
161
  }
162
- function v(r, a) {
163
- return new Promise((s, o) => {
164
- const t = D(r, [], {
165
- cwd: a,
162
+ function x(s) {
163
+ const e = i.join(s, ".github", "workflows");
164
+ o.mkdirSync(e, { recursive: !0 });
165
+ const r = `name: Unit tests
166
+
167
+ on: push
168
+
169
+ jobs:
170
+ test:
171
+ runs-on: ubuntu-latest
172
+ steps:
173
+ - uses: actions/checkout@v4
174
+
175
+ - name: Setup Node.js
176
+ uses: actions/setup-node@v4
177
+ with:
178
+ node-version: "22"
179
+ cache: "npm"
180
+
181
+ - name: Install dependencies
182
+ run: npm ci
183
+
184
+ - run: npm run type-check
185
+ - run: npm test
186
+ `, n = `name: Deploy to Dev
187
+
188
+ on:
189
+ push:
190
+ branches:
191
+ - main
192
+
193
+ jobs:
194
+ release:
195
+ name: Release and Deploy
196
+ runs-on: ubuntu-latest
197
+ steps:
198
+ - name: Checkout
199
+ uses: actions/checkout@v4
200
+ with:
201
+ fetch-depth: 0
202
+
203
+ - name: Setup Node.js
204
+ uses: actions/setup-node@v4
205
+ with:
206
+ node-version: "22"
207
+ cache: "npm"
208
+
209
+ - name: Install dependencies
210
+ run: npm ci
211
+
212
+ - name: Release
213
+ env:
214
+ GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
215
+ run: npx semantic-release
216
+
217
+ - name: Deploy to Cloudflare (Dev)
218
+ uses: cloudflare/wrangler-action@v3
219
+ with:
220
+ apiToken: \${{ secrets.CLOUDFLARE_API_TOKEN }}
221
+ command: deploy
222
+ `, a = `name: Deploy to Production
223
+
224
+ on:
225
+ release:
226
+ types: ["released"]
227
+
228
+ jobs:
229
+ deploy:
230
+ name: Deploy to Production
231
+ runs-on: ubuntu-latest
232
+ steps:
233
+ - name: Checkout
234
+ uses: actions/checkout@v4
235
+
236
+ - name: Setup Node.js
237
+ uses: actions/setup-node@v4
238
+ with:
239
+ node-version: "22"
240
+ cache: "npm"
241
+
242
+ - name: Install dependencies
243
+ run: npm ci
244
+
245
+ - name: Deploy to Cloudflare (Production)
246
+ uses: cloudflare/wrangler-action@v3
247
+ with:
248
+ apiToken: \${{ secrets.PROD_CLOUDFLARE_API_TOKEN }}
249
+ command: deploy --env production
250
+ `;
251
+ o.writeFileSync(i.join(e, "unit-tests.yml"), r), o.writeFileSync(i.join(e, "deploy-dev.yml"), n), o.writeFileSync(i.join(e, "release.yml"), a), console.log("\\n📦 GitHub CI workflows created!");
252
+ }
253
+ function C(s) {
254
+ const e = {
255
+ branches: ["main"],
256
+ plugins: [
257
+ "@semantic-release/commit-analyzer",
258
+ "@semantic-release/release-notes-generator",
259
+ "@semantic-release/github"
260
+ ]
261
+ };
262
+ o.writeFileSync(
263
+ i.join(s, ".releaserc.json"),
264
+ JSON.stringify(e, null, 2)
265
+ );
266
+ const r = i.join(s, "package.json"), n = JSON.parse(o.readFileSync(r, "utf-8"));
267
+ n.devDependencies = {
268
+ ...n.devDependencies,
269
+ "semantic-release": "^24.0.0"
270
+ }, n.scripts = {
271
+ ...n.scripts,
272
+ test: 'echo "No tests yet"',
273
+ "type-check": "tsc --noEmit"
274
+ }, o.writeFileSync(r, JSON.stringify(n, null, 2));
275
+ }
276
+ function v(s, e) {
277
+ return new Promise((r, n) => {
278
+ const a = b(s, [], {
279
+ cwd: e,
166
280
  shell: !0,
167
281
  stdio: "inherit"
168
282
  });
169
- t.on("close", (e) => {
170
- e === 0 ? s() : o(new Error(`Command failed with exit code ${e}`));
171
- }), t.on("error", o);
283
+ a.on("close", (t) => {
284
+ t === 0 ? r() : n(new Error(`Command failed with exit code ${t}`));
285
+ }), a.on("error", n);
172
286
  });
173
287
  }
174
- function S(r, a, s) {
175
- return new Promise((o, t) => {
176
- const e = D(r, [], {
177
- cwd: a,
288
+ function S(s, e, r) {
289
+ return new Promise((n, a) => {
290
+ const t = b(s, [], {
291
+ cwd: e,
178
292
  shell: !0,
179
293
  stdio: "inherit",
180
- env: { ...process.env, ...s }
294
+ env: { ...process.env, ...r }
181
295
  });
182
- e.on("close", (g) => {
183
- g === 0 ? o() : t(new Error(`Command failed with exit code ${g}`));
184
- }), e.on("error", t);
296
+ t.on("close", (f) => {
297
+ f === 0 ? n() : a(new Error(`Command failed with exit code ${f}`));
298
+ }), t.on("error", a);
185
299
  });
186
300
  }
187
- b.version("1.0.0").description("Create a new AuthHero project").argument("[project-name]", "name of the project").option(
301
+ D.version("1.0.0").description("Create a new AuthHero project").argument("[project-name]", "name of the project").option(
188
302
  "-t, --template <type>",
189
303
  "template type: local, cloudflare-simple, or cloudflare-multitenant"
190
304
  ).option("-e, --email <email>", "admin email address").option("-p, --password <password>", "admin password (min 8 characters)").option(
191
305
  "--package-manager <pm>",
192
306
  "package manager to use: npm, yarn, pnpm, or bun"
193
- ).option("--skip-install", "skip installing dependencies").option("--skip-migrate", "skip running database migrations").option("--skip-seed", "skip seeding the database").option("--skip-start", "skip starting the development server").option("--remote", "use remote mode for cloudflare-simple (production D1)").option("-y, --yes", "skip all prompts and use defaults/provided options").action(async (r, a) => {
194
- const s = a.yes === !0;
307
+ ).option("--skip-install", "skip installing dependencies").option("--skip-migrate", "skip running database migrations").option("--skip-seed", "skip seeding the database").option("--skip-start", "skip starting the development server").option("--github-ci", "include GitHub CI workflows with semantic versioning").option("-y, --yes", "skip all prompts and use defaults/provided options").action(async (s, e) => {
308
+ const r = e.yes === !0;
195
309
  console.log(`
196
310
  🔐 Welcome to AuthHero!
197
311
  `);
198
- let o = r;
199
- o || (s ? (o = "auth-server", console.log(`Using default project name: ${o}`)) : o = (await c.prompt([
312
+ let n = s;
313
+ n || (r ? (n = "auth-server", console.log(`Using default project name: ${n}`)) : n = (await m.prompt([
200
314
  {
201
315
  type: "input",
202
316
  name: "projectName",
203
317
  message: "Project name:",
204
318
  default: "auth-server",
205
- validate: (p) => p !== "" || "Project name cannot be empty"
319
+ validate: (d) => d !== "" || "Project name cannot be empty"
206
320
  }
207
321
  ])).projectName);
208
- const t = f.join(process.cwd(), o);
209
- i.existsSync(t) && (console.error(`❌ Project "${o}" already exists.`), process.exit(1));
210
- let e;
211
- a.template ? (["local", "cloudflare-simple", "cloudflare-multitenant"].includes(
212
- a.template
213
- ) || (console.error(`❌ Invalid template: ${a.template}`), console.error(
322
+ const a = i.join(process.cwd(), n);
323
+ o.existsSync(a) && (console.error(`❌ Project "${n}" already exists.`), process.exit(1));
324
+ let t;
325
+ e.template ? (["local", "cloudflare-simple", "cloudflare-multitenant"].includes(
326
+ e.template
327
+ ) || (console.error(`❌ Invalid template: ${e.template}`), console.error(
214
328
  "Valid options: local, cloudflare-simple, cloudflare-multitenant"
215
- ), process.exit(1)), e = a.template, console.log(`Using template: ${n[e].name}`)) : e = (await c.prompt([
329
+ ), process.exit(1)), t = e.template, console.log(`Using template: ${c[t].name}`)) : t = (await m.prompt([
216
330
  {
217
331
  type: "list",
218
332
  name: "setupType",
219
333
  message: "Select your setup type:",
220
334
  choices: [
221
335
  {
222
- name: `${n.local.name}
223
- ${n.local.description}`,
336
+ name: `${c.local.name}
337
+ ${c.local.description}`,
224
338
  value: "local",
225
- short: n.local.name
339
+ short: c.local.name
226
340
  },
227
341
  {
228
- name: `${n["cloudflare-simple"].name}
229
- ${n["cloudflare-simple"].description}`,
342
+ name: `${c["cloudflare-simple"].name}
343
+ ${c["cloudflare-simple"].description}`,
230
344
  value: "cloudflare-simple",
231
- short: n["cloudflare-simple"].name
345
+ short: c["cloudflare-simple"].name
232
346
  },
233
347
  {
234
- name: `${n["cloudflare-multitenant"].name}
235
- ${n["cloudflare-multitenant"].description}`,
348
+ name: `${c["cloudflare-multitenant"].name}
349
+ ${c["cloudflare-multitenant"].description}`,
236
350
  value: "cloudflare-multitenant",
237
- short: n["cloudflare-multitenant"].name
351
+ short: c["cloudflare-multitenant"].name
238
352
  }
239
353
  ]
240
354
  }
241
355
  ])).setupType;
242
- const g = n[e];
243
- i.mkdirSync(t, { recursive: !0 }), i.writeFileSync(
244
- f.join(t, "package.json"),
245
- JSON.stringify(g.packageJson(o), null, 2)
356
+ const f = c[t];
357
+ o.mkdirSync(a, { recursive: !0 }), o.writeFileSync(
358
+ i.join(a, "package.json"),
359
+ JSON.stringify(f.packageJson(n), null, 2)
246
360
  );
247
- const k = f.join(
361
+ const k = i.join(
248
362
  import.meta.url.replace("file://", "").replace("/create-authhero.js", ""),
249
- g.templateDir
363
+ f.templateDir
250
364
  );
251
- if (i.existsSync(k) ? A(k, t) : (console.error(`❌ Template directory not found: ${k}`), process.exit(1)), e === "local") {
252
- const l = $();
253
- i.writeFileSync(f.join(t, "src/seed.ts"), l);
365
+ if (o.existsSync(k) ? A(k, a) : (console.error(`❌ Template directory not found: ${k}`), process.exit(1)), t === "cloudflare-simple" || t === "cloudflare-multitenant") {
366
+ const l = i.join(a, "wrangler.toml"), d = i.join(a, "wrangler.local.toml");
367
+ o.existsSync(l) && o.copyFileSync(l, d);
368
+ const p = i.join(a, ".dev.vars.example"), u = i.join(a, ".dev.vars");
369
+ o.existsSync(p) && o.copyFileSync(p, u), console.log(
370
+ "📁 Created wrangler.local.toml and .dev.vars for local development"
371
+ );
372
+ }
373
+ let w = !1;
374
+ if ((t === "cloudflare-simple" || t === "cloudflare-multitenant") && (e.githubCi !== void 0 ? (w = e.githubCi, w && console.log("Including GitHub CI workflows with semantic versioning")) : r || (w = (await m.prompt([
375
+ {
376
+ type: "confirm",
377
+ name: "includeGithubCi",
378
+ message: "Would you like to include GitHub CI with semantic versioning?",
379
+ default: !1
380
+ }
381
+ ])).includeGithubCi), w && (x(a), C(a))), t === "local") {
382
+ const l = I();
383
+ o.writeFileSync(i.join(a, "src/seed.ts"), l);
254
384
  }
255
385
  console.log(
256
386
  `
257
- ✅ Project "${o}" has been created with ${g.name} setup!
387
+ ✅ Project "${n}" has been created with ${f.name} setup!
258
388
  `
259
389
  );
260
390
  let h;
261
- if (a.skipInstall ? h = !1 : s ? h = !0 : h = (await c.prompt([
391
+ if (e.skipInstall ? h = !1 : r ? h = !0 : h = (await m.prompt([
262
392
  {
263
393
  type: "confirm",
264
394
  name: "shouldInstall",
@@ -267,9 +397,9 @@ b.version("1.0.0").description("Create a new AuthHero project").argument("[proje
267
397
  }
268
398
  ])).shouldInstall, h) {
269
399
  let l;
270
- a.packageManager ? (["npm", "yarn", "pnpm", "bun"].includes(a.packageManager) || (console.error(
271
- `❌ Invalid package manager: ${a.packageManager}`
272
- ), console.error("Valid options: npm, yarn, pnpm, bun"), process.exit(1)), l = a.packageManager) : s ? l = "pnpm" : l = (await c.prompt([
400
+ e.packageManager ? (["npm", "yarn", "pnpm", "bun"].includes(e.packageManager) || (console.error(
401
+ `❌ Invalid package manager: ${e.packageManager}`
402
+ ), console.error("Valid options: npm, yarn, pnpm, bun"), process.exit(1)), l = e.packageManager) : r ? l = "pnpm" : l = (await m.prompt([
273
403
  {
274
404
  type: "list",
275
405
  name: "packageManager",
@@ -286,36 +416,14 @@ b.version("1.0.0").description("Create a new AuthHero project").argument("[proje
286
416
  📦 Installing dependencies with ${l}...
287
417
  `);
288
418
  try {
289
- const p = l === "pnpm" ? "pnpm install --ignore-workspace" : `${l} install`;
290
- await v(p, t), e === "local" && (console.log(`
419
+ const d = l === "pnpm" ? "pnpm install --ignore-workspace" : `${l} install`;
420
+ if (await v(d, a), t === "local" && (console.log(`
291
421
  🔧 Building native modules...
292
- `), await v("npm rebuild better-sqlite3", t)), console.log(`
422
+ `), await v("npm rebuild better-sqlite3", a)), console.log(`
293
423
  ✅ Dependencies installed successfully!
294
- `);
295
- let y = a.remote ? "remote" : "local";
296
- if (e === "local" || e === "cloudflare-simple" || e === "cloudflare-multitenant") {
297
- (e === "cloudflare-simple" || e === "cloudflare-multitenant") && !s && !a.remote && (y = (await c.prompt([
298
- {
299
- type: "list",
300
- name: "mode",
301
- message: "Would you like to run in local mode or remote mode?",
302
- choices: [
303
- {
304
- name: "Local (using local D1 database)",
305
- value: "local",
306
- short: "Local"
307
- },
308
- {
309
- name: "Remote (using production D1 database)",
310
- value: "remote",
311
- short: "Remote"
312
- }
313
- ],
314
- default: "local"
315
- }
316
- ])).mode);
424
+ `), t === "local" || t === "cloudflare-simple" || t === "cloudflare-multitenant") {
317
425
  let u;
318
- if (a.skipMigrate && a.skipSeed ? u = !1 : s ? u = !a.skipMigrate || !a.skipSeed : u = (await c.prompt([
426
+ if (e.skipMigrate && e.skipSeed ? u = !1 : r ? u = !e.skipMigrate || !e.skipSeed : u = (await m.prompt([
319
427
  {
320
428
  type: "confirm",
321
429
  name: "shouldSetup",
@@ -323,84 +431,72 @@ b.version("1.0.0").description("Create a new AuthHero project").argument("[proje
323
431
  default: !0
324
432
  }
325
433
  ])).shouldSetup, u) {
326
- let d;
327
- if (a.email && a.password ? (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(a.email) || (console.error("❌ Invalid email address provided"), process.exit(1)), a.password.length < 8 && (console.error("❌ Password must be at least 8 characters"), process.exit(1)), d = {
328
- username: a.email,
329
- password: a.password
330
- }, console.log(`Using admin email: ${a.email}`)) : d = await c.prompt([
434
+ let g;
435
+ e.email && e.password ? (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e.email) || (console.error("❌ Invalid email address provided"), process.exit(1)), e.password.length < 8 && (console.error("❌ Password must be at least 8 characters"), process.exit(1)), g = {
436
+ username: e.email,
437
+ password: e.password
438
+ }, console.log(`Using admin email: ${e.email}`)) : g = await m.prompt([
331
439
  {
332
440
  type: "input",
333
441
  name: "username",
334
442
  message: "Admin email:",
335
443
  default: "admin@example.com",
336
- validate: (m) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(m) || "Please enter a valid email address"
444
+ validate: (y) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(y) || "Please enter a valid email address"
337
445
  },
338
446
  {
339
447
  type: "password",
340
448
  name: "password",
341
449
  message: "Admin password:",
342
450
  mask: "*",
343
- validate: (m) => m.length < 8 ? "Password must be at least 8 characters" : !0
451
+ validate: (y) => y.length < 8 ? "Password must be at least 8 characters" : !0
344
452
  }
345
- ]), !a.skipMigrate) {
346
- console.log(`
453
+ ]), e.skipMigrate || (console.log(`
347
454
  🔄 Running migrations...
348
- `);
349
- const m = (e === "cloudflare-simple" || e === "cloudflare-multitenant") && y === "remote" ? `${l} run db:migrate:remote` : `${l} run migrate`;
350
- await v(m, t);
351
- }
352
- if (!a.skipSeed)
353
- if (console.log(`
455
+ `), await v(`${l} run migrate`, a)), e.skipSeed || (console.log(`
354
456
  🌱 Seeding database...
355
- `), e === "local")
356
- await S(
357
- `${l} run seed`,
358
- t,
359
- {
360
- ADMIN_EMAIL: d.username,
361
- ADMIN_PASSWORD: d.password
362
- }
363
- );
364
- else {
365
- const m = y === "remote" ? `${l} run seed:remote` : `${l} run seed:local`;
366
- await S(m, t, {
367
- ADMIN_EMAIL: d.username,
368
- ADMIN_PASSWORD: d.password
369
- });
457
+ `), t === "local" ? await S(
458
+ `${l} run seed`,
459
+ a,
460
+ {
461
+ ADMIN_EMAIL: g.username,
462
+ ADMIN_PASSWORD: g.password
370
463
  }
464
+ ) : await S(
465
+ `${l} run seed:local`,
466
+ a,
467
+ {
468
+ ADMIN_EMAIL: g.username,
469
+ ADMIN_PASSWORD: g.password
470
+ }
471
+ ));
371
472
  }
372
473
  }
373
- let w;
374
- if (a.skipStart || s ? w = !1 : w = (await c.prompt([
474
+ let p;
475
+ e.skipStart || r ? p = !1 : p = (await m.prompt([
375
476
  {
376
477
  type: "confirm",
377
478
  name: "shouldStart",
378
479
  message: "Would you like to start the development server?",
379
480
  default: !0
380
481
  }
381
- ])).shouldStart, w) {
382
- console.log(
383
- `
482
+ ])).shouldStart, p && (console.log(
483
+ `
384
484
  🚀 Starting development server on https://localhost:3000 ...
385
485
  `
386
- );
387
- const u = (e === "cloudflare-simple" || e === "cloudflare-multitenant") && y === "remote" ? `${l} run dev:remote` : `${l} run dev`;
388
- await v(u, t);
389
- }
390
- s && !w && (console.log(`
486
+ ), await v(`${l} run dev`, a)), r && !p && (console.log(`
391
487
  ✅ Setup complete!`), console.log(`
392
- To start the development server:`), console.log(` cd ${o}`), console.log((e === "cloudflare-simple" || e === "cloudflare-multitenant") && y === "remote" ? " npm run dev:remote" : " npm run dev"), (e === "cloudflare-simple" || e === "cloudflare-multitenant") && console.log(
488
+ To start the development server:`), console.log(` cd ${n}`), console.log(" npm run dev"), (t === "cloudflare-simple" || t === "cloudflare-multitenant") && console.log(
393
489
  `
394
490
  Server will be available at: https://localhost:3000`
395
491
  ));
396
- } catch (p) {
492
+ } catch (d) {
397
493
  console.error(`
398
- ❌ An error occurred:`, p), process.exit(1);
494
+ ❌ An error occurred:`, d), process.exit(1);
399
495
  }
400
496
  }
401
- h || (console.log("Next steps:"), console.log(` cd ${o}`), e === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(
497
+ h || (console.log("Next steps:"), console.log(` cd ${n}`), t === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(
402
498
  " ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed"
403
- ), console.log(" npm run dev")) : (e === "cloudflare-simple" || e === "cloudflare-multitenant") && (console.log(" npm install"), console.log(
499
+ ), console.log(" npm run dev")) : (t === "cloudflare-simple" || t === "cloudflare-multitenant") && (console.log(" npm install"), console.log(
404
500
  " npm run migrate # or npm run db:migrate:remote for production"
405
501
  ), console.log(
406
502
  " ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed"
@@ -409,4 +505,4 @@ Server will be available at: https://localhost:3000`)), console.log(`
409
505
  For more information, visit: https://authhero.net/docs
410
506
  `));
411
507
  });
412
- b.parse(process.argv);
508
+ D.parse(process.argv);
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "type": "git",
6
6
  "url": "https://github.com/markusahlstrand/authhero"
7
7
  },
8
- "version": "0.15.0",
8
+ "version": "0.17.0",
9
9
  "type": "module",
10
10
  "main": "dist/create-authhero.js",
11
11
  "bin": {