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.
- package/dist/create-authhero.js +95 -82
- package/dist/local/src/index.ts +84 -3
- package/package.json +1 -1
package/dist/create-authhero.js
CHANGED
|
@@ -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
|
|
6
|
-
import { fileURLToPath as
|
|
7
|
-
import { spawn as
|
|
8
|
-
const
|
|
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: (
|
|
13
|
+
packageJson: (a, e, o, r, n) => {
|
|
14
14
|
const t = r ? "workspace:*" : "latest";
|
|
15
15
|
return {
|
|
16
|
-
name:
|
|
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: (
|
|
53
|
+
packageJson: (a, e, o, r, n) => {
|
|
54
54
|
const t = r ? "workspace:*" : "latest";
|
|
55
55
|
return {
|
|
56
|
-
name:
|
|
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: (
|
|
102
|
+
packageJson: (a, e, o, r, n) => {
|
|
103
103
|
const t = r ? "workspace:*" : "latest";
|
|
104
104
|
return {
|
|
105
|
-
name:
|
|
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(
|
|
141
|
-
i.readdirSync(
|
|
142
|
-
const n =
|
|
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
|
|
147
|
-
const n =
|
|
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],
|
|
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: ${!!
|
|
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
|
-
${
|
|
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
|
|
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: ${
|
|
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
|
|
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(
|
|
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: "${
|
|
539
|
-
tenantName: "${
|
|
540
|
-
isControlPlane: ${!!
|
|
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(
|
|
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
|
|
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
|
|
658
|
-
return
|
|
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
|
|
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: "${
|
|
793
|
-
tenantName: "${
|
|
794
|
-
isControlPlane: ${!!
|
|
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(
|
|
804
|
-
const o =
|
|
816
|
+
function W(a, e) {
|
|
817
|
+
const o = s.join(a, "src");
|
|
805
818
|
i.writeFileSync(
|
|
806
|
-
|
|
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
|
|
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(
|
|
817
|
-
const e =
|
|
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(
|
|
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(
|
|
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
|
-
|
|
930
|
+
s.join(a, ".releaserc.json"),
|
|
918
931
|
JSON.stringify(e, null, 2)
|
|
919
932
|
);
|
|
920
|
-
const o =
|
|
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
|
|
943
|
+
function A(a, e) {
|
|
931
944
|
return new Promise((o, r) => {
|
|
932
|
-
const n =
|
|
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(
|
|
943
|
-
const r =
|
|
955
|
+
function z(a, e, o) {
|
|
956
|
+
const r = s.join(a, "src");
|
|
944
957
|
i.writeFileSync(
|
|
945
|
-
|
|
958
|
+
s.join(r, "app.ts"),
|
|
946
959
|
H(e, o)
|
|
947
960
|
), i.writeFileSync(
|
|
948
|
-
|
|
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
|
|
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
|
-
|
|
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 (
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
],
|
|
1059
|
-
if (
|
|
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 =
|
|
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 =
|
|
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
|
|
1072
|
-
if (t === "cloudflare" && (e.githubCi !== void 0 ? (
|
|
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),
|
|
1080
|
-
const 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(
|
|
1087
|
-
const u =
|
|
1088
|
-
i.writeFileSync(
|
|
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
|
-
|
|
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
|
|
1165
|
+
if (await A(u, n), t === "local" && (console.log(`
|
|
1153
1166
|
🔧 Building native modules...
|
|
1154
|
-
`), await
|
|
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
|
|
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" ?
|
|
1178
|
-
`), await
|
|
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" ?
|
|
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
|
-
|
|
1220
|
+
N.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
|
});
|