create-authhero 0.41.0 → 0.41.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,18 +2,18 @@
2
2
  import { Command as R } from "commander";
3
3
  import m from "inquirer";
4
4
  import i from "fs";
5
- import a from "path";
6
- import { fileURLToPath as U } from "url";
7
- import { spawn as O } from "child_process";
8
- const T = new R(), p = {
5
+ import s from "path";
6
+ import { fileURLToPath as O } from "url";
7
+ import { spawn as U } from "child_process";
8
+ const N = new R(), p = {
9
9
  local: {
10
10
  name: "Local (SQLite)",
11
11
  description: "Local development setup with SQLite database - great for getting started",
12
12
  templateDir: "local",
13
- packageJson: (s, e, o, r, n) => {
13
+ packageJson: (a, e, o, r, n) => {
14
14
  const t = r ? "workspace:*" : "latest";
15
15
  return {
16
- name: s,
16
+ name: a,
17
17
  version: "1.0.0",
18
18
  type: "module",
19
19
  scripts: {
@@ -50,10 +50,10 @@ const T = new R(), p = {
50
50
  name: "Cloudflare Workers (D1)",
51
51
  description: "Cloudflare Workers setup with D1 database",
52
52
  templateDir: "cloudflare",
53
- packageJson: (s, e, o, r, n) => {
53
+ packageJson: (a, e, o, r, n) => {
54
54
  const t = r ? "workspace:*" : "latest";
55
55
  return {
56
- name: s,
56
+ name: a,
57
57
  version: "1.0.0",
58
58
  type: "module",
59
59
  scripts: {
@@ -99,10 +99,10 @@ const T = new R(), p = {
99
99
  name: "AWS SST (Lambda + DynamoDB)",
100
100
  description: "Serverless AWS deployment with Lambda, DynamoDB, and SST",
101
101
  templateDir: "aws-sst",
102
- packageJson: (s, e, o, r, n) => {
102
+ packageJson: (a, e, o, r, n) => {
103
103
  const t = r ? "workspace:*" : "latest";
104
104
  return {
105
- name: s,
105
+ name: a,
106
106
  version: "1.0.0",
107
107
  type: "module",
108
108
  scripts: {
@@ -137,14 +137,14 @@ const T = new R(), p = {
137
137
  seedFile: "seed.ts"
138
138
  }
139
139
  };
140
- function P(s, e) {
141
- i.readdirSync(s).forEach((r) => {
142
- const n = a.join(s, r), t = a.join(e, r);
140
+ function P(a, e) {
141
+ i.readdirSync(a).forEach((r) => {
142
+ const n = s.join(a, r), t = s.join(e, r);
143
143
  i.lstatSync(n).isDirectory() ? (i.mkdirSync(t, { recursive: !0 }), P(n, t)) : i.copyFileSync(n, t);
144
144
  });
145
145
  }
146
- function L(s, e = !1, o = "authhero-local", r) {
147
- const n = s ? "control_plane" : "main", t = s ? "Control Plane" : "Main", c = [
146
+ function $(a, e = !1, o = "authhero-local", r) {
147
+ const n = a ? "control_plane" : "main", t = a ? "Control Plane" : "Main", c = [
148
148
  "https://manage.authhero.net/auth-callback",
149
149
  "https://local.authhero.net/auth-callback",
150
150
  "http://localhost:5173/auth-callback",
@@ -158,17 +158,26 @@ function L(s, e = !1, o = "authhero-local", r) {
158
158
  "https://local.authhero.net",
159
159
  "http://localhost:5173",
160
160
  "http://localhost:3000"
161
- ], C = e ? ["https://localhost:8443/", "https://localhost.emobix.co.uk:8443/"] : [], y = [...h, ...C], A = e ? `
161
+ ], C = e ? ["https://localhost:8443/", "https://localhost.emobix.co.uk:8443/"] : [], y = [...h, ...C], _ = e ? `
162
162
  // Create OpenID Conformance Suite test clients and user
163
163
  console.log("Creating conformance test clients and user...");
164
164
 
165
165
  // The OIDCC basic test plan calls /token without an audience param. AuthHero
166
166
  // requires either an explicit audience or a tenant default_audience to mint
167
167
  // an access token, so set one here for the conformance setup.
168
+ // enable_dynamic_client_registration is required by the OIDCC dynamic plan,
169
+ // which has the suite register its own client via /oidc/register. Existing
170
+ // flags (e.g. inherit_global_permissions_in_organizations set by seed for
171
+ // the control-plane tenant) are merged in so the update doesn't clobber.
172
+ const existingTenant = await adapters.tenants.get("${n}");
168
173
  await adapters.tenants.update("${n}", {
169
174
  default_audience: "urn:authhero:management",
175
+ flags: {
176
+ ...(existingTenant?.flags ?? {}),
177
+ enable_dynamic_client_registration: true,
178
+ },
170
179
  });
171
- console.log("✅ Set tenant default_audience for conformance");
180
+ console.log("✅ Set tenant default_audience and enabled DCR for conformance");
172
181
 
173
182
  const conformanceCallbacks = [
174
183
  "https://localhost.emobix.co.uk:8443/test/a/${o}/callback",
@@ -273,7 +282,7 @@ function L(s, e = !1, o = "authhero-local", r) {
273
282
  return `import { SqliteDialect, Kysely } from "kysely";
274
283
  import Database from "better-sqlite3";
275
284
  import createAdapters from "@authhero/kysely-adapter";
276
- import { seed } from "authhero";
285
+ import { seed${e ? ", USERNAME_PASSWORD_PROVIDER" : ""} } from "authhero";
277
286
 
278
287
  interface ExtraClient {
279
288
  client_id: string;
@@ -282,6 +291,7 @@ interface ExtraClient {
282
291
  callbacks?: string[];
283
292
  allowed_logout_urls?: string[];
284
293
  web_origins?: string[];
294
+ auth0_conformant?: boolean;
285
295
  }
286
296
 
287
297
  function parseFlag(name: string): string | undefined {
@@ -333,7 +343,7 @@ async function main() {
333
343
  adminPassword,
334
344
  tenantId: "${n}",
335
345
  tenantName: "${t}",
336
- isControlPlane: ${!!s},
346
+ isControlPlane: ${!!a},
337
347
  clientId: "default",
338
348
  callbacks: ${JSON.stringify(f)},
339
349
  allowedLogoutUrls: ${JSON.stringify(y)},
@@ -354,6 +364,9 @@ async function main() {
354
364
  web_origins: c.web_origins ?? [],
355
365
  connections: ["Username-Password-Authentication"],
356
366
  client_metadata: { universal_login_version: "2" },
367
+ ...(c.auth0_conformant !== undefined && {
368
+ auth0_conformant: c.auth0_conformant,
369
+ }),
357
370
  });
358
371
  console.log(\`✅ Created client "\${c.client_id}"\`);
359
372
  }
@@ -362,7 +375,7 @@ async function main() {
362
375
  await adapters.users.update(seedResult.tenantId, seedResult.userId, userProfile);
363
376
  console.log(\`✅ Updated profile of user "\${seedResult.username}"\`);
364
377
  }
365
- ${A}
378
+ ${_}
366
379
  await db.destroy();
367
380
  }
368
381
 
@@ -372,7 +385,7 @@ main().catch((err) => {
372
385
  });
373
386
  `;
374
387
  }
375
- function $(s, e) {
388
+ function L(a, e) {
376
389
  const o = e ? `import fs from "fs";
377
390
  ` : "", r = e ? `
378
391
  const adminDistPath = path.resolve(
@@ -390,7 +403,7 @@ const adminIndexPath = path.join(adminDistPath, "index.html");
390
403
  .replace(/href="\\.\\//g, 'href="/admin/');
391
404
  const configJson = JSON.stringify({
392
405
  domain: issuer.replace(/\\/$/, ""),
393
- clientId: ${s ? "CONTROL_PLANE_CLIENT_ID," : '"default",'}
406
+ clientId: ${a ? "CONTROL_PLANE_CLIENT_ID," : '"default",'}
394
407
  basePath: "/admin",
395
408
  }).replace(/</g, "\\\\u003c");
396
409
  configWithHandlers.adminIndexHtml = rawHtml.replace(
@@ -403,7 +416,7 @@ const adminIndexPath = path.join(adminDistPath, "index.html");
403
416
  });
404
417
  }
405
418
  ` : "";
406
- return s ? `import { Context } from "hono";
419
+ return a ? `import { Context } from "hono";
407
420
  import { swaggerUI } from "@hono/swagger-ui";
408
421
  import { AuthHeroConfig, DataAdapters } from "authhero";
409
422
  import { serveStatic } from "@hono/node-server/serve-static";
@@ -508,7 +521,7 @@ ${n}
508
521
  }
509
522
  `;
510
523
  }
511
- function j(s) {
524
+ function j(a) {
512
525
  return `import { D1Dialect } from "kysely-d1";
513
526
  import { Kysely } from "kysely";
514
527
  import createAdapters from "@authhero/kysely-adapter";
@@ -535,9 +548,9 @@ export default {
535
548
  adminUsername,
536
549
  adminPassword,
537
550
  issuer,
538
- tenantId: "${s ? "control_plane" : "main"}",
539
- tenantName: "${s ? "Control Plane" : "Main"}",
540
- isControlPlane: ${!!s},
551
+ tenantId: "${a ? "control_plane" : "main"}",
552
+ tenantName: "${a ? "Control Plane" : "Main"}",
553
+ isControlPlane: ${!!a},
541
554
  clientId: "default",
542
555
  });
543
556
 
@@ -569,11 +582,11 @@ export default {
569
582
  };
570
583
  `;
571
584
  }
572
- function H(s, e) {
585
+ function H(a, e) {
573
586
  const o = e ? `import adminIndexHtml from "./admin-index-html";
574
587
  ` : "", r = e ? ` adminIndexHtml,
575
588
  ` : "";
576
- return s ? `import { Context } from "hono";
589
+ return a ? `import { Context } from "hono";
577
590
  import { swaggerUI } from "@hono/swagger-ui";
578
591
  import { AuthHeroConfig, DataAdapters } from "authhero";
579
592
  import { initMultiTenant } from "@authhero/multi-tenancy";
@@ -654,8 +667,8 @@ ${r} });
654
667
  }
655
668
  `;
656
669
  }
657
- function F(s) {
658
- return s ? `import { Context } from "hono";
670
+ function M(a) {
671
+ return a ? `import { Context } from "hono";
659
672
  import { swaggerUI } from "@hono/swagger-ui";
660
673
  import { AuthHeroConfig, DataAdapters } from "authhero";
661
674
  import { initMultiTenant } from "@authhero/multi-tenancy";
@@ -760,7 +773,7 @@ export default function createApp(config: AppConfig) {
760
773
  }
761
774
  `;
762
775
  }
763
- function M(s) {
776
+ function F(a) {
764
777
  return `import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
765
778
  import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
766
779
  import createAdapters from "@authhero/aws";
@@ -789,9 +802,9 @@ async function main() {
789
802
  await seed(adapters, {
790
803
  adminUsername,
791
804
  adminPassword,
792
- tenantId: "${s ? "control_plane" : "main"}",
793
- tenantName: "${s ? "Control Plane" : "Main"}",
794
- isControlPlane: ${!!s},
805
+ tenantId: "${a ? "control_plane" : "main"}",
806
+ tenantName: "${a ? "Control Plane" : "Main"}",
807
+ isControlPlane: ${!!a},
795
808
  });
796
809
 
797
810
  console.log("✅ Database seeded successfully!");
@@ -800,21 +813,21 @@ async function main() {
800
813
  main().catch(console.error);
801
814
  `;
802
815
  }
803
- function W(s, e) {
804
- const o = a.join(s, "src");
816
+ function W(a, e) {
817
+ const o = s.join(a, "src");
805
818
  i.writeFileSync(
806
- a.join(o, "app.ts"),
807
- F(e)
808
- ), i.writeFileSync(
809
- a.join(o, "seed.ts"),
819
+ s.join(o, "app.ts"),
810
820
  M(e)
821
+ ), i.writeFileSync(
822
+ s.join(o, "seed.ts"),
823
+ F(e)
811
824
  );
812
825
  }
813
- function I() {
826
+ function k() {
814
827
  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");
815
828
  }
816
- function q(s) {
817
- const e = a.join(s, ".github", "workflows");
829
+ function q(a) {
830
+ const e = s.join(a, ".github", "workflows");
818
831
  i.mkdirSync(e, { recursive: !0 });
819
832
  const o = `name: Unit tests
820
833
 
@@ -902,9 +915,9 @@ jobs:
902
915
  apiToken: \${{ secrets.PROD_CLOUDFLARE_API_TOKEN }}
903
916
  command: deploy --env production
904
917
  `;
905
- i.writeFileSync(a.join(e, "unit-tests.yml"), o), i.writeFileSync(a.join(e, "deploy-dev.yml"), r), i.writeFileSync(a.join(e, "release.yml"), n), console.log("\\n📦 GitHub CI workflows created!");
918
+ 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!");
906
919
  }
907
- function J(s) {
920
+ function J(a) {
908
921
  const e = {
909
922
  branches: ["main"],
910
923
  plugins: [
@@ -914,10 +927,10 @@ function J(s) {
914
927
  ]
915
928
  };
916
929
  i.writeFileSync(
917
- a.join(s, ".releaserc.json"),
930
+ s.join(a, ".releaserc.json"),
918
931
  JSON.stringify(e, null, 2)
919
932
  );
920
- const o = a.join(s, "package.json"), r = JSON.parse(i.readFileSync(o, "utf-8"));
933
+ const o = s.join(a, "package.json"), r = JSON.parse(i.readFileSync(o, "utf-8"));
921
934
  r.devDependencies = {
922
935
  ...r.devDependencies,
923
936
  "semantic-release": "^24.0.0"
@@ -927,9 +940,9 @@ function J(s) {
927
940
  "type-check": "tsc --noEmit"
928
941
  }, i.writeFileSync(o, JSON.stringify(r, null, 2));
929
942
  }
930
- function b(s, e) {
943
+ function A(a, e) {
931
944
  return new Promise((o, r) => {
932
- const n = O(s, [], {
945
+ const n = U(a, [], {
933
946
  cwd: e,
934
947
  shell: !0,
935
948
  stdio: "inherit"
@@ -939,13 +952,13 @@ function b(s, e) {
939
952
  }), n.on("error", r);
940
953
  });
941
954
  }
942
- function z(s, e, o) {
943
- const r = a.join(s, "src");
955
+ function z(a, e, o) {
956
+ const r = s.join(a, "src");
944
957
  i.writeFileSync(
945
- a.join(r, "app.ts"),
958
+ s.join(r, "app.ts"),
946
959
  H(e, o)
947
960
  ), i.writeFileSync(
948
- a.join(r, "seed.ts"),
961
+ s.join(r, "seed.ts"),
949
962
  j(e)
950
963
  );
951
964
  }
@@ -954,12 +967,12 @@ function D() {
954
967
  ` + "─".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) + `
955
968
  `);
956
969
  }
957
- function N() {
970
+ function T() {
958
971
  console.log(`
959
972
  ` + "─".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) + `
960
973
  `);
961
974
  }
962
- 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(
975
+ N.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(
963
976
  "--package-manager <pm>",
964
977
  "package manager to use: npm, yarn, pnpm, or bun"
965
978
  ).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(
@@ -968,12 +981,12 @@ T.version("1.0.0").description("Create a new AuthHero project").argument("[proje
968
981
  ).option(
969
982
  "--workspace",
970
983
  "use workspace:* dependencies for local monorepo development"
971
- ).option("-y, --yes", "skip all prompts and use defaults/provided options").action(async (s, e) => {
984
+ ).option("-y, --yes", "skip all prompts and use defaults/provided options").action(async (a, e) => {
972
985
  const o = e.yes === !0;
973
986
  console.log(`
974
987
  🔐 Welcome to AuthHero!
975
988
  `);
976
- let r = s;
989
+ let r = a;
977
990
  r || (o ? (r = "auth-server", console.log(`Using default project name: ${r}`)) : r = (await m.prompt([
978
991
  {
979
992
  type: "input",
@@ -983,7 +996,7 @@ T.version("1.0.0").description("Create a new AuthHero project").argument("[proje
983
996
  validate: (u) => u !== "" || "Project name cannot be empty"
984
997
  }
985
998
  ])).projectName);
986
- const n = a.join(process.cwd(), r);
999
+ const n = s.join(process.cwd(), r);
987
1000
  i.existsSync(n) && (console.error(`❌ Project "${r}" already exists.`), process.exit(1));
988
1001
  let t;
989
1002
  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([
@@ -1039,7 +1052,7 @@ T.version("1.0.0").description("Create a new AuthHero project").argument("[proje
1039
1052
  C && console.log("Workspace mode: enabled (using workspace:* dependencies)");
1040
1053
  const y = p[t];
1041
1054
  i.mkdirSync(n, { recursive: !0 }), i.writeFileSync(
1042
- a.join(n, "package.json"),
1055
+ s.join(n, "package.json"),
1043
1056
  JSON.stringify(
1044
1057
  y.packageJson(
1045
1058
  r,
@@ -1052,40 +1065,40 @@ T.version("1.0.0").description("Create a new AuthHero project").argument("[proje
1052
1065
  2
1053
1066
  )
1054
1067
  );
1055
- const A = y.templateDir, S = a.dirname(U(import.meta.url)), x = [
1056
- a.join(S, A),
1057
- a.join(S, "..", "templates", A)
1058
- ], k = x.find((l) => i.existsSync(l));
1059
- if (k ? P(k, n) : (console.error(
1068
+ const _ = y.templateDir, S = s.dirname(O(import.meta.url)), x = [
1069
+ s.join(S, _),
1070
+ s.join(S, "..", "templates", _)
1071
+ ], I = x.find((l) => i.existsSync(l));
1072
+ if (I ? P(I, n) : (console.error(
1060
1073
  `❌ Template directory not found. Looked in:
1061
1074
  ${x.join(`
1062
1075
  `)}`
1063
1076
  ), process.exit(1)), t === "cloudflare" && z(n, c, d), t === "cloudflare") {
1064
- const l = a.join(n, "wrangler.toml"), u = a.join(n, "wrangler.local.toml");
1077
+ const l = s.join(n, "wrangler.toml"), u = s.join(n, "wrangler.local.toml");
1065
1078
  i.existsSync(l) && i.copyFileSync(l, u);
1066
- const g = a.join(n, ".dev.vars.example"), w = a.join(n, ".dev.vars");
1079
+ const g = s.join(n, ".dev.vars.example"), w = s.join(n, ".dev.vars");
1067
1080
  i.existsSync(g) && i.copyFileSync(g, w), console.log(
1068
1081
  "📁 Created wrangler.local.toml and .dev.vars for local development"
1069
1082
  );
1070
1083
  }
1071
- let _ = !1;
1072
- if (t === "cloudflare" && (e.githubCi !== void 0 ? (_ = e.githubCi, _ && console.log("Including GitHub CI workflows with semantic versioning")) : o || (_ = (await m.prompt([
1084
+ let b = !1;
1085
+ if (t === "cloudflare" && (e.githubCi !== void 0 ? (b = e.githubCi, b && console.log("Including GitHub CI workflows with semantic versioning")) : o || (b = (await m.prompt([
1073
1086
  {
1074
1087
  type: "confirm",
1075
1088
  name: "includeGithubCi",
1076
1089
  message: "Would you like to include GitHub CI with semantic versioning?",
1077
1090
  default: !1
1078
1091
  }
1079
- ])).includeGithubCi), _ && (q(n), J(n))), t === "local") {
1080
- const l = L(
1092
+ ])).includeGithubCi), b && (q(n), J(n))), t === "local") {
1093
+ const l = $(
1081
1094
  c,
1082
1095
  f,
1083
1096
  h,
1084
1097
  d
1085
1098
  );
1086
- i.writeFileSync(a.join(n, "src/seed.ts"), l);
1087
- const u = $(c, d);
1088
- i.writeFileSync(a.join(n, "src/app.ts"), u);
1099
+ i.writeFileSync(s.join(n, "src/seed.ts"), l);
1100
+ const u = L(c, d);
1101
+ i.writeFileSync(s.join(n, "src/app.ts"), u);
1089
1102
  }
1090
1103
  if (t === "aws-sst" && W(n, c), f) {
1091
1104
  const l = {
@@ -1107,7 +1120,7 @@ T.version("1.0.0").description("Create a new AuthHero project").argument("[proje
1107
1120
  }
1108
1121
  };
1109
1122
  i.writeFileSync(
1110
- a.join(n, "conformance-config.json"),
1123
+ s.join(n, "conformance-config.json"),
1111
1124
  JSON.stringify(l, null, 2)
1112
1125
  ), console.log(
1113
1126
  "📝 Created conformance-config.json for OpenID Conformance Suite"
@@ -1149,9 +1162,9 @@ T.version("1.0.0").description("Create a new AuthHero project").argument("[proje
1149
1162
  `);
1150
1163
  try {
1151
1164
  const u = l === "pnpm" ? "pnpm install --ignore-workspace" : `${l} install`;
1152
- if (await b(u, n), t === "local" && (console.log(`
1165
+ if (await A(u, n), t === "local" && (console.log(`
1153
1166
  🔧 Building native modules...
1154
- `), await b("npm rebuild better-sqlite3", n)), console.log(`
1167
+ `), await A("npm rebuild better-sqlite3", n)), console.log(`
1155
1168
  ✅ Dependencies installed successfully!
1156
1169
  `), (t === "local" || t === "cloudflare") && !e.skipMigrate) {
1157
1170
  let w;
@@ -1164,7 +1177,7 @@ T.version("1.0.0").description("Create a new AuthHero project").argument("[proje
1164
1177
  }
1165
1178
  ])).shouldMigrate, w && (console.log(`
1166
1179
  🔄 Running migrations...
1167
- `), await b(`${l} run migrate`, n));
1180
+ `), await A(`${l} run migrate`, n));
1168
1181
  }
1169
1182
  let g;
1170
1183
  e.skipStart || o ? g = !1 : g = (await m.prompt([
@@ -1174,10 +1187,10 @@ T.version("1.0.0").description("Create a new AuthHero project").argument("[proje
1174
1187
  message: "Would you like to start the development server?",
1175
1188
  default: !0
1176
1189
  }
1177
- ])).shouldStart, g && (t === "cloudflare" ? D() : t === "aws-sst" ? I() : N(), console.log(`🚀 Starting development server...
1178
- `), await b(`${l} run dev`, n)), o && !g && (console.log(`
1190
+ ])).shouldStart, g && (t === "cloudflare" ? D() : t === "aws-sst" ? k() : T(), console.log(`🚀 Starting development server...
1191
+ `), await A(`${l} run dev`, n)), o && !g && (console.log(`
1179
1192
  ✅ Setup complete!`), console.log(`
1180
- To start the development server:`), console.log(` cd ${r}`), console.log(" npm run dev"), t === "cloudflare" ? D() : t === "aws-sst" ? I() : N());
1193
+ To start the development server:`), console.log(` cd ${r}`), console.log(" npm run dev"), t === "cloudflare" ? D() : t === "aws-sst" ? k() : T());
1181
1194
  } catch (u) {
1182
1195
  console.error(`
1183
1196
  ❌ An error occurred:`, u), process.exit(1);
@@ -1204,4 +1217,4 @@ Server will be available at: http://localhost:3000`), f && (console.log(`
1204
1217
  For more information, visit: https://authhero.net/docs
1205
1218
  `));
1206
1219
  });
1207
- T.parse(process.argv);
1220
+ N.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.41.0",
8
+ "version": "0.41.2",
9
9
  "type": "module",
10
10
  "main": "dist/create-authhero.js",
11
11
  "bin": {