create-authhero 0.41.2 → 0.43.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,164 +1,187 @@
1
1
  #!/usr/bin/env node
2
- import { Command as R } from "commander";
3
- import m from "inquirer";
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 N = new R(), p = {
9
- local: {
10
- name: "Local (SQLite)",
11
- description: "Local development setup with SQLite database - great for getting started",
12
- templateDir: "local",
13
- packageJson: (a, e, o, r, n) => {
14
- const t = r ? "workspace:*" : "latest";
15
- return {
16
- name: a,
17
- version: "1.0.0",
18
- type: "module",
19
- scripts: {
20
- dev: "npx tsx watch src/index.ts",
21
- start: "npx tsx src/index.ts",
22
- migrate: "npx tsx src/migrate.ts",
23
- seed: "npx tsx src/seed.ts"
24
- },
25
- dependencies: {
26
- "@authhero/kysely-adapter": t,
27
- ...n && { "@authhero/react-admin": t },
28
- "@authhero/widget": t,
29
- "@hono/swagger-ui": "^0.5.0",
30
- "@hono/zod-openapi": "^0.19.0",
31
- "@hono/node-server": "latest",
32
- authhero: t,
33
- "better-sqlite3": "latest",
34
- hono: "^4.6.0",
35
- kysely: "latest",
36
- ...e && { "@authhero/multi-tenancy": t },
37
- ...o && { bcryptjs: "latest" }
38
- },
39
- devDependencies: {
40
- "@types/better-sqlite3": "^7.6.0",
41
- "@types/node": "^20.0.0",
42
- tsx: "^4.0.0",
43
- typescript: "^5.5.0"
44
- }
45
- };
46
- },
47
- seedFile: "seed.ts"
48
- },
49
- cloudflare: {
50
- name: "Cloudflare Workers (D1)",
51
- description: "Cloudflare Workers setup with D1 database",
52
- templateDir: "cloudflare",
53
- packageJson: (a, e, o, r, n) => {
54
- const t = r ? "workspace:*" : "latest";
55
- return {
56
- name: a,
57
- version: "1.0.0",
58
- type: "module",
59
- scripts: {
60
- postinstall: "node copy-assets.js",
61
- "copy-assets": "node copy-assets.js",
62
- dev: "node copy-assets.js && wrangler dev --port 3000 --local-protocol https",
63
- "dev:remote": "node copy-assets.js && wrangler dev --port 3000 --local-protocol https --remote --config wrangler.local.toml",
64
- deploy: "node copy-assets.js && wrangler deploy --config wrangler.local.toml",
65
- "db:migrate:local": "wrangler d1 migrations apply AUTH_DB --local",
66
- "db:migrate:remote": "wrangler d1 migrations apply AUTH_DB --remote --config wrangler.local.toml",
67
- migrate: "wrangler d1 migrations apply AUTH_DB --local",
68
- "seed:local": "node seed-helper.js",
69
- "seed:remote": "node seed-helper.js '' '' remote",
70
- seed: "node seed-helper.js",
71
- setup: "cp wrangler.toml wrangler.local.toml && cp .dev.vars.example .dev.vars && echo '✅ Created wrangler.local.toml and .dev.vars - update with your IDs'"
72
- },
73
- dependencies: {
74
- "@authhero/drizzle": t,
75
- "@authhero/kysely-adapter": t,
76
- ...n && { "@authhero/react-admin": t },
77
- "@authhero/widget": t,
78
- "@hono/swagger-ui": "^0.5.0",
79
- "@hono/zod-openapi": "^0.19.0",
80
- authhero: t,
81
- hono: "^4.6.0",
82
- kysely: "latest",
83
- "kysely-d1": "latest",
84
- ...e && { "@authhero/multi-tenancy": t },
85
- ...o && { bcryptjs: "latest" }
86
- },
87
- devDependencies: {
88
- "@cloudflare/workers-types": "^4.0.0",
89
- "drizzle-kit": "^0.31.0",
90
- "drizzle-orm": "^0.44.0",
91
- typescript: "^5.5.0",
92
- wrangler: "^3.0.0"
93
- }
94
- };
95
- },
96
- seedFile: "seed.ts"
97
- },
98
- "aws-sst": {
99
- name: "AWS SST (Lambda + DynamoDB)",
100
- description: "Serverless AWS deployment with Lambda, DynamoDB, and SST",
101
- templateDir: "aws-sst",
102
- packageJson: (a, e, o, r, n) => {
103
- const t = r ? "workspace:*" : "latest";
104
- return {
105
- name: a,
106
- version: "1.0.0",
107
- type: "module",
108
- scripts: {
109
- dev: "sst dev",
110
- deploy: "sst deploy --stage production",
111
- remove: "sst remove",
112
- seed: "npx tsx src/seed.ts",
113
- "copy-assets": "node copy-assets.js"
114
- },
115
- dependencies: {
116
- "@authhero/aws": t,
117
- ...n && { "@authhero/react-admin": t },
118
- "@authhero/widget": t,
119
- "@aws-sdk/client-dynamodb": "^3.0.0",
120
- "@aws-sdk/lib-dynamodb": "^3.0.0",
121
- "@hono/swagger-ui": "^0.5.0",
122
- "@hono/zod-openapi": "^0.19.0",
123
- authhero: t,
124
- hono: "^4.6.0",
125
- ...e && { "@authhero/multi-tenancy": t },
126
- ...o && { bcryptjs: "latest" }
127
- },
128
- devDependencies: {
129
- "@types/aws-lambda": "^8.10.0",
130
- "@types/node": "^20.0.0",
131
- sst: "^3.0.0",
132
- tsx: "^4.0.0",
133
- typescript: "^5.5.0"
134
- }
135
- };
136
- },
137
- seedFile: "seed.ts"
138
- }
2
+ import { Command as e } from "commander";
3
+ import t from "inquirer";
4
+ import n from "fs";
5
+ import r from "path";
6
+ import { fileURLToPath as i } from "url";
7
+ import { spawn as a } from "child_process";
8
+ //#region src/index.ts
9
+ var o = new e(), s = {
10
+ local: {
11
+ name: "Local (SQLite)",
12
+ description: "Local development setup with SQLite database - great for getting started",
13
+ templateDir: "local",
14
+ packageJson: (e, t, n, r, i) => {
15
+ let a = r ? "workspace:*" : "latest";
16
+ return {
17
+ name: e,
18
+ version: "1.0.0",
19
+ type: "module",
20
+ scripts: {
21
+ dev: "npx tsx watch src/index.ts",
22
+ start: "npx tsx src/index.ts",
23
+ migrate: "npx tsx src/migrate.ts",
24
+ seed: "npx tsx src/seed.ts"
25
+ },
26
+ dependencies: {
27
+ "@authhero/kysely-adapter": a,
28
+ ...i && { "@authhero/admin": a },
29
+ "@authhero/widget": a,
30
+ "@hono/swagger-ui": "^0.5.0",
31
+ "@hono/zod-openapi": "^0.19.0",
32
+ "@hono/node-server": "latest",
33
+ authhero: a,
34
+ "better-sqlite3": "latest",
35
+ hono: "^4.6.0",
36
+ kysely: "latest",
37
+ ...t && { "@authhero/multi-tenancy": a },
38
+ ...n && { bcryptjs: "latest" }
39
+ },
40
+ devDependencies: {
41
+ "@types/better-sqlite3": "^7.6.0",
42
+ "@types/node": "^20.0.0",
43
+ tsx: "^4.0.0",
44
+ typescript: "^5.5.0"
45
+ }
46
+ };
47
+ },
48
+ seedFile: "seed.ts"
49
+ },
50
+ cloudflare: {
51
+ name: "Cloudflare Workers (D1)",
52
+ description: "Cloudflare Workers setup with D1 database",
53
+ templateDir: "cloudflare",
54
+ packageJson: (e, t, n, r, i) => {
55
+ let a = r ? "workspace:*" : "latest";
56
+ return {
57
+ name: e,
58
+ version: "1.0.0",
59
+ type: "module",
60
+ scripts: {
61
+ postinstall: "node copy-assets.js",
62
+ "copy-assets": "node copy-assets.js",
63
+ dev: "node copy-assets.js && wrangler dev --port 3000 --local-protocol https",
64
+ "dev:remote": "node copy-assets.js && wrangler dev --port 3000 --local-protocol https --remote --config wrangler.local.toml",
65
+ deploy: "node copy-assets.js && wrangler deploy --config wrangler.local.toml",
66
+ "db:migrate:local": "wrangler d1 migrations apply AUTH_DB --local",
67
+ "db:migrate:remote": "wrangler d1 migrations apply AUTH_DB --remote --config wrangler.local.toml",
68
+ migrate: "wrangler d1 migrations apply AUTH_DB --local",
69
+ "seed:local": "node seed-helper.js",
70
+ "seed:remote": "node seed-helper.js '' '' remote",
71
+ seed: "node seed-helper.js",
72
+ setup: "cp wrangler.toml wrangler.local.toml && cp .dev.vars.example .dev.vars && echo '✅ Created wrangler.local.toml and .dev.vars - update with your IDs'"
73
+ },
74
+ dependencies: {
75
+ "@authhero/drizzle": a,
76
+ "@authhero/kysely-adapter": a,
77
+ ...i && { "@authhero/admin": a },
78
+ "@authhero/widget": a,
79
+ "@hono/swagger-ui": "^0.5.0",
80
+ "@hono/zod-openapi": "^0.19.0",
81
+ authhero: a,
82
+ hono: "^4.6.0",
83
+ kysely: "latest",
84
+ "kysely-d1": "latest",
85
+ ...t && { "@authhero/multi-tenancy": a },
86
+ ...n && { bcryptjs: "latest" }
87
+ },
88
+ devDependencies: {
89
+ "@cloudflare/workers-types": "^4.0.0",
90
+ "drizzle-kit": "^0.31.0",
91
+ "drizzle-orm": "^0.44.0",
92
+ typescript: "^5.5.0",
93
+ wrangler: "^3.0.0"
94
+ }
95
+ };
96
+ },
97
+ seedFile: "seed.ts"
98
+ },
99
+ proxy: {
100
+ name: "Proxy (Cloudflare Workers)",
101
+ description: "Host-based reverse proxy on Cloudflare Workers — static config, no DB",
102
+ templateDir: "proxy",
103
+ packageJson: (e, t, n, r) => ({
104
+ name: e,
105
+ version: "1.0.0",
106
+ type: "module",
107
+ scripts: {
108
+ dev: "wrangler dev --port 8787",
109
+ deploy: "wrangler deploy",
110
+ logs: "wrangler tail"
111
+ },
112
+ dependencies: {
113
+ "@authhero/proxy": r ? "workspace:*" : "latest",
114
+ hono: "^4.6.0"
115
+ },
116
+ devDependencies: {
117
+ "@cloudflare/workers-types": "^4.0.0",
118
+ "@types/node": "^20.0.0",
119
+ typescript: "^5.5.0",
120
+ wrangler: "^3.0.0"
121
+ }
122
+ })
123
+ },
124
+ "aws-sst": {
125
+ name: "AWS SST (Lambda + DynamoDB)",
126
+ description: "Serverless AWS deployment with Lambda, DynamoDB, and SST",
127
+ templateDir: "aws-sst",
128
+ packageJson: (e, t, n, r, i) => {
129
+ let a = r ? "workspace:*" : "latest";
130
+ return {
131
+ name: e,
132
+ version: "1.0.0",
133
+ type: "module",
134
+ scripts: {
135
+ dev: "sst dev",
136
+ deploy: "sst deploy --stage production",
137
+ remove: "sst remove",
138
+ seed: "npx tsx src/seed.ts",
139
+ "copy-assets": "node copy-assets.js"
140
+ },
141
+ dependencies: {
142
+ "@authhero/aws": a,
143
+ ...i && { "@authhero/admin": a },
144
+ "@authhero/widget": a,
145
+ "@aws-sdk/client-dynamodb": "^3.0.0",
146
+ "@aws-sdk/lib-dynamodb": "^3.0.0",
147
+ "@hono/swagger-ui": "^0.5.0",
148
+ "@hono/zod-openapi": "^0.19.0",
149
+ authhero: a,
150
+ hono: "^4.6.0",
151
+ ...t && { "@authhero/multi-tenancy": a },
152
+ ...n && { bcryptjs: "latest" }
153
+ },
154
+ devDependencies: {
155
+ "@types/aws-lambda": "^8.10.0",
156
+ "@types/node": "^20.0.0",
157
+ sst: "^3.0.0",
158
+ tsx: "^4.0.0",
159
+ typescript: "^5.5.0"
160
+ }
161
+ };
162
+ },
163
+ seedFile: "seed.ts"
164
+ }
139
165
  };
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);
144
- });
166
+ function c(e, t) {
167
+ n.readdirSync(e).forEach((i) => {
168
+ let a = r.join(e, i), o = r.join(t, i);
169
+ n.lstatSync(a).isDirectory() ? (n.mkdirSync(o, { recursive: !0 }), c(a, o)) : n.copyFileSync(a, o);
170
+ });
145
171
  }
146
- function $(a, e = !1, o = "authhero-local", r) {
147
- const n = a ? "control_plane" : "main", t = a ? "Control Plane" : "Main", c = [
148
- "https://manage.authhero.net/auth-callback",
149
- "https://local.authhero.net/auth-callback",
150
- "http://localhost:5173/auth-callback",
151
- "http://localhost:3000/auth-callback",
152
- ...r ? ["http://localhost:3000/admin/auth-callback"] : []
153
- ], d = e ? [
154
- `https://localhost.emobix.co.uk:8443/test/a/${o}/callback`,
155
- `https://localhost:8443/test/a/${o}/callback`
156
- ] : [], f = [...c, ...d], h = [
157
- "https://manage.authhero.net",
158
- "https://local.authhero.net",
159
- "http://localhost:5173",
160
- "http://localhost:3000"
161
- ], C = e ? ["https://localhost:8443/", "https://localhost.emobix.co.uk:8443/"] : [], y = [...h, ...C], _ = e ? `
172
+ function l(e, t = !1, n = "authhero-local", r) {
173
+ let i = e ? "control_plane" : "main", a = e ? "Control Plane" : "Main", o = [
174
+ "https://manage.authhero.net/auth-callback",
175
+ "https://local.authhero.net/auth-callback",
176
+ "http://localhost:5173/auth-callback",
177
+ "http://localhost:3000/auth-callback",
178
+ ...r ? ["http://localhost:3000/admin/auth-callback"] : []
179
+ ], s = t ? [`https://localhost.emobix.co.uk:8443/test/a/${n}/callback`, `https://localhost:8443/test/a/${n}/callback`] : [], c = [...o, ...s], l = [
180
+ "https://manage.authhero.net",
181
+ "https://local.authhero.net",
182
+ "http://localhost:5173",
183
+ "http://localhost:3000"
184
+ ], u = t ? ["https://localhost:8443/", "https://localhost.emobix.co.uk:8443/"] : [], d = [...l, ...u], f = t ? `
162
185
  // Create OpenID Conformance Suite test clients and user
163
186
  console.log("Creating conformance test clients and user...");
164
187
 
@@ -166,22 +189,26 @@ function $(a, e = !1, o = "authhero-local", r) {
166
189
  // requires either an explicit audience or a tenant default_audience to mint
167
190
  // an access token, so set one here for the conformance setup.
168
191
  // 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}");
173
- await adapters.tenants.update("${n}", {
192
+ // which has the suite register its own client via /oidc/register. The
193
+ // OIDCC dynamic_client variant uses open DCR (no Initial Access Token), so
194
+ // dcr_require_initial_access_token must be flipped off the AuthHero
195
+ // default is to require an IAT. Existing flags (e.g.
196
+ // inherit_global_permissions_in_organizations set by seed for the
197
+ // control-plane tenant) are merged in so the update doesn't clobber.
198
+ const existingTenant = await adapters.tenants.get("${i}");
199
+ await adapters.tenants.update("${i}", {
174
200
  default_audience: "urn:authhero:management",
175
201
  flags: {
176
202
  ...(existingTenant?.flags ?? {}),
177
203
  enable_dynamic_client_registration: true,
204
+ dcr_require_initial_access_token: false,
178
205
  },
179
206
  });
180
207
  console.log("✅ Set tenant default_audience and enabled DCR for conformance");
181
208
 
182
209
  const conformanceCallbacks = [
183
- "https://localhost.emobix.co.uk:8443/test/a/${o}/callback",
184
- "https://localhost:8443/test/a/${o}/callback",
210
+ "https://localhost.emobix.co.uk:8443/test/a/${n}/callback",
211
+ "https://localhost:8443/test/a/${n}/callback",
185
212
  ];
186
213
  const conformanceLogoutUrls = [
187
214
  "https://localhost:8443/",
@@ -192,46 +219,51 @@ function $(a, e = !1, o = "authhero-local", r) {
192
219
  "https://localhost.emobix.co.uk:8443",
193
220
  ];
194
221
 
195
- try {
196
- await adapters.clients.create("${n}", {
222
+ // Strict OIDC 5.4: scope-driven claims (profile/email/address/phone) belong
223
+ // in /userinfo whenever an access_token is co-issued at /authorize. The OIDF
224
+ // suite enforces this via EnsureIdTokenDoesNotContainEmailForScopeEmail;
225
+ // running the conformance tenant under Auth0-compatible defaults would WARN.
226
+ const conformanceClientSpecs = [
227
+ {
197
228
  client_id: "conformance-test",
198
229
  client_secret: "conformanceTestSecret123",
199
230
  name: "Conformance Test Client",
200
- callbacks: conformanceCallbacks,
201
- allowed_logout_urls: conformanceLogoutUrls,
202
- web_origins: conformanceWebOrigins,
203
- });
204
- console.log("✅ Created conformance-test client");
205
- } catch (e: any) {
206
- if (e.message?.includes("UNIQUE constraint")) {
207
- console.log("ℹ️ conformance-test client already exists");
208
- } else {
209
- throw e;
210
- }
211
- }
212
-
213
- try {
214
- await adapters.clients.create("${n}", {
231
+ },
232
+ {
215
233
  client_id: "conformance-test2",
216
234
  client_secret: "conformanceTestSecret456",
217
235
  name: "Conformance Test Client 2",
236
+ },
237
+ ];
238
+ for (const spec of conformanceClientSpecs) {
239
+ const desired = {
240
+ name: spec.name,
241
+ client_secret: spec.client_secret,
218
242
  callbacks: conformanceCallbacks,
219
243
  allowed_logout_urls: conformanceLogoutUrls,
220
244
  web_origins: conformanceWebOrigins,
221
- });
222
- console.log("✅ Created conformance-test2 client");
223
- } catch (e: any) {
224
- if (e.message?.includes("UNIQUE constraint")) {
225
- console.log("ℹ️ conformance-test2 client already exists");
245
+ auth0_conformant: false,
246
+ };
247
+ // Idempotent reconcile: prior runs may have created the client with stale
248
+ // callbacks/web_origins after this seed file was changed. Update existing
249
+ // records in place rather than just logging "already exists".
250
+ const existing = await adapters.clients.get("${i}", spec.client_id);
251
+ if (existing) {
252
+ await adapters.clients.update("${i}", spec.client_id, desired);
253
+ console.log(\`🔄 Updated \${spec.client_id} client\`);
226
254
  } else {
227
- throw e;
255
+ await adapters.clients.create("${i}", {
256
+ client_id: spec.client_id,
257
+ ...desired,
258
+ });
259
+ console.log(\`✅ Created \${spec.client_id} client\`);
228
260
  }
229
261
  }
230
262
 
231
263
  // Create a conformance test user with ALL OIDC profile claims populated
232
264
  // This is required for OIDCC-5.4 (VerifyScopesReturnedInUserInfoClaims) test
233
265
  try {
234
- await adapters.users.create("${n}", {
266
+ await adapters.users.create("${i}", {
235
267
  user_id: \`\${USERNAME_PASSWORD_PROVIDER}|conformance-user\`,
236
268
  email: "conformance@example.com",
237
269
  email_verified: true,
@@ -266,7 +298,7 @@ function $(a, e = !1, o = "authhero-local", r) {
266
298
  try {
267
299
  const bcrypt = await import("bcryptjs");
268
300
  const hashedPassword = await bcrypt.hash("ConformanceTest123!", 10);
269
- await adapters.passwords.create("${n}", {
301
+ await adapters.passwords.create("${i}", {
270
302
  user_id: \`\${USERNAME_PASSWORD_PROVIDER}|conformance-user\`,
271
303
  password: hashedPassword,
272
304
  });
@@ -279,10 +311,10 @@ function $(a, e = !1, o = "authhero-local", r) {
279
311
  }
280
312
  }
281
313
  ` : "";
282
- return `import { SqliteDialect, Kysely } from "kysely";
314
+ return `import { SqliteDialect, Kysely } from "kysely";
283
315
  import Database from "better-sqlite3";
284
316
  import createAdapters from "@authhero/kysely-adapter";
285
- import { seed${e ? ", USERNAME_PASSWORD_PROVIDER" : ""} } from "authhero";
317
+ import { seed${t ? ", USERNAME_PASSWORD_PROVIDER" : ""} } from "authhero";
286
318
 
287
319
  interface ExtraClient {
288
320
  client_id: string;
@@ -341,12 +373,12 @@ async function main() {
341
373
  const seedResult = await seed(adapters, {
342
374
  adminUsername,
343
375
  adminPassword,
344
- tenantId: "${n}",
345
- tenantName: "${t}",
346
- isControlPlane: ${!!a},
376
+ tenantId: "${i}",
377
+ tenantName: "${a}",
378
+ isControlPlane: ${!!e},
347
379
  clientId: "default",
348
- callbacks: ${JSON.stringify(f)},
349
- allowedLogoutUrls: ${JSON.stringify(y)},
380
+ callbacks: ${JSON.stringify(c)},
381
+ allowedLogoutUrls: ${JSON.stringify(d)},
350
382
  });
351
383
 
352
384
  for (const c of extraClients) {
@@ -375,7 +407,7 @@ async function main() {
375
407
  await adapters.users.update(seedResult.tenantId, seedResult.userId, userProfile);
376
408
  console.log(\`✅ Updated profile of user "\${seedResult.username}"\`);
377
409
  }
378
- ${_}
410
+ ${f}
379
411
  await db.destroy();
380
412
  }
381
413
 
@@ -385,15 +417,8 @@ main().catch((err) => {
385
417
  });
386
418
  `;
387
419
  }
388
- function L(a, e) {
389
- const o = e ? `import fs from "fs";
390
- ` : "", r = e ? `
391
- const adminDistPath = path.resolve(
392
- __dirname,
393
- "../node_modules/@authhero/react-admin/dist",
394
- );
395
- const adminIndexPath = path.join(adminDistPath, "index.html");
396
- ` : "", n = e ? `
420
+ function u(e, t) {
421
+ let n = t ? "import fs from \"fs\";\n" : "", r = t ? "\nconst adminDistPath = path.resolve(\n __dirname,\n \"../node_modules/@authhero/admin/dist\",\n);\nconst adminIndexPath = path.join(adminDistPath, \"index.html\");\n" : "", i = t ? `
397
422
  // Add admin UI handler if the package is installed
398
423
  if (fs.existsSync(adminIndexPath)) {
399
424
  const issuer =
@@ -403,7 +428,7 @@ const adminIndexPath = path.join(adminDistPath, "index.html");
403
428
  .replace(/href="\\.\\//g, 'href="/admin/');
404
429
  const configJson = JSON.stringify({
405
430
  domain: issuer.replace(/\\/$/, ""),
406
- clientId: ${a ? "CONTROL_PLANE_CLIENT_ID," : '"default",'}
431
+ clientId: ${e ? "CONTROL_PLANE_CLIENT_ID," : "\"default\","}
407
432
  basePath: "/admin",
408
433
  }).replace(/</g, "\\\\u003c");
409
434
  configWithHandlers.adminIndexHtml = rawHtml.replace(
@@ -416,13 +441,13 @@ const adminIndexPath = path.join(adminDistPath, "index.html");
416
441
  });
417
442
  }
418
443
  ` : "";
419
- return a ? `import { Context } from "hono";
444
+ return e ? `import { Context } from "hono";
420
445
  import { swaggerUI } from "@hono/swagger-ui";
421
446
  import { AuthHeroConfig, DataAdapters } from "authhero";
422
447
  import { serveStatic } from "@hono/node-server/serve-static";
423
448
  import { initMultiTenant } from "@authhero/multi-tenancy";
424
449
  import path from "path";
425
- ${o}import { fileURLToPath } from "url";
450
+ ${n}import { fileURLToPath } from "url";
426
451
 
427
452
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
428
453
 
@@ -443,7 +468,7 @@ export default function createApp(config: AuthHeroConfig & { dataAdapter: DataAd
443
468
  rewriteRequestPath: (p) => p.replace("/u/widget", ""),
444
469
  }),
445
470
  };
446
- ${n}
471
+ ${i}
447
472
  // Initialize multi-tenant AuthHero - syncs resource servers, roles, and connections by default
448
473
  const { app } = initMultiTenant({
449
474
  ...configWithHandlers,
@@ -480,7 +505,7 @@ import { AuthHeroConfig, init } from "authhero";
480
505
  import { swaggerUI } from "@hono/swagger-ui";
481
506
  import { serveStatic } from "@hono/node-server/serve-static";
482
507
  import path from "path";
483
- ${o}import { fileURLToPath } from "url";
508
+ ${n}import { fileURLToPath } from "url";
484
509
 
485
510
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
486
511
 
@@ -497,7 +522,7 @@ export default function createApp(config: AuthHeroConfig) {
497
522
  rewriteRequestPath: (p) => p.replace("/u/widget", ""),
498
523
  }),
499
524
  };
500
- ${n}
525
+ ${i}
501
526
  const { app } = init(configWithHandlers);
502
527
 
503
528
  app
@@ -521,8 +546,8 @@ ${n}
521
546
  }
522
547
  `;
523
548
  }
524
- function j(a) {
525
- return `import { D1Dialect } from "kysely-d1";
549
+ function d(e) {
550
+ return `import { D1Dialect } from "kysely-d1";
526
551
  import { Kysely } from "kysely";
527
552
  import createAdapters from "@authhero/kysely-adapter";
528
553
  import { seed } from "authhero";
@@ -548,9 +573,9 @@ export default {
548
573
  adminUsername,
549
574
  adminPassword,
550
575
  issuer,
551
- tenantId: "${a ? "control_plane" : "main"}",
552
- tenantName: "${a ? "Control Plane" : "Main"}",
553
- isControlPlane: ${!!a},
576
+ tenantId: "${e ? "control_plane" : "main"}",
577
+ tenantName: "${e ? "Control Plane" : "Main"}",
578
+ isControlPlane: ${!!e},
554
579
  clientId: "default",
555
580
  });
556
581
 
@@ -582,15 +607,13 @@ export default {
582
607
  };
583
608
  `;
584
609
  }
585
- function H(a, e) {
586
- const o = e ? `import adminIndexHtml from "./admin-index-html";
587
- ` : "", r = e ? ` adminIndexHtml,
588
- ` : "";
589
- return a ? `import { Context } from "hono";
610
+ function f(e, t) {
611
+ let n = t ? "import adminIndexHtml from \"./admin-index-html\";\n" : "", r = t ? " adminIndexHtml,\n" : "";
612
+ return e ? `import { Context } from "hono";
590
613
  import { swaggerUI } from "@hono/swagger-ui";
591
614
  import { AuthHeroConfig, DataAdapters } from "authhero";
592
615
  import { initMultiTenant } from "@authhero/multi-tenancy";
593
- ${o}
616
+ ${n}
594
617
  // Control plane configuration
595
618
  const CONTROL_PLANE_TENANT_ID = "control_plane";
596
619
  const CONTROL_PLANE_CLIENT_ID = "default";
@@ -631,7 +654,7 @@ ${r} controlPlane: {
631
654
  import { cors } from "hono/cors";
632
655
  import { AuthHeroConfig, init } from "authhero";
633
656
  import { swaggerUI } from "@hono/swagger-ui";
634
- ${o}
657
+ ${n}
635
658
  export default function createApp(config: AuthHeroConfig) {
636
659
  const { app } = init({
637
660
  ...config,
@@ -667,114 +690,11 @@ ${r} });
667
690
  }
668
691
  `;
669
692
  }
670
- function M(a) {
671
- return a ? `import { Context } from "hono";
672
- import { swaggerUI } from "@hono/swagger-ui";
673
- import { AuthHeroConfig, DataAdapters } from "authhero";
674
- import { initMultiTenant } from "@authhero/multi-tenancy";
675
-
676
- // Control plane configuration
677
- const CONTROL_PLANE_TENANT_ID = "control_plane";
678
- const CONTROL_PLANE_CLIENT_ID = "default";
679
-
680
- interface AppConfig extends AuthHeroConfig {
681
- dataAdapter: DataAdapters;
682
- widgetUrl: string;
683
- }
684
-
685
- export default function createApp(config: AppConfig) {
686
- // Initialize multi-tenant AuthHero
687
- const { app } = initMultiTenant({
688
- ...config,
689
- controlPlane: {
690
- tenantId: CONTROL_PLANE_TENANT_ID,
691
- clientId: CONTROL_PLANE_CLIENT_ID,
692
- },
693
- });
694
-
695
- app
696
- .onError((err, ctx) => {
697
- if (err && typeof err === "object" && "getResponse" in err) {
698
- return (err as { getResponse: () => Response }).getResponse();
699
- }
700
- console.error(err);
701
- return ctx.text(err instanceof Error ? err.message : "Internal Server Error", 500);
702
- })
703
- .get("/", async (ctx: Context) => {
704
- return ctx.json({
705
- name: "AuthHero Multi-Tenant Server (AWS)",
706
- version: "1.0.0",
707
- status: "running",
708
- docs: "/docs",
709
- controlPlaneTenant: CONTROL_PLANE_TENANT_ID,
710
- });
711
- })
712
- .get("/docs", swaggerUI({ url: "/api/v2/spec" }))
713
- // Redirect widget requests to S3/CloudFront
714
- .get("/u/widget/*", async (ctx) => {
715
- const file = ctx.req.path.replace("/u/widget/", "");
716
- return ctx.redirect(\`\${config.widgetUrl}/u/widget/\${file}\`);
717
- })
718
- .get("/u/*", async (ctx) => {
719
- const file = ctx.req.path.replace("/u/", "");
720
- return ctx.redirect(\`\${config.widgetUrl}/u/\${file}\`);
721
- });
722
-
723
- return app;
693
+ function p(e) {
694
+ return e ? "import { Context } from \"hono\";\nimport { swaggerUI } from \"@hono/swagger-ui\";\nimport { AuthHeroConfig, DataAdapters } from \"authhero\";\nimport { initMultiTenant } from \"@authhero/multi-tenancy\";\n\n// Control plane configuration\nconst CONTROL_PLANE_TENANT_ID = \"control_plane\";\nconst CONTROL_PLANE_CLIENT_ID = \"default\";\n\ninterface AppConfig extends AuthHeroConfig {\n dataAdapter: DataAdapters;\n widgetUrl: string;\n}\n\nexport default function createApp(config: AppConfig) {\n // Initialize multi-tenant AuthHero\n const { app } = initMultiTenant({\n ...config,\n controlPlane: {\n tenantId: CONTROL_PLANE_TENANT_ID,\n clientId: CONTROL_PLANE_CLIENT_ID,\n },\n });\n\n app\n .onError((err, ctx) => {\n if (err && typeof err === \"object\" && \"getResponse\" in err) {\n return (err as { getResponse: () => Response }).getResponse();\n }\n console.error(err);\n return ctx.text(err instanceof Error ? err.message : \"Internal Server Error\", 500);\n })\n .get(\"/\", async (ctx: Context) => {\n return ctx.json({\n name: \"AuthHero Multi-Tenant Server (AWS)\",\n version: \"1.0.0\",\n status: \"running\",\n docs: \"/docs\",\n controlPlaneTenant: CONTROL_PLANE_TENANT_ID,\n });\n })\n .get(\"/docs\", swaggerUI({ url: \"/api/v2/spec\" }))\n // Redirect widget requests to S3/CloudFront\n .get(\"/u/widget/*\", async (ctx) => {\n const file = ctx.req.path.replace(\"/u/widget/\", \"\");\n return ctx.redirect(`${config.widgetUrl}/u/widget/${file}`);\n })\n .get(\"/u/*\", async (ctx) => {\n const file = ctx.req.path.replace(\"/u/\", \"\");\n return ctx.redirect(`${config.widgetUrl}/u/${file}`);\n });\n\n return app;\n}\n" : "import { Context } from \"hono\";\nimport { cors } from \"hono/cors\";\nimport { AuthHeroConfig, init, DataAdapters } from \"authhero\";\nimport { swaggerUI } from \"@hono/swagger-ui\";\n\ninterface AppConfig extends AuthHeroConfig {\n dataAdapter: DataAdapters;\n widgetUrl: string;\n}\n\nexport default function createApp(config: AppConfig) {\n const { app } = init(config);\n\n // Enable CORS for all origins in development\n app.use(\"*\", cors({\n origin: (origin) => origin || \"*\",\n allowMethods: [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\", \"OPTIONS\"],\n allowHeaders: [\"Content-Type\", \"Authorization\", \"Auth0-Client\"],\n exposeHeaders: [\"Content-Length\"],\n credentials: true,\n }));\n\n app\n .onError((err, ctx) => {\n if (err && typeof err === \"object\" && \"getResponse\" in err) {\n return (err as { getResponse: () => Response }).getResponse();\n }\n console.error(err);\n return ctx.text(err instanceof Error ? err.message : \"Internal Server Error\", 500);\n })\n .get(\"/\", async (ctx: Context) => {\n return ctx.json({\n name: \"AuthHero Server (AWS)\",\n status: \"running\",\n });\n })\n .get(\"/docs\", swaggerUI({ url: \"/api/v2/spec\" }))\n // Redirect widget requests to S3/CloudFront\n .get(\"/u/widget/*\", async (ctx) => {\n const file = ctx.req.path.replace(\"/u/widget/\", \"\");\n return ctx.redirect(`${config.widgetUrl}/u/widget/${file}`);\n })\n .get(\"/u/*\", async (ctx) => {\n const file = ctx.req.path.replace(\"/u/\", \"\");\n return ctx.redirect(`${config.widgetUrl}/u/${file}`);\n });\n\n return app;\n}\n";
724
695
  }
725
- ` : `import { Context } from "hono";
726
- import { cors } from "hono/cors";
727
- import { AuthHeroConfig, init, DataAdapters } from "authhero";
728
- import { swaggerUI } from "@hono/swagger-ui";
729
-
730
- interface AppConfig extends AuthHeroConfig {
731
- dataAdapter: DataAdapters;
732
- widgetUrl: string;
733
- }
734
-
735
- export default function createApp(config: AppConfig) {
736
- const { app } = init(config);
737
-
738
- // Enable CORS for all origins in development
739
- app.use("*", cors({
740
- origin: (origin) => origin || "*",
741
- allowMethods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
742
- allowHeaders: ["Content-Type", "Authorization", "Auth0-Client"],
743
- exposeHeaders: ["Content-Length"],
744
- credentials: true,
745
- }));
746
-
747
- app
748
- .onError((err, ctx) => {
749
- if (err && typeof err === "object" && "getResponse" in err) {
750
- return (err as { getResponse: () => Response }).getResponse();
751
- }
752
- console.error(err);
753
- return ctx.text(err instanceof Error ? err.message : "Internal Server Error", 500);
754
- })
755
- .get("/", async (ctx: Context) => {
756
- return ctx.json({
757
- name: "AuthHero Server (AWS)",
758
- status: "running",
759
- });
760
- })
761
- .get("/docs", swaggerUI({ url: "/api/v2/spec" }))
762
- // Redirect widget requests to S3/CloudFront
763
- .get("/u/widget/*", async (ctx) => {
764
- const file = ctx.req.path.replace("/u/widget/", "");
765
- return ctx.redirect(\`\${config.widgetUrl}/u/widget/\${file}\`);
766
- })
767
- .get("/u/*", async (ctx) => {
768
- const file = ctx.req.path.replace("/u/", "");
769
- return ctx.redirect(\`\${config.widgetUrl}/u/\${file}\`);
770
- });
771
-
772
- return app;
773
- }
774
- `;
775
- }
776
- function F(a) {
777
- return `import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
696
+ function m(e) {
697
+ return `import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
778
698
  import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
779
699
  import createAdapters from "@authhero/aws";
780
700
  import { seed } from "authhero";
@@ -802,9 +722,9 @@ async function main() {
802
722
  await seed(adapters, {
803
723
  adminUsername,
804
724
  adminPassword,
805
- tenantId: "${a ? "control_plane" : "main"}",
806
- tenantName: "${a ? "Control Plane" : "Main"}",
807
- isControlPlane: ${!!a},
725
+ tenantId: "${e ? "control_plane" : "main"}",
726
+ tenantName: "${e ? "Control Plane" : "Main"}",
727
+ isControlPlane: ${!!e},
808
728
  });
809
729
 
810
730
  console.log("✅ Database seeded successfully!");
@@ -813,408 +733,223 @@ async function main() {
813
733
  main().catch(console.error);
814
734
  `;
815
735
  }
816
- function W(a, e) {
817
- const o = s.join(a, "src");
818
- i.writeFileSync(
819
- s.join(o, "app.ts"),
820
- M(e)
821
- ), i.writeFileSync(
822
- s.join(o, "seed.ts"),
823
- F(e)
824
- );
736
+ function h(e, t) {
737
+ let i = r.join(e, "src");
738
+ n.writeFileSync(r.join(i, "app.ts"), p(t)), n.writeFileSync(r.join(i, "seed.ts"), m(t));
825
739
  }
826
- function k() {
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");
740
+ function g() {
741
+ 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");
828
742
  }
829
- function q(a) {
830
- const e = s.join(a, ".github", "workflows");
831
- i.mkdirSync(e, { recursive: !0 });
832
- const o = `name: Unit tests
833
-
834
- on: push
835
-
836
- jobs:
837
- test:
838
- runs-on: ubuntu-latest
839
- steps:
840
- - uses: actions/checkout@v4
841
-
842
- - name: Setup Node.js
843
- uses: actions/setup-node@v4
844
- with:
845
- node-version: "22"
846
- cache: "npm"
847
-
848
- - name: Install dependencies
849
- run: npm ci
850
-
851
- - run: npm run type-check
852
- - run: npm test
853
- `, r = `name: Deploy to Dev
854
-
855
- on:
856
- push:
857
- branches:
858
- - main
859
-
860
- jobs:
861
- release:
862
- name: Release and Deploy
863
- runs-on: ubuntu-latest
864
- steps:
865
- - name: Checkout
866
- uses: actions/checkout@v4
867
- with:
868
- fetch-depth: 0
869
-
870
- - name: Setup Node.js
871
- uses: actions/setup-node@v4
872
- with:
873
- node-version: "22"
874
- cache: "npm"
875
-
876
- - name: Install dependencies
877
- run: npm ci
878
-
879
- - name: Release
880
- env:
881
- GITHUB_TOKEN: \${{ secrets.GITHUB_TOKEN }}
882
- run: npx semantic-release
883
-
884
- - name: Deploy to Cloudflare (Dev)
885
- uses: cloudflare/wrangler-action@v3
886
- with:
887
- apiToken: \${{ secrets.CLOUDFLARE_API_TOKEN }}
888
- command: deploy
889
- `, n = `name: Deploy to Production
890
-
891
- on:
892
- release:
893
- types: ["released"]
894
-
895
- jobs:
896
- deploy:
897
- name: Deploy to Production
898
- runs-on: ubuntu-latest
899
- steps:
900
- - name: Checkout
901
- uses: actions/checkout@v4
902
-
903
- - name: Setup Node.js
904
- uses: actions/setup-node@v4
905
- with:
906
- node-version: "22"
907
- cache: "npm"
908
-
909
- - name: Install dependencies
910
- run: npm ci
911
-
912
- - name: Deploy to Cloudflare (Production)
913
- uses: cloudflare/wrangler-action@v3
914
- with:
915
- apiToken: \${{ secrets.PROD_CLOUDFLARE_API_TOKEN }}
916
- command: deploy --env production
917
- `;
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!");
743
+ function _(e) {
744
+ let t = r.join(e, ".github", "workflows");
745
+ n.mkdirSync(t, { recursive: !0 }), n.writeFileSync(r.join(t, "unit-tests.yml"), "name: Unit tests\n\non: push\n\njobs:\n test:\n runs-on: ubuntu-latest\n steps:\n - uses: actions/checkout@v4\n\n - name: Setup Node.js\n uses: actions/setup-node@v4\n with:\n node-version: \"22\"\n cache: \"npm\"\n\n - name: Install dependencies\n run: npm ci\n\n - run: npm run type-check\n - run: npm test\n"), n.writeFileSync(r.join(t, "deploy-dev.yml"), "name: Deploy to Dev\n\non:\n push:\n branches:\n - main\n\njobs:\n release:\n name: Release and Deploy\n runs-on: ubuntu-latest\n steps:\n - name: Checkout\n uses: actions/checkout@v4\n with:\n fetch-depth: 0\n\n - name: Setup Node.js\n uses: actions/setup-node@v4\n with:\n node-version: \"22\"\n cache: \"npm\"\n\n - name: Install dependencies\n run: npm ci\n\n - name: Release\n env:\n GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n run: npx semantic-release\n\n - name: Deploy to Cloudflare (Dev)\n uses: cloudflare/wrangler-action@v3\n with:\n apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}\n command: deploy\n"), n.writeFileSync(r.join(t, "release.yml"), "name: Deploy to Production\n\non:\n release:\n types: [\"released\"]\n\njobs:\n deploy:\n name: Deploy to Production\n runs-on: ubuntu-latest\n steps:\n - name: Checkout\n uses: actions/checkout@v4\n\n - name: Setup Node.js\n uses: actions/setup-node@v4\n with:\n node-version: \"22\"\n cache: \"npm\"\n\n - name: Install dependencies\n run: npm ci\n\n - name: Deploy to Cloudflare (Production)\n uses: cloudflare/wrangler-action@v3\n with:\n apiToken: ${{ secrets.PROD_CLOUDFLARE_API_TOKEN }}\n command: deploy --env production\n"), console.log("\\n📦 GitHub CI workflows created!");
919
746
  }
920
- function J(a) {
921
- const e = {
922
- branches: ["main"],
923
- plugins: [
924
- "@semantic-release/commit-analyzer",
925
- "@semantic-release/release-notes-generator",
926
- "@semantic-release/github"
927
- ]
928
- };
929
- i.writeFileSync(
930
- s.join(a, ".releaserc.json"),
931
- JSON.stringify(e, null, 2)
932
- );
933
- const o = s.join(a, "package.json"), r = JSON.parse(i.readFileSync(o, "utf-8"));
934
- r.devDependencies = {
935
- ...r.devDependencies,
936
- "semantic-release": "^24.0.0"
937
- }, r.scripts = {
938
- ...r.scripts,
939
- test: 'echo "No tests yet"',
940
- "type-check": "tsc --noEmit"
941
- }, i.writeFileSync(o, JSON.stringify(r, null, 2));
747
+ function v(e) {
748
+ n.writeFileSync(r.join(e, ".releaserc.json"), JSON.stringify({
749
+ branches: ["main"],
750
+ plugins: [
751
+ "@semantic-release/commit-analyzer",
752
+ "@semantic-release/release-notes-generator",
753
+ "@semantic-release/github"
754
+ ]
755
+ }, null, 2));
756
+ let t = r.join(e, "package.json"), i = JSON.parse(n.readFileSync(t, "utf-8"));
757
+ i.devDependencies = {
758
+ ...i.devDependencies,
759
+ "semantic-release": "^24.0.0"
760
+ }, i.scripts = {
761
+ ...i.scripts,
762
+ test: "echo \"No tests yet\"",
763
+ "type-check": "tsc --noEmit"
764
+ }, n.writeFileSync(t, JSON.stringify(i, null, 2));
942
765
  }
943
- function A(a, e) {
944
- return new Promise((o, r) => {
945
- const n = U(a, [], {
946
- cwd: e,
947
- shell: !0,
948
- stdio: "inherit"
949
- });
950
- n.on("close", (t) => {
951
- t === 0 ? o() : r(new Error(`Command failed with exit code ${t}`));
952
- }), n.on("error", r);
953
- });
766
+ function y(e, t) {
767
+ return new Promise((n, r) => {
768
+ let i = a(e, [], {
769
+ cwd: t,
770
+ shell: !0,
771
+ stdio: "inherit"
772
+ });
773
+ i.on("close", (e) => {
774
+ e === 0 ? n() : r(/* @__PURE__ */ Error(`Command failed with exit code ${e}`));
775
+ }), i.on("error", r);
776
+ });
954
777
  }
955
- function z(a, e, o) {
956
- const r = s.join(a, "src");
957
- i.writeFileSync(
958
- s.join(r, "app.ts"),
959
- H(e, o)
960
- ), i.writeFileSync(
961
- s.join(r, "seed.ts"),
962
- j(e)
963
- );
778
+ function b(e, t, i) {
779
+ let a = r.join(e, "src");
780
+ n.writeFileSync(r.join(a, "app.ts"), f(t, i)), n.writeFileSync(r.join(a, "seed.ts"), d(t));
964
781
  }
965
- function D() {
966
- console.log(`
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) + `
968
- `);
782
+ function x() {
783
+ console.log("\n" + "─".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) + "\n");
969
784
  }
970
- function T() {
971
- console.log(`
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) + `
973
- `);
785
+ function S() {
786
+ console.log("\n" + "─".repeat(50)), console.log("🛰️ AuthHero proxy running at http://localhost:8787"), console.log("✏️ Edit src/proxy.config.ts to add hosts and routes"), console.log("📖 See README.md for deployment instructions"), console.log("─".repeat(50) + "\n");
974
787
  }
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(
976
- "--package-manager <pm>",
977
- "package manager to use: npm, yarn, pnpm, or bun"
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(
979
- "--conformance-alias <alias>",
980
- "alias for conformance suite (default: authhero-local)"
981
- ).option(
982
- "--workspace",
983
- "use workspace:* dependencies for local monorepo development"
984
- ).option("-y, --yes", "skip all prompts and use defaults/provided options").action(async (a, e) => {
985
- const o = e.yes === !0;
986
- console.log(`
987
- 🔐 Welcome to AuthHero!
988
- `);
989
- let r = a;
990
- r || (o ? (r = "auth-server", console.log(`Using default project name: ${r}`)) : r = (await m.prompt([
991
- {
992
- type: "input",
993
- name: "projectName",
994
- message: "Project name:",
995
- default: "auth-server",
996
- validate: (u) => u !== "" || "Project name cannot be empty"
997
- }
998
- ])).projectName);
999
- const n = s.join(process.cwd(), r);
1000
- i.existsSync(n) && (console.error(`❌ Project "${r}" already exists.`), process.exit(1));
1001
- let t;
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([
1003
- {
1004
- type: "list",
1005
- name: "setupType",
1006
- message: "Select your setup type:",
1007
- choices: [
1008
- {
1009
- name: `${p.local.name}
1010
- ${p.local.description}`,
1011
- value: "local",
1012
- short: p.local.name
1013
- },
1014
- {
1015
- name: `${p.cloudflare.name}
1016
- ${p.cloudflare.description}`,
1017
- value: "cloudflare",
1018
- short: p.cloudflare.name
1019
- },
1020
- {
1021
- name: `${p["aws-sst"].name}
1022
- ${p["aws-sst"].description}`,
1023
- value: "aws-sst",
1024
- short: p["aws-sst"].name
1025
- }
1026
- ]
1027
- }
1028
- ])).setupType;
1029
- let c;
1030
- e.multiTenant !== void 0 ? c = e.multiTenant : o ? c = !1 : c = (await m.prompt([
1031
- {
1032
- type: "confirm",
1033
- name: "multiTenant",
1034
- message: "Would you like to enable multi-tenant mode?",
1035
- default: !1
1036
- }
1037
- ])).multiTenant, c && console.log("Multi-tenant mode: enabled");
1038
- let d = !1;
1039
- (t === "local" || t === "cloudflare") && (e.adminUi !== void 0 ? d = e.adminUi : o ? d = !0 : d = (await m.prompt([
1040
- {
1041
- type: "confirm",
1042
- name: "adminUi",
1043
- message: "Would you like to include the admin UI at /admin?",
1044
- default: !0
1045
- }
1046
- ])).adminUi, d && console.log("Admin UI: enabled (available at /admin)"));
1047
- const f = e.conformance || !1, h = e.conformanceAlias || "authhero-local";
1048
- f && console.log(
1049
- `OpenID Conformance Suite: enabled (alias: ${h})`
1050
- );
1051
- const C = e.workspace || !1;
1052
- C && console.log("Workspace mode: enabled (using workspace:* dependencies)");
1053
- const y = p[t];
1054
- i.mkdirSync(n, { recursive: !0 }), i.writeFileSync(
1055
- s.join(n, "package.json"),
1056
- JSON.stringify(
1057
- y.packageJson(
1058
- r,
1059
- c,
1060
- f,
1061
- C,
1062
- d
1063
- ),
1064
- null,
1065
- 2
1066
- )
1067
- );
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(
1073
- `❌ Template directory not found. Looked in:
1074
- ${x.join(`
1075
- `)}`
1076
- ), process.exit(1)), t === "cloudflare" && z(n, c, d), t === "cloudflare") {
1077
- const l = s.join(n, "wrangler.toml"), u = s.join(n, "wrangler.local.toml");
1078
- i.existsSync(l) && i.copyFileSync(l, u);
1079
- const g = s.join(n, ".dev.vars.example"), w = s.join(n, ".dev.vars");
1080
- i.existsSync(g) && i.copyFileSync(g, w), console.log(
1081
- "📁 Created wrangler.local.toml and .dev.vars for local development"
1082
- );
1083
- }
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([
1086
- {
1087
- type: "confirm",
1088
- name: "includeGithubCi",
1089
- message: "Would you like to include GitHub CI with semantic versioning?",
1090
- default: !1
1091
- }
1092
- ])).includeGithubCi), b && (q(n), J(n))), t === "local") {
1093
- const l = $(
1094
- c,
1095
- f,
1096
- h,
1097
- d
1098
- );
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);
1102
- }
1103
- if (t === "aws-sst" && W(n, c), f) {
1104
- const l = {
1105
- alias: h,
1106
- description: "AuthHero Conformance Test",
1107
- server: {
1108
- discoveryUrl: "http://host.docker.internal:3000/.well-known/openid-configuration"
1109
- },
1110
- client: {
1111
- client_id: "conformance-test",
1112
- client_secret: "conformanceTestSecret123"
1113
- },
1114
- client2: {
1115
- client_id: "conformance-test2",
1116
- client_secret: "conformanceTestSecret456"
1117
- },
1118
- resource: {
1119
- resourceUrl: "http://host.docker.internal:3000/userinfo"
1120
- }
1121
- };
1122
- i.writeFileSync(
1123
- s.join(n, "conformance-config.json"),
1124
- JSON.stringify(l, null, 2)
1125
- ), console.log(
1126
- "📝 Created conformance-config.json for OpenID Conformance Suite"
1127
- );
1128
- }
1129
- const E = c ? "multi-tenant" : "single-tenant";
1130
- console.log(
1131
- `
1132
- Project "${r}" has been created with ${y.name} (${E}) setup!
1133
- `
1134
- );
1135
- let v;
1136
- if (e.skipInstall ? v = !1 : o ? v = !0 : v = (await m.prompt([
1137
- {
1138
- type: "confirm",
1139
- name: "shouldInstall",
1140
- message: "Would you like to install dependencies now?",
1141
- default: !0
1142
- }
1143
- ])).shouldInstall, v) {
1144
- let l;
1145
- e.packageManager ? (["npm", "yarn", "pnpm", "bun"].includes(e.packageManager) || (console.error(
1146
- `❌ Invalid package manager: ${e.packageManager}`
1147
- ), console.error("Valid options: npm, yarn, pnpm, bun"), process.exit(1)), l = e.packageManager) : o ? l = "pnpm" : l = (await m.prompt([
1148
- {
1149
- type: "list",
1150
- name: "packageManager",
1151
- message: "Which package manager would you like to use?",
1152
- choices: [
1153
- { name: "pnpm", value: "pnpm" },
1154
- { name: "npm", value: "npm" },
1155
- { name: "yarn", value: "yarn" },
1156
- { name: "bun", value: "bun" }
1157
- ],
1158
- default: "pnpm"
1159
- }
1160
- ])).packageManager, console.log(`
1161
- 📦 Installing dependencies with ${l}...
1162
- `);
1163
- try {
1164
- const u = l === "pnpm" ? "pnpm install --ignore-workspace" : `${l} install`;
1165
- if (await A(u, n), t === "local" && (console.log(`
1166
- 🔧 Building native modules...
1167
- `), await A("npm rebuild better-sqlite3", n)), console.log(`
1168
- ✅ Dependencies installed successfully!
1169
- `), (t === "local" || t === "cloudflare") && !e.skipMigrate) {
1170
- let w;
1171
- o ? w = !0 : w = (await m.prompt([
1172
- {
1173
- type: "confirm",
1174
- name: "shouldMigrate",
1175
- message: "Would you like to run database migrations?",
1176
- default: !0
1177
- }
1178
- ])).shouldMigrate, w && (console.log(`
1179
- 🔄 Running migrations...
1180
- `), await A(`${l} run migrate`, n));
1181
- }
1182
- let g;
1183
- e.skipStart || o ? g = !1 : g = (await m.prompt([
1184
- {
1185
- type: "confirm",
1186
- name: "shouldStart",
1187
- message: "Would you like to start the development server?",
1188
- default: !0
1189
- }
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(`
1192
- ✅ Setup complete!`), console.log(`
1193
- To start the development server:`), console.log(` cd ${r}`), console.log(" npm run dev"), t === "cloudflare" ? D() : t === "aws-sst" ? k() : T());
1194
- } catch (u) {
1195
- console.error(`
1196
- ❌ An error occurred:`, u), process.exit(1);
1197
- }
1198
- }
1199
- v || (console.log("Next steps:"), console.log(` cd ${r}`), t === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(" npm run dev"), console.log(
1200
- `
1201
- Open http://localhost:3000/setup to complete initial setup`
1202
- )) : t === "cloudflare" ? (console.log(" npm install"), console.log(
1203
- " npm run migrate # or npm run db:migrate:remote for production"
1204
- ), console.log(" npm run dev # or npm run dev:remote for production"), console.log(
1205
- `
1206
- Open https://localhost:3000/setup to complete initial setup`
1207
- )) : t === "aws-sst" && (console.log(" npm install"), console.log(" npm run dev # Deploys to AWS in development mode"), console.log(`
1208
- Open your server URL /setup to complete initial setup`)), console.log(`
1209
- Server will be available at: http://localhost:3000`), f && (console.log(`
1210
- 🧪 OpenID Conformance Suite Testing:`), console.log(
1211
- " 1. Clone and start the conformance suite (if not already running):"
1212
- ), console.log(
1213
- " git clone https://gitlab.com/openid/conformance-suite.git"
1214
- ), 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(
1215
- " 3. Create a test plan and use conformance-config.json for settings"
1216
- ), console.log(` 4. Use alias: ${h}`)), console.log(`
1217
- For more information, visit: https://authhero.net/docs
1218
- `));
1219
- });
1220
- N.parse(process.argv);
788
+ function C() {
789
+ console.log("\n" + "─".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) + "\n");
790
+ }
791
+ o.version("1.0.0").description("Create a new AuthHero project").argument("[project-name]", "name of the project").option("-t, --template <type>", "template type: local, cloudflare, aws-sst, or proxy").option("--package-manager <pm>", "package manager to use: npm, yarn, pnpm, or bun").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("--conformance-alias <alias>", "alias for conformance suite (default: authhero-local)").option("--workspace", "use workspace:* dependencies for local monorepo development").option("-y, --yes", "skip all prompts and use defaults/provided options").action(async (e, a) => {
792
+ let o = a.yes === !0;
793
+ console.log("\n🔐 Welcome to AuthHero!\n");
794
+ let d = e;
795
+ d || (o ? (d = "auth-server", console.log(`Using default project name: ${d}`)) : d = (await t.prompt([{
796
+ type: "input",
797
+ name: "projectName",
798
+ message: "Project name:",
799
+ default: "auth-server",
800
+ validate: (e) => e !== "" || "Project name cannot be empty"
801
+ }])).projectName);
802
+ let f = r.join(process.cwd(), d);
803
+ n.existsSync(f) && (console.error(`❌ Project "${d}" already exists.`), process.exit(1));
804
+ let p;
805
+ a.template ? ([
806
+ "local",
807
+ "cloudflare",
808
+ "aws-sst",
809
+ "proxy"
810
+ ].includes(a.template) || (console.error(`❌ Invalid template: ${a.template}`), console.error("Valid options: local, cloudflare, aws-sst, proxy"), process.exit(1)), p = a.template, console.log(`Using template: ${s[p].name}`)) : p = (await t.prompt([{
811
+ type: "list",
812
+ name: "setupType",
813
+ message: "Select your setup type:",
814
+ choices: [
815
+ {
816
+ name: `${s.local.name}\n ${s.local.description}`,
817
+ value: "local",
818
+ short: s.local.name
819
+ },
820
+ {
821
+ name: `${s.cloudflare.name}\n ${s.cloudflare.description}`,
822
+ value: "cloudflare",
823
+ short: s.cloudflare.name
824
+ },
825
+ {
826
+ name: `${s["aws-sst"].name}\n ${s["aws-sst"].description}`,
827
+ value: "aws-sst",
828
+ short: s["aws-sst"].name
829
+ },
830
+ {
831
+ name: `${s.proxy.name}\n ${s.proxy.description}`,
832
+ value: "proxy",
833
+ short: s.proxy.name
834
+ }
835
+ ]
836
+ }])).setupType;
837
+ let m;
838
+ m = p === "proxy" ? !1 : a.multiTenant === void 0 ? o ? !1 : (await t.prompt([{
839
+ type: "confirm",
840
+ name: "multiTenant",
841
+ message: "Would you like to enable multi-tenant mode?",
842
+ default: !1
843
+ }])).multiTenant : a.multiTenant, m && console.log("Multi-tenant mode: enabled");
844
+ let w = !1;
845
+ (p === "local" || p === "cloudflare") && (w = a.adminUi === void 0 ? o ? !0 : (await t.prompt([{
846
+ type: "confirm",
847
+ name: "adminUi",
848
+ message: "Would you like to include the admin UI at /admin?",
849
+ default: !0
850
+ }])).adminUi : a.adminUi, w && console.log("Admin UI: enabled (available at /admin)"));
851
+ let T = a.conformance || !1, E = a.conformanceAlias || "authhero-local";
852
+ T && console.log(`OpenID Conformance Suite: enabled (alias: ${E})`);
853
+ let D = a.workspace || !1;
854
+ D && console.log("Workspace mode: enabled (using workspace:* dependencies)");
855
+ let O = s[p];
856
+ n.mkdirSync(f, { recursive: !0 }), n.writeFileSync(r.join(f, "package.json"), JSON.stringify(O.packageJson(d, m, T, D, w), null, 2));
857
+ let k = O.templateDir, A = r.dirname(i(import.meta.url)), j = [r.join(A, k), r.join(A, "..", "templates", k)], M = j.find((e) => n.existsSync(e));
858
+ if (M ? c(M, f) : (console.error(`❌ Template directory not found. Looked in:\n ${j.join("\n ")}`), process.exit(1)), p === "cloudflare" && b(f, m, w), p === "cloudflare") {
859
+ let e = r.join(f, "wrangler.toml"), t = r.join(f, "wrangler.local.toml");
860
+ n.existsSync(e) && n.copyFileSync(e, t);
861
+ let i = r.join(f, ".dev.vars.example"), a = r.join(f, ".dev.vars");
862
+ n.existsSync(i) && n.copyFileSync(i, a), console.log("📁 Created wrangler.local.toml and .dev.vars for local development");
863
+ }
864
+ let N = !1;
865
+ if (p === "cloudflare" && (a.githubCi === void 0 ? o || (N = (await t.prompt([{
866
+ type: "confirm",
867
+ name: "includeGithubCi",
868
+ message: "Would you like to include GitHub CI with semantic versioning?",
869
+ default: !1
870
+ }])).includeGithubCi) : (N = a.githubCi, N && console.log("Including GitHub CI workflows with semantic versioning")), N && (_(f), v(f))), p === "local") {
871
+ let e = l(m, T, E, w);
872
+ n.writeFileSync(r.join(f, "src/seed.ts"), e);
873
+ let t = u(m, w);
874
+ n.writeFileSync(r.join(f, "src/app.ts"), t);
875
+ }
876
+ if (p === "aws-sst" && h(f, m), T) {
877
+ let e = {
878
+ alias: E,
879
+ description: "AuthHero Conformance Test",
880
+ server: { discoveryUrl: "http://host.docker.internal:3000/.well-known/openid-configuration" },
881
+ client: {
882
+ client_id: "conformance-test",
883
+ client_secret: "conformanceTestSecret123"
884
+ },
885
+ client2: {
886
+ client_id: "conformance-test2",
887
+ client_secret: "conformanceTestSecret456"
888
+ },
889
+ resource: { resourceUrl: "http://host.docker.internal:3000/userinfo" }
890
+ };
891
+ n.writeFileSync(r.join(f, "conformance-config.json"), JSON.stringify(e, null, 2)), console.log("📝 Created conformance-config.json for OpenID Conformance Suite");
892
+ }
893
+ let P = m ? "multi-tenant" : "single-tenant";
894
+ console.log(`\n✅ Project "${d}" has been created with ${O.name} (${P}) setup!\n`);
895
+ let F;
896
+ if (F = a.skipInstall ? !1 : o ? !0 : (await t.prompt([{
897
+ type: "confirm",
898
+ name: "shouldInstall",
899
+ message: "Would you like to install dependencies now?",
900
+ default: !0
901
+ }])).shouldInstall, F) {
902
+ let e;
903
+ a.packageManager ? ([
904
+ "npm",
905
+ "yarn",
906
+ "pnpm",
907
+ "bun"
908
+ ].includes(a.packageManager) || (console.error(`❌ Invalid package manager: ${a.packageManager}`), console.error("Valid options: npm, yarn, pnpm, bun"), process.exit(1)), e = a.packageManager) : e = o ? "pnpm" : (await t.prompt([{
909
+ type: "list",
910
+ name: "packageManager",
911
+ message: "Which package manager would you like to use?",
912
+ choices: [
913
+ {
914
+ name: "pnpm",
915
+ value: "pnpm"
916
+ },
917
+ {
918
+ name: "npm",
919
+ value: "npm"
920
+ },
921
+ {
922
+ name: "yarn",
923
+ value: "yarn"
924
+ },
925
+ {
926
+ name: "bun",
927
+ value: "bun"
928
+ }
929
+ ],
930
+ default: "pnpm"
931
+ }])).packageManager, console.log(`\n📦 Installing dependencies with ${e}...\n`);
932
+ try {
933
+ if (await y(e === "pnpm" ? "pnpm install --ignore-workspace" : `${e} install`, f), p === "local" && (console.log("\n🔧 Building native modules...\n"), await y("npm rebuild better-sqlite3", f)), console.log("\n✅ Dependencies installed successfully!\n"), (p === "local" || p === "cloudflare") && !a.skipMigrate) {
934
+ let n;
935
+ n = o ? !0 : (await t.prompt([{
936
+ type: "confirm",
937
+ name: "shouldMigrate",
938
+ message: "Would you like to run database migrations?",
939
+ default: !0
940
+ }])).shouldMigrate, n && (console.log("\n🔄 Running migrations...\n"), await y(`${e} run migrate`, f));
941
+ }
942
+ let n;
943
+ n = a.skipStart || o ? !1 : (await t.prompt([{
944
+ type: "confirm",
945
+ name: "shouldStart",
946
+ message: "Would you like to start the development server?",
947
+ default: !0
948
+ }])).shouldStart, n && (p === "cloudflare" ? x() : p === "aws-sst" ? g() : p === "proxy" ? S() : C(), console.log("🚀 Starting development server...\n"), await y(`${e} run dev`, f)), o && !n && (console.log("\n✅ Setup complete!"), console.log("\nTo start the development server:"), console.log(` cd ${d}`), console.log(" npm run dev"), p === "cloudflare" ? x() : p === "aws-sst" ? g() : p === "proxy" ? S() : C());
949
+ } catch (e) {
950
+ console.error("\n❌ An error occurred:", e), process.exit(1);
951
+ }
952
+ }
953
+ F || (console.log("Next steps:"), console.log(` cd ${d}`), p === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(" npm run dev"), console.log("\nOpen http://localhost:3000/setup to complete initial setup")) : p === "cloudflare" ? (console.log(" npm install"), console.log(" npm run migrate # or npm run db:migrate:remote for production"), console.log(" npm run dev # or npm run dev:remote for production"), console.log("\nOpen https://localhost:3000/setup to complete initial setup")) : p === "aws-sst" ? (console.log(" npm install"), console.log(" npm run dev # Deploys to AWS in development mode"), console.log("\nOpen your server URL /setup to complete initial setup")) : p === "proxy" && (console.log(" npm install"), console.log(" npm run dev"), console.log("\nEdit src/proxy.config.ts to add hosts and routes")), console.log(`\nServer will be available at: http://localhost:${p === "proxy" ? 8787 : 3e3}`), T && (console.log("\n🧪 OpenID Conformance Suite Testing:"), console.log(" 1. Clone and start the conformance suite (if not already running):"), console.log(" git clone https://gitlab.com/openid/conformance-suite.git"), 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(" 3. Create a test plan and use conformance-config.json for settings"), console.log(` 4. Use alias: ${E}`)), console.log("\nFor more information, visit: https://authhero.net/docs\n"));
954
+ }), o.parse(process.argv);
955
+ //#endregion