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

NextJS Edge Runtime (+ Vercel Edge Functions) #5

Open
daveycodez opened this issue Dec 17, 2024 · 1 comment
Open

NextJS Edge Runtime (+ Vercel Edge Functions) #5

daveycodez opened this issue Dec 17, 2024 · 1 comment

Comments

@daveycodez
Copy link

daveycodez commented Dec 17, 2024

Hey saw the guide over at Zuplo and love what you have built here. I know their guide showed the Pages Router API route and I see your update to support the App Router... But I want to use the Pages API Route with Edge runtime. Is this possible?

export const config = { runtime: "edge" }

This is the error I'm getting -

 ⨯ Error: The edge runtime does not support Node.js 'path' module.
Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime
    at [project]/node_modules/@subzerocloud/nodejs/index.js [edge-api] (ecmascript) (.next/server/edge/chunks/_d81405._.js:10225:168)
    at [project]/src/pages/api/[...query].ts [edge-api] (ecmascript) (src/pages/api/[...query].ts:7:0)
   5 | // The code provided in next.config.ts should work once those issues are fixed.
   6 |
>  7 | import Subzero, {
   8 |     SubzeroError,
   9 |     getIntrospectionQuery,
  10 |     Env as QueryEnv
 GET /api/user?select=* 500 in 89ms

/pages/api/[...query].ts

// Due to various issues with Vercel bundling the wasm file when using the app
// directory (ex. https://github.com/orgs/vercel/discussions/1278), I was
// unfortunately not able to get this working. I even tried a standalone
// but hit https://github.com/vercel/next.js/issues/50072
// The code provided in next.config.ts should work once those issues are fixed.

import Subzero, {
    SubzeroError,
    getIntrospectionQuery,
    Env as QueryEnv
} from "@subzerocloud/nodejs"
import { neon, NeonQueryFunction } from "@neondatabase/serverless"

const urlPrefix = "/api"
const publicSchema = "public"
const dbType = "postgresql"
export const dynamic = "force-dynamic" // static by default, unless reading the request

let subzero: Subzero
const role = "anonymous"

async function initSubzero(sql: NeonQueryFunction<false, false>) {
    const { query, parameters } = getIntrospectionQuery(
        dbType,
        publicSchema // the schema name that is exposed to the HTTP api (ex: public, api)
    )
    const data = await sql(query, parameters)

    // the result of the introspection query is a json string representation of the database schema/structure
    // this schema object is used to generate the queries and check the permissions
    // to make the function startup faster, one can cache the schema object
    const schema = JSON.parse(data[0].json_schema)
    subzero = new Subzero(dbType, schema)
}

const handler = async (request: Request) => {
    const method = request.method
    if (!process.env.DATABASE_URL) {
        throw new Error("DATABASE_URL is not set")
    }
    if (!["GET", "POST", "PUT", "DELETE", "PATCH"].includes(method)) {
        throw new SubzeroError(`Method ${method} not allowed`, 400)
    }

    const sql = neon(process.env.DATABASE_URL!)
    // initialize the subzero instance if it is not initialized yet
    if (!subzero) {
        await initSubzero(sql)
    }

    const queryEnv: QueryEnv = [
        ["role", role],
        ["request.method", method],
        ["request.headers", JSON.stringify(request.headers)],
        ["request.jwt.claims", JSON.stringify({ role })],
    ]
    const { query, parameters } = await subzero.fmtStatement(
        publicSchema,
        `${urlPrefix}/`,
        role,
        request,
        queryEnv
    )

    let result: Record<string, unknown>[]

    try {
        result = await sql(query, parameters)
    } catch (e) {
        console.error(
            `Error performing query ${query} with parameters ${parameters}`,
            e
        )
        throw e
    }

    const headers = {
        "content-type": "application/json",
    }

    return new Response(JSON.stringify(result), {
        status: 200,
        headers,
    })
}

export default handler

export const config = { runtime: "edge" }
@daveycodez
Copy link
Author

daveycodez commented Dec 17, 2024

https://github.com/chaiNNer-org/node-path/

This polyfill for path should work, not sure what others might be needed to support Edge.

I'm working on a SWR Hook Generator project that will create useSWR hooks for React that are totally type safe and introspect the types from the database using Kysely codegen to pull down the types. The useSWR hooks will use the @supabase/postgrest-js client to interface with Subzero Postgrest, preferably running on Vercel Edge, and from there using Neon Serverless for optimal latency. And I'm planning to top all of that off with Better-Auth + JWT plugin for Neon RLS, and then running everything through Upstash rate limiting in middleware.ts. Magic Christmas Dreamland?

@daveycodez daveycodez changed the title NextJS Edge Runtime (Pages Router API NextJS Edge Runtime (+ Vercel Edge Functions) Dec 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant