1
0
mirror of synced 2026-02-06 09:00:12 -05:00

Compare commits

...

28 Commits

Author SHA1 Message Date
Siddharth Suresh
1e5d691eae try fix 2025-01-12 18:37:55 +05:30
Siddharth Suresh
d4f0230979 commit 2025-01-12 18:28:13 +05:30
Siddharth Suresh
47554d39e7 initial 2024-12-23 17:23:58 +05:30
Siddharth Suresh
2bb10b86cf fix again 2024-12-20 20:18:01 +05:30
Siddharth Suresh
a38caabd10 fix 2024-12-20 18:38:27 +05:30
Siddharth Suresh
fbd64739cb fix 2024-12-20 17:41:34 +05:30
Siddharth Suresh
f8ab8fce25 fix unit tests 2024-12-20 17:38:51 +05:30
Siddharth Suresh
a0448fff17 upgrade to react 19 2024-12-20 17:24:12 +05:30
Siddharth Suresh
83d236e456 Merge branch 'siddharth/upgrade-to-next-15' of https://github.com/blitz-js/blitz into siddharth/upgrade-to-next-15 2024-12-20 17:22:46 +05:30
Siddharth Suresh
b0bab155d4 Merge branch 'main' into siddharth/upgrade-to-next-15 2024-12-07 11:52:05 +05:30
Siddharth Suresh
ad493c489d fix
chore: remove outdated `@testing-library/react-hooks`
2024-12-03 14:10:05 +05:30
Siddharth Suresh
f303bc6ab1 fix turbopack exports 2024-12-03 14:10:05 +05:30
Siddharth Suresh
a4f4e7e098 upgrade testing library 2024-12-03 14:10:05 +05:30
Siddharth Suresh
12faac9f69 Merge branch 'siddharth/upgrade-to-next-15' of https://github.com/blitz-js/blitz into siddharth/upgrade-to-next-15 2024-12-03 14:10:05 +05:30
Siddharth Suresh
9219ec7ccc chore: remove outdated @testing-library/react-hooks 2024-10-26 13:05:41 +05:30
Siddharth Suresh
dfb5d6b360 fix 2024-10-26 13:02:18 +05:30
Siddharth Suresh
170af30c93 fix turbopack exports 2024-10-26 13:00:20 +05:30
Siddharth Suresh
362893835f upgrade testing library 2024-10-26 11:31:52 +05:30
Siddharth Suresh
f9301b6fd6 Merge branch 'siddharth/upgrade-to-next-15' of https://github.com/blitz-js/blitz into siddharth/upgrade-to-next-15 2024-10-26 11:24:34 +05:30
Siddharth Suresh
b25ec48a6f fix: react types 2024-10-26 11:24:30 +05:30
Siddharth Suresh
1802227f70 Create wild-news-shop.md 2024-10-26 11:15:10 +05:30
Siddharth Suresh
714f293d69 fix: remaining type fixes 2024-10-26 11:13:32 +05:30
Siddharth Suresh
5d4d4daa2d chore: upgrade to latest dynamic import 2024-10-26 10:58:42 +05:30
Siddharth Suresh
668ed49964 fix: add await to blitz rpc handler 2024-10-26 10:54:12 +05:30
Siddharth Suresh
19884bff01 upgrade to latest react 2024-10-26 10:50:00 +05:30
Siddharth Suresh
fe8ed06a6e chore: run codemod 2024-10-26 10:41:21 +05:30
Siddharth Suresh
a362d8ac68 fix: await cookies and headers in blitz auth 2024-10-26 10:39:09 +05:30
Siddharth Suresh
99cb249ee3 chore: upgrade to next.js 15 2024-10-26 10:39:09 +05:30
79 changed files with 1587 additions and 931 deletions

View File

@@ -0,0 +1,8 @@
---
"@blitzjs/auth": minor
"@blitzjs/next": minor
"@blitzjs/rpc": minor
"blitz": minor
---
chore: support next.js 15

View File

@@ -148,7 +148,7 @@ jobs:
- name: Install playwright
if: matrix.folder != 'next-13-app-dir' || matrix.os != 'windows-latest'
run: |
pnpx playwright@1.28.0 install --with-deps
pnpx playwright@1.49.1 install --with-deps
shell: bash
- name: Build

View File

@@ -36,3 +36,5 @@ yarn-error.log*
next-env.d.ts
.vscode
certificates

View File

@@ -20,20 +20,21 @@
"@hookform/resolvers": "2.9.10",
"@prisma/client": "^4.5.0",
"@tanstack/react-query": "4.0.10",
"arctic": "2.3.3",
"blitz": "2.1.3",
"flatted": "3.2.7",
"next": "14.2.15",
"next": "15.0.1",
"prisma": "^4.5.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-hook-form": "7.39.1",
"superjson": "1.11.0",
"zod": "3.23.8"
},
"devDependencies": {
"@types/node": "18.11.7",
"@types/react": "18.0.23",
"@types/react-dom": "18.0.7",
"@types/react": "npm:types-react@19.0.0",
"@types/react-dom": "npm:types-react-dom@19.0.0",
"eslint": "8.26.0",
"eslint-config-next": "13.0.0",
"typescript": "4.8.4"

View File

@@ -0,0 +1,21 @@
import {oAuth2Handler} from "@blitzjs/auth"
import {GitHub, Google} from "arctic"
export const {GET} = oAuth2Handler([
{
client: new GitHub(process.env.GITHUB_CLIENT_ID!, process.env.GITHUB_CLIENT_SECRET!, null),
name: "github",
scopes: ["user:email"],
withPkce: false,
},
{
client: new Google(
process.env.GOOGLE_CLIENT_ID!,
process.env.GOOGLE_CLIENT_SECRET!,
"https://localhost:3000/api/auth/google/callback",
),
name: "google",
scopes: ["email", "profile"],
withPkce: true,
},
])

View File

@@ -4,7 +4,7 @@ import {zodResolver} from "@hookform/resolvers/zod"
import {z} from "zod"
export interface FormProps<S extends z.ZodType<any, any>>
extends Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit"> {
extends Omit<PropsWithoutRef<React.JSX.IntrinsicElements["form"]>, "onSubmit"> {
/** All your form fields */
children?: ReactNode
/** Text to display in the submit button */

View File

@@ -2,14 +2,15 @@ import {forwardRef, PropsWithoutRef, ComponentPropsWithoutRef} from "react"
import {useFormContext} from "react-hook-form"
import {ErrorMessage} from "@hookform/error-message"
export interface LabeledTextFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["input"]> {
export interface LabeledTextFieldProps
extends PropsWithoutRef<React.JSX.IntrinsicElements["input"]> {
/** Field name. */
name: string
/** Field label. */
label: string
/** Field type. Doesn't include radio buttons and checkboxes */
type?: "text" | "password" | "email" | "number"
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>
labelProps?: ComponentPropsWithoutRef<"label">
}

View File

@@ -31,23 +31,22 @@
"@hookform/resolvers": "2.9.10",
"@prisma/client": "4.6.1",
"blitz": "2.1.3",
"next": "14.2.15",
"next": "15.0.1",
"openid-client": "5.2.1",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-hook-form": "7.39.1",
"ts-node": "10.9.1",
"zod": "3.23.8"
},
"devDependencies": {
"@next/bundle-analyzer": "12.0.8",
"@testing-library/react": "13.4.0",
"@testing-library/react-hooks": "8.0.1",
"@testing-library/react": "16.0.1",
"@types/jest": "29.2.2",
"@types/node": "18.11.9",
"@types/preview-email": "2.0.1",
"@types/react": "18.0.25",
"@types/react": "npm:types-react@19.0.0",
"@typescript-eslint/eslint-plugin": "5.42.1",
"eslint": "8.27.0",
"eslint-config-next": "12.3.1",

View File

@@ -4,7 +4,7 @@ import { zodResolver } from "@hookform/resolvers/zod"
import { z } from "zod"
export interface FormProps<S extends z.ZodType<any, any>>
extends Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit"> {
extends Omit<PropsWithoutRef<React.JSX.IntrinsicElements["form"]>, "onSubmit"> {
/** All your form fields */
children?: ReactNode
/** Text to display in the submit button */

View File

@@ -2,14 +2,15 @@ import { forwardRef, PropsWithoutRef, ComponentPropsWithoutRef } from "react"
import { useFormContext } from "react-hook-form"
import { ErrorMessage } from "@hookform/error-message"
export interface LabeledTextFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["input"]> {
export interface LabeledTextFieldProps
extends PropsWithoutRef<React.JSX.IntrinsicElements["input"]> {
/** Field name. */
name: string
/** Field label. */
label: string
/** Field type. Doesn't include radio buttons and checkboxes */
type?: "text" | "password" | "email" | "number"
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>
labelProps?: ComponentPropsWithoutRef<"label">
}

View File

@@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.

View File

@@ -32,11 +32,11 @@
"@hookform/resolvers": "2.9.10",
"@prisma/client": "4.6.1",
"blitz": "2.1.3",
"next": "14.2.15",
"next": "15.0.1",
"next-auth": "4.24.7",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-hook-form": "7.39.1",
"ts-node": "10.9.1",
"zod": "3.23.8"
@@ -44,11 +44,10 @@
"devDependencies": {
"@next/bundle-analyzer": "12.0.8",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "13.4.0",
"@testing-library/react-hooks": "8.0.1",
"@testing-library/react": "16.0.1",
"@types/node": "18.11.9",
"@types/preview-email": "2.0.1",
"@types/react": "18.0.25",
"@types/react": "npm:types-react@19.0.0",
"@typescript-eslint/eslint-plugin": "5.42.1",
"@vitejs/plugin-react": "2.2.0",
"eslint": "8.27.0",

View File

@@ -4,7 +4,7 @@ import { zodResolver } from "@hookform/resolvers/zod"
import { z } from "zod"
export interface FormProps<S extends z.ZodType<any, any>>
extends Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit"> {
extends Omit<PropsWithoutRef<React.JSX.IntrinsicElements["form"]>, "onSubmit"> {
/** All your form fields */
children?: ReactNode
/** Text to display in the submit button */

View File

@@ -2,14 +2,15 @@ import { ComponentPropsWithoutRef, forwardRef, PropsWithoutRef } from "react"
import { useFormContext } from "react-hook-form"
import { ErrorMessage } from "@hookform/error-message"
export interface LabeledSelectFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["select"]> {
export interface LabeledSelectFieldProps
extends PropsWithoutRef<React.JSX.IntrinsicElements["select"]> {
/** Field name. */
name: string
/** Field label. */
label: string
/** Field type. Doesn't include radio buttons and checkboxes */
options: any[]
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>
labelProps?: ComponentPropsWithoutRef<"label">
}

View File

@@ -2,14 +2,15 @@ import { forwardRef, PropsWithoutRef, ComponentPropsWithoutRef } from "react"
import { useFormContext } from "react-hook-form"
import { ErrorMessage } from "@hookform/error-message"
export interface LabeledTextFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["input"]> {
export interface LabeledTextFieldProps
extends PropsWithoutRef<React.JSX.IntrinsicElements["input"]> {
/** Field name. */
name: string
/** Field label. */
label: string
/** Field type. Doesn't include radio buttons and checkboxes */
type?: "text" | "password" | "email" | "number"
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>
labelProps?: ComponentPropsWithoutRef<"label">
}

View File

@@ -26,17 +26,17 @@
"blitz": "2.1.3",
"jest": "29.3.0",
"jest-environment-jsdom": "29.3.0",
"next": "14.2.15",
"next": "15.0.1",
"passport-mock-strategy": "2.0.0",
"passport-twitter": "1.0.4",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"ts-node": "10.9.1"
},
"devDependencies": {
"@next/bundle-analyzer": "12.0.8",
"@types/react": "18.0.25",
"@types/react": "npm:types-react@19.0.0",
"eslint": "8.27.0",
"typescript": "^4.8.4"
}

View File

@@ -26,10 +26,10 @@
"@prisma/client": "4.6.1",
"blitz": "2.1.3",
"delay": "5.0.0",
"next": "14.2.15",
"next": "15.0.1",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-hook-form": "7.39.1",
"ts-node": "10.9.1",
"zod": "3.23.8"
@@ -37,11 +37,10 @@
"devDependencies": {
"@next/bundle-analyzer": "12.0.8",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "13.4.0",
"@testing-library/react-hooks": "8.0.1",
"@testing-library/react": "16.0.1",
"@types/node": "18.11.9",
"@types/preview-email": "2.0.1",
"@types/react": "18.0.25",
"@types/react": "npm:types-react@19.0.0",
"@typescript-eslint/eslint-plugin": "5.42.1",
"@vitejs/plugin-react": "2.2.0",
"eslint": "8.27.0",

View File

@@ -23,10 +23,10 @@
"@prisma/client": "4.6.1",
"blitz": "2.1.3",
"lowdb": "3.0.0",
"next": "14.2.15",
"next": "15.0.1",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"secure-password": "4.0.0",
"wait-port": "1.0.4"
},
@@ -36,7 +36,7 @@
"@types/fs-extra": "9.0.13",
"@types/node": "18.7.13",
"@types/node-fetch": "2.6.1",
"@types/react": "18.0.25",
"@types/react": "npm:types-react@19.0.0",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",

View File

@@ -22,10 +22,10 @@
"@prisma/client": "4.6.1",
"blitz": "2.1.3",
"lowdb": "2.1.0",
"next": "14.2.15",
"next": "15.0.1",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0"
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@blitzjs/config": "2.1.3",
@@ -33,7 +33,7 @@
"@types/express": "4.17.13",
"@types/fs-extra": "9.0.13",
"@types/node-fetch": "2.6.1",
"@types/react": "18.0.25",
"@types/react": "npm:types-react@19.0.0",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",

View File

@@ -15,16 +15,16 @@
"@blitzjs/next": "2.1.3",
"@blitzjs/rpc": "2.1.3",
"blitz": "2.1.3",
"next": "14.2.15",
"react": "18.2.0",
"react-dom": "18.2.0"
"next": "15.0.1",
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@next/bundle-analyzer": "12.0.8",
"@types/express": "4.17.13",
"@types/fs-extra": "9.0.13",
"@types/node-fetch": "2.6.1",
"@types/react": "18.0.25",
"@types/react": "npm:types-react@19.0.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",
"get-port": "6.1.2",

View File

@@ -2,4 +2,4 @@
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.

View File

@@ -24,10 +24,10 @@
"@prisma/client": "4.6.1",
"blitz": "2.1.3",
"lowdb": "2.1.0",
"next": "14.2.15",
"next": "15.0.1",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"secure-password": "4.0.0",
"wait-port": "1.0.4"
},
@@ -37,7 +37,7 @@
"@types/fs-extra": "9.0.13",
"@types/node": "18.7.13",
"@types/node-fetch": "2.6.1",
"@types/react": "18.0.25",
"@types/react": "npm:types-react@19.0.0",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",

View File

@@ -22,10 +22,10 @@
"@prisma/client": "4.6.1",
"blitz": "2.1.3",
"lowdb": "3.0.0",
"next": "14.2.15",
"next": "15.0.1",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0"
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@blitzjs/config": "2.1.3",
@@ -33,7 +33,7 @@
"@types/express": "4.17.13",
"@types/fs-extra": "9.0.13",
"@types/node-fetch": "2.6.1",
"@types/react": "18.0.25",
"@types/react": "npm:types-react@19.0.0",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",

View File

@@ -15,14 +15,14 @@
"@prisma/client": "4.6.1",
"@tanstack/react-query": "4.0.10",
"blitz": "2.1.3",
"next": "14.2.15",
"next": "15.0.1",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0"
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@testing-library/react": "13.4.0",
"@types/react": "18.0.25",
"@testing-library/react": "16.0.1",
"@types/react": "npm:types-react@19.0.0",
"@vitejs/plugin-react": "1.3.0",
"delay": "5.0.0",
"eslint": "8.27.0",

View File

@@ -21,10 +21,10 @@
"@prisma/client": "4.6.1",
"blitz": "2.1.3",
"lowdb": "3.0.0",
"next": "14.2.15",
"next": "15.0.1",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0"
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@blitzjs/config": "2.1.3",
@@ -32,7 +32,7 @@
"@types/express": "4.17.13",
"@types/fs-extra": "9.0.13",
"@types/node-fetch": "2.6.1",
"@types/react": "18.0.25",
"@types/react": "npm:types-react@19.0.0",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",

View File

@@ -11,15 +11,15 @@
"@blitzjs/next": "2.1.3",
"@blitzjs/rpc": "2.1.3",
"blitz": "2.1.3",
"next": "14.2.15",
"react": "18.2.0",
"react-dom": "18.2.0"
"next": "15.0.1",
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@types/express": "4.17.13",
"@types/fs-extra": "9.0.13",
"@types/node-fetch": "2.6.1",
"@types/react": "18.0.25",
"@types/react": "npm:types-react@19.0.0",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",

View File

@@ -11,15 +11,15 @@
"@blitzjs/next": "2.1.3",
"@blitzjs/rpc": "2.1.3",
"blitz": "2.1.3",
"next": "14.2.15",
"react": "18.2.0",
"react-dom": "18.2.0"
"next": "15.0.1",
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@types/express": "4.17.13",
"@types/fs-extra": "9.0.13",
"@types/node-fetch": "2.6.1",
"@types/react": "18.0.25",
"@types/react": "npm:types-react@19.0.0",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",

View File

@@ -22,10 +22,10 @@
"@prisma/client": "4.6.1",
"blitz": "2.1.3",
"lowdb": "3.0.0",
"next": "14.2.15",
"next": "15.0.1",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0"
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@blitzjs/config": "2.1.3",
@@ -33,7 +33,7 @@
"@types/express": "4.17.13",
"@types/fs-extra": "9.0.13",
"@types/node-fetch": "2.6.1",
"@types/react": "18.0.25",
"@types/react": "npm:types-react@19.0.0",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",

View File

@@ -7,11 +7,11 @@
"@blitzjs/next": "workspace:2.1.3",
"@blitzjs/rpc": "workspace:2.1.3",
"@tanstack/react-query": "4.13.0",
"@testing-library/react": "13.4.0",
"@testing-library/react": "16.0.1",
"@types/express": "4.17.13",
"@types/fs-extra": "9.0.13",
"@types/node-fetch": "2.6.1",
"@types/react": "18.0.25",
"@types/react": "npm:types-react@19.0.0",
"@types/rimraf": "3.0.2",
"@types/selenium-webdriver": "4.0.18",
"chromedriver": "100.0.0",
@@ -23,8 +23,8 @@
"node-fetch": "3.2.3",
"pkg-dir": "5.0.0",
"playwright-chromium": "1.28.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"resolve-cwd": "3.0.0",
"resolve-from": "5.0.0",
"rimraf": "3.0.2",

View File

@@ -29,7 +29,7 @@
"husky": "8.0.2",
"jsdom": "^19.0.0",
"lint-staged": "13.0.3",
"next": "14.2.15",
"next": "15.0.1",
"only-allow": "1.1.0",
"prettier": "^2.8.8",
"prettier-plugin-prisma": "4.4.0",
@@ -51,7 +51,9 @@
},
"overrides": {
"@types/mime": "3.0.4",
"next": "14.2.15"
"next": "15.0.1",
"@types/react": "npm:types-react@rc",
"@types/react-dom": "npm:types-react-dom@rc"
}
}
}

View File

@@ -32,6 +32,7 @@
"@types/oauth": "0.9.1",
"@types/passport": "1.0.7",
"@types/secure-password": "3.1.1",
"arctic": "2.3.3",
"b64-lite": "1.4.0",
"bad-behavior": "1.0.1",
"cookie": "0.4.1",
@@ -68,18 +69,17 @@
},
"devDependencies": {
"@blitzjs/config": "2.1.3",
"@testing-library/react": "13.4.0",
"@testing-library/react-hooks": "8.0.1",
"@testing-library/react": "16.0.1",
"@types/cookie": "0.4.1",
"@types/debug": "4.1.7",
"@types/jsonwebtoken": "8.5.8",
"@types/react": "18.0.25",
"@types/react-dom": "17.0.14",
"@types/react": "npm:types-react@19.0.0",
"@types/react-dom": "npm:types-react-dom@19.0.0",
"blitz": "2.1.3",
"next": "14.2.15",
"next": "15.0.1",
"next-auth": "4.24.7",
"react": "18.2.0",
"react-dom": "18.2.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"secure-password": "4.0.0",
"typescript": "^4.8.4",
"unbuild": "0.7.6",

View File

@@ -7,7 +7,7 @@ import {parsePublicDataToken, getPublicDataStore, useSession} from "./index"
import {COOKIE_PUBLIC_DATA_TOKEN} from "../shared"
import {toBase64} from "b64-lite"
import {act} from "@testing-library/react"
import {renderHook} from "@testing-library/react-hooks"
import {renderHook} from "@testing-library/react"
vi.mock("blitz", async () => {
const blitz = await vi.importActual("blitz")

View File

@@ -260,7 +260,7 @@ export type RedirectAuthenticatedToFn = (
) => RedirectAuthenticatedTo
export type BlitzPage<P = {}> = React.ComponentType<P> & {
getLayout?: (component: JSX.Element) => JSX.Element
getLayout?: (component: React.JSX.Element) => React.JSX.Element
authenticate?: boolean | {redirectTo?: string | RouteUrlObject; role?: string | Array<string>}
suppressFirstRenderFlicker?: boolean
redirectAuthenticatedTo?: RedirectAuthenticatedTo | RedirectAuthenticatedToFn

View File

@@ -2,3 +2,4 @@ import "./global"
export * from "./index-browser"
export * from "./server"
export * from "./oauth"

View File

@@ -0,0 +1,37 @@
import {decodeIdToken, GitHub, Google, OAuth2Tokens} from "arctic"
import {ArcticOAuthClient, SupportedOAuthProviders} from "./types"
type InternalConfig = {
name: SupportedOAuthProviders
profile(token: OAuth2Tokens): Record<string, unknown>
pkce: true
client:
}
export function getInternalConfig(provider: SupportedOAuthProviders, client: ArcticOAuthClient) {
switch (provider) {
case SupportedOAuthProviders.Google:
return {
name: SupportedOAuthProviders.Google,
profile(token: OAuth2Tokens) {
const idToken = token.idToken()
return decodeIdToken(idToken)
},
pkce: true,
client: client,
}
case SupportedOAuthProviders.GitHub:
return {
name: SupportedOAuthProviders.GitHub,
profile(token: OAuth2Tokens) {
const idToken = token.idToken()
return decodeIdToken(idToken)
},
pkce: false,
client: client,
}
default:
throw new Error(`Unsupported provider: ${provider}`)
}
}

View File

@@ -0,0 +1,112 @@
import {
ArcticFetchError,
decodeIdToken,
generateCodeVerifier,
OAuth2Client,
OAuth2RequestError,
OAuth2Tokens,
} from "arctic"
import {generateState} from "arctic"
import cookie, {parse} from "cookie"
import {ArcticOAuthClient, SupportedOAuthProviders} from "./types"
import {getInternalConfig} from "./config"
type Params = Record<string, unknown>
type OAuthConfig = Array<{
client: ArcticOAuthClient
name: string
scopes: string[]
}>
export function oAuth2Handler(config: OAuthConfig) {
async function GET(req: Request, segmentData: {params: Promise<Params>}) {
const params = await segmentData.params
const blitzAuth = params.blitzAuth as string[]
const clientName = blitzAuth[0]
const clientConfig = config.find((c) => c.name === clientName)
if (clientConfig === undefined || !clientName) {
return new Response("Not Found", {status: 404})
}
const internalConfig = getInternalConfig(
clientName as SupportedOAuthProviders,
clientConfig.client,
)
const action = blitzAuth[1]
if (action === "callback") {
const cookies = parse(req.headers.get("Cookie") || "")
const storedState = cookies.state
const codeVerifier = cookies.code_verifier
const url = new URL(req.url)
const code = url.searchParams.get("code")
const state = url.searchParams.get("state")
if (
code === null ||
storedState === undefined ||
codeVerifier === undefined ||
state !== storedState
) {
return new Response("Bad Request", {status: 400})
}
try {
let token: OAuth2Tokens
if (internalConfig.pkce) {
token = await internalConfig.client.validateAuthorizationCode(code, codeVerifier)
} else {
token = await internalConfig.client.validateAuthorizationCode(code, clientConfig.scopes)
}
console.log(token)
const idToken = token.idToken()
console.log(idToken, decodeIdToken(idToken))
} catch (e) {
if (e instanceof OAuth2RequestError) {
const code = e.code
const message = e.message
console.log(code, message)
return new Response("Bad Request", {status: 400})
}
if (e instanceof ArcticFetchError) {
const message = e.message
console.log(message)
return new Response("Bad Request", {status: 400})
}
console.log(e)
return new Response("Bad Request", {status: 400})
}
} else {
const state = generateState()
const codeVerifier = generateCodeVerifier()
let url: URL
if (internalConfig.pkce) {
url = internalConfig.client.createAuthorizationURL(state, codeVerifier, clientConfig.scopes)
} else {
url = internalConfig.client.createAuthorizationURL(state, clientConfig.scopes)
}
const stateCookie = cookie.serialize("state", state, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
maxAge: 60 * 10,
path: "/",
})
const codeVerifierCookie = cookie.serialize("code_verifier", codeVerifier, {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
maxAge: 60 * 10,
path: "/",
})
const headers = new Headers({
Location: url.toString(),
})
headers.append("Set-Cookie", stateCookie)
headers.append("Set-Cookie", codeVerifierCookie)
return new Response(null, {
status: 302,
headers,
})
}
}
return {GET}
}

View File

@@ -0,0 +1,165 @@
import {AmazonCognito} from "arctic"
import {AniList} from "arctic"
import {Apple} from "arctic"
import {Atlassian} from "arctic"
import {Auth0} from "arctic"
import {Authentik} from "arctic"
import {Bitbucket} from "arctic"
import {Box} from "arctic"
import {Bungie} from "arctic"
import {Coinbase} from "arctic"
import {Discord} from "arctic"
import {Dribbble} from "arctic"
import {Dropbox} from "arctic"
import {Etsy} from "arctic"
import {EpicGames} from "arctic"
import {Facebook} from "arctic"
import {Figma} from "arctic"
import {Intuit} from "arctic"
import {GitHub} from "arctic"
import {GitLab} from "arctic"
import {Google} from "arctic"
import {Kakao} from "arctic"
import {KeyCloak} from "arctic"
import {Lichess} from "arctic"
import {Line} from "arctic"
import {Linear} from "arctic"
import {LinkedIn} from "arctic"
import {MicrosoftEntraId} from "arctic"
import {MyAnimeList} from "arctic"
import {Naver} from "arctic"
import {Notion} from "arctic"
import {Okta} from "arctic"
import {Osu} from "arctic"
import {Patreon} from "arctic"
import {Polar} from "arctic"
import {Reddit} from "arctic"
import {Roblox} from "arctic"
import {Salesforce} from "arctic"
import {Shikimori} from "arctic"
import {Slack} from "arctic"
import {Spotify} from "arctic"
import {StartGG} from "arctic"
import {Strava} from "arctic"
import {Tiltify} from "arctic"
import {Tumblr} from "arctic"
import {Twitch} from "arctic"
import {Twitter} from "arctic"
import {VK} from "arctic"
import {WorkOS} from "arctic"
import {Yahoo} from "arctic"
import {Yandex} from "arctic"
import {Zoom} from "arctic"
import {FortyTwo} from "arctic"
export type ArcticOAuthClient =
| AniList
| Reddit
| Apple
| Atlassian
| Auth0
| Bitbucket
| Box
| Bungie
| Coinbase
| Discord
| Dribbble
| Dropbox
| EpicGames
| Facebook
| Figma
| FortyTwo
| GitHub
| GitLab
| Kakao
| LinkedIn
| Linear
| Naver
| Notion
| Osu
| Patreon
| Shikimori
| Slack
| Spotify
| StartGG
| Strava
| Tiltify
| Tumblr
| Twitch
| VK
| WorkOS
| Yahoo
| Yandex
| Intuit
// pkce
| Authentik
| AmazonCognito
| Twitter
| Polar
| MyAnimeList
| KeyCloak
| Salesforce
| Roblox
| Lichess
| MicrosoftEntraId
| Google
| Okta
| Etsy
| Line
| Zoom
export enum SupportedOAuthProviders {
Authentik = "Authentik",
AmazonCognito = "AmazonCognito",
Twitter = "Twitter",
Polar = "Polar",
MyAnimeList = "MyAnimeList",
KeyCloak = "KeyCloak",
Salesforce = "Salesforce",
Roblox = "Roblox",
Lichess = "Lichess",
MicrosoftEntraId = "MicrosoftEntraId",
Google = "Google",
Okta = "Okta",
Etsy = "Etsy",
Line = "Line",
Zoom = "Zoom",
AniList = "AniList",
Reddit = "Reddit",
Apple = "Apple",
Atlassian = "Atlassian",
Auth0 = "Auth0",
Bitbucket = "Bitbucket",
Box = "Box",
Bungie = "Bungie",
Coinbase = "Coinbase",
Discord = "Discord",
Dribbble = "Dribbble",
Dropbox = "Dropbox",
EpicGames = "EpicGames",
Facebook = "Facebook",
Figma = "Figma",
FortyTwo = "FortyTwo",
GitHub = "GitHub",
GitLab = "GitLab",
Kakao = "Kakao",
LinkedIn = "LinkedIn",
Linear = "Linear",
Naver = "Naver",
Notion = "Notion",
Osu = "Osu",
Patreon = "Patreon",
Shikimori = "Shikimori",
Slack = "Slack",
Spotify = "Spotify",
StartGG = "StartGG",
Strava = "Strava",
Tiltify = "Tiltify",
Tumblr = "Tumblr",
Twitch = "Twitch",
VK = "VK",
WorkOS = "WorkOS",
Yahoo = "Yahoo",
Yandex = "Yandex",
Intuit = "Intuit",
}

View File

@@ -289,8 +289,10 @@ const makeProxyToPublicData = <T extends SessionContextClass>(ctxClass: T): T =>
export async function getBlitzContext(): Promise<Ctx> {
try {
const {headers, cookies} = require("next/headers")
const reqHeader = Object.fromEntries(headers())
const csrfToken = cookies().get(COOKIE_CSRF_TOKEN())
const cookieStore = await cookies()
const headersStore = await headers()
const reqHeader = Object.fromEntries(headersStore)
const csrfToken = cookieStore.get(COOKIE_CSRF_TOKEN())
if (csrfToken) {
reqHeader[HEADER_CSRF] = csrfToken.value
}

View File

@@ -48,21 +48,20 @@
"@blitzjs/config": "2.1.3",
"@testing-library/dom": "8.13.0",
"@testing-library/jest-dom": "5.16.3",
"@testing-library/react": "13.4.0",
"@testing-library/react-hooks": "8.0.1",
"@testing-library/react": "16.0.1",
"@testing-library/user-event": "13.5.0",
"@types/debug": "4.1.7",
"@types/node": "18.11.9",
"@types/react": "18.0.25",
"@types/react-dom": "17.0.14",
"@types/react": "npm:types-react@19.0.0",
"@types/react-dom": "npm:types-react-dom@19.0.0",
"@types/testing-library__react-hooks": "4.0.0",
"blitz": "2.1.3",
"cross-spawn": "7.0.3",
"find-up": "4.1.0",
"next": "14.2.15",
"next": "15.0.1",
"next-router-mock": "0.9.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"resolve-from": "5.0.0",
"ts-jest": "27.1.4",
"tslog": "4.9.0",

View File

@@ -1 +1,8 @@
module.exports = {}
const exports = {
"npm-which": {},
"cross-spawn": {},
fs: {},
child_process: {},
}
module.exports = exports

View File

@@ -70,7 +70,7 @@ test("handleError forwards along async errors", async () => {
//
// React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary."
// `)
expect(consoleError).toHaveBeenCalledTimes(3)
expect(consoleError).toHaveBeenCalledTimes(1)
consoleError.mockClear()
// can recover
@@ -116,7 +116,7 @@ test("can pass an error to useErrorHandler", async () => {
//
// React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundary."
// `)
expect(consoleError).toHaveBeenCalledTimes(3)
expect(consoleError).toHaveBeenCalledTimes(1)
consoleError.mockClear()
// can recover

View File

@@ -77,25 +77,10 @@ test("standard use-case", () => {
const {unmount} = render(<App />)
userEvent.type(screen.getByRole("textbox", {name: /username/i}), "fail")
const [[actualError], [componentStack]] = consoleError.mock.calls
expect(firstLine(actualError as string)).toMatchInlineSnapshot(
`"Error: Uncaught [Error: 💥 CABOOM 💥]"`,
)
expect(cleanStack(componentStack)).toMatchInlineSnapshot(`
"Error: Uncaught [Error: 💥 CABOOM 💥]
at reportException
at innerInvokeEventListeners
at invokeEventListeners
at HTMLUnknownElementImpl._dispatch
at HTMLUnknownElementImpl.dispatchEvent
at HTMLUnknownElement.dispatchEvent
at Object.invokeGuardedCallbackDev
at invokeGuardedCallback
at beginWork\$1
at performUnitOfWork "
`)
expect(consoleError).toHaveBeenCalledTimes(3)
const calls = consoleError.mock.calls[0]
//@ts-expect-error - it's a mock
expect(calls[1]).toMatchInlineSnapshot("[Error: 💥 CABOOM 💥]")
expect(consoleError).toHaveBeenCalledTimes(1)
consoleError.mockClear()
expect(screen.getByRole("alert")).toMatchInlineSnapshot(`
@@ -149,7 +134,7 @@ test("fallbackRender prop", () => {
}
const {unmount} = render(<App />)
expect(consoleError).toHaveBeenCalledTimes(3)
expect(consoleError).toHaveBeenCalledTimes(1)
consoleError.mockClear()
// the render prop API allows a single action to reset the app state
@@ -168,7 +153,7 @@ test("simple fallback is supported", () => {
<span>child</span>
</ErrorBoundary>,
)
expect(consoleError).toHaveBeenCalledTimes(3)
expect(consoleError).toHaveBeenCalledTimes(1)
consoleError.mockClear()
expect(screen.getByText(/oh no/i)).to.exist
expect(screen.queryByText(/child/i)).to.not.exist
@@ -183,27 +168,16 @@ test("withErrorBoundary HOC", () => {
() => {
throw new Error("💥 CABOOM 💥")
},
{FallbackComponent: ErrorFallback, onError: onErrorHandler},
{
FallbackComponent: ErrorFallback,
onError: onErrorHandler,
},
)
const {unmount} = render(<Boundary />)
const [[actualError], [componentStack]] = consoleError.mock.calls
const firstLineOfError = firstLine(actualError as string)
expect(firstLineOfError).toMatchInlineSnapshot(`"Error: Uncaught [Error: 💥 CABOOM 💥]"`)
expect(cleanStack(componentStack)).toMatchInlineSnapshot(`
"Error: Uncaught [Error: 💥 CABOOM 💥]
at reportException
at innerInvokeEventListeners
at invokeEventListeners
at HTMLUnknownElementImpl._dispatch
at HTMLUnknownElementImpl.dispatchEvent
at HTMLUnknownElement.dispatchEvent
at Object.invokeGuardedCallbackDev
at invokeGuardedCallback
at beginWork\$1
at performUnitOfWork "
`)
expect(consoleError).toHaveBeenCalledTimes(3)
const calls = consoleError.mock.calls[0]
//@ts-expect-error - it's a mock
expect(calls[1]).toMatchInlineSnapshot("[Error: 💥 CABOOM 💥]")
expect(consoleError).toHaveBeenCalledTimes(1)
consoleError.mockClear()
const [error, onErrorComponentStack] = (onErrorHandler.mock.calls as [[Error, string]])[0]
@@ -265,7 +239,6 @@ test("requires either a fallback, fallbackRender, or FallbackComponent", () => {
let unmount: undefined | (() => void)
expect(() => {
const result = render(
// @ts-expect-error we're testing the runtime check of missing props here
<ErrorBoundary>
<Bomb />
</ErrorBoundary>,
@@ -318,7 +291,7 @@ test("supports automatic reset of error boundary when resetKeys change", () => {
// blow it up
userEvent.click(screen.getByText("toggle explode"))
expect(screen.getByRole("alert")).to.exist
expect(consoleError).toHaveBeenCalledTimes(3)
expect(consoleError).toHaveBeenCalledTimes(1)
consoleError.mockClear()
// recover via try again button
@@ -333,7 +306,7 @@ test("supports automatic reset of error boundary when resetKeys change", () => {
// blow it up again
userEvent.click(screen.getByText("toggle explode"))
expect(screen.getByRole("alert")).to.exist
expect(consoleError).toHaveBeenCalledTimes(3)
expect(consoleError).toHaveBeenCalledTimes(1)
consoleError.mockClear()
// recover via resetKeys change
@@ -348,7 +321,7 @@ test("supports automatic reset of error boundary when resetKeys change", () => {
// blow it up again
userEvent.click(screen.getByText("toggle explode"))
expect(screen.getByRole("alert")).to.exist
expect(consoleError).toHaveBeenCalledTimes(3)
expect(consoleError).toHaveBeenCalledTimes(1)
consoleError.mockClear()
// toggles adding an extra resetKey to the array
@@ -358,7 +331,7 @@ test("supports automatic reset of error boundary when resetKeys change", () => {
expect(handleResetKeysChange).toHaveBeenCalledWith([true], [true, true])
handleResetKeysChange.mockClear()
expect(screen.getByRole("alert")).to.exist
expect(consoleError).toHaveBeenCalledTimes(3)
expect(consoleError).toHaveBeenCalledTimes(1)
consoleError.mockClear()
// toggle explode back to false
@@ -369,7 +342,7 @@ test("supports automatic reset of error boundary when resetKeys change", () => {
expect(handleResetKeysChange).toHaveBeenCalledWith([true, true], [false, true])
expect(screen.getByRole("alert")).to.exist
handleResetKeysChange.mockClear()
expect(consoleError).toHaveBeenCalledTimes(3)
expect(consoleError).toHaveBeenCalledTimes(1)
consoleError.mockClear()
// toggle extra resetKey
@@ -411,7 +384,7 @@ test("supports reset via resetKeys right after error is triggered on component m
// it blows up on render
expect(screen.queryByRole("alert", {})).to.exist
expect(consoleError).toHaveBeenCalledTimes(3)
expect(consoleError).toHaveBeenCalledTimes(1)
consoleError.mockClear()
// recover via "toggle explode" button

View File

@@ -1,7 +1,7 @@
import {RedirectError} from "blitz"
import {useRouter} from "next/compat/router"
import type {NextRouter} from "next/router"
import * as React from "react"
import React from "react"
import {RouterContext} from "./router-context"
import _debug from "debug"
import type {ExcludeRouterProps, WithRouterProps} from "next/dist/client/with-router"
@@ -77,7 +77,7 @@ const initialState: ErrorBoundaryState = {error: null}
function withRouter<P extends WithRouterProps>(
ComposedComponent: React.ComponentType<P>,
): React.ComponentType<ExcludeRouterProps<P>> {
function WithRouterWrapper(props: any): JSX.Element {
function WithRouterWrapper(props: any): React.JSX.Element {
return <ComposedComponent router={useRouter()} {...props} />
}
@@ -114,7 +114,13 @@ export const ErrorBoundary = withRouter(
await this.props.router.push(error.url)
return
}
this.props.onError?.(error, info)
if (this.props.onError) {
let componentStack = info.componentStack
if (!componentStack) {
componentStack = new Error("Stack trace").stack || ""
}
this.props.onError(error, {componentStack})
}
}
componentDidMount() {
@@ -190,7 +196,7 @@ export const ErrorBoundary = withRouter(
},
)
function withErrorBoundary<P extends JSX.IntrinsicAttributes>(
function withErrorBoundary<P extends React.JSX.IntrinsicAttributes>(
Component: React.ComponentType<P>,
errorBoundaryProps: ErrorBoundaryProps,
): React.ComponentType<P> {

View File

@@ -1,10 +1,16 @@
import React from "react"
import {NextPageContext} from "next"
import dynamic from "next/dynamic"
const Head = dynamic(() => import("next/head").then((mod) => mod.default), {
ssr: false,
loading: () => null,
})
const Head = dynamic(
() =>
import("next/head").then((mod) => ({
default: mod.default,
})),
{
ssr: false,
loading: () => null,
},
)
const statusCodes: {[code: number]: string} = {
400: "Bad Request",

View File

@@ -9,10 +9,16 @@ import type {Router} from "next/router"
import {BlitzProvider} from "./provider"
import dynamic from "next/dynamic"
export {Routes} from ".blitz"
const Head = dynamic(() => import("next/head").then((mod) => mod.default), {
ssr: false,
loading: () => null,
})
const Head = dynamic(
() =>
import("next/head").then((mod) => ({
default: mod.default,
})),
{
ssr: false,
loading: () => null,
},
)
export {BlitzProvider} from "./provider"
@@ -55,7 +61,7 @@ type RedirectAuthenticatedToFnCtx = {
}
type RedirectAuthenticatedToFn = (args: RedirectAuthenticatedToFnCtx) => RedirectAuthenticatedTo
export type BlitzPage<P = {}> = React.ComponentType<P> & {
getLayout?: (component: JSX.Element) => JSX.Element
getLayout?: (component: React.JSX.Element) => React.JSX.Element
authenticate?: boolean | {redirectTo?: string | RouteUrlObject; role?: string | Array<string>}
suppressFirstRenderFlicker?: boolean
redirectAuthenticatedTo?: RedirectAuthenticatedTo | RedirectAuthenticatedToFn

View File

@@ -3,7 +3,7 @@ import type {QueryClient, HydrateOptions} from "@blitzjs/rpc"
import React from "react"
export type BlitzProviderProps = {
children: JSX.Element
children: React.JSX.Element
client?: QueryClient
contextSharing?: boolean
dehydratedState?: unknown

View File

@@ -4,7 +4,7 @@
import React from "react"
import {describe, it, expect, vi, afterEach} from "vitest"
import {extractRouterParams, useParam, useParams} from "./use-params"
import {renderHook as defaultRenderHook} from "@testing-library/react-hooks"
import {renderHook as defaultRenderHook} from "@testing-library/react"
import {NextRouter} from "next/router"
import {RouterContext} from "./router-context"

View File

@@ -46,12 +46,12 @@
"@blitzjs/config": "2.1.3",
"@tanstack/query-core": "4.24.4",
"@types/debug": "4.1.7",
"@types/react": "18.0.25",
"@types/react-dom": "17.0.14",
"@types/react": "npm:types-react@19.0.0",
"@types/react-dom": "npm:types-react-dom@19.0.0",
"blitz": "2.1.3",
"next": "14.2.15",
"react": "18.2.0",
"react-dom": "18.2.0",
"next": "15.0.1",
"react": "19.0.0",
"react-dom": "19.0.0",
"typescript": "^4.8.4",
"unbuild": "0.7.6",
"watch": "1.0.2",

View File

@@ -221,7 +221,7 @@ async function getResolverMap(): Promise<ResolverFiles | null | undefined> {
// Handles:
// - Vite
// {
// const {resolverFilesLoaded, viteProvider} = await loadTelefuncFilesWithVite(runContext)
// const {resolverFilesLoaded, viteProvider} = await loadTelefuncFilesWithVite(run
// if (resolverFilesLoaded) {
// assertUsage(
// Object.keys(resolverFilesLoaded).length > 0,
@@ -364,17 +364,18 @@ type Params = Record<string, unknown>
export function rpcAppHandler(config?: RpcConfig) {
registerBlitzErrorClasses()
async function handleRpcRequest(req: Request, context: {params: Params}, ctx?: Ctx) {
async function handleRpcRequest(req: Request, segmentData: {params: Promise<Params>}, ctx?: Ctx) {
const params = await segmentData.params
const session = ctx?.session
const resolverMap = await getResolverMap()
assert(resolverMap, "No query or mutation resolvers found")
assert(
Array.isArray(context.params.blitz),
Array.isArray(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 relativeRoutePath = (params.blitz as string[])?.join("/")
const routePath = "/" + relativeRoutePath
const resolverName = routePath.replace(/(\/api\/rpc)?\//, "")
const rpcLogger = new RpcLogger(resolverName, config?.logging)
@@ -413,14 +414,14 @@ export function rpcAppHandler(config?: RpcConfig) {
json:
req.method === "POST"
? body.params
: context.params.params
? parse(`${context.params.params}`)
: params.params
? parse(`${params.params}`)
: undefined,
meta:
req.method === "POST"
? body.meta?.params
: context.params.meta
? parse(`${context.params.meta}`)
: params.meta
? parse(`${params.meta}`)
: undefined,
})
rpcLogger.timer.initResolver()

View File

@@ -1,7 +1,7 @@
import {QueryClientProvider} from "@tanstack/react-query"
import React from "react"
export type BlitzProviderType = ({children}: {children: React.ReactNode}) => JSX.Element
export type BlitzProviderType = ({children}: {children: React.ReactNode}) => React.JSX.Element
const BlitzProvider: BlitzProviderType = ({children}) => {
const [queryClient] = React.useState(globalThis.queryClient)

View File

@@ -95,12 +95,12 @@
"@types/npm-which": "3.0.1",
"@types/progress": "2.0.5",
"@types/prompts": "2.0.14",
"@types/react": "18.0.25",
"@types/react-dom": "17.0.14",
"@types/react": "npm:types-react@19.0.0",
"@types/react-dom": "npm:types-react-dom@19.0.0",
"@types/test-listen": "1.1.0",
"@types/watchpack": "1.1.1",
"express": "4.17.3",
"react": "18.2.0",
"react": "19.0.0",
"test-listen": "1.1.0",
"typescript": "^4.8.4",
"unbuild": "0.7.6",

View File

@@ -11,6 +11,7 @@ import {
registerBlitzErrorClasses,
} from "./errors"
import type {EventHooks, MiddlewareHooks} from "./types"
import React from "react"
export {
AuthenticationError,
AuthorizationError,
@@ -26,7 +27,7 @@ export * from "./utils/enhance-prisma"
export type BlitzProviderComponentType = <TProps = any>(
component: ComponentType<TProps>,
) => {
(props: TProps): JSX.Element
(props: TProps): React.JSX.Element
displayName: string
}

View File

@@ -64,15 +64,15 @@
"@types/mem-fs-editor": "7.0.1",
"@types/pluralize": "0.0.29",
"@types/prettier": "2.4.4",
"@types/react": "18.0.25",
"@types/react-dom": "17.0.14",
"@types/react": "npm:types-react@19.0.0",
"@types/react-dom": "npm:types-react-dom@19.0.0",
"@types/vinyl": "2.0.6",
"@typescript-eslint/eslint-plugin": "5.42.1",
"@typescript-eslint/parser": "5.9.1",
"babylon": "6.18.0",
"debug": "4.3.3",
"eslint": "8.27.0",
"react": "18.2.0",
"react": "19.0.0",
"typescript": "^4.8.4",
"unbuild": "0.6.9",
"watch": "1.0.2"

View File

@@ -5,7 +5,7 @@ import { validateZodSchema } from "blitz"
export { FORM_ERROR } from "final-form"
export interface FormProps<S extends z.ZodType<any, any>>
extends Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit"> {
extends Omit<PropsWithoutRef<React.JSX.IntrinsicElements["form"]>, "onSubmit"> {
/** All your form fields */
children?: ReactNode
/** Text to display in the submit button */

View File

@@ -1,14 +1,14 @@
import { forwardRef, PropsWithoutRef } from "react"
import { useField } from "react-final-form"
export interface LabeledSelectFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["select"]> {
export interface LabeledSelectFieldProps extends PropsWithoutRef<React.JSX.IntrinsicElements["select"]> {
/** Field name. */
name: string
/** Field label. */
label: string
type?: "number" | "string"
options: any
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>
}
export const LabeledSelectField = forwardRef<HTMLSelectElement, LabeledSelectFieldProps>(

View File

@@ -1,14 +1,14 @@
import { forwardRef, ComponentPropsWithoutRef, PropsWithoutRef } from "react"
import { useField, UseFieldConfig } from "react-final-form"
export interface LabeledTextFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["input"]> {
export interface LabeledTextFieldProps extends PropsWithoutRef<React.JSX.IntrinsicElements["input"]> {
/** Field name. */
name: string
/** Field label. */
label: string
/** Field type. Doesn't include radio buttons and checkboxes */
type?: "text" | "password" | "email" | "number"
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>
labelProps?: ComponentPropsWithoutRef<"label">
fieldProps?: UseFieldConfig<string>
}

View File

@@ -4,7 +4,7 @@ import { validateZodSchema } from "blitz"
import { z } from "zod"
export interface FormProps<S extends z.ZodType<any, any>>
extends Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit"> {
extends Omit<PropsWithoutRef<React.JSX.IntrinsicElements["form"]>, "onSubmit"> {
/** All your form fields */
children?: ReactNode
/** Text to display in the submit button */

View File

@@ -2,14 +2,14 @@ import { forwardRef, PropsWithoutRef } from "react";
import { useFormikContext, ErrorMessage, Field } from "formik";
export interface LabeledSelectFieldProps
extends PropsWithoutRef<JSX.IntrinsicElements["select"]> {
extends PropsWithoutRef<React.JSX.IntrinsicElements["select"]> {
/** Field name. */
name: string;
/** Field label. */
label: string;
/** Field options. */
options: any;
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>;
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>;
}
export const LabeledSelectField = forwardRef<

View File

@@ -1,14 +1,14 @@
import { forwardRef, PropsWithoutRef } from "react"
import { useField, useFormikContext, ErrorMessage } from "formik"
export interface LabeledTextFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["input"]> {
export interface LabeledTextFieldProps extends PropsWithoutRef<React.JSX.IntrinsicElements["input"]> {
/** Field name. */
name: string
/** Field label. */
label: string
/** Field type. Doesn't include radio buttons and checkboxes */
type?: "text" | "password" | "email" | "number"
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>
}
export const LabeledTextField = forwardRef<HTMLInputElement, LabeledTextFieldProps>(

View File

@@ -4,7 +4,7 @@ import { zodResolver } from "@hookform/resolvers/zod"
import { z } from "zod"
export interface FormProps<S extends z.ZodType<any, any>>
extends Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit"> {
extends Omit<PropsWithoutRef<React.JSX.IntrinsicElements["form"]>, "onSubmit"> {
/** All your form fields */
children?: ReactNode
/** Text to display in the submit button */

View File

@@ -2,14 +2,14 @@ import { ComponentPropsWithoutRef, forwardRef, PropsWithoutRef } from "react"
import { useFormContext } from "react-hook-form"
import { ErrorMessage } from "@hookform/error-message"
export interface LabeledSelectFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["select"]> {
export interface LabeledSelectFieldProps extends PropsWithoutRef<React.JSX.IntrinsicElements["select"]> {
/** Field name. */
name: string
/** Field label. */
label: string
/** Field type. Doesn't include radio buttons and checkboxes */
options: any[]
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>
labelProps?: ComponentPropsWithoutRef<"label">
}

View File

@@ -2,14 +2,14 @@ import { forwardRef, PropsWithoutRef, ComponentPropsWithoutRef } from "react"
import { useFormContext } from "react-hook-form"
import { ErrorMessage } from "@hookform/error-message"
export interface LabeledTextFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["input"]> {
export interface LabeledTextFieldProps extends PropsWithoutRef<React.JSX.IntrinsicElements["input"]> {
/** Field name. */
name: string
/** Field label. */
label: string
/** Field type. Doesn't include radio buttons and checkboxes */
type?: "text" | "password" | "email" | "number"
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>
labelProps?: ComponentPropsWithoutRef<"label">
}

View File

@@ -41,8 +41,7 @@
"devDependencies": {
"@next/env": "13.4.19",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "13.4.0",
"@testing-library/react-hooks": "8.0.1",
"@testing-library/react": "16.0.1",
"@types/node": "18.11.9",
"@types/preview-email": "2.0.1",
"@types/react": "18.0.25",

View File

@@ -5,7 +5,7 @@ import { validateZodSchema } from "blitz"
export { FORM_ERROR } from "final-form"
export interface FormProps<S extends z.ZodType<any, any>>
extends Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit"> {
extends Omit<PropsWithoutRef<React.JSX.IntrinsicElements["form"]>, "onSubmit"> {
/** All your form fields */
children?: ReactNode
/** Text to display in the submit button */

View File

@@ -1,14 +1,14 @@
import { forwardRef, PropsWithoutRef } from "react"
import { useField } from "react-final-form"
export interface LabeledSelectFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["select"]> {
export interface LabeledSelectFieldProps extends PropsWithoutRef<React.JSX.IntrinsicElements["select"]> {
/** Field name. */
name: string
/** Field label. */
label: string
type?: "number" | "string"
options: any
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>
}
export const LabeledSelectField = forwardRef<HTMLSelectElement, LabeledSelectFieldProps>(

View File

@@ -1,14 +1,14 @@
import { forwardRef, ComponentPropsWithoutRef, PropsWithoutRef } from "react"
import { useField, UseFieldConfig } from "react-final-form"
export interface LabeledTextFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["input"]> {
export interface LabeledTextFieldProps extends PropsWithoutRef<React.JSX.IntrinsicElements["input"]> {
/** Field name. */
name: string
/** Field label. */
label: string
/** Field type. Doesn't include radio buttons and checkboxes */
type?: "text" | "password" | "email" | "number"
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>
labelProps?: ComponentPropsWithoutRef<"label">
fieldProps?: UseFieldConfig<string>
}

View File

@@ -4,7 +4,7 @@ import { validateZodSchema } from "blitz"
import { z } from "zod"
export interface FormProps<S extends z.ZodType<any, any>>
extends Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit"> {
extends Omit<PropsWithoutRef<React.JSX.IntrinsicElements["form"]>, "onSubmit"> {
/** All your form fields */
children?: ReactNode
/** Text to display in the submit button */

View File

@@ -2,14 +2,14 @@ import { forwardRef, PropsWithoutRef } from "react";
import { useFormikContext, ErrorMessage, Field } from "formik";
export interface LabeledSelectFieldProps
extends PropsWithoutRef<JSX.IntrinsicElements["select"]> {
extends PropsWithoutRef<React.JSX.IntrinsicElements["select"]> {
/** Field name. */
name: string;
/** Field label. */
label: string;
/** Field options. */
options: any;
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>;
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>;
}
export const LabeledSelectField = forwardRef<

View File

@@ -1,14 +1,14 @@
import { forwardRef, PropsWithoutRef } from "react"
import { useField, useFormikContext, ErrorMessage } from "formik"
export interface LabeledTextFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["input"]> {
export interface LabeledTextFieldProps extends PropsWithoutRef<React.JSX.IntrinsicElements["input"]> {
/** Field name. */
name: string
/** Field label. */
label: string
/** Field type. Doesn't include radio buttons and checkboxes */
type?: "text" | "password" | "email" | "number"
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>
}
export const LabeledTextField = forwardRef<HTMLInputElement, LabeledTextFieldProps>(

View File

@@ -4,7 +4,7 @@ import { zodResolver } from "@hookform/resolvers/zod"
import { z } from "zod"
export interface FormProps<S extends z.ZodType<any, any>>
extends Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit"> {
extends Omit<PropsWithoutRef<React.JSX.IntrinsicElements["form"]>, "onSubmit"> {
/** All your form fields */
children?: ReactNode
/** Text to display in the submit button */

View File

@@ -2,14 +2,14 @@ import { ComponentPropsWithoutRef, forwardRef, PropsWithoutRef } from "react"
import { useFormContext } from "react-hook-form"
import { ErrorMessage } from "@hookform/error-message"
export interface LabeledSelectFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["select"]> {
export interface LabeledSelectFieldProps extends PropsWithoutRef<React.JSX.IntrinsicElements["select"]> {
/** Field name. */
name: string
/** Field label. */
label: string
/** Field type. Doesn't include radio buttons and checkboxes */
options: any[]
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>
labelProps?: ComponentPropsWithoutRef<"label">
}

View File

@@ -2,14 +2,14 @@ import { forwardRef, PropsWithoutRef, ComponentPropsWithoutRef } from "react"
import { useFormContext } from "react-hook-form"
import { ErrorMessage } from "@hookform/error-message"
export interface LabeledTextFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["input"]> {
export interface LabeledTextFieldProps extends PropsWithoutRef<React.JSX.IntrinsicElements["input"]> {
/** Field name. */
name: string
/** Field label. */
label: string
/** Field type. Doesn't include radio buttons and checkboxes */
type?: "text" | "password" | "email" | "number"
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>
labelProps?: ComponentPropsWithoutRef<"label">
}

View File

@@ -37,8 +37,7 @@
"devDependencies": {
"@next/bundle-analyzer": "12.0.8",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "13.4.0",
"@testing-library/react-hooks": "8.0.1",
"@testing-library/react": "16.0.1",
"@types/node": "18.11.9",
"@types/preview-email": "2.0.1",
"@types/react": "18.0.25",

View File

@@ -38,8 +38,7 @@
"@next/bundle-analyzer": "12.0.8",
"@next/env": "13.4.19",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "13.4.0",
"@testing-library/react-hooks": "8.0.1",
"@testing-library/react": "16.0.1",
"@types/node": "18.11.9",
"@types/preview-email": "2.0.1",
"@types/react": "18.0.25",

View File

@@ -1,7 +1,7 @@
import {vi} from "vitest"
import { render as defaultRender } from "@testing-library/react"
import { renderHook as defaultRenderHook } from "@testing-library/react-hooks"
import { renderHook as defaultRenderHook } from "@testing-library/react"
import { NextRouter } from "next/router"
import {BlitzProvider, RouterContext} from "@blitzjs/next"
import { QueryClient } from "@blitzjs/rpc"

View File

@@ -5,17 +5,19 @@ import get__ModelName__ from "../../queries/get__ModelName__"
import { Edit__ModelName__ } from "../../components/Edit__ModelName__"
type Edit__ModelName__PageProps = {
params: { __modelId__: string }
params: Promise<{ __modelId__: string }>
}
export async function generateMetadata({ params }: Edit__ModelName__PageProps): Promise<Metadata> {
export async function generateMetadata(props: Edit__ModelName__PageProps): Promise<Metadata> {
const params = await props.params;
const __ModelName__ = await invoke(get__ModelName__, { id: Number(params.__modelId__) })
return {
title: `Edit __ModelName__ ${__ModelName__.id} - ${__ModelName__.name}`,
}
}
export default async function Page({ params }: Edit__ModelName__PageProps) {
export default async function Page(props: Edit__ModelName__PageProps) {
const params = await props.params;
return (
<div>
<Suspense fallback={<div>Loading...</div>}>

View File

@@ -5,7 +5,8 @@ import { invoke } from "src/app/blitz-server"
import get__ModelName__ from "../queries/get__ModelName__"
import { __ModelName__ } from "../components/__ModelName__"
export async function generateMetadata({ params }: __ModelName__PageProps): Promise<Metadata> {
export async function generateMetadata(props: __ModelName__PageProps): Promise<Metadata> {
const params = await props.params;
const __ModelName__ = await invoke(get__ModelName__, { id: Number(params.__modelId__) })
return {
title: `__ModelName__ ${__ModelName__.id} - ${__ModelName__.name}`,
@@ -13,10 +14,11 @@ export async function generateMetadata({ params }: __ModelName__PageProps): Prom
}
type __ModelName__PageProps = {
params: { __modelId__: string }
params: Promise<{ __modelId__: string }>
}
export default async function Page({ params }: __ModelName__PageProps) {
export default async function Page(props: __ModelName__PageProps) {
const params = await props.params;
return (
<div>
<p>

View File

@@ -26,9 +26,9 @@
},
"devDependencies": {
"@blitzjs/config": "2.1.3",
"@types/react": "18.0.25",
"@types/react-dom": "17.0.14",
"react": "18.2.0",
"@types/react": "npm:types-react@19.0.0",
"@types/react-dom": "npm:types-react-dom@19.0.0",
"react": "19.0.0",
"typescript": "^4.8.4",
"unbuild": "0.7.6",
"watch": "1.0.2"

1690
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff