create-authhero 0.8.0 → 0.10.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.
@@ -5,6 +5,11 @@ import createApp from "./app";
5
5
  import { Env } from "./types";
6
6
  import { AuthHeroConfig } from "authhero";
7
7
 
8
+ // ──────────────────────────────────────────────────────────────────────────────
9
+ // OPTIONAL: Uncomment to enable Cloudflare adapters (Analytics Engine, etc.)
10
+ // ──────────────────────────────────────────────────────────────────────────────
11
+ // import createCloudflareAdapters from "@authhero/cloudflare-adapter";
12
+
8
13
  export default {
9
14
  async fetch(request: Request, env: Env): Promise<Response> {
10
15
  const url = new URL(request.url);
@@ -17,17 +22,45 @@ export default {
17
22
  const db = new Kysely<any>({ dialect });
18
23
  const dataAdapter = createAdapters(db);
19
24
 
25
+ // ────────────────────────────────────────────────────────────────────────
26
+ // OPTIONAL: Cloudflare Analytics Engine for centralized logging
27
+ // Uncomment to enable:
28
+ // ────────────────────────────────────────────────────────────────────────
29
+ // const cloudflareAdapters = createCloudflareAdapters({
30
+ // accountId: env.CLOUDFLARE_ACCOUNT_ID,
31
+ // apiToken: env.CLOUDFLARE_API_TOKEN,
32
+ // analyticsEngineLogs: {
33
+ // analyticsEngineBinding: env.AUTH_LOGS,
34
+ // accountId: env.CLOUDFLARE_ACCOUNT_ID,
35
+ // apiToken: env.ANALYTICS_ENGINE_API_TOKEN || env.CLOUDFLARE_API_TOKEN,
36
+ // dataset: "authhero_logs",
37
+ // },
38
+ // });
39
+
40
+ // ────────────────────────────────────────────────────────────────────────
41
+ // OPTIONAL: Rate Limiting
42
+ // Uncomment to enable rate limiting on authentication endpoints:
43
+ // ────────────────────────────────────────────────────────────────────────
44
+ // const clientIp = request.headers.get("CF-Connecting-IP") || "unknown";
45
+ // const { success } = await env.RATE_LIMITER.limit({ key: clientIp });
46
+ // if (!success) {
47
+ // return new Response("Rate limit exceeded", { status: 429 });
48
+ // }
49
+
20
50
  const config: AuthHeroConfig = {
21
51
  dataAdapter,
22
- // Allow CORS from common development origins
52
+ // ──────────────────────────────────────────────────────────────────────
53
+ // OPTIONAL: Spread Cloudflare adapters to enable Analytics Engine logging
54
+ // Uncomment when using createCloudflareAdapters above:
55
+ // ──────────────────────────────────────────────────────────────────────
56
+ // ...cloudflareAdapters,
57
+
58
+ // Allow CORS for the Management API from admin UIs
23
59
  allowedOrigins: [
24
60
  "http://localhost:5173",
25
- "http://localhost:3000",
26
- "https://localhost:5173",
27
61
  "https://localhost:3000",
28
62
  "https://manage.authhero.net",
29
63
  "https://local.authhero.net",
30
- // Also allow the requesting origin in development
31
64
  origin,
32
65
  ].filter(Boolean),
33
66
  };
@@ -1,5 +1,23 @@
1
1
  /// <reference types="@cloudflare/workers-types" />
2
2
 
3
+ // Uncomment to enable Analytics Engine logging:
4
+ // import { AnalyticsEngineDataset } from "@authhero/cloudflare-adapter";
5
+
3
6
  export interface Env {
4
7
  AUTH_DB: D1Database;
8
+
9
+ // ──────────────────────────────────────────────────────────────────────────
10
+ // OPTIONAL: Analytics Engine for centralized logging
11
+ // Uncomment to enable:
12
+ // ──────────────────────────────────────────────────────────────────────────
13
+ // AUTH_LOGS: AnalyticsEngineDataset;
14
+ // CLOUDFLARE_ACCOUNT_ID: string;
15
+ // CLOUDFLARE_API_TOKEN: string;
16
+ // ANALYTICS_ENGINE_API_TOKEN?: string; // Optional: separate token for Analytics Engine
17
+
18
+ // ──────────────────────────────────────────────────────────────────────────
19
+ // OPTIONAL: Rate Limiting
20
+ // Uncomment to enable:
21
+ // ──────────────────────────────────────────────────────────────────────────
22
+ // RATE_LIMITER: RateLimiter;
5
23
  }
@@ -18,6 +18,33 @@ database_name = "authhero-db"
18
18
  database_id = "local"
19
19
  migrations_dir = "migrations"
20
20
 
21
+ # ════════════════════════════════════════════════════════════════════════════
22
+ # OPTIONAL: Analytics Engine for centralized logging
23
+ # ════════════════════════════════════════════════════════════════════════════
24
+ # To enable Analytics Engine:
25
+ # 1. Create dataset in Cloudflare Dashboard: Workers & Pages > Analytics Engine
26
+ # 2. Uncomment the binding below
27
+ # 3. Add CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN to .dev.vars
28
+ # 4. Uncomment the Analytics Engine code in src/index.ts
29
+ #
30
+ # [[analytics_engine_datasets]]
31
+ # binding = "AUTH_LOGS"
32
+ # dataset = "authhero_logs"
33
+
34
+ # ════════════════════════════════════════════════════════════════════════════
35
+ # OPTIONAL: Rate Limiting
36
+ # ════════════════════════════════════════════════════════════════════════════
37
+ # To enable Rate Limiting:
38
+ # 1. Rate limiting is available on Workers Paid plan ($5/month)
39
+ # 2. Uncomment the binding below
40
+ # 3. Implement rate limiting logic in src/index.ts
41
+ #
42
+ # [[unsafe.bindings]]
43
+ # name = "RATE_LIMITER"
44
+ # type = "ratelimit"
45
+ # namespace_id = "1001" # Unique namespace ID for this limiter
46
+ # simple = { limit = 100, period = 60 } # 100 requests per 60 seconds
47
+
21
48
  # Optional: Enable observability
22
49
  # [observability]
23
50
  # enabled = true
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
- import { Command as I } from "commander";
3
- import m from "inquirer";
2
+ import { Command as x } from "commander";
3
+ import c from "inquirer";
4
4
  import i from "fs";
5
5
  import f from "path";
6
- import { spawn as A } from "child_process";
7
- const b = new I(), l = {
6
+ import { spawn as b } from "child_process";
7
+ const D = new x(), n = {
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: (n) => ({
13
- name: n,
12
+ packageJson: (r) => ({
13
+ name: r,
14
14
  version: "1.0.0",
15
15
  type: "module",
16
16
  scripts: {
@@ -42,8 +42,8 @@ const b = new I(), l = {
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: (n) => ({
46
- name: n,
45
+ packageJson: (r) => ({
46
+ name: r,
47
47
  version: "1.0.0",
48
48
  type: "module",
49
49
  scripts: {
@@ -80,49 +80,53 @@ const b = new I(), l = {
80
80
  },
81
81
  "cloudflare-multitenant": {
82
82
  name: "Cloudflare Multi-Tenant (Production)",
83
- description: "Production-grade multi-tenant setup with per-tenant D1 databases and Analytics Engine",
83
+ description: "Production-grade multi-tenant setup with D1 database and tenant management",
84
84
  templateDir: "cloudflare-multitenant",
85
- packageJson: (n) => ({
86
- name: n,
85
+ packageJson: (r) => ({
86
+ name: r,
87
87
  version: "1.0.0",
88
88
  type: "module",
89
89
  scripts: {
90
- dev: "wrangler dev",
90
+ "dev:local": "wrangler dev --port 3000 --local-protocol https",
91
+ "dev:remote": "wrangler dev --port 3000 --local-protocol https --remote",
92
+ dev: "wrangler dev --port 3000 --local-protocol https",
91
93
  deploy: "wrangler deploy",
92
- "db:migrate": "wrangler d1 migrations apply MAIN_DB --local",
93
- "db:migrate:prod": "wrangler d1 migrations apply MAIN_DB --remote",
94
- seed: "wrangler d1 execute MAIN_DB --local --file=seed.sql"
94
+ "db:migrate:local": "wrangler d1 migrations apply AUTH_DB --local",
95
+ "db:migrate:remote": "wrangler d1 migrations apply AUTH_DB --remote",
96
+ migrate: "wrangler d1 migrations apply AUTH_DB --local",
97
+ "db:generate": "drizzle-kit generate",
98
+ "seed:local": "node seed-helper.js",
99
+ "seed:remote": "node seed-helper.js '' '' remote",
100
+ seed: "node seed-helper.js"
95
101
  },
96
102
  dependencies: {
97
- "@authhero/cloudflare-adapter": "latest",
98
103
  "@authhero/kysely-adapter": "latest",
99
- "@authhero/multi-tenancy": "latest",
100
104
  "@hono/swagger-ui": "^0.5.0",
101
- "@hono/zod-openapi": "^0.19.10",
105
+ "@hono/zod-openapi": "^0.19.0",
102
106
  authhero: "latest",
103
107
  hono: "^4.6.0",
104
108
  kysely: "latest",
105
- "kysely-d1": "latest",
106
- wretch: "^3.0.0"
109
+ "kysely-d1": "latest"
107
110
  },
108
111
  devDependencies: {
109
112
  "@cloudflare/workers-types": "^4.0.0",
113
+ "drizzle-kit": "^0.31.0",
114
+ "drizzle-orm": "^0.44.0",
110
115
  typescript: "^5.5.0",
111
116
  wrangler: "^3.0.0"
112
117
  }
113
118
  }),
114
- seedFile: "seed.sql"
119
+ seedFile: "seed.ts"
115
120
  }
116
121
  };
117
- function D(n, e) {
118
- i.readdirSync(n).forEach((o) => {
119
- const t = f.join(n, o), a = f.join(e, o);
120
- i.lstatSync(t).isDirectory() ? (i.mkdirSync(a, { recursive: !0 }), D(t, a)) : i.copyFileSync(t, a);
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);
121
126
  });
122
127
  }
123
- function $(n) {
124
- if (n === "local")
125
- return `import { SqliteDialect, Kysely } from "kysely";
128
+ function $() {
129
+ return `import { SqliteDialect, Kysely } from "kysely";
126
130
  import Database from "better-sqlite3";
127
131
  import createAdapters from "@authhero/kysely-adapter";
128
132
  import { seed } from "authhero";
@@ -154,109 +158,88 @@ async function main() {
154
158
 
155
159
  main().catch(console.error);
156
160
  `;
157
- {
158
- const e = (/* @__PURE__ */ new Date()).toISOString(), r = "default";
159
- return `-- Seed file for AuthHero
160
- --
161
- -- IMPORTANT: This SQL file creates the basic structure but the password
162
- -- cannot be properly hashed in SQL. After running this seed, you should
163
- -- use the management API or run a script to set the admin password.
164
-
165
- -- Create default tenant
166
- INSERT OR IGNORE INTO tenants (id, friendly_name, audience, sender_email, sender_name, created_at, updated_at)
167
- VALUES ('${r}', 'Default Tenant', 'https://api.example.com', 'noreply@example.com', 'AuthHero', '${e}', '${e}');
168
-
169
- -- Create password connection
170
- INSERT OR IGNORE INTO connections (id, tenant_id, name, strategy, options, created_at, updated_at)
171
- VALUES ('conn_default', '${r}', 'Username-Password-Authentication', 'Username-Password-Authentication', '{}', '${e}', '${e}');
172
-
173
- -- Create default client
174
- INSERT OR IGNORE INTO clients (client_id, tenant_id, name, callbacks, allowed_origins, web_origins, connections, created_at, updated_at)
175
- VALUES ('default', '${r}', 'Default Application', '["https://manage.authhero.net/auth-callback","https://local.authhero.net/auth-callback"]', '[]', '[]', '["Username-Password-Authentication"]', '${e}', '${e}');
176
-
177
- -- Note: Admin user and password should be created via the management API
178
- -- or using a TypeScript seed script with proper bcrypt hashing.
179
- -- Example command: curl -X POST http://localhost:3000/api/v2/users ...
180
- `;
181
- }
182
161
  }
183
- function v(n, e) {
184
- return new Promise((r, o) => {
185
- const t = A(n, [], {
186
- cwd: e,
162
+ function v(r, a) {
163
+ return new Promise((s, o) => {
164
+ const t = b(r, [], {
165
+ cwd: a,
187
166
  shell: !0,
188
167
  stdio: "inherit"
189
168
  });
190
- t.on("close", (a) => {
191
- a === 0 ? r() : o(new Error(`Command failed with exit code ${a}`));
169
+ t.on("close", (e) => {
170
+ e === 0 ? s() : o(new Error(`Command failed with exit code ${e}`));
192
171
  }), t.on("error", o);
193
172
  });
194
173
  }
195
- function S(n, e, r) {
174
+ function S(r, a, s) {
196
175
  return new Promise((o, t) => {
197
- const a = A(n, [], {
198
- cwd: e,
176
+ const e = b(r, [], {
177
+ cwd: a,
199
178
  shell: !0,
200
179
  stdio: "inherit",
201
- env: { ...process.env, ...r }
180
+ env: { ...process.env, ...s }
202
181
  });
203
- a.on("close", (g) => {
182
+ e.on("close", (g) => {
204
183
  g === 0 ? o() : t(new Error(`Command failed with exit code ${g}`));
205
- }), a.on("error", t);
184
+ }), e.on("error", t);
206
185
  });
207
186
  }
208
- b.version("1.0.0").description("Create a new AuthHero project").argument("[project-name]", "name of the project").option(
187
+ D.version("1.0.0").description("Create a new AuthHero project").argument("[project-name]", "name of the project").option(
209
188
  "-t, --template <type>",
210
189
  "template type: local, cloudflare-simple, or cloudflare-multitenant"
211
190
  ).option("-e, --email <email>", "admin email address").option("-p, --password <password>", "admin password (min 8 characters)").option(
212
191
  "--package-manager <pm>",
213
192
  "package manager to use: npm, yarn, pnpm, or bun"
214
- ).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 (n, e) => {
215
- const r = e.yes === !0;
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;
216
195
  console.log(`
217
196
  🔐 Welcome to AuthHero!
218
197
  `);
219
- let o = n;
220
- o || (r ? (o = "auth-server", console.log(`Using default project name: ${o}`)) : o = (await m.prompt([
198
+ let o = r;
199
+ o || (s ? (o = "auth-server", console.log(`Using default project name: ${o}`)) : o = (await c.prompt([
221
200
  {
222
201
  type: "input",
223
202
  name: "projectName",
224
203
  message: "Project name:",
225
204
  default: "auth-server",
226
- validate: (d) => d !== "" || "Project name cannot be empty"
205
+ validate: (p) => p !== "" || "Project name cannot be empty"
227
206
  }
228
207
  ])).projectName);
229
208
  const t = f.join(process.cwd(), o);
230
209
  i.existsSync(t) && (console.error(`❌ Project "${o}" already exists.`), process.exit(1));
231
- let a;
232
- e.template ? (["local", "cloudflare-simple", "cloudflare-multitenant"].includes(e.template) || (console.error(`❌ Invalid template: ${e.template}`), console.error("Valid options: local, cloudflare-simple, cloudflare-multitenant"), process.exit(1)), a = e.template, console.log(`Using template: ${l[a].name}`)) : a = (await m.prompt([
210
+ let e;
211
+ a.template ? (["local", "cloudflare-simple", "cloudflare-multitenant"].includes(
212
+ a.template
213
+ ) || (console.error(`❌ Invalid template: ${a.template}`), console.error(
214
+ "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([
233
216
  {
234
217
  type: "list",
235
218
  name: "setupType",
236
219
  message: "Select your setup type:",
237
220
  choices: [
238
221
  {
239
- name: `${l.local.name}
240
- ${l.local.description}`,
222
+ name: `${n.local.name}
223
+ ${n.local.description}`,
241
224
  value: "local",
242
- short: l.local.name
225
+ short: n.local.name
243
226
  },
244
227
  {
245
- name: `${l["cloudflare-simple"].name}
246
- ${l["cloudflare-simple"].description}`,
228
+ name: `${n["cloudflare-simple"].name}
229
+ ${n["cloudflare-simple"].description}`,
247
230
  value: "cloudflare-simple",
248
- short: l["cloudflare-simple"].name
231
+ short: n["cloudflare-simple"].name
249
232
  },
250
233
  {
251
- name: `${l["cloudflare-multitenant"].name}
252
- ${l["cloudflare-multitenant"].description}`,
234
+ name: `${n["cloudflare-multitenant"].name}
235
+ ${n["cloudflare-multitenant"].description}`,
253
236
  value: "cloudflare-multitenant",
254
- short: l["cloudflare-multitenant"].name
237
+ short: n["cloudflare-multitenant"].name
255
238
  }
256
239
  ]
257
240
  }
258
241
  ])).setupType;
259
- const g = l[a];
242
+ const g = n[e];
260
243
  i.mkdirSync(t, { recursive: !0 }), i.writeFileSync(
261
244
  f.join(t, "package.json"),
262
245
  JSON.stringify(g.packageJson(o), null, 2)
@@ -265,9 +248,9 @@ b.version("1.0.0").description("Create a new AuthHero project").argument("[proje
265
248
  import.meta.url.replace("file://", "").replace("/create-authhero.js", ""),
266
249
  g.templateDir
267
250
  );
268
- if (i.existsSync(k) ? D(k, t) : (console.error(`❌ Template directory not found: ${k}`), process.exit(1)), a === "local" || a === "cloudflare-multitenant") {
269
- const s = $(a), d = a === "local" ? "src/seed.ts" : "seed.sql";
270
- i.writeFileSync(f.join(t, d), s);
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);
271
254
  }
272
255
  console.log(
273
256
  `
@@ -275,7 +258,7 @@ b.version("1.0.0").description("Create a new AuthHero project").argument("[proje
275
258
  `
276
259
  );
277
260
  let h;
278
- if (e.skipInstall ? h = !1 : r ? h = !0 : h = (await m.prompt([
261
+ if (a.skipInstall ? h = !1 : s ? h = !0 : h = (await c.prompt([
279
262
  {
280
263
  type: "confirm",
281
264
  name: "shouldInstall",
@@ -283,8 +266,10 @@ b.version("1.0.0").description("Create a new AuthHero project").argument("[proje
283
266
  default: !0
284
267
  }
285
268
  ])).shouldInstall, h) {
286
- let s;
287
- e.packageManager ? (["npm", "yarn", "pnpm", "bun"].includes(e.packageManager) || (console.error(`❌ Invalid package manager: ${e.packageManager}`), console.error("Valid options: npm, yarn, pnpm, bun"), process.exit(1)), s = e.packageManager) : r ? s = "npm" : s = (await m.prompt([
269
+ 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 = "npm" : l = (await c.prompt([
288
273
  {
289
274
  type: "list",
290
275
  name: "packageManager",
@@ -298,18 +283,18 @@ b.version("1.0.0").description("Create a new AuthHero project").argument("[proje
298
283
  default: "npm"
299
284
  }
300
285
  ])).packageManager, console.log(`
301
- 📦 Installing dependencies with ${s}...
286
+ 📦 Installing dependencies with ${l}...
302
287
  `);
303
288
  try {
304
- const d = s === "pnpm" ? "pnpm install --ignore-workspace" : `${s} install`;
305
- await v(d, t), a === "local" && (console.log(`
289
+ const p = l === "pnpm" ? "pnpm install --ignore-workspace" : `${l} install`;
290
+ await v(p, t), e === "local" && (console.log(`
306
291
  🔧 Building native modules...
307
292
  `), await v("npm rebuild better-sqlite3", t)), console.log(`
308
293
  ✅ Dependencies installed successfully!
309
294
  `);
310
- let w = e.remote ? "remote" : "local";
311
- if (a === "local" || a === "cloudflare-simple") {
312
- a === "cloudflare-simple" && !r && !e.remote && (w = (await m.prompt([
295
+ let w = a.remote ? "remote" : "local";
296
+ if (e === "local" || e === "cloudflare-simple" || e === "cloudflare-multitenant") {
297
+ (e === "cloudflare-simple" || e === "cloudflare-multitenant") && !s && !a.remote && (w = (await c.prompt([
313
298
  {
314
299
  type: "list",
315
300
  name: "mode",
@@ -330,7 +315,7 @@ b.version("1.0.0").description("Create a new AuthHero project").argument("[proje
330
315
  }
331
316
  ])).mode);
332
317
  let u;
333
- if (e.skipMigrate && e.skipSeed ? u = !1 : r ? u = !e.skipMigrate || !e.skipSeed : u = (await m.prompt([
318
+ if (a.skipMigrate && a.skipSeed ? u = !1 : s ? u = !a.skipMigrate || !a.skipSeed : u = (await c.prompt([
334
319
  {
335
320
  type: "confirm",
336
321
  name: "shouldSetup",
@@ -338,55 +323,55 @@ b.version("1.0.0").description("Create a new AuthHero project").argument("[proje
338
323
  default: !0
339
324
  }
340
325
  ])).shouldSetup, u) {
341
- let c;
342
- if (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)), c = {
343
- username: e.email,
344
- password: e.password
345
- }, console.log(`Using admin email: ${e.email}`)) : c = await m.prompt([
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([
346
331
  {
347
332
  type: "input",
348
333
  name: "username",
349
334
  message: "Admin email:",
350
335
  default: "admin@example.com",
351
- validate: (p) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(p) || "Please enter a valid email address"
336
+ validate: (m) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(m) || "Please enter a valid email address"
352
337
  },
353
338
  {
354
339
  type: "password",
355
340
  name: "password",
356
341
  message: "Admin password:",
357
342
  mask: "*",
358
- validate: (p) => p.length < 8 ? "Password must be at least 8 characters" : !0
343
+ validate: (m) => m.length < 8 ? "Password must be at least 8 characters" : !0
359
344
  }
360
- ]), !e.skipMigrate) {
345
+ ]), !a.skipMigrate) {
361
346
  console.log(`
362
347
  🔄 Running migrations...
363
348
  `);
364
- const p = a === "cloudflare-simple" && w === "remote" ? `${s} run db:migrate:remote` : `${s} run migrate`;
365
- await v(p, t);
349
+ const m = (e === "cloudflare-simple" || e === "cloudflare-multitenant") && w === "remote" ? `${l} run db:migrate:remote` : `${l} run migrate`;
350
+ await v(m, t);
366
351
  }
367
- if (!e.skipSeed)
352
+ if (!a.skipSeed)
368
353
  if (console.log(`
369
354
  🌱 Seeding database...
370
- `), a === "local")
355
+ `), e === "local")
371
356
  await S(
372
- `${s} run seed`,
357
+ `${l} run seed`,
373
358
  t,
374
359
  {
375
- ADMIN_EMAIL: c.username,
376
- ADMIN_PASSWORD: c.password
360
+ ADMIN_EMAIL: d.username,
361
+ ADMIN_PASSWORD: d.password
377
362
  }
378
363
  );
379
364
  else {
380
- const p = w === "remote" ? `${s} run seed:remote` : `${s} run seed:local`;
381
- await S(p, t, {
382
- ADMIN_EMAIL: c.username,
383
- ADMIN_PASSWORD: c.password
365
+ const m = w === "remote" ? `${l} run seed:remote` : `${l} run seed:local`;
366
+ await S(m, t, {
367
+ ADMIN_EMAIL: d.username,
368
+ ADMIN_PASSWORD: d.password
384
369
  });
385
370
  }
386
371
  }
387
372
  }
388
373
  let y;
389
- if (e.skipStart || r ? y = !1 : y = (await m.prompt([
374
+ if (a.skipStart || s ? y = !1 : y = (await c.prompt([
390
375
  {
391
376
  type: "confirm",
392
377
  name: "shouldStart",
@@ -394,30 +379,34 @@ b.version("1.0.0").description("Create a new AuthHero project").argument("[proje
394
379
  default: !0
395
380
  }
396
381
  ])).shouldStart, y) {
397
- console.log(`
382
+ console.log(
383
+ `
398
384
  🚀 Starting development server on https://localhost:3000 ...
399
- `);
400
- const u = a === "cloudflare-simple" && w === "remote" ? `${s} run dev:remote` : `${s} run dev`;
385
+ `
386
+ );
387
+ const u = (e === "cloudflare-simple" || e === "cloudflare-multitenant") && w === "remote" ? `${l} run dev:remote` : `${l} run dev`;
401
388
  await v(u, t);
402
389
  }
403
- r && !y && (console.log(`
390
+ s && !y && (console.log(`
404
391
  ✅ Setup complete!`), console.log(`
405
- To start the development server:`), console.log(` cd ${o}`), console.log(a === "cloudflare-simple" && w === "remote" ? " npm run dev:remote" : " npm run dev"), a === "cloudflare-simple" && console.log(`
406
- Server will be available at: https://localhost:3000`));
407
- } catch (d) {
392
+ To start the development server:`), console.log(` cd ${o}`), console.log((e === "cloudflare-simple" || e === "cloudflare-multitenant") && w === "remote" ? " npm run dev:remote" : " npm run dev"), (e === "cloudflare-simple" || e === "cloudflare-multitenant") && console.log(
393
+ `
394
+ Server will be available at: https://localhost:3000`
395
+ ));
396
+ } catch (p) {
408
397
  console.error(`
409
- ❌ An error occurred:`, d), process.exit(1);
398
+ ❌ An error occurred:`, p), process.exit(1);
410
399
  }
411
400
  }
412
- h || (console.log("Next steps:"), console.log(` cd ${o}`), a === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(
401
+ h || (console.log("Next steps:"), console.log(` cd ${o}`), e === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(
413
402
  " ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed"
414
- ), console.log(" npm run dev")) : a === "cloudflare-simple" ? (console.log(" npm install"), console.log(
403
+ ), console.log(" npm run dev")) : (e === "cloudflare-simple" || e === "cloudflare-multitenant") && (console.log(" npm install"), console.log(
415
404
  " npm run migrate # or npm run db:migrate:remote for production"
416
405
  ), console.log(
417
406
  " ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed"
418
407
  ), console.log(" npm run dev # or npm run dev:remote for production"), console.log(`
419
- Server will be available at: https://localhost:3000`)) : (console.log(" npm install"), console.log(" npm run db:migrate"), console.log(" npm run seed"), console.log(" npm run dev")), console.log(`
408
+ Server will be available at: https://localhost:3000`)), console.log(`
420
409
  For more information, visit: https://authhero.net/docs
421
410
  `));
422
411
  });
423
- b.parse(process.argv);
412
+ 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.8.0",
8
+ "version": "0.10.0",
9
9
  "type": "module",
10
10
  "main": "dist/create-authhero.js",
11
11
  "bin": {