1
0
mirror of synced 2026-02-07 03:00:10 -05:00

Compare commits

..

76 Commits

Author SHA1 Message Date
Siddharth Suresh
4e7f837a96 Merge branch 'main' into siddharth/work-with-request 2024-07-01 20:38:03 +05:30
Siddharth Suresh
14b9e0f599 fic 2024-06-19 00:50:18 +05:30
Siddharth Suresh
7c1159f64f fix 2024-06-19 00:49:56 +05:30
Siddharth Suresh
d8d517f0cc Update .changeset/tidy-gorillas-confess.md 2024-06-19 00:47:27 +05:30
Siddharth Suresh
ca1ed08b81 Apply suggestions from code review 2024-06-19 00:40:30 +05:30
Siddharth Suresh
64242c9748 Apply suggestions from code review
Co-authored-by: Brandon Bayer <b@bayer.ws>
2024-06-19 00:39:25 +05:30
Siddharth Suresh
dca22d155f api changes 2024-06-19 00:38:57 +05:30
Siddharth Suresh
0215480c61 fix 2024-06-18 17:42:51 +05:30
Siddharth Suresh
b1e74f894c fix unsupported method of session in rsc 2024-06-18 17:37:35 +05:30
Siddharth Suresh
fecfb99e0b separate the type imports 2024-06-18 17:28:59 +05:30
Siddharth Suresh
342a3bcd9d no var 2024-06-18 17:27:54 +05:30
Siddharth Suresh
7b37512d87 fix jsdoc 2024-06-18 17:24:20 +05:30
Siddharth Suresh
67629fd4a3 remove uses of any 2024-06-18 17:14:39 +05:30
Siddharth Suresh
4b8b909772 Merge branch 'siddharth/work-with-request' of https://github.com/blitz-js/blitz into siddharth/work-with-request 2024-06-16 22:43:30 +05:30
Siddharth Suresh
6e17a210fc remove blitzAuthRpcMiddleware 2024-06-16 22:43:27 +05:30
Siddharth Suresh
2992347aa6 Update .changeset/tidy-gorillas-confess.md 2024-06-16 22:41:29 +05:30
Siddharth Suresh
f3174ccea9 fix changeset formatting 2024-06-16 22:40:29 +05:30
Siddharth Suresh
e5af191880 chore: remove outdated changeset 2024-06-16 22:36:34 +05:30
Siddharth Suresh
0ebf9987e6 chore: add changeset 2024-06-16 22:35:59 +05:30
Siddharth Suresh
4ec2ba65e7 Merge branch 'main' into siddharth/work-with-request 2024-06-16 18:34:28 +05:30
Siddharth Suresh
1b190ba2f2 template fixes 2024-06-16 17:52:53 +05:30
Siddharth Suresh
094495b287 sort deps 2024-06-16 17:50:46 +05:30
Siddharth Suresh
4959b34492 fix the logic 2024-06-16 17:50:08 +05:30
Siddharth Suresh
ff3475a7c3 Revert "review changes"
This reverts commit 14d8eb2820.
2024-06-16 17:36:01 +05:30
Siddharth Suresh
44b88cd4ea Revert "oops"
This reverts commit 94cb55839d.
2024-06-16 17:35:58 +05:30
Siddharth Suresh
26b90c4416 Revert "fix"
This reverts commit 47d0cdd568.
2024-06-16 17:35:56 +05:30
Siddharth Suresh
1c43b2ed3d Revert "fix types"
This reverts commit b06a4fb3bf.
2024-06-16 17:35:53 +05:30
Siddharth Suresh
b1e51da7a7 Merge branch 'main' into siddharth/work-with-request 2024-06-13 19:01:28 +05:30
Siddharth Suresh
b06a4fb3bf fix types 2024-06-09 14:41:24 +05:30
Siddharth Suresh
47d0cdd568 fix 2024-06-06 01:02:09 +05:30
Siddharth Suresh
94cb55839d oops 2024-06-06 01:01:34 +05:30
Siddharth Suresh
14d8eb2820 review changes 2024-06-06 00:59:15 +05:30
Siddharth Suresh
32cc2049b0 remove dependence on http module 2024-06-03 15:30:15 +05:30
Siddharth Suresh
3a0468837e fix overload 2024-06-03 15:26:44 +05:30
Siddharth Suresh
b1d5021284 fix types 2024-06-03 15:24:08 +05:30
Siddharth Suresh
695d2ac3bc Update packages/blitz-auth/src/server/auth-sessions.ts 2024-06-02 00:07:27 +05:30
Siddharth Suresh
695c957633 remove unrelated changes 2024-06-02 00:02:48 +05:30
Siddharth Suresh
811f657d26 Apply suggestions from code review 2024-06-01 23:48:15 +05:30
Siddharth Suresh
aef8172f5b Update integration-tests/next-13-app-dir/src/blitz-server.ts 2024-06-01 23:41:22 +05:30
Siddharth Suresh
f0c3c7a558 fix 2024-06-01 23:39:16 +05:30
Siddharth Suresh
589da91e11 cleanup 2024-06-01 23:23:21 +05:30
Siddharth Suresh
8b345ccc47 imporve api naming 2024-06-01 23:20:58 +05:30
Siddharth Suresh
720e2deb76 revert unnecessary changes 2024-06-01 23:10:24 +05:30
Siddharth Suresh
3725202251 update pnpm lcok 2024-06-01 23:08:06 +05:30
Siddharth Suresh
74cc8f8cf2 fix 2024-06-01 23:04:28 +05:30
Siddharth Suresh
f84781520c pnpm lock update 2024-06-01 23:04:07 +05:30
Siddharth Suresh
ec8d1f583c fix 2024-06-01 23:01:47 +05:30
Siddharth Suresh
7f5c8bb6ab fixes 2024-06-01 23:01:42 +05:30
Siddharth Suresh
631e012969 changeset 2024-06-01 23:01:23 +05:30
Siddharth Suresh
73e0ae7b32 more fixes 2024-06-01 23:00:00 +05:30
Siddharth Suresh
43abbda23d get all tests passing 2024-06-01 22:59:37 +05:30
Siddharth Suresh
b6641c98ee fix 2024-05-28 19:46:34 +05:30
Siddharth Suresh
db9419cd7f Merge branch 'siddharth/work-with-request' of https://github.com/blitz-js/blitz into siddharth/work-with-request 2024-05-28 17:57:55 +05:30
Siddharth Suresh
166deea204 fixes 2024-05-28 17:57:52 +05:30
Siddharth Suresh
fb403302b1 Update packages/blitz-auth/package.json 2024-05-28 17:45:52 +05:30
Siddharth Suresh
31626bfad6 pointless test 2024-05-28 17:30:42 +05:30
Siddharth Suresh
6e8833c6b2 maybe required breaking change 2024-05-28 17:26:34 +05:30
Siddharth Suresh
e7da8b06e1 fix issues with auth 2024-05-28 17:23:11 +05:30
Siddharth Suresh
22d8eba3e2 Merge branch 'main' into siddharth/work-with-request 2024-05-27 10:29:31 +05:30
Siddharth Suresh
f50739a734 fixes 2024-05-22 12:46:35 +05:30
Siddharth Suresh
313e17894f more work 2024-05-22 12:43:04 +05:30
Siddharth Suresh
199b1af49c fix build 2024-04-06 22:10:40 +05:30
Siddharth Suresh
0e4e80bf40 Update packages/blitz-auth/src/server/auth-plugin.ts 2024-04-06 22:10:12 +05:30
Siddharth Suresh
8f2447f44f Merge branch 'siddharth/work-with-request' of https://github.com/blitz-js/blitz into siddharth/work-with-request 2024-04-06 22:09:52 +05:30
Siddharth Suresh
d8e5acceca pnpm lock fix 2024-04-06 22:09:46 +05:30
Siddharth Suresh
c60c0fe76b cleanup 2024-04-06 22:09:33 +05:30
Siddharth Suresh
e2911b0df5 Merge branch 'main' into siddharth/work-with-request 2024-04-06 19:37:04 +05:30
Siddharth Suresh
9b1f57529f Merge branch 'main' into siddharth/work-with-request 2024-04-04 22:59:59 +05:30
Siddharth Suresh
43cd82f4e8 working sveltekit, with regressin of next.js app dir 2023-09-04 16:21:36 +05:30
Siddharth Suresh
7b332d24ec cleanup 2023-09-04 00:21:36 +05:30
Siddharth Suresh
8f99e59dfb working 2023-09-04 00:20:26 +05:30
Siddharth Suresh
1e4cb3755c return headers 2023-08-29 18:46:07 +05:30
Siddharth Suresh
25037f3dd2 blitz-auth now works 2023-08-29 18:17:56 +05:30
Siddharth Suresh
f8054c5434 feat: improvements 2023-08-27 14:33:04 +05:30
Siddharth Suresh
ef36ad4516 rename: rpcRequestHandler 2023-08-27 12:28:20 +05:30
Siddharth Suresh
15a0b1a93c feat: make rpchandler work with Request and return a Response 2023-08-27 02:14:17 +05:30
344 changed files with 12127 additions and 4583 deletions

View File

@@ -4074,76 +4074,6 @@
"contributions": [
"code"
]
},
{
"login": "bezalel6",
"name": "bezalel6",
"avatar_url": "https://avatars.githubusercontent.com/u/51681171?v=4",
"profile": "https://github.com/bezalel6",
"contributions": [
"doc",
"code"
]
},
{
"login": "cherniavskii",
"name": "Andrew Cherniavskii",
"avatar_url": "https://avatars.githubusercontent.com/u/13808724?v=4",
"profile": "cherniavskii.com",
"contributions": [
"doc"
]
},
{
"login": "doe-base",
"name": "Daniel Idoko",
"avatar_url": "https://avatars.githubusercontent.com/u/95912955?v=4",
"profile": "https://danielidoko-r3zt.vercel.app/",
"contributions": [
"doc",
"code",
"test"
]
},
{
"login": "fungilation",
"name": "Gary Fung",
"avatar_url": "https://avatars.githubusercontent.com/u/3803466?v=4",
"profile": "https://garyfung.medium.com",
"contributions": [
"doc",
"code"
]
},
{
"login": "rene-demonsters",
"name": "René Vlugt",
"avatar_url": "https://avatars.githubusercontent.com/u/20322259?v=4",
"profile": "https://github.com/rene-demonsters",
"contributions": [
"doc",
"code"
]
},
{
"login": "kksandr7",
"name": "Ksandr",
"avatar_url": "https://avatars.githubusercontent.com/u/132560756?v=4",
"profile": "https://www.drupal.org/u/kksandr",
"contributions": [
"doc",
"code"
]
},
{
"login": "Daidalos117",
"name": "Roman Rajchert",
"avatar_url": "https://avatars.githubusercontent.com/u/15905269?v=4",
"profile": "https://github.com/Daidalos117",
"contributions": [
"doc",
"code"
]
}
],
"contributorsPerLine": 7,

View File

@@ -7,5 +7,5 @@
"access": "restricted",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": ["web", "test-*", "toolkit-*", "next-blitz-auth"]
"ignore": ["web", "test-*", "toolkit-*", "@blitzjs/recipe-*"]
}

View File

@@ -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

View File

@@ -16,12 +16,12 @@ jobs:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- uses: actions/checkout@v2
- uses: pnpm/action-setup@v2.2.4
with:
version: 8.6.6
version: 8.6.5
- name: Setup node
uses: actions/setup-node@v5
uses: actions/setup-node@v2
with:
node-version: 20
cache: "pnpm"
@@ -37,12 +37,12 @@ jobs:
runs-on: ubuntu-latest
name: Build
steps:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- uses: actions/checkout@v2
- uses: pnpm/action-setup@v2.2.4
with:
version: 8.6.6
version: 8.6.5
- name: Setup node
uses: actions/setup-node@v5
uses: actions/setup-node@v2
with:
node-version: 20
cache: "pnpm"
@@ -65,15 +65,15 @@ jobs:
NODE_VERSION: 18
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v3
- name: Setup PNPM
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@v2.2.4
with:
version: 8.6.6
version: 8.6.5
- name: Setup node@16
uses: actions/setup-node@v5
uses: actions/setup-node@v2
with:
node-version: 20
cache: "pnpm"
@@ -100,7 +100,7 @@ jobs:
outputs:
folders: ${{ steps.set-matrix.outputs.folders }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v2
- id: set-matrix
name: "Find all folders"
shell: bash
@@ -125,17 +125,17 @@ jobs:
- run: echo ${{matrix.folder}}
- name: Checkout
if: matrix.folder != 'next-13-app-dir' || matrix.os != 'windows-latest'
uses: actions/checkout@v5
uses: actions/checkout@v3
- name: Setup PNPM
if: matrix.folder != 'next-13-app-dir' || matrix.os != 'windows-latest'
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@v2.2.4
with:
version: 8.6.6
version: 8.6.5
- name: Setup node@18
if: matrix.folder != 'next-13-app-dir' || matrix.os != 'windows-latest'
uses: actions/setup-node@v5
uses: actions/setup-node@v2
with:
node-version: 20
cache: "pnpm"
@@ -148,7 +148,7 @@ jobs:
- name: Install playwright
if: matrix.folder != 'next-13-app-dir' || matrix.os != 'windows-latest'
run: |
pnpx playwright@1.49.1 install --with-deps
pnpx playwright@1.28.0 install --with-deps
shell: bash
- name: Build

View File

@@ -29,7 +29,7 @@ jobs:
run: |
pr="$(gh api repos/${{ github.repository }}/pulls/${{ github.event.issue.number }})"
head_sha="$(echo "$pr" | jq -r .head.sha)"
echo "head_sha=$head_sha" >> $GITHUB_OUTPUT
- uses: actions/checkout@v4
@@ -39,7 +39,7 @@ jobs:
- name: Setup PNPM
uses: pnpm/action-setup@646cdf48217256a3d0b80361c5a50727664284f2
with:
version: 8.6.6
version: 8.9.0
- name: Setup Node
uses: actions/setup-node@v4

View File

@@ -37,7 +37,7 @@ jobs:
- name: Pre-publish
uses: pnpm/action-setup@646cdf48217256a3d0b80361c5a50727664284f2
with:
version: 8.6.6
version: 8.9.0
- run: pnpm install
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1

View File

@@ -6,7 +6,7 @@
<img alt="" src="https://img.shields.io/badge/Join%20our%20community-6700EB.svg?style=for-the-badge&labelColor=000000&logoWidth=20&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAQ9SURBVHgB7d3dVdtAEIbhcSpICUoH0IEogQqSVBBSAU4FSSpIOoAORAfQgSghHXzZ1U/YcMD4R9rZmf2ec3y448LyiNf27iLiGIAmPLrweC9Un3DhrzG6EarLNP09nlwJ1SOZ/lQr5N80/S/p2QMVCBf5N17XCfm1Y/rBHqjAG9PPHvBsz+mf9WAP+HLA9M/YA14cOP2payH7jpj+VCtk1wnTP+vj7xCy6cTpn7EHLMLp059iD1iD8eveJbVCNsSLheX1YA/YgOWnf8YeKB3Wmf7Ud6Fy4f/FHmtpxbl3YlC4MJ/Cj0bWdwPnPbARg+L0S54XQHS32WwuxClzd4CM0z9rPfeAuTtA5ulPXYQ7wZ04Y+oOoDD9KZc9YOoOoDj9s4dwFzgXR6w1wIPoOvPWA9buAHEJ173o3gWiy3AnuBUHLEbgmYwvAk1/wuM8vAgexThzbwPDkx7/DHwVXfFOxP2GmsKd4Ab6zPeAyU8CI7AHFmH2BRCBPXAyk18GzUrqAXCTiR4ssyj0VFw/oCU8+e+RZ33AWz6KMaYbIIWxB+JSLs1bsbkeMN0AqakHvoku9oA2sAfqBvbAQdw0QArsgb25aYBUQT3QgT2gB+yBuqGcHij2UCqXDZACe2Anlw2QYg/QAOyBuoE98CL3DZDCuK4/rh/Q7oGL6U+TOvcNkJoijN8X1C48+T+g75eQDrAH/qmqAVJgDwyqaoAUe4AGYA/UDZX3QLUNkEIZPRCd5+6BahsgVUgPROwBTSijB7jpVAvGHriHvmw9wAZ4BpX1ABvgmakHtPcbRuwBTWAPULgAV9D/jKDY9YRvwvgEaurD44uQHvAol7qBW7WKluVtIHiUS7GyvA0s6CiXDnxrpQfsgbqBS7GKk/2jYHCrVlGyfxTMrVo0ALdq1Q3sgSKofh0M9oA61a+D2QM0AHugbmAPqClmSRjK2apVVQ8UsySsoK1aHdgDesCtWnUDeyCrIpeFg1u3sylyWTi3btMA7IG6gT2wuuK3hoE9sKrit4YVslWLPaAN7IG6ocKt2zmY2h4O9sDiTG0PZw/QANy6XTewBxZj9ogYVHy025LMHhEz9cBn0We6B0yfERReBLfhx0/R1YQHPx/QBPbA0VwcEwf2wNFcHBPHHjiem3MC2QPHcXdSaJjA+KfgTPQ8hhfjBzHC40mhlzJ+Xq9lK4a4PCs43AVaGTed5mZq+iOXZwWHi3AnOj2wFWNcnxYe7gTxLtBKHuamP/J+Wnh8a5irB7ZC5Yk9gPX1QuXC+usHWqGyhYvUYR0a7zboUOFCNVhnk0krZAOW7wFOvzXhom2xnEbIHizTA1wEYhWW6YFGyC6c1gOcfg9wfA80Qj7g8B7g9HuCww+haIR8wf49wOn3Cvv9k8tGyC/s7gFOv3fY3QONkH+v9MBWqB7PeqDn9FcIT//kcitUn6kHOu/T/xfWzlQy3dEHhwAAAABJRU5ErkJggg==">
</a>
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
<a aria-label="All Contributors" href="#contributors-"><img alt="" src="https://img.shields.io/badge/all_contributors-436-17BB8A.svg?style=for-the-badge&labelColor=000000"></a>
<a aria-label="All Contributors" href="#contributors-"><img alt="" src="https://img.shields.io/badge/all_contributors-429-17BB8A.svg?style=for-the-badge&labelColor=000000"></a>
<!-- ALL-CONTRIBUTORS-BADGE:END -->
<a aria-label="License" href="https://github.com/blitz-js/blitz/blob/main/LICENSE">
<img alt="" src="https://img.shields.io/npm/l/blitz.svg?style=for-the-badge&labelColor=000000&color=blue">
@@ -79,9 +79,6 @@ Your financial contributions help ensure Blitz continues to be developed and mai
</a></td>
<td><a aria-label="Simon Lammes" href="https://github.com/simon-lammes">
<img alt="" src="https://avatars.githubusercontent.com/u/46446421?v=4" width="40px"/>
</a></td>
<td><a aria-label="Route Optimizer and Route Planning Software" href="https://route4me.com">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/main/assets/route4me.png" width="40px"/>
</a></td>
</tr>
</table>
@@ -758,15 +755,6 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<tr>
<td align="center"><a href="https://timn.tech"><img src="https://avatars.githubusercontent.com/u/6324199?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tim Neutkens</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=timneutkens" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=timneutkens" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=timneutkens" title="Tests">⚠️</a></td>
<td align="center"><a href="https://redyetidev.github.io"><img src="https://avatars.githubusercontent.com/u/38299977?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aviv Keller</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=RedYetiDev" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/bezalel6"><img src="https://avatars.githubusercontent.com/u/51681171?v=4?s=100" width="100px;" alt=""/><br /><sub><b>bezalel6</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=bezalel6" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=bezalel6" title="Code">💻</a></td>
<td align="center"><a href="cherniavskii.com"><img src="https://avatars.githubusercontent.com/u/13808724?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andrew Cherniavskii</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=cherniavskii" title="Documentation">📖</a></td>
<td align="center"><a href="https://danielidoko-r3zt.vercel.app/"><img src="https://avatars.githubusercontent.com/u/95912955?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Idoko</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=doe-base" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=doe-base" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=doe-base" title="Tests">⚠️</a></td>
<td align="center"><a href="https://garyfung.medium.com"><img src="https://avatars.githubusercontent.com/u/3803466?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Gary Fung</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=fungilation" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=fungilation" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/rene-demonsters"><img src="https://avatars.githubusercontent.com/u/20322259?v=4?s=100" width="100px;" alt=""/><br /><sub><b>René Vlugt</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=rene-demonsters" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=rene-demonsters" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://www.drupal.org/u/kksandr"><img src="https://avatars.githubusercontent.com/u/132560756?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ksandr</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=kksandr7" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=kksandr7" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Daidalos117"><img src="https://avatars.githubusercontent.com/u/15905269?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Roman Rajchert</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Daidalos117" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=Daidalos117" title="Code">💻</a></td>
</tr>
</table>

View File

@@ -1,83 +1,5 @@
# next-blitz-auth
## 0.1.18
### Patch Changes
- blitz@2.2.1
- @blitzjs/auth@2.2.1
- @blitzjs/next@2.2.1
- @blitzjs/rpc@2.2.1
- @blitzjs/config@2.2.1
## 0.1.17
### Patch Changes
- Updated dependencies [565db3c5a]
- Updated dependencies [3fa3a4ef3]
- blitz@2.2.0
- @blitzjs/auth@2.2.0
- @blitzjs/next@2.2.0
- @blitzjs/rpc@2.2.0
- @blitzjs/config@2.2.0
## 0.1.16
### Patch Changes
- Updated dependencies [ce23d4ed0]
- @blitzjs/next@2.1.4
- blitz@2.1.4
- @blitzjs/auth@2.1.4
- @blitzjs/rpc@2.1.4
- @blitzjs/config@2.1.4
## 0.1.15
### Patch Changes
- Updated dependencies [0b3286468]
- Updated dependencies [50f17d21c]
- @blitzjs/auth@2.1.3
- @blitzjs/next@2.1.3
- @blitzjs/rpc@2.1.3
- blitz@2.1.3
- @blitzjs/config@2.1.3
## 0.1.14
### Patch Changes
- blitz@2.1.2
- @blitzjs/auth@2.1.2
- @blitzjs/next@2.1.2
- @blitzjs/rpc@2.1.2
- @blitzjs/config@2.1.2
## 0.1.13
### Patch Changes
- Updated dependencies [9a0ba87d1]
- @blitzjs/rpc@2.1.1
- blitz@2.1.1
- @blitzjs/next@2.1.1
- @blitzjs/auth@2.1.1
- @blitzjs/config@2.1.1
## 0.1.12
### Patch Changes
- Updated dependencies [d53da39cb]
- Updated dependencies [3b10b13e6]
- blitz@2.1.0
- @blitzjs/auth@2.1.0
- @blitzjs/next@2.1.0
- @blitzjs/rpc@2.1.0
- @blitzjs/config@2.1.0
## 0.1.11
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "next-blitz-auth",
"version": "0.1.18",
"version": "0.1.11",
"private": true,
"scripts": {
"blitz:dev": "next dev",
@@ -12,28 +12,28 @@
"schema": "prisma/schema.prisma"
},
"dependencies": {
"@blitzjs/auth": "3.0.2",
"@blitzjs/config": "3.0.2",
"@blitzjs/next": "3.0.2",
"@blitzjs/rpc": "3.0.2",
"@blitzjs/auth": "2.0.10",
"@blitzjs/config": "2.0.10",
"@blitzjs/next": "2.0.10",
"@blitzjs/rpc": "2.0.10",
"@hookform/error-message": "2.0.0",
"@hookform/resolvers": "2.9.10",
"@prisma/client": "^4.5.0",
"@tanstack/react-query": "5.51.1",
"blitz": "3.0.2",
"@tanstack/react-query": "4.0.10",
"blitz": "2.0.10",
"flatted": "3.2.7",
"next": "15.0.1",
"next": "14.3.0-canary.28",
"prisma": "^4.5.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "7.39.1",
"superjson": "1.11.0",
"zod": "3.23.8"
"zod": "3.20.2"
},
"devDependencies": {
"@types/node": "18.11.7",
"@types/react": "npm:types-react@19.0.0",
"@types/react-dom": "npm:types-react-dom@19.0.0",
"@types/react": "18.0.23",
"@types/react-dom": "18.0.7",
"eslint": "8.26.0",
"eslint-config-next": "13.0.0",
"typescript": "4.8.4"

View File

@@ -1,4 +0,0 @@
export default function Loading() {
// You can add any UI inside Loading, including a Skeleton.
return "Loading..."
}

View File

@@ -1,6 +1,6 @@
"use client"
import {useQuery, useMutation, useSuspenseQuery} from "@blitzjs/rpc"
import {useQuery, useMutation} from "@blitzjs/rpc"
import logout from "../auth/mutations/logout"
import getCurrentUser from "../users/queries/getCurrentUser"
import {useTransition} from "react"
@@ -8,7 +8,7 @@ import {useRouter} from "next/navigation"
export default function Test() {
const router = useRouter()
const [user] = useSuspenseQuery(getCurrentUser, null)
const [user] = useQuery(getCurrentUser, null)
const [isPending, startTransition] = useTransition()
const [logoutMutation] = useMutation(logout)
console.log(user)

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<React.JSX.IntrinsicElements["form"]>, "onSubmit"> {
extends Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit"> {
/** All your form fields */
children?: ReactNode
/** Text to display in the submit button */

View File

@@ -2,15 +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<React.JSX.IntrinsicElements["input"]> {
export interface LabeledTextFieldProps extends PropsWithoutRef<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<React.JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<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/pages/building-your-application/configuring/typescript for more information.
// see https://nextjs.org/docs/basic-features/typescript for more information.

View File

@@ -23,30 +23,31 @@
]
},
"dependencies": {
"@blitzjs/auth": "3.0.2",
"@blitzjs/config": "3.0.2",
"@blitzjs/next": "3.0.2",
"@blitzjs/rpc": "3.0.2",
"@blitzjs/auth": "2.0.10",
"@blitzjs/config": "2.0.10",
"@blitzjs/next": "2.0.10",
"@blitzjs/rpc": "2.0.10",
"@hookform/error-message": "2.0.0",
"@hookform/resolvers": "2.9.10",
"@prisma/client": "6.1.0",
"blitz": "3.0.2",
"next": "15.0.1",
"@prisma/client": "4.6.1",
"blitz": "2.0.10",
"next": "14.3.0-canary.28",
"openid-client": "5.2.1",
"prisma": "6.1.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "7.39.1",
"ts-node": "10.9.1",
"zod": "3.23.8"
"zod": "3.20.2"
},
"devDependencies": {
"@next/bundle-analyzer": "12.0.8",
"@testing-library/react": "16.0.1",
"@testing-library/react": "13.4.0",
"@testing-library/react-hooks": "8.0.1",
"@types/jest": "29.2.2",
"@types/node": "18.11.9",
"@types/preview-email": "2.0.1",
"@types/react": "npm:types-react@19.0.0",
"@types/react": "18.0.25",
"@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<React.JSX.IntrinsicElements["form"]>, "onSubmit"> {
extends Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit"> {
/** All your form fields */
children?: ReactNode
/** Text to display in the submit button */

View File

@@ -2,15 +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<React.JSX.IntrinsicElements["input"]> {
export interface LabeledTextFieldProps extends PropsWithoutRef<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<React.JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
labelProps?: ComponentPropsWithoutRef<"label">
}

View File

@@ -9,6 +9,7 @@ declare module "@blitzjs/auth" {
PublicData: {
userId: User["id"]
role: Role
views?: number
}
}
}

View File

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

View File

@@ -1,3 +1,4 @@
const { withNextAuthAdapter } = require("@blitzjs/auth/next-auth")
const { withBlitz } = require("@blitzjs/next")
/**
@@ -10,4 +11,4 @@ const config = {
},
}
module.exports = withBlitz(config)
module.exports = withBlitz(withNextAuthAdapter(config))

View File

@@ -24,30 +24,31 @@
]
},
"dependencies": {
"@blitzjs/auth": "3.0.2",
"@blitzjs/config": "3.0.2",
"@blitzjs/next": "3.0.2",
"@blitzjs/rpc": "3.0.2",
"@blitzjs/auth": "2.0.10",
"@blitzjs/config": "2.0.10",
"@blitzjs/next": "2.0.10",
"@blitzjs/rpc": "2.0.10",
"@hookform/error-message": "2.0.0",
"@hookform/resolvers": "2.9.10",
"@prisma/client": "6.1.0",
"blitz": "3.0.2",
"next": "15.0.1",
"@prisma/client": "4.6.1",
"blitz": "2.0.10",
"next": "14.3.0-canary.28",
"next-auth": "4.24.7",
"prisma": "6.1.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "7.39.1",
"ts-node": "10.9.1",
"zod": "3.23.8"
"zod": "3.20.2"
},
"devDependencies": {
"@next/bundle-analyzer": "12.0.8",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "16.0.1",
"@testing-library/react": "13.4.0",
"@testing-library/react-hooks": "8.0.1",
"@types/node": "18.11.9",
"@types/preview-email": "2.0.1",
"@types/react": "npm:types-react@19.0.0",
"@types/react": "18.0.25",
"@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<React.JSX.IntrinsicElements["form"]>, "onSubmit"> {
extends Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit"> {
/** All your form fields */
children?: ReactNode
/** Text to display in the submit button */

View File

@@ -2,15 +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<React.JSX.IntrinsicElements["select"]> {
export interface LabeledSelectFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["select"]> {
/** Field name. */
name: string
/** Field label. */
label: string
/** Field type. Doesn't include radio buttons and checkboxes */
options: any[]
outerProps?: PropsWithoutRef<React.JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
labelProps?: ComponentPropsWithoutRef<"label">
}

View File

@@ -2,15 +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<React.JSX.IntrinsicElements["input"]> {
export interface LabeledTextFieldProps extends PropsWithoutRef<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<React.JSX.IntrinsicElements["div"]>
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
labelProps?: ComponentPropsWithoutRef<"label">
}

View File

@@ -0,0 +1,48 @@
import { api } from "src/blitz-server"
import GithubProvider from "next-auth/providers/github"
import EmailProvider from "next-auth/providers/email"
import { NextAuthAdapter, BlitzNextAuthOptions } from "@blitzjs/auth/next-auth"
import db, { User } from "db"
import { Role } from "types"
// Has to be defined separately for `profile` to be correctly typed below
const providers = [
GithubProvider({
clientId: process.env.GITHUB_CLIENT_ID as string,
clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
}),
EmailProvider({
from: process.env.GITHUB_CLIENT_ID as string,
server: process.env.GITHUB_CLIENT_SECRET as string,
}),
]
export default api(
NextAuthAdapter({
successRedirectUrl: "/",
errorRedirectUrl: "/error",
providers,
callback: async (user, account, profile, session) => {
console.log("USER SIDE PROFILE_DATA", { user, account, profile })
let newUser: User
try {
newUser = await db.user.findFirstOrThrow({ where: { name: { equals: user.name } } })
} catch (e) {
newUser = await db.user.create({
data: {
email: user.email as string,
name: user.name as string,
role: "USER",
},
})
}
const publicData = {
userId: newUser.id,
role: newUser.role as Role,
source: "github",
}
await session.$create(publicData)
return { redirectUrl: "/" }
},
})
)

View File

@@ -44,6 +44,11 @@ const UserInfo = () => {
<Link href={"/auth/login"} className={styles.loginButton}>
<strong>Login</strong>
</Link>
<Link href="/api/auth/github/login" passHref legacyBehavior>
<a className="button small">
<strong>Sign in with GitHub</strong>
</a>
</Link>
</>
)
}

View File

@@ -9,6 +9,7 @@ declare module "@blitzjs/auth" {
PublicData: {
userId: User["id"]
role: Role
views?: number
}
}
}

View File

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

View File

@@ -16,27 +16,27 @@
"schema": "./db/schema.prisma"
},
"dependencies": {
"@blitzjs/auth": "3.0.2",
"@blitzjs/config": "3.0.2",
"@blitzjs/next": "3.0.2",
"@blitzjs/rpc": "3.0.2",
"@prisma/client": "6.1.0",
"@blitzjs/auth": "2.0.10",
"@blitzjs/config": "2.0.10",
"@blitzjs/next": "2.0.10",
"@blitzjs/rpc": "2.0.10",
"@prisma/client": "4.6.1",
"@types/jest": "29.2.2",
"@types/passport-twitter": "1.0.37",
"blitz": "3.0.2",
"blitz": "2.0.10",
"jest": "29.3.0",
"jest-environment-jsdom": "29.3.0",
"next": "15.0.1",
"next": "14.3.0-canary.28",
"passport-mock-strategy": "2.0.0",
"passport-twitter": "1.0.4",
"prisma": "6.1.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"ts-node": "10.9.1"
},
"devDependencies": {
"@next/bundle-analyzer": "12.0.8",
"@types/react": "npm:types-react@19.0.0",
"@types/react": "18.0.25",
"eslint": "8.27.0",
"typescript": "^4.8.4"
}

View File

@@ -0,0 +1,44 @@
import {passportAuth} from "@blitzjs/auth"
import {api} from "src/blitz-server"
import db from "db"
import {Strategy as TwitterStrategy} from "passport-twitter"
export default api(
passportAuth({
successRedirectUrl: "/",
errorRedirectUrl: "/",
strategies: [
{
strategy: new TwitterStrategy(
{
consumerKey: process.env.TWITTER_CONSUMER_KEY as string,
consumerSecret: process.env.TWITTER_CONSUMER_SECRET as string,
accessTokenURL: "https://api.twitter.com/oauth/access_token",
callbackURL: "http://127.0.0.1:3000/api/auth/twitter/callback",
includeEmail: true,
},
async function (_token, _tokenSecret, profile, done) {
const email = profile.emails?.[0]?.value ?? "blitz@test.com"
const user = await db.user.upsert({
where: {email},
create: {
email,
name: profile.displayName,
},
update: {email},
})
const publicData = {
userId: user.id,
roles: [user.role],
source: "twitter",
}
done(undefined, {publicData})
},
),
},
],
}),
)

View File

@@ -1,90 +0,0 @@
import {useSuspenseInfiniteQuery} from "@blitzjs/rpc"
import getInfiniteUsers from "src/queries/getInfiniteUsers"
import {useActionState} from "react"
function PageWithInfiniteQueryMutate(props) {
const [usersPages, extraInfo] = useSuspenseInfiniteQuery(
getInfiniteUsers,
(page = {take: 3, skip: 0}) => page,
{
getNextPageParam: (lastPage) => lastPage.nextPage,
initialPageParam: {take: 3, skip: 0},
},
)
const {isFetchingNextPage, fetchNextPage, hasNextPage, setQueryData} = extraInfo
const onOnContactSave = async (previousState, formData: FormData) => {
const name = formData.get("name") as string | null
await setQueryData(
(oldData) => {
if (!oldData) {
return {
pages: [],
pageParams: [],
}
}
return {
...oldData,
pages: oldData.pages.map((page, index) => {
if (index === 0) {
return {
...page,
users: [
{
id: Math.random(),
name,
role: "user",
email: `${name}@yopmail.com`,
createdAt: new Date(),
updatedAt: new Date(),
hashedPassword: "alsdklaskdoaskdokdo",
},
...page.users,
],
}
}
return page
}),
}
},
{refetch: false},
)
}
const [, formAction] = useActionState(onOnContactSave, {name: ""})
return (
<div>
<form action={formAction}>
<input type="text" name="name" placeholder="User name" />
<button type="submit">Add user</button>
</form>
{usersPages.map((usersPage) => (
<>
{usersPage?.users.map((u) => (
<div key={u.name}>
<p>name: {u.name}</p>
<p>role: {u.role}</p>
<p>email: {u.email}</p>
<hr />
</div>
))}
{usersPage.hasMore && (
<button onClick={() => fetchNextPage()} disabled={!hasNextPage || !!isFetchingNextPage}>
{isFetchingNextPage
? "Loading more..."
: hasNextPage
? "Load More"
: "Nothing more to load"}
</button>
)}
</>
))}
</div>
)
}
export default PageWithInfiniteQueryMutate

View File

@@ -1,4 +1,4 @@
import {useSuspenseInfiniteQuery} from "@blitzjs/rpc"
import {useInfiniteQuery} from "@blitzjs/rpc"
import {gSSP} from "src/blitz-server"
import getInfiniteUsers from "src/queries/getInfiniteUsers"
@@ -10,14 +10,9 @@ export const getServerSideProps = gSSP(async ({ctx}) => {
})
function PageWithPrefetchInfiniteQuery(props) {
const [usersPages] = useSuspenseInfiniteQuery(
getInfiniteUsers,
(page = {take: 3, skip: 0}) => page,
{
getNextPageParam: (lastPage) => lastPage.nextPage,
initialPageParam: {take: 3, skip: 0},
},
)
const [usersPages] = useInfiniteQuery(getInfiniteUsers, (page = {take: 3, skip: 0}) => page, {
getNextPageParam: (lastPage) => lastPage.nextPage,
})
return (
<div>
{usersPages.map((usersPage) =>

View File

@@ -1,4 +1,4 @@
import {useSuspenseQuery} from "@blitzjs/rpc"
import {useQuery} from "@blitzjs/rpc"
import {gSSP} from "src/blitz-server"
import getUsers from "src/queries/getUsers"
@@ -10,7 +10,7 @@ export const getServerSideProps = gSSP(async ({ctx}) => {
})
function PageWithPrefetch(props) {
const [users] = useSuspenseQuery(getUsers, {})
const [users] = useQuery(getUsers, {})
return (
<div>
{users.map((u) => (

View File

@@ -7,7 +7,7 @@ function UsersPage() {
<div>
Users:
<ul>
{users?.map((user) => (
{users.map((user) => (
<li key={user.id}>
{user.name} - {user.email}
</li>

View File

@@ -9,6 +9,7 @@ declare module "@blitzjs/auth" {
PublicData: {
userId: User["id"]
role: Role
views?: number
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

View File

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

View File

@@ -17,30 +17,31 @@
"prisma:studio": "prisma studio"
},
"dependencies": {
"@blitzjs/auth": "3.0.2",
"@blitzjs/config": "3.0.2",
"@blitzjs/next": "3.0.2",
"@blitzjs/rpc": "3.0.2",
"@blitzjs/auth": "2.0.10",
"@blitzjs/config": "2.0.10",
"@blitzjs/next": "2.0.10",
"@blitzjs/rpc": "2.0.10",
"@hookform/error-message": "2.0.0",
"@hookform/resolvers": "2.9.10",
"@prisma/client": "6.1.0",
"blitz": "3.0.2",
"@prisma/client": "4.6.1",
"blitz": "2.0.10",
"delay": "5.0.0",
"next": "15.0.1",
"prisma": "6.1.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"next": "14.3.0-canary.28",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "7.39.1",
"ts-node": "10.9.1",
"zod": "3.23.8"
"zod": "3.20.2"
},
"devDependencies": {
"@next/bundle-analyzer": "12.0.8",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "16.0.1",
"@testing-library/react": "13.4.0",
"@testing-library/react-hooks": "8.0.1",
"@types/node": "18.11.9",
"@types/preview-email": "2.0.1",
"@types/react": "npm:types-react@19.0.0",
"@types/react": "18.0.25",
"@typescript-eslint/eslint-plugin": "5.42.1",
"@vitejs/plugin-react": "2.2.0",
"eslint": "8.27.0",
@@ -49,7 +50,7 @@
"husky": "8.0.2",
"jsdom": "20.0.3",
"lint-staged": "13.0.3",
"playwright": "1.49.1",
"playwright": "1.28.0",
"prettier": "^2.7.1",
"prettier-plugin-prisma": "4.4.0",
"pretty-quick": "3.1.3",

View File

@@ -1,14 +1,13 @@
import {QueryClient, useMutation, useQuery} from "@blitzjs/rpc"
import {useMutation, useQuery} from "@blitzjs/rpc"
import logout from "../mutations/logout"
import getAuthenticatedBasic from "../queries/getAuthenticatedBasic"
import {Suspense} from "react"
function Content() {
const [result, {isLoading, isError, error}] = useQuery(getAuthenticatedBasic, undefined)
const [result] = useQuery(getAuthenticatedBasic, undefined)
const [logoutMutation] = useMutation(logout)
if (isError) throw error
if (isLoading || !result) return <div>Loading...</div>
return (
<>
<div>
<div id="content">{result}</div>
<button
id="logout"
@@ -18,14 +17,16 @@ function Content() {
>
logout
</button>
</>
</div>
)
}
function AuthenticatedQuery() {
return (
<div id="page">
<Content />
<Suspense fallback={"Loading..."}>
<Content />
</Suspense>
</div>
)
}

View File

@@ -1,4 +1,4 @@
import {useMutation, useSuspenseQuery} from "@blitzjs/rpc"
import {useMutation, useQuery} from "@blitzjs/rpc"
import {BlitzPage} from "@blitzjs/next"
import AuthenticateRedirectLayout from "../layouts/AuthenticateRedirectLayout"
import logout from "../mutations/logout"
@@ -6,7 +6,7 @@ import getAuthenticatedBasic from "../queries/getAuthenticatedBasic"
import {Suspense} from "react"
function Content() {
const [result] = useSuspenseQuery(getAuthenticatedBasic, undefined)
const [result] = useQuery(getAuthenticatedBasic, undefined)
const [logoutMutation] = useMutation(logout)
return (
<div>

View File

@@ -1,5 +1,5 @@
import {useRouter} from "next/router"
import {useMutation, useSuspenseQuery} from "@blitzjs/rpc"
import {useMutation, useQuery} from "@blitzjs/rpc"
import login from "../mutations/login"
import logout from "../mutations/logout"
import getCurrentUser from "../queries/getCurrentUser"
@@ -8,7 +8,7 @@ import {Suspense, useState} from "react"
function Content() {
const router = useRouter()
const [error, setError] = useState(null)
const [userId] = useSuspenseQuery(getCurrentUser, null)
const [userId] = useQuery(getCurrentUser, null)
const [loginMutation] = useMutation(login)
const [logoutMutation] = useMutation(logout)

View File

@@ -1,9 +1,9 @@
import {useSuspenseQuery} from "@blitzjs/rpc"
import {useQuery} from "@blitzjs/rpc"
import getNoauthBasic from "../queries/getNoauthBasic"
import {Suspense} from "react"
function Content() {
const [result] = useSuspenseQuery(getNoauthBasic, undefined)
const [result] = useQuery(getNoauthBasic, undefined)
return <div id="content">{result}</div>
}

View File

@@ -1,11 +1,11 @@
import {useMutation, useSuspenseQuery} from "@blitzjs/rpc"
import {useMutation, useQuery} from "@blitzjs/rpc"
import {BlitzPage} from "@blitzjs/next"
import logout from "../mutations/logout"
import getAuthenticatedBasic from "../queries/getAuthenticatedBasic"
import {Suspense} from "react"
function Content() {
const [result] = useSuspenseQuery(getAuthenticatedBasic, undefined)
const [result] = useQuery(getAuthenticatedBasic, undefined)
const [logoutMutation] = useMutation(logout)
return (
<div>

View File

@@ -1,11 +1,11 @@
import {useMutation, useSuspenseQuery} from "@blitzjs/rpc"
import {useMutation, useQuery} from "@blitzjs/rpc"
import {BlitzPage} from "@blitzjs/next"
import logout from "../mutations/logout"
import getAuthenticatedBasic from "../queries/getAuthenticatedBasic"
import {Suspense} from "react"
function Content() {
const [result] = useSuspenseQuery(getAuthenticatedBasic, undefined)
const [result] = useQuery(getAuthenticatedBasic, undefined)
const [logoutMutation] = useMutation(logout)
return (
<div>

View File

@@ -1,11 +1,11 @@
import {useMutation, useSuspenseQuery} from "@blitzjs/rpc"
import {useMutation, useQuery} from "@blitzjs/rpc"
import {BlitzPage} from "@blitzjs/next"
import logout from "../mutations/logout"
import getAuthenticatedBasic from "../queries/getAuthenticatedBasic"
import {Suspense} from "react"
function Content() {
const [result] = useSuspenseQuery(getAuthenticatedBasic, undefined)
const [result] = useQuery(getAuthenticatedBasic, undefined)
const [logoutMutation] = useMutation(logout)
return (
<div>

View File

@@ -1,11 +1,11 @@
import {useMutation, useSuspenseQuery} from "@blitzjs/rpc"
import {useMutation, useQuery} from "@blitzjs/rpc"
import {BlitzPage} from "@blitzjs/next"
import logout from "../mutations/logout"
import getAuthenticatedBasic from "../queries/getAuthenticatedBasic"
import {Suspense} from "react"
function Content() {
const [result] = useSuspenseQuery(getAuthenticatedBasic, undefined)
const [result] = useQuery(getAuthenticatedBasic, undefined)
const [logoutMutation] = useMutation(logout)
return (
<div>

View File

@@ -1,11 +1,11 @@
import {useMutation, useSuspenseQuery} from "@blitzjs/rpc"
import {useMutation, useQuery} from "@blitzjs/rpc"
import {BlitzPage} from "@blitzjs/next"
import logout from "../mutations/logout"
import getAuthenticatedBasic from "../queries/getAuthenticatedBasic"
import {Suspense} from "react"
function Content() {
const [result] = useSuspenseQuery(getAuthenticatedBasic, undefined)
const [result] = useQuery(getAuthenticatedBasic, undefined)
const [logoutMutation] = useMutation(logout)
return (
<div>

View File

@@ -32,9 +32,9 @@ type Props = {
}
export const getServerSideProps = gSSP<Props>(async ({ctx}) => {
await getQueryClient().prefetchQuery({
queryKey: getQueryKey(getNoauthBasic),
})
await getQueryClient().prefetchQuery(getQueryKey(getNoauthBasic, null), () =>
getNoauthBasic(null, ctx),
)
return {
props: {
dehydratedState: dehydrate(queryClient),

View File

@@ -1,10 +1,10 @@
import {invalidateQuery, useMutation, useSuspenseQuery} from "@blitzjs/rpc"
import {invalidateQuery, useMutation, useQuery} from "@blitzjs/rpc"
import changeRole from "../mutations/changeRole"
import getPublicDataForUser from "../queries/getPublicDataForUser"
import {Suspense} from "react"
function Content() {
const [publicData] = useSuspenseQuery(getPublicDataForUser, {userId: 1})
const [publicData] = useQuery(getPublicDataForUser, {userId: 1})
return (
<div id="session">
<>

View File

@@ -9,6 +9,7 @@ declare module "@blitzjs/auth" {
PublicData: {
userId: User["id"]
role: Role
views?: number
}
}
}

View File

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

View File

@@ -17,16 +17,16 @@
"prisma:studio": "prisma studio"
},
"dependencies": {
"@blitzjs/auth": "3.0.2",
"@blitzjs/config": "3.0.2",
"@blitzjs/next": "3.0.2",
"@prisma/client": "6.1.0",
"blitz": "3.0.2",
"@blitzjs/auth": "2.0.10",
"@blitzjs/config": "2.0.10",
"@blitzjs/next": "2.0.10",
"@prisma/client": "4.6.1",
"blitz": "2.0.10",
"lowdb": "3.0.0",
"next": "15.0.1",
"prisma": "6.1.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"next": "14.3.0-canary.28",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"secure-password": "4.0.0",
"wait-port": "1.0.4"
},
@@ -36,13 +36,13 @@
"@types/fs-extra": "9.0.13",
"@types/node": "18.7.13",
"@types/node-fetch": "2.6.1",
"@types/react": "npm:types-react@19.0.0",
"@types/react": "18.0.25",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",
"get-port": "6.1.2",
"node-fetch": "3.2.3",
"playwright": "1.49.1",
"playwright": "1.28.0",
"ts-node": "10.9.1",
"typescript": "^4.8.4"
}

View File

@@ -9,6 +9,7 @@ declare module "@blitzjs/auth" {
PublicData: {
userId: User["id"]
role: Role
views?: number
}
}
}

View File

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

View File

@@ -16,24 +16,24 @@
"schema": "db/schema.prisma"
},
"dependencies": {
"@blitzjs/auth": "3.0.2",
"@blitzjs/next": "3.0.2",
"@blitzjs/rpc": "3.0.2",
"@prisma/client": "6.1.0",
"blitz": "3.0.2",
"lowdb": "2.1.0",
"next": "15.0.1",
"prisma": "6.1.0",
"react": "19.0.0",
"react-dom": "19.0.0"
"@blitzjs/auth": "2.0.10",
"@blitzjs/next": "2.0.10",
"@blitzjs/rpc": "2.0.10",
"@prisma/client": "4.6.1",
"blitz": "2.0.10",
"lowdb": "3.0.0",
"next": "14.3.0-canary.28",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@blitzjs/config": "3.0.2",
"@blitzjs/config": "2.0.10",
"@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": "npm:types-react@19.0.0",
"@types/react": "18.0.25",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",

View File

@@ -1,16 +1,10 @@
{
"extends": "@blitzjs/config/tsconfig.nextjs.json",
"include": ["**/*.ts", "**/*.tsx", "next-env.d.ts", "types", ".next/types/**/*.ts"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "types"],
"compilerOptions": {
"paths": {
"react": ["./node_modules/@types/react"]
},
"plugins": [
{
"name": "next"
}
],
"strictNullChecks": true
}
},
"exclude": ["node_modules"],
"baseUrl": "."

View File

@@ -9,6 +9,7 @@ declare module "@blitzjs/auth" {
PublicData: {
userId: User["id"]
role: Role
views?: number
}
}
}

View File

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

View File

@@ -11,20 +11,20 @@
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next"
},
"dependencies": {
"@blitzjs/config": "3.0.2",
"@blitzjs/next": "3.0.2",
"@blitzjs/rpc": "3.0.2",
"blitz": "3.0.2",
"next": "15.0.1",
"react": "19.0.0",
"react-dom": "19.0.0"
"@blitzjs/config": "2.0.10",
"@blitzjs/next": "2.0.10",
"@blitzjs/rpc": "2.0.10",
"blitz": "2.0.10",
"next": "14.3.0-canary.28",
"react": "18.2.0",
"react-dom": "18.2.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": "npm:types-react@19.0.0",
"@types/react": "18.0.25",
"eslint": "8.27.0",
"fs-extra": "10.0.1",
"get-port": "6.1.2",

View File

@@ -1,10 +1,10 @@
"use client"
import {getQueryData, useSuspenseQuery} from "@blitzjs/rpc"
import {getQueryData, useQuery} from "@blitzjs/rpc"
import {Suspense, useState} from "react"
import getBasic from "../../src/queries/getBasic"
function Content() {
const [data] = useSuspenseQuery(getBasic, undefined)
const [data] = useQuery(getBasic, undefined)
const [newData, setNewData] = useState<string>()
return (
<div>

View File

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

View File

@@ -17,17 +17,17 @@
"prisma:studio": "prisma studio"
},
"dependencies": {
"@blitzjs/auth": "3.0.2",
"@blitzjs/config": "3.0.2",
"@blitzjs/next": "3.0.2",
"@blitzjs/rpc": "3.0.2",
"@prisma/client": "6.1.0",
"blitz": "3.0.2",
"lowdb": "2.1.0",
"next": "15.0.1",
"prisma": "6.1.0",
"react": "19.0.0",
"react-dom": "19.0.0",
"@blitzjs/auth": "2.0.10",
"@blitzjs/config": "2.0.10",
"@blitzjs/next": "2.0.10",
"@blitzjs/rpc": "2.0.10",
"@prisma/client": "4.6.1",
"blitz": "2.0.10",
"lowdb": "3.0.0",
"next": "14.3.0-canary.28",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"secure-password": "4.0.0",
"wait-port": "1.0.4"
},
@@ -37,13 +37,13 @@
"@types/fs-extra": "9.0.13",
"@types/node": "18.7.13",
"@types/node-fetch": "2.6.1",
"@types/react": "npm:types-react@19.0.0",
"@types/react": "18.0.25",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",
"get-port": "6.1.2",
"node-fetch": "3.2.3",
"playwright": "1.49.1",
"playwright": "1.28.0",
"ts-node": "10.9.1",
"typescript": "^4.9.5"
}

View File

@@ -9,6 +9,7 @@ declare module "@blitzjs/auth" {
PublicData: {
userId: User["id"]
role: Role
views?: number
}
}
}

View File

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

View File

@@ -16,24 +16,24 @@
"prisma:studio": "prisma studio"
},
"dependencies": {
"@blitzjs/auth": "3.0.2",
"@blitzjs/next": "3.0.2",
"@blitzjs/rpc": "3.0.2",
"@prisma/client": "6.1.0",
"blitz": "3.0.2",
"@blitzjs/auth": "2.0.10",
"@blitzjs/next": "2.0.10",
"@blitzjs/rpc": "2.0.10",
"@prisma/client": "4.6.1",
"blitz": "2.0.10",
"lowdb": "3.0.0",
"next": "15.0.1",
"prisma": "6.1.0",
"react": "19.0.0",
"react-dom": "19.0.0"
"next": "14.3.0-canary.28",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@blitzjs/config": "3.0.2",
"@blitzjs/config": "2.0.10",
"@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": "npm:types-react@19.0.0",
"@types/react": "18.0.25",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",

View File

@@ -1,16 +1,10 @@
{
"extends": "@blitzjs/config/tsconfig.nextjs.json",
"include": ["**/*.ts", "**/*.tsx", "next-env.d.ts", "types", ".next/types/**/*.ts"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "types"],
"compilerOptions": {
"paths": {
"react": ["./node_modules/@types/react"]
},
"plugins": [
{
"name": "next"
}
],
"strictNullChecks": true
}
},
"exclude": ["node_modules"],
"baseUrl": "."

View File

@@ -9,6 +9,7 @@ declare module "@blitzjs/auth" {
PublicData: {
userId: User["id"]
role: Role
views?: number
}
}
}

View File

@@ -8,21 +8,21 @@
"clean": "rm -rf .turbo && rm -rf node_modules"
},
"dependencies": {
"@blitzjs/auth": "3.0.2",
"@blitzjs/config": "3.0.2",
"@blitzjs/next": "3.0.2",
"@blitzjs/rpc": "3.0.2",
"@prisma/client": "6.1.0",
"@tanstack/react-query": "5.51.1",
"blitz": "3.0.2",
"next": "15.0.1",
"prisma": "6.1.0",
"react": "19.0.0",
"react-dom": "19.0.0"
"@blitzjs/auth": "2.0.10",
"@blitzjs/config": "2.0.10",
"@blitzjs/next": "2.0.10",
"@blitzjs/rpc": "2.0.10",
"@prisma/client": "4.6.1",
"@tanstack/react-query": "4.0.10",
"blitz": "2.0.10",
"next": "14.3.0-canary.28",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@testing-library/react": "16.0.1",
"@types/react": "npm:types-react@19.0.0",
"@testing-library/react": "13.4.0",
"@types/react": "18.0.25",
"@vitejs/plugin-react": "1.3.0",
"delay": "5.0.0",
"eslint": "8.27.0",

View File

@@ -3,7 +3,3 @@
exports[`useQuery > a "query" that converts the string parameter to uppercase > shouldn't work with mutation function 1`] = `"\\"useQuery\\" was expected to be called with a query but was called with a \\"mutation\\""`;
exports[`useQuery > a "query" that converts the string parameter to uppercase > shouldn't work with regular functions 1`] = `"Either the file path to your resolver is incorrect (must be in a \\"queries\\" or \\"mutations\\" folder that isn't nested inside \\"pages\\" or \\"api\\") or you are trying to use Blitz's useQuery to fetch from third-party APIs (to do that, import useQuery directly from \\"@tanstack/react-query\\")."`;
exports[`useSuspenseQuery > a "query" that converts the string parameter to uppercase > shouldn't work with mutation function 1`] = `"\\"useQuery\\" was expected to be called with a query but was called with a \\"mutation\\""`;
exports[`useSuspenseQuery > a "query" that converts the string parameter to uppercase > shouldn't work with regular functions 1`] = `"Either the file path to your resolver is incorrect (must be in a \\"queries\\" or \\"mutations\\" folder that isn't nested inside \\"pages\\" or \\"api\\") or you are trying to use Blitz's useQuery to fetch from third-party APIs (to do that, import useQuery directly from \\"@tanstack/react-query\\")."`;

View File

@@ -1,12 +1,6 @@
import {describe, it, expect, beforeAll, vi} from "vitest"
import {act, screen, waitForElementToBeRemoved} from "@testing-library/react"
import {
useSuspenseQuery,
useQuery,
useSuspenseInfiniteQuery,
BlitzRpcPlugin,
BlitzProvider,
} from "@blitzjs/rpc"
import {useQuery, useInfiniteQuery, BlitzRpcPlugin, BlitzProvider} from "@blitzjs/rpc"
import React from "react"
import delay from "delay"
import {buildMutationRpc, buildQueryRpc, mockRouter, render} from "../../utils/blitz-test-utils"
@@ -17,18 +11,19 @@ beforeAll(() => {
globalThis.IS_REACT_ACT_ENVIRONMENT = true
})
describe("useSuspenseQuery", () => {
describe("useQuery", () => {
const setupHook = (
ID: string,
params: any,
queryFn: (...args: any) => any,
options: Parameters<typeof useSuspenseQuery>[2] = {} as any,
options: Parameters<typeof useQuery>[2] = {} as any,
): [{data?: any; setQueryData?: any}, Function] => {
let res = {}
const qc = BlitzRpcPlugin({})
function TestSuspenseHarness() {
const [data, {setQueryData}] = useSuspenseQuery(queryFn, params, {
function TestHarness() {
const [data, {setQueryData}] = useQuery(queryFn, params, {
suspense: true,
...(options as any),
} as any)
@@ -43,7 +38,7 @@ describe("useSuspenseQuery", () => {
const ui = () => (
<React.Suspense fallback="Loading...">
<TestSuspenseHarness />
<TestHarness />
</React.Suspense>
)
@@ -95,101 +90,6 @@ describe("useSuspenseQuery", () => {
expect(() => setupHook("5", "test", buildMutationRpc(upcase))).toThrowErrorMatchingSnapshot()
})
it("works with options other than enabled & suspense without type error", () => {
const Demo = () => {
useSuspenseQuery(buildQueryRpc(upcase), undefined, {refetchInterval: 10000})
return <div></div>
}
const ui = () => <Demo />
const {rerender} = render(ui(), {
wrapper: ({children}) => (
<BlitzProvider>
<RouterContext.Provider value={mockRouter}>{children}</RouterContext.Provider>
</BlitzProvider>
),
})
})
})
})
describe("useQuery", () => {
const setupHook = (
ID: string,
params: any,
queryFn: (...args: any) => any,
options: Parameters<typeof useQuery>[2] = {} as any,
): [{data?: any; setQueryData?: any}, Function] => {
let res = {}
const qc = BlitzRpcPlugin({})
function TestHarness() {
const [data, {setQueryData, isLoading}] = useQuery(queryFn, params, {
...(options as any),
} as any)
Object.assign(res, {data, setQueryData})
if (isLoading) {
return <div>Loading...</div>
}
return (
<div id={`harness-${ID}`}>
<span>{data ? `Ready${ID}` : "No data"}</span>
<span>{data}</span>
</div>
)
}
const ui = () => <TestHarness />
const {rerender} = render(ui(), {
wrapper: ({children}) => (
<BlitzProvider>
<RouterContext.Provider value={mockRouter}>{children}</RouterContext.Provider>
</BlitzProvider>
),
})
return [res, () => rerender(ui())]
}
describe('a "query" that converts the string parameter to uppercase', () => {
const upcase = async (args: string) => {
await delay(500)
return args.toUpperCase()
}
it("should work with Blitz queries", async () => {
const [res] = setupHook("2", "test", buildQueryRpc(upcase))
await waitForElementToBeRemoved(() => screen.getByText("Loading..."))
await act(async () => {
await screen.queryAllByText("Ready2")[0]
expect(res.data).toBe("TEST")
})
})
it("should be able to change the data with setQueryData", async () => {
const [res] = setupHook("3", "fooBar", buildQueryRpc(upcase))
await waitForElementToBeRemoved(() => screen.getByText("Loading..."))
await act(async () => {
await screen.queryAllByText("Ready3")[0]
expect(res.data).toBe("FOOBAR")
res.setQueryData((p: string) => p.substr(3, 3), {refetch: false})
await delay(100)
})
expect(res.data).toBe("BAR")
})
it("shouldn't work with regular functions", () => {
console.error = vi.fn()
expect(() => setupHook("4", "test", upcase)).toThrowErrorMatchingSnapshot()
})
it("shouldn't work with mutation function", () => {
console.error = vi.fn()
expect(() => setupHook("5", "test", buildMutationRpc(upcase))).toThrowErrorMatchingSnapshot()
})
it("suspense disabled if enabled is false", async () => {
setupHook("6", "test", buildQueryRpc(upcase), {enabled: false})
await screen.findByText("No data")
@@ -200,9 +100,17 @@ describe("useQuery", () => {
await screen.findByText("No data")
})
// it("suspense disabled if enabled is false and suspense set", async () => {
// setupHook("8", "test", buildQueryRpc(upcase), {
// enabled: false,
// suspense: true,
// })
// await screen.findByText("No data")
// })
it("works with options other than enabled & suspense without type error", () => {
const Demo = () => {
useSuspenseQuery(buildQueryRpc(upcase), undefined, {refetchInterval: 10000})
useQuery(buildQueryRpc(upcase), undefined, {refetchInterval: 10000})
return <div></div>
}
const ui = () => <Demo />
@@ -218,7 +126,7 @@ describe("useQuery", () => {
})
})
describe("useSuspenseInfiniteQuery", () => {
describe("useInfiniteQuery", () => {
const setupHook = (
ID: string,
params: (arg?: any) => any,
@@ -230,7 +138,7 @@ describe("useSuspenseInfiniteQuery", () => {
function TestHarness() {
// TODO - fix typing
//@ts-ignore
const [groupedData] = useSuspenseInfiniteQuery(queryFn, params, {
const [groupedData] = useInfiniteQuery(queryFn, params, {
suspense: true,
getNextPageParam: () => {},
})

View File

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

View File

@@ -16,23 +16,23 @@
"schema": "db/schema.prisma"
},
"dependencies": {
"@blitzjs/next": "3.0.2",
"@blitzjs/rpc": "3.0.2",
"@prisma/client": "6.1.0",
"blitz": "3.0.2",
"@blitzjs/next": "2.0.10",
"@blitzjs/rpc": "2.0.10",
"@prisma/client": "4.6.1",
"blitz": "2.0.10",
"lowdb": "3.0.0",
"next": "15.0.1",
"prisma": "6.1.0",
"react": "19.0.0",
"react-dom": "19.0.0"
"next": "14.3.0-canary.28",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@blitzjs/config": "3.0.2",
"@blitzjs/config": "2.0.10",
"@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": "npm:types-react@19.0.0",
"@types/react": "18.0.25",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",

View File

@@ -1,9 +1,9 @@
import {getQueryData, useSuspenseQuery} from "@blitzjs/rpc"
import {getQueryData, useQuery} from "@blitzjs/rpc"
import {Suspense, useState} from "react"
import getBasic from "../app/queries/getBasic"
function Content() {
const [data] = useSuspenseQuery(getBasic, undefined)
const [data] = useQuery(getBasic, undefined)
const [newData, setNewData] = useState<string>()
return (
<div>

View File

@@ -1,9 +1,9 @@
import React, {Suspense} from "react"
import {BlitzPage} from "@blitzjs/next"
import {invalidateQuery, useSuspenseQuery} from "@blitzjs/rpc"
import {invalidateQuery, useQuery} from "@blitzjs/rpc"
import getSequence from "../app/queries/getSequence"
const useSuspenseQueryOptions = {
const useQueryOptions = {
refetchInterval: 0,
refetchOnMount: false,
refetchOnReconnect: false,
@@ -11,16 +11,8 @@ const useSuspenseQueryOptions = {
}
const PageWithInvalidateQuery: React.FC = () => {
const [query1, {isFetching: isQ1Fetching}] = useSuspenseQuery(
getSequence,
"query1",
useSuspenseQueryOptions,
)
const [query2, {isFetching: isQ2Fetching}] = useSuspenseQuery(
getSequence,
"query2",
useSuspenseQueryOptions,
)
const [query1, {isFetching: isQ1Fetching}] = useQuery(getSequence, "query1", useQueryOptions)
const [query2, {isFetching: isQ2Fetching}] = useQuery(getSequence, "query2", useQueryOptions)
const isFetching = isQ1Fetching || isQ2Fetching

View File

@@ -1,9 +1,9 @@
import {getQueryData, useSuspenseQuery} from "@blitzjs/rpc"
import {getQueryData, useQuery} from "@blitzjs/rpc"
import {Suspense, useState} from "react"
import getNoSuspenseBasic from "../../no-suspense/app/queries/getNoSuspenseBasic"
function Content() {
const [data] = useSuspenseQuery(getNoSuspenseBasic, undefined)
const [data] = useQuery(getNoSuspenseBasic, undefined)
const [newData, setNewData] = useState<string>()
return (
<div>

View File

@@ -1,4 +1,4 @@
import {useSuspenseInfiniteQuery} from "@blitzjs/rpc"
import {useInfiniteQuery} from "@blitzjs/rpc"
import {gSSP} from "../app/blitz-server"
import testQuery from "../app/queries/getInfiniteData"
@@ -12,12 +12,12 @@ export const getServerSideProps = gSSP(async ({ctx}) => {
})
const PageWithPrefetchInfQuery = () => {
const [data] = useSuspenseInfiniteQuery(
const [data] = useInfiniteQuery(
testQuery,
(pageParams) => ({...pageParams, name: "hello world"}),
{
suspense: false,
getNextPageParam: (lastPage) => lastPage,
initialPageParam: {name: "hello world"},
},
)
return <div id="data">{data ? data : "no-data"}</div>

View File

@@ -51,22 +51,22 @@ const runTests = () => {
)
})
// describe("prefetch infinite query", () => {
// it(
// "should work",
// async () => {
// const browser = await webdriver(appPort, "/page-with-prefetch-inf-query")
describe("prefetch infinite query", () => {
it(
"should work",
async () => {
const browser = await webdriver(appPort, "/page-with-prefetch-inf-query")
// browser.waitForElementByCss("#data", 0)
// const newText = await browser.elementByCss("#data").text()
// expect(newText).not.toMatch("no-data")
// expect(newText).toMatch("thanks")
browser.waitForElementByCss("#data", 0)
const newText = await browser.elementByCss("#data").text()
expect(newText).not.toMatch("no-data")
expect(newText).toMatch("thanks")
// if (browser) await browser.close()
// },
// 5000 * 60 * 2,
// )
// })
if (browser) await browser.close()
},
5000 * 60 * 2,
)
})
describe("invalidate query", () => {
it(

View File

@@ -7,19 +7,19 @@
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next"
},
"dependencies": {
"@blitzjs/config": "3.0.2",
"@blitzjs/next": "3.0.2",
"@blitzjs/rpc": "3.0.2",
"blitz": "3.0.2",
"next": "15.0.1",
"react": "19.0.0",
"react-dom": "19.0.0"
"@blitzjs/config": "2.0.10",
"@blitzjs/next": "2.0.10",
"@blitzjs/rpc": "2.0.10",
"blitz": "2.0.10",
"next": "14.3.0-canary.28",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@types/express": "4.17.13",
"@types/fs-extra": "9.0.13",
"@types/node-fetch": "2.6.1",
"@types/react": "npm:types-react@19.0.0",
"@types/react": "18.0.25",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",

View File

@@ -7,19 +7,19 @@
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next"
},
"dependencies": {
"@blitzjs/config": "3.0.2",
"@blitzjs/next": "3.0.2",
"@blitzjs/rpc": "3.0.2",
"blitz": "3.0.2",
"next": "15.0.1",
"react": "19.0.0",
"react-dom": "19.0.0"
"@blitzjs/config": "2.0.10",
"@blitzjs/next": "2.0.10",
"@blitzjs/rpc": "2.0.10",
"blitz": "2.0.10",
"next": "14.3.0-canary.28",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@types/express": "4.17.13",
"@types/fs-extra": "9.0.13",
"@types/node-fetch": "2.6.1",
"@types/react": "npm:types-react@19.0.0",
"@types/react": "18.0.25",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",

View File

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

View File

@@ -16,24 +16,24 @@
"schema": "db/schema.prisma"
},
"dependencies": {
"@blitzjs/auth": "3.0.2",
"@blitzjs/next": "3.0.2",
"@blitzjs/rpc": "3.0.2",
"@prisma/client": "6.1.0",
"blitz": "3.0.2",
"@blitzjs/auth": "2.0.10",
"@blitzjs/next": "2.0.10",
"@blitzjs/rpc": "2.0.10",
"@prisma/client": "4.6.1",
"blitz": "2.0.10",
"lowdb": "3.0.0",
"next": "15.0.1",
"prisma": "6.1.0",
"react": "19.0.0",
"react-dom": "19.0.0"
"next": "14.3.0-canary.28",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@blitzjs/config": "3.0.2",
"@blitzjs/config": "2.0.10",
"@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": "npm:types-react@19.0.0",
"@types/react": "18.0.25",
"b64-lite": "1.4.0",
"eslint": "8.27.0",
"fs-extra": "10.0.1",

View File

@@ -1,9 +1,9 @@
import getBasic from "../app/queries/getBasic"
import {useSuspenseQuery} from "@blitzjs/rpc"
import {useQuery} from "@blitzjs/rpc"
import {Suspense} from "react"
function Content() {
const [result] = useSuspenseQuery(getBasic, undefined)
const [result] = useQuery(getBasic, undefined)
return <div id="content">{result}</div>
}

View File

@@ -1,16 +1,10 @@
{
"extends": "@blitzjs/config/tsconfig.nextjs.json",
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "types", ".next/types/**/*.ts"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "types"],
"compilerOptions": {
"paths": {
"react": ["./node_modules/@types/react"]
},
"plugins": [
{
"name": "next"
}
],
"strictNullChecks": true
}
},
"exclude": ["node_modules"],
"baseUrl": "."

View File

@@ -9,6 +9,7 @@ declare module "@blitzjs/auth" {
PublicData: {
userId: User["id"]
role: Role
views?: number
}
}
}

View File

@@ -3,15 +3,15 @@
"version": "0.0.0",
"private": true,
"devDependencies": {
"@blitzjs/config": "workspace:3.0.2",
"@blitzjs/next": "workspace:3.0.2",
"@blitzjs/rpc": "workspace:3.0.2",
"@blitzjs/config": "workspace:2.0.10",
"@blitzjs/next": "workspace:2.0.10",
"@blitzjs/rpc": "workspace:2.0.10",
"@tanstack/react-query": "4.13.0",
"@testing-library/react": "16.0.1",
"@testing-library/react": "13.4.0",
"@types/express": "4.17.13",
"@types/fs-extra": "9.0.13",
"@types/node-fetch": "2.6.1",
"@types/react": "npm:types-react@19.0.0",
"@types/react": "18.0.25",
"@types/rimraf": "3.0.2",
"@types/selenium-webdriver": "4.0.18",
"chromedriver": "100.0.0",
@@ -22,9 +22,9 @@
"get-port": "6.1.2",
"node-fetch": "3.2.3",
"pkg-dir": "5.0.0",
"playwright-chromium": "1.49.1",
"react": "19.0.0",
"react-dom": "19.0.0",
"playwright-chromium": "1.28.0",
"react": "18.2.0",
"react-dom": "18.2.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": "15.0.1",
"next": "14.3.0-canary.28",
"only-allow": "1.1.0",
"prettier": "^2.8.8",
"prettier-plugin-prisma": "4.4.0",
@@ -46,11 +46,12 @@
]
},
"pnpm": {
"patchedDependencies": {
"next-auth@4.24.7": "patches/next-auth@4.24.7.patch"
},
"overrides": {
"@types/mime": "3.0.4",
"next": "15.0.1",
"@types/react": "npm:types-react@rc",
"@types/react-dom": "npm:types-react-dom@rc"
"next": "14.3.0-canary.28"
}
}
}

View File

@@ -1,128 +1,5 @@
# @blitzjs/auth
## 3.0.2
### Patch Changes
- 83b6be7ad: Upgrade cookie-session dependency to v2.1.1
- 0ef8de04b: fix: Overriden custom cookies with pages router
- blitz@3.0.2
## 3.0.1
### Patch Changes
- 816330b9d: fix: Overriden custom cookies used inside `withBlitzAuth`
- blitz@3.0.1
## 3.0.0
### Major Changes
- ce1a603b2: TODO: Upgrade @tanstack/react-query to v5.1.1
### Patch Changes
- Updated dependencies [ce1a603b2]
- Updated dependencies [1610c73f9]
- blitz@3.0.0
## 2.2.1
### Patch Changes
- blitz@2.2.1
## 2.2.0
### Minor Changes
- 3fa3a4ef3: chore: support next.js 15
### Patch Changes
- Updated dependencies [565db3c5a]
- Updated dependencies [3fa3a4ef3]
- blitz@2.2.0
## 2.1.4
### Patch Changes
- blitz@2.1.4
## 2.1.3
### Patch Changes
- 0b3286468: chore: bump `next.js` and `zod` versions
- Updated dependencies [0b3286468]
- Updated dependencies [50f17d21c]
- blitz@2.1.3
## 2.1.2
### Patch Changes
- blitz@2.1.2
## 2.1.1
### Patch Changes
- Updated dependencies [9a0ba87d1]
- blitz@2.1.1
## 2.1.0
### Minor Changes
- 3b10b13e6: 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
### Patch Changes
- Updated dependencies [d53da39cb]
- Updated dependencies [3b10b13e6]
- blitz@2.1.0
## 2.0.10
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@blitzjs/auth",
"version": "3.0.2",
"version": "2.0.10",
"homepage": "https://blitzjs.com/",
"repository": {
"type": "git",
@@ -28,14 +28,14 @@
],
"dependencies": {
"@types/b64-lite": "1.3.0",
"@types/cookie-session": "2.0.49",
"@types/cookie-session": "2.0.44",
"@types/oauth": "0.9.1",
"@types/passport": "1.0.7",
"@types/secure-password": "3.1.1",
"b64-lite": "1.4.0",
"bad-behavior": "1.0.1",
"cookie": "0.4.1",
"cookie-session": "2.1.1",
"cookie-session": "2.0.0",
"debug": "4.3.3",
"find-up": "4.1.0",
"http": "0.0.1-security",
@@ -50,7 +50,7 @@
"url": "0.11.0"
},
"peerDependencies": {
"blitz": "3.0.2",
"blitz": "2.0.10",
"next": "*",
"next-auth": "*",
"secure-password": "4.0.0"
@@ -67,18 +67,19 @@
}
},
"devDependencies": {
"@blitzjs/config": "3.0.2",
"@testing-library/react": "16.0.1",
"@blitzjs/config": "2.0.10",
"@testing-library/react": "13.4.0",
"@testing-library/react-hooks": "8.0.1",
"@types/cookie": "0.4.1",
"@types/debug": "4.1.7",
"@types/jsonwebtoken": "8.5.8",
"@types/react": "npm:types-react@19.0.0",
"@types/react-dom": "npm:types-react-dom@19.0.0",
"blitz": "3.0.2",
"next": "15.0.1",
"@types/react": "18.0.25",
"@types/react-dom": "17.0.14",
"blitz": "2.0.10",
"next": "14.3.0-canary.28",
"next-auth": "4.24.7",
"react": "19.0.0",
"react-dom": "19.0.0",
"react": "18.2.0",
"react-dom": "18.2.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"
import {renderHook} from "@testing-library/react-hooks"
vi.mock("blitz", async () => {
const blitz = await vi.importActual("blitz")

View File

@@ -152,7 +152,7 @@ export interface UseSessionOptions {
}
export const useSession = (options: UseSessionOptions = {}): ClientSession => {
const suspense = options?.suspense ?? true
const suspense = options?.suspense ?? Boolean(globalThis.__BLITZ_SUSPENSE_ENABLED)
let initialState: ClientSession
if (options.initialPublicData) {
@@ -260,7 +260,7 @@ export type RedirectAuthenticatedToFn = (
) => RedirectAuthenticatedTo
export type BlitzPage<P = {}> = React.ComponentType<P> & {
getLayout?: (component: React.JSX.Element) => React.JSX.Element
getLayout?: (component: JSX.Element) => JSX.Element
authenticate?: boolean | {redirectTo?: string | RouteUrlObject; role?: string | Array<string>}
suppressFirstRenderFlicker?: boolean
redirectAuthenticatedTo?: RedirectAuthenticatedTo | RedirectAuthenticatedToFn

View File

@@ -5,5 +5,6 @@ import type {SessionConfigMethods} from "./shared"
declare global {
var sessionConfig: AuthPluginOptions & SessionConfigMethods
var __BLITZ_SESSION_COOKIE_PREFIX: string | undefined
var __BLITZ_SUSPENSE_ENABLED: boolean
var __BLITZ_GET_RSC_CONTEXT: () => Promise<Ctx>
}

View File

@@ -1,226 +0,0 @@
import {expect, describe, it, beforeEach} from "vitest"
import {ServerResponse} from "http"
import {Writable} from "stream"
import {append} from "./auth-sessions"
class MockServerResponse extends Writable {
private headers: Map<string, string | string[]> = new Map()
getHeader(name: string) {
return this.headers.get(name)
}
setHeader(name: string, value: string | string[]) {
this.headers.set(name, value)
}
getHeaders() {
return Object.fromEntries(this.headers)
}
_write(_chunk: unknown, _encoding: string, callback: (error?: Error | null) => void): void {
callback()
}
}
describe("append", () => {
let res: ServerResponse
const COOKIE_PREFIX = "auth-tests-cookie-prefix_s"
beforeEach(() => {
res = new MockServerResponse() as unknown as ServerResponse
})
describe("Blitz Auth Flows", () => {
const anonymousSessionCookie = `${COOKIE_PREFIX}AnonymousSessionToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJibGl0empzIjp7ImlzQW5vbnltb3VzIjp0cnVlLCJoYW5kbGUiOiJEVjk4OVZadFpra0lpWHFSOFRPX3Fvem44MHBwWFBnaDphand0IiwicHVibGljRGF0YSI6eyJ1c2VySWQiOm51bGx9LCJhbnRpQ1NSRlRva2VuIjoiM25BdDBZWVI0b0xDNnAtTm1fQW1CeFQxRmJmVmpiaXMifSwiaWF0IjoxNzQwODA0NTE4LCJhdWQiOiJibGl0empzIiwiaXNzIjoiYmxpdHpqcyIsInN1YiI6ImFub255bW91cyJ9.ZpMxWh3Yq2Qe4BXzZ61d4V0YGV2luswF7ovE90DxURM; Path=/; Expires=Thu, 28 Feb 2030 04:48:38 GMT; HttpOnly; SameSite=Lax`
const antiCsrfCookie = `${COOKIE_PREFIX}AntiCsrfToken=3nAt0YYR4oLC6p-Nm_AmBxT1FbfVjbis; Path=/; Expires=Thu, 28 Feb 2030 04:48:38 GMT; SameSite=Lax`
const publicDataCookie = `${COOKIE_PREFIX}PublicDataToken=eyJ1c2VySWQiOm51bGx9; Path=/; Expires=Thu, 28 Feb 2030 04:48:38 GMT; SameSite=Lax`
const expiredSessionCookie = `${COOKIE_PREFIX}SessionToken=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=Lax`
const expiredAnonymousCookie = `${COOKIE_PREFIX}AnonymousSessionToken=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT; HttpOnly; SameSite=Lax`
// Login cookies
const loginAntiCsrfCookie = `${COOKIE_PREFIX}AntiCsrfToken=1s3yaYs0yThO-DwOuiepJLzycvN090tO; Path=/; Expires=Mon, 31 Mar 2025 04:48:38 GMT; SameSite=Lax`
const loginPublicDataCookie = `${COOKIE_PREFIX}PublicDataToken=eyJ1c2VySWQiOjEsInJvbGUiOiJ1c2VyIn0%3D; Path=/; Expires=Mon, 31 Mar 2025 04:48:38 GMT; SameSite=Lax`
const loginSessionCookie = `${COOKIE_PREFIX}SessionToken=aGNjc0o5anJ5eTF4bDdqRE5VN09LeEx5QUJoR2toUjc6b3RzO1NaWC1la3YydGR4UGNjWVp6QkM0SlBQbUdWWmZEMlpFOzhhYWU1MDI2M2Q0YmUyNDIxZWYwNDBmMmFhZGI2MDk4YTNiNjhjMTAyZjlmNmNjYTQ4NzUzMGZiYjc0ZTdhYmI7djA%3D; Path=/; Expires=Mon, 31 Mar 2025 04:48:38 GMT; HttpOnly; SameSite=Lax`
it("should handle anonymous session cookies", () => {
append(res, "Set-Cookie", [anonymousSessionCookie, antiCsrfCookie, publicDataCookie])
const cookies = res.getHeader("Set-Cookie") as string[]
expect(cookies).toHaveLength(3)
expect(cookies[0]).toBe(anonymousSessionCookie)
expect(cookies[1]).toBe(antiCsrfCookie)
expect(cookies[2]).toBe(publicDataCookie)
})
it("should deduplicate cookies when the same one is set twice", () => {
append(res, "Set-Cookie", anonymousSessionCookie)
append(res, "Set-Cookie", anonymousSessionCookie)
const cookies = res.getHeader("Set-Cookie") as string[]
expect(cookies).toHaveLength(1)
expect(cookies[0]).toBe(anonymousSessionCookie)
})
it("should replace cookies with same name when values change", () => {
append(res, "Set-Cookie", anonymousSessionCookie)
const updatedAnonymousCookie = `${COOKIE_PREFIX}AnonymousSessionToken=NEW_TOKEN_VALUE; Path=/; SameSite=Lax`
append(res, "Set-Cookie", updatedAnonymousCookie)
const cookies = res.getHeader("Set-Cookie") as string[]
expect(cookies).toHaveLength(1)
expect(cookies[0]).toBe(updatedAnonymousCookie)
})
it("should handle session expiration", () => {
// First add anonymous session
append(res, "Set-Cookie", [anonymousSessionCookie, antiCsrfCookie, publicDataCookie])
append(res, "Set-Cookie", [expiredSessionCookie, expiredAnonymousCookie])
const cookies = res.getHeader("Set-Cookie") as string[]
expect(cookies).toHaveLength(4)
expect(cookies.find((c) => c === expiredSessionCookie)).toBeDefined()
expect(cookies.find((c) => c === expiredAnonymousCookie)).toBeDefined()
})
it("should handle login flow cookies", () => {
// First anonymous session
append(res, "Set-Cookie", [anonymousSessionCookie, antiCsrfCookie, publicDataCookie])
// Then login, which expires anonymous and sets new session
append(res, "Set-Cookie", [
expiredAnonymousCookie,
loginSessionCookie,
loginAntiCsrfCookie,
loginPublicDataCookie,
])
const cookies = res.getHeader("Set-Cookie") as string[]
// Should have 4 cookies:
// - Original antiCsrf cookie (should be replaced by login one)
// - Expired anonymous cookie
// - Login session cookie
// - Login publicData cookie
expect(cookies).toHaveLength(4)
// Check proper replacement by extracting cookie names
const cookieNames = cookies.map((c) => {
const namePart = c.substring(0, c.indexOf("="))
return namePart
})
expect(cookieNames.filter((n) => n === `${COOKIE_PREFIX}AntiCsrfToken`)).toHaveLength(1)
expect(cookieNames.filter((n) => n === `${COOKIE_PREFIX}PublicDataToken`)).toHaveLength(1)
expect(cookieNames.filter((n) => n === `${COOKIE_PREFIX}SessionToken`)).toHaveLength(1)
// the expired cookie
expect(cookieNames.filter((n) => n === `${COOKIE_PREFIX}AnonymousSessionToken`)).toHaveLength(
1,
)
})
it("should properly combine multiple append calls with different cookie groups", () => {
append(res, "Set-Cookie", [anonymousSessionCookie, antiCsrfCookie])
append(res, "Set-Cookie", [publicDataCookie, loginAntiCsrfCookie])
const cookies = res.getHeader("Set-Cookie") as string[]
expect(cookies).toHaveLength(3)
const antiCsrfCookies = cookies.filter((c) => c.includes(`${COOKIE_PREFIX}AntiCsrfToken`))
expect(antiCsrfCookies).toHaveLength(1)
expect(antiCsrfCookies[0]).toBe(loginAntiCsrfCookie)
})
it("should handle the full session flow", () => {
append(res, "Set-Cookie", [anonymousSessionCookie, antiCsrfCookie, publicDataCookie])
const initialCookies = res.getHeader("Set-Cookie") as string[]
expect(initialCookies).toHaveLength(3)
append(res, "Set-Cookie", [
expiredAnonymousCookie,
loginSessionCookie,
loginAntiCsrfCookie,
loginPublicDataCookie,
])
const loginCookies = res.getHeader("Set-Cookie") as string[]
expect(loginCookies).toHaveLength(4)
append(res, "Set-Cookie", [
expiredSessionCookie,
anonymousSessionCookie,
antiCsrfCookie,
publicDataCookie,
])
const logoutCookies = res.getHeader("Set-Cookie") as string[]
expect(logoutCookies).toHaveLength(4)
const cookies = res.getHeader("Set-Cookie") as string[]
const cookieNames = cookies.map((c) => c.substring(0, c.indexOf("=")))
const counts = cookieNames.reduce((acc, name) => {
acc[name] = (acc[name] || 0) + 1
return acc
}, {} as Record<string, number>)
expect(Object.keys(counts).length).toBe(4)
Object.values(counts).forEach((count) => {
expect(count).toBeLessThanOrEqual(3)
})
})
it("should handle cookies with quoted values and special characters", () => {
const specialCookie = `${COOKIE_PREFIX}PublicDataToken="eyJ1c2VySWQiOjEsIm5hbWUiOiJKb2huIERvZSwgSnIuIn0%3D"; Path=/; SameSite=Lax`
append(res, "Set-Cookie", specialCookie)
const cookies = res.getHeader("Set-Cookie") as string[]
expect(cookies).toHaveLength(1)
expect(cookies[0]).toBe(specialCookie)
})
it("should properly merge with existing custom cookies already in the response", () => {
const customCookie1 = "custom1=value1; Path=/; HttpOnly"
const customCookie2 = "custom2=value2; Path=/; HttpOnly"
const existingAuthCookie = `${COOKIE_PREFIX}AntiCsrfToken=old-token; Path=/; SameSite=Lax`
res.setHeader("Set-Cookie", [customCookie1, customCookie2, existingAuthCookie])
// login
append(res, "Set-Cookie", [anonymousSessionCookie, loginAntiCsrfCookie, publicDataCookie])
const cookies = res.getHeader("Set-Cookie") as string[]
expect(cookies).toHaveLength(5)
// Custom cookies should be preserved
expect(cookies).toContain(customCookie1)
expect(cookies).toContain(customCookie2)
// Auth cookies should be correctly applied, with antiCsrf being updated
expect(cookies).toContain(anonymousSessionCookie)
expect(cookies).toContain(loginAntiCsrfCookie)
expect(cookies).toContain(publicDataCookie)
// The old auth cookie should be replaced
expect(cookies).not.toContain(existingAuthCookie)
// Verify we have the right counts of each cookie type
const cookieNames = cookies.map((c) => c.substring(0, c.indexOf("=")))
expect(cookieNames.filter((n) => n === "custom1")).toHaveLength(1)
expect(cookieNames.filter((n) => n === "custom2")).toHaveLength(1)
expect(cookieNames.filter((n) => n === `${COOKIE_PREFIX}AnonymousSessionToken`)).toHaveLength(
1,
)
expect(cookieNames.filter((n) => n === `${COOKIE_PREFIX}AntiCsrfToken`)).toHaveLength(1)
expect(cookieNames.filter((n) => n === `${COOKIE_PREFIX}PublicDataToken`)).toHaveLength(1)
})
})
})

View File

@@ -289,10 +289,8 @@ const makeProxyToPublicData = <T extends SessionContextClass>(ctxClass: T): T =>
export async function getBlitzContext(): Promise<Ctx> {
try {
const {headers, cookies} = require("next/headers")
const cookieStore = await cookies()
const headersStore = await headers()
const reqHeader = Object.fromEntries(headersStore)
const csrfToken = cookieStore.get(COOKIE_CSRF_TOKEN())
const reqHeader = Object.fromEntries(headers())
const csrfToken = cookies().get(COOKIE_CSRF_TOKEN())
if (csrfToken) {
reqHeader[HEADER_CSRF] = csrfToken.value
}
@@ -466,9 +464,9 @@ export class SessionContextClass implements SessionContext {
}
const cookieHeaders = this._headers.get("set-cookie")
if (response instanceof Response) {
response.headers.append("Set-Cookie", cookieHeaders!)
response.headers.set("Set-Cookie", cookieHeaders!)
} else {
append(response, "Set-Cookie", splitCookiesString(cookieHeaders!))
response.setHeader("Set-Cookie", splitCookiesString(cookieHeaders!))
}
const headers = this._headers.entries()
@@ -1249,31 +1247,12 @@ export async function setPublicDataForUser(userId: PublicData["userId"], data: R
* @param {string} field
* @param {string| string[]} val
*/
export function append(res: ServerResponse, field: string, val: string | string[]) {
function append(res: ServerResponse, field: string, val: string | string[]) {
let prev: string | string[] | undefined = res.getHeader(field) as string | string[] | undefined
let value = val
if (field.toLowerCase() === "set-cookie") {
const prevCookies = prev ? (Array.isArray(prev) ? prev : [prev]) : []
const newCookies = Array.isArray(val) ? val : [val]
const allCookies = [...prevCookies, ...newCookies].reduce((acc: string[], cookieHeader) => {
return acc.concat(splitCookiesString(cookieHeader))
}, [])
const cookieMap = new Map()
allCookies.forEach((cookieStr) => {
const firstSemicolon = cookieStr.indexOf(";")
const cookieNameValue = firstSemicolon > -1 ? cookieStr.slice(0, firstSemicolon) : cookieStr
const parsed = cookie.parse(cookieNameValue)
const name = Object.keys(parsed)[0]
if (name) {
cookieMap.set(name, cookieStr)
}
})
value = Array.from(cookieMap.values())
} else if (prev !== undefined) {
if (prev !== undefined) {
// concat the new and prev vals
value = Array.isArray(prev)
? prev.concat(val)
: Array.isArray(val)
@@ -1282,6 +1261,7 @@ export function append(res: ServerResponse, field: string, val: string | string[
}
value = Array.isArray(value) ? value.map(String) : String(value)
res.setHeader(field, value)
return res
}

View File

@@ -1,137 +1,5 @@
# @blitzjs/next
## 3.0.2
### Patch Changes
- @blitzjs/rpc@3.0.2
- blitz@3.0.2
## 3.0.1
### Patch Changes
- @blitzjs/rpc@3.0.1
- blitz@3.0.1
## 3.0.0
### Major Changes
- ce1a603b2: TODO: Upgrade @tanstack/react-query to v5.1.1
### Patch Changes
- Updated dependencies [11c9f00eb]
- Updated dependencies [ce1a603b2]
- Updated dependencies [1610c73f9]
- @blitzjs/rpc@3.0.0
- blitz@3.0.0
## 2.2.1
### Patch Changes
- blitz@2.2.1
- @blitzjs/rpc@2.2.1
## 2.2.0
### Minor Changes
- 3fa3a4ef3: chore: support next.js 15
### Patch Changes
- Updated dependencies [565db3c5a]
- Updated dependencies [3fa3a4ef3]
- blitz@2.2.0
- @blitzjs/rpc@2.2.0
## 2.1.4
### Patch Changes
- ce23d4ed0: fix: Update `turbopack-empty.js` syntax to support latest turbopack and next.js versions
- blitz@2.1.4
- @blitzjs/rpc@2.1.4
## 2.1.3
### Patch Changes
- 0b3286468: chore: bump `next.js` and `zod` versions
- Updated dependencies [0b3286468]
- Updated dependencies [50f17d21c]
- @blitzjs/rpc@2.1.3
- blitz@2.1.3
## 2.1.2
### Patch Changes
- blitz@2.1.2
- @blitzjs/rpc@2.1.2
## 2.1.1
### Patch Changes
- Updated dependencies [9a0ba87d1]
- @blitzjs/rpc@2.1.1
- blitz@2.1.1
## 2.1.0
### Minor Changes
- 3b10b13e6: 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
### Patch Changes
- Updated dependencies [d53da39cb]
- Updated dependencies [3b10b13e6]
- blitz@2.1.0
- @blitzjs/rpc@2.1.0
## 2.0.10
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "@blitzjs/next",
"version": "3.0.2",
"version": "2.0.10",
"homepage": "https://blitzjs.com/",
"repository": {
"type": "git",
@@ -29,7 +29,7 @@
"eslint.js"
],
"dependencies": {
"@blitzjs/rpc": "3.0.2",
"@blitzjs/rpc": "2.0.10",
"@types/hoist-non-react-statics": "3.3.1",
"copy-webpack-plugin": "11.0.0",
"debug": "4.3.3",
@@ -39,29 +39,30 @@
"supports-color": "8.1.1"
},
"peerDependencies": {
"blitz": "3.0.2",
"blitz": "2.0.10",
"next": "*",
"react": "*",
"tslog": "4.9.0"
},
"devDependencies": {
"@blitzjs/config": "3.0.2",
"@blitzjs/config": "2.0.10",
"@testing-library/dom": "8.13.0",
"@testing-library/jest-dom": "5.16.3",
"@testing-library/react": "16.0.1",
"@testing-library/react": "13.4.0",
"@testing-library/react-hooks": "8.0.1",
"@testing-library/user-event": "13.5.0",
"@types/debug": "4.1.7",
"@types/node": "18.11.9",
"@types/react": "npm:types-react@19.0.0",
"@types/react-dom": "npm:types-react-dom@19.0.0",
"@types/react": "18.0.25",
"@types/react-dom": "17.0.14",
"@types/testing-library__react-hooks": "4.0.0",
"blitz": "3.0.2",
"blitz": "2.0.10",
"cross-spawn": "7.0.3",
"find-up": "4.1.0",
"next": "15.0.1",
"next": "14.3.0-canary.28",
"next-router-mock": "0.9.1",
"react": "19.0.0",
"react-dom": "19.0.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"resolve-from": "5.0.0",
"ts-jest": "27.1.4",
"tslog": "4.9.0",

View File

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

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(1)
expect(consoleError).toHaveBeenCalledTimes(3)
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(1)
expect(consoleError).toHaveBeenCalledTimes(3)
consoleError.mockClear()
// can recover

View File

@@ -77,10 +77,25 @@ test("standard use-case", () => {
const {unmount} = render(<App />)
userEvent.type(screen.getByRole("textbox", {name: /username/i}), "fail")
const calls = consoleError.mock.calls[0]
//@ts-expect-error - it's a mock
expect(calls[1]).toMatchInlineSnapshot("[Error: 💥 CABOOM 💥]")
expect(consoleError).toHaveBeenCalledTimes(1)
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)
consoleError.mockClear()
expect(screen.getByRole("alert")).toMatchInlineSnapshot(`
@@ -134,7 +149,7 @@ test("fallbackRender prop", () => {
}
const {unmount} = render(<App />)
expect(consoleError).toHaveBeenCalledTimes(1)
expect(consoleError).toHaveBeenCalledTimes(3)
consoleError.mockClear()
// the render prop API allows a single action to reset the app state
@@ -153,7 +168,7 @@ test("simple fallback is supported", () => {
<span>child</span>
</ErrorBoundary>,
)
expect(consoleError).toHaveBeenCalledTimes(1)
expect(consoleError).toHaveBeenCalledTimes(3)
consoleError.mockClear()
expect(screen.getByText(/oh no/i)).to.exist
expect(screen.queryByText(/child/i)).to.not.exist
@@ -168,16 +183,27 @@ test("withErrorBoundary HOC", () => {
() => {
throw new Error("💥 CABOOM 💥")
},
{
FallbackComponent: ErrorFallback,
onError: onErrorHandler,
},
{FallbackComponent: ErrorFallback, onError: onErrorHandler},
)
const {unmount} = render(<Boundary />)
const calls = consoleError.mock.calls[0]
//@ts-expect-error - it's a mock
expect(calls[1]).toMatchInlineSnapshot("[Error: 💥 CABOOM 💥]")
expect(consoleError).toHaveBeenCalledTimes(1)
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)
consoleError.mockClear()
const [error, onErrorComponentStack] = (onErrorHandler.mock.calls as [[Error, string]])[0]
@@ -239,6 +265,7 @@ 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>,
@@ -291,7 +318,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(1)
expect(consoleError).toHaveBeenCalledTimes(3)
consoleError.mockClear()
// recover via try again button
@@ -306,7 +333,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(1)
expect(consoleError).toHaveBeenCalledTimes(3)
consoleError.mockClear()
// recover via resetKeys change
@@ -321,7 +348,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(1)
expect(consoleError).toHaveBeenCalledTimes(3)
consoleError.mockClear()
// toggles adding an extra resetKey to the array
@@ -331,7 +358,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(1)
expect(consoleError).toHaveBeenCalledTimes(3)
consoleError.mockClear()
// toggle explode back to false
@@ -342,7 +369,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(1)
expect(consoleError).toHaveBeenCalledTimes(3)
consoleError.mockClear()
// toggle extra resetKey
@@ -384,7 +411,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(1)
expect(consoleError).toHaveBeenCalledTimes(3)
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 React from "react"
import * as 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): React.JSX.Element {
function WithRouterWrapper(props: any): JSX.Element {
return <ComposedComponent router={useRouter()} {...props} />
}
@@ -114,13 +114,7 @@ export const ErrorBoundary = withRouter(
await this.props.router.push(error.url)
return
}
if (this.props.onError) {
let componentStack = info.componentStack
if (!componentStack) {
componentStack = new Error("Stack trace").stack || ""
}
this.props.onError(error, {componentStack})
}
this.props.onError?.(error, info)
}
componentDidMount() {
@@ -196,7 +190,7 @@ export const ErrorBoundary = withRouter(
},
)
function withErrorBoundary<P extends React.JSX.IntrinsicAttributes>(
function withErrorBoundary<P extends JSX.IntrinsicAttributes>(
Component: React.ComponentType<P>,
errorBoundaryProps: ErrorBoundaryProps,
): React.ComponentType<P> {

View File

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

Some files were not shown because too many files have changed in this diff Show More