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.
- package/dist/create-authhero.js +108 -99
- package/dist/local/src/index.ts +84 -3
- package/package.json +2 -1
package/dist/create-authhero.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Command as
|
|
2
|
+
import { Command as R } from "commander";
|
|
3
3
|
import m from "inquirer";
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
|
|
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: (
|
|
13
|
+
packageJson: (a, e, o, r, n) => {
|
|
13
14
|
const t = r ? "workspace:*" : "latest";
|
|
14
15
|
return {
|
|
15
|
-
name:
|
|
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: (
|
|
53
|
+
packageJson: (a, e, o, r, n) => {
|
|
53
54
|
const t = r ? "workspace:*" : "latest";
|
|
54
55
|
return {
|
|
55
|
-
name:
|
|
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: (
|
|
102
|
+
packageJson: (a, e, o, r, n) => {
|
|
102
103
|
const t = r ? "workspace:*" : "latest";
|
|
103
104
|
return {
|
|
104
|
-
name:
|
|
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
|
|
140
|
-
|
|
141
|
-
const n =
|
|
142
|
-
|
|
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
|
|
146
|
-
const n =
|
|
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],
|
|
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: ${!!
|
|
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
|
-
${
|
|
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
|
|
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: ${
|
|
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
|
|
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
|
|
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: "${
|
|
538
|
-
tenantName: "${
|
|
539
|
-
isControlPlane: ${!!
|
|
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
|
|
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
|
|
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
|
|
657
|
-
return
|
|
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
|
|
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: "${
|
|
792
|
-
tenantName: "${
|
|
793
|
-
isControlPlane: ${!!
|
|
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
|
|
803
|
-
const o =
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
),
|
|
808
|
-
|
|
809
|
-
|
|
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
|
|
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
|
|
816
|
-
const e =
|
|
817
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
916
|
-
|
|
920
|
+
i.writeFileSync(
|
|
921
|
+
s.join(a, ".releaserc.json"),
|
|
917
922
|
JSON.stringify(e, null, 2)
|
|
918
923
|
);
|
|
919
|
-
const o =
|
|
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
|
-
},
|
|
932
|
+
}, i.writeFileSync(o, JSON.stringify(r, null, 2));
|
|
928
933
|
}
|
|
929
|
-
function
|
|
934
|
+
function b(a, e) {
|
|
930
935
|
return new Promise((o, r) => {
|
|
931
|
-
const n =
|
|
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
|
|
942
|
-
const r =
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
),
|
|
947
|
-
|
|
948
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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 (
|
|
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 =
|
|
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 =
|
|
986
|
-
|
|
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
|
-
|
|
1041
|
-
|
|
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
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
);
|
|
1058
|
-
if (
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
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 && (
|
|
1075
|
-
const l =
|
|
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
|
-
|
|
1082
|
-
const u =
|
|
1083
|
-
|
|
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" &&
|
|
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
|
-
|
|
1105
|
-
|
|
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
|
|
1120
|
+
const E = c ? "multi-tenant" : "single-tenant";
|
|
1112
1121
|
console.log(
|
|
1113
1122
|
`
|
|
1114
|
-
✅ Project "${r}" has been created with ${y.name} (${
|
|
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
|
|
1156
|
+
if (await b(u, n), t === "local" && (console.log(`
|
|
1148
1157
|
🔧 Building native modules...
|
|
1149
|
-
`), await
|
|
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
|
|
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" ?
|
|
1173
|
-
`), await
|
|
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" ?
|
|
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
|
-
|
|
1211
|
+
T.parse(process.argv);
|
package/dist/local/src/index.ts
CHANGED
|
@@ -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 || `
|
|
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
|
|
45
|
-
console.log(`📚 API documentation available at
|
|
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.
|
|
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
|
},
|