create-authhero 0.17.0 → 0.18.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/dist/cloudflare-multitenant/README.md +25 -0
- package/dist/cloudflare-multitenant/copy-assets.js +66 -0
- package/dist/cloudflare-multitenant/wrangler.toml +11 -0
- package/dist/cloudflare-simple/README.md +22 -0
- package/dist/cloudflare-simple/copy-assets.js +66 -0
- package/dist/cloudflare-simple/wrangler.toml +11 -0
- package/dist/create-authhero.js +58 -56
- package/dist/local/src/app.ts +10 -1
- package/package.json +1 -1
|
@@ -4,6 +4,7 @@ A production-grade multi-tenant AuthHero authentication server using Cloudflare
|
|
|
4
4
|
|
|
5
5
|
- Multi-tenant support with tenant isolation at the data level
|
|
6
6
|
- Multiple tenants in a single D1 database
|
|
7
|
+
- Static assets (widget, CSS, JS) served via Cloudflare Workers Assets
|
|
7
8
|
- Easy setup similar to single-tenant
|
|
8
9
|
|
|
9
10
|
## Architecture
|
|
@@ -18,6 +19,11 @@ A production-grade multi-tenant AuthHero authentication server using Cloudflare
|
|
|
18
19
|
│ │ - Tenant isolation via API │ │
|
|
19
20
|
│ └─────────────────────────────────┘ │
|
|
20
21
|
│ │ │
|
|
22
|
+
│ ┌───────────┴────────────────────┐ │
|
|
23
|
+
│ │ Static Assets │ │
|
|
24
|
+
│ │ /u/widget/* /u/css/* /u/js/* │ │
|
|
25
|
+
│ └────────────────────────────────┘ │
|
|
26
|
+
│ │ │
|
|
21
27
|
└──────────────┼──────────────────────────┘
|
|
22
28
|
│
|
|
23
29
|
▼
|
|
@@ -28,6 +34,25 @@ A production-grade multi-tenant AuthHero authentication server using Cloudflare
|
|
|
28
34
|
└─────────────┘
|
|
29
35
|
```
|
|
30
36
|
|
|
37
|
+
## Static Assets
|
|
38
|
+
|
|
39
|
+
The authentication widget, CSS, and client-side JavaScript are served as static assets via Cloudflare Workers Assets.
|
|
40
|
+
|
|
41
|
+
### How It Works
|
|
42
|
+
|
|
43
|
+
1. **Source**: Assets are bundled with the `authhero` package in `node_modules/authhero/dist/assets`
|
|
44
|
+
2. **Build Step**: The `copy-assets.js` script copies these files to `./dist/assets` before dev/deploy
|
|
45
|
+
3. **Serving**: Wrangler serves files from `./dist/assets` (configured in `wrangler.toml`)
|
|
46
|
+
4. **Automatic**: The copy happens automatically when you run `npm run dev` or `npm run deploy`
|
|
47
|
+
|
|
48
|
+
> **Note**: Wrangler's Assets feature does not support serving files directly from `node_modules`, which is why the copy step is necessary.
|
|
49
|
+
|
|
50
|
+
Assets are served at:
|
|
51
|
+
|
|
52
|
+
- `/u/widget/*` - AuthHero login widget (Stencil web component)
|
|
53
|
+
- `/u/css/*` - Tailwind CSS for universal login pages
|
|
54
|
+
- `/u/js/*` - Client-side JavaScript bundle
|
|
55
|
+
|
|
31
56
|
## Security & Privacy
|
|
32
57
|
|
|
33
58
|
This project is designed to be **open-source friendly**. Sensitive Cloudflare IDs are kept out of version control:
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Copy AuthHero assets to dist directory
|
|
5
|
+
*
|
|
6
|
+
* This script copies static assets from the authhero package to the dist directory
|
|
7
|
+
* so they can be served by Wrangler's Assets feature. Wrangler does not support
|
|
8
|
+
* serving files directly from node_modules.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import fs from "fs";
|
|
12
|
+
import path from "path";
|
|
13
|
+
import { fileURLToPath } from "url";
|
|
14
|
+
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = path.dirname(__filename);
|
|
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
|
+
*/
|
|
30
|
+
function copyDirectory(src, dest) {
|
|
31
|
+
// Create destination directory if it doesn't exist
|
|
32
|
+
if (!fs.existsSync(dest)) {
|
|
33
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Read source directory
|
|
37
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
38
|
+
|
|
39
|
+
for (const entry of entries) {
|
|
40
|
+
const srcPath = path.join(src, entry.name);
|
|
41
|
+
const destPath = path.join(dest, entry.name);
|
|
42
|
+
|
|
43
|
+
if (entry.isDirectory()) {
|
|
44
|
+
copyDirectory(srcPath, destPath);
|
|
45
|
+
} else {
|
|
46
|
+
fs.copyFileSync(srcPath, destPath);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
console.log("📦 Copying AuthHero assets...");
|
|
53
|
+
|
|
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
|
+
copyDirectory(sourceDir, targetDir);
|
|
61
|
+
|
|
62
|
+
console.log(`✅ Assets copied to ${targetDir}`);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error("❌ Error copying assets:", error.message);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
@@ -15,6 +15,17 @@ name = "authhero-multitenant"
|
|
|
15
15
|
main = "src/index.ts"
|
|
16
16
|
compatibility_date = "2024-11-20"
|
|
17
17
|
|
|
18
|
+
# ════════════════════════════════════════════════════════════════════════════
|
|
19
|
+
# Static Assets (CSS, JS, Widget)
|
|
20
|
+
# ════════════════════════════════════════════════════════════════════════════
|
|
21
|
+
# Serve static assets from the authhero package.
|
|
22
|
+
# This includes the widget, CSS, and client-side JavaScript.
|
|
23
|
+
# Assets are copied from node_modules/authhero/dist/assets to dist/assets
|
|
24
|
+
# during the build process (see copy-assets.js).
|
|
25
|
+
# Assets are served at their path: /u/widget/*, /u/css/*, /u/js/*
|
|
26
|
+
[assets]
|
|
27
|
+
directory = "./dist/assets"
|
|
28
|
+
|
|
18
29
|
# ════════════════════════════════════════════════════════════════════════════
|
|
19
30
|
# D1 Database binding
|
|
20
31
|
# ════════════════════════════════════════════════════════════════════════════
|
|
@@ -130,12 +130,34 @@ The server will be available at `https://localhost:3000`.
|
|
|
130
130
|
│ ├── app.ts # AuthHero app configuration
|
|
131
131
|
│ ├── seed.ts # Database seeding worker
|
|
132
132
|
│ └── types.ts # TypeScript type definitions
|
|
133
|
+
├── dist/
|
|
134
|
+
│ └── assets/ # Copied static assets (CSS, JS, Widget)
|
|
135
|
+
├── copy-assets.js # Build script to copy assets from authhero package
|
|
133
136
|
├── drizzle.config.ts # Drizzle configuration (reference only)
|
|
134
137
|
├── seed-helper.js # Helper script for automated seeding
|
|
135
138
|
├── wrangler.toml # Cloudflare Worker configuration
|
|
136
139
|
└── package.json
|
|
137
140
|
```
|
|
138
141
|
|
|
142
|
+
## Static Assets
|
|
143
|
+
|
|
144
|
+
The authentication widget, CSS, and client-side JavaScript are served as static assets via Cloudflare Workers Assets.
|
|
145
|
+
|
|
146
|
+
### How It Works
|
|
147
|
+
|
|
148
|
+
1. **Source**: Assets are bundled with the `authhero` package in `node_modules/authhero/dist/assets`
|
|
149
|
+
2. **Build Step**: The `copy-assets.js` script copies these files to `./dist/assets` before dev/deploy
|
|
150
|
+
3. **Serving**: Wrangler serves files from `./dist/assets` (configured in `wrangler.toml`)
|
|
151
|
+
4. **Automatic**: The copy happens automatically when you run `npm run dev` or `npm run deploy`
|
|
152
|
+
|
|
153
|
+
> **Note**: Wrangler's Assets feature does not support serving files directly from `node_modules`, which is why the copy step is necessary.
|
|
154
|
+
|
|
155
|
+
Assets are served at:
|
|
156
|
+
|
|
157
|
+
- `/u/widget/*` - AuthHero login widget (Stencil web component)
|
|
158
|
+
- `/u/css/*` - Tailwind CSS for universal login pages
|
|
159
|
+
- `/u/js/*` - Client-side JavaScript bundle
|
|
160
|
+
|
|
139
161
|
## Database Migrations
|
|
140
162
|
|
|
141
163
|
Database migrations are pre-generated and shipped with the `@authhero/drizzle` package. The schema is managed by AuthHero to ensure compatibility with future updates.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Copy AuthHero assets to dist directory
|
|
5
|
+
*
|
|
6
|
+
* This script copies static assets from the authhero package to the dist directory
|
|
7
|
+
* so they can be served by Wrangler's Assets feature. Wrangler does not support
|
|
8
|
+
* serving files directly from node_modules.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import fs from "fs";
|
|
12
|
+
import path from "path";
|
|
13
|
+
import { fileURLToPath } from "url";
|
|
14
|
+
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = path.dirname(__filename);
|
|
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
|
+
*/
|
|
30
|
+
function copyDirectory(src, dest) {
|
|
31
|
+
// Create destination directory if it doesn't exist
|
|
32
|
+
if (!fs.existsSync(dest)) {
|
|
33
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Read source directory
|
|
37
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
38
|
+
|
|
39
|
+
for (const entry of entries) {
|
|
40
|
+
const srcPath = path.join(src, entry.name);
|
|
41
|
+
const destPath = path.join(dest, entry.name);
|
|
42
|
+
|
|
43
|
+
if (entry.isDirectory()) {
|
|
44
|
+
copyDirectory(srcPath, destPath);
|
|
45
|
+
} else {
|
|
46
|
+
fs.copyFileSync(srcPath, destPath);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
console.log("📦 Copying AuthHero assets...");
|
|
53
|
+
|
|
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
|
+
copyDirectory(sourceDir, targetDir);
|
|
61
|
+
|
|
62
|
+
console.log(`✅ Assets copied to ${targetDir}`);
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error("❌ Error copying assets:", error.message);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
@@ -15,6 +15,17 @@ name = "authhero-server"
|
|
|
15
15
|
main = "src/index.ts"
|
|
16
16
|
compatibility_date = "2024-11-20"
|
|
17
17
|
|
|
18
|
+
# ════════════════════════════════════════════════════════════════════════════
|
|
19
|
+
# Static Assets (CSS, JS, Widget)
|
|
20
|
+
# ════════════════════════════════════════════════════════════════════════════
|
|
21
|
+
# Serve static assets from the authhero package.
|
|
22
|
+
# This includes the widget, CSS, and client-side JavaScript.
|
|
23
|
+
# Assets are copied from node_modules/authhero/dist/assets to dist/assets
|
|
24
|
+
# during the build process (see copy-assets.js).
|
|
25
|
+
# Assets are served at their path: /u/widget/*, /u/css/*, /u/js/*
|
|
26
|
+
[assets]
|
|
27
|
+
directory = "./dist/assets"
|
|
28
|
+
|
|
18
29
|
# ════════════════════════════════════════════════════════════════════════════
|
|
19
30
|
# D1 Database binding
|
|
20
31
|
# ════════════════════════════════════════════════════════════════════════════
|
package/dist/create-authhero.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Command as
|
|
2
|
+
import { Command as A } from "commander";
|
|
3
3
|
import m from "inquirer";
|
|
4
|
-
import
|
|
4
|
+
import s from "fs";
|
|
5
5
|
import i from "path";
|
|
6
6
|
import { spawn as b } from "child_process";
|
|
7
|
-
const D = new
|
|
7
|
+
const D = new A(), c = {
|
|
8
8
|
local: {
|
|
9
9
|
name: "Local (SQLite)",
|
|
10
10
|
description: "Local development setup with SQLite database - great for getting started",
|
|
11
11
|
templateDir: "local",
|
|
12
|
-
packageJson: (
|
|
13
|
-
name:
|
|
12
|
+
packageJson: (o) => ({
|
|
13
|
+
name: o,
|
|
14
14
|
version: "1.0.0",
|
|
15
15
|
type: "module",
|
|
16
16
|
scripts: {
|
|
@@ -42,14 +42,15 @@ const D = new j(), c = {
|
|
|
42
42
|
name: "Cloudflare Simple (Single Tenant)",
|
|
43
43
|
description: "Single-tenant Cloudflare Workers setup with D1 database",
|
|
44
44
|
templateDir: "cloudflare-simple",
|
|
45
|
-
packageJson: (
|
|
46
|
-
name:
|
|
45
|
+
packageJson: (o) => ({
|
|
46
|
+
name: o,
|
|
47
47
|
version: "1.0.0",
|
|
48
48
|
type: "module",
|
|
49
49
|
scripts: {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
"copy-assets": "node copy-assets.js",
|
|
51
|
+
dev: "npm run copy-assets && wrangler dev --port 3000 --local-protocol https",
|
|
52
|
+
"dev:remote": "npm run copy-assets && wrangler dev --port 3000 --local-protocol https --remote --config wrangler.local.toml",
|
|
53
|
+
deploy: "npm run copy-assets && wrangler deploy --config wrangler.local.toml",
|
|
53
54
|
"db:migrate:local": "wrangler d1 migrations apply AUTH_DB --local",
|
|
54
55
|
"db:migrate:remote": "wrangler d1 migrations apply AUTH_DB --remote --config wrangler.local.toml",
|
|
55
56
|
migrate: "wrangler d1 migrations apply AUTH_DB --local",
|
|
@@ -82,14 +83,15 @@ const D = new j(), c = {
|
|
|
82
83
|
name: "Cloudflare Multi-Tenant (Production)",
|
|
83
84
|
description: "Production-grade multi-tenant setup with D1 database and tenant management",
|
|
84
85
|
templateDir: "cloudflare-multitenant",
|
|
85
|
-
packageJson: (
|
|
86
|
-
name:
|
|
86
|
+
packageJson: (o) => ({
|
|
87
|
+
name: o,
|
|
87
88
|
version: "1.0.0",
|
|
88
89
|
type: "module",
|
|
89
90
|
scripts: {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
"copy-assets": "node copy-assets.js",
|
|
92
|
+
dev: "npm run copy-assets && wrangler dev --port 3000 --local-protocol https",
|
|
93
|
+
"dev:remote": "npm run copy-assets && wrangler dev --port 3000 --local-protocol https --remote --config wrangler.local.toml",
|
|
94
|
+
deploy: "npm run copy-assets && wrangler deploy --config wrangler.local.toml",
|
|
93
95
|
"db:migrate:local": "wrangler d1 migrations apply AUTH_DB --local",
|
|
94
96
|
"db:migrate:remote": "wrangler d1 migrations apply AUTH_DB --remote --config wrangler.local.toml",
|
|
95
97
|
migrate: "wrangler d1 migrations apply AUTH_DB --local",
|
|
@@ -119,10 +121,10 @@ const D = new j(), c = {
|
|
|
119
121
|
seedFile: "seed.ts"
|
|
120
122
|
}
|
|
121
123
|
};
|
|
122
|
-
function
|
|
123
|
-
|
|
124
|
-
const a = i.join(
|
|
125
|
-
|
|
124
|
+
function j(o, e) {
|
|
125
|
+
s.readdirSync(o).forEach((n) => {
|
|
126
|
+
const a = i.join(o, n), t = i.join(e, n);
|
|
127
|
+
s.lstatSync(a).isDirectory() ? (s.mkdirSync(t, { recursive: !0 }), j(a, t)) : s.copyFileSync(a, t);
|
|
126
128
|
});
|
|
127
129
|
}
|
|
128
130
|
function I() {
|
|
@@ -159,9 +161,9 @@ async function main() {
|
|
|
159
161
|
main().catch(console.error);
|
|
160
162
|
`;
|
|
161
163
|
}
|
|
162
|
-
function x(
|
|
163
|
-
const e = i.join(
|
|
164
|
-
|
|
164
|
+
function x(o) {
|
|
165
|
+
const e = i.join(o, ".github", "workflows");
|
|
166
|
+
s.mkdirSync(e, { recursive: !0 });
|
|
165
167
|
const r = `name: Unit tests
|
|
166
168
|
|
|
167
169
|
on: push
|
|
@@ -248,9 +250,9 @@ jobs:
|
|
|
248
250
|
apiToken: \${{ secrets.PROD_CLOUDFLARE_API_TOKEN }}
|
|
249
251
|
command: deploy --env production
|
|
250
252
|
`;
|
|
251
|
-
|
|
253
|
+
s.writeFileSync(i.join(e, "unit-tests.yml"), r), s.writeFileSync(i.join(e, "deploy-dev.yml"), n), s.writeFileSync(i.join(e, "release.yml"), a), console.log("\\n📦 GitHub CI workflows created!");
|
|
252
254
|
}
|
|
253
|
-
function C(
|
|
255
|
+
function C(o) {
|
|
254
256
|
const e = {
|
|
255
257
|
branches: ["main"],
|
|
256
258
|
plugins: [
|
|
@@ -259,11 +261,11 @@ function C(s) {
|
|
|
259
261
|
"@semantic-release/github"
|
|
260
262
|
]
|
|
261
263
|
};
|
|
262
|
-
|
|
263
|
-
i.join(
|
|
264
|
+
s.writeFileSync(
|
|
265
|
+
i.join(o, ".releaserc.json"),
|
|
264
266
|
JSON.stringify(e, null, 2)
|
|
265
267
|
);
|
|
266
|
-
const r = i.join(
|
|
268
|
+
const r = i.join(o, "package.json"), n = JSON.parse(s.readFileSync(r, "utf-8"));
|
|
267
269
|
n.devDependencies = {
|
|
268
270
|
...n.devDependencies,
|
|
269
271
|
"semantic-release": "^24.0.0"
|
|
@@ -271,11 +273,11 @@ function C(s) {
|
|
|
271
273
|
...n.scripts,
|
|
272
274
|
test: 'echo "No tests yet"',
|
|
273
275
|
"type-check": "tsc --noEmit"
|
|
274
|
-
},
|
|
276
|
+
}, s.writeFileSync(r, JSON.stringify(n, null, 2));
|
|
275
277
|
}
|
|
276
|
-
function v(
|
|
278
|
+
function v(o, e) {
|
|
277
279
|
return new Promise((r, n) => {
|
|
278
|
-
const a = b(
|
|
280
|
+
const a = b(o, [], {
|
|
279
281
|
cwd: e,
|
|
280
282
|
shell: !0,
|
|
281
283
|
stdio: "inherit"
|
|
@@ -285,9 +287,9 @@ function v(s, e) {
|
|
|
285
287
|
}), a.on("error", n);
|
|
286
288
|
});
|
|
287
289
|
}
|
|
288
|
-
function S(
|
|
290
|
+
function S(o, e, r) {
|
|
289
291
|
return new Promise((n, a) => {
|
|
290
|
-
const t = b(
|
|
292
|
+
const t = b(o, [], {
|
|
291
293
|
cwd: e,
|
|
292
294
|
shell: !0,
|
|
293
295
|
stdio: "inherit",
|
|
@@ -304,23 +306,23 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
304
306
|
).option("-e, --email <email>", "admin email address").option("-p, --password <password>", "admin password (min 8 characters)").option(
|
|
305
307
|
"--package-manager <pm>",
|
|
306
308
|
"package manager to use: npm, yarn, pnpm, or bun"
|
|
307
|
-
).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("-y, --yes", "skip all prompts and use defaults/provided options").action(async (
|
|
309
|
+
).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("-y, --yes", "skip all prompts and use defaults/provided options").action(async (o, e) => {
|
|
308
310
|
const r = e.yes === !0;
|
|
309
311
|
console.log(`
|
|
310
312
|
🔐 Welcome to AuthHero!
|
|
311
313
|
`);
|
|
312
|
-
let n =
|
|
314
|
+
let n = o;
|
|
313
315
|
n || (r ? (n = "auth-server", console.log(`Using default project name: ${n}`)) : n = (await m.prompt([
|
|
314
316
|
{
|
|
315
317
|
type: "input",
|
|
316
318
|
name: "projectName",
|
|
317
319
|
message: "Project name:",
|
|
318
320
|
default: "auth-server",
|
|
319
|
-
validate: (
|
|
321
|
+
validate: (p) => p !== "" || "Project name cannot be empty"
|
|
320
322
|
}
|
|
321
323
|
])).projectName);
|
|
322
324
|
const a = i.join(process.cwd(), n);
|
|
323
|
-
|
|
325
|
+
s.existsSync(a) && (console.error(`❌ Project "${n}" already exists.`), process.exit(1));
|
|
324
326
|
let t;
|
|
325
327
|
e.template ? (["local", "cloudflare-simple", "cloudflare-multitenant"].includes(
|
|
326
328
|
e.template
|
|
@@ -354,7 +356,7 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
354
356
|
}
|
|
355
357
|
])).setupType;
|
|
356
358
|
const f = c[t];
|
|
357
|
-
|
|
359
|
+
s.mkdirSync(a, { recursive: !0 }), s.writeFileSync(
|
|
358
360
|
i.join(a, "package.json"),
|
|
359
361
|
JSON.stringify(f.packageJson(n), null, 2)
|
|
360
362
|
);
|
|
@@ -362,25 +364,25 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
362
364
|
import.meta.url.replace("file://", "").replace("/create-authhero.js", ""),
|
|
363
365
|
f.templateDir
|
|
364
366
|
);
|
|
365
|
-
if (
|
|
366
|
-
const l = i.join(a, "wrangler.toml"),
|
|
367
|
-
|
|
368
|
-
const
|
|
369
|
-
|
|
367
|
+
if (s.existsSync(k) ? j(k, a) : (console.error(`❌ Template directory not found: ${k}`), process.exit(1)), t === "cloudflare-simple" || t === "cloudflare-multitenant") {
|
|
368
|
+
const l = i.join(a, "wrangler.toml"), p = i.join(a, "wrangler.local.toml");
|
|
369
|
+
s.existsSync(l) && s.copyFileSync(l, p);
|
|
370
|
+
const d = i.join(a, ".dev.vars.example"), u = i.join(a, ".dev.vars");
|
|
371
|
+
s.existsSync(d) && s.copyFileSync(d, u), console.log(
|
|
370
372
|
"📁 Created wrangler.local.toml and .dev.vars for local development"
|
|
371
373
|
);
|
|
372
374
|
}
|
|
373
|
-
let
|
|
374
|
-
if ((t === "cloudflare-simple" || t === "cloudflare-multitenant") && (e.githubCi !== void 0 ? (
|
|
375
|
+
let y = !1;
|
|
376
|
+
if ((t === "cloudflare-simple" || t === "cloudflare-multitenant") && (e.githubCi !== void 0 ? (y = e.githubCi, y && console.log("Including GitHub CI workflows with semantic versioning")) : r || (y = (await m.prompt([
|
|
375
377
|
{
|
|
376
378
|
type: "confirm",
|
|
377
379
|
name: "includeGithubCi",
|
|
378
380
|
message: "Would you like to include GitHub CI with semantic versioning?",
|
|
379
381
|
default: !1
|
|
380
382
|
}
|
|
381
|
-
])).includeGithubCi),
|
|
383
|
+
])).includeGithubCi), y && (x(a), C(a))), t === "local") {
|
|
382
384
|
const l = I();
|
|
383
|
-
|
|
385
|
+
s.writeFileSync(i.join(a, "src/seed.ts"), l);
|
|
384
386
|
}
|
|
385
387
|
console.log(
|
|
386
388
|
`
|
|
@@ -416,8 +418,8 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
416
418
|
📦 Installing dependencies with ${l}...
|
|
417
419
|
`);
|
|
418
420
|
try {
|
|
419
|
-
const
|
|
420
|
-
if (await v(
|
|
421
|
+
const p = l === "pnpm" ? "pnpm install --ignore-workspace" : `${l} install`;
|
|
422
|
+
if (await v(p, a), t === "local" && (console.log(`
|
|
421
423
|
🔧 Building native modules...
|
|
422
424
|
`), await v("npm rebuild better-sqlite3", a)), console.log(`
|
|
423
425
|
✅ Dependencies installed successfully!
|
|
@@ -441,14 +443,14 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
441
443
|
name: "username",
|
|
442
444
|
message: "Admin email:",
|
|
443
445
|
default: "admin@example.com",
|
|
444
|
-
validate: (
|
|
446
|
+
validate: (w) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(w) || "Please enter a valid email address"
|
|
445
447
|
},
|
|
446
448
|
{
|
|
447
449
|
type: "password",
|
|
448
450
|
name: "password",
|
|
449
451
|
message: "Admin password:",
|
|
450
452
|
mask: "*",
|
|
451
|
-
validate: (
|
|
453
|
+
validate: (w) => w.length < 8 ? "Password must be at least 8 characters" : !0
|
|
452
454
|
}
|
|
453
455
|
]), e.skipMigrate || (console.log(`
|
|
454
456
|
🔄 Running migrations...
|
|
@@ -471,27 +473,27 @@ D.version("1.0.0").description("Create a new AuthHero project").argument("[proje
|
|
|
471
473
|
));
|
|
472
474
|
}
|
|
473
475
|
}
|
|
474
|
-
let
|
|
475
|
-
e.skipStart || r ?
|
|
476
|
+
let d;
|
|
477
|
+
e.skipStart || r ? d = !1 : d = (await m.prompt([
|
|
476
478
|
{
|
|
477
479
|
type: "confirm",
|
|
478
480
|
name: "shouldStart",
|
|
479
481
|
message: "Would you like to start the development server?",
|
|
480
482
|
default: !0
|
|
481
483
|
}
|
|
482
|
-
])).shouldStart,
|
|
484
|
+
])).shouldStart, d && (console.log(
|
|
483
485
|
`
|
|
484
486
|
🚀 Starting development server on https://localhost:3000 ...
|
|
485
487
|
`
|
|
486
|
-
), await v(`${l} run dev`, a)), r && !
|
|
488
|
+
), await v(`${l} run dev`, a)), r && !d && (console.log(`
|
|
487
489
|
✅ Setup complete!`), console.log(`
|
|
488
490
|
To start the development server:`), console.log(` cd ${n}`), console.log(" npm run dev"), (t === "cloudflare-simple" || t === "cloudflare-multitenant") && console.log(
|
|
489
491
|
`
|
|
490
492
|
Server will be available at: https://localhost:3000`
|
|
491
493
|
));
|
|
492
|
-
} catch (
|
|
494
|
+
} catch (p) {
|
|
493
495
|
console.error(`
|
|
494
|
-
❌ An error occurred:`,
|
|
496
|
+
❌ An error occurred:`, p), process.exit(1);
|
|
495
497
|
}
|
|
496
498
|
}
|
|
497
499
|
h || (console.log("Next steps:"), console.log(` cd ${n}`), t === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(
|
package/dist/local/src/app.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Context } from "hono";
|
|
|
2
2
|
import { HTTPException } from "hono/http-exception";
|
|
3
3
|
import { AuthHeroConfig, init } from "authhero";
|
|
4
4
|
import { swaggerUI } from "@hono/swagger-ui";
|
|
5
|
+
import { serveStatic } from "@hono/node-server/serve-static";
|
|
5
6
|
|
|
6
7
|
export default function createApp(config: AuthHeroConfig) {
|
|
7
8
|
const { app } = init(config);
|
|
@@ -20,7 +21,15 @@ export default function createApp(config: AuthHeroConfig) {
|
|
|
20
21
|
status: "running",
|
|
21
22
|
});
|
|
22
23
|
})
|
|
23
|
-
.get("/docs", swaggerUI({ url: "/api/v2/spec" }))
|
|
24
|
+
.get("/docs", swaggerUI({ url: "/api/v2/spec" }))
|
|
25
|
+
// Serve static assets (widget, CSS, JS) from authhero package
|
|
26
|
+
.get(
|
|
27
|
+
"/u/*",
|
|
28
|
+
serveStatic({
|
|
29
|
+
root: "./node_modules/authhero/dist/assets/u",
|
|
30
|
+
rewriteRequestPath: (path) => path.replace("/u", ""),
|
|
31
|
+
}),
|
|
32
|
+
);
|
|
24
33
|
|
|
25
34
|
return app;
|
|
26
35
|
}
|