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.
@@ -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
  # ════════════════════════════════════════════════════════════════════════════
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
- import { Command as j } from "commander";
2
+ import { Command as A } from "commander";
3
3
  import m from "inquirer";
4
- import o from "fs";
4
+ import s from "fs";
5
5
  import i from "path";
6
6
  import { spawn as b } from "child_process";
7
- const D = new j(), c = {
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: (s) => ({
13
- name: s,
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: (s) => ({
46
- name: s,
45
+ packageJson: (o) => ({
46
+ name: o,
47
47
  version: "1.0.0",
48
48
  type: "module",
49
49
  scripts: {
50
- dev: "wrangler dev --port 3000 --local-protocol https",
51
- "dev:remote": "wrangler dev --port 3000 --local-protocol https --remote --config wrangler.local.toml",
52
- deploy: "wrangler deploy --config wrangler.local.toml",
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: (s) => ({
86
- name: s,
86
+ packageJson: (o) => ({
87
+ name: o,
87
88
  version: "1.0.0",
88
89
  type: "module",
89
90
  scripts: {
90
- dev: "wrangler dev --port 3000 --local-protocol https",
91
- "dev:remote": "wrangler dev --port 3000 --local-protocol https --remote --config wrangler.local.toml",
92
- deploy: "wrangler deploy --config wrangler.local.toml",
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 A(s, e) {
123
- o.readdirSync(s).forEach((n) => {
124
- const a = i.join(s, n), t = i.join(e, n);
125
- o.lstatSync(a).isDirectory() ? (o.mkdirSync(t, { recursive: !0 }), A(a, t)) : o.copyFileSync(a, t);
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(s) {
163
- const e = i.join(s, ".github", "workflows");
164
- o.mkdirSync(e, { recursive: !0 });
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
- o.writeFileSync(i.join(e, "unit-tests.yml"), r), o.writeFileSync(i.join(e, "deploy-dev.yml"), n), o.writeFileSync(i.join(e, "release.yml"), a), console.log("\\n📦 GitHub CI workflows created!");
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(s) {
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
- o.writeFileSync(
263
- i.join(s, ".releaserc.json"),
264
+ s.writeFileSync(
265
+ i.join(o, ".releaserc.json"),
264
266
  JSON.stringify(e, null, 2)
265
267
  );
266
- const r = i.join(s, "package.json"), n = JSON.parse(o.readFileSync(r, "utf-8"));
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
- }, o.writeFileSync(r, JSON.stringify(n, null, 2));
276
+ }, s.writeFileSync(r, JSON.stringify(n, null, 2));
275
277
  }
276
- function v(s, e) {
278
+ function v(o, e) {
277
279
  return new Promise((r, n) => {
278
- const a = b(s, [], {
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(s, e, r) {
290
+ function S(o, e, r) {
289
291
  return new Promise((n, a) => {
290
- const t = b(s, [], {
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 (s, e) => {
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 = s;
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: (d) => d !== "" || "Project name cannot be empty"
321
+ validate: (p) => p !== "" || "Project name cannot be empty"
320
322
  }
321
323
  ])).projectName);
322
324
  const a = i.join(process.cwd(), n);
323
- o.existsSync(a) && (console.error(`❌ Project "${n}" already exists.`), process.exit(1));
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
- o.mkdirSync(a, { recursive: !0 }), o.writeFileSync(
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 (o.existsSync(k) ? A(k, a) : (console.error(`❌ Template directory not found: ${k}`), process.exit(1)), t === "cloudflare-simple" || t === "cloudflare-multitenant") {
366
- const l = i.join(a, "wrangler.toml"), d = i.join(a, "wrangler.local.toml");
367
- o.existsSync(l) && o.copyFileSync(l, d);
368
- const p = i.join(a, ".dev.vars.example"), u = i.join(a, ".dev.vars");
369
- o.existsSync(p) && o.copyFileSync(p, u), console.log(
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 w = !1;
374
- if ((t === "cloudflare-simple" || t === "cloudflare-multitenant") && (e.githubCi !== void 0 ? (w = e.githubCi, w && console.log("Including GitHub CI workflows with semantic versioning")) : r || (w = (await m.prompt([
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), w && (x(a), C(a))), t === "local") {
383
+ ])).includeGithubCi), y && (x(a), C(a))), t === "local") {
382
384
  const l = I();
383
- o.writeFileSync(i.join(a, "src/seed.ts"), l);
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 d = l === "pnpm" ? "pnpm install --ignore-workspace" : `${l} install`;
420
- if (await v(d, a), t === "local" && (console.log(`
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: (y) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(y) || "Please enter a valid email address"
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: (y) => y.length < 8 ? "Password must be at least 8 characters" : !0
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 p;
475
- e.skipStart || r ? p = !1 : p = (await m.prompt([
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, p && (console.log(
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 && !p && (console.log(`
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 (d) {
494
+ } catch (p) {
493
495
  console.error(`
494
- ❌ An error occurred:`, d), process.exit(1);
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(
@@ -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
  }
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "type": "git",
6
6
  "url": "https://github.com/markusahlstrand/authhero"
7
7
  },
8
- "version": "0.17.0",
8
+ "version": "0.18.0",
9
9
  "type": "module",
10
10
  "main": "dist/create-authhero.js",
11
11
  "bin": {