create-authhero 0.40.0 → 0.41.1

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.
@@ -1,18 +1,19 @@
1
1
  #!/usr/bin/env node
2
- import { Command as P } from "commander";
2
+ import { Command as R } from "commander";
3
3
  import m from "inquirer";
4
- import a from "fs";
5
- import i from "path";
6
- import { spawn as E } from "child_process";
7
- const D = new P(), p = {
4
+ import i from "fs";
5
+ import s from "path";
6
+ import { fileURLToPath as O } from "url";
7
+ import { spawn as U } from "child_process";
8
+ const T = new R(), p = {
8
9
  local: {
9
10
  name: "Local (SQLite)",
10
11
  description: "Local development setup with SQLite database - great for getting started",
11
12
  templateDir: "local",
12
- packageJson: (s, e, o, r, n) => {
13
+ packageJson: (a, e, o, r, n) => {
13
14
  const t = r ? "workspace:*" : "latest";
14
15
  return {
15
- name: s,
16
+ name: a,
16
17
  version: "1.0.0",
17
18
  type: "module",
18
19
  scripts: {
@@ -49,10 +50,10 @@ const D = new P(), p = {
49
50
  name: "Cloudflare Workers (D1)",
50
51
  description: "Cloudflare Workers setup with D1 database",
51
52
  templateDir: "cloudflare",
52
- packageJson: (s, e, o, r, n) => {
53
+ packageJson: (a, e, o, r, n) => {
53
54
  const t = r ? "workspace:*" : "latest";
54
55
  return {
55
- name: s,
56
+ name: a,
56
57
  version: "1.0.0",
57
58
  type: "module",
58
59
  scripts: {
@@ -98,10 +99,10 @@ const D = new P(), p = {
98
99
  name: "AWS SST (Lambda + DynamoDB)",
99
100
  description: "Serverless AWS deployment with Lambda, DynamoDB, and SST",
100
101
  templateDir: "aws-sst",
101
- packageJson: (s, e, o, r, n) => {
102
+ packageJson: (a, e, o, r, n) => {
102
103
  const t = r ? "workspace:*" : "latest";
103
104
  return {
104
- name: s,
105
+ name: a,
105
106
  version: "1.0.0",
106
107
  type: "module",
107
108
  scripts: {
@@ -136,14 +137,14 @@ const D = new P(), p = {
136
137
  seedFile: "seed.ts"
137
138
  }
138
139
  };
139
- function N(s, e) {
140
- a.readdirSync(s).forEach((r) => {
141
- const n = i.join(s, r), t = i.join(e, r);
142
- a.lstatSync(n).isDirectory() ? (a.mkdirSync(t, { recursive: !0 }), N(n, t)) : a.copyFileSync(n, t);
140
+ function P(a, e) {
141
+ i.readdirSync(a).forEach((r) => {
142
+ const n = s.join(a, r), t = s.join(e, r);
143
+ i.lstatSync(n).isDirectory() ? (i.mkdirSync(t, { recursive: !0 }), P(n, t)) : i.copyFileSync(n, t);
143
144
  });
144
145
  }
145
- function R(s, e = !1, o = "authhero-local", r) {
146
- const n = s ? "control_plane" : "main", t = s ? "Control Plane" : "Main", c = [
146
+ function L(a, e = !1, o = "authhero-local", r) {
147
+ const n = a ? "control_plane" : "main", t = a ? "Control Plane" : "Main", c = [
147
148
  "https://manage.authhero.net/auth-callback",
148
149
  "https://local.authhero.net/auth-callback",
149
150
  "http://localhost:5173/auth-callback",
@@ -157,7 +158,7 @@ function R(s, e = !1, o = "authhero-local", r) {
157
158
  "https://local.authhero.net",
158
159
  "http://localhost:5173",
159
160
  "http://localhost:3000"
160
- ], C = e ? ["https://localhost:8443/", "https://localhost.emobix.co.uk:8443/"] : [], y = [...h, ...C], b = e ? `
161
+ ], C = e ? ["https://localhost:8443/", "https://localhost.emobix.co.uk:8443/"] : [], y = [...h, ...C], _ = e ? `
161
162
  // Create OpenID Conformance Suite test clients and user
162
163
  console.log("Creating conformance test clients and user...");
163
164
 
@@ -272,7 +273,7 @@ function R(s, e = !1, o = "authhero-local", r) {
272
273
  return `import { SqliteDialect, Kysely } from "kysely";
273
274
  import Database from "better-sqlite3";
274
275
  import createAdapters from "@authhero/kysely-adapter";
275
- import { seed } from "authhero";
276
+ import { seed${e ? ", USERNAME_PASSWORD_PROVIDER" : ""} } from "authhero";
276
277
 
277
278
  interface ExtraClient {
278
279
  client_id: string;
@@ -281,6 +282,7 @@ interface ExtraClient {
281
282
  callbacks?: string[];
282
283
  allowed_logout_urls?: string[];
283
284
  web_origins?: string[];
285
+ auth0_conformant?: boolean;
284
286
  }
285
287
 
286
288
  function parseFlag(name: string): string | undefined {
@@ -332,7 +334,7 @@ async function main() {
332
334
  adminPassword,
333
335
  tenantId: "${n}",
334
336
  tenantName: "${t}",
335
- isControlPlane: ${!!s},
337
+ isControlPlane: ${!!a},
336
338
  clientId: "default",
337
339
  callbacks: ${JSON.stringify(f)},
338
340
  allowedLogoutUrls: ${JSON.stringify(y)},
@@ -353,6 +355,9 @@ async function main() {
353
355
  web_origins: c.web_origins ?? [],
354
356
  connections: ["Username-Password-Authentication"],
355
357
  client_metadata: { universal_login_version: "2" },
358
+ ...(c.auth0_conformant !== undefined && {
359
+ auth0_conformant: c.auth0_conformant,
360
+ }),
356
361
  });
357
362
  console.log(\`✅ Created client "\${c.client_id}"\`);
358
363
  }
@@ -361,7 +366,7 @@ async function main() {
361
366
  await adapters.users.update(seedResult.tenantId, seedResult.userId, userProfile);
362
367
  console.log(\`✅ Updated profile of user "\${seedResult.username}"\`);
363
368
  }
364
- ${b}
369
+ ${_}
365
370
  await db.destroy();
366
371
  }
367
372
 
@@ -371,7 +376,7 @@ main().catch((err) => {
371
376
  });
372
377
  `;
373
378
  }
374
- function O(s, e) {
379
+ function $(a, e) {
375
380
  const o = e ? `import fs from "fs";
376
381
  ` : "", r = e ? `
377
382
  const adminDistPath = path.resolve(
@@ -389,7 +394,7 @@ const adminIndexPath = path.join(adminDistPath, "index.html");
389
394
  .replace(/href="\\.\\//g, 'href="/admin/');
390
395
  const configJson = JSON.stringify({
391
396
  domain: issuer.replace(/\\/$/, ""),
392
- clientId: ${s ? "CONTROL_PLANE_CLIENT_ID," : '"default",'}
397
+ clientId: ${a ? "CONTROL_PLANE_CLIENT_ID," : '"default",'}
393
398
  basePath: "/admin",
394
399
  }).replace(/</g, "\\\\u003c");
395
400
  configWithHandlers.adminIndexHtml = rawHtml.replace(
@@ -402,7 +407,7 @@ const adminIndexPath = path.join(adminDistPath, "index.html");
402
407
  });
403
408
  }
404
409
  ` : "";
405
- return s ? `import { Context } from "hono";
410
+ return a ? `import { Context } from "hono";
406
411
  import { swaggerUI } from "@hono/swagger-ui";
407
412
  import { AuthHeroConfig, DataAdapters } from "authhero";
408
413
  import { serveStatic } from "@hono/node-server/serve-static";
@@ -507,7 +512,7 @@ ${n}
507
512
  }
508
513
  `;
509
514
  }
510
- function U(s) {
515
+ function j(a) {
511
516
  return `import { D1Dialect } from "kysely-d1";
512
517
  import { Kysely } from "kysely";
513
518
  import createAdapters from "@authhero/kysely-adapter";
@@ -534,9 +539,9 @@ export default {
534
539
  adminUsername,
535
540
  adminPassword,
536
541
  issuer,
537
- tenantId: "${s ? "control_plane" : "main"}",
538
- tenantName: "${s ? "Control Plane" : "Main"}",
539
- isControlPlane: ${!!s},
542
+ tenantId: "${a ? "control_plane" : "main"}",
543
+ tenantName: "${a ? "Control Plane" : "Main"}",
544
+ isControlPlane: ${!!a},
540
545
  clientId: "default",
541
546
  });
542
547
 
@@ -568,11 +573,11 @@ export default {
568
573
  };
569
574
  `;
570
575
  }
571
- function $(s, e) {
576
+ function H(a, e) {
572
577
  const o = e ? `import adminIndexHtml from "./admin-index-html";
573
578
  ` : "", r = e ? ` adminIndexHtml,
574
579
  ` : "";
575
- return s ? `import { Context } from "hono";
580
+ return a ? `import { Context } from "hono";
576
581
  import { swaggerUI } from "@hono/swagger-ui";
577
582
  import { AuthHeroConfig, DataAdapters } from "authhero";
578
583
  import { initMultiTenant } from "@authhero/multi-tenancy";
@@ -653,8 +658,8 @@ ${r} });
653
658
  }
654
659
  `;
655
660
  }
656
- function L(s) {
657
- return s ? `import { Context } from "hono";
661
+ function M(a) {
662
+ return a ? `import { Context } from "hono";
658
663
  import { swaggerUI } from "@hono/swagger-ui";
659
664
  import { AuthHeroConfig, DataAdapters } from "authhero";
660
665
  import { initMultiTenant } from "@authhero/multi-tenancy";
@@ -759,7 +764,7 @@ export default function createApp(config: AppConfig) {
759
764
  }
760
765
  `;
761
766
  }
762
- function j(s) {
767
+ function F(a) {
763
768
  return `import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
764
769
  import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
765
770
  import createAdapters from "@authhero/aws";
@@ -788,9 +793,9 @@ async function main() {
788
793
  await seed(adapters, {
789
794
  adminUsername,
790
795
  adminPassword,
791
- tenantId: "${s ? "control_plane" : "main"}",
792
- tenantName: "${s ? "Control Plane" : "Main"}",
793
- isControlPlane: ${!!s},
796
+ tenantId: "${a ? "control_plane" : "main"}",
797
+ tenantName: "${a ? "Control Plane" : "Main"}",
798
+ isControlPlane: ${!!a},
794
799
  });
795
800
 
796
801
  console.log("✅ Database seeded successfully!");
@@ -799,22 +804,22 @@ async function main() {
799
804
  main().catch(console.error);
800
805
  `;
801
806
  }
802
- function H(s, e) {
803
- const o = i.join(s, "src");
804
- a.writeFileSync(
805
- i.join(o, "app.ts"),
806
- L(e)
807
- ), a.writeFileSync(
808
- i.join(o, "seed.ts"),
809
- j(e)
807
+ function W(a, e) {
808
+ const o = s.join(a, "src");
809
+ i.writeFileSync(
810
+ s.join(o, "app.ts"),
811
+ M(e)
812
+ ), i.writeFileSync(
813
+ s.join(o, "seed.ts"),
814
+ F(e)
810
815
  );
811
816
  }
812
- function x() {
817
+ function k() {
813
818
  console.log("\\n" + "─".repeat(50)), console.log("🔐 AuthHero deployed to AWS!"), console.log("📚 Check SST output for your API URL"), console.log("🚀 Open your server URL /setup to complete initial setup"), console.log("🌐 Portal available at https://local.authhero.net"), console.log("─".repeat(50) + "\\n");
814
819
  }
815
- function F(s) {
816
- const e = i.join(s, ".github", "workflows");
817
- a.mkdirSync(e, { recursive: !0 });
820
+ function q(a) {
821
+ const e = s.join(a, ".github", "workflows");
822
+ i.mkdirSync(e, { recursive: !0 });
818
823
  const o = `name: Unit tests
819
824
 
820
825
  on: push
@@ -901,9 +906,9 @@ jobs:
901
906
  apiToken: \${{ secrets.PROD_CLOUDFLARE_API_TOKEN }}
902
907
  command: deploy --env production
903
908
  `;
904
- a.writeFileSync(i.join(e, "unit-tests.yml"), o), a.writeFileSync(i.join(e, "deploy-dev.yml"), r), a.writeFileSync(i.join(e, "release.yml"), n), console.log("\\n📦 GitHub CI workflows created!");
909
+ i.writeFileSync(s.join(e, "unit-tests.yml"), o), i.writeFileSync(s.join(e, "deploy-dev.yml"), r), i.writeFileSync(s.join(e, "release.yml"), n), console.log("\\n📦 GitHub CI workflows created!");
905
910
  }
906
- function M(s) {
911
+ function J(a) {
907
912
  const e = {
908
913
  branches: ["main"],
909
914
  plugins: [
@@ -912,11 +917,11 @@ function M(s) {
912
917
  "@semantic-release/github"
913
918
  ]
914
919
  };
915
- a.writeFileSync(
916
- i.join(s, ".releaserc.json"),
920
+ i.writeFileSync(
921
+ s.join(a, ".releaserc.json"),
917
922
  JSON.stringify(e, null, 2)
918
923
  );
919
- const o = i.join(s, "package.json"), r = JSON.parse(a.readFileSync(o, "utf-8"));
924
+ const o = s.join(a, "package.json"), r = JSON.parse(i.readFileSync(o, "utf-8"));
920
925
  r.devDependencies = {
921
926
  ...r.devDependencies,
922
927
  "semantic-release": "^24.0.0"
@@ -924,11 +929,11 @@ function M(s) {
924
929
  ...r.scripts,
925
930
  test: 'echo "No tests yet"',
926
931
  "type-check": "tsc --noEmit"
927
- }, a.writeFileSync(o, JSON.stringify(r, null, 2));
932
+ }, i.writeFileSync(o, JSON.stringify(r, null, 2));
928
933
  }
929
- function _(s, e) {
934
+ function b(a, e) {
930
935
  return new Promise((o, r) => {
931
- const n = E(s, [], {
936
+ const n = U(a, [], {
932
937
  cwd: e,
933
938
  shell: !0,
934
939
  stdio: "inherit"
@@ -938,27 +943,27 @@ function _(s, e) {
938
943
  }), n.on("error", r);
939
944
  });
940
945
  }
941
- function W(s, e, o) {
942
- const r = i.join(s, "src");
943
- a.writeFileSync(
944
- i.join(r, "app.ts"),
945
- $(e, o)
946
- ), a.writeFileSync(
947
- i.join(r, "seed.ts"),
948
- U(e)
946
+ function z(a, e, o) {
947
+ const r = s.join(a, "src");
948
+ i.writeFileSync(
949
+ s.join(r, "app.ts"),
950
+ H(e, o)
951
+ ), i.writeFileSync(
952
+ s.join(r, "seed.ts"),
953
+ j(e)
949
954
  );
950
955
  }
951
- function I() {
956
+ function D() {
952
957
  console.log(`
953
958
  ` + "─".repeat(50)), console.log("🔐 AuthHero server running at https://localhost:3000"), console.log("🚀 Open https://localhost:3000/setup to complete initial setup"), console.log("─".repeat(50) + `
954
959
  `);
955
960
  }
956
- function k() {
961
+ function N() {
957
962
  console.log(`
958
963
  ` + "─".repeat(50)), console.log("✅ Self-signed certificates generated with openssl"), console.log("⚠️ You may need to trust the certificate in your browser"), console.log("🔐 AuthHero server running at http://localhost:3000"), console.log("📚 API documentation available at http://localhost:3000/docs"), console.log("🚀 Open http://localhost:3000/setup to complete initial setup"), console.log("─".repeat(50) + `
959
964
  `);
960
965
  }
961
- D.version("1.0.0").description("Create a new AuthHero project").argument("[project-name]", "name of the project").option("-t, --template <type>", "template type: local or cloudflare").option(
966
+ T.version("1.0.0").description("Create a new AuthHero project").argument("[project-name]", "name of the project").option("-t, --template <type>", "template type: local or cloudflare").option(
962
967
  "--package-manager <pm>",
963
968
  "package manager to use: npm, yarn, pnpm, or bun"
964
969
  ).option("--multi-tenant", "enable multi-tenant mode").option("--admin-ui", "include admin UI at /admin").option("--skip-install", "skip installing dependencies").option("--skip-migrate", "skip running database migrations").option("--skip-start", "skip starting the development server").option("--github-ci", "include GitHub CI workflows with semantic versioning").option("--conformance", "add OpenID conformance suite test clients").option(
@@ -967,12 +972,12 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
967
972
  ).option(
968
973
  "--workspace",
969
974
  "use workspace:* dependencies for local monorepo development"
970
- ).option("-y, --yes", "skip all prompts and use defaults/provided options").action(async (s, e) => {
975
+ ).option("-y, --yes", "skip all prompts and use defaults/provided options").action(async (a, e) => {
971
976
  const o = e.yes === !0;
972
977
  console.log(`
973
978
  🔐 Welcome to AuthHero!
974
979
  `);
975
- let r = s;
980
+ let r = a;
976
981
  r || (o ? (r = "auth-server", console.log(`Using default project name: ${r}`)) : r = (await m.prompt([
977
982
  {
978
983
  type: "input",
@@ -982,8 +987,8 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
982
987
  validate: (u) => u !== "" || "Project name cannot be empty"
983
988
  }
984
989
  ])).projectName);
985
- const n = i.join(process.cwd(), r);
986
- a.existsSync(n) && (console.error(`❌ Project "${r}" already exists.`), process.exit(1));
990
+ const n = s.join(process.cwd(), r);
991
+ i.existsSync(n) && (console.error(`❌ Project "${r}" already exists.`), process.exit(1));
987
992
  let t;
988
993
  e.template ? (["local", "cloudflare", "aws-sst"].includes(e.template) || (console.error(`❌ Invalid template: ${e.template}`), console.error("Valid options: local, cloudflare, aws-sst"), process.exit(1)), t = e.template, console.log(`Using template: ${p[t].name}`)) : t = (await m.prompt([
989
994
  {
@@ -1037,8 +1042,8 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
1037
1042
  const C = e.workspace || !1;
1038
1043
  C && console.log("Workspace mode: enabled (using workspace:* dependencies)");
1039
1044
  const y = p[t];
1040
- a.mkdirSync(n, { recursive: !0 }), a.writeFileSync(
1041
- i.join(n, "package.json"),
1045
+ i.mkdirSync(n, { recursive: !0 }), i.writeFileSync(
1046
+ s.join(n, "package.json"),
1042
1047
  JSON.stringify(
1043
1048
  y.packageJson(
1044
1049
  r,
@@ -1051,15 +1056,19 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
1051
1056
  2
1052
1057
  )
1053
1058
  );
1054
- const b = y.templateDir, S = i.join(
1055
- import.meta.url.replace("file://", "").replace("/create-authhero.js", ""),
1056
- b
1057
- );
1058
- if (a.existsSync(S) ? N(S, n) : (console.error(`❌ Template directory not found: ${S}`), process.exit(1)), t === "cloudflare" && W(n, c, d), t === "cloudflare") {
1059
- const l = i.join(n, "wrangler.toml"), u = i.join(n, "wrangler.local.toml");
1060
- a.existsSync(l) && a.copyFileSync(l, u);
1061
- const g = i.join(n, ".dev.vars.example"), w = i.join(n, ".dev.vars");
1062
- a.existsSync(g) && a.copyFileSync(g, w), console.log(
1059
+ const _ = y.templateDir, S = s.dirname(O(import.meta.url)), x = [
1060
+ s.join(S, _),
1061
+ s.join(S, "..", "templates", _)
1062
+ ], I = x.find((l) => i.existsSync(l));
1063
+ if (I ? P(I, n) : (console.error(
1064
+ `❌ Template directory not found. Looked in:
1065
+ ${x.join(`
1066
+ `)}`
1067
+ ), process.exit(1)), t === "cloudflare" && z(n, c, d), t === "cloudflare") {
1068
+ const l = s.join(n, "wrangler.toml"), u = s.join(n, "wrangler.local.toml");
1069
+ i.existsSync(l) && i.copyFileSync(l, u);
1070
+ const g = s.join(n, ".dev.vars.example"), w = s.join(n, ".dev.vars");
1071
+ i.existsSync(g) && i.copyFileSync(g, w), console.log(
1063
1072
  "📁 Created wrangler.local.toml and .dev.vars for local development"
1064
1073
  );
1065
1074
  }
@@ -1071,18 +1080,18 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
1071
1080
  message: "Would you like to include GitHub CI with semantic versioning?",
1072
1081
  default: !1
1073
1082
  }
1074
- ])).includeGithubCi), A && (F(n), M(n))), t === "local") {
1075
- const l = R(
1083
+ ])).includeGithubCi), A && (q(n), J(n))), t === "local") {
1084
+ const l = L(
1076
1085
  c,
1077
1086
  f,
1078
1087
  h,
1079
1088
  d
1080
1089
  );
1081
- a.writeFileSync(i.join(n, "src/seed.ts"), l);
1082
- const u = O(c, d);
1083
- a.writeFileSync(i.join(n, "src/app.ts"), u);
1090
+ i.writeFileSync(s.join(n, "src/seed.ts"), l);
1091
+ const u = $(c, d);
1092
+ i.writeFileSync(s.join(n, "src/app.ts"), u);
1084
1093
  }
1085
- if (t === "aws-sst" && H(n, c), f) {
1094
+ if (t === "aws-sst" && W(n, c), f) {
1086
1095
  const l = {
1087
1096
  alias: h,
1088
1097
  description: "AuthHero Conformance Test",
@@ -1101,17 +1110,17 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
1101
1110
  resourceUrl: "http://host.docker.internal:3000/userinfo"
1102
1111
  }
1103
1112
  };
1104
- a.writeFileSync(
1105
- i.join(n, "conformance-config.json"),
1113
+ i.writeFileSync(
1114
+ s.join(n, "conformance-config.json"),
1106
1115
  JSON.stringify(l, null, 2)
1107
1116
  ), console.log(
1108
1117
  "📝 Created conformance-config.json for OpenID Conformance Suite"
1109
1118
  );
1110
1119
  }
1111
- const T = c ? "multi-tenant" : "single-tenant";
1120
+ const E = c ? "multi-tenant" : "single-tenant";
1112
1121
  console.log(
1113
1122
  `
1114
- ✅ Project "${r}" has been created with ${y.name} (${T}) setup!
1123
+ ✅ Project "${r}" has been created with ${y.name} (${E}) setup!
1115
1124
  `
1116
1125
  );
1117
1126
  let v;
@@ -1144,9 +1153,9 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
1144
1153
  `);
1145
1154
  try {
1146
1155
  const u = l === "pnpm" ? "pnpm install --ignore-workspace" : `${l} install`;
1147
- if (await _(u, n), t === "local" && (console.log(`
1156
+ if (await b(u, n), t === "local" && (console.log(`
1148
1157
  🔧 Building native modules...
1149
- `), await _("npm rebuild better-sqlite3", n)), console.log(`
1158
+ `), await b("npm rebuild better-sqlite3", n)), console.log(`
1150
1159
  ✅ Dependencies installed successfully!
1151
1160
  `), (t === "local" || t === "cloudflare") && !e.skipMigrate) {
1152
1161
  let w;
@@ -1159,7 +1168,7 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
1159
1168
  }
1160
1169
  ])).shouldMigrate, w && (console.log(`
1161
1170
  🔄 Running migrations...
1162
- `), await _(`${l} run migrate`, n));
1171
+ `), await b(`${l} run migrate`, n));
1163
1172
  }
1164
1173
  let g;
1165
1174
  e.skipStart || o ? g = !1 : g = (await m.prompt([
@@ -1169,10 +1178,10 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
1169
1178
  message: "Would you like to start the development server?",
1170
1179
  default: !0
1171
1180
  }
1172
- ])).shouldStart, g && (t === "cloudflare" ? I() : t === "aws-sst" ? x() : k(), console.log(`🚀 Starting development server...
1173
- `), await _(`${l} run dev`, n)), o && !g && (console.log(`
1181
+ ])).shouldStart, g && (t === "cloudflare" ? D() : t === "aws-sst" ? k() : N(), console.log(`🚀 Starting development server...
1182
+ `), await b(`${l} run dev`, n)), o && !g && (console.log(`
1174
1183
  ✅ Setup complete!`), console.log(`
1175
- To start the development server:`), console.log(` cd ${r}`), console.log(" npm run dev"), t === "cloudflare" ? I() : t === "aws-sst" ? x() : k());
1184
+ To start the development server:`), console.log(` cd ${r}`), console.log(" npm run dev"), t === "cloudflare" ? D() : t === "aws-sst" ? k() : N());
1176
1185
  } catch (u) {
1177
1186
  console.error(`
1178
1187
  ❌ An error occurred:`, u), process.exit(1);
@@ -1199,4 +1208,4 @@ Server will be available at: http://localhost:3000`), f && (console.log(`
1199
1208
  For more information, visit: https://authhero.net/docs
1200
1209
  `));
1201
1210
  });
1202
- D.parse(process.argv);
1211
+ T.parse(process.argv);
@@ -4,6 +4,76 @@ import { Kysely } from "kysely";
4
4
  import Database from "better-sqlite3";
5
5
  import createAdapters from "@authhero/kysely-adapter";
6
6
  import createApp from "./app";
7
+ import fs from "fs";
8
+ import path from "path";
9
+ import { execFileSync } from "child_process";
10
+ import https from "https";
11
+
12
+ // Generate self-signed certificates for local HTTPS if they don't exist
13
+ const certDir = path.join(process.cwd(), ".certs");
14
+ const keyPath = path.join(certDir, "localhost-key.pem");
15
+ const certPath = path.join(certDir, "localhost.pem");
16
+
17
+ function ensureCertificates() {
18
+ if (!fs.existsSync(certDir)) {
19
+ fs.mkdirSync(certDir, { recursive: true });
20
+ }
21
+
22
+ if (!fs.existsSync(keyPath) || !fs.existsSync(certPath)) {
23
+ console.log("🔑 Generating self-signed certificates for local HTTPS...");
24
+
25
+ // Try mkcert first (if installed), otherwise fall back to openssl
26
+ try {
27
+ execFileSync("which", ["mkcert"], { stdio: "ignore" });
28
+ execFileSync(
29
+ "mkcert",
30
+ ["-key-file", keyPath, "-cert-file", certPath, "localhost", "127.0.0.1"],
31
+ { stdio: "inherit" },
32
+ );
33
+ console.log("✅ Certificates generated with mkcert");
34
+ } catch {
35
+ // Fall back to openssl
36
+ try {
37
+ execFileSync(
38
+ "openssl",
39
+ [
40
+ "req",
41
+ "-x509",
42
+ "-newkey",
43
+ "rsa:2048",
44
+ "-keyout",
45
+ keyPath,
46
+ "-out",
47
+ certPath,
48
+ "-days",
49
+ "365",
50
+ "-nodes",
51
+ "-subj",
52
+ "/CN=localhost",
53
+ ],
54
+ { stdio: "inherit" },
55
+ );
56
+ console.log("✅ Self-signed certificates generated with openssl");
57
+ console.log(
58
+ "⚠️ You may need to trust the certificate in your browser",
59
+ );
60
+ } catch (err) {
61
+ console.error(
62
+ "❌ Failed to generate certificates. Please install mkcert or openssl",
63
+ );
64
+ console.error(
65
+ " Install mkcert: brew install mkcert && mkcert -install",
66
+ );
67
+ process.exit(1);
68
+ }
69
+ }
70
+ }
71
+
72
+ return {
73
+ key: fs.readFileSync(keyPath),
74
+ cert: fs.readFileSync(certPath),
75
+ };
76
+ }
7
77
 
8
78
  // Initialize SQLite database
9
79
  let db: Kysely<any>;
@@ -34,15 +104,19 @@ const app = createApp({
34
104
  "https://manage.authhero.net",
35
105
  "https://local.authhero.net",
36
106
  "http://localhost:5173",
107
+ "https://localhost:5173",
37
108
  ],
38
109
  });
39
110
 
40
111
  // Start the server
41
112
  const port = Number(process.env.PORT) || 3000;
42
- const issuer = process.env.ISSUER || `http://localhost:${port}/`;
113
+ const issuer = process.env.ISSUER || `https://localhost:${port}/`;
114
+
115
+ // Get or generate certificates
116
+ const { key, cert } = ensureCertificates();
43
117
 
44
- console.log(`🔐 AuthHero server running at http://localhost:${port}`);
45
- console.log(`📚 API documentation available at http://localhost:${port}/docs`);
118
+ console.log(`🔐 AuthHero server running at https://localhost:${port}`);
119
+ console.log(`📚 API documentation available at https://localhost:${port}/docs`);
46
120
  console.log(`🌐 Portal available at https://local.authhero.net`);
47
121
 
48
122
  serve({
@@ -53,4 +127,11 @@ serve({
53
127
  });
54
128
  },
55
129
  port,
130
+ // Bind to all IPv4 interfaces explicitly. Node's default (`::`) is
131
+ // supposed to be dual-stack but on Docker Desktop Mac the docker bridge
132
+ // gateway IPv4 (e.g. 192.168.65.254) often isn't reachable that way,
133
+ // causing connections from inside the suite container to be refused.
134
+ hostname: "0.0.0.0",
135
+ createServer: https.createServer,
136
+ serverOptions: { key, cert },
56
137
  });
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.40.0",
8
+ "version": "0.41.1",
9
9
  "type": "module",
10
10
  "main": "dist/create-authhero.js",
11
11
  "bin": {
@@ -20,6 +20,7 @@
20
20
  "@rollup/plugin-node-resolve": "^15.2.3",
21
21
  "@types/inquirer": "^9.0.7",
22
22
  "@types/node": "^20.14.9",
23
+ "tsx": "^4.19.4",
23
24
  "typescript": "^5.5.2",
24
25
  "vite": "^5.3.2"
25
26
  },