create-authhero 0.38.0 โ 0.40.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.
|
@@ -44,7 +44,7 @@ export async function handler(event: APIGatewayProxyEventV2, context: Context) {
|
|
|
44
44
|
// WARNING: These localhost origins are for development only
|
|
45
45
|
// Remove or override via ALLOWED_ORIGINS env var in production
|
|
46
46
|
"http://localhost:5173",
|
|
47
|
-
"
|
|
47
|
+
"http://localhost:3000",
|
|
48
48
|
origin,
|
|
49
49
|
].filter(Boolean);
|
|
50
50
|
|
|
@@ -58,7 +58,7 @@ This project is designed to be **open-source friendly**. Sensitive Cloudflare ID
|
|
|
58
58
|
npm run dev
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
The server will be available at `
|
|
61
|
+
The server will be available at `http://localhost:3000`.
|
|
62
62
|
|
|
63
63
|
### Remote Development (Your Cloudflare Account)
|
|
64
64
|
|
package/dist/create-authhero.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command as P } from "commander";
|
|
3
3
|
import m from "inquirer";
|
|
4
|
-
import
|
|
4
|
+
import a from "fs";
|
|
5
5
|
import i from "path";
|
|
6
6
|
import { spawn as E } from "child_process";
|
|
7
7
|
const D = new P(), p = {
|
|
@@ -9,10 +9,10 @@ const D = new P(), p = {
|
|
|
9
9
|
name: "Local (SQLite)",
|
|
10
10
|
description: "Local development setup with SQLite database - great for getting started",
|
|
11
11
|
templateDir: "local",
|
|
12
|
-
packageJson: (
|
|
12
|
+
packageJson: (s, e, o, r, n) => {
|
|
13
13
|
const t = r ? "workspace:*" : "latest";
|
|
14
14
|
return {
|
|
15
|
-
name:
|
|
15
|
+
name: s,
|
|
16
16
|
version: "1.0.0",
|
|
17
17
|
type: "module",
|
|
18
18
|
scripts: {
|
|
@@ -23,7 +23,7 @@ const D = new P(), p = {
|
|
|
23
23
|
},
|
|
24
24
|
dependencies: {
|
|
25
25
|
"@authhero/kysely-adapter": t,
|
|
26
|
-
...
|
|
26
|
+
...n && { "@authhero/react-admin": t },
|
|
27
27
|
"@authhero/widget": t,
|
|
28
28
|
"@hono/swagger-ui": "^0.5.0",
|
|
29
29
|
"@hono/zod-openapi": "^0.19.0",
|
|
@@ -33,7 +33,7 @@ const D = new P(), p = {
|
|
|
33
33
|
hono: "^4.6.0",
|
|
34
34
|
kysely: "latest",
|
|
35
35
|
...e && { "@authhero/multi-tenancy": t },
|
|
36
|
-
...
|
|
36
|
+
...o && { bcryptjs: "latest" }
|
|
37
37
|
},
|
|
38
38
|
devDependencies: {
|
|
39
39
|
"@types/better-sqlite3": "^7.6.0",
|
|
@@ -49,10 +49,10 @@ const D = new P(), p = {
|
|
|
49
49
|
name: "Cloudflare Workers (D1)",
|
|
50
50
|
description: "Cloudflare Workers setup with D1 database",
|
|
51
51
|
templateDir: "cloudflare",
|
|
52
|
-
packageJson: (
|
|
52
|
+
packageJson: (s, e, o, r, n) => {
|
|
53
53
|
const t = r ? "workspace:*" : "latest";
|
|
54
54
|
return {
|
|
55
|
-
name:
|
|
55
|
+
name: s,
|
|
56
56
|
version: "1.0.0",
|
|
57
57
|
type: "module",
|
|
58
58
|
scripts: {
|
|
@@ -72,7 +72,7 @@ const D = new P(), p = {
|
|
|
72
72
|
dependencies: {
|
|
73
73
|
"@authhero/drizzle": t,
|
|
74
74
|
"@authhero/kysely-adapter": t,
|
|
75
|
-
...
|
|
75
|
+
...n && { "@authhero/react-admin": t },
|
|
76
76
|
"@authhero/widget": t,
|
|
77
77
|
"@hono/swagger-ui": "^0.5.0",
|
|
78
78
|
"@hono/zod-openapi": "^0.19.0",
|
|
@@ -81,7 +81,7 @@ const D = new P(), p = {
|
|
|
81
81
|
kysely: "latest",
|
|
82
82
|
"kysely-d1": "latest",
|
|
83
83
|
...e && { "@authhero/multi-tenancy": t },
|
|
84
|
-
...
|
|
84
|
+
...o && { bcryptjs: "latest" }
|
|
85
85
|
},
|
|
86
86
|
devDependencies: {
|
|
87
87
|
"@cloudflare/workers-types": "^4.0.0",
|
|
@@ -98,10 +98,10 @@ const D = new P(), p = {
|
|
|
98
98
|
name: "AWS SST (Lambda + DynamoDB)",
|
|
99
99
|
description: "Serverless AWS deployment with Lambda, DynamoDB, and SST",
|
|
100
100
|
templateDir: "aws-sst",
|
|
101
|
-
packageJson: (
|
|
101
|
+
packageJson: (s, e, o, r, n) => {
|
|
102
102
|
const t = r ? "workspace:*" : "latest";
|
|
103
103
|
return {
|
|
104
|
-
name:
|
|
104
|
+
name: s,
|
|
105
105
|
version: "1.0.0",
|
|
106
106
|
type: "module",
|
|
107
107
|
scripts: {
|
|
@@ -113,7 +113,7 @@ const D = new P(), p = {
|
|
|
113
113
|
},
|
|
114
114
|
dependencies: {
|
|
115
115
|
"@authhero/aws": t,
|
|
116
|
-
...
|
|
116
|
+
...n && { "@authhero/react-admin": t },
|
|
117
117
|
"@authhero/widget": t,
|
|
118
118
|
"@aws-sdk/client-dynamodb": "^3.0.0",
|
|
119
119
|
"@aws-sdk/lib-dynamodb": "^3.0.0",
|
|
@@ -122,7 +122,7 @@ const D = new P(), p = {
|
|
|
122
122
|
authhero: t,
|
|
123
123
|
hono: "^4.6.0",
|
|
124
124
|
...e && { "@authhero/multi-tenancy": t },
|
|
125
|
-
...
|
|
125
|
+
...o && { bcryptjs: "latest" }
|
|
126
126
|
},
|
|
127
127
|
devDependencies: {
|
|
128
128
|
"@types/aws-lambda": "^8.10.0",
|
|
@@ -136,34 +136,42 @@ const D = new P(), p = {
|
|
|
136
136
|
seedFile: "seed.ts"
|
|
137
137
|
}
|
|
138
138
|
};
|
|
139
|
-
function N(
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
139
|
+
function N(s, e) {
|
|
140
|
+
a.readdirSync(s).forEach((r) => {
|
|
141
|
+
const n = i.join(s, r), t = i.join(e, r);
|
|
142
|
+
a.lstatSync(n).isDirectory() ? (a.mkdirSync(t, { recursive: !0 }), N(n, t)) : a.copyFileSync(n, t);
|
|
143
143
|
});
|
|
144
144
|
}
|
|
145
|
-
function R(
|
|
146
|
-
const
|
|
145
|
+
function R(s, e = !1, o = "authhero-local", r) {
|
|
146
|
+
const n = s ? "control_plane" : "main", t = s ? "Control Plane" : "Main", c = [
|
|
147
147
|
"https://manage.authhero.net/auth-callback",
|
|
148
148
|
"https://local.authhero.net/auth-callback",
|
|
149
149
|
"http://localhost:5173/auth-callback",
|
|
150
|
-
"
|
|
151
|
-
...r ? ["
|
|
150
|
+
"http://localhost:3000/auth-callback",
|
|
151
|
+
...r ? ["http://localhost:3000/admin/auth-callback"] : []
|
|
152
152
|
], d = e ? [
|
|
153
|
-
`https://localhost.emobix.co.uk:8443/test/a/${
|
|
154
|
-
`https://localhost:8443/test/a/${
|
|
153
|
+
`https://localhost.emobix.co.uk:8443/test/a/${o}/callback`,
|
|
154
|
+
`https://localhost:8443/test/a/${o}/callback`
|
|
155
155
|
] : [], f = [...c, ...d], h = [
|
|
156
156
|
"https://manage.authhero.net",
|
|
157
157
|
"https://local.authhero.net",
|
|
158
158
|
"http://localhost:5173",
|
|
159
|
-
"
|
|
160
|
-
], C = e ? ["https://localhost:8443/", "https://localhost.emobix.co.uk:8443/"] : [], y = [...h, ...C],
|
|
159
|
+
"http://localhost:3000"
|
|
160
|
+
], C = e ? ["https://localhost:8443/", "https://localhost.emobix.co.uk:8443/"] : [], y = [...h, ...C], b = e ? `
|
|
161
161
|
// Create OpenID Conformance Suite test clients and user
|
|
162
162
|
console.log("Creating conformance test clients and user...");
|
|
163
|
-
|
|
163
|
+
|
|
164
|
+
// The OIDCC basic test plan calls /token without an audience param. AuthHero
|
|
165
|
+
// requires either an explicit audience or a tenant default_audience to mint
|
|
166
|
+
// an access token, so set one here for the conformance setup.
|
|
167
|
+
await adapters.tenants.update("${n}", {
|
|
168
|
+
default_audience: "urn:authhero:management",
|
|
169
|
+
});
|
|
170
|
+
console.log("โ
Set tenant default_audience for conformance");
|
|
171
|
+
|
|
164
172
|
const conformanceCallbacks = [
|
|
165
|
-
"https://localhost.emobix.co.uk:8443/test/a/${
|
|
166
|
-
"https://localhost:8443/test/a/${
|
|
173
|
+
"https://localhost.emobix.co.uk:8443/test/a/${o}/callback",
|
|
174
|
+
"https://localhost:8443/test/a/${o}/callback",
|
|
167
175
|
];
|
|
168
176
|
const conformanceLogoutUrls = [
|
|
169
177
|
"https://localhost:8443/",
|
|
@@ -175,7 +183,7 @@ function R(a, e = !1, n = "authhero-local", r) {
|
|
|
175
183
|
];
|
|
176
184
|
|
|
177
185
|
try {
|
|
178
|
-
await adapters.clients.create("${
|
|
186
|
+
await adapters.clients.create("${n}", {
|
|
179
187
|
client_id: "conformance-test",
|
|
180
188
|
client_secret: "conformanceTestSecret123",
|
|
181
189
|
name: "Conformance Test Client",
|
|
@@ -193,7 +201,7 @@ function R(a, e = !1, n = "authhero-local", r) {
|
|
|
193
201
|
}
|
|
194
202
|
|
|
195
203
|
try {
|
|
196
|
-
await adapters.clients.create("${
|
|
204
|
+
await adapters.clients.create("${n}", {
|
|
197
205
|
client_id: "conformance-test2",
|
|
198
206
|
client_secret: "conformanceTestSecret456",
|
|
199
207
|
name: "Conformance Test Client 2",
|
|
@@ -213,7 +221,7 @@ function R(a, e = !1, n = "authhero-local", r) {
|
|
|
213
221
|
// Create a conformance test user with ALL OIDC profile claims populated
|
|
214
222
|
// This is required for OIDCC-5.4 (VerifyScopesReturnedInUserInfoClaims) test
|
|
215
223
|
try {
|
|
216
|
-
await adapters.users.create("${
|
|
224
|
+
await adapters.users.create("${n}", {
|
|
217
225
|
user_id: \`\${USERNAME_PASSWORD_PROVIDER}|conformance-user\`,
|
|
218
226
|
email: "conformance@example.com",
|
|
219
227
|
email_verified: true,
|
|
@@ -248,7 +256,7 @@ function R(a, e = !1, n = "authhero-local", r) {
|
|
|
248
256
|
try {
|
|
249
257
|
const bcrypt = await import("bcryptjs");
|
|
250
258
|
const hashedPassword = await bcrypt.hash("ConformanceTest123!", 10);
|
|
251
|
-
await adapters.passwords.create("${
|
|
259
|
+
await adapters.passwords.create("${n}", {
|
|
252
260
|
user_id: \`\${USERNAME_PASSWORD_PROVIDER}|conformance-user\`,
|
|
253
261
|
password: hashedPassword,
|
|
254
262
|
});
|
|
@@ -266,9 +274,51 @@ import Database from "better-sqlite3";
|
|
|
266
274
|
import createAdapters from "@authhero/kysely-adapter";
|
|
267
275
|
import { seed } from "authhero";
|
|
268
276
|
|
|
277
|
+
interface ExtraClient {
|
|
278
|
+
client_id: string;
|
|
279
|
+
client_secret: string;
|
|
280
|
+
name?: string;
|
|
281
|
+
callbacks?: string[];
|
|
282
|
+
allowed_logout_urls?: string[];
|
|
283
|
+
web_origins?: string[];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function parseFlag(name: string): string | undefined {
|
|
287
|
+
const argv = process.argv.slice(2);
|
|
288
|
+
const eqPrefix = \`--\${name}=\`;
|
|
289
|
+
for (let i = 0; i < argv.length; i++) {
|
|
290
|
+
const arg = argv[i]!;
|
|
291
|
+
if (arg === \`--\${name}\`) return argv[i + 1];
|
|
292
|
+
if (arg.startsWith(eqPrefix)) return arg.slice(eqPrefix.length);
|
|
293
|
+
}
|
|
294
|
+
return undefined;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function positionalArgs(): string[] {
|
|
298
|
+
const out: string[] = [];
|
|
299
|
+
const argv = process.argv.slice(2);
|
|
300
|
+
for (let i = 0; i < argv.length; i++) {
|
|
301
|
+
const arg = argv[i]!;
|
|
302
|
+
if (arg.startsWith("--")) {
|
|
303
|
+
if (!arg.includes("=")) i++;
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
out.push(arg);
|
|
307
|
+
}
|
|
308
|
+
return out;
|
|
309
|
+
}
|
|
310
|
+
|
|
269
311
|
async function main() {
|
|
270
|
-
const
|
|
271
|
-
const
|
|
312
|
+
const positional = positionalArgs();
|
|
313
|
+
const adminUsername = positional[0] || process.env.ADMIN_USERNAME || "admin";
|
|
314
|
+
const adminPassword = positional[1] || process.env.ADMIN_PASSWORD || "admin";
|
|
315
|
+
|
|
316
|
+
const clientsJson = parseFlag("clients");
|
|
317
|
+
const userProfileJson = parseFlag("user-profile");
|
|
318
|
+
const extraClients: ExtraClient[] = clientsJson ? JSON.parse(clientsJson) : [];
|
|
319
|
+
const userProfile: Record<string, unknown> = userProfileJson
|
|
320
|
+
? JSON.parse(userProfileJson)
|
|
321
|
+
: {};
|
|
272
322
|
|
|
273
323
|
const dialect = new SqliteDialect({
|
|
274
324
|
database: new Database("db.sqlite"),
|
|
@@ -277,42 +327,69 @@ async function main() {
|
|
|
277
327
|
const db = new Kysely<any>({ dialect });
|
|
278
328
|
const adapters = createAdapters(db);
|
|
279
329
|
|
|
280
|
-
await seed(adapters, {
|
|
330
|
+
const seedResult = await seed(adapters, {
|
|
281
331
|
adminUsername,
|
|
282
332
|
adminPassword,
|
|
283
|
-
tenantId: "${
|
|
333
|
+
tenantId: "${n}",
|
|
284
334
|
tenantName: "${t}",
|
|
285
|
-
isControlPlane: ${!!
|
|
286
|
-
clientId: "default"
|
|
335
|
+
isControlPlane: ${!!s},
|
|
336
|
+
clientId: "default",
|
|
287
337
|
callbacks: ${JSON.stringify(f)},
|
|
288
338
|
allowedLogoutUrls: ${JSON.stringify(y)},
|
|
289
339
|
});
|
|
290
|
-
|
|
340
|
+
|
|
341
|
+
for (const c of extraClients) {
|
|
342
|
+
const existing = await adapters.clients.get(seedResult.tenantId, c.client_id);
|
|
343
|
+
if (existing) {
|
|
344
|
+
console.log(\`Client "\${c.client_id}" already exists, skipping...\`);
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
await adapters.clients.create(seedResult.tenantId, {
|
|
348
|
+
client_id: c.client_id,
|
|
349
|
+
client_secret: c.client_secret,
|
|
350
|
+
name: c.name ?? c.client_id,
|
|
351
|
+
callbacks: c.callbacks ?? [],
|
|
352
|
+
allowed_logout_urls: c.allowed_logout_urls ?? [],
|
|
353
|
+
web_origins: c.web_origins ?? [],
|
|
354
|
+
connections: ["Username-Password-Authentication"],
|
|
355
|
+
client_metadata: { universal_login_version: "2" },
|
|
356
|
+
});
|
|
357
|
+
console.log(\`โ
Created client "\${c.client_id}"\`);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (Object.keys(userProfile).length > 0) {
|
|
361
|
+
await adapters.users.update(seedResult.tenantId, seedResult.userId, userProfile);
|
|
362
|
+
console.log(\`โ
Updated profile of user "\${seedResult.username}"\`);
|
|
363
|
+
}
|
|
364
|
+
${b}
|
|
291
365
|
await db.destroy();
|
|
292
366
|
}
|
|
293
367
|
|
|
294
|
-
main().catch(
|
|
368
|
+
main().catch((err) => {
|
|
369
|
+
console.error(err);
|
|
370
|
+
process.exit(1);
|
|
371
|
+
});
|
|
295
372
|
`;
|
|
296
373
|
}
|
|
297
|
-
function
|
|
298
|
-
const
|
|
374
|
+
function O(s, e) {
|
|
375
|
+
const o = e ? `import fs from "fs";
|
|
299
376
|
` : "", r = e ? `
|
|
300
377
|
const adminDistPath = path.resolve(
|
|
301
378
|
__dirname,
|
|
302
379
|
"../node_modules/@authhero/react-admin/dist",
|
|
303
380
|
);
|
|
304
381
|
const adminIndexPath = path.join(adminDistPath, "index.html");
|
|
305
|
-
` : "",
|
|
382
|
+
` : "", n = e ? `
|
|
306
383
|
// Add admin UI handler if the package is installed
|
|
307
384
|
if (fs.existsSync(adminIndexPath)) {
|
|
308
385
|
const issuer =
|
|
309
|
-
process.env.ISSUER || \`
|
|
386
|
+
process.env.ISSUER || \`http://localhost:\${process.env.PORT || 3000}/\`;
|
|
310
387
|
const rawHtml = fs.readFileSync(adminIndexPath, "utf-8")
|
|
311
388
|
.replace(/src="\\.\\//g, 'src="/admin/')
|
|
312
389
|
.replace(/href="\\.\\//g, 'href="/admin/');
|
|
313
390
|
const configJson = JSON.stringify({
|
|
314
391
|
domain: issuer.replace(/\\/$/, ""),
|
|
315
|
-
clientId: ${
|
|
392
|
+
clientId: ${s ? "CONTROL_PLANE_CLIENT_ID," : '"default",'}
|
|
316
393
|
basePath: "/admin",
|
|
317
394
|
}).replace(/</g, "\\\\u003c");
|
|
318
395
|
configWithHandlers.adminIndexHtml = rawHtml.replace(
|
|
@@ -325,13 +402,13 @@ const adminIndexPath = path.join(adminDistPath, "index.html");
|
|
|
325
402
|
});
|
|
326
403
|
}
|
|
327
404
|
` : "";
|
|
328
|
-
return
|
|
405
|
+
return s ? `import { Context } from "hono";
|
|
329
406
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
330
407
|
import { AuthHeroConfig, DataAdapters } from "authhero";
|
|
331
408
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
332
409
|
import { initMultiTenant } from "@authhero/multi-tenancy";
|
|
333
410
|
import path from "path";
|
|
334
|
-
${
|
|
411
|
+
${o}import { fileURLToPath } from "url";
|
|
335
412
|
|
|
336
413
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
337
414
|
|
|
@@ -352,7 +429,7 @@ export default function createApp(config: AuthHeroConfig & { dataAdapter: DataAd
|
|
|
352
429
|
rewriteRequestPath: (p) => p.replace("/u/widget", ""),
|
|
353
430
|
}),
|
|
354
431
|
};
|
|
355
|
-
${
|
|
432
|
+
${n}
|
|
356
433
|
// Initialize multi-tenant AuthHero - syncs resource servers, roles, and connections by default
|
|
357
434
|
const { app } = initMultiTenant({
|
|
358
435
|
...configWithHandlers,
|
|
@@ -389,7 +466,7 @@ import { AuthHeroConfig, init } from "authhero";
|
|
|
389
466
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
390
467
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
391
468
|
import path from "path";
|
|
392
|
-
${
|
|
469
|
+
${o}import { fileURLToPath } from "url";
|
|
393
470
|
|
|
394
471
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
395
472
|
|
|
@@ -406,7 +483,7 @@ export default function createApp(config: AuthHeroConfig) {
|
|
|
406
483
|
rewriteRequestPath: (p) => p.replace("/u/widget", ""),
|
|
407
484
|
}),
|
|
408
485
|
};
|
|
409
|
-
${
|
|
486
|
+
${n}
|
|
410
487
|
const { app } = init(configWithHandlers);
|
|
411
488
|
|
|
412
489
|
app
|
|
@@ -430,7 +507,7 @@ ${o}
|
|
|
430
507
|
}
|
|
431
508
|
`;
|
|
432
509
|
}
|
|
433
|
-
function
|
|
510
|
+
function U(s) {
|
|
434
511
|
return `import { D1Dialect } from "kysely-d1";
|
|
435
512
|
import { Kysely } from "kysely";
|
|
436
513
|
import createAdapters from "@authhero/kysely-adapter";
|
|
@@ -457,9 +534,9 @@ export default {
|
|
|
457
534
|
adminUsername,
|
|
458
535
|
adminPassword,
|
|
459
536
|
issuer,
|
|
460
|
-
tenantId: "${
|
|
461
|
-
tenantName: "${
|
|
462
|
-
isControlPlane: ${!!
|
|
537
|
+
tenantId: "${s ? "control_plane" : "main"}",
|
|
538
|
+
tenantName: "${s ? "Control Plane" : "Main"}",
|
|
539
|
+
isControlPlane: ${!!s},
|
|
463
540
|
clientId: "default",
|
|
464
541
|
});
|
|
465
542
|
|
|
@@ -491,15 +568,15 @@ export default {
|
|
|
491
568
|
};
|
|
492
569
|
`;
|
|
493
570
|
}
|
|
494
|
-
function
|
|
495
|
-
const
|
|
571
|
+
function $(s, e) {
|
|
572
|
+
const o = e ? `import adminIndexHtml from "./admin-index-html";
|
|
496
573
|
` : "", r = e ? ` adminIndexHtml,
|
|
497
574
|
` : "";
|
|
498
|
-
return
|
|
575
|
+
return s ? `import { Context } from "hono";
|
|
499
576
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
500
577
|
import { AuthHeroConfig, DataAdapters } from "authhero";
|
|
501
578
|
import { initMultiTenant } from "@authhero/multi-tenancy";
|
|
502
|
-
${
|
|
579
|
+
${o}
|
|
503
580
|
// Control plane configuration
|
|
504
581
|
const CONTROL_PLANE_TENANT_ID = "control_plane";
|
|
505
582
|
const CONTROL_PLANE_CLIENT_ID = "default";
|
|
@@ -540,7 +617,7 @@ ${r} controlPlane: {
|
|
|
540
617
|
import { cors } from "hono/cors";
|
|
541
618
|
import { AuthHeroConfig, init } from "authhero";
|
|
542
619
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
543
|
-
${
|
|
620
|
+
${o}
|
|
544
621
|
export default function createApp(config: AuthHeroConfig) {
|
|
545
622
|
const { app } = init({
|
|
546
623
|
...config,
|
|
@@ -576,8 +653,8 @@ ${r} });
|
|
|
576
653
|
}
|
|
577
654
|
`;
|
|
578
655
|
}
|
|
579
|
-
function
|
|
580
|
-
return
|
|
656
|
+
function L(s) {
|
|
657
|
+
return s ? `import { Context } from "hono";
|
|
581
658
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
582
659
|
import { AuthHeroConfig, DataAdapters } from "authhero";
|
|
583
660
|
import { initMultiTenant } from "@authhero/multi-tenancy";
|
|
@@ -682,7 +759,7 @@ export default function createApp(config: AppConfig) {
|
|
|
682
759
|
}
|
|
683
760
|
`;
|
|
684
761
|
}
|
|
685
|
-
function
|
|
762
|
+
function j(s) {
|
|
686
763
|
return `import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
687
764
|
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
|
|
688
765
|
import createAdapters from "@authhero/aws";
|
|
@@ -711,9 +788,9 @@ async function main() {
|
|
|
711
788
|
await seed(adapters, {
|
|
712
789
|
adminUsername,
|
|
713
790
|
adminPassword,
|
|
714
|
-
tenantId: "${
|
|
715
|
-
tenantName: "${
|
|
716
|
-
isControlPlane: ${!!
|
|
791
|
+
tenantId: "${s ? "control_plane" : "main"}",
|
|
792
|
+
tenantName: "${s ? "Control Plane" : "Main"}",
|
|
793
|
+
isControlPlane: ${!!s},
|
|
717
794
|
});
|
|
718
795
|
|
|
719
796
|
console.log("โ
Database seeded successfully!");
|
|
@@ -722,23 +799,23 @@ async function main() {
|
|
|
722
799
|
main().catch(console.error);
|
|
723
800
|
`;
|
|
724
801
|
}
|
|
725
|
-
function H(
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
i.join(
|
|
802
|
+
function H(s, e) {
|
|
803
|
+
const o = i.join(s, "src");
|
|
804
|
+
a.writeFileSync(
|
|
805
|
+
i.join(o, "app.ts"),
|
|
806
|
+
L(e)
|
|
807
|
+
), a.writeFileSync(
|
|
808
|
+
i.join(o, "seed.ts"),
|
|
729
809
|
j(e)
|
|
730
|
-
), s.writeFileSync(
|
|
731
|
-
i.join(n, "seed.ts"),
|
|
732
|
-
$(e)
|
|
733
810
|
);
|
|
734
811
|
}
|
|
735
812
|
function x() {
|
|
736
813
|
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");
|
|
737
814
|
}
|
|
738
|
-
function
|
|
739
|
-
const e = i.join(
|
|
740
|
-
|
|
741
|
-
const
|
|
815
|
+
function F(s) {
|
|
816
|
+
const e = i.join(s, ".github", "workflows");
|
|
817
|
+
a.mkdirSync(e, { recursive: !0 });
|
|
818
|
+
const o = `name: Unit tests
|
|
742
819
|
|
|
743
820
|
on: push
|
|
744
821
|
|
|
@@ -795,7 +872,7 @@ jobs:
|
|
|
795
872
|
with:
|
|
796
873
|
apiToken: \${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
797
874
|
command: deploy
|
|
798
|
-
`,
|
|
875
|
+
`, n = `name: Deploy to Production
|
|
799
876
|
|
|
800
877
|
on:
|
|
801
878
|
release:
|
|
@@ -824,9 +901,9 @@ jobs:
|
|
|
824
901
|
apiToken: \${{ secrets.PROD_CLOUDFLARE_API_TOKEN }}
|
|
825
902
|
command: deploy --env production
|
|
826
903
|
`;
|
|
827
|
-
|
|
904
|
+
a.writeFileSync(i.join(e, "unit-tests.yml"), o), a.writeFileSync(i.join(e, "deploy-dev.yml"), r), a.writeFileSync(i.join(e, "release.yml"), n), console.log("\\n๐ฆ GitHub CI workflows created!");
|
|
828
905
|
}
|
|
829
|
-
function
|
|
906
|
+
function M(s) {
|
|
830
907
|
const e = {
|
|
831
908
|
branches: ["main"],
|
|
832
909
|
plugins: [
|
|
@@ -835,11 +912,11 @@ function F(a) {
|
|
|
835
912
|
"@semantic-release/github"
|
|
836
913
|
]
|
|
837
914
|
};
|
|
838
|
-
|
|
839
|
-
i.join(
|
|
915
|
+
a.writeFileSync(
|
|
916
|
+
i.join(s, ".releaserc.json"),
|
|
840
917
|
JSON.stringify(e, null, 2)
|
|
841
918
|
);
|
|
842
|
-
const
|
|
919
|
+
const o = i.join(s, "package.json"), r = JSON.parse(a.readFileSync(o, "utf-8"));
|
|
843
920
|
r.devDependencies = {
|
|
844
921
|
...r.devDependencies,
|
|
845
922
|
"semantic-release": "^24.0.0"
|
|
@@ -847,38 +924,38 @@ function F(a) {
|
|
|
847
924
|
...r.scripts,
|
|
848
925
|
test: 'echo "No tests yet"',
|
|
849
926
|
"type-check": "tsc --noEmit"
|
|
850
|
-
},
|
|
927
|
+
}, a.writeFileSync(o, JSON.stringify(r, null, 2));
|
|
851
928
|
}
|
|
852
|
-
function
|
|
853
|
-
return new Promise((
|
|
854
|
-
const
|
|
929
|
+
function _(s, e) {
|
|
930
|
+
return new Promise((o, r) => {
|
|
931
|
+
const n = E(s, [], {
|
|
855
932
|
cwd: e,
|
|
856
933
|
shell: !0,
|
|
857
934
|
stdio: "inherit"
|
|
858
935
|
});
|
|
859
|
-
|
|
860
|
-
t === 0 ?
|
|
861
|
-
}),
|
|
936
|
+
n.on("close", (t) => {
|
|
937
|
+
t === 0 ? o() : r(new Error(`Command failed with exit code ${t}`));
|
|
938
|
+
}), n.on("error", r);
|
|
862
939
|
});
|
|
863
940
|
}
|
|
864
|
-
function W(
|
|
865
|
-
const r = i.join(
|
|
866
|
-
|
|
941
|
+
function W(s, e, o) {
|
|
942
|
+
const r = i.join(s, "src");
|
|
943
|
+
a.writeFileSync(
|
|
867
944
|
i.join(r, "app.ts"),
|
|
868
|
-
|
|
869
|
-
),
|
|
945
|
+
$(e, o)
|
|
946
|
+
), a.writeFileSync(
|
|
870
947
|
i.join(r, "seed.ts"),
|
|
871
|
-
|
|
948
|
+
U(e)
|
|
872
949
|
);
|
|
873
950
|
}
|
|
874
|
-
function
|
|
951
|
+
function I() {
|
|
875
952
|
console.log(`
|
|
876
|
-
` + "โ".repeat(50)), console.log("๐ AuthHero server running at https://localhost:3000"), console.log("
|
|
953
|
+
` + "โ".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) + `
|
|
877
954
|
`);
|
|
878
955
|
}
|
|
879
956
|
function k() {
|
|
880
957
|
console.log(`
|
|
881
|
-
` + "โ".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
|
|
958
|
+
` + "โ".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) + `
|
|
882
959
|
`);
|
|
883
960
|
}
|
|
884
961
|
D.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(
|
|
@@ -890,13 +967,13 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
890
967
|
).option(
|
|
891
968
|
"--workspace",
|
|
892
969
|
"use workspace:* dependencies for local monorepo development"
|
|
893
|
-
).option("-y, --yes", "skip all prompts and use defaults/provided options").action(async (
|
|
894
|
-
const
|
|
970
|
+
).option("-y, --yes", "skip all prompts and use defaults/provided options").action(async (s, e) => {
|
|
971
|
+
const o = e.yes === !0;
|
|
895
972
|
console.log(`
|
|
896
973
|
๐ Welcome to AuthHero!
|
|
897
974
|
`);
|
|
898
|
-
let r =
|
|
899
|
-
r || (
|
|
975
|
+
let r = s;
|
|
976
|
+
r || (o ? (r = "auth-server", console.log(`Using default project name: ${r}`)) : r = (await m.prompt([
|
|
900
977
|
{
|
|
901
978
|
type: "input",
|
|
902
979
|
name: "projectName",
|
|
@@ -905,8 +982,8 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
905
982
|
validate: (u) => u !== "" || "Project name cannot be empty"
|
|
906
983
|
}
|
|
907
984
|
])).projectName);
|
|
908
|
-
const
|
|
909
|
-
|
|
985
|
+
const n = i.join(process.cwd(), r);
|
|
986
|
+
a.existsSync(n) && (console.error(`โ Project "${r}" already exists.`), process.exit(1));
|
|
910
987
|
let t;
|
|
911
988
|
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([
|
|
912
989
|
{
|
|
@@ -936,7 +1013,7 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
936
1013
|
}
|
|
937
1014
|
])).setupType;
|
|
938
1015
|
let c;
|
|
939
|
-
e.multiTenant !== void 0 ? c = e.multiTenant :
|
|
1016
|
+
e.multiTenant !== void 0 ? c = e.multiTenant : o ? c = !1 : c = (await m.prompt([
|
|
940
1017
|
{
|
|
941
1018
|
type: "confirm",
|
|
942
1019
|
name: "multiTenant",
|
|
@@ -945,7 +1022,7 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
945
1022
|
}
|
|
946
1023
|
])).multiTenant, c && console.log("Multi-tenant mode: enabled");
|
|
947
1024
|
let d = !1;
|
|
948
|
-
(t === "local" || t === "cloudflare") && (e.adminUi !== void 0 ? d = e.adminUi :
|
|
1025
|
+
(t === "local" || t === "cloudflare") && (e.adminUi !== void 0 ? d = e.adminUi : o ? d = !0 : d = (await m.prompt([
|
|
949
1026
|
{
|
|
950
1027
|
type: "confirm",
|
|
951
1028
|
name: "adminUi",
|
|
@@ -960,8 +1037,8 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
960
1037
|
const C = e.workspace || !1;
|
|
961
1038
|
C && console.log("Workspace mode: enabled (using workspace:* dependencies)");
|
|
962
1039
|
const y = p[t];
|
|
963
|
-
|
|
964
|
-
i.join(
|
|
1040
|
+
a.mkdirSync(n, { recursive: !0 }), a.writeFileSync(
|
|
1041
|
+
i.join(n, "package.json"),
|
|
965
1042
|
JSON.stringify(
|
|
966
1043
|
y.packageJson(
|
|
967
1044
|
r,
|
|
@@ -974,38 +1051,38 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
974
1051
|
2
|
|
975
1052
|
)
|
|
976
1053
|
);
|
|
977
|
-
const
|
|
1054
|
+
const b = y.templateDir, S = i.join(
|
|
978
1055
|
import.meta.url.replace("file://", "").replace("/create-authhero.js", ""),
|
|
979
|
-
|
|
1056
|
+
b
|
|
980
1057
|
);
|
|
981
|
-
if (
|
|
982
|
-
const l = i.join(
|
|
983
|
-
|
|
984
|
-
const g = i.join(
|
|
985
|
-
|
|
1058
|
+
if (a.existsSync(S) ? N(S, n) : (console.error(`โ Template directory not found: ${S}`), process.exit(1)), t === "cloudflare" && W(n, c, d), t === "cloudflare") {
|
|
1059
|
+
const l = i.join(n, "wrangler.toml"), u = i.join(n, "wrangler.local.toml");
|
|
1060
|
+
a.existsSync(l) && a.copyFileSync(l, u);
|
|
1061
|
+
const g = i.join(n, ".dev.vars.example"), w = i.join(n, ".dev.vars");
|
|
1062
|
+
a.existsSync(g) && a.copyFileSync(g, w), console.log(
|
|
986
1063
|
"๐ Created wrangler.local.toml and .dev.vars for local development"
|
|
987
1064
|
);
|
|
988
1065
|
}
|
|
989
1066
|
let A = !1;
|
|
990
|
-
if (t === "cloudflare" && (e.githubCi !== void 0 ? (A = e.githubCi, A && console.log("Including GitHub CI workflows with semantic versioning")) :
|
|
1067
|
+
if (t === "cloudflare" && (e.githubCi !== void 0 ? (A = e.githubCi, A && console.log("Including GitHub CI workflows with semantic versioning")) : o || (A = (await m.prompt([
|
|
991
1068
|
{
|
|
992
1069
|
type: "confirm",
|
|
993
1070
|
name: "includeGithubCi",
|
|
994
1071
|
message: "Would you like to include GitHub CI with semantic versioning?",
|
|
995
1072
|
default: !1
|
|
996
1073
|
}
|
|
997
|
-
])).includeGithubCi), A && (
|
|
1074
|
+
])).includeGithubCi), A && (F(n), M(n))), t === "local") {
|
|
998
1075
|
const l = R(
|
|
999
1076
|
c,
|
|
1000
1077
|
f,
|
|
1001
1078
|
h,
|
|
1002
1079
|
d
|
|
1003
1080
|
);
|
|
1004
|
-
|
|
1005
|
-
const u =
|
|
1006
|
-
|
|
1081
|
+
a.writeFileSync(i.join(n, "src/seed.ts"), l);
|
|
1082
|
+
const u = O(c, d);
|
|
1083
|
+
a.writeFileSync(i.join(n, "src/app.ts"), u);
|
|
1007
1084
|
}
|
|
1008
|
-
if (t === "aws-sst" && H(
|
|
1085
|
+
if (t === "aws-sst" && H(n, c), f) {
|
|
1009
1086
|
const l = {
|
|
1010
1087
|
alias: h,
|
|
1011
1088
|
description: "AuthHero Conformance Test",
|
|
@@ -1024,8 +1101,8 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
1024
1101
|
resourceUrl: "http://host.docker.internal:3000/userinfo"
|
|
1025
1102
|
}
|
|
1026
1103
|
};
|
|
1027
|
-
|
|
1028
|
-
i.join(
|
|
1104
|
+
a.writeFileSync(
|
|
1105
|
+
i.join(n, "conformance-config.json"),
|
|
1029
1106
|
JSON.stringify(l, null, 2)
|
|
1030
1107
|
), console.log(
|
|
1031
1108
|
"๐ Created conformance-config.json for OpenID Conformance Suite"
|
|
@@ -1038,7 +1115,7 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
1038
1115
|
`
|
|
1039
1116
|
);
|
|
1040
1117
|
let v;
|
|
1041
|
-
if (e.skipInstall ? v = !1 :
|
|
1118
|
+
if (e.skipInstall ? v = !1 : o ? v = !0 : v = (await m.prompt([
|
|
1042
1119
|
{
|
|
1043
1120
|
type: "confirm",
|
|
1044
1121
|
name: "shouldInstall",
|
|
@@ -1049,7 +1126,7 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
1049
1126
|
let l;
|
|
1050
1127
|
e.packageManager ? (["npm", "yarn", "pnpm", "bun"].includes(e.packageManager) || (console.error(
|
|
1051
1128
|
`โ Invalid package manager: ${e.packageManager}`
|
|
1052
|
-
), console.error("Valid options: npm, yarn, pnpm, bun"), process.exit(1)), l = e.packageManager) :
|
|
1129
|
+
), console.error("Valid options: npm, yarn, pnpm, bun"), process.exit(1)), l = e.packageManager) : o ? l = "pnpm" : l = (await m.prompt([
|
|
1053
1130
|
{
|
|
1054
1131
|
type: "list",
|
|
1055
1132
|
name: "packageManager",
|
|
@@ -1067,13 +1144,13 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
1067
1144
|
`);
|
|
1068
1145
|
try {
|
|
1069
1146
|
const u = l === "pnpm" ? "pnpm install --ignore-workspace" : `${l} install`;
|
|
1070
|
-
if (await
|
|
1147
|
+
if (await _(u, n), t === "local" && (console.log(`
|
|
1071
1148
|
๐ง Building native modules...
|
|
1072
|
-
`), await
|
|
1149
|
+
`), await _("npm rebuild better-sqlite3", n)), console.log(`
|
|
1073
1150
|
โ
Dependencies installed successfully!
|
|
1074
1151
|
`), (t === "local" || t === "cloudflare") && !e.skipMigrate) {
|
|
1075
1152
|
let w;
|
|
1076
|
-
|
|
1153
|
+
o ? w = !0 : w = (await m.prompt([
|
|
1077
1154
|
{
|
|
1078
1155
|
type: "confirm",
|
|
1079
1156
|
name: "shouldMigrate",
|
|
@@ -1082,20 +1159,20 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
1082
1159
|
}
|
|
1083
1160
|
])).shouldMigrate, w && (console.log(`
|
|
1084
1161
|
๐ Running migrations...
|
|
1085
|
-
`), await
|
|
1162
|
+
`), await _(`${l} run migrate`, n));
|
|
1086
1163
|
}
|
|
1087
1164
|
let g;
|
|
1088
|
-
e.skipStart ||
|
|
1165
|
+
e.skipStart || o ? g = !1 : g = (await m.prompt([
|
|
1089
1166
|
{
|
|
1090
1167
|
type: "confirm",
|
|
1091
1168
|
name: "shouldStart",
|
|
1092
1169
|
message: "Would you like to start the development server?",
|
|
1093
1170
|
default: !0
|
|
1094
1171
|
}
|
|
1095
|
-
])).shouldStart, g && (t === "cloudflare" ?
|
|
1096
|
-
`), await
|
|
1172
|
+
])).shouldStart, g && (t === "cloudflare" ? I() : t === "aws-sst" ? x() : k(), console.log(`๐ Starting development server...
|
|
1173
|
+
`), await _(`${l} run dev`, n)), o && !g && (console.log(`
|
|
1097
1174
|
โ
Setup complete!`), console.log(`
|
|
1098
|
-
To start the development server:`), console.log(` cd ${r}`), console.log(" npm run dev"), t === "cloudflare" ?
|
|
1175
|
+
To start the development server:`), console.log(` cd ${r}`), console.log(" npm run dev"), t === "cloudflare" ? I() : t === "aws-sst" ? x() : k());
|
|
1099
1176
|
} catch (u) {
|
|
1100
1177
|
console.error(`
|
|
1101
1178
|
โ An error occurred:`, u), process.exit(1);
|
|
@@ -1103,7 +1180,7 @@ To start the development server:`), console.log(` cd ${r}`), console.log(" npm
|
|
|
1103
1180
|
}
|
|
1104
1181
|
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(
|
|
1105
1182
|
`
|
|
1106
|
-
Open
|
|
1183
|
+
Open http://localhost:3000/setup to complete initial setup`
|
|
1107
1184
|
)) : t === "cloudflare" ? (console.log(" npm install"), console.log(
|
|
1108
1185
|
" npm run migrate # or npm run db:migrate:remote for production"
|
|
1109
1186
|
), console.log(" npm run dev # or npm run dev:remote for production"), console.log(
|
|
@@ -1111,7 +1188,7 @@ Open https://localhost:3000/setup to complete initial setup`
|
|
|
1111
1188
|
Open https://localhost:3000/setup to complete initial setup`
|
|
1112
1189
|
)) : t === "aws-sst" && (console.log(" npm install"), console.log(" npm run dev # Deploys to AWS in development mode"), console.log(`
|
|
1113
1190
|
Open your server URL /setup to complete initial setup`)), console.log(`
|
|
1114
|
-
Server will be available at:
|
|
1191
|
+
Server will be available at: http://localhost:3000`), f && (console.log(`
|
|
1115
1192
|
๐งช OpenID Conformance Suite Testing:`), console.log(
|
|
1116
1193
|
" 1. Clone and start the conformance suite (if not already running):"
|
|
1117
1194
|
), console.log(
|
package/dist/local/src/app.ts
CHANGED
|
@@ -33,7 +33,7 @@ export default function createApp(config: AuthHeroConfig) {
|
|
|
33
33
|
// Add admin UI handler if the package is installed
|
|
34
34
|
if (fs.existsSync(adminIndexPath)) {
|
|
35
35
|
const issuer =
|
|
36
|
-
process.env.ISSUER || `
|
|
36
|
+
process.env.ISSUER || `http://localhost:${process.env.PORT || 3000}/`;
|
|
37
37
|
const rawHtml = fs
|
|
38
38
|
.readFileSync(adminIndexPath, "utf-8")
|
|
39
39
|
.replace(/src="\.\/assets\//g, 'src="/admin/assets/')
|