create-authhero 0.25.0 → 0.26.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.
@@ -1,15 +1,15 @@
1
1
  #!/usr/bin/env node
2
- import { Command as k } from "commander";
2
+ import { Command as L } from "commander";
3
3
  import u from "inquirer";
4
- import a from "fs";
5
- import i from "path";
4
+ import s from "fs";
5
+ import l from "path";
6
6
  import { spawn as N } from "child_process";
7
- const b = new k(), p = {
7
+ const T = new L(), p = {
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: (t, e) => ({
12
+ packageJson: (t, e, o) => ({
13
13
  name: t,
14
14
  version: "1.0.0",
15
15
  type: "module",
@@ -29,7 +29,8 @@ const b = new k(), p = {
29
29
  "better-sqlite3": "latest",
30
30
  hono: "^4.6.0",
31
31
  kysely: "latest",
32
- ...e && { "@authhero/multi-tenancy": "latest" }
32
+ ...e && { "@authhero/multi-tenancy": "latest" },
33
+ ...o && { bcryptjs: "latest" }
33
34
  },
34
35
  devDependencies: {
35
36
  "@types/better-sqlite3": "^7.6.0",
@@ -44,7 +45,7 @@ const b = new k(), p = {
44
45
  name: "Cloudflare Workers (D1)",
45
46
  description: "Cloudflare Workers setup with D1 database",
46
47
  templateDir: "cloudflare",
47
- packageJson: (t, e) => ({
48
+ packageJson: (t, e, o) => ({
48
49
  name: t,
49
50
  version: "1.0.0",
50
51
  type: "module",
@@ -72,7 +73,8 @@ const b = new k(), p = {
72
73
  hono: "^4.6.0",
73
74
  kysely: "latest",
74
75
  "kysely-d1": "latest",
75
- ...e && { "@authhero/multi-tenancy": "latest" }
76
+ ...e && { "@authhero/multi-tenancy": "latest" },
77
+ ...o && { bcryptjs: "latest" }
76
78
  },
77
79
  devDependencies: {
78
80
  "@cloudflare/workers-types": "^4.0.0",
@@ -88,7 +90,7 @@ const b = new k(), p = {
88
90
  name: "AWS SST (Lambda + DynamoDB)",
89
91
  description: "Serverless AWS deployment with Lambda, DynamoDB, and SST",
90
92
  templateDir: "aws-sst",
91
- packageJson: (t, e) => ({
93
+ packageJson: (t, e, o) => ({
92
94
  name: t,
93
95
  version: "1.0.0",
94
96
  type: "module",
@@ -108,7 +110,8 @@ const b = new k(), p = {
108
110
  "@hono/zod-openapi": "^0.19.0",
109
111
  authhero: "latest",
110
112
  hono: "^4.6.0",
111
- ...e && { "@authhero/multi-tenancy": "latest" }
113
+ ...e && { "@authhero/multi-tenancy": "latest" },
114
+ ...o && { bcryptjs: "latest" }
112
115
  },
113
116
  devDependencies: {
114
117
  "@types/aws-lambda": "^8.10.0",
@@ -122,12 +125,129 @@ const b = new k(), p = {
122
125
  }
123
126
  };
124
127
  function E(t, e) {
125
- a.readdirSync(t).forEach((s) => {
126
- const n = i.join(t, s), o = i.join(e, s);
127
- a.lstatSync(n).isDirectory() ? (a.mkdirSync(o, { recursive: !0 }), E(n, o)) : a.copyFileSync(n, o);
128
+ s.readdirSync(t).forEach((r) => {
129
+ const n = l.join(t, r), a = l.join(e, r);
130
+ s.lstatSync(n).isDirectory() ? (s.mkdirSync(a, { recursive: !0 }), E(n, a)) : s.copyFileSync(n, a);
128
131
  });
129
132
  }
130
- function P(t) {
133
+ function R(t, e = !1, o = "authhero-local") {
134
+ const r = t ? "control_plane" : "main", n = t ? "Control Plane" : "Main", a = [
135
+ "https://manage.authhero.net/auth-callback",
136
+ "https://local.authhero.net/auth-callback",
137
+ "http://localhost:5173/auth-callback",
138
+ "https://localhost:3000/auth-callback"
139
+ ], c = e ? [
140
+ `https://localhost.emobix.co.uk:8443/test/a/${o}/callback`,
141
+ `https://localhost:8443/test/a/${o}/callback`
142
+ ] : [], g = [...a, ...c], w = [
143
+ "https://manage.authhero.net",
144
+ "https://local.authhero.net",
145
+ "http://localhost:5173",
146
+ "https://localhost:3000"
147
+ ], y = e ? ["https://localhost:8443/", "https://localhost.emobix.co.uk:8443/"] : [], x = [...w, ...y], v = e ? `
148
+ // Create OpenID Conformance Suite test clients and user
149
+ console.log("Creating conformance test clients and user...");
150
+
151
+ const conformanceCallbacks = [
152
+ "https://localhost.emobix.co.uk:8443/test/a/${o}/callback",
153
+ "https://localhost:8443/test/a/${o}/callback",
154
+ ];
155
+ const conformanceLogoutUrls = [
156
+ "https://localhost:8443/",
157
+ "https://localhost.emobix.co.uk:8443/",
158
+ ];
159
+ const conformanceWebOrigins = [
160
+ "https://localhost:8443",
161
+ "https://localhost.emobix.co.uk:8443",
162
+ ];
163
+
164
+ try {
165
+ await adapters.clients.create("${r}", {
166
+ client_id: "conformance-test",
167
+ client_secret: "conformanceTestSecret123",
168
+ name: "Conformance Test Client",
169
+ callbacks: conformanceCallbacks,
170
+ allowed_logout_urls: conformanceLogoutUrls,
171
+ web_origins: conformanceWebOrigins,
172
+ });
173
+ console.log("✅ Created conformance-test client");
174
+ } catch (e: any) {
175
+ if (e.message?.includes("UNIQUE constraint")) {
176
+ console.log("ℹ️ conformance-test client already exists");
177
+ } else {
178
+ throw e;
179
+ }
180
+ }
181
+
182
+ try {
183
+ await adapters.clients.create("${r}", {
184
+ client_id: "conformance-test2",
185
+ client_secret: "conformanceTestSecret456",
186
+ name: "Conformance Test Client 2",
187
+ callbacks: conformanceCallbacks,
188
+ allowed_logout_urls: conformanceLogoutUrls,
189
+ web_origins: conformanceWebOrigins,
190
+ });
191
+ console.log("✅ Created conformance-test2 client");
192
+ } catch (e: any) {
193
+ if (e.message?.includes("UNIQUE constraint")) {
194
+ console.log("ℹ️ conformance-test2 client already exists");
195
+ } else {
196
+ throw e;
197
+ }
198
+ }
199
+
200
+ // Create a conformance test user with ALL OIDC profile claims populated
201
+ // This is required for OIDCC-5.4 (VerifyScopesReturnedInUserInfoClaims) test
202
+ try {
203
+ await adapters.users.create("${r}", {
204
+ user_id: "auth2|conformance-user",
205
+ email: "conformance@example.com",
206
+ email_verified: true,
207
+ name: "Conformance Test User",
208
+ given_name: "Conformance",
209
+ family_name: "User",
210
+ middle_name: "Test",
211
+ nickname: "conformance",
212
+ username: "conformance_user",
213
+ picture: "https://example.com/conformance.png",
214
+ profile: "https://example.com/conformance",
215
+ website: "https://example.com",
216
+ gender: "other",
217
+ birthdate: "2000-01-01",
218
+ zoneinfo: "Europe/London",
219
+ locale: "en-US",
220
+ connection: "Username-Password-Authentication",
221
+ provider: "auth2",
222
+ is_social: false,
223
+ });
224
+ console.log("✅ Created conformance test user (conformance@example.com)");
225
+ } catch (e: any) {
226
+ if (e.message?.includes("UNIQUE constraint")) {
227
+ console.log("ℹ️ conformance test user already exists");
228
+ } else {
229
+ throw e;
230
+ }
231
+ }
232
+
233
+ // Create password for conformance test user
234
+ // Password: ConformanceTest123!
235
+ try {
236
+ const bcrypt = await import("bcryptjs");
237
+ const hashedPassword = await bcrypt.hash("ConformanceTest123!", 10);
238
+ await adapters.passwords.create("${r}", {
239
+ user_id: "auth2|conformance-user",
240
+ password: hashedPassword,
241
+ });
242
+ console.log("✅ Created password for conformance test user");
243
+ } catch (e: any) {
244
+ if (e.message?.includes("UNIQUE constraint")) {
245
+ console.log("ℹ️ conformance test user password already exists");
246
+ } else {
247
+ throw e;
248
+ }
249
+ }
250
+ ` : "";
131
251
  return `import { SqliteDialect, Kysely } from "kysely";
132
252
  import Database from "better-sqlite3";
133
253
  import createAdapters from "@authhero/kysely-adapter";
@@ -153,18 +273,20 @@ async function main() {
153
273
  await seed(adapters, {
154
274
  adminEmail,
155
275
  adminPassword,
156
- tenantId: "${t ? "control_plane" : "main"}",
157
- tenantName: "${t ? "Control Plane" : "Main"}",
276
+ tenantId: "${r}",
277
+ tenantName: "${n}",
158
278
  isControlPlane: ${t},
279
+ callbacks: ${JSON.stringify(g)},
280
+ allowedLogoutUrls: ${JSON.stringify(x)},
159
281
  });
160
-
282
+ ${v}
161
283
  await db.destroy();
162
284
  }
163
285
 
164
286
  main().catch(console.error);
165
287
  `;
166
288
  }
167
- function R(t) {
289
+ function O(t) {
168
290
  return t ? `import { Context } from "hono";
169
291
  import { swaggerUI } from "@hono/swagger-ui";
170
292
  import { AuthHeroConfig, DataAdapters } from "authhero";
@@ -268,7 +390,7 @@ export default function createApp(config: AuthHeroConfig) {
268
390
  }
269
391
  `;
270
392
  }
271
- function L(t) {
393
+ function j(t) {
272
394
  return `import { D1Dialect } from "kysely-d1";
273
395
  import { Kysely } from "kysely";
274
396
  import createAdapters from "@authhero/kysely-adapter";
@@ -341,7 +463,7 @@ export default {
341
463
  };
342
464
  `;
343
465
  }
344
- function M(t) {
466
+ function U(t) {
345
467
  return t ? `import { Context } from "hono";
346
468
  import { swaggerUI } from "@hono/swagger-ui";
347
469
  import { AuthHeroConfig, DataAdapters } from "authhero";
@@ -421,7 +543,7 @@ export default function createApp(config: AuthHeroConfig) {
421
543
  }
422
544
  `;
423
545
  }
424
- function j(t) {
546
+ function M(t) {
425
547
  return t ? `import { Context } from "hono";
426
548
  import { swaggerUI } from "@hono/swagger-ui";
427
549
  import { AuthHeroConfig, DataAdapters } from "authhero";
@@ -527,7 +649,7 @@ export default function createApp(config: AppConfig) {
527
649
  }
528
650
  `;
529
651
  }
530
- function O(t) {
652
+ function $(t) {
531
653
  return `import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
532
654
  import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
533
655
  import createAdapters from "@authhero/aws";
@@ -573,23 +695,23 @@ async function main() {
573
695
  main().catch(console.error);
574
696
  `;
575
697
  }
576
- function $(t, e) {
577
- const r = i.join(t, "src");
578
- a.writeFileSync(
579
- i.join(r, "app.ts"),
580
- j(e)
581
- ), a.writeFileSync(
582
- i.join(r, "seed.ts"),
583
- O(e)
698
+ function H(t, e) {
699
+ const o = l.join(t, "src");
700
+ s.writeFileSync(
701
+ l.join(o, "app.ts"),
702
+ M(e)
703
+ ), s.writeFileSync(
704
+ l.join(o, "seed.ts"),
705
+ $(e)
584
706
  );
585
707
  }
586
- function C(t) {
708
+ function I(t) {
587
709
  console.log("\\n" + "─".repeat(50)), console.log("🔐 AuthHero deployed to AWS!"), console.log("📚 Check SST output for your API URL"), console.log("🌐 Portal available at https://local.authhero.net"), console.log(t ? "🏢 Multi-tenant mode enabled with control_plane tenant" : "🏠 Single-tenant mode with 'main' tenant"), console.log("─".repeat(50) + "\\n");
588
710
  }
589
- function H(t) {
590
- const e = i.join(t, ".github", "workflows");
591
- a.mkdirSync(e, { recursive: !0 });
592
- const r = `name: Unit tests
711
+ function F(t) {
712
+ const e = l.join(t, ".github", "workflows");
713
+ s.mkdirSync(e, { recursive: !0 });
714
+ const o = `name: Unit tests
593
715
 
594
716
  on: push
595
717
 
@@ -610,7 +732,7 @@ jobs:
610
732
 
611
733
  - run: npm run type-check
612
734
  - run: npm test
613
- `, s = `name: Deploy to Dev
735
+ `, r = `name: Deploy to Dev
614
736
 
615
737
  on:
616
738
  push:
@@ -675,9 +797,9 @@ jobs:
675
797
  apiToken: \${{ secrets.PROD_CLOUDFLARE_API_TOKEN }}
676
798
  command: deploy --env production
677
799
  `;
678
- a.writeFileSync(i.join(e, "unit-tests.yml"), r), a.writeFileSync(i.join(e, "deploy-dev.yml"), s), a.writeFileSync(i.join(e, "release.yml"), n), console.log("\\n📦 GitHub CI workflows created!");
800
+ s.writeFileSync(l.join(e, "unit-tests.yml"), o), s.writeFileSync(l.join(e, "deploy-dev.yml"), r), s.writeFileSync(l.join(e, "release.yml"), n), console.log("\\n📦 GitHub CI workflows created!");
679
801
  }
680
- function U(t) {
802
+ function W(t) {
681
803
  const e = {
682
804
  branches: ["main"],
683
805
  plugins: [
@@ -686,75 +808,78 @@ function U(t) {
686
808
  "@semantic-release/github"
687
809
  ]
688
810
  };
689
- a.writeFileSync(
690
- i.join(t, ".releaserc.json"),
811
+ s.writeFileSync(
812
+ l.join(t, ".releaserc.json"),
691
813
  JSON.stringify(e, null, 2)
692
814
  );
693
- const r = i.join(t, "package.json"), s = JSON.parse(a.readFileSync(r, "utf-8"));
694
- s.devDependencies = {
695
- ...s.devDependencies,
815
+ const o = l.join(t, "package.json"), r = JSON.parse(s.readFileSync(o, "utf-8"));
816
+ r.devDependencies = {
817
+ ...r.devDependencies,
696
818
  "semantic-release": "^24.0.0"
697
- }, s.scripts = {
698
- ...s.scripts,
819
+ }, r.scripts = {
820
+ ...r.scripts,
699
821
  test: 'echo "No tests yet"',
700
822
  "type-check": "tsc --noEmit"
701
- }, a.writeFileSync(r, JSON.stringify(s, null, 2));
823
+ }, s.writeFileSync(o, JSON.stringify(r, null, 2));
702
824
  }
703
- function v(t, e) {
704
- return new Promise((r, s) => {
825
+ function b(t, e) {
826
+ return new Promise((o, r) => {
705
827
  const n = N(t, [], {
706
828
  cwd: e,
707
829
  shell: !0,
708
830
  stdio: "inherit"
709
831
  });
710
- n.on("close", (o) => {
711
- o === 0 ? r() : s(new Error(`Command failed with exit code ${o}`));
712
- }), n.on("error", s);
832
+ n.on("close", (a) => {
833
+ a === 0 ? o() : r(new Error(`Command failed with exit code ${a}`));
834
+ }), n.on("error", r);
713
835
  });
714
836
  }
715
- function D(t, e, r) {
716
- return new Promise((s, n) => {
717
- const o = N(t, [], {
837
+ function D(t, e, o) {
838
+ return new Promise((r, n) => {
839
+ const a = N(t, [], {
718
840
  cwd: e,
719
841
  shell: !0,
720
842
  stdio: "inherit",
721
- env: { ...process.env, ...r }
843
+ env: { ...process.env, ...o }
722
844
  });
723
- o.on("close", (c) => {
724
- c === 0 ? s() : n(new Error(`Command failed with exit code ${c}`));
725
- }), o.on("error", n);
845
+ a.on("close", (c) => {
846
+ c === 0 ? r() : n(new Error(`Command failed with exit code ${c}`));
847
+ }), a.on("error", n);
726
848
  });
727
849
  }
728
- function F(t, e) {
729
- const r = i.join(t, "src");
730
- a.writeFileSync(
731
- i.join(r, "app.ts"),
732
- M(e)
733
- ), a.writeFileSync(
734
- i.join(r, "seed.ts"),
735
- L(e)
850
+ function q(t, e) {
851
+ const o = l.join(t, "src");
852
+ s.writeFileSync(
853
+ l.join(o, "app.ts"),
854
+ U(e)
855
+ ), s.writeFileSync(
856
+ l.join(o, "seed.ts"),
857
+ j(e)
736
858
  );
737
859
  }
738
- function I(t) {
860
+ function k(t) {
739
861
  console.log(`
740
862
  ` + "─".repeat(50)), console.log("🔐 AuthHero server running at https://localhost:3000"), console.log("📚 API documentation available at https://localhost:3000/docs"), console.log("🌐 Portal available at https://local.authhero.net"), console.log(t ? "🏢 Multi-tenant mode enabled with control_plane tenant" : "🏠 Single-tenant mode with 'main' tenant"), console.log("─".repeat(50) + `
741
863
  `);
742
864
  }
743
- function x(t) {
865
+ function _(t) {
744
866
  console.log(`
745
867
  ` + "─".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 https://localhost:3000"), console.log("📚 API documentation available at https://localhost:3000/docs"), console.log("🌐 Portal available at https://local.authhero.net"), console.log(t ? "🏢 Multi-tenant mode enabled with control_plane tenant" : "🏠 Single-tenant mode with 'main' tenant"), console.log("─".repeat(50) + `
746
868
  `);
747
869
  }
748
- b.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("-e, --email <email>", "admin email address").option("-p, --password <password>", "admin password (min 8 characters)").option(
870
+ 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("-e, --email <email>", "admin email address").option("-p, --password <password>", "admin password (min 8 characters)").option(
749
871
  "--package-manager <pm>",
750
872
  "package manager to use: npm, yarn, pnpm, or bun"
751
- ).option("--multi-tenant", "enable multi-tenant mode").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 (t, e) => {
752
- const r = e.yes === !0;
873
+ ).option("--multi-tenant", "enable multi-tenant mode").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("--conformance", "add OpenID conformance suite test clients").option(
874
+ "--conformance-alias <alias>",
875
+ "alias for conformance suite (default: authhero-local)"
876
+ ).option("-y, --yes", "skip all prompts and use defaults/provided options").action(async (t, e) => {
877
+ const o = e.yes === !0;
753
878
  console.log(`
754
879
  🔐 Welcome to AuthHero!
755
880
  `);
756
- let s = t;
757
- s || (r ? (s = "auth-server", console.log(`Using default project name: ${s}`)) : s = (await u.prompt([
881
+ let r = t;
882
+ r || (o ? (r = "auth-server", console.log(`Using default project name: ${r}`)) : r = (await u.prompt([
758
883
  {
759
884
  type: "input",
760
885
  name: "projectName",
@@ -763,10 +888,10 @@ b.version("1.0.0").description("Create a new AuthHero project").argument("[proje
763
888
  validate: (d) => d !== "" || "Project name cannot be empty"
764
889
  }
765
890
  ])).projectName);
766
- const n = i.join(process.cwd(), s);
767
- a.existsSync(n) && (console.error(`❌ Project "${s}" already exists.`), process.exit(1));
768
- let o;
769
- 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)), o = e.template, console.log(`Using template: ${p[o].name}`)) : o = (await u.prompt([
891
+ const n = l.join(process.cwd(), r);
892
+ s.existsSync(n) && (console.error(`❌ Project "${r}" already exists.`), process.exit(1));
893
+ let a;
894
+ 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)), a = e.template, console.log(`Using template: ${p[a].name}`)) : a = (await u.prompt([
770
895
  {
771
896
  type: "list",
772
897
  name: "setupType",
@@ -794,7 +919,7 @@ b.version("1.0.0").description("Create a new AuthHero project").argument("[proje
794
919
  }
795
920
  ])).setupType;
796
921
  let c;
797
- e.multiTenant !== void 0 ? (c = e.multiTenant, console.log(`Multi-tenant mode: ${c ? "enabled" : "disabled"}`)) : r ? c = !1 : c = (await u.prompt([
922
+ e.multiTenant !== void 0 ? (c = e.multiTenant, console.log(`Multi-tenant mode: ${c ? "enabled" : "disabled"}`)) : o ? c = !1 : c = (await u.prompt([
798
923
  {
799
924
  type: "confirm",
800
925
  name: "multiTenant",
@@ -803,57 +928,90 @@ b.version("1.0.0").description("Create a new AuthHero project").argument("[proje
803
928
  default: !1
804
929
  }
805
930
  ])).multiTenant;
806
- const A = p[o];
807
- a.mkdirSync(n, { recursive: !0 }), a.writeFileSync(
808
- i.join(n, "package.json"),
809
- JSON.stringify(A.packageJson(s, c), null, 2)
931
+ const g = e.conformance || !1, w = e.conformanceAlias || "authhero-local";
932
+ g && console.log(
933
+ `OpenID Conformance Suite: enabled (alias: ${w})`
934
+ );
935
+ const y = p[a];
936
+ s.mkdirSync(n, { recursive: !0 }), s.writeFileSync(
937
+ l.join(n, "package.json"),
938
+ JSON.stringify(y.packageJson(r, c, g), null, 2)
810
939
  );
811
- const _ = A.templateDir, S = i.join(
940
+ const x = y.templateDir, v = l.join(
812
941
  import.meta.url.replace("file://", "").replace("/create-authhero.js", ""),
813
- _
942
+ x
814
943
  );
815
- if (a.existsSync(S) ? E(S, n) : (console.error(`❌ Template directory not found: ${S}`), process.exit(1)), o === "cloudflare" && F(n, c), o === "cloudflare") {
816
- const l = i.join(n, "wrangler.toml"), d = i.join(n, "wrangler.local.toml");
817
- a.existsSync(l) && a.copyFileSync(l, d);
818
- const m = i.join(n, ".dev.vars.example"), g = i.join(n, ".dev.vars");
819
- a.existsSync(m) && a.copyFileSync(m, g), console.log(
944
+ if (s.existsSync(v) ? E(v, n) : (console.error(`❌ Template directory not found: ${v}`), process.exit(1)), a === "cloudflare" && q(n, c), a === "cloudflare") {
945
+ const i = l.join(n, "wrangler.toml"), d = l.join(n, "wrangler.local.toml");
946
+ s.existsSync(i) && s.copyFileSync(i, d);
947
+ const m = l.join(n, ".dev.vars.example"), f = l.join(n, ".dev.vars");
948
+ s.existsSync(m) && s.copyFileSync(m, f), console.log(
820
949
  "📁 Created wrangler.local.toml and .dev.vars for local development"
821
950
  );
822
951
  }
823
- let w = !1;
824
- if (o === "cloudflare" && (e.githubCi !== void 0 ? (w = e.githubCi, w && console.log("Including GitHub CI workflows with semantic versioning")) : r || (w = (await u.prompt([
952
+ let C = !1;
953
+ if (a === "cloudflare" && (e.githubCi !== void 0 ? (C = e.githubCi, C && console.log("Including GitHub CI workflows with semantic versioning")) : o || (C = (await u.prompt([
825
954
  {
826
955
  type: "confirm",
827
956
  name: "includeGithubCi",
828
957
  message: "Would you like to include GitHub CI with semantic versioning?",
829
958
  default: !1
830
959
  }
831
- ])).includeGithubCi), w && (H(n), U(n))), o === "local") {
832
- const l = P(c);
833
- a.writeFileSync(i.join(n, "src/seed.ts"), l);
834
- const d = R(c);
835
- a.writeFileSync(i.join(n, "src/app.ts"), d);
960
+ ])).includeGithubCi), C && (F(n), W(n))), a === "local") {
961
+ const i = R(
962
+ c,
963
+ g,
964
+ w
965
+ );
966
+ s.writeFileSync(l.join(n, "src/seed.ts"), i);
967
+ const d = O(c);
968
+ s.writeFileSync(l.join(n, "src/app.ts"), d);
969
+ }
970
+ if (a === "aws-sst" && H(n, c), g) {
971
+ const i = {
972
+ alias: w,
973
+ description: "AuthHero Conformance Test",
974
+ server: {
975
+ discoveryUrl: "http://host.docker.internal:3000/.well-known/openid-configuration"
976
+ },
977
+ client: {
978
+ client_id: "conformance-test",
979
+ client_secret: "conformanceTestSecret123"
980
+ },
981
+ client2: {
982
+ client_id: "conformance-test2",
983
+ client_secret: "conformanceTestSecret456"
984
+ },
985
+ resource: {
986
+ resourceUrl: "http://host.docker.internal:3000/userinfo"
987
+ }
988
+ };
989
+ s.writeFileSync(
990
+ l.join(n, "conformance-config.json"),
991
+ JSON.stringify(i, null, 2)
992
+ ), console.log(
993
+ "📝 Created conformance-config.json for OpenID Conformance Suite"
994
+ );
836
995
  }
837
- o === "aws-sst" && $(n, c);
838
- const T = c ? "multi-tenant" : "single-tenant";
996
+ const P = c ? "multi-tenant" : "single-tenant";
839
997
  console.log(
840
998
  `
841
- ✅ Project "${s}" has been created with ${A.name} (${T}) setup!
999
+ ✅ Project "${r}" has been created with ${y.name} (${P}) setup!
842
1000
  `
843
1001
  );
844
- let h;
845
- if (e.skipInstall ? h = !1 : r ? h = !0 : h = (await u.prompt([
1002
+ let A;
1003
+ if (e.skipInstall ? A = !1 : o ? A = !0 : A = (await u.prompt([
846
1004
  {
847
1005
  type: "confirm",
848
1006
  name: "shouldInstall",
849
1007
  message: "Would you like to install dependencies now?",
850
1008
  default: !0
851
1009
  }
852
- ])).shouldInstall, h) {
853
- let l;
1010
+ ])).shouldInstall, A) {
1011
+ let i;
854
1012
  e.packageManager ? (["npm", "yarn", "pnpm", "bun"].includes(e.packageManager) || (console.error(
855
1013
  `❌ Invalid package manager: ${e.packageManager}`
856
- ), console.error("Valid options: npm, yarn, pnpm, bun"), process.exit(1)), l = e.packageManager) : r ? l = "pnpm" : l = (await u.prompt([
1014
+ ), console.error("Valid options: npm, yarn, pnpm, bun"), process.exit(1)), i = e.packageManager) : o ? i = "pnpm" : i = (await u.prompt([
857
1015
  {
858
1016
  type: "list",
859
1017
  name: "packageManager",
@@ -867,92 +1025,99 @@ b.version("1.0.0").description("Create a new AuthHero project").argument("[proje
867
1025
  default: "pnpm"
868
1026
  }
869
1027
  ])).packageManager, console.log(`
870
- 📦 Installing dependencies with ${l}...
1028
+ 📦 Installing dependencies with ${i}...
871
1029
  `);
872
1030
  try {
873
- const d = l === "pnpm" ? "pnpm install --ignore-workspace" : `${l} install`;
874
- if (await v(d, n), o === "local" && (console.log(`
1031
+ const d = i === "pnpm" ? "pnpm install --ignore-workspace" : `${i} install`;
1032
+ if (await b(d, n), a === "local" && (console.log(`
875
1033
  🔧 Building native modules...
876
- `), await v("npm rebuild better-sqlite3", n)), console.log(`
1034
+ `), await b("npm rebuild better-sqlite3", n)), console.log(`
877
1035
  ✅ Dependencies installed successfully!
878
- `), o === "local" || o === "cloudflare") {
879
- let g;
880
- if (e.skipMigrate && e.skipSeed ? g = !1 : r ? g = !e.skipMigrate || !e.skipSeed : g = (await u.prompt([
1036
+ `), a === "local" || a === "cloudflare") {
1037
+ let f;
1038
+ if (e.skipMigrate && e.skipSeed ? f = !1 : o ? f = !e.skipMigrate || !e.skipSeed : f = (await u.prompt([
881
1039
  {
882
1040
  type: "confirm",
883
1041
  name: "shouldSetup",
884
1042
  message: "Would you like to run migrations and seed the database?",
885
1043
  default: !0
886
1044
  }
887
- ])).shouldSetup, g) {
888
- let f;
889
- 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)), f = {
1045
+ ])).shouldSetup, f) {
1046
+ let h;
1047
+ 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)), h = {
890
1048
  username: e.email,
891
1049
  password: e.password
892
- }, console.log(`Using admin email: ${e.email}`)) : f = await u.prompt([
1050
+ }, console.log(`Using admin email: ${e.email}`)) : h = await u.prompt([
893
1051
  {
894
1052
  type: "input",
895
1053
  name: "username",
896
1054
  message: "Admin email:",
897
1055
  default: "admin@example.com",
898
- validate: (y) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(y) || "Please enter a valid email address"
1056
+ validate: (S) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(S) || "Please enter a valid email address"
899
1057
  },
900
1058
  {
901
1059
  type: "password",
902
1060
  name: "password",
903
1061
  message: "Admin password:",
904
1062
  mask: "*",
905
- validate: (y) => y.length < 8 ? "Password must be at least 8 characters" : !0
1063
+ validate: (S) => S.length < 8 ? "Password must be at least 8 characters" : !0
906
1064
  }
907
1065
  ]), e.skipMigrate || (console.log(`
908
1066
  🔄 Running migrations...
909
- `), await v(`${l} run migrate`, n)), e.skipSeed || (console.log(`
1067
+ `), await b(`${i} run migrate`, n)), e.skipSeed || (console.log(`
910
1068
  🌱 Seeding database...
911
- `), o === "local" ? await D(
912
- `${l} run seed`,
1069
+ `), a === "local" ? await D(
1070
+ `${i} run seed`,
913
1071
  n,
914
1072
  {
915
- ADMIN_EMAIL: f.username,
916
- ADMIN_PASSWORD: f.password
1073
+ ADMIN_EMAIL: h.username,
1074
+ ADMIN_PASSWORD: h.password
917
1075
  }
918
1076
  ) : await D(
919
- `${l} run seed:local`,
1077
+ `${i} run seed:local`,
920
1078
  n,
921
1079
  {
922
- ADMIN_EMAIL: f.username,
923
- ADMIN_PASSWORD: f.password
1080
+ ADMIN_EMAIL: h.username,
1081
+ ADMIN_PASSWORD: h.password
924
1082
  }
925
1083
  ));
926
1084
  }
927
1085
  }
928
1086
  let m;
929
- e.skipStart || r ? m = !1 : m = (await u.prompt([
1087
+ e.skipStart || o ? m = !1 : m = (await u.prompt([
930
1088
  {
931
1089
  type: "confirm",
932
1090
  name: "shouldStart",
933
1091
  message: "Would you like to start the development server?",
934
1092
  default: !0
935
1093
  }
936
- ])).shouldStart, m && (o === "cloudflare" ? I(c) : o === "aws-sst" ? C(c) : x(c), console.log(`🚀 Starting development server...
937
- `), await v(`${l} run dev`, n)), r && !m && (console.log(`
1094
+ ])).shouldStart, m && (a === "cloudflare" ? k(c) : a === "aws-sst" ? I(c) : _(c), console.log(`🚀 Starting development server...
1095
+ `), await b(`${i} run dev`, n)), o && !m && (console.log(`
938
1096
  ✅ Setup complete!`), console.log(`
939
- To start the development server:`), console.log(` cd ${s}`), console.log(" npm run dev"), o === "cloudflare" ? I(c) : o === "aws-sst" ? C(c) : x(c));
1097
+ To start the development server:`), console.log(` cd ${r}`), console.log(" npm run dev"), a === "cloudflare" ? k(c) : a === "aws-sst" ? I(c) : _(c));
940
1098
  } catch (d) {
941
1099
  console.error(`
942
1100
  ❌ An error occurred:`, d), process.exit(1);
943
1101
  }
944
1102
  }
945
- h || (console.log("Next steps:"), console.log(` cd ${s}`), o === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(
1103
+ A || (console.log("Next steps:"), console.log(` cd ${r}`), a === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(
946
1104
  " ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed"
947
- ), console.log(" npm run dev")) : o === "cloudflare" ? (console.log(" npm install"), console.log(
1105
+ ), console.log(" npm run dev")) : a === "cloudflare" ? (console.log(" npm install"), console.log(
948
1106
  " npm run migrate # or npm run db:migrate:remote for production"
949
1107
  ), console.log(
950
1108
  " ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed"
951
- ), console.log(" npm run dev # or npm run dev:remote for production")) : o === "aws-sst" && (console.log(" npm install"), console.log(" npm run dev # Deploys to AWS in development mode"), console.log(" # After deploy, get TABLE_NAME from output, then:"), console.log(
1109
+ ), console.log(" npm run dev # or npm run dev:remote for production")) : a === "aws-sst" && (console.log(" npm install"), console.log(" npm run dev # Deploys to AWS in development mode"), console.log(" # After deploy, get TABLE_NAME from output, then:"), console.log(
952
1110
  " TABLE_NAME=<your-table> ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed"
953
1111
  )), console.log(`
954
- Server will be available at: https://localhost:3000`), console.log("Portal available at: https://local.authhero.net"), console.log(`
1112
+ Server will be available at: https://localhost:3000`), console.log("Portal available at: https://local.authhero.net"), g && (console.log(`
1113
+ 🧪 OpenID Conformance Suite Testing:`), console.log(
1114
+ " 1. Clone and start the conformance suite (if not already running):"
1115
+ ), console.log(
1116
+ " git clone https://gitlab.com/openid/conformance-suite.git"
1117
+ ), console.log(" cd conformance-suite && mvn clean package"), console.log(" docker-compose up -d"), console.log(" 2. Open https://localhost.emobix.co.uk:8443"), console.log(
1118
+ " 3. Create a test plan and use conformance-config.json for settings"
1119
+ ), console.log(` 4. Use alias: ${w}`)), console.log(`
955
1120
  For more information, visit: https://authhero.net/docs
956
1121
  `));
957
1122
  });
958
- b.parse(process.argv);
1123
+ T.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.25.0",
8
+ "version": "0.26.0",
9
9
  "type": "module",
10
10
  "main": "dist/create-authhero.js",
11
11
  "bin": {