create-authhero 0.45.0 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
- import { D1Dialect } from "kysely-d1";
2
- import { Kysely } from "kysely";
3
- import createAdapters from "@authhero/kysely-adapter";
1
+ import { drizzle } from "drizzle-orm/d1";
2
+ import createAdapters from "@authhero/drizzle";
3
+ import * as schema from "@authhero/drizzle/schema/sqlite";
4
4
  import createApp from "./app";
5
5
  import { Env } from "./types";
6
6
  import {
@@ -22,8 +22,7 @@ export default {
22
22
  // Get the origin from the request for dynamic CORS
23
23
  const origin = request.headers.get("Origin") || "";
24
24
 
25
- const dialect = new D1Dialect({ database: env.AUTH_DB });
26
- const db = new Kysely<any>({ dialect });
25
+ const db = drizzle(env.AUTH_DB, { schema });
27
26
  let dataAdapter = createAdapters(db, { useTransactions: false });
28
27
 
29
28
  // Encrypt sensitive credential fields at rest when ENCRYPTION_KEY is set.
@@ -13,7 +13,7 @@
13
13
 
14
14
  name = "authhero-server"
15
15
  main = "src/index.ts"
16
- compatibility_date = "2024-11-20"
16
+ compatibility_date = "2026-05-01"
17
17
  compatibility_flags = ["nodejs_compat"]
18
18
 
19
19
  # ════════════════════════════════════════════════════════════════════════════
@@ -0,0 +1,94 @@
1
+ # AuthHero WFP Dispatcher
2
+
3
+ Thin Cloudflare Worker that fronts a Workers-for-Platforms deployment of AuthHero. Resolves an incoming request's `Host` header to a tenant via the shared platform D1 (`custom_domains` table) and dispatches the request to that tenant's full authhero auth server, deployed as a script in a Cloudflare dispatch namespace.
4
+
5
+ ## Architecture
6
+
7
+ ```
8
+ Internet
9
+ |
10
+ v
11
+ [This worker — the dispatcher]
12
+ 1. Host header -> custom_domains -> tenant_id
13
+ 2. env.DISPATCHER.get('tenant-<id>-auth').fetch(request)
14
+ |
15
+ v
16
+ [authhero-tenants dispatch namespace]
17
+ |- tenant-acme-auth (full authhero, deployed from the `cloudflare` template)
18
+ |- tenant-bob-auth
19
+ |- ...
20
+ ```
21
+
22
+ Tenant workers come from the **`cloudflare` create-authhero template** — they're the same single-tenant auth server, deployed into the namespace instead of standalone.
23
+
24
+ ## Prerequisites
25
+
26
+ - A Cloudflare account on the **Workers for Platforms** plan (required for dispatch namespaces).
27
+ - [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/install-and-update/).
28
+ - A D1 database (shared with the tenant workers).
29
+
30
+ ## One-time platform setup
31
+
32
+ ```bash
33
+ # 1. Create the dispatch namespace
34
+ npx wrangler dispatch-namespace create authhero-tenants
35
+
36
+ # 2. Create the shared D1 (or reuse the one your tenant workers use)
37
+ npx wrangler d1 create authhero-db
38
+
39
+ # 3. Copy wrangler.toml -> wrangler.local.toml and paste the database_id
40
+
41
+ # 4. Install project dependencies (provides the local wrangler used by the
42
+ # db:migrate:* scripts)
43
+ npm install
44
+
45
+ # 5. Apply migrations to the shared D1
46
+ npm run db:migrate:remote
47
+ # Or, without installing dependencies first:
48
+ # npx wrangler d1 migrations apply AUTH_DB --remote --config wrangler.local.toml
49
+ ```
50
+
51
+ ## Deploy the dispatcher
52
+
53
+ ```bash
54
+ npm run deploy
55
+ ```
56
+
57
+ ## Onboard a tenant
58
+
59
+ For each publisher:
60
+
61
+ 1. **Provision the tenant in D1** — insert a `tenants` row, then a `custom_domains` row mapping their domain to the tenant_id. (Either via the authhero management API or by direct D1 query.)
62
+
63
+ 2. **Deploy their auth worker into the namespace.** From the sibling `cloudflare` template:
64
+
65
+ ```bash
66
+ # In the tenant's directory (scaffolded from `create-authhero --template=cloudflare`)
67
+ npx wrangler deploy \
68
+ --dispatch-namespace=authhero-tenants \
69
+ --name=tenant-<tenant_id>-auth
70
+ ```
71
+
72
+ 3. **Point their custom domain at this dispatcher worker** (Cloudflare → Workers → Triggers → Add Custom Domain on this worker, or via DNS to the worker's `*.workers.dev` route).
73
+
74
+ Once those three steps are done, a request to `auth.<their-domain>/authorize?...` flows to this dispatcher → resolved via custom_domains → dispatched to their tenant worker.
75
+
76
+ ## Per-tenant routing customization
77
+
78
+ By default, hosts with no `proxy_routes` rows get a single catch-all that dispatches to `tenant-<tenant_id>-auth`. If a tenant needs richer routing — different middleware chains, CORS, a special path that bypasses the namespace — insert `proxy_routes` rows for that `custom_domain_id`. The dispatcher uses the configured routes verbatim instead of the default.
79
+
80
+ The script-name template (`tenant-{tenant_id}-auth`) can be overridden globally via the `SCRIPT_NAME_TEMPLATE` env var. Supported placeholders: `{tenant_id}`, `{custom_domain_id}`, `{domain}`, `{host}`.
81
+
82
+ ## Local development
83
+
84
+ ```bash
85
+ npm run dev
86
+ ```
87
+
88
+ `wrangler dev` runs against a **local SQLite-backed D1**. The dispatch namespace cannot be emulated locally — for end-to-end tests, deploy to a real Cloudflare account using `npm run dev:remote`.
89
+
90
+ ## Files
91
+
92
+ - `src/index.ts` — dispatcher worker entrypoint
93
+ - `src/types.ts` — Env interface (D1 binding + DISPATCHER namespace binding)
94
+ - `wrangler.toml` — Cloudflare config (assets, D1, dispatch namespace)
@@ -0,0 +1,72 @@
1
+ import { drizzle } from "drizzle-orm/d1";
2
+ import { createProxyDataAdapter } from "@authhero/drizzle";
3
+ import * as schema from "@authhero/drizzle/schema/sqlite";
4
+ import {
5
+ createProxyApp,
6
+ type ProxyDataAdapter,
7
+ type ResolvedHost,
8
+ } from "@authhero/proxy";
9
+ import type { Env } from "./types";
10
+
11
+ // `tenant-{tenant_id}-auth` is the deploy convention used by this template's
12
+ // per-tenant worker setup. Override with the SCRIPT_NAME_TEMPLATE env var or
13
+ // by configuring proxy_routes rows per tenant for richer routing.
14
+ const DEFAULT_SCRIPT_NAME_TEMPLATE = "tenant-{tenant_id}-auth";
15
+
16
+ // If a host resolves to a known tenant but has no proxy_routes configured,
17
+ // synthesize a single catch-all that dispatches to the tenant's auth worker
18
+ // in the namespace. Operators who need middleware (CORS, headers, rate
19
+ // limiting) per tenant can add real proxy_routes rows and this fallback
20
+ // stays out of the way.
21
+ function withDefaultDispatchRoute(
22
+ inner: ProxyDataAdapter,
23
+ binding: string,
24
+ scriptNameTemplate: string,
25
+ ): ProxyDataAdapter {
26
+ return {
27
+ proxyRoutes: inner.proxyRoutes,
28
+ resolveHost: async (host): Promise<ResolvedHost | null> => {
29
+ const resolved = await inner.resolveHost(host);
30
+ if (!resolved || resolved.routes.length > 0) return resolved;
31
+ const now = new Date(0).toISOString();
32
+ return {
33
+ ...resolved,
34
+ routes: [
35
+ {
36
+ id: `default-${resolved.custom_domain_id}`,
37
+ tenant_id: resolved.tenant_id,
38
+ custom_domain_id: resolved.custom_domain_id,
39
+ priority: 1000,
40
+ match: { path: "/*" },
41
+ handlers: [
42
+ {
43
+ type: "dispatch_namespace",
44
+ options: { binding, script_name: scriptNameTemplate },
45
+ },
46
+ ],
47
+ created_at: now,
48
+ updated_at: now,
49
+ },
50
+ ],
51
+ };
52
+ },
53
+ };
54
+ }
55
+
56
+ export default {
57
+ async fetch(request: Request, env: Env): Promise<Response> {
58
+ const db = drizzle(env.AUTH_DB, { schema });
59
+ const data = withDefaultDispatchRoute(
60
+ createProxyDataAdapter(db),
61
+ "DISPATCHER",
62
+ env.SCRIPT_NAME_TEMPLATE || DEFAULT_SCRIPT_NAME_TEMPLATE,
63
+ );
64
+
65
+ const app = createProxyApp({
66
+ data,
67
+ bindings: { DISPATCHER: env.DISPATCHER },
68
+ });
69
+
70
+ return app.fetch(request);
71
+ },
72
+ };
@@ -0,0 +1,17 @@
1
+ /// <reference types="@cloudflare/workers-types" />
2
+
3
+ export interface Env {
4
+ // The shared platform D1 database. Holds custom_domains (host -> tenant)
5
+ // and proxy_routes (optional per-host route overrides).
6
+ AUTH_DB: D1Database;
7
+
8
+ // The Cloudflare Workers for Platforms dispatch namespace where each
9
+ // tenant's auth worker is deployed. Wrangler binding configured in
10
+ // wrangler.toml as `[[dispatch_namespaces]] binding = "DISPATCHER"`.
11
+ DISPATCHER: DispatchNamespace;
12
+
13
+ // Optional template for resolving a tenant to a dispatch namespace
14
+ // script name. Defaults to `tenant-{tenant_id}-auth`. Supported
15
+ // placeholders: {tenant_id}, {custom_domain_id}, {domain}, {host}.
16
+ SCRIPT_NAME_TEMPLATE?: string;
17
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "types": ["@cloudflare/workers-types"]
11
+ },
12
+ "include": ["src/**/*"],
13
+ "exclude": ["node_modules"]
14
+ }
@@ -0,0 +1,56 @@
1
+ # ════════════════════════════════════════════════════════════════════════════
2
+ # AuthHero WFP Dispatcher Configuration
3
+ # ════════════════════════════════════════════════════════════════════════════
4
+ # Thin Cloudflare Worker that resolves a request's Host header to a tenant
5
+ # (via the shared platform D1) and dispatches to that tenant's full
6
+ # authhero auth server, deployed as a script in the `authhero-tenants`
7
+ # dispatch namespace.
8
+ #
9
+ # Tenant workers are deployed separately via the `cloudflare` template,
10
+ # using `wrangler deploy --dispatch-namespace=authhero-tenants
11
+ # --name=tenant-<id>-auth`.
12
+ #
13
+ # Sensitive IDs (database_id) go in wrangler.local.toml (gitignored) or
14
+ # GitHub Secrets, not this file.
15
+ # ════════════════════════════════════════════════════════════════════════════
16
+
17
+ name = "authhero-wfp-dispatcher"
18
+ main = "src/index.ts"
19
+ compatibility_date = "2026-05-01"
20
+ compatibility_flags = ["nodejs_compat"]
21
+
22
+ # ════════════════════════════════════════════════════════════════════════════
23
+ # Dispatch namespace binding
24
+ # ════════════════════════════════════════════════════════════════════════════
25
+ # Create the namespace once before the first deploy:
26
+ # npx wrangler dispatch-namespace create authhero-tenants
27
+ [[dispatch_namespaces]]
28
+ binding = "DISPATCHER"
29
+ namespace = "authhero-tenants"
30
+
31
+ # ════════════════════════════════════════════════════════════════════════════
32
+ # Shared platform D1 database
33
+ # ════════════════════════════════════════════════════════════════════════════
34
+ # Same D1 that the tenant workers read/write. Holds custom_domains and
35
+ # proxy_routes that drive the dispatcher's host -> tenant resolution.
36
+ [[d1_databases]]
37
+ binding = "AUTH_DB"
38
+ database_name = "authhero-db"
39
+ database_id = "local" # Use "local" for local dev, or your actual ID in wrangler.local.toml
40
+ migrations_dir = "node_modules/@authhero/drizzle/drizzle"
41
+
42
+ # ════════════════════════════════════════════════════════════════════════════
43
+ # OPTIONAL: Custom Domain
44
+ # ════════════════════════════════════════════════════════════════════════════
45
+ # Point your platform's wildcard or per-publisher custom domains at this
46
+ # worker. The publishers' subdomains must resolve here so the dispatcher
47
+ # can route into the namespace.
48
+ #
49
+ # [[routes]]
50
+ # pattern = "*.auth.yourplatform.com/*"
51
+ # zone_name = "yourplatform.com"
52
+
53
+ # Optional: Enable observability for `wrangler tail` insight into dispatch
54
+ # decisions and namespace invocation latency.
55
+ # [observability]
56
+ # enabled = true
@@ -81,22 +81,19 @@ var c = new e(), l = {
81
81
  },
82
82
  dependencies: {
83
83
  "@authhero/drizzle": a,
84
- "@authhero/kysely-adapter": a,
85
84
  ...i && { "@authhero/admin": a },
86
85
  "@authhero/widget": a,
87
86
  "@hono/swagger-ui": "^0.5.0",
88
87
  "@hono/zod-openapi": "^0.19.0",
89
88
  authhero: a,
89
+ "drizzle-orm": "^0.44.0",
90
90
  hono: "^4.6.0",
91
- kysely: "latest",
92
- "kysely-d1": "latest",
93
91
  ...t && { "@authhero/multi-tenancy": a },
94
92
  ...n && { bcryptjs: "latest" }
95
93
  },
96
94
  devDependencies: {
97
95
  "@cloudflare/workers-types": "^4.0.0",
98
96
  "drizzle-kit": "^0.31.0",
99
- "drizzle-orm": "^0.44.0",
100
97
  typescript: "^5.5.0",
101
98
  wrangler: "^3.0.0"
102
99
  }
@@ -104,6 +101,40 @@ var c = new e(), l = {
104
101
  },
105
102
  seedFile: "seed.ts"
106
103
  },
104
+ "cloudflare-wfp-dispatcher": {
105
+ name: "Cloudflare Workers for Platforms — Dispatcher",
106
+ description: "Thin dispatcher worker that routes per-publisher custom domains to tenant auth workers in a dispatch namespace (pair with the `cloudflare` template for tenant workers)",
107
+ templateDir: "cloudflare-wfp-dispatcher",
108
+ packageJson: (e, t, n, r) => {
109
+ let i = r ? "workspace:*" : "latest";
110
+ return {
111
+ name: e,
112
+ version: "1.0.0",
113
+ type: "module",
114
+ scripts: {
115
+ dev: "wrangler dev --port 3001 --local-protocol https",
116
+ "dev:remote": "wrangler dev --port 3001 --local-protocol https --remote --config wrangler.local.toml",
117
+ deploy: "wrangler deploy --config wrangler.local.toml",
118
+ "db:migrate:local": "wrangler d1 migrations apply AUTH_DB --local",
119
+ "db:migrate:remote": "wrangler d1 migrations apply AUTH_DB --remote --config wrangler.local.toml",
120
+ migrate: "wrangler d1 migrations apply AUTH_DB --local",
121
+ setup: "cp wrangler.toml wrangler.local.toml && echo '✅ Created wrangler.local.toml - update with your IDs'"
122
+ },
123
+ dependencies: {
124
+ "@authhero/drizzle": i,
125
+ "@authhero/proxy": i,
126
+ "drizzle-orm": "^0.44.0",
127
+ hono: "^4.6.0"
128
+ },
129
+ devDependencies: {
130
+ "@cloudflare/workers-types": "^4.0.0",
131
+ "drizzle-kit": "^0.31.0",
132
+ typescript: "^5.5.0",
133
+ wrangler: "^3.0.0"
134
+ }
135
+ };
136
+ }
137
+ },
107
138
  proxy: {
108
139
  name: "Proxy (Cloudflare Workers)",
109
140
  description: "Host-based reverse proxy on Cloudflare Workers — static config, no DB",
@@ -563,9 +594,9 @@ ${i}
563
594
  `;
564
595
  }
565
596
  function p(e) {
566
- return `import { D1Dialect } from "kysely-d1";
567
- import { Kysely } from "kysely";
568
- import createAdapters from "@authhero/kysely-adapter";
597
+ return `import { drizzle } from "drizzle-orm/d1";
598
+ import createAdapters from "@authhero/drizzle";
599
+ import * as schema from "@authhero/drizzle/schema/sqlite";
569
600
  import { seed, createEncryptedDataAdapter, loadEncryptionKey } from "authhero";
570
601
 
571
602
  interface Env {
@@ -582,8 +613,7 @@ export default {
582
613
  const issuer = \`\${url.protocol}//\${url.host}/\`;
583
614
 
584
615
  try {
585
- const dialect = new D1Dialect({ database: env.AUTH_DB });
586
- const db = new Kysely<any>({ dialect });
616
+ const db = drizzle(env.AUTH_DB, { schema });
587
617
  let adapters = createAdapters(db, { useTransactions: false });
588
618
 
589
619
  if (env.ENCRYPTION_KEY) {
@@ -813,9 +843,12 @@ function C() {
813
843
  console.log("\n" + "─".repeat(50)), console.log("🔐 AuthHero server running at https://localhost:3000"), console.log("🚀 Open https://localhost:3000/setup to complete initial setup"), console.log("─".repeat(50) + "\n");
814
844
  }
815
845
  function w() {
816
- console.log("\n" + "─".repeat(50)), console.log("🛰️ AuthHero proxy running at http://localhost:8787"), console.log("✏️ Edit src/proxy.config.ts to add hosts and routes"), console.log("📖 See README.md for deployment instructions"), console.log("─".repeat(50) + "\n");
846
+ console.log("\n" + "─".repeat(50)), console.log("🛰️ WFP dispatcher running at https://localhost:3001"), console.log("📦 Pair with the `cloudflare` template to deploy tenant workers:"), console.log(" wrangler deploy --dispatch-namespace=authhero-tenants --name=tenant-<id>-auth"), console.log("📖 See README.md for the full onboarding workflow"), console.log("─".repeat(50) + "\n");
817
847
  }
818
848
  function T() {
849
+ console.log("\n" + "─".repeat(50)), console.log("🛰️ AuthHero proxy running at http://localhost:8787"), console.log("✏️ Edit src/proxy.config.ts to add hosts and routes"), console.log("📖 See README.md for deployment instructions"), console.log("─".repeat(50) + "\n");
850
+ }
851
+ function E() {
819
852
  console.log("\n" + "─".repeat(50)), console.log("✅ Self-signed certificates generated with openssl"), console.log("⚠️ You may need to trust the certificate in your browser"), console.log("🔐 AuthHero server running at http://localhost:3000"), console.log("📚 API documentation available at http://localhost:3000/docs"), console.log("🚀 Open http://localhost:3000/setup to complete initial setup"), console.log("─".repeat(50) + "\n");
820
853
  }
821
854
  c.version("1.0.0").description("Create a new AuthHero project").argument("[project-name]", "name of the project").option("-t, --template <type>", "template type: local, cloudflare, aws-sst, or proxy").option("--package-manager <pm>", "package manager to use: npm, yarn, pnpm, or bun").option("--multi-tenant", "enable multi-tenant mode").option("--admin-ui", "include admin UI at /admin").option("--skip-install", "skip installing dependencies").option("--skip-migrate", "skip running database migrations").option("--skip-start", "skip starting the development server").option("--github-ci", "include GitHub CI workflows with semantic versioning").option("--conformance", "add OpenID conformance suite test clients").option("--conformance-alias <alias>", "alias for conformance suite (default: authhero-local)").option("--workspace", "use workspace:* dependencies for local monorepo development").option("-y, --yes", "skip all prompts and use defaults/provided options").action(async (e, i) => {
@@ -835,9 +868,10 @@ c.version("1.0.0").description("Create a new AuthHero project").argument("[proje
835
868
  i.template ? ([
836
869
  "local",
837
870
  "cloudflare",
871
+ "cloudflare-wfp-dispatcher",
838
872
  "aws-sst",
839
873
  "proxy"
840
- ].includes(i.template) || (console.error(`❌ Invalid template: ${i.template}`), console.error("Valid options: local, cloudflare, aws-sst, proxy"), process.exit(1)), m = i.template, console.log(`Using template: ${l[m].name}`)) : m = (await t.prompt([{
874
+ ].includes(i.template) || (console.error(`❌ Invalid template: ${i.template}`), console.error("Valid options: local, cloudflare, cloudflare-wfp-dispatcher, aws-sst, proxy"), process.exit(1)), m = i.template, console.log(`Using template: ${l[m].name}`)) : m = (await t.prompt([{
841
875
  type: "list",
842
876
  name: "setupType",
843
877
  message: "Select your setup type:",
@@ -852,6 +886,11 @@ c.version("1.0.0").description("Create a new AuthHero project").argument("[proje
852
886
  value: "cloudflare",
853
887
  short: l.cloudflare.name
854
888
  },
889
+ {
890
+ name: `${l["cloudflare-wfp-dispatcher"].name}\n ${l["cloudflare-wfp-dispatcher"].description}`,
891
+ value: "cloudflare-wfp-dispatcher",
892
+ short: l["cloudflare-wfp-dispatcher"].name
893
+ },
855
894
  {
856
895
  name: `${l["aws-sst"].name}\n ${l["aws-sst"].description}`,
857
896
  value: "aws-sst",
@@ -865,7 +904,7 @@ c.version("1.0.0").description("Create a new AuthHero project").argument("[proje
865
904
  ]
866
905
  }])).setupType;
867
906
  let h;
868
- h = m === "proxy" ? !1 : i.multiTenant === void 0 ? o ? !1 : (await t.prompt([{
907
+ h = m === "proxy" || m === "cloudflare-wfp-dispatcher" ? !1 : i.multiTenant === void 0 ? o ? !1 : (await t.prompt([{
869
908
  type: "confirm",
870
909
  name: "multiTenant",
871
910
  message: "Would you like to enable multi-tenant mode?",
@@ -878,27 +917,28 @@ c.version("1.0.0").description("Create a new AuthHero project").argument("[proje
878
917
  message: "Would you like to include the admin UI at /admin?",
879
918
  default: !0
880
919
  }])).adminUi : i.adminUi, g && console.log("Admin UI: enabled (available at /admin)"));
881
- let E = i.conformance || !1, D = i.conformanceAlias || "authhero-local";
882
- E && console.log(`OpenID Conformance Suite: enabled (alias: ${D})`);
883
- let O = i.workspace || !1;
884
- O && console.log("Workspace mode: enabled (using workspace:* dependencies)");
885
- let k = l[m];
886
- n.mkdirSync(p, { recursive: !0 }), n.writeFileSync(r.join(p, "package.json"), JSON.stringify(k.packageJson(c, h, E, O, g), null, 2));
887
- let A = k.templateDir, j = r.dirname(a(import.meta.url)), M = [r.join(j, A), r.join(j, "..", "templates", A)], N = M.find((e) => n.existsSync(e));
888
- if (N ? u(N, p) : (console.error(`❌ Template directory not found. Looked in:\n ${M.join("\n ")}`), process.exit(1)), m === "cloudflare" && S(p, h, g), m === "cloudflare") {
920
+ let D = i.conformance || !1, O = i.conformanceAlias || "authhero-local";
921
+ D && console.log(`OpenID Conformance Suite: enabled (alias: ${O})`);
922
+ let k = i.workspace || !1;
923
+ k && console.log("Workspace mode: enabled (using workspace:* dependencies)");
924
+ let A = l[m];
925
+ n.mkdirSync(p, { recursive: !0 }), n.writeFileSync(r.join(p, "package.json"), JSON.stringify(A.packageJson(c, h, D, k, g), null, 2));
926
+ let j = A.templateDir, M = r.dirname(a(import.meta.url)), N = [r.join(M, j), r.join(M, "..", "templates", j)], P = N.find((e) => n.existsSync(e));
927
+ if (P ? u(P, p) : (console.error(`❌ Template directory not found. Looked in:\n ${N.join("\n ")}`), process.exit(1)), m === "cloudflare" && S(p, h, g), m === "cloudflare" || m === "cloudflare-wfp-dispatcher") {
889
928
  let e = r.join(p, "wrangler.toml"), t = r.join(p, "wrangler.local.toml");
890
- n.existsSync(e) && n.copyFileSync(e, t);
891
- let i = r.join(p, ".dev.vars.example"), a = r.join(p, ".dev.vars");
892
- n.existsSync(i) && (n.copyFileSync(i, a), n.appendFileSync(a, `\n# Generated at-rest encryption key (local dev). Use a separate secret in production.\nENCRYPTION_KEY=${s()}\n`), console.log("🔒 Added a generated ENCRYPTION_KEY to .dev.vars")), console.log("📁 Created wrangler.local.toml and .dev.vars for local development");
929
+ if (n.existsSync(e) && !n.existsSync(t) && n.copyFileSync(e, t), m === "cloudflare") {
930
+ let e = r.join(p, ".dev.vars.example"), t = r.join(p, ".dev.vars");
931
+ n.existsSync(e) && (n.copyFileSync(e, t), n.appendFileSync(t, `\n# Generated at-rest encryption key (local dev). Use a separate secret in production.\nENCRYPTION_KEY=${s()}\n`), console.log("🔒 Added a generated ENCRYPTION_KEY to .dev.vars")), console.log("📁 Created wrangler.local.toml and .dev.vars for local development");
932
+ } else console.log("📁 Created wrangler.local.toml for local development");
893
933
  }
894
- let P = !1;
895
- if (m === "cloudflare" && (i.githubCi === void 0 ? o || (P = (await t.prompt([{
934
+ let F = !1;
935
+ if (m === "cloudflare" && (i.githubCi === void 0 ? o || (F = (await t.prompt([{
896
936
  type: "confirm",
897
937
  name: "includeGithubCi",
898
938
  message: "Would you like to include GitHub CI with semantic versioning?",
899
939
  default: !1
900
- }])).includeGithubCi) : (P = i.githubCi, P && console.log("Including GitHub CI workflows with semantic versioning")), P && (y(p), b(p))), m === "local") {
901
- let e = d(h, E, D, g);
940
+ }])).includeGithubCi) : (F = i.githubCi, F && console.log("Including GitHub CI workflows with semantic versioning")), F && (y(p), b(p))), m === "local") {
941
+ let e = d(h, D, O, g);
902
942
  n.writeFileSync(r.join(p, "src/seed.ts"), e);
903
943
  let t = f(h, g);
904
944
  n.writeFileSync(r.join(p, "src/app.ts"), t);
@@ -909,9 +949,9 @@ ENCRYPTION_KEY=${s()}
909
949
  `;
910
950
  n.writeFileSync(r.join(p, ".env"), i), console.log("🔒 Generated .env with an at-rest encryption key");
911
951
  }
912
- if (m === "aws-sst" && _(p, h), E) {
952
+ if (m === "aws-sst" && _(p, h), D) {
913
953
  let e = {
914
- alias: D,
954
+ alias: O,
915
955
  description: "AuthHero Conformance Test",
916
956
  server: { discoveryUrl: "http://host.docker.internal:3000/.well-known/openid-configuration" },
917
957
  client: {
@@ -926,15 +966,15 @@ ENCRYPTION_KEY=${s()}
926
966
  };
927
967
  n.writeFileSync(r.join(p, "conformance-config.json"), JSON.stringify(e, null, 2)), console.log("📝 Created conformance-config.json for OpenID Conformance Suite");
928
968
  }
929
- let F = h ? "multi-tenant" : "single-tenant";
930
- console.log(`\n✅ Project "${c}" has been created with ${k.name} (${F}) setup!\n`);
931
- let I;
932
- if (I = i.skipInstall ? !1 : o ? !0 : (await t.prompt([{
969
+ let I = h ? "multi-tenant" : "single-tenant";
970
+ console.log(`\n✅ Project "${c}" has been created with ${A.name} (${I}) setup!\n`);
971
+ let L;
972
+ if (L = i.skipInstall ? !1 : o ? !0 : (await t.prompt([{
933
973
  type: "confirm",
934
974
  name: "shouldInstall",
935
975
  message: "Would you like to install dependencies now?",
936
976
  default: !0
937
- }])).shouldInstall, I) {
977
+ }])).shouldInstall, L) {
938
978
  let e;
939
979
  i.packageManager ? ([
940
980
  "npm",
@@ -981,11 +1021,11 @@ ENCRYPTION_KEY=${s()}
981
1021
  name: "shouldStart",
982
1022
  message: "Would you like to start the development server?",
983
1023
  default: !0
984
- }])).shouldStart, n && (m === "cloudflare" ? C() : m === "aws-sst" ? v() : m === "proxy" ? w() : T(), console.log("🚀 Starting development server...\n"), await x(`${e} run dev`, p)), o && !n && (console.log("\n✅ Setup complete!"), console.log("\nTo start the development server:"), console.log(` cd ${c}`), console.log(" npm run dev"), m === "cloudflare" ? C() : m === "aws-sst" ? v() : m === "proxy" ? w() : T());
1024
+ }])).shouldStart, n && (m === "cloudflare" ? C() : m === "cloudflare-wfp-dispatcher" ? w() : m === "aws-sst" ? v() : m === "proxy" ? T() : E(), console.log("🚀 Starting development server...\n"), await x(`${e} run dev`, p)), o && !n && (console.log("\n✅ Setup complete!"), console.log("\nTo start the development server:"), console.log(` cd ${c}`), console.log(" npm run dev"), m === "cloudflare" ? C() : m === "cloudflare-wfp-dispatcher" ? w() : m === "aws-sst" ? v() : m === "proxy" ? T() : E());
985
1025
  } catch (e) {
986
1026
  console.error("\n❌ An error occurred:", e), process.exit(1);
987
1027
  }
988
1028
  }
989
- I || (console.log("Next steps:"), console.log(` cd ${c}`), m === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(" npm run dev"), console.log("\nOpen http://localhost:3000/setup to complete initial setup")) : m === "cloudflare" ? (console.log(" npm install"), console.log(" npm run migrate # or npm run db:migrate:remote for production"), console.log(" npm run dev # or npm run dev:remote for production"), console.log("\nOpen https://localhost:3000/setup to complete initial setup")) : m === "aws-sst" ? (console.log(" npm install"), console.log(" npm run dev # Deploys to AWS in development mode"), console.log("\nOpen your server URL /setup to complete initial setup")) : m === "proxy" && (console.log(" npm install"), console.log(" npm run dev"), console.log("\nEdit src/proxy.config.ts to add hosts and routes")), console.log(`\nServer will be available at: http://localhost:${m === "proxy" ? 8787 : 3e3}`), E && (console.log("\n🧪 OpenID Conformance Suite Testing:"), console.log(" 1. Clone and start the conformance suite (if not already running):"), console.log(" git clone https://gitlab.com/openid/conformance-suite.git"), console.log(" cd conformance-suite && mvn clean package"), console.log(" docker-compose up -d"), console.log(" 2. Open https://localhost.emobix.co.uk:8443"), console.log(" 3. Create a test plan and use conformance-config.json for settings"), console.log(` 4. Use alias: ${D}`)), console.log("\nFor more information, visit: https://authhero.net/docs\n"));
1029
+ L || (console.log("Next steps:"), console.log(` cd ${c}`), m === "local" ? (console.log(" npm install"), console.log(" npm run migrate"), console.log(" npm run dev"), console.log("\nOpen http://localhost:3000/setup to complete initial setup")) : m === "cloudflare" ? (console.log(" npm install"), console.log(" npm run migrate # or npm run db:migrate:remote for production"), console.log(" npm run dev # or npm run dev:remote for production"), console.log("\nOpen https://localhost:3000/setup to complete initial setup")) : m === "cloudflare-wfp-dispatcher" ? (console.log(" npm install"), console.log(" npm run setup # creates wrangler.local.toml — paste your database_id"), console.log(" npx wrangler dispatch-namespace create authhero-tenants"), console.log(" npm run dev # or npm run dev:remote for production"), console.log("\nDeploy tenant workers separately (`cloudflare` template):"), console.log(" wrangler deploy --dispatch-namespace=authhero-tenants --name=tenant-<id>-auth")) : m === "aws-sst" ? (console.log(" npm install"), console.log(" npm run dev # Deploys to AWS in development mode"), console.log("\nOpen your server URL /setup to complete initial setup")) : m === "proxy" && (console.log(" npm install"), console.log(" npm run dev"), console.log("\nEdit src/proxy.config.ts to add hosts and routes")), console.log(`\nServer will be available at: http://localhost:${m === "proxy" ? 8787 : m === "cloudflare-wfp-dispatcher" ? 3001 : 3e3}`), D && (console.log("\n🧪 OpenID Conformance Suite Testing:"), console.log(" 1. Clone and start the conformance suite (if not already running):"), console.log(" git clone https://gitlab.com/openid/conformance-suite.git"), console.log(" cd conformance-suite && mvn clean package"), console.log(" docker-compose up -d"), console.log(" 2. Open https://localhost.emobix.co.uk:8443"), console.log(" 3. Create a test plan and use conformance-config.json for settings"), console.log(` 4. Use alias: ${O}`)), console.log("\nFor more information, visit: https://authhero.net/docs\n"));
990
1030
  }), c.parse(process.argv);
991
1031
  //#endregion
@@ -1,8 +1,5 @@
1
1
  import { AsyncLocalStorage } from "node:async_hooks";
2
- import {
3
- createProxyApp,
4
- createStaticProxyAdapter,
5
- } from "@authhero/proxy";
2
+ import { createProxyApp, createStaticProxyAdapter } from "@authhero/proxy";
6
3
  import { proxyConfig } from "./proxy.config";
7
4
 
8
5
  // AsyncLocalStorage threads each request's ExecutionContext through to the
@@ -32,9 +29,8 @@ const app = createProxyApp({
32
29
 
33
30
  export default {
34
31
  fetch(request: Request, _env: unknown, ctx: ExecutionContext) {
35
- return requestCtx.run(
36
- { waitUntil: ctx.waitUntil.bind(ctx) },
37
- () => app.fetch(request),
32
+ return requestCtx.run({ waitUntil: ctx.waitUntil.bind(ctx) }, () =>
33
+ app.fetch(request),
38
34
  );
39
35
  },
40
36
  };
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.45.0",
8
+ "version": "0.46.0",
9
9
  "type": "module",
10
10
  "main": "dist/create-authhero.js",
11
11
  "bin": {