create-authhero 0.24.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.
- package/dist/create-authhero.js +310 -133
- package/package.json +1 -1
package/dist/create-authhero.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Command as
|
|
2
|
+
import { Command as L } from "commander";
|
|
3
3
|
import u from "inquirer";
|
|
4
4
|
import s from "fs";
|
|
5
|
-
import
|
|
6
|
-
import { spawn as
|
|
7
|
-
const
|
|
5
|
+
import l from "path";
|
|
6
|
+
import { spawn as N } from "child_process";
|
|
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 N = new P(), 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 N = new P(), 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 N = new P(), 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 N = new P(), 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 N = new P(), 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",
|
|
@@ -121,13 +124,130 @@ const N = new P(), p = {
|
|
|
121
124
|
seedFile: "seed.ts"
|
|
122
125
|
}
|
|
123
126
|
};
|
|
124
|
-
function
|
|
125
|
-
s.readdirSync(t).forEach((
|
|
126
|
-
const n =
|
|
127
|
-
s.lstatSync(n).isDirectory() ? (s.mkdirSync(
|
|
127
|
+
function E(t, e) {
|
|
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
|
|
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,32 +273,38 @@ async function main() {
|
|
|
153
273
|
await seed(adapters, {
|
|
154
274
|
adminEmail,
|
|
155
275
|
adminPassword,
|
|
156
|
-
tenantId: "${
|
|
157
|
-
tenantName: "${
|
|
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
|
|
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";
|
|
171
293
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
172
294
|
import { initMultiTenant } from "@authhero/multi-tenancy";
|
|
173
295
|
|
|
174
|
-
// Control plane
|
|
296
|
+
// Control plane configuration
|
|
175
297
|
const CONTROL_PLANE_TENANT_ID = "control_plane";
|
|
298
|
+
const CONTROL_PLANE_CLIENT_ID = "default_client";
|
|
176
299
|
|
|
177
300
|
export default function createApp(config: AuthHeroConfig & { dataAdapter: DataAdapters }) {
|
|
178
301
|
// Initialize multi-tenant AuthHero - syncs resource servers, roles, and connections by default
|
|
179
302
|
const { app } = initMultiTenant({
|
|
180
303
|
...config,
|
|
181
|
-
|
|
304
|
+
controlPlane: {
|
|
305
|
+
tenantId: CONTROL_PLANE_TENANT_ID,
|
|
306
|
+
clientId: CONTROL_PLANE_CLIENT_ID,
|
|
307
|
+
},
|
|
182
308
|
});
|
|
183
309
|
|
|
184
310
|
app
|
|
@@ -264,7 +390,7 @@ export default function createApp(config: AuthHeroConfig) {
|
|
|
264
390
|
}
|
|
265
391
|
`;
|
|
266
392
|
}
|
|
267
|
-
function
|
|
393
|
+
function j(t) {
|
|
268
394
|
return `import { D1Dialect } from "kysely-d1";
|
|
269
395
|
import { Kysely } from "kysely";
|
|
270
396
|
import createAdapters from "@authhero/kysely-adapter";
|
|
@@ -337,20 +463,24 @@ export default {
|
|
|
337
463
|
};
|
|
338
464
|
`;
|
|
339
465
|
}
|
|
340
|
-
function
|
|
466
|
+
function U(t) {
|
|
341
467
|
return t ? `import { Context } from "hono";
|
|
342
468
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
343
469
|
import { AuthHeroConfig, DataAdapters } from "authhero";
|
|
344
470
|
import { initMultiTenant } from "@authhero/multi-tenancy";
|
|
345
471
|
|
|
346
|
-
// Control plane
|
|
472
|
+
// Control plane configuration
|
|
347
473
|
const CONTROL_PLANE_TENANT_ID = "control_plane";
|
|
474
|
+
const CONTROL_PLANE_CLIENT_ID = "default_client";
|
|
348
475
|
|
|
349
476
|
export default function createApp(config: AuthHeroConfig & { dataAdapter: DataAdapters }) {
|
|
350
477
|
// Initialize multi-tenant AuthHero - syncs resource servers, roles, and connections by default
|
|
351
478
|
const { app } = initMultiTenant({
|
|
352
479
|
...config,
|
|
353
|
-
|
|
480
|
+
controlPlane: {
|
|
481
|
+
tenantId: CONTROL_PLANE_TENANT_ID,
|
|
482
|
+
clientId: CONTROL_PLANE_CLIENT_ID,
|
|
483
|
+
},
|
|
354
484
|
});
|
|
355
485
|
|
|
356
486
|
app
|
|
@@ -413,14 +543,15 @@ export default function createApp(config: AuthHeroConfig) {
|
|
|
413
543
|
}
|
|
414
544
|
`;
|
|
415
545
|
}
|
|
416
|
-
function
|
|
546
|
+
function M(t) {
|
|
417
547
|
return t ? `import { Context } from "hono";
|
|
418
548
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
419
549
|
import { AuthHeroConfig, DataAdapters } from "authhero";
|
|
420
550
|
import { initMultiTenant } from "@authhero/multi-tenancy";
|
|
421
551
|
|
|
422
|
-
// Control plane
|
|
552
|
+
// Control plane configuration
|
|
423
553
|
const CONTROL_PLANE_TENANT_ID = "control_plane";
|
|
554
|
+
const CONTROL_PLANE_CLIENT_ID = "default_client";
|
|
424
555
|
|
|
425
556
|
interface AppConfig extends AuthHeroConfig {
|
|
426
557
|
dataAdapter: DataAdapters;
|
|
@@ -431,7 +562,10 @@ export default function createApp(config: AppConfig) {
|
|
|
431
562
|
// Initialize multi-tenant AuthHero
|
|
432
563
|
const { app } = initMultiTenant({
|
|
433
564
|
...config,
|
|
434
|
-
|
|
565
|
+
controlPlane: {
|
|
566
|
+
tenantId: CONTROL_PLANE_TENANT_ID,
|
|
567
|
+
clientId: CONTROL_PLANE_CLIENT_ID,
|
|
568
|
+
},
|
|
435
569
|
});
|
|
436
570
|
|
|
437
571
|
app
|
|
@@ -561,23 +695,23 @@ async function main() {
|
|
|
561
695
|
main().catch(console.error);
|
|
562
696
|
`;
|
|
563
697
|
}
|
|
564
|
-
function
|
|
565
|
-
const
|
|
698
|
+
function H(t, e) {
|
|
699
|
+
const o = l.join(t, "src");
|
|
566
700
|
s.writeFileSync(
|
|
567
|
-
|
|
568
|
-
|
|
701
|
+
l.join(o, "app.ts"),
|
|
702
|
+
M(e)
|
|
569
703
|
), s.writeFileSync(
|
|
570
|
-
|
|
704
|
+
l.join(o, "seed.ts"),
|
|
571
705
|
$(e)
|
|
572
706
|
);
|
|
573
707
|
}
|
|
574
|
-
function
|
|
708
|
+
function I(t) {
|
|
575
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");
|
|
576
710
|
}
|
|
577
|
-
function
|
|
578
|
-
const e =
|
|
711
|
+
function F(t) {
|
|
712
|
+
const e = l.join(t, ".github", "workflows");
|
|
579
713
|
s.mkdirSync(e, { recursive: !0 });
|
|
580
|
-
const
|
|
714
|
+
const o = `name: Unit tests
|
|
581
715
|
|
|
582
716
|
on: push
|
|
583
717
|
|
|
@@ -598,7 +732,7 @@ jobs:
|
|
|
598
732
|
|
|
599
733
|
- run: npm run type-check
|
|
600
734
|
- run: npm test
|
|
601
|
-
`,
|
|
735
|
+
`, r = `name: Deploy to Dev
|
|
602
736
|
|
|
603
737
|
on:
|
|
604
738
|
push:
|
|
@@ -663,9 +797,9 @@ jobs:
|
|
|
663
797
|
apiToken: \${{ secrets.PROD_CLOUDFLARE_API_TOKEN }}
|
|
664
798
|
command: deploy --env production
|
|
665
799
|
`;
|
|
666
|
-
s.writeFileSync(
|
|
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!");
|
|
667
801
|
}
|
|
668
|
-
function
|
|
802
|
+
function W(t) {
|
|
669
803
|
const e = {
|
|
670
804
|
branches: ["main"],
|
|
671
805
|
plugins: [
|
|
@@ -675,74 +809,77 @@ function U(t) {
|
|
|
675
809
|
]
|
|
676
810
|
};
|
|
677
811
|
s.writeFileSync(
|
|
678
|
-
|
|
812
|
+
l.join(t, ".releaserc.json"),
|
|
679
813
|
JSON.stringify(e, null, 2)
|
|
680
814
|
);
|
|
681
|
-
const
|
|
682
|
-
|
|
683
|
-
...
|
|
815
|
+
const o = l.join(t, "package.json"), r = JSON.parse(s.readFileSync(o, "utf-8"));
|
|
816
|
+
r.devDependencies = {
|
|
817
|
+
...r.devDependencies,
|
|
684
818
|
"semantic-release": "^24.0.0"
|
|
685
|
-
},
|
|
686
|
-
...
|
|
819
|
+
}, r.scripts = {
|
|
820
|
+
...r.scripts,
|
|
687
821
|
test: 'echo "No tests yet"',
|
|
688
822
|
"type-check": "tsc --noEmit"
|
|
689
|
-
}, s.writeFileSync(
|
|
823
|
+
}, s.writeFileSync(o, JSON.stringify(r, null, 2));
|
|
690
824
|
}
|
|
691
|
-
function
|
|
692
|
-
return new Promise((
|
|
693
|
-
const n =
|
|
825
|
+
function b(t, e) {
|
|
826
|
+
return new Promise((o, r) => {
|
|
827
|
+
const n = N(t, [], {
|
|
694
828
|
cwd: e,
|
|
695
829
|
shell: !0,
|
|
696
830
|
stdio: "inherit"
|
|
697
831
|
});
|
|
698
|
-
n.on("close", (
|
|
699
|
-
|
|
700
|
-
}), n.on("error",
|
|
832
|
+
n.on("close", (a) => {
|
|
833
|
+
a === 0 ? o() : r(new Error(`Command failed with exit code ${a}`));
|
|
834
|
+
}), n.on("error", r);
|
|
701
835
|
});
|
|
702
836
|
}
|
|
703
|
-
function D(t, e,
|
|
704
|
-
return new Promise((
|
|
705
|
-
const
|
|
837
|
+
function D(t, e, o) {
|
|
838
|
+
return new Promise((r, n) => {
|
|
839
|
+
const a = N(t, [], {
|
|
706
840
|
cwd: e,
|
|
707
841
|
shell: !0,
|
|
708
842
|
stdio: "inherit",
|
|
709
|
-
env: { ...process.env, ...
|
|
843
|
+
env: { ...process.env, ...o }
|
|
710
844
|
});
|
|
711
|
-
|
|
712
|
-
c === 0 ?
|
|
713
|
-
}),
|
|
845
|
+
a.on("close", (c) => {
|
|
846
|
+
c === 0 ? r() : n(new Error(`Command failed with exit code ${c}`));
|
|
847
|
+
}), a.on("error", n);
|
|
714
848
|
});
|
|
715
849
|
}
|
|
716
|
-
function
|
|
717
|
-
const
|
|
850
|
+
function q(t, e) {
|
|
851
|
+
const o = l.join(t, "src");
|
|
718
852
|
s.writeFileSync(
|
|
719
|
-
|
|
720
|
-
|
|
853
|
+
l.join(o, "app.ts"),
|
|
854
|
+
U(e)
|
|
721
855
|
), s.writeFileSync(
|
|
722
|
-
|
|
723
|
-
|
|
856
|
+
l.join(o, "seed.ts"),
|
|
857
|
+
j(e)
|
|
724
858
|
);
|
|
725
859
|
}
|
|
726
|
-
function
|
|
860
|
+
function k(t) {
|
|
727
861
|
console.log(`
|
|
728
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) + `
|
|
729
863
|
`);
|
|
730
864
|
}
|
|
731
|
-
function
|
|
865
|
+
function _(t) {
|
|
732
866
|
console.log(`
|
|
733
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) + `
|
|
734
868
|
`);
|
|
735
869
|
}
|
|
736
|
-
|
|
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(
|
|
737
871
|
"--package-manager <pm>",
|
|
738
872
|
"package manager to use: npm, yarn, pnpm, or bun"
|
|
739
|
-
).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("
|
|
740
|
-
|
|
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;
|
|
741
878
|
console.log(`
|
|
742
879
|
🔐 Welcome to AuthHero!
|
|
743
880
|
`);
|
|
744
|
-
let
|
|
745
|
-
|
|
881
|
+
let r = t;
|
|
882
|
+
r || (o ? (r = "auth-server", console.log(`Using default project name: ${r}`)) : r = (await u.prompt([
|
|
746
883
|
{
|
|
747
884
|
type: "input",
|
|
748
885
|
name: "projectName",
|
|
@@ -751,10 +888,10 @@ N.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
751
888
|
validate: (d) => d !== "" || "Project name cannot be empty"
|
|
752
889
|
}
|
|
753
890
|
])).projectName);
|
|
754
|
-
const n =
|
|
755
|
-
s.existsSync(n) && (console.error(`❌ Project "${
|
|
756
|
-
let
|
|
757
|
-
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)),
|
|
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([
|
|
758
895
|
{
|
|
759
896
|
type: "list",
|
|
760
897
|
name: "setupType",
|
|
@@ -782,7 +919,7 @@ N.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
782
919
|
}
|
|
783
920
|
])).setupType;
|
|
784
921
|
let c;
|
|
785
|
-
e.multiTenant !== void 0 ? (c = e.multiTenant, console.log(`Multi-tenant mode: ${c ? "enabled" : "disabled"}`)) :
|
|
922
|
+
e.multiTenant !== void 0 ? (c = e.multiTenant, console.log(`Multi-tenant mode: ${c ? "enabled" : "disabled"}`)) : o ? c = !1 : c = (await u.prompt([
|
|
786
923
|
{
|
|
787
924
|
type: "confirm",
|
|
788
925
|
name: "multiTenant",
|
|
@@ -791,57 +928,90 @@ N.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
791
928
|
default: !1
|
|
792
929
|
}
|
|
793
930
|
])).multiTenant;
|
|
794
|
-
const
|
|
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];
|
|
795
936
|
s.mkdirSync(n, { recursive: !0 }), s.writeFileSync(
|
|
796
|
-
|
|
797
|
-
JSON.stringify(
|
|
937
|
+
l.join(n, "package.json"),
|
|
938
|
+
JSON.stringify(y.packageJson(r, c, g), null, 2)
|
|
798
939
|
);
|
|
799
|
-
const
|
|
940
|
+
const x = y.templateDir, v = l.join(
|
|
800
941
|
import.meta.url.replace("file://", "").replace("/create-authhero.js", ""),
|
|
801
|
-
|
|
942
|
+
x
|
|
802
943
|
);
|
|
803
|
-
if (s.existsSync(
|
|
804
|
-
const
|
|
805
|
-
s.existsSync(
|
|
806
|
-
const m =
|
|
807
|
-
s.existsSync(m) && s.copyFileSync(m,
|
|
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(
|
|
808
949
|
"📁 Created wrangler.local.toml and .dev.vars for local development"
|
|
809
950
|
);
|
|
810
951
|
}
|
|
811
|
-
let
|
|
812
|
-
if (
|
|
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([
|
|
813
954
|
{
|
|
814
955
|
type: "confirm",
|
|
815
956
|
name: "includeGithubCi",
|
|
816
957
|
message: "Would you like to include GitHub CI with semantic versioning?",
|
|
817
958
|
default: !1
|
|
818
959
|
}
|
|
819
|
-
])).includeGithubCi),
|
|
820
|
-
const
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
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
|
+
);
|
|
824
995
|
}
|
|
825
|
-
|
|
826
|
-
const T = c ? "multi-tenant" : "single-tenant";
|
|
996
|
+
const P = c ? "multi-tenant" : "single-tenant";
|
|
827
997
|
console.log(
|
|
828
998
|
`
|
|
829
|
-
✅ Project "${
|
|
999
|
+
✅ Project "${r}" has been created with ${y.name} (${P}) setup!
|
|
830
1000
|
`
|
|
831
1001
|
);
|
|
832
|
-
let
|
|
833
|
-
if (e.skipInstall ?
|
|
1002
|
+
let A;
|
|
1003
|
+
if (e.skipInstall ? A = !1 : o ? A = !0 : A = (await u.prompt([
|
|
834
1004
|
{
|
|
835
1005
|
type: "confirm",
|
|
836
1006
|
name: "shouldInstall",
|
|
837
1007
|
message: "Would you like to install dependencies now?",
|
|
838
1008
|
default: !0
|
|
839
1009
|
}
|
|
840
|
-
])).shouldInstall,
|
|
841
|
-
let
|
|
1010
|
+
])).shouldInstall, A) {
|
|
1011
|
+
let i;
|
|
842
1012
|
e.packageManager ? (["npm", "yarn", "pnpm", "bun"].includes(e.packageManager) || (console.error(
|
|
843
1013
|
`❌ Invalid package manager: ${e.packageManager}`
|
|
844
|
-
), console.error("Valid options: npm, yarn, pnpm, bun"), process.exit(1)),
|
|
1014
|
+
), console.error("Valid options: npm, yarn, pnpm, bun"), process.exit(1)), i = e.packageManager) : o ? i = "pnpm" : i = (await u.prompt([
|
|
845
1015
|
{
|
|
846
1016
|
type: "list",
|
|
847
1017
|
name: "packageManager",
|
|
@@ -855,92 +1025,99 @@ N.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
855
1025
|
default: "pnpm"
|
|
856
1026
|
}
|
|
857
1027
|
])).packageManager, console.log(`
|
|
858
|
-
📦 Installing dependencies with ${
|
|
1028
|
+
📦 Installing dependencies with ${i}...
|
|
859
1029
|
`);
|
|
860
1030
|
try {
|
|
861
|
-
const d =
|
|
862
|
-
if (await
|
|
1031
|
+
const d = i === "pnpm" ? "pnpm install --ignore-workspace" : `${i} install`;
|
|
1032
|
+
if (await b(d, n), a === "local" && (console.log(`
|
|
863
1033
|
🔧 Building native modules...
|
|
864
|
-
`), await
|
|
1034
|
+
`), await b("npm rebuild better-sqlite3", n)), console.log(`
|
|
865
1035
|
✅ Dependencies installed successfully!
|
|
866
|
-
`),
|
|
867
|
-
let
|
|
868
|
-
if (e.skipMigrate && e.skipSeed ?
|
|
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([
|
|
869
1039
|
{
|
|
870
1040
|
type: "confirm",
|
|
871
1041
|
name: "shouldSetup",
|
|
872
1042
|
message: "Would you like to run migrations and seed the database?",
|
|
873
1043
|
default: !0
|
|
874
1044
|
}
|
|
875
|
-
])).shouldSetup,
|
|
876
|
-
let
|
|
877
|
-
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)),
|
|
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 = {
|
|
878
1048
|
username: e.email,
|
|
879
1049
|
password: e.password
|
|
880
|
-
}, console.log(`Using admin email: ${e.email}`)) :
|
|
1050
|
+
}, console.log(`Using admin email: ${e.email}`)) : h = await u.prompt([
|
|
881
1051
|
{
|
|
882
1052
|
type: "input",
|
|
883
1053
|
name: "username",
|
|
884
1054
|
message: "Admin email:",
|
|
885
1055
|
default: "admin@example.com",
|
|
886
|
-
validate: (
|
|
1056
|
+
validate: (S) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(S) || "Please enter a valid email address"
|
|
887
1057
|
},
|
|
888
1058
|
{
|
|
889
1059
|
type: "password",
|
|
890
1060
|
name: "password",
|
|
891
1061
|
message: "Admin password:",
|
|
892
1062
|
mask: "*",
|
|
893
|
-
validate: (
|
|
1063
|
+
validate: (S) => S.length < 8 ? "Password must be at least 8 characters" : !0
|
|
894
1064
|
}
|
|
895
1065
|
]), e.skipMigrate || (console.log(`
|
|
896
1066
|
🔄 Running migrations...
|
|
897
|
-
`), await
|
|
1067
|
+
`), await b(`${i} run migrate`, n)), e.skipSeed || (console.log(`
|
|
898
1068
|
🌱 Seeding database...
|
|
899
|
-
`),
|
|
900
|
-
`${
|
|
1069
|
+
`), a === "local" ? await D(
|
|
1070
|
+
`${i} run seed`,
|
|
901
1071
|
n,
|
|
902
1072
|
{
|
|
903
|
-
ADMIN_EMAIL:
|
|
904
|
-
ADMIN_PASSWORD:
|
|
1073
|
+
ADMIN_EMAIL: h.username,
|
|
1074
|
+
ADMIN_PASSWORD: h.password
|
|
905
1075
|
}
|
|
906
1076
|
) : await D(
|
|
907
|
-
`${
|
|
1077
|
+
`${i} run seed:local`,
|
|
908
1078
|
n,
|
|
909
1079
|
{
|
|
910
|
-
ADMIN_EMAIL:
|
|
911
|
-
ADMIN_PASSWORD:
|
|
1080
|
+
ADMIN_EMAIL: h.username,
|
|
1081
|
+
ADMIN_PASSWORD: h.password
|
|
912
1082
|
}
|
|
913
1083
|
));
|
|
914
1084
|
}
|
|
915
1085
|
}
|
|
916
1086
|
let m;
|
|
917
|
-
e.skipStart ||
|
|
1087
|
+
e.skipStart || o ? m = !1 : m = (await u.prompt([
|
|
918
1088
|
{
|
|
919
1089
|
type: "confirm",
|
|
920
1090
|
name: "shouldStart",
|
|
921
1091
|
message: "Would you like to start the development server?",
|
|
922
1092
|
default: !0
|
|
923
1093
|
}
|
|
924
|
-
])).shouldStart, m && (
|
|
925
|
-
`), await
|
|
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(`
|
|
926
1096
|
✅ Setup complete!`), console.log(`
|
|
927
|
-
To start the development server:`), console.log(` cd ${
|
|
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));
|
|
928
1098
|
} catch (d) {
|
|
929
1099
|
console.error(`
|
|
930
1100
|
❌ An error occurred:`, d), process.exit(1);
|
|
931
1101
|
}
|
|
932
1102
|
}
|
|
933
|
-
|
|
1103
|
+
A || (console.log("Next steps:"), console.log(` cd ${r}`), a === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(
|
|
934
1104
|
" ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed"
|
|
935
|
-
), console.log(" npm run dev")) :
|
|
1105
|
+
), console.log(" npm run dev")) : a === "cloudflare" ? (console.log(" npm install"), console.log(
|
|
936
1106
|
" npm run migrate # or npm run db:migrate:remote for production"
|
|
937
1107
|
), console.log(
|
|
938
1108
|
" ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed"
|
|
939
|
-
), console.log(" npm run dev # or npm run dev:remote for production")) :
|
|
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(
|
|
940
1110
|
" TABLE_NAME=<your-table> ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=yourpassword npm run seed"
|
|
941
1111
|
)), console.log(`
|
|
942
|
-
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(`
|
|
943
1120
|
For more information, visit: https://authhero.net/docs
|
|
944
1121
|
`));
|
|
945
1122
|
});
|
|
946
|
-
|
|
1123
|
+
T.parse(process.argv);
|