create-authhero 0.28.0 โ 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/aws-sst/README.md +4 -5
- package/dist/aws-sst/copy-assets.js +56 -26
- package/dist/cloudflare/README.md +9 -3
- package/dist/cloudflare/copy-assets.js +7 -1
- package/dist/cloudflare/seed-helper.js +8 -16
- package/dist/cloudflare/src/index.ts +1 -1
- package/dist/create-authhero.js +105 -131
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -87,7 +87,7 @@ my-auth-project/
|
|
|
87
87
|
cd my-auth-project
|
|
88
88
|
npm install
|
|
89
89
|
npm run migrate
|
|
90
|
-
|
|
90
|
+
npm run seed
|
|
91
91
|
npm run dev
|
|
92
92
|
```
|
|
93
93
|
|
|
@@ -158,7 +158,7 @@ my-auth-project/
|
|
|
158
158
|
cd my-auth-project
|
|
159
159
|
npm install
|
|
160
160
|
npm run migrate
|
|
161
|
-
|
|
161
|
+
npm run seed
|
|
162
162
|
npm run dev
|
|
163
163
|
```
|
|
164
164
|
|
package/dist/aws-sst/README.md
CHANGED
|
@@ -33,9 +33,8 @@ A serverless AuthHero deployment using [SST](https://sst.dev) with AWS Lambda an
|
|
|
33
33
|
After the dev server starts, seed your database:
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
|
-
#
|
|
37
|
-
export
|
|
38
|
-
export ADMIN_PASSWORD=your-secure-password
|
|
36
|
+
# Optionally set admin credentials (defaults to admin/admin)
|
|
37
|
+
export ADMIN_USERNAME=admin
|
|
39
38
|
|
|
40
39
|
npm run seed
|
|
41
40
|
```
|
|
@@ -76,8 +75,8 @@ Set these in SST or AWS Systems Manager:
|
|
|
76
75
|
|----------|-------------|
|
|
77
76
|
| `TABLE_NAME` | DynamoDB table name (auto-set by SST) |
|
|
78
77
|
| `WIDGET_URL` | URL to widget assets (auto-set by SST) |
|
|
79
|
-
| `
|
|
80
|
-
| `ADMIN_PASSWORD` | Admin user password (
|
|
78
|
+
| `ADMIN_USERNAME` | Admin username (defaults to "admin") |
|
|
79
|
+
| `ADMIN_PASSWORD` | Admin user password (defaults to "admin") |
|
|
81
80
|
|
|
82
81
|
## Widget Assets
|
|
83
82
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Copy AuthHero
|
|
4
|
+
* Copy AuthHero assets to dist directory
|
|
5
5
|
*
|
|
6
|
-
* This script copies
|
|
7
|
-
* so they can be
|
|
6
|
+
* This script copies static assets from the authhero package to the dist directory
|
|
7
|
+
* so they can be served as static files. Most deployment targets do not support
|
|
8
|
+
* serving files directly from node_modules.
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
import fs from "fs";
|
|
@@ -14,11 +15,25 @@ import { fileURLToPath } from "url";
|
|
|
14
15
|
const __filename = fileURLToPath(import.meta.url);
|
|
15
16
|
const __dirname = path.dirname(__filename);
|
|
16
17
|
|
|
18
|
+
const sourceDir = path.join(
|
|
19
|
+
__dirname,
|
|
20
|
+
"node_modules",
|
|
21
|
+
"authhero",
|
|
22
|
+
"dist",
|
|
23
|
+
"assets",
|
|
24
|
+
);
|
|
25
|
+
const targetDir = path.join(__dirname, "dist", "assets");
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Recursively copy directory contents
|
|
29
|
+
*/
|
|
17
30
|
function copyDirectory(src, dest) {
|
|
31
|
+
// Create destination directory if it doesn't exist
|
|
18
32
|
if (!fs.existsSync(dest)) {
|
|
19
33
|
fs.mkdirSync(dest, { recursive: true });
|
|
20
34
|
}
|
|
21
35
|
|
|
36
|
+
// Read source directory
|
|
22
37
|
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
23
38
|
|
|
24
39
|
for (const entry of entries) {
|
|
@@ -33,29 +48,44 @@ function copyDirectory(src, dest) {
|
|
|
33
48
|
}
|
|
34
49
|
}
|
|
35
50
|
|
|
36
|
-
|
|
37
|
-
const authHeroAssets = path.join(__dirname, "node_modules/authhero/dist/assets");
|
|
38
|
-
const widgetSource = path.join(
|
|
39
|
-
__dirname,
|
|
40
|
-
"node_modules/@authhero/widget/dist/authhero-widget"
|
|
41
|
-
);
|
|
42
|
-
const targetDir = path.join(__dirname, "dist/assets");
|
|
43
|
-
const widgetTarget = path.join(targetDir, "u/widget");
|
|
44
|
-
|
|
45
|
-
// Copy authhero assets
|
|
46
|
-
if (fs.existsSync(authHeroAssets)) {
|
|
51
|
+
try {
|
|
47
52
|
console.log("๐ฆ Copying AuthHero assets...");
|
|
48
|
-
copyDirectory(authHeroAssets, targetDir);
|
|
49
|
-
} else {
|
|
50
|
-
console.log("โ ๏ธ AuthHero assets not found at:", authHeroAssets);
|
|
51
|
-
}
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
if (!fs.existsSync(sourceDir)) {
|
|
55
|
+
console.error(`โ Source directory not found: ${sourceDir}`);
|
|
56
|
+
console.error("Make sure the authhero package is installed.");
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Clean target directory to remove stale files from previous builds
|
|
61
|
+
if (fs.existsSync(targetDir)) {
|
|
62
|
+
fs.rmSync(targetDir, { recursive: true });
|
|
63
|
+
console.log("๐งน Cleaned old assets");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
copyDirectory(sourceDir, targetDir);
|
|
60
67
|
|
|
61
|
-
|
|
68
|
+
// Also copy widget files from @authhero/widget package
|
|
69
|
+
const widgetSourceDir = path.join(
|
|
70
|
+
__dirname,
|
|
71
|
+
"node_modules",
|
|
72
|
+
"@authhero",
|
|
73
|
+
"widget",
|
|
74
|
+
"dist",
|
|
75
|
+
"authhero-widget",
|
|
76
|
+
);
|
|
77
|
+
const widgetTargetDir = path.join(targetDir, "u", "widget");
|
|
78
|
+
|
|
79
|
+
if (fs.existsSync(widgetSourceDir)) {
|
|
80
|
+
console.log("๐ฆ Copying widget assets...");
|
|
81
|
+
copyDirectory(widgetSourceDir, widgetTargetDir);
|
|
82
|
+
} else {
|
|
83
|
+
console.warn(`โ ๏ธ Widget directory not found: ${widgetSourceDir}`);
|
|
84
|
+
console.warn("Widget features may not work. Install @authhero/widget to enable.");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log(`โ
Assets copied to ${targetDir}`);
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error("โ Error copying assets:", error.message);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
@@ -43,7 +43,13 @@ This project is designed to be **open-source friendly**. Sensitive Cloudflare ID
|
|
|
43
43
|
3. Seed the database with an admin user:
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
|
|
46
|
+
npm run seed
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This creates an admin user with username `admin` and password `admin`. You can override with:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
ADMIN_USERNAME=myadmin ADMIN_PASSWORD=mypassword npm run seed
|
|
47
53
|
```
|
|
48
54
|
|
|
49
55
|
4. Start the development server:
|
|
@@ -81,7 +87,7 @@ The server will be available at `https://localhost:3000`.
|
|
|
81
87
|
4. Seed the remote database:
|
|
82
88
|
|
|
83
89
|
```bash
|
|
84
|
-
|
|
90
|
+
npm run seed:remote
|
|
85
91
|
```
|
|
86
92
|
|
|
87
93
|
5. Start with remote D1:
|
|
@@ -119,7 +125,7 @@ The server will be available at `https://localhost:3000`.
|
|
|
119
125
|
|
|
120
126
|
4. Seed the production database:
|
|
121
127
|
```bash
|
|
122
|
-
|
|
128
|
+
npm run seed:remote
|
|
123
129
|
```
|
|
124
130
|
|
|
125
131
|
## Project Structure
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Copy AuthHero assets to dist directory
|
|
5
5
|
*
|
|
6
6
|
* This script copies static assets from the authhero package to the dist directory
|
|
7
|
-
* so they can be served
|
|
7
|
+
* so they can be served as static files. Most deployment targets do not support
|
|
8
8
|
* serving files directly from node_modules.
|
|
9
9
|
*/
|
|
10
10
|
|
|
@@ -57,6 +57,12 @@ try {
|
|
|
57
57
|
process.exit(1);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
// Clean target directory to remove stale files from previous builds
|
|
61
|
+
if (fs.existsSync(targetDir)) {
|
|
62
|
+
fs.rmSync(targetDir, { recursive: true });
|
|
63
|
+
console.log("๐งน Cleaned old assets");
|
|
64
|
+
}
|
|
65
|
+
|
|
60
66
|
copyDirectory(sourceDir, targetDir);
|
|
61
67
|
|
|
62
68
|
// Also copy widget files from @authhero/widget package
|
|
@@ -8,18 +8,10 @@
|
|
|
8
8
|
import { spawn } from "child_process";
|
|
9
9
|
import { setTimeout } from "timers/promises";
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
const adminPassword = process.argv[3] || process.env.ADMIN_PASSWORD;
|
|
11
|
+
const adminUsername = process.argv[2] || process.env.ADMIN_USERNAME || "admin";
|
|
12
|
+
const adminPassword = process.argv[3] || process.env.ADMIN_PASSWORD || "admin";
|
|
13
13
|
const mode = process.argv[4] || "local";
|
|
14
14
|
|
|
15
|
-
if (!adminEmail || !adminPassword) {
|
|
16
|
-
console.error("Usage: node seed-helper.js <email> <password> [local|remote]");
|
|
17
|
-
console.error(
|
|
18
|
-
" or: ADMIN_EMAIL=... ADMIN_PASSWORD=... node seed-helper.js",
|
|
19
|
-
);
|
|
20
|
-
process.exit(1);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
15
|
console.log(`Starting seed worker in ${mode} mode...`);
|
|
24
16
|
|
|
25
17
|
const wranglerArgs = ["dev", "src/seed.ts"];
|
|
@@ -44,7 +36,7 @@ worker.stdout?.on("data", (data) => {
|
|
|
44
36
|
if (urlMatch) {
|
|
45
37
|
workerUrl = urlMatch[0].replace(/\/$/, ""); // Remove trailing slash
|
|
46
38
|
}
|
|
47
|
-
|
|
39
|
+
|
|
48
40
|
// Detect when the worker is ready
|
|
49
41
|
if (output.includes("Ready on") || output.includes("Listening on")) {
|
|
50
42
|
workerReady = true;
|
|
@@ -56,8 +48,8 @@ async function waitForWorker(maxAttempts = 30, delayMs = 1000) {
|
|
|
56
48
|
for (let i = 0; i < maxAttempts; i++) {
|
|
57
49
|
try {
|
|
58
50
|
// Just check if the server responds (even with an error is fine)
|
|
59
|
-
const response = await fetch(workerUrl, {
|
|
60
|
-
signal: AbortSignal.timeout(2000)
|
|
51
|
+
const response = await fetch(workerUrl, {
|
|
52
|
+
signal: AbortSignal.timeout(2000)
|
|
61
53
|
});
|
|
62
54
|
// Any response means the server is up
|
|
63
55
|
return true;
|
|
@@ -68,13 +60,13 @@ async function waitForWorker(maxAttempts = 30, delayMs = 1000) {
|
|
|
68
60
|
return true;
|
|
69
61
|
}
|
|
70
62
|
}
|
|
71
|
-
|
|
63
|
+
|
|
72
64
|
if (workerReady) {
|
|
73
65
|
// Give it a bit more time after wrangler reports ready
|
|
74
66
|
await setTimeout(500);
|
|
75
67
|
return true;
|
|
76
68
|
}
|
|
77
|
-
|
|
69
|
+
|
|
78
70
|
await setTimeout(delayMs);
|
|
79
71
|
if (i > 0 && i % 5 === 0) {
|
|
80
72
|
console.log(`Still waiting for worker... (attempt ${i + 1}/${maxAttempts})`);
|
|
@@ -95,7 +87,7 @@ if (!isReady) {
|
|
|
95
87
|
console.log(`\nMaking seed request to ${workerUrl}...`);
|
|
96
88
|
|
|
97
89
|
try {
|
|
98
|
-
const url = `${workerUrl}/?
|
|
90
|
+
const url = `${workerUrl}/?username=${encodeURIComponent(adminUsername)}&password=${encodeURIComponent(adminPassword)}`;
|
|
99
91
|
|
|
100
92
|
const response = await fetch(url);
|
|
101
93
|
const result = await response.json();
|
|
@@ -20,7 +20,7 @@ export default {
|
|
|
20
20
|
|
|
21
21
|
const dialect = new D1Dialect({ database: env.AUTH_DB });
|
|
22
22
|
const db = new Kysely<any>({ dialect });
|
|
23
|
-
const dataAdapter = createAdapters(db);
|
|
23
|
+
const dataAdapter = createAdapters(db, { useTransactions: false });
|
|
24
24
|
|
|
25
25
|
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
26
26
|
// OPTIONAL: Cloudflare Analytics Engine for centralized logging
|
package/dist/create-authhero.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Command as
|
|
2
|
+
import { Command as U } from "commander";
|
|
3
3
|
import u from "inquirer";
|
|
4
|
-
import
|
|
4
|
+
import s from "fs";
|
|
5
5
|
import l from "path";
|
|
6
|
-
import { spawn as
|
|
7
|
-
const
|
|
6
|
+
import { spawn as _ } from "child_process";
|
|
7
|
+
const I = new U(), p = {
|
|
8
8
|
local: {
|
|
9
9
|
name: "Local (SQLite)",
|
|
10
10
|
description: "Local development setup with SQLite database - great for getting started",
|
|
@@ -57,9 +57,9 @@ const E = new R(), p = {
|
|
|
57
57
|
scripts: {
|
|
58
58
|
postinstall: "node copy-assets.js",
|
|
59
59
|
"copy-assets": "node copy-assets.js",
|
|
60
|
-
dev: "wrangler dev --port 3000 --local-protocol https",
|
|
61
|
-
"dev:remote": "wrangler dev --port 3000 --local-protocol https --remote --config wrangler.local.toml",
|
|
62
|
-
deploy: "wrangler deploy --config wrangler.local.toml",
|
|
60
|
+
dev: "node copy-assets.js && wrangler dev --port 3000 --local-protocol https",
|
|
61
|
+
"dev:remote": "node copy-assets.js && wrangler dev --port 3000 --local-protocol https --remote --config wrangler.local.toml",
|
|
62
|
+
deploy: "node copy-assets.js && wrangler deploy --config wrangler.local.toml",
|
|
63
63
|
"db:migrate:local": "wrangler d1 migrations apply AUTH_DB --local",
|
|
64
64
|
"db:migrate:remote": "wrangler d1 migrations apply AUTH_DB --remote --config wrangler.local.toml",
|
|
65
65
|
migrate: "wrangler d1 migrations apply AUTH_DB --local",
|
|
@@ -133,14 +133,14 @@ const E = new R(), p = {
|
|
|
133
133
|
seedFile: "seed.ts"
|
|
134
134
|
}
|
|
135
135
|
};
|
|
136
|
-
function
|
|
137
|
-
|
|
138
|
-
const t = l.join(o, n),
|
|
139
|
-
|
|
136
|
+
function E(o, e) {
|
|
137
|
+
s.readdirSync(o).forEach((n) => {
|
|
138
|
+
const t = l.join(o, n), a = l.join(e, n);
|
|
139
|
+
s.lstatSync(t).isDirectory() ? (s.mkdirSync(a, { recursive: !0 }), E(t, a)) : s.copyFileSync(t, a);
|
|
140
140
|
});
|
|
141
141
|
}
|
|
142
|
-
function
|
|
143
|
-
const n = o ? "control_plane" : "main", t = o ? "Control Plane" : "Main",
|
|
142
|
+
function j(o, e = !1, r = "authhero-local") {
|
|
143
|
+
const n = o ? "control_plane" : "main", t = o ? "Control Plane" : "Main", a = [
|
|
144
144
|
"https://manage.authhero.net/auth-callback",
|
|
145
145
|
"https://local.authhero.net/auth-callback",
|
|
146
146
|
"http://localhost:5173/auth-callback",
|
|
@@ -148,12 +148,12 @@ function O(o, e = !1, r = "authhero-local") {
|
|
|
148
148
|
], c = e ? [
|
|
149
149
|
`https://localhost.emobix.co.uk:8443/test/a/${r}/callback`,
|
|
150
150
|
`https://localhost:8443/test/a/${r}/callback`
|
|
151
|
-
] : [], g = [...
|
|
151
|
+
] : [], g = [...a, ...c], w = [
|
|
152
152
|
"https://manage.authhero.net",
|
|
153
153
|
"https://local.authhero.net",
|
|
154
154
|
"http://localhost:5173",
|
|
155
155
|
"https://localhost:3000"
|
|
156
|
-
],
|
|
156
|
+
], C = e ? ["https://localhost:8443/", "https://localhost.emobix.co.uk:8443/"] : [], y = [...w, ...C], b = e ? `
|
|
157
157
|
// Create OpenID Conformance Suite test clients and user
|
|
158
158
|
console.log("Creating conformance test clients and user...");
|
|
159
159
|
|
|
@@ -263,14 +263,8 @@ import createAdapters from "@authhero/kysely-adapter";
|
|
|
263
263
|
import { seed } from "authhero";
|
|
264
264
|
|
|
265
265
|
async function main() {
|
|
266
|
-
const
|
|
267
|
-
const adminPassword = process.argv[3] || process.env.ADMIN_PASSWORD;
|
|
268
|
-
|
|
269
|
-
if (!adminEmail || !adminPassword) {
|
|
270
|
-
console.error("Usage: npm run seed <email> <password>");
|
|
271
|
-
console.error(" or: ADMIN_EMAIL=... ADMIN_PASSWORD=... npm run seed");
|
|
272
|
-
process.exit(1);
|
|
273
|
-
}
|
|
266
|
+
const adminUsername = process.argv[2] || process.env.ADMIN_USERNAME || "admin";
|
|
267
|
+
const adminPassword = process.argv[3] || process.env.ADMIN_PASSWORD || "admin";
|
|
274
268
|
|
|
275
269
|
const dialect = new SqliteDialect({
|
|
276
270
|
database: new Database("db.sqlite"),
|
|
@@ -280,7 +274,7 @@ async function main() {
|
|
|
280
274
|
const adapters = createAdapters(db);
|
|
281
275
|
|
|
282
276
|
await seed(adapters, {
|
|
283
|
-
|
|
277
|
+
adminUsername,
|
|
284
278
|
adminPassword,
|
|
285
279
|
tenantId: "${n}",
|
|
286
280
|
tenantName: "${t}",
|
|
@@ -288,14 +282,14 @@ async function main() {
|
|
|
288
282
|
callbacks: ${JSON.stringify(g)},
|
|
289
283
|
allowedLogoutUrls: ${JSON.stringify(y)},
|
|
290
284
|
});
|
|
291
|
-
${
|
|
285
|
+
${b}
|
|
292
286
|
await db.destroy();
|
|
293
287
|
}
|
|
294
288
|
|
|
295
289
|
main().catch(console.error);
|
|
296
290
|
`;
|
|
297
291
|
}
|
|
298
|
-
function
|
|
292
|
+
function L(o) {
|
|
299
293
|
return o ? `import { Context } from "hono";
|
|
300
294
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
301
295
|
import { AuthHeroConfig, DataAdapters } from "authhero";
|
|
@@ -399,7 +393,7 @@ export default function createApp(config: AuthHeroConfig) {
|
|
|
399
393
|
}
|
|
400
394
|
`;
|
|
401
395
|
}
|
|
402
|
-
function
|
|
396
|
+
function R(o) {
|
|
403
397
|
return `import { D1Dialect } from "kysely-d1";
|
|
404
398
|
import { Kysely } from "kysely";
|
|
405
399
|
import createAdapters from "@authhero/kysely-adapter";
|
|
@@ -412,31 +406,18 @@ interface Env {
|
|
|
412
406
|
export default {
|
|
413
407
|
async fetch(request: Request, env: Env): Promise<Response> {
|
|
414
408
|
const url = new URL(request.url);
|
|
415
|
-
const
|
|
416
|
-
const adminPassword = url.searchParams.get("password");
|
|
409
|
+
const adminUsername = url.searchParams.get("username") || "admin";
|
|
410
|
+
const adminPassword = url.searchParams.get("password") || "admin";
|
|
417
411
|
// Compute issuer from the request URL (for Management API identifier)
|
|
418
412
|
const issuer = \`\${url.protocol}//\${url.host}/\`;
|
|
419
413
|
|
|
420
|
-
if (!adminEmail || !adminPassword) {
|
|
421
|
-
return new Response(
|
|
422
|
-
JSON.stringify({
|
|
423
|
-
error: "Missing email or password query parameters",
|
|
424
|
-
usage: "/?email=admin@example.com&password=yourpassword",
|
|
425
|
-
}),
|
|
426
|
-
{
|
|
427
|
-
status: 400,
|
|
428
|
-
headers: { "Content-Type": "application/json" },
|
|
429
|
-
},
|
|
430
|
-
);
|
|
431
|
-
}
|
|
432
|
-
|
|
433
414
|
try {
|
|
434
415
|
const dialect = new D1Dialect({ database: env.AUTH_DB });
|
|
435
416
|
const db = new Kysely<any>({ dialect });
|
|
436
|
-
const adapters = createAdapters(db);
|
|
417
|
+
const adapters = createAdapters(db, { useTransactions: false });
|
|
437
418
|
|
|
438
419
|
const result = await seed(adapters, {
|
|
439
|
-
|
|
420
|
+
adminUsername,
|
|
440
421
|
adminPassword,
|
|
441
422
|
issuer,
|
|
442
423
|
tenantId: "${o ? "control_plane" : "main"}",
|
|
@@ -472,7 +453,7 @@ export default {
|
|
|
472
453
|
};
|
|
473
454
|
`;
|
|
474
455
|
}
|
|
475
|
-
function
|
|
456
|
+
function O(o) {
|
|
476
457
|
return o ? `import { Context } from "hono";
|
|
477
458
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
478
459
|
import { AuthHeroConfig, DataAdapters } from "authhero";
|
|
@@ -658,23 +639,17 @@ export default function createApp(config: AppConfig) {
|
|
|
658
639
|
}
|
|
659
640
|
`;
|
|
660
641
|
}
|
|
661
|
-
function
|
|
642
|
+
function M(o) {
|
|
662
643
|
return `import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
663
644
|
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
|
|
664
645
|
import createAdapters from "@authhero/aws";
|
|
665
646
|
import { seed } from "authhero";
|
|
666
647
|
|
|
667
648
|
async function main() {
|
|
668
|
-
const
|
|
669
|
-
const adminPassword = process.argv[3] || process.env.ADMIN_PASSWORD;
|
|
649
|
+
const adminUsername = process.argv[2] || process.env.ADMIN_USERNAME || "admin";
|
|
650
|
+
const adminPassword = process.argv[3] || process.env.ADMIN_PASSWORD || "admin";
|
|
670
651
|
const tableName = process.argv[4] || process.env.TABLE_NAME;
|
|
671
652
|
|
|
672
|
-
if (!adminEmail || !adminPassword) {
|
|
673
|
-
console.error("Usage: npm run seed <email> <password>");
|
|
674
|
-
console.error(" or: ADMIN_EMAIL=... ADMIN_PASSWORD=... npm run seed");
|
|
675
|
-
process.exit(1);
|
|
676
|
-
}
|
|
677
|
-
|
|
678
653
|
if (!tableName) {
|
|
679
654
|
console.error("TABLE_NAME environment variable is required");
|
|
680
655
|
console.error("Run 'sst dev' first to get the table name from outputs");
|
|
@@ -691,7 +666,7 @@ async function main() {
|
|
|
691
666
|
const adapters = createAdapters(docClient, { tableName });
|
|
692
667
|
|
|
693
668
|
await seed(adapters, {
|
|
694
|
-
|
|
669
|
+
adminUsername,
|
|
695
670
|
adminPassword,
|
|
696
671
|
tenantId: "${o ? "control_plane" : "main"}",
|
|
697
672
|
tenantName: "${o ? "Control Plane" : "Main"}",
|
|
@@ -704,22 +679,22 @@ async function main() {
|
|
|
704
679
|
main().catch(console.error);
|
|
705
680
|
`;
|
|
706
681
|
}
|
|
707
|
-
function
|
|
682
|
+
function H(o, e) {
|
|
708
683
|
const r = l.join(o, "src");
|
|
709
|
-
|
|
684
|
+
s.writeFileSync(
|
|
710
685
|
l.join(r, "app.ts"),
|
|
711
686
|
$(e)
|
|
712
|
-
),
|
|
687
|
+
), s.writeFileSync(
|
|
713
688
|
l.join(r, "seed.ts"),
|
|
714
|
-
|
|
689
|
+
M(e)
|
|
715
690
|
);
|
|
716
691
|
}
|
|
717
|
-
function
|
|
692
|
+
function x(o) {
|
|
718
693
|
console.log("\\n" + "โ".repeat(50)), console.log("๐ AuthHero deployed to AWS!"), console.log("๐ Check SST output for your API URL"), console.log("๐ Portal available at https://local.authhero.net"), console.log(o ? "๐ข Multi-tenant mode enabled with control_plane tenant" : "๐ Single-tenant mode with 'main' tenant"), console.log("โ".repeat(50) + "\\n");
|
|
719
694
|
}
|
|
720
|
-
function
|
|
695
|
+
function F(o) {
|
|
721
696
|
const e = l.join(o, ".github", "workflows");
|
|
722
|
-
|
|
697
|
+
s.mkdirSync(e, { recursive: !0 });
|
|
723
698
|
const r = `name: Unit tests
|
|
724
699
|
|
|
725
700
|
on: push
|
|
@@ -806,9 +781,9 @@ jobs:
|
|
|
806
781
|
apiToken: \${{ secrets.PROD_CLOUDFLARE_API_TOKEN }}
|
|
807
782
|
command: deploy --env production
|
|
808
783
|
`;
|
|
809
|
-
|
|
784
|
+
s.writeFileSync(l.join(e, "unit-tests.yml"), r), s.writeFileSync(l.join(e, "deploy-dev.yml"), n), s.writeFileSync(l.join(e, "release.yml"), t), console.log("\\n๐ฆ GitHub CI workflows created!");
|
|
810
785
|
}
|
|
811
|
-
function
|
|
786
|
+
function W(o) {
|
|
812
787
|
const e = {
|
|
813
788
|
branches: ["main"],
|
|
814
789
|
plugins: [
|
|
@@ -817,11 +792,11 @@ function q(o) {
|
|
|
817
792
|
"@semantic-release/github"
|
|
818
793
|
]
|
|
819
794
|
};
|
|
820
|
-
|
|
795
|
+
s.writeFileSync(
|
|
821
796
|
l.join(o, ".releaserc.json"),
|
|
822
797
|
JSON.stringify(e, null, 2)
|
|
823
798
|
);
|
|
824
|
-
const r = l.join(o, "package.json"), n = JSON.parse(
|
|
799
|
+
const r = l.join(o, "package.json"), n = JSON.parse(s.readFileSync(r, "utf-8"));
|
|
825
800
|
n.devDependencies = {
|
|
826
801
|
...n.devDependencies,
|
|
827
802
|
"semantic-release": "^24.0.0"
|
|
@@ -829,54 +804,54 @@ function q(o) {
|
|
|
829
804
|
...n.scripts,
|
|
830
805
|
test: 'echo "No tests yet"',
|
|
831
806
|
"type-check": "tsc --noEmit"
|
|
832
|
-
},
|
|
807
|
+
}, s.writeFileSync(r, JSON.stringify(n, null, 2));
|
|
833
808
|
}
|
|
834
|
-
function
|
|
809
|
+
function S(o, e) {
|
|
835
810
|
return new Promise((r, n) => {
|
|
836
|
-
const t =
|
|
811
|
+
const t = _(o, [], {
|
|
837
812
|
cwd: e,
|
|
838
813
|
shell: !0,
|
|
839
814
|
stdio: "inherit"
|
|
840
815
|
});
|
|
841
|
-
t.on("close", (
|
|
842
|
-
|
|
816
|
+
t.on("close", (a) => {
|
|
817
|
+
a === 0 ? r() : n(new Error(`Command failed with exit code ${a}`));
|
|
843
818
|
}), t.on("error", n);
|
|
844
819
|
});
|
|
845
820
|
}
|
|
846
|
-
function
|
|
821
|
+
function N(o, e, r) {
|
|
847
822
|
return new Promise((n, t) => {
|
|
848
|
-
const
|
|
823
|
+
const a = _(o, [], {
|
|
849
824
|
cwd: e,
|
|
850
825
|
shell: !0,
|
|
851
826
|
stdio: "inherit",
|
|
852
827
|
env: { ...process.env, ...r }
|
|
853
828
|
});
|
|
854
|
-
|
|
829
|
+
a.on("close", (c) => {
|
|
855
830
|
c === 0 ? n() : t(new Error(`Command failed with exit code ${c}`));
|
|
856
|
-
}),
|
|
831
|
+
}), a.on("error", t);
|
|
857
832
|
});
|
|
858
833
|
}
|
|
859
|
-
function
|
|
834
|
+
function q(o, e) {
|
|
860
835
|
const r = l.join(o, "src");
|
|
861
|
-
|
|
836
|
+
s.writeFileSync(
|
|
862
837
|
l.join(r, "app.ts"),
|
|
863
|
-
|
|
864
|
-
),
|
|
838
|
+
O(e)
|
|
839
|
+
), s.writeFileSync(
|
|
865
840
|
l.join(r, "seed.ts"),
|
|
866
|
-
|
|
841
|
+
R(e)
|
|
867
842
|
);
|
|
868
843
|
}
|
|
869
|
-
function
|
|
844
|
+
function D(o) {
|
|
870
845
|
console.log(`
|
|
871
846
|
` + "โ".repeat(50)), console.log("๐ AuthHero server running at https://localhost:3000"), console.log("๐ API documentation available at https://localhost:3000/docs"), console.log("๐ Portal available at https://local.authhero.net"), console.log(o ? "๐ข Multi-tenant mode enabled with control_plane tenant" : "๐ Single-tenant mode with 'main' tenant"), console.log("โ".repeat(50) + `
|
|
872
847
|
`);
|
|
873
848
|
}
|
|
874
|
-
function
|
|
849
|
+
function T(o) {
|
|
875
850
|
console.log(`
|
|
876
851
|
` + "โ".repeat(50)), console.log("โ
Self-signed certificates generated with openssl"), console.log("โ ๏ธ You may need to trust the certificate in your browser"), console.log("๐ AuthHero server running at https://localhost:3000"), console.log("๐ API documentation available at https://localhost:3000/docs"), console.log("๐ Portal available at https://local.authhero.net"), console.log(o ? "๐ข Multi-tenant mode enabled with control_plane tenant" : "๐ Single-tenant mode with 'main' tenant"), console.log("โ".repeat(50) + `
|
|
877
852
|
`);
|
|
878
853
|
}
|
|
879
|
-
|
|
854
|
+
I.version("1.0.0").description("Create a new AuthHero project").argument("[project-name]", "name of the project").option("-t, --template <type>", "template type: local or cloudflare").option("-e, --email <email>", "admin email address").option("-p, --password <password>", "admin password (min 8 characters)").option(
|
|
880
855
|
"--package-manager <pm>",
|
|
881
856
|
"package manager to use: npm, yarn, pnpm, or bun"
|
|
882
857
|
).option("--multi-tenant", "enable multi-tenant mode").option("--skip-install", "skip installing dependencies").option("--skip-migrate", "skip running database migrations").option("--skip-seed", "skip seeding the database").option("--skip-start", "skip starting the development server").option("--github-ci", "include GitHub CI workflows with semantic versioning").option("--conformance", "add OpenID conformance suite test clients").option(
|
|
@@ -898,9 +873,9 @@ E.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
898
873
|
}
|
|
899
874
|
])).projectName);
|
|
900
875
|
const t = l.join(process.cwd(), n);
|
|
901
|
-
|
|
902
|
-
let
|
|
903
|
-
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)),
|
|
876
|
+
s.existsSync(t) && (console.error(`โ Project "${n}" already exists.`), process.exit(1));
|
|
877
|
+
let a;
|
|
878
|
+
e.template ? (["local", "cloudflare", "aws-sst"].includes(e.template) || (console.error(`โ Invalid template: ${e.template}`), console.error("Valid options: local, cloudflare, aws-sst"), process.exit(1)), a = e.template, console.log(`Using template: ${p[a].name}`)) : a = (await u.prompt([
|
|
904
879
|
{
|
|
905
880
|
type: "list",
|
|
906
881
|
name: "setupType",
|
|
@@ -941,44 +916,44 @@ E.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
941
916
|
g && console.log(
|
|
942
917
|
`OpenID Conformance Suite: enabled (alias: ${w})`
|
|
943
918
|
);
|
|
944
|
-
const
|
|
945
|
-
|
|
946
|
-
const y = p[
|
|
947
|
-
|
|
919
|
+
const C = e.workspace || !1;
|
|
920
|
+
C && console.log("Workspace mode: enabled (using workspace:* dependencies)");
|
|
921
|
+
const y = p[a];
|
|
922
|
+
s.mkdirSync(t, { recursive: !0 }), s.writeFileSync(
|
|
948
923
|
l.join(t, "package.json"),
|
|
949
|
-
JSON.stringify(y.packageJson(n, c, g,
|
|
924
|
+
JSON.stringify(y.packageJson(n, c, g, C), null, 2)
|
|
950
925
|
);
|
|
951
|
-
const
|
|
926
|
+
const b = y.templateDir, k = l.join(
|
|
952
927
|
import.meta.url.replace("file://", "").replace("/create-authhero.js", ""),
|
|
953
|
-
|
|
928
|
+
b
|
|
954
929
|
);
|
|
955
|
-
if (
|
|
930
|
+
if (s.existsSync(k) ? E(k, t) : (console.error(`โ Template directory not found: ${k}`), process.exit(1)), a === "cloudflare" && q(t, c), a === "cloudflare") {
|
|
956
931
|
const i = l.join(t, "wrangler.toml"), d = l.join(t, "wrangler.local.toml");
|
|
957
|
-
|
|
932
|
+
s.existsSync(i) && s.copyFileSync(i, d);
|
|
958
933
|
const m = l.join(t, ".dev.vars.example"), f = l.join(t, ".dev.vars");
|
|
959
|
-
|
|
934
|
+
s.existsSync(m) && s.copyFileSync(m, f), console.log(
|
|
960
935
|
"๐ Created wrangler.local.toml and .dev.vars for local development"
|
|
961
936
|
);
|
|
962
937
|
}
|
|
963
|
-
let
|
|
964
|
-
if (
|
|
938
|
+
let A = !1;
|
|
939
|
+
if (a === "cloudflare" && (e.githubCi !== void 0 ? (A = e.githubCi, A && console.log("Including GitHub CI workflows with semantic versioning")) : r || (A = (await u.prompt([
|
|
965
940
|
{
|
|
966
941
|
type: "confirm",
|
|
967
942
|
name: "includeGithubCi",
|
|
968
943
|
message: "Would you like to include GitHub CI with semantic versioning?",
|
|
969
944
|
default: !1
|
|
970
945
|
}
|
|
971
|
-
])).includeGithubCi),
|
|
972
|
-
const i =
|
|
946
|
+
])).includeGithubCi), A && (F(t), W(t))), a === "local") {
|
|
947
|
+
const i = j(
|
|
973
948
|
c,
|
|
974
949
|
g,
|
|
975
950
|
w
|
|
976
951
|
);
|
|
977
|
-
|
|
978
|
-
const d =
|
|
979
|
-
|
|
952
|
+
s.writeFileSync(l.join(t, "src/seed.ts"), i);
|
|
953
|
+
const d = L(c);
|
|
954
|
+
s.writeFileSync(l.join(t, "src/app.ts"), d);
|
|
980
955
|
}
|
|
981
|
-
if (
|
|
956
|
+
if (a === "aws-sst" && H(t, c), g) {
|
|
982
957
|
const i = {
|
|
983
958
|
alias: w,
|
|
984
959
|
description: "AuthHero Conformance Test",
|
|
@@ -997,17 +972,17 @@ E.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
997
972
|
resourceUrl: "http://host.docker.internal:3000/userinfo"
|
|
998
973
|
}
|
|
999
974
|
};
|
|
1000
|
-
|
|
975
|
+
s.writeFileSync(
|
|
1001
976
|
l.join(t, "conformance-config.json"),
|
|
1002
977
|
JSON.stringify(i, null, 2)
|
|
1003
978
|
), console.log(
|
|
1004
979
|
"๐ Created conformance-config.json for OpenID Conformance Suite"
|
|
1005
980
|
);
|
|
1006
981
|
}
|
|
1007
|
-
const
|
|
982
|
+
const P = c ? "multi-tenant" : "single-tenant";
|
|
1008
983
|
console.log(
|
|
1009
984
|
`
|
|
1010
|
-
โ
Project "${n}" has been created with ${y.name} (${
|
|
985
|
+
โ
Project "${n}" has been created with ${y.name} (${P}) setup!
|
|
1011
986
|
`
|
|
1012
987
|
);
|
|
1013
988
|
let v;
|
|
@@ -1040,11 +1015,11 @@ E.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
1040
1015
|
`);
|
|
1041
1016
|
try {
|
|
1042
1017
|
const d = i === "pnpm" ? "pnpm install --ignore-workspace" : `${i} install`;
|
|
1043
|
-
if (await
|
|
1018
|
+
if (await S(d, t), a === "local" && (console.log(`
|
|
1044
1019
|
๐ง Building native modules...
|
|
1045
|
-
`), await
|
|
1020
|
+
`), await S("npm rebuild better-sqlite3", t)), console.log(`
|
|
1046
1021
|
โ
Dependencies installed successfully!
|
|
1047
|
-
`),
|
|
1022
|
+
`), a === "local" || a === "cloudflare") {
|
|
1048
1023
|
let f;
|
|
1049
1024
|
if (e.skipMigrate && e.skipSeed ? f = !1 : r ? f = !e.skipMigrate || !e.skipSeed : f = (await u.prompt([
|
|
1050
1025
|
{
|
|
@@ -1055,40 +1030,39 @@ E.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
1055
1030
|
}
|
|
1056
1031
|
])).shouldSetup, f) {
|
|
1057
1032
|
let h;
|
|
1058
|
-
e.email && e.password ? (
|
|
1033
|
+
e.email && e.password ? (h = {
|
|
1059
1034
|
username: e.email,
|
|
1060
1035
|
password: e.password
|
|
1061
|
-
}, console.log(`Using admin
|
|
1036
|
+
}, console.log(`Using admin username: ${e.email}`)) : h = await u.prompt([
|
|
1062
1037
|
{
|
|
1063
1038
|
type: "input",
|
|
1064
1039
|
name: "username",
|
|
1065
|
-
message: "Admin
|
|
1066
|
-
default: "admin
|
|
1067
|
-
validate: (S) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(S) || "Please enter a valid email address"
|
|
1040
|
+
message: "Admin username:",
|
|
1041
|
+
default: "admin"
|
|
1068
1042
|
},
|
|
1069
1043
|
{
|
|
1070
1044
|
type: "password",
|
|
1071
1045
|
name: "password",
|
|
1072
1046
|
message: "Admin password:",
|
|
1073
1047
|
mask: "*",
|
|
1074
|
-
|
|
1048
|
+
default: "admin"
|
|
1075
1049
|
}
|
|
1076
1050
|
]), e.skipMigrate || (console.log(`
|
|
1077
1051
|
๐ Running migrations...
|
|
1078
|
-
`), await
|
|
1052
|
+
`), await S(`${i} run migrate`, t)), e.skipSeed || (console.log(`
|
|
1079
1053
|
๐ฑ Seeding database...
|
|
1080
|
-
`),
|
|
1054
|
+
`), a === "local" ? await N(
|
|
1081
1055
|
`${i} run seed`,
|
|
1082
1056
|
t,
|
|
1083
1057
|
{
|
|
1084
|
-
|
|
1058
|
+
ADMIN_USERNAME: h.username,
|
|
1085
1059
|
ADMIN_PASSWORD: h.password
|
|
1086
1060
|
}
|
|
1087
|
-
) : await
|
|
1061
|
+
) : await N(
|
|
1088
1062
|
`${i} run seed:local`,
|
|
1089
1063
|
t,
|
|
1090
1064
|
{
|
|
1091
|
-
|
|
1065
|
+
ADMIN_USERNAME: h.username,
|
|
1092
1066
|
ADMIN_PASSWORD: h.password
|
|
1093
1067
|
}
|
|
1094
1068
|
));
|
|
@@ -1102,23 +1076,23 @@ E.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
1102
1076
|
message: "Would you like to start the development server?",
|
|
1103
1077
|
default: !0
|
|
1104
1078
|
}
|
|
1105
|
-
])).shouldStart, m && (
|
|
1106
|
-
`), await
|
|
1079
|
+
])).shouldStart, m && (a === "cloudflare" ? D(c) : a === "aws-sst" ? x(c) : T(c), console.log(`๐ Starting development server...
|
|
1080
|
+
`), await S(`${i} run dev`, t)), r && !m && (console.log(`
|
|
1107
1081
|
โ
Setup complete!`), console.log(`
|
|
1108
|
-
To start the development server:`), console.log(` cd ${n}`), console.log(" npm run dev"),
|
|
1082
|
+
To start the development server:`), console.log(` cd ${n}`), console.log(" npm run dev"), a === "cloudflare" ? D(c) : a === "aws-sst" ? x(c) : T(c));
|
|
1109
1083
|
} catch (d) {
|
|
1110
1084
|
console.error(`
|
|
1111
1085
|
โ An error occurred:`, d), process.exit(1);
|
|
1112
1086
|
}
|
|
1113
1087
|
}
|
|
1114
|
-
v || (console.log("Next steps:"), console.log(` cd ${n}`),
|
|
1115
|
-
"
|
|
1116
|
-
), console.log(" npm run dev")) :
|
|
1088
|
+
v || (console.log("Next steps:"), console.log(` cd ${n}`), a === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(
|
|
1089
|
+
" npm run seed # defaults to admin/admin"
|
|
1090
|
+
), console.log(" npm run dev")) : a === "cloudflare" ? (console.log(" npm install"), console.log(
|
|
1117
1091
|
" npm run migrate # or npm run db:migrate:remote for production"
|
|
1118
1092
|
), console.log(
|
|
1119
|
-
"
|
|
1120
|
-
), console.log(" npm run dev # or npm run dev:remote for production")) :
|
|
1121
|
-
" TABLE_NAME=<your-table>
|
|
1093
|
+
" npm run seed # defaults to admin/admin"
|
|
1094
|
+
), console.log(" npm run dev # or npm run dev:remote for production")) : a === "aws-sst" && (console.log(" npm install"), console.log(" npm run dev # Deploys to AWS in development mode"), console.log(" # After deploy, get TABLE_NAME from output, then:"), console.log(
|
|
1095
|
+
" TABLE_NAME=<your-table> npm run seed # defaults to admin/admin"
|
|
1122
1096
|
)), console.log(`
|
|
1123
1097
|
Server will be available at: https://localhost:3000`), console.log("Portal available at: https://local.authhero.net"), g && (console.log(`
|
|
1124
1098
|
๐งช OpenID Conformance Suite Testing:`), console.log(
|
|
@@ -1131,4 +1105,4 @@ Server will be available at: https://localhost:3000`), console.log("Portal avail
|
|
|
1131
1105
|
For more information, visit: https://authhero.net/docs
|
|
1132
1106
|
`));
|
|
1133
1107
|
});
|
|
1134
|
-
|
|
1108
|
+
I.parse(process.argv);
|