Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type "AppRouteHandlerFnContext" is not a valid type for the function's second argument. #12224

Open
KennyMwendwaX opened this issue Nov 12, 2024 · 15 comments
Labels
bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.

Comments

@KennyMwendwaX
Copy link

Environment

System:
    OS: Linux 6.8 Ubuntu 24.04.1 LTS 24.04.1 LTS (Noble Numbat)
    CPU: (4) x64 Intel(R) Core(TM) i5-4210U CPU @ 1.70GHz
    Memory: 3.74 GB / 7.63 GB
    Container: Yes
    Shell: 5.2.21 - /bin/bash
  Binaries:
    Node: 20.18.0 - /run/user/1000/fnm_multishells/92976_1731438033311/bin/node
    npm: 10.8.2 - /run/user/1000/fnm_multishells/92976_1731438033311/bin/npm
  Browsers:
    Brave Browser: 129.1.70.119
    Chrome: 129.0.6668.89
  npmPackages:
    @auth/drizzle-adapter: ^1.7.2 => 1.7.2 
    next: ^15.0.2 => 15.0.2 
    next-auth: ^5.0.0-beta.25 => 5.0.0-beta.25 
    react: ^18.3.1 => 18.3.1 

Reproduction URL

https://github.com/KennyMwendwaX/task-trace/

Describe the issue

invitation code api route handler:

import { auth } from "@/auth";
import db from "@/database/db";
import { NextResponse } from "next/server";
import { customAlphabet } from "nanoid";
import { invitationCodes, members, projects } from "@/database/schema";
import { add } from "date-fns/add";
import { and, eq } from "drizzle-orm/sql";

export const GET = auth(async (request) => {
  if (!req.auth || !req.auth.user || !req.auth.user.id) {
    return NextResponse.json({ message: "Unauthorized" }, { status: 401 });
  }
  try {
    const segments = req.nextUrl.pathname.split("/");
    const projectId = segments[segments.length - 2];

    if (!projectId)
      return NextResponse.json(
        { message: "No project Id found" },
        { status: 404 }
      );

    const project = await db.query.projects.findFirst({
      where: eq(projects.id, projectId),
    });

    if (!project)
      return NextResponse.json(
        { message: "Project not found" },
        { status: 400 }
      );

    const currentUserMember = await db.query.members.findFirst({
      where: and(
        eq(members.projectId, projectId),
        eq(members.userId, req.auth.user.id)
      ),
    });

    if (
      !currentUserMember ||
      !["OWNER", "ADMIN"].includes(currentUserMember.role)
    ) {
      return NextResponse.json(
        {
          message: "You don't have permission get the project invitation code",
        },
        { status: 403 }
      );
    }

    const invitationCode = await db.query.invitationCodes.findFirst({
      where: eq(invitationCodes.projectId, projectId),
    });

    if (!invitationCode) {
      return NextResponse.json(
        { message: "No invitation code found for this project" },
        { status: 404 }
      );
    }

    const currentDateTime = new Date();
    if (
      invitationCode.expiresAt &&
      invitationCode.expiresAt < currentDateTime
    ) {
      return NextResponse.json(
        { message: "Invitation code expired. Please regenerate." },
        { status: 410 }
      );
    }

    return NextResponse.json(
      { code: invitationCode.code, expiresAt: invitationCode.expiresAt },
      { status: 200 }
    );
  } catch (error) {
    console.log("Error getting invitation code:", error);
    return NextResponse.json(
      { message: "Failed to get invitation code" },
      { status: 500 }
    );
  }
});

This is the api route with the issue, it works perfectly in development when you build using the npm run build, the following error is produced on the terminal:

src/app/api/projects/[projectId]/invitation-code/route.ts
Type error: Route "src/app/api/projects/[projectId]/invitation-code/route.ts" has an invalid "GET" export:
  Type "AppRouteHandlerFnContext" is not a valid type for the function's second argument.
    Expected "Promise<any>", got "Record<string, string | string[]> | undefined".
      Expected "Promise<any>", got "undefined".

How to reproduce

  1. Clone the repo on github: https://github.com/KennyMwendwaX/task-trace/
  2. Install the dependencies
npm install
  1. Build the project
npm run build

Expected behavior

It actually works quite good in development but when I build the project it fails.

@KennyMwendwaX KennyMwendwaX added bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime. labels Nov 12, 2024
@barrynorman
Copy link

Same error here. Cannot build my project

@Ant59
Copy link

Ant59 commented Nov 14, 2024

I've just come across this error too. It seems to already be fixed on main via 6cbd6a5

@barrynorman
Copy link

Ok nice. So we need to wait for the next release. Thx

@Starefossen
Copy link

Just got hit by this as well! Any notes on the next release?

@hirurg-lybitel
Copy link

Sure, it's just a temporary fix, but it lets me move forward with building my app.

export const POST = auth(async (request) => {
  try {
    const {
      code
    } = await request.json();

    const decodedData = decrypt(code);

    const isValid = new Date(decodedData.expiresAt).getTime() > new Date().getTime() ;

    if (!isValid) {
      return Response.json({ isValid });  
    }
      
    return Response.json({ isValid, decodedData });        
  } catch (error: any) {
    return Response.json({ message: error.message}, { status: 500 });
  }
}) as any; <------ SOLUTION HERE

@barrynorman
Copy link

Why does this take so long to release?
People are depending on a working Auth Framework.

@leantrace
Copy link

What is the status on releasing this particular fix?

The fix has been made >6 weeks ago, but apparently not released yet
6cbd6a5

I cannot make a production build unless I temporarily add:

typescript: {
    // !! WARN !!
    // Dangerously allow production builds to successfully complete even if
    // your project has type errors.
    // !! WARN !!
    ignoreBuildErrors: true,
  }, 

to my next.config.mjs

===

  Type error: Route "src/app/api/users/[id]/route.ts" has an invalid "GET" export:
  Type "AppRouteHandlerFnContext" is not a valid type for the function's second argument.
    Expected "Promise<any>", got "Record<string, string | string[]> | undefined".
      Expected "Promise<any>", got "undefined".

@yordis
Copy link
Contributor

yordis commented Dec 16, 2024

The same problem, just copy and paste the example code:

import { auth } from '@/auth';
import { NextResponse } from 'next/server';

export const GET = auth((req) => {
  if (req.auth) {
    return NextResponse.json({ data: 'Protected data' });
  }
  return NextResponse.json({ message: 'Not authenticated' }, { status: 401 });
});

Hopefully a new version is released soon 😭

@larodiel
Copy link

I'm on next 15.0.3 and "next-auth": "^5.0.0-beta.25" and I've switched from auth wrapper to auth function inside the request and it started to working

export async function GET(request: NextRequest) {
  const authSession = await auth();
  if (!authSession) {
      return NextResponse.json(
        {
          message: 'Unauthorized',
          medias: [],
        },
        { status: 401 },
      );
    }
  }

This is my Front End request:

//import { cookies } from 'next/headers';
//const cookiesSession = await cookies();
 const response = await axios.get(`/api/media?page=${page}&limit=${limit}`, {
    headers: {
      'Content-Type': 'application/json',
      //Cookie: cookiesSession.toString(), //the cookies are required if using SSR
    },
    withCredentials: true,
  });

@yordis
Copy link
Contributor

yordis commented Dec 31, 2024

@larodiel, how did you figure that one out? Also, I hope you are right! I prefer explicit call and check the returned value instead of that closure way to do things

@larodiel
Copy link

larodiel commented Jan 2, 2025

@yordis I was reading the documentation https://authjs.dev/getting-started/session-management/protecting and as call the auth function was nothing passing on the deploy step, I tried to validate it as we validate pages, and it worked.
IDK if it's the better way, but for now, as it's on beta and I'm not using on a large scale app, I decided to follow this path.

@ralphsmith80
Copy link

I'm on next 15.0.3 and "next-auth": "^5.0.0-beta.25" and I've switched from auth wrapper to auth function inside the request and it started to working

export async function GET(request: NextRequest) {
  const authSession = await auth();
  if (!authSession) {
      return NextResponse.json(
        {
          message: 'Unauthorized',
          medias: [],
        },
        { status: 401 },
      );
    }
  }

This is my Front End request:

//import { cookies } from 'next/headers';
//const cookiesSession = await cookies();
 const response = await axios.get(`/api/media?page=${page}&limit=${limit}`, {
    headers: {
      'Content-Type': 'application/json',
      //Cookie: cookiesSession.toString(), //the cookies are required if using SSR
    },
    withCredentials: true,
  });

This is what AI (claude) is also suggesting. Poking around here and glad to see others running with the same method. I'll probably make a simple util function so I don't have to re-type this everywhere though.

@Nfinished
Copy link
Contributor

wrapping is less ergonomic anyway tbh

@ralphsmith80
Copy link

ralphsmith80 commented Jan 7, 2025

This is just a reimplementation of what I think auth should be doing, but it works.

import { auth } from '@/auth'
import { NextRequest } from 'next/server'

export interface NextRequestExt extends NextRequest {
  // this is for my needs
  auth?: { role?: string; user?: { id?: string; email?: string | null } }
}

export const withAuth = (
  handler: (req: NextRequestExt) => Promise<Response>
) => {
  return async function (req: NextRequestExt) {
    try {
      const session = await auth()
      if (!session) {
        return Response.json({ error: 'Unauthorized' }, { status: 401 })
      }

      // Add session to request for use in handler
      req.auth = session

      return handler(req)
    } catch (error) {
      console.error(error)
      return Response.json({ error: 'Internal server error' }, { status: 500 })
    }
  }
}
import { NextResponse } from 'next/server'
import { withAuth } from '@/utils/auth'

import type { NextRequestExt } from '@/utils/auth'

export const GET = withAuth(async function GET(req: NextRequestExt) {
  try {
    return NextResponse.json(req.auth)
  } catch (error) {
    console.error(error)
    return NextResponse.json(
      { error: 'Failed to test' },
      { status: 500 }
    )
  }
})

I'm also using the for RBAC.

export const withRole = (
  role: string,
  handler: (req: NextRequestExt) => Promise<Response>
) => {
  return withAuth(async (req: NextRequestExt) => {
    try {
     // db request for user role based on unique email values
      const userRole = await getRole(req.auth?.user?.email ?? '')
      if (userRole !== role) {
        return Response.json({ error: 'Forbidden' }, { status: 403 })
      }

      req.auth!.role = userRole
      return handler(req)
    } catch (error) {
      console.error(error)
      return Response.json({ error: 'Internal server error' }, { status: 500 })
    }
  })
}

Edit: I changed those to use NextResponse, but I didn't update the code above.

@ataschz
Copy link

ataschz commented Jan 16, 2025

Why the new release is delayed? Couldn't we push a hotfix version?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working triage Unseen or unconfirmed by a maintainer yet. Provide extra information in the meantime.
Projects
None yet
Development

No branches or pull requests