diff --git a/.changeset/tidy-gorillas-confess.md b/.changeset/tidy-gorillas-confess.md new file mode 100644 index 0000000000..c3855c60b7 --- /dev/null +++ b/.changeset/tidy-gorillas-confess.md @@ -0,0 +1,47 @@ +--- +"blitz": minor +"@blitzjs/auth": minor +"@blitzjs/next": minor +"@blitzjs/rpc": minor +"@blitzjs/generator": minor +--- + +feat: add blitz auth support for the Web `Request` API standard + +Usage using the new `withBlitzAuth` adapter in the App Router: + +```ts +import {withBlitzAuth} from "app/blitz-server" + +export const {POST} = withBlitzAuth({ + POST: async (_request, _params, ctx) => { + const session = ctx.session + await session.$revoke() + + return new Response( + JSON.stringify({ + userId: session.userId, + }), + {status: 200}, + ) + }, +}) +``` + +feat: New Blitz RPC handler meant to with the next.js app router `route.ts` files + +Usage using the new `rpcAppHandler` function + +```ts +// app/api/rpc/[[...blitz]]/route.ts +import {rpcAppHandler} from "@blitzjs/rpc" +import {withBlitzAuth} from "app/blitz-server" + +// Usage with blitz auth +export const {GET, POST, HEAD} = withBlitzAuth(rpcAppHandler()) + +// Standalone usage +export const {GET, POST, HEAD} = rpcAppHandler() +``` + +chore: Update the app directory starter diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ab8c820fde..1284ea3560 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -23,7 +23,7 @@ jobs: - name: Setup node uses: actions/setup-node@v2 with: - node-version: 18 + node-version: 20 cache: "pnpm" - name: Install dependencies run: pnpm install --frozen-lockfile @@ -44,7 +44,7 @@ jobs: - name: Setup node uses: actions/setup-node@v2 with: - node-version: 18 + node-version: 20 cache: "pnpm" - run: pnpm install --frozen-lockfile - name: Build @@ -75,7 +75,7 @@ jobs: - name: Setup node@16 uses: actions/setup-node@v2 with: - node-version: 18 + node-version: 20 cache: "pnpm" - name: Install dependencies @@ -137,7 +137,7 @@ jobs: if: matrix.folder != 'next-13-app-dir' || matrix.os != 'windows-latest' uses: actions/setup-node@v2 with: - node-version: 18 + node-version: 20 cache: "pnpm" - name: Install dependencies diff --git a/apps/next13/package.json b/apps/next13/package.json index d2e7d971d8..2edd5eba17 100644 --- a/apps/next13/package.json +++ b/apps/next13/package.json @@ -22,7 +22,7 @@ "@tanstack/react-query": "4.0.10", "blitz": "2.0.10", "flatted": "3.2.7", - "next": "canary", + "next": "14.3.0-canary.28", "prisma": "^4.5.0", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/apps/next13/prisma/dev.db b/apps/next13/prisma/dev.db index 8c8b503c1a..be8dd7c832 100644 Binary files a/apps/next13/prisma/dev.db and b/apps/next13/prisma/dev.db differ diff --git a/apps/next13/src/app/api/rpc/[[...blitz]]/route.ts b/apps/next13/src/app/api/rpc/[[...blitz]]/route.ts new file mode 100644 index 0000000000..c3fefe9049 --- /dev/null +++ b/apps/next13/src/app/api/rpc/[[...blitz]]/route.ts @@ -0,0 +1,4 @@ +import {rpcAppHandler} from "@blitzjs/rpc" +import {withBlitzAuth} from "src/blitz-server" + +export const {GET, POST, HEAD} = withBlitzAuth(rpcAppHandler()) diff --git a/apps/next13/src/blitz-server.ts b/apps/next13/src/blitz-server.ts index cf597fd68f..8f4ed47e21 100644 --- a/apps/next13/src/blitz-server.ts +++ b/apps/next13/src/blitz-server.ts @@ -6,26 +6,27 @@ import {simpleRolesIsAuthorized} from "@blitzjs/auth" import {BlitzLogger} from "blitz" import {RpcServerPlugin} from "@blitzjs/rpc" -const {api, getBlitzContext, useAuthenticatedBlitzContext, invoke} = setupBlitzServer({ - plugins: [ - AuthServerPlugin({ - cookiePrefix: "web-cookie-prefix", - storage: PrismaStorage(db), - isAuthorized: simpleRolesIsAuthorized, - }), - RpcServerPlugin({ - logging: { - disablelevel: "debug", - }, - onInvokeError(error) { - console.log("onInvokeError", error) - }, - }), - ], - logger: BlitzLogger({}), -}) +const {api, getBlitzContext, useAuthenticatedBlitzContext, invoke, withBlitzAuth} = + setupBlitzServer({ + plugins: [ + AuthServerPlugin({ + cookiePrefix: "web-cookie-prefix", + storage: PrismaStorage(db), + isAuthorized: simpleRolesIsAuthorized, + }), + RpcServerPlugin({ + logging: { + disablelevel: "debug", + }, + onInvokeError(error) { + console.log("onInvokeError", error) + }, + }), + ], + logger: BlitzLogger({}), + }) -export {api, getBlitzContext, useAuthenticatedBlitzContext, invoke} +export {api, getBlitzContext, useAuthenticatedBlitzContext, invoke, withBlitzAuth} export const cliConfig: BlitzCliConfig = { customTemplates: "src/templates", diff --git a/apps/next13/src/pages/api/rpc/[[...blitz]].ts b/apps/next13/src/pages/api/rpc/[[...blitz]].ts deleted file mode 100644 index 0d0c822dad..0000000000 --- a/apps/next13/src/pages/api/rpc/[[...blitz]].ts +++ /dev/null @@ -1,4 +0,0 @@ -import {rpcHandler} from "@blitzjs/rpc" -import {api} from "../../../blitz-server" - -export default api(rpcHandler({onError: (error, ctx) => console.log(error)})) diff --git a/apps/next13/src/users/queries/getCurrentUser.ts b/apps/next13/src/users/queries/getCurrentUser.ts index 9cc86e0737..856ed38bc6 100644 --- a/apps/next13/src/users/queries/getCurrentUser.ts +++ b/apps/next13/src/users/queries/getCurrentUser.ts @@ -12,5 +12,5 @@ export default async function getCurrentUser(input: null, ctx: Ctx) { } export const config = { - httpMethod: "GET", + httpMethod: "POST", } diff --git a/apps/toolkit-app-passportjs/package.json b/apps/toolkit-app-passportjs/package.json index f6fa8730a1..e55f5c3394 100644 --- a/apps/toolkit-app-passportjs/package.json +++ b/apps/toolkit-app-passportjs/package.json @@ -31,7 +31,7 @@ "@hookform/resolvers": "2.9.10", "@prisma/client": "4.6.1", "blitz": "2.0.10", - "next": "canary", + "next": "14.3.0-canary.28", "openid-client": "5.2.1", "prisma": "4.6.1", "react": "18.2.0", diff --git a/apps/toolkit-app/package.json b/apps/toolkit-app/package.json index 0eb8e8cedc..186916521e 100644 --- a/apps/toolkit-app/package.json +++ b/apps/toolkit-app/package.json @@ -32,7 +32,7 @@ "@hookform/resolvers": "2.9.10", "@prisma/client": "4.6.1", "blitz": "2.0.10", - "next": "canary", + "next": "14.3.0-canary.28", "next-auth": "4.24.7", "prisma": "4.6.1", "react": "18.2.0", diff --git a/apps/toolkit-app/src/pages/auth/forgot-password.tsx b/apps/toolkit-app/src/pages/forgot-password.tsx similarity index 100% rename from apps/toolkit-app/src/pages/auth/forgot-password.tsx rename to apps/toolkit-app/src/pages/forgot-password.tsx diff --git a/apps/toolkit-app/src/pages/auth/login.tsx b/apps/toolkit-app/src/pages/login.tsx similarity index 85% rename from apps/toolkit-app/src/pages/auth/login.tsx rename to apps/toolkit-app/src/pages/login.tsx index cc572db3ff..4e6017dfe4 100644 --- a/apps/toolkit-app/src/pages/auth/login.tsx +++ b/apps/toolkit-app/src/pages/login.tsx @@ -11,15 +11,11 @@ const LoginPage: BlitzPage = () => { { const next = router.query.next ? decodeURIComponent(router.query.next as string) : "/" - // return router.push(next) + return router.push(next) }} /> ) } -LoginPage.authenticate = { - redirectTo: "/", -} - export default LoginPage diff --git a/apps/toolkit-app/src/pages/auth/reset-password.tsx b/apps/toolkit-app/src/pages/reset-password.tsx similarity index 100% rename from apps/toolkit-app/src/pages/auth/reset-password.tsx rename to apps/toolkit-app/src/pages/reset-password.tsx diff --git a/apps/toolkit-app/src/pages/auth/signup.tsx b/apps/toolkit-app/src/pages/signup.tsx similarity index 100% rename from apps/toolkit-app/src/pages/auth/signup.tsx rename to apps/toolkit-app/src/pages/signup.tsx diff --git a/apps/web/package.json b/apps/web/package.json index 0dfdb1cd6d..1011601553 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -26,7 +26,7 @@ "blitz": "2.0.10", "jest": "29.3.0", "jest-environment-jsdom": "29.3.0", - "next": "canary", + "next": "14.3.0-canary.28", "passport-mock-strategy": "2.0.0", "passport-twitter": "1.0.4", "prisma": "4.6.1", diff --git a/integration-tests/auth-with-rpc/package.json b/integration-tests/auth-with-rpc/package.json index 21513c52a8..da6b6198ba 100644 --- a/integration-tests/auth-with-rpc/package.json +++ b/integration-tests/auth-with-rpc/package.json @@ -26,7 +26,7 @@ "@prisma/client": "4.6.1", "blitz": "2.0.10", "delay": "5.0.0", - "next": "canary", + "next": "14.3.0-canary.28", "prisma": "4.6.1", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/integration-tests/auth/package.json b/integration-tests/auth/package.json index 441a6793e7..2527121975 100644 --- a/integration-tests/auth/package.json +++ b/integration-tests/auth/package.json @@ -23,7 +23,7 @@ "@prisma/client": "4.6.1", "blitz": "2.0.10", "lowdb": "3.0.0", - "next": "canary", + "next": "14.3.0-canary.28", "prisma": "4.6.1", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/integration-tests/auth/pages/api/signin.ts b/integration-tests/auth/pages/api/signin.ts index ddfc9f22aa..f5bf99785b 100644 --- a/integration-tests/auth/pages/api/signin.ts +++ b/integration-tests/auth/pages/api/signin.ts @@ -21,14 +21,11 @@ export const authenticateUser = async (email: string, password: string) => { } export default api(async (req, res, ctx) => { - const blitzContext = ctx - const user = await authenticateUser(req.query.email as string, req.query.password as string) - - await blitzContext.session.$create({ + await ctx.session.$create({ userId: user.id, role: user.role as Role, }) - res.status(200).json({email: req.query.email, userId: blitzContext.session.userId}) + res.status(200).json({email: req.query.email, userId: ctx.session.userId}) }) diff --git a/integration-tests/get-initial-props/package.json b/integration-tests/get-initial-props/package.json index 028a06280e..056964a576 100644 --- a/integration-tests/get-initial-props/package.json +++ b/integration-tests/get-initial-props/package.json @@ -22,7 +22,7 @@ "@prisma/client": "4.6.1", "blitz": "2.0.10", "lowdb": "3.0.0", - "next": "canary", + "next": "14.3.0-canary.28", "prisma": "4.6.1", "react": "18.2.0", "react-dom": "18.2.0" diff --git a/integration-tests/middleware/package.json b/integration-tests/middleware/package.json index 3de66489cc..6528337153 100644 --- a/integration-tests/middleware/package.json +++ b/integration-tests/middleware/package.json @@ -15,7 +15,7 @@ "@blitzjs/next": "2.0.10", "@blitzjs/rpc": "2.0.10", "blitz": "2.0.10", - "next": "canary", + "next": "14.3.0-canary.28", "react": "18.2.0", "react-dom": "18.2.0" }, diff --git a/integration-tests/next-13-app-dir/app/api/logout/route.ts b/integration-tests/next-13-app-dir/app/api/logout/route.ts new file mode 100644 index 0000000000..63708d01bc --- /dev/null +++ b/integration-tests/next-13-app-dir/app/api/logout/route.ts @@ -0,0 +1,15 @@ +import {withBlitzAuth} from "../../../src/blitz-server" + +export const {POST} = withBlitzAuth({ + POST: async (_request, _params, ctx) => { + const session = ctx.session + await session.$revoke() + + return new Response( + JSON.stringify({ + userId: session.userId, + }), + {status: 200}, + ) + }, +}) diff --git a/integration-tests/next-13-app-dir/app/api/noauth/route.ts b/integration-tests/next-13-app-dir/app/api/noauth/route.ts new file mode 100644 index 0000000000..eab9ed7ed5 --- /dev/null +++ b/integration-tests/next-13-app-dir/app/api/noauth/route.ts @@ -0,0 +1,11 @@ +import {H} from "@blitzjs/auth/dist/index-0ecbee46" +import {withBlitzAuth} from "../../../src/blitz-server" + +const emptyResponse = async () => { + return new Response(null, {status: 200}) +} + +export const {POST, HEAD} = withBlitzAuth({ + POST: emptyResponse, + HEAD: emptyResponse, +}) diff --git a/integration-tests/next-13-app-dir/app/api/rpc/[[...blitz]]/route.ts b/integration-tests/next-13-app-dir/app/api/rpc/[[...blitz]]/route.ts new file mode 100644 index 0000000000..79d1799359 --- /dev/null +++ b/integration-tests/next-13-app-dir/app/api/rpc/[[...blitz]]/route.ts @@ -0,0 +1,4 @@ +import {rpcAppHandler} from "@blitzjs/rpc" +import {withBlitzAuth} from "../../../../src/blitz-server" + +export const {GET, POST, HEAD} = withBlitzAuth(rpcAppHandler()) diff --git a/integration-tests/next-13-app-dir/app/api/signin/route.ts b/integration-tests/next-13-app-dir/app/api/signin/route.ts new file mode 100644 index 0000000000..fc326e02cf --- /dev/null +++ b/integration-tests/next-13-app-dir/app/api/signin/route.ts @@ -0,0 +1,38 @@ +import {withBlitzAuth} from "../../../src/blitz-server" +import prisma from "../../../db/index" +import {Role} from "../../../types" + +export const authenticateUser = async (email: string, password: string) => { + const user = await prisma.user.findFirst({where: {email}}) + + if (!user) throw new Error("Authentication Error") + await prisma.user.update({where: {id: user.id}, data: {hashedPassword: password}}) + + const {hashedPassword, ...rest} = user + return rest +} + +export const {POST} = withBlitzAuth({ + POST: async (request: Request, context, ctx) => { + const {searchParams} = new URL(request.url) + const user = await authenticateUser( + searchParams.get("email") as string, + searchParams.get("password") as string, + ) + + await ctx.session.$create({ + userId: user.id, + role: user.role as Role, + }) + + return new Response( + JSON.stringify({email: searchParams.get("email"), userId: ctx.session.userId}), + { + status: 200, + headers: { + "Content-Type": "application/json", + }, + }, + ) + }, +}) diff --git a/integration-tests/next-13-app-dir/next-env.d.ts b/integration-tests/next-13-app-dir/next-env.d.ts index fd36f9494e..4f11a03dc6 100644 --- a/integration-tests/next-13-app-dir/next-env.d.ts +++ b/integration-tests/next-13-app-dir/next-env.d.ts @@ -1,6 +1,5 @@ /// /// -/// // NOTE: This file should not be edited // see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/integration-tests/next-13-app-dir/package.json b/integration-tests/next-13-app-dir/package.json index 5470a50ccf..f057e24ac8 100644 --- a/integration-tests/next-13-app-dir/package.json +++ b/integration-tests/next-13-app-dir/package.json @@ -24,7 +24,7 @@ "@prisma/client": "4.6.1", "blitz": "2.0.10", "lowdb": "3.0.0", - "next": "canary", + "next": "14.3.0-canary.28", "prisma": "4.6.1", "react": "18.2.0", "react-dom": "18.2.0", @@ -45,6 +45,6 @@ "node-fetch": "3.2.3", "playwright": "1.28.0", "ts-node": "10.9.1", - "typescript": "^4.8.4" + "typescript": "^4.9.5" } } diff --git a/integration-tests/next-13-app-dir/pages/api/logout.ts b/integration-tests/next-13-app-dir/pages/api/logout.ts deleted file mode 100644 index 7c1d8b3e53..0000000000 --- a/integration-tests/next-13-app-dir/pages/api/logout.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {api} from "../../src/blitz-server" - -export default api(async (_req, res, ctx) => { - const blitzContext = ctx - - await blitzContext.session.$revoke() - - res.status(200).json({userId: blitzContext.session.userId}) -}) diff --git a/integration-tests/next-13-app-dir/pages/api/noauth.ts b/integration-tests/next-13-app-dir/pages/api/noauth.ts deleted file mode 100644 index fada7c9758..0000000000 --- a/integration-tests/next-13-app-dir/pages/api/noauth.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {api} from "../../src/blitz-server" - -export default api(async (_req, res, ctx) => { - res.status(200).end() -}) diff --git a/integration-tests/next-13-app-dir/pages/api/rpc/[[...blitz]].ts b/integration-tests/next-13-app-dir/pages/api/rpc/[[...blitz]].ts deleted file mode 100644 index 0c8772eb20..0000000000 --- a/integration-tests/next-13-app-dir/pages/api/rpc/[[...blitz]].ts +++ /dev/null @@ -1,4 +0,0 @@ -import {rpcHandler} from "@blitzjs/rpc" -import {api} from "../../../src/blitz-server" - -export default api(rpcHandler({onError: (error, ctx) => console.log(error)})) diff --git a/integration-tests/next-13-app-dir/pages/api/signin.ts b/integration-tests/next-13-app-dir/pages/api/signin.ts deleted file mode 100644 index ddfc9f22aa..0000000000 --- a/integration-tests/next-13-app-dir/pages/api/signin.ts +++ /dev/null @@ -1,34 +0,0 @@ -import {api} from "../../src/blitz-server" -import prisma from "../../db/index" -import {SecurePassword} from "@blitzjs/auth/secure-password" -import {Role} from "../../types" - -export const authenticateUser = async (email: string, password: string) => { - const user = await prisma.user.findFirst({where: {email}}) - - if (!user) throw new Error("Authentication Error") - - const result = await SecurePassword.verify(user.hashedPassword, password) - - if (result === SecurePassword.VALID_NEEDS_REHASH) { - // Upgrade hashed password with a more secure hash - const improvedHash = await SecurePassword.hash(password) - await prisma.user.update({where: {id: user.id}, data: {hashedPassword: improvedHash}}) - } - - const {hashedPassword, ...rest} = user - return rest -} - -export default api(async (req, res, ctx) => { - const blitzContext = ctx - - const user = await authenticateUser(req.query.email as string, req.query.password as string) - - await blitzContext.session.$create({ - userId: user.id, - role: user.role as Role, - }) - - res.status(200).json({email: req.query.email, userId: blitzContext.session.userId}) -}) diff --git a/integration-tests/next-13-app-dir/src/blitz-server.ts b/integration-tests/next-13-app-dir/src/blitz-server.ts index 422c7f10de..6da257ee9e 100644 --- a/integration-tests/next-13-app-dir/src/blitz-server.ts +++ b/integration-tests/next-13-app-dir/src/blitz-server.ts @@ -3,16 +3,16 @@ import {AuthServerPlugin, PrismaStorage} from "@blitzjs/auth" import db from "../db" import {simpleRolesIsAuthorized} from "@blitzjs/auth" import {BlitzLogger} from "blitz" +import {RpcServerPlugin} from "@blitzjs/rpc" -const {api, getBlitzContext} = setupBlitzServer({ +export const {api, getBlitzContext, withBlitzAuth} = setupBlitzServer({ plugins: [ AuthServerPlugin({ cookiePrefix: "auth-tests-cookie-prefix", storage: PrismaStorage(db), isAuthorized: simpleRolesIsAuthorized, }), + RpcServerPlugin({}), ], logger: BlitzLogger({}), }) - -export {api, getBlitzContext} diff --git a/integration-tests/next-13-app-dir/test/index.test.ts b/integration-tests/next-13-app-dir/test/index.test.ts index a6185fd917..2e2a6074e2 100644 --- a/integration-tests/next-13-app-dir/test/index.test.ts +++ b/integration-tests/next-13-app-dir/test/index.test.ts @@ -57,7 +57,7 @@ const runTests = (mode?: string) => { "should render result for open query", async () => { const res = await fetch(`http://localhost:${appPort}/api/noauth`, { - method: "GET", + method: "POST", headers: {"Content-Type": "application/json; charset=utf-8"}, }) expect(res.status).toBe(200) @@ -67,7 +67,7 @@ const runTests = (mode?: string) => { it("sets correct cookie", async () => { const res = await fetch(`http://localhost:${appPort}/api/noauth`, { - method: "GET", + method: "POST", headers: {"Content-Type": "application/json; charset=utf-8"}, }) const cookieHeader = res.headers.get("Set-Cookie") @@ -94,6 +94,8 @@ const runTests = (mode?: string) => { async () => { const browser = await webdriver(appPort, "/react-query") + await browser.refresh() + browser.waitForElementByCss("#button", 0) await browser.elementByCss("#button").click() @@ -133,7 +135,7 @@ const runTests = (mode?: string) => { it("does not require CSRF header on HEAD requests", async () => { const res = await fetch(`http://localhost:${appPort}/api/noauth`, { - method: "GET", + method: "POST", headers: {"Content-Type": "application/json; charset=utf-8"}, }) const cookieHeader = res.headers.get("Set-Cookie") diff --git a/integration-tests/no-suspense/package.json b/integration-tests/no-suspense/package.json index 8cb8dfb9b9..81dec770fa 100644 --- a/integration-tests/no-suspense/package.json +++ b/integration-tests/no-suspense/package.json @@ -22,7 +22,7 @@ "@prisma/client": "4.6.1", "blitz": "2.0.10", "lowdb": "3.0.0", - "next": "canary", + "next": "14.3.0-canary.28", "prisma": "4.6.1", "react": "18.2.0", "react-dom": "18.2.0" diff --git a/integration-tests/qm/package.json b/integration-tests/qm/package.json index dfe5b534b1..8f8d4798c7 100644 --- a/integration-tests/qm/package.json +++ b/integration-tests/qm/package.json @@ -15,7 +15,7 @@ "@prisma/client": "4.6.1", "@tanstack/react-query": "4.0.10", "blitz": "2.0.10", - "next": "canary", + "next": "14.3.0-canary.28", "prisma": "4.6.1", "react": "18.2.0", "react-dom": "18.2.0" diff --git a/integration-tests/react-query-utils/package.json b/integration-tests/react-query-utils/package.json index 8d0772a9a3..f38f171081 100644 --- a/integration-tests/react-query-utils/package.json +++ b/integration-tests/react-query-utils/package.json @@ -21,7 +21,7 @@ "@prisma/client": "4.6.1", "blitz": "2.0.10", "lowdb": "3.0.0", - "next": "canary", + "next": "14.3.0-canary.28", "prisma": "4.6.1", "react": "18.2.0", "react-dom": "18.2.0" diff --git a/integration-tests/rpc-path-root/package.json b/integration-tests/rpc-path-root/package.json index b45f45df59..6d9a2e34fd 100644 --- a/integration-tests/rpc-path-root/package.json +++ b/integration-tests/rpc-path-root/package.json @@ -11,7 +11,7 @@ "@blitzjs/next": "2.0.10", "@blitzjs/rpc": "2.0.10", "blitz": "2.0.10", - "next": "canary", + "next": "14.3.0-canary.28", "react": "18.2.0", "react-dom": "18.2.0" }, diff --git a/integration-tests/rpc/package.json b/integration-tests/rpc/package.json index 83793eaac8..851cbfbfd6 100644 --- a/integration-tests/rpc/package.json +++ b/integration-tests/rpc/package.json @@ -11,7 +11,7 @@ "@blitzjs/next": "2.0.10", "@blitzjs/rpc": "2.0.10", "blitz": "2.0.10", - "next": "canary", + "next": "14.3.0-canary.28", "react": "18.2.0", "react-dom": "18.2.0" }, diff --git a/integration-tests/trailing-slash/package.json b/integration-tests/trailing-slash/package.json index 6528f12a0e..0ee4516535 100644 --- a/integration-tests/trailing-slash/package.json +++ b/integration-tests/trailing-slash/package.json @@ -22,7 +22,7 @@ "@prisma/client": "4.6.1", "blitz": "2.0.10", "lowdb": "3.0.0", - "next": "canary", + "next": "14.3.0-canary.28", "prisma": "4.6.1", "react": "18.2.0", "react-dom": "18.2.0" diff --git a/package.json b/package.json index be9f3f9cd5..22529fcf31 100644 --- a/package.json +++ b/package.json @@ -29,9 +29,9 @@ "husky": "8.0.2", "jsdom": "^19.0.0", "lint-staged": "13.0.3", - "next": "canary", + "next": "14.3.0-canary.28", "only-allow": "1.1.0", - "prettier": "^2.7.1", + "prettier": "^2.8.8", "prettier-plugin-prisma": "4.4.0", "pretty-quick": "3.1.3", "turbo": "1.10.9", @@ -50,7 +50,8 @@ "next-auth@4.24.7": "patches/next-auth@4.24.7.patch" }, "overrides": { - "@types/mime": "3.0.4" + "@types/mime": "3.0.4", + "next": "14.3.0-canary.28" } } } diff --git a/packages/blitz-auth/package.json b/packages/blitz-auth/package.json index ac84ed67c1..c73e5a4255 100644 --- a/packages/blitz-auth/package.json +++ b/packages/blitz-auth/package.json @@ -76,7 +76,7 @@ "@types/react": "18.0.25", "@types/react-dom": "17.0.14", "blitz": "2.0.10", - "next": "canary", + "next": "14.3.0-canary.28", "next-auth": "4.24.7", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/packages/blitz-auth/src/server/auth-plugin.ts b/packages/blitz-auth/src/server/auth-plugin.ts index fe0c152f4b..ce2e361358 100644 --- a/packages/blitz-auth/src/server/auth-plugin.ts +++ b/packages/blitz-auth/src/server/auth-plugin.ts @@ -1,6 +1,6 @@ import {RequestMiddleware, Ctx, createServerPlugin} from "blitz" import {assert} from "blitz" -import {IncomingMessage, ServerResponse} from "http" +import type {IncomingMessage, ServerResponse} from "http" import {PublicData, SessionModel, SessionConfigMethods} from "../shared/types" import {getBlitzContext, getSession, useAuthenticatedBlitzContext} from "./auth-sessions" @@ -130,11 +130,28 @@ export const AuthServerPlugin = createServerPlugin((options: AuthPluginOptions) if (!globalThis.__BLITZ_GET_RSC_CONTEXT) { globalThis.__BLITZ_GET_RSC_CONTEXT = getBlitzContext } + + type Handler = (request: Request, context: any, ctx: Ctx) => Promise | Response + function withBlitzAuth(handlers: T): T { + return Object.fromEntries( + Object.entries(handlers).map(([method, handler]) => [ + method, + async (request: Request, params: unknown) => { + const session = await getSession(request) + const response = await handler(request, params, {session}) + session.setSession(response) + return response + }, + ]), + ) as unknown as T + } + return { requestMiddlewares: [authPluginSessionMiddleware()], exports: () => ({ getBlitzContext, useAuthenticatedBlitzContext, + withBlitzAuth, }), } }) diff --git a/packages/blitz-auth/src/server/auth-sessions.test.ts b/packages/blitz-auth/src/server/auth-sessions.test.ts deleted file mode 100644 index fc7c9d825e..0000000000 --- a/packages/blitz-auth/src/server/auth-sessions.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {expect, describe, it} from "vitest" -import {setCookie} from "./auth-sessions" -import cookie from "cookie" -import {ServerResponse} from "http" - -describe("blitz-auth", () => { - describe("setCookie", () => { - it("works with empty start", async () => { - const res = new ServerResponse({} as any) - setCookie(res, cookie.serialize("A", "a-value", {})) - expect(res.getHeader("Set-Cookie")).toBe("A=a-value") - }) - - it("works with string start", async () => { - const res = new ServerResponse({} as any) - res.setHeader("Set-Cookie", cookie.serialize("A", "a-value", {})) - setCookie(res, cookie.serialize("B", "b-value", {})) - expect(res.getHeader("Set-Cookie")).toEqual(["A=a-value", "B=b-value"]) - }) - - it("works with array start for new name", async () => { - const res = new ServerResponse({} as any) - res.setHeader("Set-Cookie", [ - cookie.serialize("A", "a-value", {}), - cookie.serialize("B", "b-value", {}), - ]) - setCookie(res, cookie.serialize("C", "c-value", {})) - expect(res.getHeader("Set-Cookie")).toEqual(["A=a-value", "B=b-value", "C=c-value"]) - }) - - it("works with array start for existing name", async () => { - const res = new ServerResponse({} as any) - res.setHeader("Set-Cookie", [ - cookie.serialize("A", "a-value", {}), - cookie.serialize("B", "b-value", {}), - ]) - setCookie(res, cookie.serialize("A", "new-a-value", {})) - expect(res.getHeader("Set-Cookie")).toEqual(["A=new-a-value", "B=b-value"]) - }) - }) -}) diff --git a/packages/blitz-auth/src/server/auth-sessions.ts b/packages/blitz-auth/src/server/auth-sessions.ts index 35f4f90363..31494911dc 100644 --- a/packages/blitz-auth/src/server/auth-sessions.ts +++ b/packages/blitz-auth/src/server/auth-sessions.ts @@ -1,7 +1,6 @@ import {fromBase64, toBase64} from "b64-lite" import cookie, {parse} from "cookie" -import {IncomingMessage, ServerResponse} from "http" -import {sign as jwtSign, verify as jwtVerify} from "jsonwebtoken" +import jsonwebtoken from "jsonwebtoken" import { assert, isPast, @@ -13,9 +12,9 @@ import { AuthorizationError, CSRFTokenMismatchError, log, + AuthenticatedCtx, baseLogger, chalk, - AuthenticatedCtx, } from "blitz" import { EmptyPublicData, @@ -39,12 +38,69 @@ import { AuthenticatedSessionContext, } from "../shared" import {generateToken, hash256} from "./auth-utils" -import {Socket} from "net" -import {UrlObject} from "url" import {formatWithValidation} from "../shared/url-utils" -export function isLocalhost(req: IncomingMessage): boolean { - let {host} = req.headers +import type {UrlObject} from "url" +import type {IncomingMessage, ServerResponse} from "http" + +function splitCookiesString(cookiesString: string) { + if (!cookiesString) return [] + let cookiesStrings = [] + let pos = 0 + let start + let ch + let lastComma + let nextStart + let cookiesSeparatorFound + function skipWhitespace() { + while (pos < cookiesString.length && /\s/.test(cookiesString.charAt(pos))) { + pos += 1 + } + return pos < cookiesString.length + } + function notSpecialChar() { + ch = cookiesString.charAt(pos) + return ch !== "=" && ch !== ";" && ch !== "," + } + while (pos < cookiesString.length) { + start = pos + cookiesSeparatorFound = false + while (skipWhitespace()) { + ch = cookiesString.charAt(pos) + if (ch === ",") { + lastComma = pos + pos += 1 + skipWhitespace() + nextStart = pos + while (pos < cookiesString.length && notSpecialChar()) { + pos += 1 + } + if (pos < cookiesString.length && cookiesString.charAt(pos) === "=") { + cookiesSeparatorFound = true + pos = nextStart + cookiesStrings.push(cookiesString.substring(start, lastComma)) + start = pos + } else { + pos = lastComma + 1 + } + } else { + pos += 1 + } + } + if (!cookiesSeparatorFound || pos >= cookiesString.length) { + cookiesStrings.push(cookiesString.substring(start, cookiesString.length)) + } + } + return cookiesStrings +} + +export function isLocalhost(req: IncomingMessage | Request): boolean { + let host: string | undefined + if (req instanceof Request) { + host = req.headers.get("host") || "" + } else { + host = req.headers.host || "" + } let localhost = false if (host) { host = host.split(":")[0] @@ -69,7 +125,8 @@ export function getCookieParser(headers: {[key: string]: undefined | string | st } } -const debug = require("debug")("blitz:session") +import Debug from "debug" +const debug = Debug("blitz:session") export interface SimpleRolesIsAuthorized { ({ctx, args}: {ctx: any; args: [roleOrRoles?: RoleType | RoleType[]]}): boolean @@ -131,14 +188,6 @@ type AuthedSessionKernel = { } type SessionKernel = AnonSessionKernel | AuthedSessionKernel -function ensureApiRequest( - req: IncomingMessage & {[key: string]: any}, -): asserts req is IncomingMessage & {cookies: {[key: string]: string}} { - if (!("cookies" in req)) { - // Cookie parser isn't include inside getServerSideProps, so we have to add it - req.cookies = getCookieParser(req.headers)() - } -} function ensureMiddlewareResponse( res: ServerResponse & {[key: string]: any}, ): asserts res is ServerResponse & {blitzCtx: Ctx} { @@ -147,58 +196,112 @@ function ensureMiddlewareResponse( } } +function convertRequestToHeader(req: IncomingMessage | Request): Headers { + const headersFromRequest = req.headers + if (headersFromRequest instanceof Headers) { + return headersFromRequest + } else { + const headers = new Headers() + Object.entries(headersFromRequest).forEach(([key, value]) => { + if (value) { + if (Array.isArray(value)) { + headers.append(key, value.join(",")) + } else { + headers.append(key, value) + } + } + }) + return headers + } +} + +function getCookiesFromHeader(headers: Headers) { + const cookieHeader = headers.get("Cookie") + if (cookieHeader) { + return cookie.parse(cookieHeader) + } else { + return {} + } +} + +export async function getSession(req: Request): Promise +export async function getSession(req: Request, res: never, isRsc: boolean): Promise +export async function getSession(req: IncomingMessage, res: ServerResponse): Promise export async function getSession( req: IncomingMessage, res: ServerResponse, - appDir = false, + isRsc: boolean, +): Promise +export async function getSession( + req: IncomingMessage | Request, + res?: ServerResponse, + isRsc?: boolean, ): Promise { - ensureApiRequest(req) - ensureMiddlewareResponse(res) - - debug("cookiePrefix", globalThis.__BLITZ_SESSION_COOKIE_PREFIX) - - if (res.blitzCtx.session) { - debug("Returning existing session") - return res.blitzCtx.session + const headers = convertRequestToHeader(req) + if (res) { + ensureMiddlewareResponse(res) + debug("cookiePrefix", globalThis.__BLITZ_SESSION_COOKIE_PREFIX) + if (res.blitzCtx.session) { + debug("Returning existing session") + return res.blitzCtx.session + } } - - let sessionKernel = await getSessionKernel(req, res) + const method = req.method + let sessionKernel = await getSessionKernel({headers, method}) if (sessionKernel) { debug("Got existing session", sessionKernel) } if (!sessionKernel) { - debug("No session found, creating anonymous session") - sessionKernel = await createAnonymousSession(req, res) + sessionKernel = await createAnonymousSession({headers}) } const sessionContext = makeProxyToPublicData( - new SessionContextClass(req, res, sessionKernel, appDir), + new SessionContextClass(headers, sessionKernel, !!isRsc, res), ) debug("New session context") - res.blitzCtx.session = sessionContext + if (res) { + ;(res as any).blitzCtx = { + session: sessionContext, + } + sessionContext.setSession(res) + } return sessionContext } +interface RouteUrlObject extends Pick { + pathname: string +} + +const makeProxyToPublicData = (ctxClass: T): T => { + return new Proxy(ctxClass, { + get(target, prop, receiver) { + if (prop in target || prop === "then") { + return Reflect.get(target, prop, receiver) + } else { + return Reflect.get(target.$publicData, prop, receiver) + } + }, + }) +} + export async function getBlitzContext(): Promise { try { const {headers, cookies} = require("next/headers") - const req = new IncomingMessage(new Socket()) as IncomingMessage & { - cookies: {[key: string]: string} - } - req.headers = Object.fromEntries(headers()) + const reqHeader = Object.fromEntries(headers()) const csrfToken = cookies().get(COOKIE_CSRF_TOKEN()) if (csrfToken) { - req.headers[HEADER_CSRF] = csrfToken.value + reqHeader[HEADER_CSRF] = csrfToken.value } - req.cookies = Object.fromEntries( - cookies() - .getAll() - .map((c: {name: string; value: string}) => [c.name, c.value]), + const session = await getSession( + { + headers: new Headers(reqHeader), + method: "POST", + } as Request, + null as never, + true, ) - const res = new ServerResponse(req) - const session = await getSession(req, res, true) const ctx: Ctx = { session, } @@ -206,17 +309,13 @@ export async function getBlitzContext(): Promise { } catch (e) { if ((e as NodeJS.ErrnoException).code === "MODULE_NOT_FOUND") { throw new Error( - "Usage of `useAuthenticatedBlitzContext` is supported only in next.js 13.0.0 and above. Please upgrade your next.js version.", + "Usage of `getBlitzContext` is supported only in next.js 13.0.0 and above. Please upgrade your next.js version.", ) } throw e } } -interface RouteUrlObject extends Pick { - pathname: string -} - export async function useAuthenticatedBlitzContext({ redirectTo, redirectAuthenticatedTo, @@ -291,18 +390,6 @@ export async function useAuthenticatedBlitzContext({ } } -const makeProxyToPublicData = (ctxClass: T): T => { - return new Proxy(ctxClass, { - get(target, prop, receiver) { - if (prop in target || prop === "then") { - return Reflect.get(target, prop, receiver) - } else { - return Reflect.get(target.$publicData, prop, receiver) - } - }, - }) -} - const NotSupportedMessage = async (method: string) => { const message = `Method ${method} is not yet supported in React Server Components` const _box = await log.box(message, log.chalk.hex("8a3df0").bold("Blitz Auth")) @@ -310,21 +397,27 @@ const NotSupportedMessage = async (method: string) => { } export class SessionContextClass implements SessionContext { - private _req: IncomingMessage & {cookies: {[key: string]: string}} - private _res: ServerResponse & {blitzCtx: Ctx} + private _headers: Headers private _kernel: SessionKernel - private _appDir: boolean - - constructor( - req: IncomingMessage & {cookies: {[key: string]: string}}, - res: ServerResponse & {blitzCtx: Ctx}, - kernel: SessionKernel, - appDir: boolean, - ) { - this._req = req - this._res = res + private _isRsc: boolean + private _response?: ServerResponse + + private static headersToIncludeInResponse = [ + HEADER_CSRF, + HEADER_CSRF_ERROR, + HEADER_PUBLIC_DATA_TOKEN, + HEADER_SESSION_CREATED, + ] + + constructor(headers: Headers, kernel: SessionKernel, isRsc: boolean, response?: ServerResponse) { + this._headers = headers this._kernel = kernel - this._appDir = appDir + this._isRsc = isRsc + this._response = response + } + + $antiCSRFToken() { + return this._kernel.antiCSRFToken } get $handle() { @@ -352,38 +445,69 @@ export class SessionContextClass implements SessionContext { $isAuthorized(...args: IsAuthorizedArgs) { if (!this.userId) return false - return global.sessionConfig.isAuthorized({ctx: this._res.blitzCtx, args}) + return global.sessionConfig.isAuthorized({ + ctx: { + session: this as AuthenticatedSessionContext, + }, + args, + }) } $thisIsAuthorized(...args: IsAuthorizedArgs): this is AuthenticatedSessionContext { return this.$isAuthorized(...args) } + setSession(response: Response | ServerResponse) { + if (this._isRsc) { + void NotSupportedMessage("setSession") + return + } + const cookieHeaders = this._headers.get("set-cookie") + if (response instanceof Response) { + response.headers.set("Set-Cookie", cookieHeaders!) + } else { + response.setHeader("Set-Cookie", splitCookiesString(cookieHeaders!)) + } + + const headers = this._headers.entries() + for (const [key, value] of headers) { + if (SessionContextClass.headersToIncludeInResponse.includes(key)) { + if (response instanceof Response) { + response.headers.set(key, value) + } else { + response.setHeader(key, value) + } + } + } + } + async $create(publicData: PublicData, privateData?: Record) { - if (this._appDir) { + if (this._isRsc) { void NotSupportedMessage("$create") return } this._kernel = await createNewSession({ - req: this._req, - res: this._res, + headers: this._headers, publicData, privateData, jwtPayload: this._kernel.jwtPayload, anonymous: false, }) + + if (this._response) this.setSession(this._response) } async $revoke() { - if (this._appDir) { + if (this._isRsc) { void NotSupportedMessage("$revoke") return } - this._kernel = await revokeSession(this._req, this._res, this.$handle) + this._kernel = await revokeSession(this._headers, this.$handle) + if (this._response) this.setSession(this._response) } async $revokeAll() { - if (this._appDir) { + if (this._isRsc) { void NotSupportedMessage("$revokeAll") return } @@ -395,25 +519,28 @@ export class SessionContextClass implements SessionContext { } async $setPublicData(data: Record) { - if (this._appDir) { + if (this._isRsc) { void NotSupportedMessage("$setPublicData") return } if (this.userId) { await syncPubicDataFieldsForUserIfNeeded(this.userId, data) } - this._kernel.publicData = await setPublicData(this._req, this._res, this._kernel, data) + this._kernel.publicData = await setPublicData(this._headers, this._kernel, data) + if (this._response) this.setSession(this._response) } async $getPrivateData() { return (await getPrivateData(this.$handle)) || {} } - $setPrivateData(data: Record) { - if (this._appDir) { + + async $setPrivateData(data: Record) { + if (this._isRsc) { void NotSupportedMessage("$setPrivateData") return Promise.resolve() } - return setPrivateData(this._kernel, data) + await setPrivateData(this._kernel, data) + if (this._response) this.setSession(this._response) } } @@ -505,7 +632,7 @@ const JWT_ANONYMOUS_SUBJECT = "anonymous" const JWT_ALGORITHM = "HS256" const createAnonymousSessionToken = (payload: AnonymousSessionPayload) => { - return jwtSign({[JWT_NAMESPACE]: payload}, getSessionSecretKey() || "", { + return jsonwebtoken.sign({[JWT_NAMESPACE]: payload}, getSessionSecretKey() || "", { algorithm: JWT_ALGORITHM, issuer: JWT_ISSUER, audience: JWT_AUDIENCE, @@ -519,7 +646,7 @@ const parseAnonymousSessionToken = (token: string) => { const secret = getSessionSecretKey() try { - const fullPayload = jwtVerify(token, secret!, { + const fullPayload = jsonwebtoken.verify(token, secret!, { algorithms: [JWT_ALGORITHM], issuer: JWT_ISSUER, audience: JWT_AUDIENCE, @@ -536,126 +663,127 @@ const parseAnonymousSessionToken = (token: string) => { } } -export const setCookie = (res: ServerResponse, cookieStr: string) => { - const getCookieName = (c: string) => c.split("=", 2)[0] - const appendCookie = () => append(res, "Set-Cookie", cookieStr) - - const cookiesHeader = res.getHeader("Set-Cookie") - const cookieName = getCookieName(cookieStr) - - if (typeof cookiesHeader !== "string" && !Array.isArray(cookiesHeader)) { - appendCookie() - return +const cookieOptions = (headers: Headers, expires: Date, httpOnly: boolean) => { + return { + path: "/", + secure: + global.sessionConfig.secureCookies && + !isLocalhost({ + headers, + } as Request), + sameSite: global.sessionConfig.sameSite, + domain: global.sessionConfig.domain, + expires: new Date(expires), + httpOnly, } +} - if (typeof cookiesHeader === "string") { - if (cookieName === getCookieName(cookiesHeader)) { - res.setHeader("Set-Cookie", cookieStr) +function replaceOrAppendValueInSetCookieHeader( + headers: Headers, + cookieName: string, + newValue: string, +): string { + const cookies = headers.get("set-cookie") + if (!cookies) return newValue + const cookiesAsArray = splitCookiesString(cookies!) + for (let i = 0; i < cookiesAsArray.length; i++) { + const cookie = cookiesAsArray[i] + if (cookie?.startsWith(cookieName)) { + cookiesAsArray[i] = newValue + return cookiesAsArray.join(", ") } else { - appendCookie() - } - } else { - for (let i = 0; i < cookiesHeader.length; i++) { - if (cookieName === getCookieName(cookiesHeader[i] || "")) { - cookiesHeader[i] = cookieStr - res.setHeader("Set-Cookie", cookiesHeader) - return + if (i === cookiesAsArray.length - 1) { + cookiesAsArray.push(newValue) + return cookiesAsArray.join(", ") } } - appendCookie() } + return cookiesAsArray.filter(Boolean).join(", ") } -const setHeader = (res: ServerResponse, name: string, value: string) => { - res.setHeader(name, value) - if ("_blitz" in res) { - ;(res as any)._blitz[name] = value - } -} - -const setSessionCookie = (res: ServerResponse, sessionToken: string, expiresAt: Date) => { - setCookie( - res, - cookie.serialize(COOKIE_SESSION_TOKEN(), sessionToken, { - path: "/", - httpOnly: true, - secure: global.sessionConfig.secureCookies, - sameSite: global.sessionConfig.sameSite, - domain: global.sessionConfig.domain, - expires: expiresAt, - }), +const setSessionCookie = (headers: Headers, sessionToken: string, expiresAt: Date) => { + const sessionCookie = cookie.serialize( + COOKIE_SESSION_TOKEN(), + sessionToken, + cookieOptions(headers, expiresAt, true), + ) + const newCookies = replaceOrAppendValueInSetCookieHeader( + headers, + COOKIE_SESSION_TOKEN(), + sessionCookie, ) + headers.set("Set-Cookie", newCookies) } -const setAnonymousSessionCookie = (res: ServerResponse, token: string, expiresAt: Date) => { - setCookie( - res, - cookie.serialize(COOKIE_ANONYMOUS_SESSION_TOKEN(), token, { - path: "/", - httpOnly: true, - secure: global.sessionConfig.secureCookies, - sameSite: global.sessionConfig.sameSite, - domain: global.sessionConfig.domain, - expires: expiresAt, - }), +const setAnonymousSessionCookie = (headers: Headers, token: string, expiresAt: Date) => { + const anonCookie = cookie.serialize( + COOKIE_ANONYMOUS_SESSION_TOKEN(), + token, + cookieOptions(headers, expiresAt, true), ) + const newCookies = replaceOrAppendValueInSetCookieHeader( + headers, + COOKIE_ANONYMOUS_SESSION_TOKEN(), + anonCookie, + ) + headers.set("Set-Cookie", newCookies) } -const setCSRFCookie = ( - req: IncomingMessage, - res: ServerResponse, - antiCSRFToken: string, - expiresAt: Date, -) => { +const setCSRFCookie = (headers: Headers, antiCSRFToken: string, expiresAt: Date) => { debug("setCSRFCookie", antiCSRFToken) assert(antiCSRFToken !== undefined, "Internal error: antiCSRFToken is being set to undefined") - setCookie( - res, - cookie.serialize(COOKIE_CSRF_TOKEN(), antiCSRFToken, { - path: "/", - secure: global.sessionConfig.secureCookies && !isLocalhost(req), - sameSite: global.sessionConfig.sameSite, - domain: global.sessionConfig.domain, - expires: expiresAt, - }), + const csrfCookie = cookie.serialize( + COOKIE_CSRF_TOKEN(), + antiCSRFToken, + cookieOptions(headers, expiresAt, false), ) + + const newCookies = replaceOrAppendValueInSetCookieHeader(headers, COOKIE_CSRF_TOKEN(), csrfCookie) + headers.set("Set-Cookie", newCookies) } -const setPublicDataCookie = ( - req: IncomingMessage, - res: ServerResponse, - publicDataToken: string, - expiresAt: Date, -) => { - setHeader(res, HEADER_PUBLIC_DATA_TOKEN, "updated") - setCookie( - res, - cookie.serialize(COOKIE_PUBLIC_DATA_TOKEN(), publicDataToken, { - path: "/", - secure: global.sessionConfig.secureCookies && !isLocalhost(req), - sameSite: global.sessionConfig.sameSite, - domain: global.sessionConfig.domain, - expires: expiresAt, - }), +const setPublicDataCookie = (headers: Headers, publicDataToken: string, expiresAt: Date) => { + headers.set(HEADER_PUBLIC_DATA_TOKEN, "updated") + const publicDataCookie = cookie.serialize( + COOKIE_PUBLIC_DATA_TOKEN(), + publicDataToken, + cookieOptions(headers, expiresAt, false), + ) + const newCookies = replaceOrAppendValueInSetCookieHeader( + headers, + COOKIE_PUBLIC_DATA_TOKEN(), + publicDataCookie, ) + headers.set("Set-Cookie", newCookies) } // -------------------------------- // Get Session // -------------------------------- -async function getSessionKernel( - req: IncomingMessage & {cookies: {[key: string]: string}}, - res: ServerResponse, -): Promise { - const anonymousSessionToken = req.cookies[COOKIE_ANONYMOUS_SESSION_TOKEN()] - const sessionToken = req.cookies[COOKIE_SESSION_TOKEN()] // for essential method - const idRefreshToken = req.cookies[COOKIE_REFRESH_TOKEN()] // for advanced method +async function getSessionKernel({ + headers, + method, +}: { + headers: Headers + method: string | undefined +}): Promise { + const cookies = getCookiesFromHeader(headers) + const anonymousSessionToken = cookies[COOKIE_ANONYMOUS_SESSION_TOKEN()] + const sessionToken = cookies[COOKIE_SESSION_TOKEN()] // for essential method + const idRefreshToken = cookies[COOKIE_REFRESH_TOKEN()] // for advanced method + const antiCSRFToken = headers.get(HEADER_CSRF) + debug("getSessionKernel", { + anonymousSessionToken, + sessionToken, + idRefreshToken, + antiCSRFToken, + }) + const enableCsrfProtection = - req.method !== "GET" && - req.method !== "OPTIONS" && - req.method !== "HEAD" && + method !== "GET" && + method !== "OPTIONS" && + method !== "HEAD" && !process.env.DANGEROUSLY_DISABLE_CSRF_PROTECTION - const antiCSRFToken = req.headers[HEADER_CSRF] as string | undefined if (sessionToken) { debug("[getSessionKernel] Request has sessionToken") @@ -698,7 +826,7 @@ async function getSessionKernel( ) } - setHeader(res, HEADER_CSRF_ERROR, "true") + headers.set(HEADER_CSRF_ERROR, "true") throw new CSRFTokenMismatchError() } @@ -710,7 +838,7 @@ async function getSessionKernel( * But only renew with non-GET requests because a GET request could be from a * browser level navigation */ - if (req.method !== "GET") { + if (method !== "GET") { // The publicData in the DB could have been updated since this client last made // a request. If so, then we generate a new access token const hasPublicDataChanged = @@ -733,8 +861,7 @@ async function getSessionKernel( if (hasPublicDataChanged || hasQuarterExpiryTimePassed) { await refreshSession( - req, - res, + headers, { handle, publicData: JSON.parse(persistedSession.publicData || ""), @@ -774,7 +901,7 @@ async function getSessionKernel( ) } - setHeader(res, HEADER_CSRF_ERROR, "true") + headers.set(HEADER_CSRF_ERROR, "true") throw new CSRFTokenMismatchError() } @@ -795,16 +922,14 @@ async function getSessionKernel( // Create Session // -------------------------------- interface CreateNewAnonSession { - req: IncomingMessage - res: ServerResponse + headers: Headers publicData: EmptyPublicData privateData?: Record anonymous: true jwtPayload?: JwtPayload } interface CreateNewAuthedSession { - req: IncomingMessage - res: ServerResponse + headers: Headers publicData: PublicData privateData?: Record anonymous: false @@ -814,7 +939,6 @@ interface CreateNewAuthedSession { async function createNewSession( args: CreateNewAnonSession | CreateNewAuthedSession, ): Promise { - const {req, res} = args assert(args.publicData.userId !== undefined, "You must provide publicData.userId") const antiCSRFToken = createAntiCSRFToken() @@ -835,12 +959,12 @@ async function createNewSession( new Date(), global.sessionConfig.anonSessionExpiryMinutes as number, ) - setAnonymousSessionCookie(res, anonymousSessionToken, expiresAt) - setCSRFCookie(req, res, antiCSRFToken, expiresAt) - setPublicDataCookie(req, res, publicDataToken, expiresAt) + setAnonymousSessionCookie(args.headers, anonymousSessionToken, expiresAt) + setCSRFCookie(args.headers, antiCSRFToken, expiresAt) + setPublicDataCookie(args.headers, publicDataToken, expiresAt) // Clear the essential session cookie in case it was previously set - setSessionCookie(res, "", new Date(0)) - setHeader(res, HEADER_SESSION_CREATED, "true") + setSessionCookie(args.headers, "", new Date(0)) + args.headers.set(HEADER_SESSION_CREATED, "true") return { handle, @@ -891,12 +1015,13 @@ async function createNewSession( privateData: JSON.stringify(newPrivateData), }) - setSessionCookie(res, sessionToken, expiresAt) - setCSRFCookie(req, res, antiCSRFToken, expiresAt) - setPublicDataCookie(req, res, publicDataToken, expiresAt) + setSessionCookie(args.headers, sessionToken, expiresAt) + debug("Session created", {handle, publicData: newPublicData, expiresAt}) + setCSRFCookie(args.headers, antiCSRFToken, expiresAt) + setPublicDataCookie(args.headers, publicDataToken, expiresAt) // Clear the anonymous session cookie in case it was previously set - setAnonymousSessionCookie(res, "", new Date(0)) - setHeader(res, HEADER_SESSION_CREATED, "true") + setAnonymousSessionCookie(args.headers, "", new Date(0)) + args.headers.set(HEADER_SESSION_CREATED, "true") return { handle, @@ -914,10 +1039,9 @@ async function createNewSession( } } -async function createAnonymousSession(req: IncomingMessage, res: ServerResponse) { +async function createAnonymousSession({headers}: {headers: Headers}) { return await createNewSession({ - req, - res, + headers, publicData: {userId: null}, anonymous: true, }) @@ -928,8 +1052,7 @@ async function createAnonymousSession(req: IncomingMessage, res: ServerResponse) // -------------------------------- async function refreshSession( - req: IncomingMessage, - res: ServerResponse, + headers: Headers, sessionKernel: SessionKernel, {publicDataChanged}: {publicDataChanged: boolean}, ) { @@ -943,8 +1066,8 @@ async function refreshSession( const publicDataToken = createPublicDataToken(sessionKernel.publicData) const expiresAt = addYears(new Date(), 30) - setAnonymousSessionCookie(res, anonymousSessionToken, expiresAt) - setPublicDataCookie(req, res, publicDataToken, expiresAt) + setAnonymousSessionCookie(headers, anonymousSessionToken, expiresAt) + setPublicDataCookie(headers, publicDataToken, expiresAt) } else if (global.sessionConfig.method === "essential" && "sessionToken" in sessionKernel) { const expiresAt = addMinutes(new Date(), global.sessionConfig.sessionExpiryMinutes as number) @@ -952,7 +1075,7 @@ async function refreshSession( if (publicDataChanged) { debug("Public data has changed") const publicDataToken = createPublicDataToken(sessionKernel.publicData) - setPublicDataCookie(req, res, publicDataToken, expiresAt) + setPublicDataCookie(headers, publicDataToken, expiresAt) await global.sessionConfig.updateSession(sessionKernel.handle, { expiresAt, publicData: JSON.stringify(sessionKernel.publicData), @@ -994,12 +1117,7 @@ async function syncPubicDataFieldsForUserIfNeeded( } } -async function revokeSession( - req: IncomingMessage, - res: ServerResponse, - handle: string, - anonymous: boolean = false, -) { +async function revokeSession(headers: Headers, handle: string, anonymous: boolean = false) { debug("Revoking session", handle) if (!anonymous) { try { @@ -1012,7 +1130,9 @@ async function revokeSession( // This fixes race condition where all client side queries get refreshed // in parallel and each creates a new anon session // https://github.com/blitz-js/blitz/issues/2746 - return createAnonymousSession(req, res) + return createAnonymousSession({ + headers, + }) } async function revokeAllSessionsForUser(userId: PublicData["userId"]) { @@ -1078,8 +1198,7 @@ async function setPrivateData(sessionKernel: SessionKernel, data: Record, ) { @@ -1091,7 +1210,7 @@ async function setPublicData( ...data, } as PublicData - await refreshSession(req, res, {...sessionKernel, publicData}, {publicDataChanged: true}) + await refreshSession(headers, {...sessionKernel, publicData}, {publicDataChanged: true}) return publicData } diff --git a/packages/blitz-auth/src/server/index.ts b/packages/blitz-auth/src/server/index.ts index 2d9326f932..7a8a8f57f0 100644 --- a/packages/blitz-auth/src/server/index.ts +++ b/packages/blitz-auth/src/server/index.ts @@ -9,8 +9,6 @@ export { getSession, isLocalhost, setPublicDataForUser, - setCookie, simpleRolesIsAuthorized, - getBlitzContext, } from "./auth-sessions" export type {AnonymousSessionPayload, SimpleRolesIsAuthorized} from "./auth-sessions" diff --git a/packages/blitz-auth/src/shared/types.ts b/packages/blitz-auth/src/shared/types.ts index 1018c37e65..e92c4d20e2 100644 --- a/packages/blitz-auth/src/shared/types.ts +++ b/packages/blitz-auth/src/shared/types.ts @@ -1,5 +1,6 @@ //@ts-nocheck -import {Ctx} from "blitz" +import type {Ctx} from "blitz" +import type {ServerResponse} from "http" export interface Session { // isAuthorize can be injected here @@ -66,6 +67,12 @@ export interface SessionContextBase { $getPrivateData: () => Promise> $setPrivateData: (data: Record) => Promise $setPublicData: (data: Partial>) => Promise + /** + * This function is only for manual session handling + * + * Instead use {@link https://blitzjs.com/docs/auth-server#with-blitz-auth-api withBlitzAuth} to handle session creation and update + */ + setSession: (res: Response | ServerResponse) => void } // Could be anonymous diff --git a/packages/blitz-next/package.json b/packages/blitz-next/package.json index 6b2f702792..450b163a32 100644 --- a/packages/blitz-next/package.json +++ b/packages/blitz-next/package.json @@ -59,7 +59,7 @@ "blitz": "2.0.10", "cross-spawn": "7.0.3", "find-up": "4.1.0", - "next": "canary", + "next": "14.3.0-canary.28", "next-router-mock": "0.9.1", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/packages/blitz-next/src/index-server.ts b/packages/blitz-next/src/index-server.ts index 123e4ba27d..a3af4c8528 100644 --- a/packages/blitz-next/src/index-server.ts +++ b/packages/blitz-next/src/index-server.ts @@ -243,6 +243,7 @@ export interface BlitzConfig extends NextConfig { } } + export function withBlitz(nextConfig: BlitzConfig = {}): NextConfig { if ( process.env.NODE_ENV !== "production" && diff --git a/packages/blitz-rpc/package.json b/packages/blitz-rpc/package.json index a90cf3e4ed..9a531bfec2 100644 --- a/packages/blitz-rpc/package.json +++ b/packages/blitz-rpc/package.json @@ -49,7 +49,7 @@ "@types/react": "18.0.25", "@types/react-dom": "17.0.14", "blitz": "2.0.10", - "next": "canary", + "next": "14.3.0-canary.28", "react": "18.2.0", "react-dom": "18.2.0", "typescript": "^4.8.4", diff --git a/packages/blitz-rpc/src/index-server.ts b/packages/blitz-rpc/src/index-server.ts index 3412ef5416..57416ef9f0 100644 --- a/packages/blitz-rpc/src/index-server.ts +++ b/packages/blitz-rpc/src/index-server.ts @@ -172,6 +172,12 @@ export function installTurboConfig() { as: "*.ts", }, }, + "**/*...blitz*/route.{jsx,tsx,js,ts}": { + default: { + loaders: [{loader: loaderServer, options: {}}], + as: "*.ts", + }, + }, "**/{queries,mutations}/**": { browser: { loaders: [ @@ -227,12 +233,12 @@ async function getResolverMap(): Promise { } interface RpcConfig { - onError?: (error: Error, ctx: Ctx) => void - formatError?: (error: Error, ctx: Ctx) => Error + onError?: (error: Error, ctx?: Ctx) => void + formatError?: (error: Error, ctx?: Ctx) => Error logging?: RpcLoggerOptions } -export function rpcHandler(config: RpcConfig) { +export function rpcHandler(config?: RpcConfig) { return async function handleRpcRequest(req: NextApiRequest, res: NextApiResponse, ctx: Ctx) { const resolverMap = await getResolverMap() assert(resolverMap, "No query or mutation resolvers found") @@ -244,7 +250,7 @@ export function rpcHandler(config: RpcConfig) { const relativeRoutePath = (req.query.blitz as string[])?.join("/") const routePath = "/" + relativeRoutePath const resolverName = routePath.replace(/(\/api\/rpc)?\//, "") - const rpcLogger = new RpcLogger(resolverName, config.logging) + const rpcLogger = new RpcLogger(resolverName, config?.logging) const loadableResolver = resolverMap?.[routePath]?.resolver if (!loadableResolver) { @@ -303,6 +309,7 @@ export function rpcHandler(config: RpcConfig) { rpcLogger.timer.initNextJsSerialization() ;(res as any).blitzResult = result + ctx?.session?.setSession(res) res.json({ result: serializedResult.json, error: null, @@ -322,16 +329,18 @@ export function rpcHandler(config: RpcConfig) { error.stack = "" } - config.onError?.(error, ctx) + config?.onError?.(error, ctx) rpcLogger.error(error) if (!error.statusCode) { error.statusCode = 500 } - const formattedError = config.formatError?.(error, ctx) ?? error + const formattedError = config?.formatError?.(error, ctx) ?? error const serializedError = superjsonSerialize(formattedError) + ctx?.session?.setSession(res) + res.json({ result: null, error: serializedError.json, @@ -349,3 +358,128 @@ export function rpcHandler(config: RpcConfig) { } } } + +type Params = Record + +export function rpcAppHandler(config?: RpcConfig) { + async function handleRpcRequest(req: Request, context: {params: Params}, ctx?: Ctx) { + const session = ctx?.session + const resolverMap = await getResolverMap() + assert(resolverMap, "No query or mutation resolvers found") + + assert( + Array.isArray(context.params.blitz), + "It seems your Blitz RPC endpoint file is not named [[...blitz]].(jt)s. Please ensure it is", + ) + + const relativeRoutePath = (context.params.blitz as string[])?.join("/") + const routePath = "/" + relativeRoutePath + const resolverName = routePath.replace(/(\/api\/rpc)?\//, "") + const rpcLogger = new RpcLogger(resolverName, config?.logging) + + const loadableResolver = resolverMap?.[routePath]?.resolver + if (!loadableResolver) { + throw new Error("No resolver for path: " + routePath) + } + + const {default: resolver, config: resolverConfig} = await loadableResolver() + + if (!resolver) { + throw new Error("No default export for resolver path: " + routePath) + } + + const resolverConfigWithDefaults = {...defaultConfig, ...resolverConfig} + + if (req.method === "HEAD") { + // We used to initiate database connection here + return new Response(null, {status: 200}) + } + + if ( + req.method === "POST" || + (req.method === "GET" && resolverConfigWithDefaults.httpMethod === "GET") + ) { + const body = await req.json() + if (req.method === "POST" && typeof body.params === "undefined") { + const error = {message: "Request body is missing the `params` key"} + rpcLogger.error(error.message) + return new Response(JSON.stringify({result: null, error}), {status: 400}) + } + + try { + const data = deserialize({ + json: + req.method === "POST" + ? body.params + : context.params.params + ? parse(`${context.params.params}`) + : undefined, + meta: + req.method === "POST" + ? body.meta?.params + : context.params.meta + ? parse(`${context.params.meta}`) + : undefined, + }) + rpcLogger.timer.initResolver() + rpcLogger.preResolver(data) + + const result = await resolver(data, {session}) + rpcLogger.timer.resolverDuration() + rpcLogger.postResolver(result) + + rpcLogger.timer.initSerialization() + const serializedResult = superjsonSerialize(result) + + rpcLogger.timer.initNextJsSerialization() + const response = new Response( + JSON.stringify({ + result: serializedResult.json, + error: null, + meta: { + result: serializedResult.meta, + }, + }), + ) + session?.setSession(response) + return response + } catch (error: any) { + if (error._clearStack) { + error.stack = "" + } + + config?.onError?.(error, {session} as Ctx) + rpcLogger.error(error) + + if (!error.statusCode) { + error.statusCode = 500 + } + + const formattedError = config?.formatError?.(error, {session} as Ctx) ?? error + const serializedError = superjsonSerialize(formattedError) + + const response = new Response( + JSON.stringify({ + result: null, + error: serializedError.json, + meta: { + error: serializedError.meta, + }, + }), + ) + session?.setSession(response) + return response + } + } else { + // Everything else is error + rpcLogger.warn(`${req.method} method not supported`) + return new Response(null, {status: 404}) + } + } + + return { + GET: handleRpcRequest, + POST: handleRpcRequest, + HEAD: handleRpcRequest, + } +} diff --git a/packages/blitz/src/cli/commands/install.ts b/packages/blitz/src/cli/commands/install.ts index be4a275cf8..db81c89703 100644 --- a/packages/blitz/src/cli/commands/install.ts +++ b/packages/blitz/src/cli/commands/install.ts @@ -3,7 +3,8 @@ import {CliCommand} from "../index" import prompts from "prompts" import {bootstrap} from "global-agent" import {baseLogger, log} from "../../logging" -const debug = require("debug")("blitz:cli") +import Debug from "debug" +const debug = Debug("blitz:cli") import {join, resolve, dirname} from "path" import {Stream} from "stream" import {promisify} from "util" diff --git a/packages/blitz/src/cli/utils/config.ts b/packages/blitz/src/cli/utils/config.ts index c709a654b5..e06e907ea8 100644 --- a/packages/blitz/src/cli/utils/config.ts +++ b/packages/blitz/src/cli/utils/config.ts @@ -4,7 +4,8 @@ import {readJSON} from "fs-extra" import path from "path" import pkgDir from "pkg-dir" import resolveCwd from "resolve-cwd" -const debug = require("debug")("blitz:utils") +import Debug from "debug" +const debug = Debug("blitz:utils") export async function resolveBinAsync(pkg: string, executable = pkg) { const packageDir = await pkgDir(resolveCwd(pkg)) diff --git a/packages/blitz/src/cli/utils/next-console.ts b/packages/blitz/src/cli/utils/next-console.ts index 613ec8738f..4d86acbe99 100644 --- a/packages/blitz/src/cli/utils/next-console.ts +++ b/packages/blitz/src/cli/utils/next-console.ts @@ -5,7 +5,8 @@ import path from "path" import * as REPL from "repl" import {REPLCommand, REPLServer} from "repl" // eslint-disable-next-line @next/next/no-assign-module-variable -const debug = require("debug")("blitz:repl") +import Debug from "debug" +const debug = Debug("blitz:repl") import ProgressBar from "progress" import {log} from "../../logging" diff --git a/packages/blitz/src/cli/utils/next-utils.ts b/packages/blitz/src/cli/utils/next-utils.ts index aa049e5d7d..d902f8088c 100644 --- a/packages/blitz/src/cli/utils/next-utils.ts +++ b/packages/blitz/src/cli/utils/next-utils.ts @@ -7,7 +7,8 @@ import * as esbuild from "esbuild" import pkgDir from "pkg-dir" import type {ServerConfig} from "./config" -const debug = require("debug")("blitz:utils") +import Debug from "debug" +const debug = Debug("blitz:utils") export function getProjectRootSync() { return process.cwd() diff --git a/packages/blitz/src/cli/utils/routes-manifest.ts b/packages/blitz/src/cli/utils/routes-manifest.ts index 651d95b68c..9e721b3534 100644 --- a/packages/blitz/src/cli/utils/routes-manifest.ts +++ b/packages/blitz/src/cli/utils/routes-manifest.ts @@ -5,7 +5,8 @@ import {outputFile, readdir, readFile} from "fs-extra" import Watchpack from "watchpack" import {findNodeModulesRoot} from "./find-node-modules" -const debug = require("debug")("blitz") +import Debug from "debug" +const debug = Debug("blitz") export const CONFIG_FILE = ".blitz.config.compiled.js" export const NEXT_CONFIG_FILE = "next.config.js" export const PHASE_PRODUCTION_SERVER = "phase-production-server" diff --git a/packages/blitz/src/index-server.ts b/packages/blitz/src/index-server.ts index 1f4db65750..0c4869a96e 100644 --- a/packages/blitz/src/index-server.ts +++ b/packages/blitz/src/index-server.ts @@ -9,7 +9,7 @@ export * from "./utils/enhance-prisma" export * from "./middleware" export * from "./paginate" export * from "./logging" -export {reduceBlitzServerPlugins} from "./plugin" +export {reduceBlitzServerPlugins, merge, pipe} from "./plugin" export {findNodeModulesRoot, findNodeModulesRootSync} from "./cli/utils/find-node-modules" export {startWatcher, stopWatcher} from "./cli/utils/routes-manifest" diff --git a/packages/blitz/src/logging.ts b/packages/blitz/src/logging.ts index 001b3bf9be..efb3058018 100644 --- a/packages/blitz/src/logging.ts +++ b/packages/blitz/src/logging.ts @@ -99,8 +99,8 @@ const branded = (msg: string) => { * @param {string} msg */ const clearLine = (msg?: string) => { - readline.clearLine(process.stdout, 0) - readline.cursorTo(process.stdout, 0) + readline.clearLine(process.stdout as any, 0) + readline.cursorTo(process.stdout as any, 0) msg && process.stdout.write(msg) } @@ -173,7 +173,8 @@ const box = async (mes: string, title: string) => { * If the DEBUG env var is set this will write to the console * @param str msg */ -const debug = require("debug")("blitz") +import Debug from "debug" +const debug = Debug("blitz") export const log = { withBrand, diff --git a/packages/generator/src/generators/app-generator.ts b/packages/generator/src/generators/app-generator.ts index 8f0e0cb39b..c72d4d3ea4 100644 --- a/packages/generator/src/generators/app-generator.ts +++ b/packages/generator/src/generators/app-generator.ts @@ -68,11 +68,15 @@ export class AppGenerator extends Generator { this.destinationPath("package.json"), ) - const rpcEndpointPath = `src/pages/api/rpc/blitzrpcroute.${this.options.useTs ? "ts" : "js"}` + const rpcEndpointPath = `src/app/api/rpc/blitzrpcroute/route.${ + this.options.useTs ? "ts" : "js" + }` if (this.fs.exists(rpcEndpointPath)) { this.fs.move( this.destinationPath(rpcEndpointPath), - this.destinationPath(`src/pages/api/rpc/[[...blitz]].${this.options.useTs ? "ts" : "js"}`), + this.destinationPath( + `src/app/api/rpc/[[...blitz]]/route.${this.options.useTs ? "ts" : "js"}`, + ), ) } diff --git a/packages/generator/templates/app/.editorconfig b/packages/generator/templates/app/.editorconfig deleted file mode 100644 index 09d7a33a4f..0000000000 --- a/packages/generator/templates/app/.editorconfig +++ /dev/null @@ -1,11 +0,0 @@ -# https://EditorConfig.org - -root = true - -[*] -charset = utf-8 -end_of_line = lf -indent_size = 2 -indent_style = space -insert_final_newline = true -trim_trailing_whitespace = true diff --git a/packages/generator/templates/app/src/app/api/rpc/blitzrpcroute/route.ts b/packages/generator/templates/app/src/app/api/rpc/blitzrpcroute/route.ts new file mode 100644 index 0000000000..16fdf81665 --- /dev/null +++ b/packages/generator/templates/app/src/app/api/rpc/blitzrpcroute/route.ts @@ -0,0 +1,4 @@ +import {rpcAppHandler} from "@blitzjs/rpc" +import {withBlitzAuth} from "src/app/blitz-server" + +export const {GET, HEAD, POST} = withBlitzAuth(rpcAppHandler()) diff --git a/packages/generator/templates/app/src/app/blitz-server.ts b/packages/generator/templates/app/src/app/blitz-server.ts index 2957df8fd3..6c42fcbb25 100644 --- a/packages/generator/templates/app/src/app/blitz-server.ts +++ b/packages/generator/templates/app/src/app/blitz-server.ts @@ -5,7 +5,7 @@ import {BlitzLogger} from "blitz" import {RpcServerPlugin} from "@blitzjs/rpc" import {authConfig} from "./blitz-auth-config" -const {api, getBlitzContext, useAuthenticatedBlitzContext, invoke} = setupBlitzServer({ +const {api, getBlitzContext, useAuthenticatedBlitzContext, invoke,withBlitzAuth} = setupBlitzServer({ plugins: [ AuthServerPlugin({ ...authConfig, @@ -17,4 +17,4 @@ const {api, getBlitzContext, useAuthenticatedBlitzContext, invoke} = setupBlitzS logger: BlitzLogger({}), }) -export {api, getBlitzContext, useAuthenticatedBlitzContext, invoke} +export {api, getBlitzContext, useAuthenticatedBlitzContext, invoke,withBlitzAuth} diff --git a/packages/generator/templates/app/src/pages/api/rpc/blitzrpcroute.ts b/packages/generator/templates/app/src/pages/api/rpc/blitzrpcroute.ts deleted file mode 100644 index 5fcde42f38..0000000000 --- a/packages/generator/templates/app/src/pages/api/rpc/blitzrpcroute.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Note: This stays in the /pages folder for the time being - -import { rpcHandler } from "@blitzjs/rpc" -import { api } from "src/app/blitz-server" - -export default api(rpcHandler({ onError: (error, ctx) => console.log(error) })) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bfb8f35ab5..37f71443c7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,6 +6,7 @@ settings: overrides: "@types/mime": 3.0.4 + next: 14.3.0-canary.28 patchedDependencies: next-auth@4.24.7: @@ -34,20 +35,20 @@ importers: specifier: 13.0.3 version: 13.0.3 next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) only-allow: specifier: 1.1.0 version: 1.1.0 prettier: - specifier: ^2.7.1 - version: 2.7.1 + specifier: ^2.8.8 + version: 2.8.8 prettier-plugin-prisma: specifier: 4.4.0 - version: 4.4.0(prettier@2.7.1) + version: 4.4.0(prettier@2.8.8) pretty-quick: specifier: 3.1.3 - version: 3.1.3(prettier@2.7.1) + version: 3.1.3(prettier@2.8.8) turbo: specifier: 1.10.9 version: 1.10.9 @@ -91,8 +92,8 @@ importers: specifier: 3.2.7 version: 3.2.7 next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) prisma: specifier: ^4.5.0 version: 4.6.1 @@ -158,8 +159,8 @@ importers: specifier: 2.0.10 version: link:../../packages/blitz next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0) next-auth: specifier: 4.24.7 version: 4.24.7(patch_hash=xxwv3g3ul7bnzqsfasefw3kyq4)(next@14.2.0-canary.51)(react-dom@18.2.0)(react@18.2.0) @@ -276,8 +277,8 @@ importers: specifier: 2.0.10 version: link:../../packages/blitz next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) openid-client: specifier: 5.2.1 version: 5.2.1 @@ -394,8 +395,8 @@ importers: specifier: 29.3.0 version: 29.3.0 next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) passport-mock-strategy: specifier: 2.0.0 version: 2.0.0 @@ -449,8 +450,8 @@ importers: specifier: 3.0.0 version: 3.0.0 next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) prisma: specifier: 4.6.1 version: 4.6.1 @@ -540,8 +541,8 @@ importers: specifier: 5.0.0 version: 5.0.0 next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0) prisma: specifier: 4.6.1 version: 4.6.1 @@ -652,8 +653,8 @@ importers: specifier: 3.0.0 version: 3.0.0 next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) prisma: specifier: 4.6.1 version: 4.6.1 @@ -716,8 +717,8 @@ importers: specifier: 2.0.10 version: link:../../packages/blitz next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) react: specifier: 18.2.0 version: 18.2.0 @@ -780,8 +781,8 @@ importers: specifier: 3.0.0 version: 3.0.0 next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) prisma: specifier: 4.6.1 version: 4.6.1 @@ -836,10 +837,10 @@ importers: version: 1.28.0 ts-node: specifier: 10.9.1 - version: 10.9.1(@types/node@18.7.13)(typescript@4.8.4) + version: 10.9.1(@types/node@18.7.13)(typescript@4.9.5) typescript: - specifier: ^4.8.4 - version: 4.8.4 + specifier: ^4.9.5 + version: 4.9.5 integration-tests/no-suspense: dependencies: @@ -862,8 +863,8 @@ importers: specifier: 3.0.0 version: 3.0.0 next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) prisma: specifier: 4.6.1 version: 4.6.1 @@ -935,8 +936,8 @@ importers: specifier: 2.0.10 version: link:../../packages/blitz next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.18.2)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.18.2)(react-dom@18.2.0)(react@18.2.0) prisma: specifier: 4.6.1 version: 4.6.1 @@ -993,8 +994,8 @@ importers: specifier: 3.0.0 version: 3.0.0 next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) prisma: specifier: 4.6.1 version: 4.6.1 @@ -1057,8 +1058,8 @@ importers: specifier: 2.0.10 version: link:../../packages/blitz next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) react: specifier: 18.2.0 version: 18.2.0 @@ -1106,8 +1107,8 @@ importers: specifier: 2.0.10 version: link:../../packages/blitz next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) react: specifier: 18.2.0 version: 18.2.0 @@ -1161,8 +1162,8 @@ importers: specifier: 3.0.0 version: 3.0.0 next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0) prisma: specifier: 4.6.1 version: 4.6.1 @@ -1617,8 +1618,8 @@ importers: specifier: 2.0.10 version: link:../blitz next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0) next-auth: specifier: 4.24.7 version: 4.24.7(patch_hash=xxwv3g3ul7bnzqsfasefw3kyq4)(next@14.2.0-canary.51)(react-dom@18.2.0)(react@18.2.0) @@ -1711,11 +1712,11 @@ importers: specifier: 4.1.0 version: 4.1.0 next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0) next-router-mock: specifier: 0.9.1 - version: 0.9.1(next@14.2.0-canary.51)(react@18.2.0) + version: 0.9.1(next@14.3.0-canary.28)(react@18.2.0) react: specifier: 18.2.0 version: 18.2.0 @@ -1790,8 +1791,8 @@ importers: specifier: 2.0.10 version: link:../blitz next: - specifier: canary - version: 14.2.0-canary.51(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.3.0-canary.28 + version: 14.3.0-canary.28(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0) react: specifier: 18.2.0 version: 18.2.0 @@ -2628,22 +2629,6 @@ packages: semver: 6.3.1 dev: false - /@babel/helper-compilation-targets@7.20.0(@babel/core@7.18.2): - resolution: - { - integrity: sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==, - } - engines: {node: ">=6.9.0"} - peerDependencies: - "@babel/core": ^7.0.0 - dependencies: - "@babel/compat-data": 7.20.1 - "@babel/core": 7.18.2(supports-color@8.1.1) - "@babel/helper-validator-option": 7.18.6 - browserslist: 4.21.4 - semver: 6.3.1 - dev: false - /@babel/helper-compilation-targets@7.20.0(@babel/core@7.20.2): resolution: { @@ -3193,7 +3178,7 @@ packages: "@babel/core": ^7.0.0-0 dependencies: "@babel/core": 7.12.10 - "@babel/helper-plugin-utils": 7.17.12 + "@babel/helper-plugin-utils": 7.20.2 "@babel/helper-remap-async-to-generator": 7.16.8(supports-color@8.1.1) "@babel/plugin-syntax-async-generators": 7.8.4(@babel/core@7.12.10) transitivePeerDependencies: @@ -3753,19 +3738,6 @@ packages: "@babel/helper-plugin-utils": 7.17.12 dev: false - /@babel/plugin-syntax-flow@7.17.12(@babel/core@7.18.2): - resolution: - { - integrity: sha512-B8QIgBvkIG6G2jgsOHQUist7Sm0EBLDCx8sen072IwqNuzMegZNXrYnSv77cYzA8mLDZAfQYqsLIhimiP1s2HQ==, - } - engines: {node: ">=6.9.0"} - peerDependencies: - "@babel/core": ^7.0.0-0 - dependencies: - "@babel/core": 7.18.2(supports-color@8.1.1) - "@babel/helper-plugin-utils": 7.17.12 - dev: false - /@babel/plugin-syntax-flow@7.17.12(@babel/core@7.20.2): resolution: { @@ -4050,19 +4022,6 @@ packages: "@babel/core": 7.12.10 "@babel/helper-plugin-utils": 7.17.12 - /@babel/plugin-syntax-typescript@7.17.12(@babel/core@7.18.2): - resolution: - { - integrity: sha512-TYY0SXFiO31YXtNg3HtFwNJHjLsAyIIhAhNWkQ5whPPS7HWUFlg9z0Ta4qAQNjQbP1wsSt/oKkmZ/4/WWdMUpw==, - } - engines: {node: ">=6.9.0"} - peerDependencies: - "@babel/core": ^7.0.0-0 - dependencies: - "@babel/core": 7.18.2(supports-color@8.1.1) - "@babel/helper-plugin-utils": 7.17.12 - dev: false - /@babel/plugin-syntax-typescript@7.17.12(@babel/core@7.20.2): resolution: { @@ -4395,20 +4354,6 @@ packages: "@babel/helper-plugin-utils": 7.17.12 dev: false - /@babel/plugin-transform-flow-strip-types@7.17.12(@babel/core@7.18.2): - resolution: - { - integrity: sha512-g8cSNt+cHCpG/uunPQELdq/TeV3eg1OLJYwxypwHtAWo9+nErH3lQx9CSO2uI9lF74A0mR0t4KoMjs1snSgnTw==, - } - engines: {node: ">=6.9.0"} - peerDependencies: - "@babel/core": ^7.0.0-0 - dependencies: - "@babel/core": 7.18.2(supports-color@8.1.1) - "@babel/helper-plugin-utils": 7.17.12 - "@babel/plugin-syntax-flow": 7.17.12(@babel/core@7.18.2) - dev: false - /@babel/plugin-transform-flow-strip-types@7.17.12(@babel/core@7.20.2): resolution: { @@ -5207,23 +5152,6 @@ packages: - supports-color dev: false - /@babel/plugin-transform-typescript@7.18.4(@babel/core@7.18.2)(supports-color@8.1.1): - resolution: - { - integrity: sha512-l4vHuSLUajptpHNEOUDEGsnpl9pfRLsN1XUoDQDD/YBuXTM+v37SHGS+c6n4jdcZy96QtuUuSvZYMLSSsjH8Mw==, - } - engines: {node: ">=6.9.0"} - peerDependencies: - "@babel/core": ^7.0.0-0 - dependencies: - "@babel/core": 7.18.2(supports-color@8.1.1) - "@babel/helper-create-class-features-plugin": 7.18.0(@babel/core@7.18.2)(supports-color@8.1.1) - "@babel/helper-plugin-utils": 7.17.12 - "@babel/plugin-syntax-typescript": 7.17.12(@babel/core@7.18.2) - transitivePeerDependencies: - - supports-color - dev: false - /@babel/plugin-transform-typescript@7.18.4(@babel/core@7.20.2)(supports-color@8.1.1): resolution: { @@ -5458,12 +5386,12 @@ packages: peerDependencies: "@babel/core": ^7.0.0-0 dependencies: - "@babel/compat-data": 7.20.1 + "@babel/compat-data": 7.17.10 "@babel/core": 7.18.2(supports-color@8.1.1) - "@babel/helper-compilation-targets": 7.20.0(@babel/core@7.18.2) - "@babel/helper-module-imports": 7.18.6 - "@babel/helper-plugin-utils": 7.20.2 - "@babel/helper-validator-option": 7.18.6 + "@babel/helper-compilation-targets": 7.18.2(@babel/core@7.18.2) + "@babel/helper-module-imports": 7.16.7 + "@babel/helper-plugin-utils": 7.17.12 + "@babel/helper-validator-option": 7.16.7 "@babel/plugin-proposal-async-generator-functions": 7.17.12(@babel/core@7.18.2)(supports-color@8.1.1) "@babel/plugin-proposal-class-properties": 7.17.12(@babel/core@7.18.2)(supports-color@8.1.1) "@babel/plugin-proposal-dynamic-import": 7.16.7(@babel/core@7.18.2) @@ -5522,28 +5450,13 @@ packages: "@babel/plugin-transform-unicode-escapes": 7.16.7(@babel/core@7.18.2) "@babel/plugin-transform-unicode-regex": 7.16.7(@babel/core@7.18.2) "@babel/preset-modules": 0.1.5(@babel/core@7.18.2) - "@babel/types": 7.12.10 + "@babel/types": 7.17.12 core-js-compat: 3.22.5 semver: 5.7.1 transitivePeerDependencies: - supports-color dev: false - /@babel/preset-flow@7.17.12(@babel/core@7.18.2): - resolution: - { - integrity: sha512-7QDz7k4uiaBdu7N89VKjUn807pJRXmdirQu0KyR9LXnQrr5Jt41eIMKTS7ljej+H29erwmMrwq9Io9mJHLI3Lw==, - } - engines: {node: ">=6.9.0"} - peerDependencies: - "@babel/core": ^7.0.0-0 - dependencies: - "@babel/core": 7.18.2(supports-color@8.1.1) - "@babel/helper-plugin-utils": 7.17.12 - "@babel/helper-validator-option": 7.16.7 - "@babel/plugin-transform-flow-strip-types": 7.17.12(@babel/core@7.18.2) - dev: false - /@babel/preset-flow@7.17.12(@babel/core@7.20.2): resolution: { @@ -5590,24 +5503,7 @@ packages: esutils: 2.0.3 dev: false - /@babel/preset-typescript@7.17.12(@babel/core@7.18.2)(supports-color@8.1.1): - resolution: - { - integrity: sha512-S1ViF8W2QwAKUGJXxP9NAfNaqGDdEBJKpYkxHf5Yy2C4NPPzXGeR3Lhk7G8xJaaLcFTRfNjVbtbVtm8Gb0mqvg==, - } - engines: {node: ">=6.9.0"} - peerDependencies: - "@babel/core": ^7.0.0-0 - dependencies: - "@babel/core": 7.18.2(supports-color@8.1.1) - "@babel/helper-plugin-utils": 7.17.12 - "@babel/helper-validator-option": 7.16.7 - "@babel/plugin-transform-typescript": 7.18.4(@babel/core@7.18.2)(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - dev: false - - /@babel/preset-typescript@7.17.12(@babel/core@7.20.2): + /@babel/preset-typescript@7.17.12(@babel/core@7.20.2)(supports-color@8.1.1): resolution: { integrity: sha512-S1ViF8W2QwAKUGJXxP9NAfNaqGDdEBJKpYkxHf5Yy2C4NPPzXGeR3Lhk7G8xJaaLcFTRfNjVbtbVtm8Gb0mqvg==, @@ -5624,23 +5520,6 @@ packages: - supports-color dev: false - /@babel/register@7.17.7(@babel/core@7.18.2): - resolution: - { - integrity: sha512-fg56SwvXRifootQEDQAu1mKdjh5uthPzdO0N6t358FktfL4XjAVXuH58ULoiW8mesxiOgNIrxiImqEwv0+hRRA==, - } - engines: {node: ">=6.9.0"} - peerDependencies: - "@babel/core": ^7.0.0-0 - dependencies: - "@babel/core": 7.18.2(supports-color@8.1.1) - clone-deep: 4.0.1 - find-cache-dir: 2.1.0 - make-dir: 2.1.0 - pirates: 4.0.5 - source-map-support: 0.5.21 - dev: false - /@babel/register@7.17.7(@babel/core@7.20.2): resolution: { @@ -6099,6 +5978,16 @@ packages: } dev: true + /@emnapi/runtime@1.2.0: + resolution: + { + integrity: sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==, + } + requiresBuild: true + dependencies: + tslib: 2.4.0 + optional: true + /@esbuild/android-arm@0.15.15: resolution: { @@ -6208,6 +6097,291 @@ packages: integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==, } + /@img/sharp-darwin-arm64@0.33.4: + resolution: + { + integrity: sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==, + } + engines: + { + glibc: ">=2.26", + node: ^18.17.0 || ^20.3.0 || >=21.0.0, + npm: ">=9.6.5", + pnpm: ">=7.1.0", + yarn: ">=3.2.0", + } + cpu: [arm64] + os: [darwin] + requiresBuild: true + optionalDependencies: + "@img/sharp-libvips-darwin-arm64": 1.0.2 + optional: true + + /@img/sharp-darwin-x64@0.33.4: + resolution: + { + integrity: sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==, + } + engines: + { + glibc: ">=2.26", + node: ^18.17.0 || ^20.3.0 || >=21.0.0, + npm: ">=9.6.5", + pnpm: ">=7.1.0", + yarn: ">=3.2.0", + } + cpu: [x64] + os: [darwin] + requiresBuild: true + optionalDependencies: + "@img/sharp-libvips-darwin-x64": 1.0.2 + optional: true + + /@img/sharp-libvips-darwin-arm64@1.0.2: + resolution: + { + integrity: sha512-tcK/41Rq8IKlSaKRCCAuuY3lDJjQnYIW1UXU1kxcEKrfL8WR7N6+rzNoOxoQRJWTAECuKwgAHnPvqXGN8XfkHA==, + } + engines: {macos: ">=11", npm: ">=9.6.5", pnpm: ">=7.1.0", yarn: ">=3.2.0"} + cpu: [arm64] + os: [darwin] + requiresBuild: true + optional: true + + /@img/sharp-libvips-darwin-x64@1.0.2: + resolution: + { + integrity: sha512-Ofw+7oaWa0HiiMiKWqqaZbaYV3/UGL2wAPeLuJTx+9cXpCRdvQhCLG0IH8YGwM0yGWGLpsF4Su9vM1o6aer+Fw==, + } + engines: {macos: ">=10.13", npm: ">=9.6.5", pnpm: ">=7.1.0", yarn: ">=3.2.0"} + cpu: [x64] + os: [darwin] + requiresBuild: true + optional: true + + /@img/sharp-libvips-linux-arm64@1.0.2: + resolution: + { + integrity: sha512-x7kCt3N00ofFmmkkdshwj3vGPCnmiDh7Gwnd4nUwZln2YjqPxV1NlTyZOvoDWdKQVDL911487HOueBvrpflagw==, + } + engines: {glibc: ">=2.26", npm: ">=9.6.5", pnpm: ">=7.1.0", yarn: ">=3.2.0"} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + + /@img/sharp-libvips-linux-arm@1.0.2: + resolution: + { + integrity: sha512-iLWCvrKgeFoglQxdEwzu1eQV04o8YeYGFXtfWU26Zr2wWT3q3MTzC+QTCO3ZQfWd3doKHT4Pm2kRmLbupT+sZw==, + } + engines: {glibc: ">=2.28", npm: ">=9.6.5", pnpm: ">=7.1.0", yarn: ">=3.2.0"} + cpu: [arm] + os: [linux] + requiresBuild: true + optional: true + + /@img/sharp-libvips-linux-s390x@1.0.2: + resolution: + { + integrity: sha512-cmhQ1J4qVhfmS6szYW7RT+gLJq9dH2i4maq+qyXayUSn9/3iY2ZeWpbAgSpSVbV2E1JUL2Gg7pwnYQ1h8rQIog==, + } + engines: {glibc: ">=2.28", npm: ">=9.6.5", pnpm: ">=7.1.0", yarn: ">=3.2.0"} + cpu: [s390x] + os: [linux] + requiresBuild: true + optional: true + + /@img/sharp-libvips-linux-x64@1.0.2: + resolution: + { + integrity: sha512-E441q4Qdb+7yuyiADVi5J+44x8ctlrqn8XgkDTwr4qPJzWkaHwD489iZ4nGDgcuya4iMN3ULV6NwbhRZJ9Z7SQ==, + } + engines: {glibc: ">=2.26", npm: ">=9.6.5", pnpm: ">=7.1.0", yarn: ">=3.2.0"} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@img/sharp-libvips-linuxmusl-arm64@1.0.2: + resolution: + { + integrity: sha512-3CAkndNpYUrlDqkCM5qhksfE+qSIREVpyoeHIU6jd48SJZViAmznoQQLAv4hVXF7xyUB9zf+G++e2v1ABjCbEQ==, + } + engines: {musl: ">=1.2.2", npm: ">=9.6.5", pnpm: ">=7.1.0", yarn: ">=3.2.0"} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + + /@img/sharp-libvips-linuxmusl-x64@1.0.2: + resolution: + { + integrity: sha512-VI94Q6khIHqHWNOh6LLdm9s2Ry4zdjWJwH56WoiJU7NTeDwyApdZZ8c+SADC8OH98KWNQXnE01UdJ9CSfZvwZw==, + } + engines: {musl: ">=1.2.2", npm: ">=9.6.5", pnpm: ">=7.1.0", yarn: ">=3.2.0"} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@img/sharp-linux-arm64@0.33.4: + resolution: + { + integrity: sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==, + } + engines: + { + glibc: ">=2.26", + node: ^18.17.0 || ^20.3.0 || >=21.0.0, + npm: ">=9.6.5", + pnpm: ">=7.1.0", + yarn: ">=3.2.0", + } + cpu: [arm64] + os: [linux] + requiresBuild: true + optionalDependencies: + "@img/sharp-libvips-linux-arm64": 1.0.2 + optional: true + + /@img/sharp-linux-arm@0.33.4: + resolution: + { + integrity: sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==, + } + engines: + { + glibc: ">=2.28", + node: ^18.17.0 || ^20.3.0 || >=21.0.0, + npm: ">=9.6.5", + pnpm: ">=7.1.0", + yarn: ">=3.2.0", + } + cpu: [arm] + os: [linux] + requiresBuild: true + optionalDependencies: + "@img/sharp-libvips-linux-arm": 1.0.2 + optional: true + + /@img/sharp-linux-s390x@0.33.4: + resolution: + { + integrity: sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==, + } + engines: + { + glibc: ">=2.31", + node: ^18.17.0 || ^20.3.0 || >=21.0.0, + npm: ">=9.6.5", + pnpm: ">=7.1.0", + yarn: ">=3.2.0", + } + cpu: [s390x] + os: [linux] + requiresBuild: true + optionalDependencies: + "@img/sharp-libvips-linux-s390x": 1.0.2 + optional: true + + /@img/sharp-linux-x64@0.33.4: + resolution: + { + integrity: sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==, + } + engines: + { + glibc: ">=2.26", + node: ^18.17.0 || ^20.3.0 || >=21.0.0, + npm: ">=9.6.5", + pnpm: ">=7.1.0", + yarn: ">=3.2.0", + } + cpu: [x64] + os: [linux] + requiresBuild: true + optionalDependencies: + "@img/sharp-libvips-linux-x64": 1.0.2 + optional: true + + /@img/sharp-linuxmusl-arm64@0.33.4: + resolution: + { + integrity: sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==, + } + engines: + { + musl: ">=1.2.2", + node: ^18.17.0 || ^20.3.0 || >=21.0.0, + npm: ">=9.6.5", + pnpm: ">=7.1.0", + yarn: ">=3.2.0", + } + cpu: [arm64] + os: [linux] + requiresBuild: true + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64": 1.0.2 + optional: true + + /@img/sharp-linuxmusl-x64@0.33.4: + resolution: + { + integrity: sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==, + } + engines: + { + musl: ">=1.2.2", + node: ^18.17.0 || ^20.3.0 || >=21.0.0, + npm: ">=9.6.5", + pnpm: ">=7.1.0", + yarn: ">=3.2.0", + } + cpu: [x64] + os: [linux] + requiresBuild: true + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64": 1.0.2 + optional: true + + /@img/sharp-wasm32@0.33.4: + resolution: + { + integrity: sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==, + } + engines: + {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: ">=9.6.5", pnpm: ">=7.1.0", yarn: ">=3.2.0"} + cpu: [wasm32] + requiresBuild: true + dependencies: + "@emnapi/runtime": 1.2.0 + optional: true + + /@img/sharp-win32-ia32@0.33.4: + resolution: + { + integrity: sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==, + } + engines: + {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: ">=9.6.5", pnpm: ">=7.1.0", yarn: ">=3.2.0"} + cpu: [ia32] + os: [win32] + requiresBuild: true + optional: true + + /@img/sharp-win32-x64@0.33.4: + resolution: + { + integrity: sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==, + } + engines: + {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: ">=9.6.5", pnpm: ">=7.1.0", yarn: ">=3.2.0"} + cpu: [x64] + os: [win32] + requiresBuild: true + optional: true + /@istanbuljs/load-nyc-config@1.1.0: resolution: { @@ -6876,10 +7050,10 @@ packages: - utf-8-validate dev: true - /@next/env@14.2.0-canary.51: + /@next/env@14.3.0-canary.28: resolution: { - integrity: sha512-f8X3gsAV7kfh+yUK10zksWpmuK+BhDgaM/jONIb0nyR+h2zZ3X8n4xi5aDd6vzUHV2OFN9obLO5lQgjXSsKNtg==, + integrity: sha512-pq8MtYZnPW7BL0nhMMwCRzQ48QYPiNj6yOYfEJmQ+Egv+rU76Lg+k7FT/kHK2soNX7dbk+K58Ywf7LD+PPTNEA==, } /@next/eslint-plugin-next@12.3.1: @@ -6908,10 +7082,10 @@ packages: glob: 7.1.7 dev: true - /@next/swc-darwin-arm64@14.2.0-canary.51: + /@next/swc-darwin-arm64@14.3.0-canary.28: resolution: { - integrity: sha512-Q3m+FnDKHnENuJvmLSKCBjRc7xicndPnyI6W5dJlKeQhP+fD60zI6EEcMVou1NYM9TpJPKBnRTHqyW5xkg7OtQ==, + integrity: sha512-jrdaB9s2p0D2vGaqze/gRTM/CWcxFKDIJrARQd/gfbtzP3orYPODfpbs3BxLxPBR+iKWYVHWYFkiRE9r876uVA==, } engines: {node: ">= 10"} cpu: [arm64] @@ -6919,10 +7093,10 @@ packages: requiresBuild: true optional: true - /@next/swc-darwin-x64@14.2.0-canary.51: + /@next/swc-darwin-x64@14.3.0-canary.28: resolution: { - integrity: sha512-dOB+vxqzQw1d0yrdFawsdlieOXXbVTBeRXaZpEuoloiqHop41t4zlDChe5VE0XxDLOO/1nCwS8ET5TDPkGRRCw==, + integrity: sha512-qf82UMWsw52XK9H0XYrt4sKBnYxNGPRZVyTVIMFFeEUVGZBE5irUdWK7qJ9ej278jmDfGwtkyU09ptAfa9nt0A==, } engines: {node: ">= 10"} cpu: [x64] @@ -6930,10 +7104,10 @@ packages: requiresBuild: true optional: true - /@next/swc-linux-arm64-gnu@14.2.0-canary.51: + /@next/swc-linux-arm64-gnu@14.3.0-canary.28: resolution: { - integrity: sha512-ZAhoaWoEGywbUbOzoiWN7MHEv39TNaiaBvSrMk9OBndsXSDIThciV/6uQ4U4ruxS7kBkimjdMppspOEsPUmeWQ==, + integrity: sha512-UigFFnzhzgev/qpWmvneaJOwKK2mwynU4lg04iJFv0xrIqCZry+R/63c7H1gjs/eX0R9ZusOov7A5QEzPnJHoQ==, } engines: {node: ">= 10"} cpu: [arm64] @@ -6941,10 +7115,10 @@ packages: requiresBuild: true optional: true - /@next/swc-linux-arm64-musl@14.2.0-canary.51: + /@next/swc-linux-arm64-musl@14.3.0-canary.28: resolution: { - integrity: sha512-7KDiUfydVlP7rXmPEUY2ikq2sT044GU+y1sAYy/hoLJFK29k324wJwjOJHc/9nnh4kzzf4UqMxolfCjAUT2XTg==, + integrity: sha512-y6Dhsfw8qKQDuM5gQRCApZG0hEGFs2yu6GDUDqr3j8QbnHontJwtzhLwspq2CbYY4KsXJiw5sTRwhITAJDeibA==, } engines: {node: ">= 10"} cpu: [arm64] @@ -6952,10 +7126,10 @@ packages: requiresBuild: true optional: true - /@next/swc-linux-x64-gnu@14.2.0-canary.51: + /@next/swc-linux-x64-gnu@14.3.0-canary.28: resolution: { - integrity: sha512-1XJqG/JAus1uSITsID0yOgSGxnuEubeB2rdZUkhO2xoolm2V3ceae+VvSfR6undTc/y+TG/uZMQbpt9n1T6dDg==, + integrity: sha512-9UxI4iPjF8mJJ64WM7ngEe80S8AIs2G+5dGMNdeo37pmaVM9CjvAK3qfmLuS0kbWkuOQXtk5tveVKjvDggEv/Q==, } engines: {node: ">= 10"} cpu: [x64] @@ -6963,10 +7137,10 @@ packages: requiresBuild: true optional: true - /@next/swc-linux-x64-musl@14.2.0-canary.51: + /@next/swc-linux-x64-musl@14.3.0-canary.28: resolution: { - integrity: sha512-W5y1+Ujv88Y2XJOdpgTQLVvyRSHRVMcNvR0nYWAGq9laCFi1YiUG7jafXCsU2qcgAdZFflJZITv3C1Hwd/IrlA==, + integrity: sha512-ouhg8s/IBhdr3sa2p3Ps3fxeyzjIhoy+xo9yzP5y9yKeU2pvPPBW2EthOP9HK+hVBRKRE/haTimr4dkhn97XGQ==, } engines: {node: ">= 10"} cpu: [x64] @@ -6974,10 +7148,10 @@ packages: requiresBuild: true optional: true - /@next/swc-win32-arm64-msvc@14.2.0-canary.51: + /@next/swc-win32-arm64-msvc@14.3.0-canary.28: resolution: { - integrity: sha512-60XzQoM3/DkEl5X4xcarwFnKRR69ROcLAQ8keTVeqSfRVWIIhYgryQAW2V7O9ggLY/5qe1OxtntpCp4PHYZLKg==, + integrity: sha512-pGC6y7aHPVyEeD6iDbVnG8Wn3UmkWoRRlEdMzWx/8GpEBpXg10IiGnoa6K6v1lw9uowhvBJ7ciGGH3sYLoIKRw==, } engines: {node: ">= 10"} cpu: [arm64] @@ -6985,10 +7159,10 @@ packages: requiresBuild: true optional: true - /@next/swc-win32-ia32-msvc@14.2.0-canary.51: + /@next/swc-win32-ia32-msvc@14.3.0-canary.28: resolution: { - integrity: sha512-H9N6Y5Z8dvHBUDh0plrjBCEa9VY4OUtdH29njJWHD0pc/LNWCKkPN+aKUq3evsiTi5E1zrFa19mulQYEd0gM4g==, + integrity: sha512-RFUFCotHnl13z4vdKBCA3T9RQuhQs3+axEdqWAURKt4fpbH5IPPR5ds4GzSmWYZQQO2FAj5EZTlwT0bL9IWqRA==, } engines: {node: ">= 10"} cpu: [ia32] @@ -6996,10 +7170,10 @@ packages: requiresBuild: true optional: true - /@next/swc-win32-x64-msvc@14.2.0-canary.51: + /@next/swc-win32-x64-msvc@14.3.0-canary.28: resolution: { - integrity: sha512-f4DoFhCy9dQ++PLC+YN9EnnbRKXYaiEjKE3minxaOHepRALj53uuxlNeYQwFxjmvXmXj8ZY1DpiB9ifYwfiUNA==, + integrity: sha512-gaf0/jxRNsXiEj+4yC9Wbj/M4Waz/kB7fbhQhsIdN60edSjCcyN8MbTnRhrN37gkfKAAI5xqnsg+eEczco0VBQ==, } engines: {node: ">= 10"} cpu: [x64] @@ -7526,19 +7700,12 @@ packages: "@swc/core-win32-x64-msvc": 1.3.7 dev: false - /@swc/counter@0.1.3: - resolution: - { - integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==, - } - - /@swc/helpers@0.5.5: + /@swc/helpers@0.5.11: resolution: { - integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==, + integrity: sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==, } dependencies: - "@swc/counter": 0.1.3 tslib: 2.4.0 /@swc/wasm@1.2.122: @@ -9973,17 +10140,6 @@ packages: dependencies: base-64: 0.1.0 - /babel-core@7.0.0-bridge.0(@babel/core@7.18.2): - resolution: - { - integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==, - } - peerDependencies: - "@babel/core": ^7.0.0-0 - dependencies: - "@babel/core": 7.18.2(supports-color@8.1.1) - dev: false - /babel-core@7.0.0-bridge.0(@babel/core@7.20.2): resolution: { @@ -11012,6 +11168,29 @@ packages: integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, } + /color-string@1.9.1: + resolution: + { + integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==, + } + requiresBuild: true + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + optional: true + + /color@4.2.3: + resolution: + { + integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==, + } + engines: {node: ">=12.5.0"} + requiresBuild: true + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + optional: true + /colorette@2.0.17: resolution: { @@ -11806,6 +11985,15 @@ packages: engines: {node: ">=8"} dev: false + /detect-libc@2.0.3: + resolution: + { + integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==, + } + engines: {node: ">=8"} + requiresBuild: true + optional: true + /detect-newline@3.1.0: resolution: { @@ -15759,6 +15947,14 @@ packages: integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==, } + /is-arrayish@0.3.2: + resolution: + { + integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==, + } + requiresBuild: true + optional: true + /is-async-function@2.0.0: resolution: { @@ -17583,7 +17779,7 @@ packages: "@babel/plugin-transform-modules-commonjs": 7.18.2(@babel/core@7.20.2)(supports-color@8.1.1) "@babel/preset-env": 7.12.10(@babel/core@7.12.10) "@babel/preset-flow": 7.17.12(@babel/core@7.20.2) - "@babel/preset-typescript": 7.17.12(@babel/core@7.20.2) + "@babel/preset-typescript": 7.17.12(@babel/core@7.20.2)(supports-color@8.1.1) "@babel/register": 7.17.7(@babel/core@7.20.2) babel-core: 7.0.0-bridge.0(@babel/core@7.20.2) colors: 1.4.0 @@ -17608,20 +17804,20 @@ packages: peerDependencies: "@babel/preset-env": ^7.1.6 dependencies: - "@babel/core": 7.18.2(supports-color@8.1.1) - "@babel/parser": 7.18.4 - "@babel/plugin-proposal-class-properties": 7.17.12(@babel/core@7.18.2)(supports-color@8.1.1) - "@babel/plugin-proposal-nullish-coalescing-operator": 7.17.12(@babel/core@7.18.2) - "@babel/plugin-proposal-optional-chaining": 7.17.12(@babel/core@7.18.2) - "@babel/plugin-transform-modules-commonjs": 7.18.2(@babel/core@7.18.2)(supports-color@8.1.1) + "@babel/core": 7.20.2(supports-color@8.1.1) + "@babel/parser": 7.20.3 + "@babel/plugin-proposal-class-properties": 7.17.12(@babel/core@7.20.2)(supports-color@8.1.1) + "@babel/plugin-proposal-nullish-coalescing-operator": 7.17.12(@babel/core@7.20.2) + "@babel/plugin-proposal-optional-chaining": 7.17.12(@babel/core@7.20.2) + "@babel/plugin-transform-modules-commonjs": 7.18.2(@babel/core@7.20.2)(supports-color@8.1.1) "@babel/preset-env": 7.12.10(@babel/core@7.18.2)(supports-color@8.1.1) - "@babel/preset-flow": 7.17.12(@babel/core@7.18.2) - "@babel/preset-typescript": 7.17.12(@babel/core@7.18.2)(supports-color@8.1.1) - "@babel/register": 7.17.7(@babel/core@7.18.2) - babel-core: 7.0.0-bridge.0(@babel/core@7.18.2) + "@babel/preset-flow": 7.17.12(@babel/core@7.20.2) + "@babel/preset-typescript": 7.17.12(@babel/core@7.20.2)(supports-color@8.1.1) + "@babel/register": 7.17.7(@babel/core@7.20.2) + babel-core: 7.0.0-bridge.0(@babel/core@7.20.2) colors: 1.4.0 flow-parser: 0.179.0 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 micromatch: 3.1.10(supports-color@8.1.1) neo-async: 2.6.2 node-dir: 0.1.17 @@ -18784,7 +18980,7 @@ packages: engines: {node: ">=10"} hasBin: true - /mkdist@0.3.13(typescript@4.8.4): + /mkdist@0.3.13(typescript@4.9.5): resolution: { integrity: sha512-+eCPpkr8l2X630y5PIlkts2tzYEsb+aGIgXdrQv9ZGtWE2bLlD6kVIFfI6FJwFpjjw4dPPyorxQc6Uhm/oXlvg==, @@ -18803,7 +18999,7 @@ packages: jiti: 1.14.0 mri: 1.2.0 pathe: 0.2.0 - typescript: 4.8.4 + typescript: 4.9.5 dev: true /mlly@0.4.3: @@ -19000,7 +19196,7 @@ packages: integrity: sha512-iChjE8ov/1K/z98gdKbn2Jw+2vLgJtVV39X+rCP5SGnVQuco7QOr19FRNGMIrD8d3LYhHWV9j9sKLzq1aDWWQQ==, } peerDependencies: - next: ^12.2.5 || ^13 || ^14 + next: 14.3.0-canary.28 nodemailer: ^6.6.5 react: ^17.0.2 || ^18 react-dom: ^17.0.2 || ^18 @@ -19011,8 +19207,8 @@ packages: "@babel/runtime": 7.23.2 "@panva/hkdf": 1.0.2 cookie: 0.5.0 - jose: 4.15.5 - next: 14.2.0-canary.51(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0) + jose: 4.11.2 + next: 14.3.0-canary.28(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0) oauth: 0.9.15 openid-client: 5.6.5 preact: 10.11.3 @@ -19022,23 +19218,23 @@ packages: uuid: 8.3.2 patched: true - /next-router-mock@0.9.1(next@14.2.0-canary.51)(react@18.2.0): + /next-router-mock@0.9.1(next@14.3.0-canary.28)(react@18.2.0): resolution: { integrity: sha512-GTrns944dnFNgycpinyRszOiwwk99LUJsvvX0FWRgUFHv6hOuzCns1rmTlzO+DRimYB9/XMA+87X2/dQLzjiUQ==, } peerDependencies: - next: ">=10.0.0" + next: 14.3.0-canary.28 react: ">=17.0.0" dependencies: - next: 14.2.0-canary.51(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0) + next: 14.3.0-canary.28(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 dev: true - /next@14.2.0-canary.51(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0): + /next@14.3.0-canary.28(@babel/core@7.12.10)(react-dom@18.2.0)(react@18.2.0): resolution: { - integrity: sha512-TZyy/TmrVmiZOdy1AT1uJovt9DIOh+q7JDU5qgpI/6cvvwRugzWyxdb4Cgs9K9QIaHI1jSKogJme5641g10buQ==, + integrity: sha512-nl4uVgqz1nH+CnlqQlLSd8LBClY2HKQlonA+s/A+Nl4kZnOupR9ovKoewteQsarQiLkNsFzUKTeHgnbdVUXwag==, } engines: {node: ">=18.17.0"} hasBin: true @@ -19056,8 +19252,8 @@ packages: sass: optional: true dependencies: - "@next/env": 14.2.0-canary.51 - "@swc/helpers": 0.5.5 + "@next/env": 14.3.0-canary.28 + "@swc/helpers": 0.5.11 busboy: 1.6.0 caniuse-lite: 1.0.30001599 graceful-fs: 4.2.11 @@ -19066,24 +19262,25 @@ packages: react-dom: 18.2.0(react@18.2.0) styled-jsx: 5.1.1(@babel/core@7.12.10)(react@18.2.0) optionalDependencies: - "@next/swc-darwin-arm64": 14.2.0-canary.51 - "@next/swc-darwin-x64": 14.2.0-canary.51 - "@next/swc-linux-arm64-gnu": 14.2.0-canary.51 - "@next/swc-linux-arm64-musl": 14.2.0-canary.51 - "@next/swc-linux-x64-gnu": 14.2.0-canary.51 - "@next/swc-linux-x64-musl": 14.2.0-canary.51 - "@next/swc-win32-arm64-msvc": 14.2.0-canary.51 - "@next/swc-win32-ia32-msvc": 14.2.0-canary.51 - "@next/swc-win32-x64-msvc": 14.2.0-canary.51 + "@next/swc-darwin-arm64": 14.3.0-canary.28 + "@next/swc-darwin-x64": 14.3.0-canary.28 + "@next/swc-linux-arm64-gnu": 14.3.0-canary.28 + "@next/swc-linux-arm64-musl": 14.3.0-canary.28 + "@next/swc-linux-x64-gnu": 14.3.0-canary.28 + "@next/swc-linux-x64-musl": 14.3.0-canary.28 + "@next/swc-win32-arm64-msvc": 14.3.0-canary.28 + "@next/swc-win32-ia32-msvc": 14.3.0-canary.28 + "@next/swc-win32-x64-msvc": 14.3.0-canary.28 + sharp: 0.33.4 transitivePeerDependencies: - "@babel/core" - babel-plugin-macros dev: false - /next@14.2.0-canary.51(@babel/core@7.18.2)(react-dom@18.2.0)(react@18.2.0): + /next@14.3.0-canary.28(@babel/core@7.18.2)(react-dom@18.2.0)(react@18.2.0): resolution: { - integrity: sha512-TZyy/TmrVmiZOdy1AT1uJovt9DIOh+q7JDU5qgpI/6cvvwRugzWyxdb4Cgs9K9QIaHI1jSKogJme5641g10buQ==, + integrity: sha512-nl4uVgqz1nH+CnlqQlLSd8LBClY2HKQlonA+s/A+Nl4kZnOupR9ovKoewteQsarQiLkNsFzUKTeHgnbdVUXwag==, } engines: {node: ">=18.17.0"} hasBin: true @@ -19101,8 +19298,8 @@ packages: sass: optional: true dependencies: - "@next/env": 14.2.0-canary.51 - "@swc/helpers": 0.5.5 + "@next/env": 14.3.0-canary.28 + "@swc/helpers": 0.5.11 busboy: 1.6.0 caniuse-lite: 1.0.30001599 graceful-fs: 4.2.11 @@ -19111,24 +19308,25 @@ packages: react-dom: 18.2.0(react@18.2.0) styled-jsx: 5.1.1(@babel/core@7.18.2)(react@18.2.0) optionalDependencies: - "@next/swc-darwin-arm64": 14.2.0-canary.51 - "@next/swc-darwin-x64": 14.2.0-canary.51 - "@next/swc-linux-arm64-gnu": 14.2.0-canary.51 - "@next/swc-linux-arm64-musl": 14.2.0-canary.51 - "@next/swc-linux-x64-gnu": 14.2.0-canary.51 - "@next/swc-linux-x64-musl": 14.2.0-canary.51 - "@next/swc-win32-arm64-msvc": 14.2.0-canary.51 - "@next/swc-win32-ia32-msvc": 14.2.0-canary.51 - "@next/swc-win32-x64-msvc": 14.2.0-canary.51 + "@next/swc-darwin-arm64": 14.3.0-canary.28 + "@next/swc-darwin-x64": 14.3.0-canary.28 + "@next/swc-linux-arm64-gnu": 14.3.0-canary.28 + "@next/swc-linux-arm64-musl": 14.3.0-canary.28 + "@next/swc-linux-x64-gnu": 14.3.0-canary.28 + "@next/swc-linux-x64-musl": 14.3.0-canary.28 + "@next/swc-win32-arm64-msvc": 14.3.0-canary.28 + "@next/swc-win32-ia32-msvc": 14.3.0-canary.28 + "@next/swc-win32-x64-msvc": 14.3.0-canary.28 + sharp: 0.33.4 transitivePeerDependencies: - "@babel/core" - babel-plugin-macros dev: false - /next@14.2.0-canary.51(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0): + /next@14.3.0-canary.28(@babel/core@7.20.2)(react-dom@18.2.0)(react@18.2.0): resolution: { - integrity: sha512-TZyy/TmrVmiZOdy1AT1uJovt9DIOh+q7JDU5qgpI/6cvvwRugzWyxdb4Cgs9K9QIaHI1jSKogJme5641g10buQ==, + integrity: sha512-nl4uVgqz1nH+CnlqQlLSd8LBClY2HKQlonA+s/A+Nl4kZnOupR9ovKoewteQsarQiLkNsFzUKTeHgnbdVUXwag==, } engines: {node: ">=18.17.0"} hasBin: true @@ -19146,8 +19344,8 @@ packages: sass: optional: true dependencies: - "@next/env": 14.2.0-canary.51 - "@swc/helpers": 0.5.5 + "@next/env": 14.3.0-canary.28 + "@swc/helpers": 0.5.11 busboy: 1.6.0 caniuse-lite: 1.0.30001599 graceful-fs: 4.2.11 @@ -19156,15 +19354,16 @@ packages: react-dom: 18.2.0(react@18.2.0) styled-jsx: 5.1.1(@babel/core@7.20.2)(react@18.2.0) optionalDependencies: - "@next/swc-darwin-arm64": 14.2.0-canary.51 - "@next/swc-darwin-x64": 14.2.0-canary.51 - "@next/swc-linux-arm64-gnu": 14.2.0-canary.51 - "@next/swc-linux-arm64-musl": 14.2.0-canary.51 - "@next/swc-linux-x64-gnu": 14.2.0-canary.51 - "@next/swc-linux-x64-musl": 14.2.0-canary.51 - "@next/swc-win32-arm64-msvc": 14.2.0-canary.51 - "@next/swc-win32-ia32-msvc": 14.2.0-canary.51 - "@next/swc-win32-x64-msvc": 14.2.0-canary.51 + "@next/swc-darwin-arm64": 14.3.0-canary.28 + "@next/swc-darwin-x64": 14.3.0-canary.28 + "@next/swc-linux-arm64-gnu": 14.3.0-canary.28 + "@next/swc-linux-arm64-musl": 14.3.0-canary.28 + "@next/swc-linux-x64-gnu": 14.3.0-canary.28 + "@next/swc-linux-x64-musl": 14.3.0-canary.28 + "@next/swc-win32-arm64-msvc": 14.3.0-canary.28 + "@next/swc-win32-ia32-msvc": 14.3.0-canary.28 + "@next/swc-win32-x64-msvc": 14.3.0-canary.28 + sharp: 0.33.4 transitivePeerDependencies: - "@babel/core" - babel-plugin-macros @@ -20423,6 +20622,20 @@ packages: dependencies: "@prisma/prisma-fmt-wasm": 4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6 prettier: 2.7.1 + dev: true + + /prettier-plugin-prisma@4.4.0(prettier@2.8.8): + resolution: + { + integrity: sha512-631zwtvHUjcuS+i83wkxE3LqizazojWie4Pkha9GL6r1UsochNUedvxfvWPCdw6Dpyawvc5UKkmxcb9aT9+xfg==, + } + engines: {node: ">=12", npm: ">=7"} + peerDependencies: + prettier: ">=2" + dependencies: + "@prisma/prisma-fmt-wasm": 4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6 + prettier: 2.8.8 + dev: false /prettier@1.19.1: resolution: @@ -20441,6 +20654,15 @@ packages: engines: {node: ">=10.13.0"} hasBin: true + /prettier@2.8.8: + resolution: + { + integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==, + } + engines: {node: ">=10.13.0"} + hasBin: true + dev: false + /pretty-bytes@5.6.0: resolution: { @@ -20503,6 +20725,26 @@ packages: mri: 1.2.0 multimatch: 4.0.0 prettier: 2.7.1 + dev: true + + /pretty-quick@3.1.3(prettier@2.8.8): + resolution: + { + integrity: sha512-kOCi2FJabvuh1as9enxYmrnBC6tVMoVOenMaBqRfsvBHB0cbpYHjdQEpSglpASDFEXVwplpcGR4CLEaisYAFcA==, + } + engines: {node: ">=10.13"} + hasBin: true + peerDependencies: + prettier: ">=2.0.0" + dependencies: + chalk: 3.0.0 + execa: 4.1.0 + find-up: 4.1.0 + ignore: 5.2.0 + mri: 1.2.0 + multimatch: 4.0.0 + prettier: 2.8.8 + dev: false /preview-email@3.0.7: resolution: @@ -21489,7 +21731,7 @@ packages: sprintf-js: 1.1.2 dev: false - /rollup-plugin-dts@4.2.2(rollup@2.77.2)(typescript@4.8.4): + /rollup-plugin-dts@4.2.2(rollup@2.77.2)(typescript@4.9.5): resolution: { integrity: sha512-A3g6Rogyko/PXeKoUlkjxkP++8UDVpgA7C+Tdl77Xj4fgEaIjPSnxRmR53EzvoYy97VMVwLAOcWJudaVAuxneQ==, @@ -21501,7 +21743,7 @@ packages: dependencies: magic-string: 0.26.7 rollup: 2.77.2 - typescript: 4.8.4 + typescript: 4.9.5 optionalDependencies: "@babel/code-frame": 7.18.6 dev: true @@ -21789,6 +22031,16 @@ packages: dependencies: lru-cache: 6.0.0 + /semver@7.6.2: + resolution: + { + integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==, + } + engines: {node: ">=10"} + hasBin: true + requiresBuild: true + optional: true + /send@0.17.2(supports-color@8.1.1): resolution: { @@ -21914,6 +22166,39 @@ packages: kind-of: 6.0.3 dev: false + /sharp@0.33.4: + resolution: + { + integrity: sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==, + } + engines: {libvips: ">=8.15.2", node: ^18.17.0 || ^20.3.0 || >=21.0.0} + requiresBuild: true + dependencies: + color: 4.2.3 + detect-libc: 2.0.3 + semver: 7.6.2 + optionalDependencies: + "@img/sharp-darwin-arm64": 0.33.4 + "@img/sharp-darwin-x64": 0.33.4 + "@img/sharp-libvips-darwin-arm64": 1.0.2 + "@img/sharp-libvips-darwin-x64": 1.0.2 + "@img/sharp-libvips-linux-arm": 1.0.2 + "@img/sharp-libvips-linux-arm64": 1.0.2 + "@img/sharp-libvips-linux-s390x": 1.0.2 + "@img/sharp-libvips-linux-x64": 1.0.2 + "@img/sharp-libvips-linuxmusl-arm64": 1.0.2 + "@img/sharp-libvips-linuxmusl-x64": 1.0.2 + "@img/sharp-linux-arm": 0.33.4 + "@img/sharp-linux-arm64": 0.33.4 + "@img/sharp-linux-s390x": 0.33.4 + "@img/sharp-linux-x64": 0.33.4 + "@img/sharp-linuxmusl-arm64": 0.33.4 + "@img/sharp-linuxmusl-x64": 0.33.4 + "@img/sharp-wasm32": 0.33.4 + "@img/sharp-win32-ia32": 0.33.4 + "@img/sharp-win32-x64": 0.33.4 + optional: true + /shebang-command@1.2.0: resolution: { @@ -21968,6 +22253,16 @@ packages: integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==, } + /simple-swizzle@0.2.2: + resolution: + { + integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==, + } + requiresBuild: true + dependencies: + is-arrayish: 0.3.2 + optional: true + /simple-wcswidth@1.0.1: resolution: { @@ -23225,6 +23520,40 @@ packages: yn: 3.1.1 dev: true + /ts-node@10.9.1(@types/node@18.7.13)(typescript@4.9.5): + resolution: + { + integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==, + } + hasBin: true + peerDependencies: + "@swc/core": ">=1.2.50" + "@swc/wasm": ">=1.2.50" + "@types/node": "*" + typescript: ">=2.7" + peerDependenciesMeta: + "@swc/core": + optional: true + "@swc/wasm": + optional: true + dependencies: + "@cspotcode/source-map-support": 0.8.1 + "@tsconfig/node10": 1.0.9 + "@tsconfig/node12": 1.0.10 + "@tsconfig/node14": 1.0.2 + "@tsconfig/node16": 1.0.3 + "@types/node": 18.7.13 + acorn: 8.8.1 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.9.5 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: true + /tsconfig-paths@3.14.1: resolution: { @@ -23547,6 +23876,15 @@ packages: engines: {node: ">=4.2.0"} hasBin: true + /typescript@4.9.5: + resolution: + { + integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==, + } + engines: {node: ">=4.2.0"} + hasBin: true + dev: true + /uc.micro@1.0.6: resolution: { @@ -23586,7 +23924,7 @@ packages: jiti: 1.14.0 magic-string: 0.25.9 mkdirp: 1.0.4 - mkdist: 0.3.13(typescript@4.8.4) + mkdist: 0.3.13(typescript@4.9.5) mlly: 0.4.3 mri: 1.2.0 pathe: 0.2.0 @@ -23594,10 +23932,10 @@ packages: pretty-bytes: 5.6.0 rimraf: 3.0.2 rollup: 2.77.2 - rollup-plugin-dts: 4.2.2(rollup@2.77.2)(typescript@4.8.4) + rollup-plugin-dts: 4.2.2(rollup@2.77.2)(typescript@4.9.5) rollup-plugin-esbuild: 4.9.1(esbuild@0.14.51)(rollup@2.77.2)(supports-color@8.1.1) scule: 0.2.1 - typescript: 4.8.4 + typescript: 4.9.5 untyped: 0.3.0 transitivePeerDependencies: - supports-color @@ -23624,7 +23962,7 @@ packages: jiti: 1.14.0 magic-string: 0.26.2 mkdirp: 1.0.4 - mkdist: 0.3.13(typescript@4.8.4) + mkdist: 0.3.13(typescript@4.9.5) mlly: 0.5.5 mri: 1.2.0 pathe: 0.3.2 @@ -23632,10 +23970,10 @@ packages: pretty-bytes: 6.0.0 rimraf: 3.0.2 rollup: 2.77.2 - rollup-plugin-dts: 4.2.2(rollup@2.77.2)(typescript@4.8.4) + rollup-plugin-dts: 4.2.2(rollup@2.77.2)(typescript@4.9.5) rollup-plugin-esbuild: 4.9.1(esbuild@0.14.51)(rollup@2.77.2)(supports-color@8.1.1) scule: 0.2.1 - typescript: 4.8.4 + typescript: 4.9.5 untyped: 0.4.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color