create-authhero 0.18.0 → 0.20.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.
@@ -59,6 +59,25 @@ try {
59
59
 
60
60
  copyDirectory(sourceDir, targetDir);
61
61
 
62
+ // Also copy widget files from @authhero/widget package
63
+ const widgetSourceDir = path.join(
64
+ __dirname,
65
+ "node_modules",
66
+ "@authhero",
67
+ "widget",
68
+ "dist",
69
+ "authhero-widget",
70
+ );
71
+ const widgetTargetDir = path.join(targetDir, "u", "widget");
72
+
73
+ if (fs.existsSync(widgetSourceDir)) {
74
+ console.log("📦 Copying widget assets...");
75
+ copyDirectory(widgetSourceDir, widgetTargetDir);
76
+ } else {
77
+ console.warn(`⚠️ Widget directory not found: ${widgetSourceDir}`);
78
+ console.warn("Widget features may not work. Install @authhero/widget to enable.");
79
+ }
80
+
62
81
  console.log(`✅ Assets copied to ${targetDir}`);
63
82
  } catch (error) {
64
83
  console.error("❌ Error copying assets:", error.message);
@@ -1,29 +1,65 @@
1
1
  import { Context } from "hono";
2
2
  import { HTTPException } from "hono/http-exception";
3
3
  import { swaggerUI } from "@hono/swagger-ui";
4
+ import { init, AuthHeroConfig, fetchAll } from "authhero";
4
5
  import {
5
- init,
6
- MultiTenantAuthHeroConfig,
7
- DataAdapters,
6
+ createSyncHooks,
7
+ createTenantsOpenAPIRouter,
8
+ createProtectSyncedMiddleware,
8
9
  } from "@authhero/multi-tenancy";
10
+ import { DataAdapters } from "@authhero/adapter-interfaces";
9
11
 
10
12
  // Control plane tenant ID - the tenant that manages all other tenants
11
13
  const CONTROL_PLANE_TENANT_ID = "control_plane";
12
14
 
13
- export default function createApp(
14
- config: Omit<MultiTenantAuthHeroConfig, "controlPlaneTenantId"> & {
15
- dataAdapter: DataAdapters;
16
- },
17
- ) {
15
+ export default function createApp(config: AuthHeroConfig & { dataAdapter: DataAdapters }) {
16
+ // Create sync hooks for syncing entities from control plane to child tenants
17
+ const { entityHooks, tenantHooks } = createSyncHooks({
18
+ controlPlaneTenantId: CONTROL_PLANE_TENANT_ID,
19
+ getChildTenantIds: async () => {
20
+ const allTenants = await fetchAll<{ id: string }>(
21
+ (params) => config.dataAdapter.tenants.list(params),
22
+ "tenants",
23
+ { cursorField: "id", pageSize: 100 },
24
+ );
25
+ return allTenants
26
+ .filter((t) => t.id !== CONTROL_PLANE_TENANT_ID)
27
+ .map((t) => t.id);
28
+ },
29
+ getAdapters: async () => config.dataAdapter,
30
+ getControlPlaneAdapters: async () => config.dataAdapter,
31
+ sync: {
32
+ resourceServers: true,
33
+ roles: true,
34
+ connections: true,
35
+ },
36
+ });
37
+
38
+ // Create tenants router
39
+ const tenantsRouter = createTenantsOpenAPIRouter(
40
+ {
41
+ accessControl: {
42
+ controlPlaneTenantId: CONTROL_PLANE_TENANT_ID,
43
+ requireOrganizationMatch: false,
44
+ defaultPermissions: ["tenant:admin"],
45
+ },
46
+ },
47
+ { tenants: tenantHooks },
48
+ );
49
+
50
+ // Initialize AuthHero with sync hooks and tenant routes
18
51
  const { app } = init({
19
52
  ...config,
20
- controlPlaneTenantId: CONTROL_PLANE_TENANT_ID,
21
- // Sync resource servers from control plane tenant to all child tenants
22
- syncResourceServers: true,
23
- // Sync roles from control plane tenant to all child tenants
24
- syncRoles: true,
53
+ entityHooks,
54
+ managementApiExtensions: [
55
+ ...(config.managementApiExtensions || []),
56
+ { path: "/tenants", router: tenantsRouter },
57
+ ],
25
58
  });
26
59
 
60
+ // Add middleware to protect synced entities from modification on child tenants
61
+ app.use("/api/v2/*", createProtectSyncedMiddleware());
62
+
27
63
  app
28
64
  .onError((err, ctx) => {
29
65
  if (err instanceof HTTPException) {
@@ -3,7 +3,7 @@ import { Kysely } from "kysely";
3
3
  import createAdapters from "@authhero/kysely-adapter";
4
4
  import createApp from "./app";
5
5
  import { Env } from "./types";
6
- import { AuthHeroConfig } from "@authhero/multi-tenancy";
6
+ import { AuthHeroConfig } from "authhero";
7
7
 
8
8
  // ──────────────────────────────────────────────────────────────────────────────
9
9
  // OPTIONAL: Uncomment to enable Cloudflare adapters (Analytics Engine, etc.)
@@ -59,6 +59,25 @@ try {
59
59
 
60
60
  copyDirectory(sourceDir, targetDir);
61
61
 
62
+ // Also copy widget files from @authhero/widget package
63
+ const widgetSourceDir = path.join(
64
+ __dirname,
65
+ "node_modules",
66
+ "@authhero",
67
+ "widget",
68
+ "dist",
69
+ "authhero-widget",
70
+ );
71
+ const widgetTargetDir = path.join(targetDir, "u", "widget");
72
+
73
+ if (fs.existsSync(widgetSourceDir)) {
74
+ console.log("📦 Copying widget assets...");
75
+ copyDirectory(widgetSourceDir, widgetTargetDir);
76
+ } else {
77
+ console.warn(`⚠️ Widget directory not found: ${widgetSourceDir}`);
78
+ console.warn("Widget features may not work. Install @authhero/widget to enable.");
79
+ }
80
+
62
81
  console.log(`✅ Assets copied to ${targetDir}`);
63
82
  } catch (error) {
64
83
  console.error("❌ Error copying assets:", error.message);
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command as A } from "commander";
3
3
  import m from "inquirer";
4
- import s from "fs";
4
+ import o from "fs";
5
5
  import i from "path";
6
6
  import { spawn as b } from "child_process";
7
7
  const D = new A(), c = {
@@ -9,8 +9,8 @@ const D = new A(), c = {
9
9
  name: "Local (SQLite)",
10
10
  description: "Local development setup with SQLite database - great for getting started",
11
11
  templateDir: "local",
12
- packageJson: (o) => ({
13
- name: o,
12
+ packageJson: (n) => ({
13
+ name: n,
14
14
  version: "1.0.0",
15
15
  type: "module",
16
16
  scripts: {
@@ -42,15 +42,16 @@ const D = new A(), c = {
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: (o) => ({
46
- name: o,
45
+ packageJson: (n) => ({
46
+ name: n,
47
47
  version: "1.0.0",
48
48
  type: "module",
49
49
  scripts: {
50
+ postinstall: "node copy-assets.js",
50
51
  "copy-assets": "node copy-assets.js",
51
- dev: "npm run copy-assets && wrangler dev --port 3000 --local-protocol https",
52
- "dev:remote": "npm run copy-assets && wrangler dev --port 3000 --local-protocol https --remote --config wrangler.local.toml",
53
- deploy: "npm run copy-assets && wrangler deploy --config wrangler.local.toml",
52
+ dev: "wrangler dev --port 3000 --local-protocol https",
53
+ "dev:remote": "wrangler dev --port 3000 --local-protocol https --remote --config wrangler.local.toml",
54
+ deploy: "wrangler deploy --config wrangler.local.toml",
54
55
  "db:migrate:local": "wrangler d1 migrations apply AUTH_DB --local",
55
56
  "db:migrate:remote": "wrangler d1 migrations apply AUTH_DB --remote --config wrangler.local.toml",
56
57
  migrate: "wrangler d1 migrations apply AUTH_DB --local",
@@ -62,6 +63,7 @@ const D = new A(), c = {
62
63
  dependencies: {
63
64
  "@authhero/drizzle": "latest",
64
65
  "@authhero/kysely-adapter": "latest",
66
+ "@authhero/widget": "latest",
65
67
  "@hono/swagger-ui": "^0.5.0",
66
68
  "@hono/zod-openapi": "^0.19.0",
67
69
  authhero: "latest",
@@ -83,15 +85,16 @@ const D = new A(), c = {
83
85
  name: "Cloudflare Multi-Tenant (Production)",
84
86
  description: "Production-grade multi-tenant setup with D1 database and tenant management",
85
87
  templateDir: "cloudflare-multitenant",
86
- packageJson: (o) => ({
87
- name: o,
88
+ packageJson: (n) => ({
89
+ name: n,
88
90
  version: "1.0.0",
89
91
  type: "module",
90
92
  scripts: {
93
+ postinstall: "node copy-assets.js",
91
94
  "copy-assets": "node copy-assets.js",
92
- dev: "npm run copy-assets && wrangler dev --port 3000 --local-protocol https",
93
- "dev:remote": "npm run copy-assets && wrangler dev --port 3000 --local-protocol https --remote --config wrangler.local.toml",
94
- deploy: "npm run copy-assets && wrangler deploy --config wrangler.local.toml",
95
+ dev: "wrangler dev --port 3000 --local-protocol https",
96
+ "dev:remote": "wrangler dev --port 3000 --local-protocol https --remote --config wrangler.local.toml",
97
+ deploy: "wrangler deploy --config wrangler.local.toml",
95
98
  "db:migrate:local": "wrangler d1 migrations apply AUTH_DB --local",
96
99
  "db:migrate:remote": "wrangler d1 migrations apply AUTH_DB --remote --config wrangler.local.toml",
97
100
  migrate: "wrangler d1 migrations apply AUTH_DB --local",
@@ -104,8 +107,10 @@ const D = new A(), c = {
104
107
  "@authhero/drizzle": "latest",
105
108
  "@authhero/kysely-adapter": "latest",
106
109
  "@authhero/multi-tenancy": "latest",
110
+ "@authhero/widget": "latest",
107
111
  "@hono/swagger-ui": "^0.5.0",
108
112
  "@hono/zod-openapi": "^0.19.0",
113
+ authhero: "latest",
109
114
  hono: "^4.6.0",
110
115
  kysely: "latest",
111
116
  "kysely-d1": "latest"
@@ -121,10 +126,10 @@ const D = new A(), c = {
121
126
  seedFile: "seed.ts"
122
127
  }
123
128
  };
124
- function j(o, e) {
125
- s.readdirSync(o).forEach((n) => {
126
- const a = i.join(o, n), t = i.join(e, n);
127
- s.lstatSync(a).isDirectory() ? (s.mkdirSync(t, { recursive: !0 }), j(a, t)) : s.copyFileSync(a, t);
129
+ function j(n, e) {
130
+ o.readdirSync(n).forEach((s) => {
131
+ const a = i.join(n, s), t = i.join(e, s);
132
+ o.lstatSync(a).isDirectory() ? (o.mkdirSync(t, { recursive: !0 }), j(a, t)) : o.copyFileSync(a, t);
128
133
  });
129
134
  }
130
135
  function I() {
@@ -161,9 +166,9 @@ async function main() {
161
166
  main().catch(console.error);
162
167
  `;
163
168
  }
164
- function x(o) {
165
- const e = i.join(o, ".github", "workflows");
166
- s.mkdirSync(e, { recursive: !0 });
169
+ function x(n) {
170
+ const e = i.join(n, ".github", "workflows");
171
+ o.mkdirSync(e, { recursive: !0 });
167
172
  const r = `name: Unit tests
168
173
 
169
174
  on: push
@@ -185,7 +190,7 @@ jobs:
185
190
 
186
191
  - run: npm run type-check
187
192
  - run: npm test
188
- `, n = `name: Deploy to Dev
193
+ `, s = `name: Deploy to Dev
189
194
 
190
195
  on:
191
196
  push:
@@ -250,9 +255,9 @@ jobs:
250
255
  apiToken: \${{ secrets.PROD_CLOUDFLARE_API_TOKEN }}
251
256
  command: deploy --env production
252
257
  `;
253
- s.writeFileSync(i.join(e, "unit-tests.yml"), r), s.writeFileSync(i.join(e, "deploy-dev.yml"), n), s.writeFileSync(i.join(e, "release.yml"), a), console.log("\\n📦 GitHub CI workflows created!");
258
+ o.writeFileSync(i.join(e, "unit-tests.yml"), r), o.writeFileSync(i.join(e, "deploy-dev.yml"), s), o.writeFileSync(i.join(e, "release.yml"), a), console.log("\\n📦 GitHub CI workflows created!");
254
259
  }
255
- function C(o) {
260
+ function C(n) {
256
261
  const e = {
257
262
  branches: ["main"],
258
263
  plugins: [
@@ -261,42 +266,42 @@ function C(o) {
261
266
  "@semantic-release/github"
262
267
  ]
263
268
  };
264
- s.writeFileSync(
265
- i.join(o, ".releaserc.json"),
269
+ o.writeFileSync(
270
+ i.join(n, ".releaserc.json"),
266
271
  JSON.stringify(e, null, 2)
267
272
  );
268
- const r = i.join(o, "package.json"), n = JSON.parse(s.readFileSync(r, "utf-8"));
269
- n.devDependencies = {
270
- ...n.devDependencies,
273
+ const r = i.join(n, "package.json"), s = JSON.parse(o.readFileSync(r, "utf-8"));
274
+ s.devDependencies = {
275
+ ...s.devDependencies,
271
276
  "semantic-release": "^24.0.0"
272
- }, n.scripts = {
273
- ...n.scripts,
277
+ }, s.scripts = {
278
+ ...s.scripts,
274
279
  test: 'echo "No tests yet"',
275
280
  "type-check": "tsc --noEmit"
276
- }, s.writeFileSync(r, JSON.stringify(n, null, 2));
281
+ }, o.writeFileSync(r, JSON.stringify(s, null, 2));
277
282
  }
278
- function v(o, e) {
279
- return new Promise((r, n) => {
280
- const a = b(o, [], {
283
+ function v(n, e) {
284
+ return new Promise((r, s) => {
285
+ const a = b(n, [], {
281
286
  cwd: e,
282
287
  shell: !0,
283
288
  stdio: "inherit"
284
289
  });
285
290
  a.on("close", (t) => {
286
- t === 0 ? r() : n(new Error(`Command failed with exit code ${t}`));
287
- }), a.on("error", n);
291
+ t === 0 ? r() : s(new Error(`Command failed with exit code ${t}`));
292
+ }), a.on("error", s);
288
293
  });
289
294
  }
290
- function S(o, e, r) {
291
- return new Promise((n, a) => {
292
- const t = b(o, [], {
295
+ function S(n, e, r) {
296
+ return new Promise((s, a) => {
297
+ const t = b(n, [], {
293
298
  cwd: e,
294
299
  shell: !0,
295
300
  stdio: "inherit",
296
301
  env: { ...process.env, ...r }
297
302
  });
298
303
  t.on("close", (f) => {
299
- f === 0 ? n() : a(new Error(`Command failed with exit code ${f}`));
304
+ f === 0 ? s() : a(new Error(`Command failed with exit code ${f}`));
300
305
  }), t.on("error", a);
301
306
  });
302
307
  }
@@ -306,23 +311,23 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
306
311
  ).option("-e, --email <email>", "admin email address").option("-p, --password <password>", "admin password (min 8 characters)").option(
307
312
  "--package-manager <pm>",
308
313
  "package manager to use: npm, yarn, pnpm, or bun"
309
- ).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 (o, e) => {
314
+ ).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 (n, e) => {
310
315
  const r = e.yes === !0;
311
316
  console.log(`
312
317
  🔐 Welcome to AuthHero!
313
318
  `);
314
- let n = o;
315
- n || (r ? (n = "auth-server", console.log(`Using default project name: ${n}`)) : n = (await m.prompt([
319
+ let s = n;
320
+ s || (r ? (s = "auth-server", console.log(`Using default project name: ${s}`)) : s = (await m.prompt([
316
321
  {
317
322
  type: "input",
318
323
  name: "projectName",
319
324
  message: "Project name:",
320
325
  default: "auth-server",
321
- validate: (p) => p !== "" || "Project name cannot be empty"
326
+ validate: (d) => d !== "" || "Project name cannot be empty"
322
327
  }
323
328
  ])).projectName);
324
- const a = i.join(process.cwd(), n);
325
- s.existsSync(a) && (console.error(`❌ Project "${n}" already exists.`), process.exit(1));
329
+ const a = i.join(process.cwd(), s);
330
+ o.existsSync(a) && (console.error(`❌ Project "${s}" already exists.`), process.exit(1));
326
331
  let t;
327
332
  e.template ? (["local", "cloudflare-simple", "cloudflare-multitenant"].includes(
328
333
  e.template
@@ -356,37 +361,37 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
356
361
  }
357
362
  ])).setupType;
358
363
  const f = c[t];
359
- s.mkdirSync(a, { recursive: !0 }), s.writeFileSync(
364
+ o.mkdirSync(a, { recursive: !0 }), o.writeFileSync(
360
365
  i.join(a, "package.json"),
361
- JSON.stringify(f.packageJson(n), null, 2)
366
+ JSON.stringify(f.packageJson(s), null, 2)
362
367
  );
363
368
  const k = i.join(
364
369
  import.meta.url.replace("file://", "").replace("/create-authhero.js", ""),
365
370
  f.templateDir
366
371
  );
367
- if (s.existsSync(k) ? j(k, a) : (console.error(`❌ Template directory not found: ${k}`), process.exit(1)), t === "cloudflare-simple" || t === "cloudflare-multitenant") {
368
- const l = i.join(a, "wrangler.toml"), p = i.join(a, "wrangler.local.toml");
369
- s.existsSync(l) && s.copyFileSync(l, p);
370
- const d = i.join(a, ".dev.vars.example"), u = i.join(a, ".dev.vars");
371
- s.existsSync(d) && s.copyFileSync(d, u), console.log(
372
+ if (o.existsSync(k) ? j(k, a) : (console.error(`❌ Template directory not found: ${k}`), process.exit(1)), t === "cloudflare-simple" || t === "cloudflare-multitenant") {
373
+ const l = i.join(a, "wrangler.toml"), d = i.join(a, "wrangler.local.toml");
374
+ o.existsSync(l) && o.copyFileSync(l, d);
375
+ const p = i.join(a, ".dev.vars.example"), u = i.join(a, ".dev.vars");
376
+ o.existsSync(p) && o.copyFileSync(p, u), console.log(
372
377
  "📁 Created wrangler.local.toml and .dev.vars for local development"
373
378
  );
374
379
  }
375
- let y = !1;
376
- if ((t === "cloudflare-simple" || t === "cloudflare-multitenant") && (e.githubCi !== void 0 ? (y = e.githubCi, y && console.log("Including GitHub CI workflows with semantic versioning")) : r || (y = (await m.prompt([
380
+ let w = !1;
381
+ 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([
377
382
  {
378
383
  type: "confirm",
379
384
  name: "includeGithubCi",
380
385
  message: "Would you like to include GitHub CI with semantic versioning?",
381
386
  default: !1
382
387
  }
383
- ])).includeGithubCi), y && (x(a), C(a))), t === "local") {
388
+ ])).includeGithubCi), w && (x(a), C(a))), t === "local") {
384
389
  const l = I();
385
- s.writeFileSync(i.join(a, "src/seed.ts"), l);
390
+ o.writeFileSync(i.join(a, "src/seed.ts"), l);
386
391
  }
387
392
  console.log(
388
393
  `
389
- ✅ Project "${n}" has been created with ${f.name} setup!
394
+ ✅ Project "${s}" has been created with ${f.name} setup!
390
395
  `
391
396
  );
392
397
  let h;
@@ -418,8 +423,8 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
418
423
  📦 Installing dependencies with ${l}...
419
424
  `);
420
425
  try {
421
- const p = l === "pnpm" ? "pnpm install --ignore-workspace" : `${l} install`;
422
- if (await v(p, a), t === "local" && (console.log(`
426
+ const d = l === "pnpm" ? "pnpm install --ignore-workspace" : `${l} install`;
427
+ if (await v(d, a), t === "local" && (console.log(`
423
428
  🔧 Building native modules...
424
429
  `), await v("npm rebuild better-sqlite3", a)), console.log(`
425
430
  ✅ Dependencies installed successfully!
@@ -443,14 +448,14 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
443
448
  name: "username",
444
449
  message: "Admin email:",
445
450
  default: "admin@example.com",
446
- validate: (w) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(w) || "Please enter a valid email address"
451
+ validate: (y) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(y) || "Please enter a valid email address"
447
452
  },
448
453
  {
449
454
  type: "password",
450
455
  name: "password",
451
456
  message: "Admin password:",
452
457
  mask: "*",
453
- validate: (w) => w.length < 8 ? "Password must be at least 8 characters" : !0
458
+ validate: (y) => y.length < 8 ? "Password must be at least 8 characters" : !0
454
459
  }
455
460
  ]), e.skipMigrate || (console.log(`
456
461
  🔄 Running migrations...
@@ -473,30 +478,30 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
473
478
  ));
474
479
  }
475
480
  }
476
- let d;
477
- e.skipStart || r ? d = !1 : d = (await m.prompt([
481
+ let p;
482
+ e.skipStart || r ? p = !1 : p = (await m.prompt([
478
483
  {
479
484
  type: "confirm",
480
485
  name: "shouldStart",
481
486
  message: "Would you like to start the development server?",
482
487
  default: !0
483
488
  }
484
- ])).shouldStart, d && (console.log(
489
+ ])).shouldStart, p && (console.log(
485
490
  `
486
491
  🚀 Starting development server on https://localhost:3000 ...
487
492
  `
488
- ), await v(`${l} run dev`, a)), r && !d && (console.log(`
493
+ ), await v(`${l} run dev`, a)), r && !p && (console.log(`
489
494
  ✅ Setup complete!`), console.log(`
490
- To start the development server:`), console.log(` cd ${n}`), console.log(" npm run dev"), (t === "cloudflare-simple" || t === "cloudflare-multitenant") && console.log(
495
+ To start the development server:`), console.log(` cd ${s}`), console.log(" npm run dev"), (t === "cloudflare-simple" || t === "cloudflare-multitenant") && console.log(
491
496
  `
492
497
  Server will be available at: https://localhost:3000`
493
498
  ));
494
- } catch (p) {
499
+ } catch (d) {
495
500
  console.error(`
496
- ❌ An error occurred:`, p), process.exit(1);
501
+ ❌ An error occurred:`, d), process.exit(1);
497
502
  }
498
503
  }
499
- h || (console.log("Next steps:"), console.log(` cd ${n}`), t === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(
504
+ h || (console.log("Next steps:"), console.log(` cd ${s}`), t === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(
500
505
  " ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed"
501
506
  ), console.log(" npm run dev")) : (t === "cloudflare-simple" || t === "cloudflare-multitenant") && (console.log(" npm install"), console.log(
502
507
  " npm run migrate # or npm run db:migrate:remote for production"
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.18.0",
8
+ "version": "0.20.0",
9
9
  "type": "module",
10
10
  "main": "dist/create-authhero.js",
11
11
  "bin": {