1

When I am trying to do next build to prepare my application for production, the next build script always stuck at collect page data, with the following error:

TypeError: o is not a function
#13 89.81 at 17692 (.next/server/app/api/(myapi)/route.js:1:xxx)

Opening up the .next file will show its breaking at the following expression:

  let u = [
      o({
        name: "Credentials",
        credentials: {
          email: { label: "Email", type: "email" },
          password: { label: "Password", type: "password" },
        },

I am using nextjs with App Router, reading NextAuth seems has very little document on v4 for App Router and on v5 document does not even exist, this is super confusing and I got totally stuck, wondering if there is anyone can offer help?

My code:

app/api/auth/[...nextauth]/route.js:

import NextAuth from "next-auth";
import { authOptions } from "@/lib/auth/options";

const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };

lib/auth/options.js:

import { PrismaAdapter } from "@next-auth/prisma-adapter";
import prisma from "@/lib/prisma";
import { getProviders } from "./providers";
import { callbacks } from "./callbacks";

export const authOptions = {
  adapter: PrismaAdapter(prisma),
  providers: getProviders(),
  callbacks,
  pages: {
    signIn: "/sign_in",
    signUp: "/sign_up",
    verifyRequest: "/verify-email",
  },
  session: {
    strategy: "jwt",
  },
  secret: process.env.NEXTAUTH_SECRET,
  debug: process.env.NODE_ENV !== "production",
};

lib/auth/providers.js:

import CredentialsProvider from "next-auth/providers/credentials";
import GoogleProvider from "next-auth/providers/google";
import prisma from "@/lib/prisma";
import bcrypt from "bcrypt";

export const getProviders = () => {
  const providers = [
    CredentialsProvider({
      name: "Credentials",
      credentials: {
        email: { label: "Email", type: "email" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {
        try {
          if (!credentials?.email || !credentials?.password) {
            throw new Error("allFieldsRequired");
          }

          const user = await prisma.user.findUnique({
            where: { email: credentials.email },
          });

          if (!user || !user.password) {
            throw new Error("invalidCredentials");
          }

          const isValid = await bcrypt.compare(credentials.password, user.password);
          if (!isValid) {
            throw new Error("invalidCredentials");
          }

          if (!user.emailVerified) {
            throw new Error("emailNotVerified");
          }

          return { id: user.id, name: user.name, email: user.email, accessToken: user.accessToken };
        } catch (error) {
          console.error("Authorize error:", error.message);
          throw error;
        }
      },
    }),
  ];

  if (
    process.env.GOOGLE_CLIENT_ID &&
    process.env.GOOGLE_CLIENT_SECRET &&
    process.env.NEXT_PUBLIC_ENABLE_GOOGLE_LOGIN !== "false"
  ) {
    providers.push(
      GoogleProvider({
        clientId: process.env.GOOGLE_CLIENT_ID,
        clientSecret: process.env.GOOGLE_CLIENT_SECRET,
        authorization: {
          params: {
            scope: "openid email profile https://www.googleapis.com/auth/calendar",
          },
        },
      })
    );
  }

  return providers;
};

lib/auth/callbacks.js:

import prisma from "@/lib/prisma";

export const callbacks = {
  async signIn({ user, account }) {
    try {
      if (account.provider === "google") {
        await prisma.user.upsert({
          where: { email: user.email },
          update: {
            accessToken: account.access_token,
            emailVerified: user.emailVerified || new Date(),
          },
          create: {
            email: user.email,
            name: user.name,
            googleId: account.providerAccountId,
            accessToken: account.access_token,
            emailVerified: new Date(),
          },
        });
      }
      return true;
    } catch (error) {
      console.error("SignIn callback error:", error);
      return false;
    }
  },

  async jwt({ token, user }) {
    if (user) {
      token.id = user.id;
      token.accessToken = user.accessToken;
      token.name = user.name;
      token.email = user.email;
    }
    return token;
  },

  async session({ session, token }) {
    try {
      session.user.id = token.id;
      session.user.accessToken = token.accessToken;
      session.user.name = token.name;
      session.user.email = token.email;
      return session;
    } catch (error) {
      console.error("Session callback error:", error);
      throw error;
    }
  },
};

In my API calls when I need to secure the call:

import { getServerSession } from 'next-auth/next';
import { authOptions } from '@/lib/auth/options';
import prisma from '@/lib/prisma.js';
import { NextResponse } from 'next/server';

export async function GET(req) {
  try {
    const session = await getServerSession(authOptions);
    if (!session || !session.user || !session.user.id) {
...

It's very plain boilerplate code that works fine in npm run dev but breaks when build npm run build

2
  • I've deleted my earlier comment because you edited in code as requested (thanks! have a +1) but I would like to reiterate the bit about Typescript: there's a good chance you've got a simple error somewhere in all of this that the type checker could have warned you about, probably right inside your text editor/IDE. Commented Apr 21 at 12:40
  • The problem is my entire project is based on JS, so I don’t think switching to TS is an option, I am literally just trying to solve a build bug. And this doesn’t make sense either- remember it runs fine when in development mode, just the build process failed Commented Apr 21 at 13:59

1 Answer 1

0
  • Try to strip (delete big project folders)in your project until u get successful build

  • this will take simply 20-30 minutes

  • this way u will get to know file causing issue

  • try to delete .next before every build

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.