Repository: markusahlstrand/authhero
Pull request #54: add user-registration hooks
Author: login: markusahlstrand
Created: 2025-03-07T14:51:08Z | Merged: 2025-03-10T07:40:05Z



<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **New Features**
  - Added customizable hooks for user registration allowing custom logic to be executed both before and after a user registers.

- **Documentation**
  - Enhanced descriptions for database adapters, including a new package supporting custom domains.
  - Expanded the Authhero guide with comprehensive setup instructions, detailed usage of multiple API components, and configuration guidance for authentication.

- **Tests**
  - Introduced new tests to verify that the registration hooks function as expected.
  - Added tests for the functionality of both pre-user registration and post-user registration hooks.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/.changeset/chilly-foxes-complain.md b/.changeset/chilly-foxes-complain.md
new file mode 100644
index 000000000..df8b0ab0a
--- /dev/null
+++ b/.changeset/chilly-foxes-complain.md
@@ -0,0 +1,5 @@
+---
+"authhero": minor
+---
+
+Add pre user registration hook
diff --git a/.changeset/ninety-trees-cross.md b/.changeset/ninety-trees-cross.md
new file mode 100644
index 000000000..540817295
--- /dev/null
+++ b/.changeset/ninety-trees-cross.md
@@ -0,0 +1,5 @@
+---
+"authhero": minor
+---
+
+Add the post user registration hook
diff --git a/README.md b/README.md
index 98398a91e..2f24f2461 100644
--- a/README.md
+++ b/README.md
@@ -5,10 +5,10 @@ Monorepo for authhero containing the following packages:
 - authhero. The main package for authhero that handles authentication and API requests.
 - create-authhero, a CLI for creating authhero projects
 - adapters:
-
   - adapter-interfaces, a package containing interfaces for creating adapters for authhero
-  - kyssely
-  - drizzle
+  - kyssely, ORM for sql databases
+  - drizzle, ORM for sql databases (not in a working state)
+  - cloudflare, custom domains support
 
 It also contains the following apps:
 
diff --git a/packages/authhero/README.md b/packages/authhero/README.md
index 6f747341e..6edefef5a 100644
--- a/packages/authhero/README.md
+++ b/packages/authhero/README.md
@@ -1,9 +1,83 @@
 # Authhero
 
-An open-source auth library for building a drop-in replacement for Auth0.
+Authhero is an open-source authentication library designed as a drop-in replacement for Auth0. It provides a fully functional auth server that you can set up in minutes.
 
-Setup a new project with Authhero in 5 minutes or less:
+## Getting Started
+
+Set up a new project with Authhero in 5 minutes or less:
 
 ```bash
 npx create authhero
 ```
+
+Alternatively, you can install the npm packages into an existing project and integrate Authhero with your existing setup.
+
+## Installation
+
+Authhero consists of several npm packages that provide different authentication-related functionalities. The package includes four Hono routers, each handling a different aspect of the auth server:
+
+- **Management API (`management-api`)**: Exposes endpoints for managing authentication data, compatible with Auth0's `/api/v2`.
+- **Auth API (`auth-api`)**: Implements OAuth2/OIDC endpoints for user authentication.
+- **Universal Auth (`universal-auth`)**: Provides a server-side rendered UI for login.
+- **SAML App (`saml-app`)**: Handles SAML authentication endpoints.
+
+## Creating a New Auth Server
+
+To initialize an auth server using Authhero:
+
+```javascript
+const { managementApp, oauthApp, universalApp, samlApp } = init({
+  dataAdapter: params.dataAdapter,
+});
+
+rootApp
+  .route("/", oauthApp)
+  .route("/u", universalApp)
+  .route("/api/v2", managementApp)
+  .route("/", samlApp);
+```
+
+## Data Adapters
+
+Authhero uses data adapters to handle persistence. The default adapter is `@authhero/kysely`, which connects to any SQL database using Kysely. Future versions will migrate to Drizzle as the default data adapter. You can also create custom adapters, such as DynamoDB + Elasticsearch.
+
+## Hooks
+
+Authhero supports hooks to customize authentication logic. For example, you can grant roles dynamically using the `onExecuteCredentialsExchange` hook:
+
+```javascript
+hooks: {
+  onExecuteCredentialsExchange: async (
+    event: OnExecuteCredentialsExchangeEvent,
+    api: OnExecuteCredentialsExchangeAPI,
+  ) => {
+    if (event.client.id === "sampleClient") {
+      api.accessToken.setCustomClaim("roles", "admin");
+    }
+  }
+},
+```
+
+### Supported Hooks
+
+- `onExecuteCredentialsExchange`
+- `onExecutePreUserRegistration`
+- `onExecutePostUserRegistration`
+
+## Email Providers
+
+Authhero supports email providers for sending authentication-related emails. You can use pre-built email provider packages or configure a custom provider. Example:
+
+```javascript
+emailProviders: {
+  sqs: sendSqsEmail,
+},
+```
+
+## Contributing
+
+Contributions are welcome! Feel free to open issues and submit pull requests to improve Authhero.
+
+## License
+
+Authhero is open-source and available under the MIT License.
diff --git a/packages/authhero/src/hooks/index.ts b/packages/authhero/src/hooks/index.ts
index dd04a0243..61eb15d75 100644
--- a/packages/authhero/src/hooks/index.ts
+++ b/packages/authhero/src/hooks/index.ts
@@ -17,8 +17,51 @@ function createUserHooks(
   data: DataAdapters,
 ) {
   return async (tenant_id: string, user: User) => {
+    if (ctx.env.hooks?.onExecutePreUserRegistration) {
+      try {
+        await ctx.env.hooks.onExecutePreUserRegistration(
+          {
+            user,
+          },
+          {
+            user: {
+              setUserMetadata: async (key, value) => {
+                user[key] = value;
+              },
+            },
+          },
+        );
+      } catch (err) {
+        const log = createLogMessage(ctx, {
+          type: LogTypes.FAILED_SIGNUP,
+          description: "Pre user registration hook failed",
+        });
+        await ctx.env.data.logs.create(tenant_id, log);
+      }
+    }
+
     // Check for existing user with the same email and if so link the users
     let result = await linkUsersHook(data)(tenant_id, user);
+
+    if (ctx.env.hooks?.onExecutePostUserRegistration) {
+      try {
+        await ctx.env.hooks.onExecutePostUserRegistration(
+          {
+            user,
+          },
+          {
+            user: {},
+          },
+        );
+      } catch (err) {
+        const log = createLogMessage(ctx, {
+          type: LogTypes.FAILED_SIGNUP,
+          description: "Post user registration hook failed",
+        });
+        await ctx.env.data.logs.create(tenant_id, log);
+      }
+    }
+
     // Invoke post-user-registration webhooks
     await postUserRegistrationWebhook(ctx, data)(tenant_id, result);
 
diff --git a/packages/authhero/src/index.ts b/packages/authhero/src/index.ts
index 7d137eb37..b85d02cc1 100644
--- a/packages/authhero/src/index.ts
+++ b/packages/authhero/src/index.ts
@@ -1,12 +1,10 @@
 import { OpenAPIHono } from "@hono/zod-openapi";
 import { Context } from "hono";
 import i18next from "i18next";
-import { Bindings, Variables } from "./types";
+import { Bindings, Variables, AuthHeroConfig } from "./types";
 import createManagementApi from "./routes/management-api";
 import createOauthApi from "./routes/auth-api";
 import createUniversalLogin from "./routes/universal-login";
-import { AuthHeroConfig } from "./types/AuthHeroConfig";
-import { addDataHooks } from "./hooks";
 import { createX509Certificate } from "./utils/encryption";
 import { en, it, nb, sv, pl, cs, fi } from "./locales";
 
@@ -30,24 +28,19 @@ i18next.init({
 export function init(config: AuthHeroConfig) {
   const app = new OpenAPIHono<{ Bindings: Bindings; Variables: Variables }>();
 
-  app.use(async (ctx, next) => {
-    ctx.env.data = addDataHooks(ctx, config.dataAdapter);
-    return next();
-  });
-
   app.get("/", (ctx: Context) => {
     return ctx.json({
       name: "authhero",
     });
   });
 
-  const managementApp = createManagementApi();
+  const managementApp = createManagementApi(config);
   app.route("/api/v2", managementApp);
 
-  const oauthApp = createOauthApi();
+  const oauthApp = createOauthApi(config);
   app.route("/", oauthApp);
 
-  const universalApp = createUniversalLogin();
+  const universalApp = createUniversalLogin(config);
   app.route("/u", universalApp);
 
   return {
diff --git a/packages/authhero/src/routes/auth-api/index.ts b/packages/authhero/src/routes/auth-api/index.ts
index 20b2d32f9..11adb0ed0 100644
--- a/packages/authhero/src/routes/auth-api/index.ts
+++ b/packages/authhero/src/routes/auth-api/index.ts
@@ -1,7 +1,6 @@
 import { OpenAPIHono } from "@hono/zod-openapi";
-import { Bindings, Variables } from "../../types";
+import { AuthHeroConfig, Bindings, Variables } from "../../types";
 import { registerComponent } from "../../middlewares/register-component";
-import { DataAdapters } from "@authhero/adapter-interfaces";
 import { createAuthMiddleware } from "../../middlewares/authentication";
 
 import { callbackRoutes } from "./callback";
@@ -13,17 +12,19 @@ import { dbConnectionRoutes } from "./dbconnections";
 import { passwordlessRoutes } from "./passwordless";
 import { authenticateRoutes } from "./authenticate";
 import { authorizeRoutes } from "./authorize";
+import { addDataHooks } from "../../hooks";
 
-export interface CreateAuthParams {
-  dataAdapter: DataAdapters;
-}
-
-export default function create() {
+export default function create(config: AuthHeroConfig) {
   const app = new OpenAPIHono<{
     Bindings: Bindings;
     Variables: Variables;
   }>();
 
+  app.use(async (ctx, next) => {
+    ctx.env.data = addDataHooks(ctx, config.dataAdapter);
+    return next();
+  });
+
   app.use(createAuthMiddleware(app));
 
   const oauthApp = app
diff --git a/packages/authhero/src/routes/management-api/index.ts b/packages/authhero/src/routes/management-api/index.ts
index 6503293aa..89cdf41f1 100644
--- a/packages/authhero/src/routes/management-api/index.ts
+++ b/packages/authhero/src/routes/management-api/index.ts
@@ -1,5 +1,5 @@
 import { OpenAPIHono } from "@hono/zod-openapi";
-import { Bindings, Variables } from "../../types";
+import { Bindings, Variables, AuthHeroConfig } from "../../types";
 import { brandingRoutes } from "./branding";
 import { userRoutes } from "./users";
 import { keyRoutes } from "./keys";
@@ -11,18 +11,14 @@ import { hooksRoutes } from "./hooks";
 import { connectionRoutes } from "./connections";
 import { promptsRoutes } from "./prompts";
 import { registerComponent } from "../../middlewares/register-component";
-import { DataAdapters } from "@authhero/adapter-interfaces";
 import { createAuthMiddleware } from "../../middlewares/authentication";
 import { emailProviderRoutes } from "./emails";
 import { sessionsRoutes } from "./sessions";
 import { refreshTokensRoutes } from "./refresh_tokens";
 import { customDomainRoutes } from "./custom-domains";
+import { addDataHooks } from "../../hooks";
 
-export interface CreateAuthParams {
-  dataAdapter: DataAdapters;
-}
-
-export default function create() {
+export default function create(config: AuthHeroConfig) {
   const app = new OpenAPIHono<{
     Bindings: Bindings;
     Variables: Variables;
@@ -30,6 +26,11 @@ export default function create() {
 
   registerComponent(app);
 
+  app.use(async (ctx, next) => {
+    ctx.env.data = addDataHooks(ctx, config.dataAdapter);
+    return next();
+  });
+
   app.use(createAuthMiddleware(app));
 
   const managementApp = app
diff --git a/packages/authhero/src/routes/universal-login/index.ts b/packages/authhero/src/routes/universal-login/index.ts
index a66e61e8f..b7b9f194b 100644
--- a/packages/authhero/src/routes/universal-login/index.ts
+++ b/packages/authhero/src/routes/universal-login/index.ts
@@ -1,6 +1,5 @@
 import { OpenAPIHono } from "@hono/zod-openapi";
-import { Bindings, Variables } from "../../types";
-import { DataAdapters } from "@authhero/adapter-interfaces";
+import { AuthHeroConfig, Bindings, Variables } from "../../types";
 import { enterEmailRoutes } from "./enter-email";
 import { enterCodeRoutes } from "./enter-code";
 import { enterPasswordRoutes } from "./enter-password";
@@ -8,17 +7,19 @@ import { signupRoutes } from "./signup";
 import { resetPasswordRoutes } from "./reset-password";
 import { forgotPasswordRoutes } from "./forgot-password";
 import { checkAccountRoutes } from "./check-account";
+import { addDataHooks } from "../../hooks";
 
-export interface CreateAuthParams {
-  dataAdapter: DataAdapters;
-}
-
-export default function create() {
+export default function create(config: AuthHeroConfig) {
   const app = new OpenAPIHono<{
     Bindings: Bindings;
     Variables: Variables;
   }>();
 
+  app.use(async (ctx, next) => {
+    ctx.env.data = addDataHooks(ctx, config.dataAdapter);
+    return next();
+  });
+
   const universalApp = app
     .route("/check-account", checkAccountRoutes)
     .route("/enter-email", enterEmailRoutes)
diff --git a/packages/authhero/src/types/Bindings.ts b/packages/authhero/src/types/Bindings.ts
index f4f06d469..05952d720 100644
--- a/packages/authhero/src/types/Bindings.ts
+++ b/packages/authhero/src/types/Bindings.ts
@@ -1,5 +1,9 @@
 import { DataAdapters } from "@authhero/adapter-interfaces";
-import { OnExecuteCredentialsExchange } from "./Hooks";
+import {
+  OnExecuteCredentialsExchange,
+  OnExecutePostUserRegistration,
+  OnExecutePreUserRegistration,
+} from "./Hooks";
 import { EmailService } from "./EmailService";
 import { Strategy } from "../strategies";
 
@@ -20,6 +24,8 @@ export type Bindings = {
 
   hooks?: {
     onExecuteCredentialsExchange?: OnExecuteCredentialsExchange;
+    onExecutePreUserRegistration?: OnExecutePreUserRegistration;
+    onExecutePostUserRegistration?: OnExecutePostUserRegistration;
   };
   emailProviders?: { [key: string]: EmailService };
 
diff --git a/packages/authhero/src/types/Hooks.ts b/packages/authhero/src/types/Hooks.ts
index 62f770f1d..3fa231b4d 100644
--- a/packages/authhero/src/types/Hooks.ts
+++ b/packages/authhero/src/types/Hooks.ts
@@ -1,10 +1,10 @@
 import { Client, User } from "@authhero/adapter-interfaces";
 
-export type OnExecuteCredentialsExchangeEvent = {
-  client: Client;
+export type HookEvent = {
+  client?: Client;
   user?: User;
-  scope: string; // Space-separated list of scopes being requested
-  grant_type: string; // The grant type (e.g., "password", "refresh_token")
+  scope?: string; // Space-separated list of scopes being requested
+  grant_type?: string; // The grant type (e.g., "password", "refresh_token")
   audience?: string; // Optional audience being requested
 };
 
@@ -21,6 +21,26 @@ export type OnExecuteCredentialsExchangeAPI = {
 };
 
 export type OnExecuteCredentialsExchange = (
-  event: OnExecuteCredentialsExchangeEvent,
+  event: HookEvent,
   access: OnExecuteCredentialsExchangeAPI,
 ) => Promise<void>;
+
+export type OnExecutePreUserRegistrationAPI = {
+  user: {
+    setUserMetadata: (key: string, value: any) => void;
+  };
+};
+
+export type OnExecutePostUserRegistrationAPI = {
+  user: {};
+};
+
+export type OnExecutePreUserRegistration = (
+  event: HookEvent,
+  api: OnExecutePreUserRegistrationAPI,
+) => Promise<void>;
+
+export type OnExecutePostUserRegistration = (
+  event: HookEvent,
+  api: OnExecutePostUserRegistrationAPI,
+) => Promise<void>;
diff --git a/packages/authhero/src/types/index.ts b/packages/authhero/src/types/index.ts
index 0ccf8fd46..653c0583d 100644
--- a/packages/authhero/src/types/index.ts
+++ b/packages/authhero/src/types/index.ts
@@ -1,3 +1,4 @@
 export * from "./Variables";
 export * from "./Bindings";
 export * from "./auth0";
+export * from "./AuthHeroConfig";
diff --git a/packages/authhero/test/helpers/test-server.ts b/packages/authhero/test/helpers/test-server.ts
index b2ff66d2e..36fcbef0d 100644
--- a/packages/authhero/test/helpers/test-server.ts
+++ b/packages/authhero/test/helpers/test-server.ts
@@ -6,7 +6,12 @@ import createAdapters, {
   migrateToLatest,
 } from "@authhero/kysely-adapter";
 import * as x509 from "@peculiar/x509";
-import { init } from "../../src";
+import {
+  init,
+  OnExecuteCredentialsExchange,
+  OnExecutePostUserRegistration,
+  OnExecutePreUserRegistration,
+} from "../../src";
 import { getCertificate } from "./token";
 import { Bindings } from "../../src/types";
 import { MockEmailService } from "./mock-email-service";
@@ -16,6 +21,11 @@ type getEnvParams = {
   testTenantLanguage?: string;
   emailValidation?: "enabled" | "enforced" | "disabled";
   mockEmail?: boolean;
+  hooks?: {
+    onExecuteCredentialsExchange?: OnExecuteCredentialsExchange;
+    onExecutePreUserRegistration?: OnExecutePreUserRegistration;
+    onExecutePostUserRegistration?: OnExecutePostUserRegistration;
+  };
 };
 
 type TestServer = {
@@ -95,6 +105,7 @@ export async function getTestServer(
 
   const env: Bindings = {
     data,
+    hooks: args.hooks,
     emailProviders: {
       "mock-email": mockEmailService.sendEmail.bind(mockEmailService),
     },
diff --git a/packages/authhero/test/hooks/credentials-exchange.spec.ts b/packages/authhero/test/hooks/credentials-exchange.spec.ts
index 73ca596cd..841fa316a 100644
--- a/packages/authhero/test/hooks/credentials-exchange.spec.ts
+++ b/packages/authhero/test/hooks/credentials-exchange.spec.ts
@@ -3,8 +3,8 @@ import { testClient } from "hono/testing";
 import { getTestServer } from "../helpers/test-server";
 import { parseJWT } from "oslo/jwt";
 import {
+  HookEvent,
   OnExecuteCredentialsExchangeAPI,
-  OnExecuteCredentialsExchangeEvent,
 } from "../../src/types/Hooks";
 
 describe("client-credentials-hooks", () => {
@@ -14,10 +14,10 @@ describe("client-credentials-hooks", () => {
 
     env.hooks = {
       onExecuteCredentialsExchange: async (
-        event: OnExecuteCredentialsExchangeEvent,
+        event: HookEvent,
         api: OnExecuteCredentialsExchangeAPI,
       ) => {
-        if (event.client.id === "clientId") {
+        if (event.client?.id === "clientId") {
           api.accessToken.setCustomClaim("foo", "bar");
         }
       },
diff --git a/packages/authhero/test/hooks/on-post-user-registration.spec.ts b/packages/authhero/test/hooks/on-post-user-registration.spec.ts
new file mode 100644
index 000000000..a6fe05bc4
--- /dev/null
+++ b/packages/authhero/test/hooks/on-post-user-registration.spec.ts
@@ -0,0 +1,44 @@
+import { describe, it, expect } from "vitest";
+import { getTestServer } from "../helpers/test-server";
+import { HookEvent } from "../../src/types/Hooks";
+import { testClient } from "hono/testing";
+import { getAdminToken } from "../helpers/token";
+
+describe("on-post-user-registration-hook", () => {
+  it("should trigger an event", async () => {
+    const events: HookEvent[] = [];
+
+    const { env, managementApp } = await getTestServer({
+      hooks: {
+        onExecutePostUserRegistration: async (event: HookEvent) => {
+          events.push(event);
+        },
+      },
+    });
+
+    const client = testClient(managementApp, env);
+
+    const token = await getAdminToken();
+
+    // Create a user
+    const userResponse = await client.users.$post(
+      {
+        json: {
+          email: "foo2@example.com",
+        },
+        header: {
+          "tenant-id": "tenantId",
+        },
+      },
+      {
+        headers: {
+          authorization: `Bearer ${token}`,
+        },
+      },
+    );
+
+    expect(userResponse.status).toBe(201);
+
+    expect(events.length).toBe(1);
+  });
+});
diff --git a/packages/authhero/test/hooks/on-pre-user-registration.spec.ts b/packages/authhero/test/hooks/on-pre-user-registration.spec.ts
new file mode 100644
index 000000000..7bf487c25
--- /dev/null
+++ b/packages/authhero/test/hooks/on-pre-user-registration.spec.ts
@@ -0,0 +1,49 @@
+import { describe, it, expect } from "vitest";
+import { getTestServer } from "../helpers/test-server";
+import {
+  HookEvent,
+  OnExecutePreUserRegistrationAPI,
+} from "../../src/types/Hooks";
+import { testClient } from "hono/testing";
+import { getAdminToken } from "../helpers/token";
+
+describe("on-pre-user-registration-hook", () => {
+  it("should update user metadata", async () => {
+    const { env, managementApp } = await getTestServer({
+      hooks: {
+        onExecutePreUserRegistration: async (
+          _: HookEvent,
+          api: OnExecutePreUserRegistrationAPI,
+        ) => {
+          api.user.setUserMetadata("given_name", "given_name");
+        },
+      },
+    });
+
+    const client = testClient(managementApp, env);
+
+    const token = await getAdminToken();
+
+    // Create a user
+    const userResponse = await client.users.$post(
+      {
+        json: {
+          email: "foo2@example.com",
+        },
+        header: {
+          "tenant-id": "tenantId",
+        },
+      },
+      {
+        headers: {
+          authorization: `Bearer ${token}`,
+        },
+      },
+    );
+
+    expect(userResponse.status).toBe(201);
+    const user = await userResponse.json();
+
+    expect(user?.given_name).toBe("given_name");
+  });
+});


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## PR Overview

This pull request adds new user-registration hooks with corresponding tests while updating documentation and hook type definitions for enhanced flexibility in user creation. Key changes include:
- Adding tests for pre and post user registration hooks.
- Integrating hook execution into the user creation flow and updating error logging.
- Updating documentation and type definitions to support the new hooks.

### Reviewed Changes

| File | Description |
| ---- | ----------- |
| packages/authhero/test/hooks/on-post-user-registration.spec.ts | Added test ensuring the post user registration hook is triggered. |
| packages/authhero/test/hooks/on-pre-user-registration.spec.ts | Added test validating the pre user registration hook updates user metadata. |
| packages/authhero/README.md | Updated documentation to clarify features and installation instructions. |
| .changeset/ninety-trees-cross.md | Minor changeset for adding the post user registration hook. |
| .changeset/chilly-foxes-complain.md | Minor changeset for adding the pre user registration hook. |
| packages/authhero/src/routes/management-api/index.ts | Integrated the new hook functionality into the management API routing. |
| packages/authhero/src/hooks/index.ts | Updated the user creation pipeline to invoke pre and post registration hooks. |
| packages/authhero/src/types/Hooks.ts | Updated hook type definitions to support pre and post user registration hooks. |
| packages/authhero/src/routes/auth-api/index.ts | Enhanced API route configuration with hooks integration. |
| packages/authhero/src/types/Bindings.ts | Added new hook types to the bindings interface. |
| packages/authhero/src/routes/universal-login/index.ts | Updated route configuration to include hooks integration. |
| packages/authhero/test/helpers/test-server.ts | Integrated hooks into the test server initialization. |
| README.md | Updated high-level documentation for the monorepo and packages. |
| packages/authhero/test/hooks/credentials-exchange.spec.ts | Modified credentials exchange tests to account for updated hook properties. |
| packages/authhero/src/index.ts | Updated application initialization to pass new hook configurations. |

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.

<details>
<summary>Comments suppressed due to low confidence (1)</summary>

**packages/authhero/src/types/Hooks.ts:39**
* [nitpick] The API object for OnExecutePostUserRegistration is currently defined as an empty object. Consider defining a proper API interface or adding documentation to clarify its intended usage.
```
export type OnExecutePostUserRegistration = (
```
</details>


state: COMMENTED
author_association: NONE
submitted_at: 2025-03-07T14:52:45Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>🧹 Nitpick comments (7)</summary><blockquote>

<details>
<summary>.changeset/chilly-foxes-complain.md (1)</summary><blockquote>

`1-6`: **LGTM! Changeset properly documents the pre-registration hook addition.**

The changeset correctly specifies a minor version bump for the pre-registration hook feature.


**Note**: Consider whether these two closely related features (pre and post registration hooks) could be consolidated into a single changeset, as they're part of the same logical feature set and will likely be released together.

</blockquote></details>
<details>
<summary>packages/authhero/test/hooks/on-pre-user-registration.spec.ts (2)</summary><blockquote>

`10-49`: **Test for pre-registration hook looks good, but could be more comprehensive.**

The test effectively verifies that the pre-registration hook can modify user metadata, which is a key functionality.



Consider enhancing the test suite with:
1. Edge cases (e.g., what happens if the hook throws an exception?)
2. Multiple metadata fields being set simultaneously
3. Verification that other user properties remain unchanged
4. Different user scenarios (e.g., users with different properties)

This would make the test coverage more robust and provide greater confidence in the hook's functionality.

---

`28-42`: **Test covers the basic user creation flow.**

The test creates a user with minimal properties, which is good for focused testing.



Consider parameterizing this test to verify the hook works with different types of user data, such as users with existing metadata or different email formats.

</blockquote></details>
<details>
<summary>README.md (1)</summary><blockquote>

`9-11`: **Ensure consistent naming and clarify adapter states.**

"Kysely" is typically spelled with a single 's' in the official documentation (i.e., "Kysely"). Also, clarify whether 'drizzle' is truly non-functional or simply under experimental development. This extra context will help users gauge the stability of the adapters.

</blockquote></details>
<details>
<summary>packages/authhero/test/hooks/on-post-user-registration.spec.ts (1)</summary><blockquote>

`7-43`: **Expand coverage to validate event contents.**

Currently, the test only checks the presence of an event being triggered. For greater assurance, consider verifying the contents of the `event` object. For instance, confirm that the user details or timestamp fields are set as expected.

</blockquote></details>
<details>
<summary>packages/authhero/src/hooks/index.ts (1)</summary><blockquote>

`20-41`: **Validate error logging messages.**

In the `onExecutePreUserRegistration` block, any unhandled error logs “Pre user registration hook failed” correctly. However, ensure a meaningful message is also logged if multiple hooks are doing similar tasks, so debugging remains clear.

</blockquote></details>
<details>
<summary>packages/authhero/README.md (1)</summary><blockquote>

`77-80`: **Consider more specific contributing information**

The contributing section is quite brief. Consider adding more specific information about the contribution process, such as coding standards, pull request procedures, or linking to a CONTRIBUTING.md file.


```diff
## Contributing

-Contributions are welcome! Feel free to open issues and submit pull requests to improve Authhero.
+Contributions are welcome! Please open issues for bug reports or feature requests. When submitting pull requests, ensure tests pass and follow the existing code style. See our [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed guidelines.
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 LanguageTool</summary>

[style] ~79-~79: The phrase ‘feel free to’ is used quite frequently. Consider using a less frequent alternative to set your writing apart from others and make it sound more professional.
Context: ...ontributing  Contributions are welcome! Feel free to open issues and submit pull requests to...

(FEEL_FREE_TO_STYLE_ME)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between be9e7125ad9dcb3ed4fd4ddfe4ed56ccc7329e5e and 52896d7393b7cfd4ef9842ec1c8ae05c722449fd.

</details>

<details>
<summary>📒 Files selected for processing (16)</summary>

* `.changeset/chilly-foxes-complain.md` (1 hunks)
* `.changeset/ninety-trees-cross.md` (1 hunks)
* `README.md` (1 hunks)
* `packages/authhero/README.md` (1 hunks)
* `packages/authhero/src/hooks/index.ts` (1 hunks)
* `packages/authhero/src/index.ts` (2 hunks)
* `packages/authhero/src/routes/auth-api/index.ts` (2 hunks)
* `packages/authhero/src/routes/management-api/index.ts` (2 hunks)
* `packages/authhero/src/routes/universal-login/index.ts` (1 hunks)
* `packages/authhero/src/types/Bindings.ts` (2 hunks)
* `packages/authhero/src/types/Hooks.ts` (2 hunks)
* `packages/authhero/src/types/index.ts` (1 hunks)
* `packages/authhero/test/helpers/test-server.ts` (3 hunks)
* `packages/authhero/test/hooks/credentials-exchange.spec.ts` (2 hunks)
* `packages/authhero/test/hooks/on-post-user-registration.spec.ts` (1 hunks)
* `packages/authhero/test/hooks/on-pre-user-registration.spec.ts` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 LanguageTool</summary>

<details>
<summary>packages/authhero/README.md</summary>

[style] ~79-~79: The phrase ‘feel free to’ is used quite frequently. Consider using a less frequent alternative to set your writing apart from others and make it sound more professional.
Context: ...ontributing  Contributions are welcome! Feel free to open issues and submit pull requests to...

(FEEL_FREE_TO_STYLE_ME)

</details>

</details>
<details>
<summary>🪛 Biome (1.9.4)</summary>

<details>
<summary>packages/authhero/src/types/Hooks.ts</summary>

[error] 41-41: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (22)</summary><blockquote>

<details>
<summary>.changeset/ninety-trees-cross.md (1)</summary>

`1-6`: **LGTM! Changeset clearly indicates a minor version bump for the post-registration hook.**

The changeset correctly specifies a minor version bump for the "authhero" package and includes a clear description of the new feature being added.

</details>
<details>
<summary>packages/authhero/src/types/index.ts (1)</summary>

`4-4`: **Export added for AuthHeroConfig types.**

The export statement follows the existing pattern in the file and makes the AuthHeroConfig types accessible to consumers of the package.

</details>
<details>
<summary>packages/authhero/test/hooks/on-pre-user-registration.spec.ts (1)</summary>

`14-20`: **Consider testing hook execution order.**

The hook implementation sets metadata, but there's no verification that this happens at the right point in the registration flow.


You might want to add a test that confirms the hook executes before user creation by checking if metadata from the hook is available immediately after registration completes.

</details>
<details>
<summary>packages/authhero/test/hooks/credentials-exchange.spec.ts (2)</summary>

`6-6`: **Consistent event type naming is a good step.**

Changing the event type to `HookEvent` ensures uniform naming across hooks, simplifying code maintenance.

---

`17-20`: **Use of optional chaining is prudent.**

The optional chaining `event.client?.id` avoids potential runtime errors if `client` is undefined. This is a robust approach for handling potentially absent properties.

</details>
<details>
<summary>packages/authhero/src/routes/management-api/index.ts (4)</summary>

`2-2`: **Good addition of AuthHeroConfig import**

This import is necessary for the updated function signature and shows good attention to type safety.

---

`19-19`: **Good import of addDataHooks helper**

Importing the addDataHooks function from the hooks module follows good separation of concerns.

---

`21-21`: **Function signature properly updated**

The function now accepts a configuration parameter, which is a good practice for allowing customization.

---

`29-32`: **Well-implemented middleware for data hooks**

The middleware correctly uses the addDataHooks function to enhance the data adapter with hooks before proceeding to the next middleware. This pattern ensures hooks are available throughout the request lifecycle.

</details>
<details>
<summary>packages/authhero/src/types/Bindings.ts (2)</summary>

`2-6`: **Well-structured imports for hook types**

The import statement is properly updated to include both new hooks in a clean, organized way.

---

`27-28`: **Good addition of pre/post user registration hooks**

The new hooks are correctly added as optional properties to the hooks object, maintaining consistency with the existing pattern and allowing for flexible implementation.

</details>
<details>
<summary>packages/authhero/test/helpers/test-server.ts (3)</summary>

`9-14`: **Comprehensive imports for testing**

The imports now include all necessary hook types and the init function, providing everything needed for test setup.

---

`24-28`: **Well-defined hook types for test parameters**

The getEnvParams type is properly extended to include the hooks object with all three hook types, ensuring type safety in tests.

---

`108-108`: **Clean hooks integration in test environment**

The env object now includes the hooks from args, allowing tests to properly simulate hook behavior.

</details>
<details>
<summary>packages/authhero/src/routes/auth-api/index.ts (4)</summary>

`2-2`: **Good import of required types**

The import is properly updated to include AuthHeroConfig alongside the existing types.

---

`15-15`: **Good import of addDataHooks helper**

Properly imports the addDataHooks function for middleware integration.

---

`17-17`: **Function signature properly updated**

The function now accepts a configuration parameter, consistent with the changes in the management API.

---

`23-26`: **Well-implemented middleware for data hooks**

The middleware correctly integrates the data hooks into the context, following the same pattern as in the management API for consistency.

</details>
<details>
<summary>packages/authhero/src/routes/universal-login/index.ts (1)</summary>

`2-2`: **Function signature change and middleware addition look good**

The update to accept an `AuthHeroConfig` parameter and the new middleware for data hooks align well with the PR's objective of adding user-registration hooks. The middleware properly sets up the data hooks context before processing requests.




Also applies to: 10-10, 12-12, 18-21

</details>
<details>
<summary>packages/authhero/README.md (1)</summary>

`61-66`: **Documentation update for new hooks is excellent**

The README has been updated to include documentation for the new hooks, which improves the developer experience. The section clearly lists the supported hooks including the newly added `onExecutePreUserRegistration` and `onExecutePostUserRegistration`.

</details>
<details>
<summary>packages/authhero/src/index.ts (1)</summary>

`37-37`: **API initialization updated correctly**

The changes to pass the configuration object to each API initialization function are consistent with the updated function signatures in their respective modules. This ensures the hooks configuration is available throughout the application.




Also applies to: 40-40, 43-43

</details>
<details>
<summary>packages/authhero/src/types/Hooks.ts (1)</summary>

`3-9`: **Good refactoring of event type**

Refactoring the specific event type to a more generic `HookEvent` is a good design choice that promotes code reuse across different hooks. Making the client, scope, and grant_type properties optional provides flexibility for different hook scenarios.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T14:55:26Z

Review comments:
diff_hunk: @@ -17,8 +17,51 @@ function createUserHooks(
   data: DataAdapters,
 ) {
   return async (tenant_id: string, user: User) => {
+    if (ctx.env.hooks?.onExecutePreUserRegistration) {
+      try {
+        await ctx.env.hooks.onExecutePreUserRegistration(
+          {
+            user,
+          },
+          {
+            user: {
+              setUserMetadata: async (key, value) => {
+                user[key] = value;
+              },
+            },
+          },
+        );
+      } catch (err) {
+        const log = createLogMessage(ctx, {
+          type: LogTypes.FAILED_SIGNUP,
+          description: "Pre user registration hook failed",
+        });
+        await ctx.env.data.logs.create(tenant_id, log);
+      }
+    }
+
     // Check for existing user with the same email and if so link the users
     let result = await linkUsersHook(data)(tenant_id, user);
+
+    if (ctx.env.hooks?.onExecutePostUserRegistration) {
+      try {
+        await ctx.env.hooks.onExecutePostUserRegistration(
+          {
+            user,
+          },
+          {
+            user: {},
+          },
+        );
+      } catch (err) {
+        const log = createLogMessage(ctx, {
+          type: LogTypes.FAILED_SIGNUP,
+          description: "Pre user registration hook failed",
path: packages/authhero/src/hooks/index.ts
user: login: Copilot
body: In the post user registration hook block, the error log description still references 'Pre user registration hook failed'. This should be updated to 'Post user registration hook failed' to accurately reflect the error context.
```suggestion
          description: "Post user registration hook failed",
```
created_at: 2025-03-07T14:52:45Z
author_association: NONE
diff_hunk: @@ -17,8 +17,51 @@ function createUserHooks(
   data: DataAdapters,
 ) {
   return async (tenant_id: string, user: User) => {
+    if (ctx.env.hooks?.onExecutePreUserRegistration) {
+      try {
+        await ctx.env.hooks.onExecutePreUserRegistration(
+          {
+            user,
+          },
+          {
+            user: {
+              setUserMetadata: async (key, value) => {
+                user[key] = value;
+              },
+            },
+          },
+        );
+      } catch (err) {
+        const log = createLogMessage(ctx, {
+          type: LogTypes.FAILED_SIGNUP,
+          description: "Pre user registration hook failed",
+        });
+        await ctx.env.data.logs.create(tenant_id, log);
+      }
+    }
+
     // Check for existing user with the same email and if so link the users
     let result = await linkUsersHook(data)(tenant_id, user);
+
+    if (ctx.env.hooks?.onExecutePostUserRegistration) {
+      try {
+        await ctx.env.hooks.onExecutePostUserRegistration(
+          {
+            user,
+          },
+          {
+            user: {},
+          },
+        );
+      } catch (err) {
+        const log = createLogMessage(ctx, {
+          type: LogTypes.FAILED_SIGNUP,
+          description: "Pre user registration hook failed",
+        });
+        await ctx.env.data.logs.create(tenant_id, log);
+      }
+    }
path: packages/authhero/src/hooks/index.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Correct the mismatched error message for the post-registration hook.**

The log message in the catch block (line 59) reads “Pre user registration hook failed” when it should reflect the post-registration context. Use a descriptive message to avoid confusion.


Apply this diff to fix the message:

```diff
-          description: "Pre user registration hook failed",
+          description: "Post user registration hook failed",
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
    if (ctx.env.hooks?.onExecutePostUserRegistration) {
      try {
        await ctx.env.hooks.onExecutePostUserRegistration(
          {
            user,
          },
          {
            user: {},
          },
        );
      } catch (err) {
        const log = createLogMessage(ctx, {
          type: LogTypes.FAILED_SIGNUP,
          description: "Post user registration hook failed",
        });
        await ctx.env.data.logs.create(tenant_id, log);
      }
    }
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-07T14:55:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -21,6 +21,22 @@ export type OnExecuteCredentialsExchangeAPI = {
 };
 
 export type OnExecuteCredentialsExchange = (
-  event: OnExecuteCredentialsExchangeEvent,
+  event: HookEvent,
   access: OnExecuteCredentialsExchangeAPI,
 ) => Promise<void>;
+
+export type OnExecutePreUserRegistrationAPI = {
+  user: {
+    setUserMetadata: (key: string, value: any) => void;
+  };
+};
+
+export type OnExecutePreUserRegistration = (
+  event: HookEvent,
+  api: OnExecutePreUserRegistrationAPI,
+) => Promise<void>;
+
+export type OnExecutePostUserRegistration = (
+  event: HookEvent,
+  api: {},
+) => Promise<void>;
path: packages/authhero/src/types/Hooks.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**API type definition needs improvement**

The new hooks types look good overall, but there's an issue with the empty object type.


Replace the empty object type with a proper interface, even if it's currently empty:

```diff
export type OnExecutePostUserRegistration = (
  event: HookEvent,
-  api: {},
+  api: OnExecutePostUserRegistrationAPI,
) => Promise<void>;

+export interface OnExecutePostUserRegistrationAPI {
+  // Reserved for future use
+}
```

This provides better type safety and makes it easier to extend the API in the future without breaking changes.


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
export type OnExecutePreUserRegistrationAPI = {
  user: {
    setUserMetadata: (key: string, value: any) => void;
  };
};

export type OnExecutePreUserRegistration = (
  event: HookEvent,
  api: OnExecutePreUserRegistrationAPI,
) => Promise<void>;

export type OnExecutePostUserRegistration = (
  event: HookEvent,
  api: OnExecutePostUserRegistrationAPI,
) => Promise<void>;

export interface OnExecutePostUserRegistrationAPI {
  // Reserved for future use
}
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 41-41: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-03-07T14:55:26Z
author_association: CONTRIBUTOR

PR comments:
user: login: vercel[bot]
created_at: 2025-03-07T14:51:12Z
body: [vc]: #lAyMx/6Uk12MFGGNeCkAJul0In9Anuxwlqhwv0vUyCM=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJhdXRoaGVyby1yZWFjdC1hZG1pbiIsImluc3BlY3RvclVybCI6Imh0dHBzOi8vdmVyY2VsLmNvbS9tYXJrdXMtYWhsc3RyYW5kcy1wcm9qZWN0cy9hdXRoaGVyby1yZWFjdC1hZG1pbi9KV1NKdW1Ib2R4c2hocG1jY1lORzRWM1FURldZIiwicHJldmlld1VybCI6IiIsIm5leHRDb21taXRTdGF0dXMiOiJGQUlMRUQiLCJsaXZlRmVlZGJhY2siOnsicmVzb2x2ZWQiOjAsInVucmVzb2x2ZWQiOjAsInRvdGFsIjowLCJsaW5rIjoiIn0sInJvb3REaXJlY3RvcnkiOiJhcHBzL3JlYWN0LWFkbWluIn1dfQ==
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **authhero-react-admin** | ❌ Failed ([Inspect](https://vercel.com/markus-ahlstrands-projects/authhero-react-admin/JWSJumHodxshhpmccYNG4V3QTFWY)) |  |  | Mar 8, 2025 11:40am |


author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-03-07T14:51:18Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough
This pull request introduces minor updates to the Authhero package. It adds two new hooks—one to run before user registration and another to run after registration—to allow custom logic execution. Updates include changes to documentation, API initialization, middleware integration, and type definitions. In addition, the test suite now incorporates tests for both pre and post user registration hooks. These updates enhance the configuration flexibility and extend the hook functionality in the Authhero authentication workflow without altering the public API declarations.

## Changes

| File(s) | Changes Summary |
|---------|-----------------|
| `.changeset/chilly-foxes-complain.md`<br>`.changeset/ninety-trees-cross.md` | Added minor `"authhero": minor` entries indicating new pre and post user registration hooks. |
| `README.md` | Updated adapter descriptions for `kyssely` and `drizzle`; added a new entry for `cloudflare` regarding custom domain support. |
| `packages/authhero/README.md` | Expanded documentation with detailed instructions on setup, installation, API components, hooks usage, data adapters, email providers, contribution guidelines, and licensing information. |
| `packages/authhero/src/{hooks,index,routes/**}` | Introduced new asynchronous hooks (`onExecutePreUserRegistration` and `onExecutePostUserRegistration`) with error logging; updated API initialization to pass configuration and integrated middleware for applying data hooks. |
| `packages/authhero/src/types/{Bindings,Hooks,index}` | Updated type definitions by renaming and extending hook types, adding new hook types for pre and post registration, and exporting additional configuration types. |
| `packages/authhero/test/{helpers,test/hooks}` | Updated test server to include hooks in environment parameters; added new tests for pre and post user registration hooks; modified existing tests to use updated hook types with optional chaining. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
  participant U as User
  participant R as Registration Service
  participant Pre as Pre-Registration Hook
  participant Data as Data Hooks Middleware
  participant Post as Post-Registration Hook

  U->>R: Submit registration request
  R->>Pre: Call pre-registration hook
  Pre-->>R: Return with user metadata modifications
  R->>Data: Apply data hooks (via middleware)
  R->>R: Process user registration
  R->>Post: Call post-registration hook
  Post-->>R: Log hook execution result
  R->>U: Respond with success (201)
```

## Possibly related PRs
- **markusahlstrand/authhero#52:** Ensures hooks are correctly invoked for pre and post user registration, directly aligning with the new hook additions.
- **markusahlstrand/authhero#10:** Focuses on enhancements to user registration hooks, modifying initialization to integrate hooks similarly.
- **markusahlstrand/authhero#12:** Updates hook signatures, closely related to the new hook type definitions introduced in this PR.

## Poem
> In a field of code, I hop with cheer,  
> Pre and post hooks popping up far and near.  
> I nibble on bugs and test with delight,  
> Scanning the docs under the moonlit night.  
> With whiskers twitching at every commit,  
> My little rabbit heart just won’t quit!  
> 🐇 Hop on, code friends – let’s keep it lit!

<!-- walkthrough_end -->
<!-- This is an auto-generated comment: all tool run failures by coderabbit.ai -->

> [!WARNING]
> There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.
> 
> <details>
> <summary>🔧 ESLint</summary>
> 
> > If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
> 
> <details>
> <summary>packages/authhero/src/hooks/index.ts</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 9.5.0
> 
> file:///eslint.config.mjs?mtime=1741433993443:6
> import { configs, rules as reactRules } from "eslint-plugin-react";
>          ^^^^^^^
> SyntaxError: Named export 'configs' not found. The requested module 'eslint-plugin-react' is a CommonJS module, which may not support all module.exports as named exports.
> CommonJS modules can always be imported via the default export, for example using:
> 
> import pkg from 'eslint-plugin-react';
> const { configs, rules: reactRules } = pkg;
> 
>     at ModuleJob._instantiate (node:internal/modules/esm/module_job:171:21)
>     at async ModuleJob.run (node:internal/modules/esm/module_job:254:5)
>     at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:483:26)
>     at async loadFlatConfigFile (/node_modules/.pnpm/eslint@9.5.0/node_modules/eslint/lib/eslint/eslint.js:316:21)
>     at async calculateConfigArray (/node_modules/.pnpm/eslint@9.5.0/node_modules/eslint/lib/eslint/eslint.js:396:28)
>     at async ESLint.lintFiles (/node_modules/.pnpm/eslint@9.5.0/node_modules/eslint/lib/eslint/eslint.js:815:25)
>     at async Object.execute (/node_modules/.pnpm/eslint@9.5.0/node_modules/eslint/lib/cli.js:500:23)
>     at async main (/node_modules/.pnpm/eslint@9.5.0/node_modules/eslint/bin/eslint.js:153:22)
> 
> </details>
> 
> <details>
> <summary>packages/authhero/src/types/Hooks.ts</summary>
> 
> 
> Oops! Something went wrong! :(
> 
> ESLint: 9.5.0
> 
> file:///eslint.config.mjs?mtime=1741433993443:6
> import { configs, rules as reactRules } from "eslint-plugin-react";
>          ^^^^^^^
> SyntaxError: Named export 'configs' not found. The requested module 'eslint-plugin-react' is a CommonJS module, which may not support all module.exports as named exports.
> CommonJS modules can always be imported via the default export, for example using:
> 
> import pkg from 'eslint-plugin-react';
> const { configs, rules: reactRules } = pkg;
> 
>     at ModuleJob._instantiate (node:internal/modules/esm/module_job:171:21)
>     at async ModuleJob.run (node:internal/modules/esm/module_job:254:5)
>     at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:483:26)
>     at async loadFlatConfigFile (/node_modules/.pnpm/eslint@9.5.0/node_modules/eslint/lib/eslint/eslint.js:316:21)
>     at async calculateConfigArray (/node_modules/.pnpm/eslint@9.5.0/node_modules/eslint/lib/eslint/eslint.js:396:28)
>     at async ESLint.lintFiles (/node_modules/.pnpm/eslint@9.5.0/node_modules/eslint/lib/eslint/eslint.js:815:25)
>     at async Object.execute (/node_modules/.pnpm/eslint@9.5.0/node_modules/eslint/lib/cli.js:500:23)
>     at async main (/node_modules/.pnpm/eslint@9.5.0/node_modules/eslint/bin/eslint.js:153:22)
> 
> </details>
> 
> </details>

<!-- end of auto-generated comment: all tool run failures by coderabbit.ai -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 52896d7393b7cfd4ef9842ec1c8ae05c722449fd and 40f9eb1c5830252ee63547ea383ebee87a3b596a.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `packages/authhero/src/hooks/index.ts` (1 hunks)
* `packages/authhero/src/types/Hooks.ts` (2 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (1)</summary>

* packages/authhero/src/hooks/index.ts

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

<details>
<summary>packages/authhero/src/types/Hooks.ts</summary>

[error] 35-35: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

</details>

</details>

</details>

<details>
<summary>🔇 Additional comments (5)</summary><blockquote>

<details>
<summary>packages/authhero/src/types/Hooks.ts (5)</summary>

`3-9`: **Good choice in refactoring to a reusable `HookEvent` type.**

Renaming `OnExecuteCredentialsExchangeEvent` to `HookEvent` and making fields optional improves reusability across different hooks. This approach provides better flexibility and reduces code duplication.

---

`23-26`: **LGTM.**

The update to use the new `HookEvent` type in the `OnExecuteCredentialsExchange` function signature is consistent with the type refactoring.

---

`28-32`: **Good implementation of the pre-registration API.**

The `OnExecutePreUserRegistrationAPI` provides a clean interface for setting user metadata during the registration process.

---

`34-36`: **Don't use empty object type.**

The empty object type `{}` should be replaced with a proper interface, even if currently empty, for better type safety and future extensibility.


```diff
export type OnExecutePostUserRegistrationAPI = {
-  user: {};
+  user: Record<string, never>; // or a proper interface
};
```

Alternatively, create a proper interface:

```diff
export type OnExecutePostUserRegistrationAPI = {
-  user: {};
+  user: PostRegistrationUserAPI;
};

+export interface PostRegistrationUserAPI {
+  // Reserved for future use
+}
```

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 35-35: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

</details>

</details>

---

`38-46`: **Well-defined hook function signatures.**

The function signatures for both pre-registration and post-registration hooks follow a consistent pattern, making the API intuitive. They correctly use the HookEvent type and their respective API interfaces.

</details>

</blockquote></details>

</details>
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---



<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=markusahlstrand/authhero&utm_content=54):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR