1
0
mirror of synced 2026-02-04 03:01:17 -05:00

Compare commits

...

38 Commits

Author SHA1 Message Date
Siddharth Suresh
9be4d86174 Version Packages (beta) (#4035)
* Version Packages (beta)

* Version Packages (beta)

* pnpm lock

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-01-04 01:16:55 +05:30
Siddharth Suresh
249e7cf527 Revert "Version Packages (beta) (#4012)" (#4034)
This reverts commit 76df5db1c3.
2023-01-04 00:54:38 +05:30
github-actions[bot]
76df5db1c3 Version Packages (beta) (#4012)
* Version Packages (beta)

* pnpmlock

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Dillon Raphael <dillon@creatorsneverdie.com>
2023-01-04 00:37:02 +05:30
Brandon Bayer
556f5cd13d update CODEOWNERS 2023-01-03 14:02:03 -05:00
Dillon Raphael
d692b4c1d7 Fix suspense error codegen patch for latest nextjs version (#4031)
* Use the new nextjs constant to check if SSR and fix suspense for nextjs 13.1 and above

* satisfy version from 13 to 13.0.6

* check for DYNAMIC_SERVER_USAGE error string for nextjs versions 13-13.0.6

* Create fluffy-coats-flow.md

* revert toolkit-app update to next 13.1

* set error message for compatability with next 13.0.7

* fix changeset
2023-01-03 13:49:53 -05:00
Blitz.js Bot
bd4db6d701 (meta) added @Trancever as contributor 2023-01-02 14:18:58 -05:00
Dawid Urbaniak
82e8b64f59 fix: properly add authError query param to redirect url (#4027) 2023-01-02 14:18:53 -05:00
Tobias
e9dfbcf85a Reference vitest.config.ts instead of jest for README|s (#4019)
* Reference `vitest.config.ts` instead of jest for README|s

* Update apps/toolkit-app/README.md

Co-authored-by: Dillon Raphael <dillon@creatorsneverdie.com>
2022-12-29 14:51:14 -05:00
Blitz.js Bot
a4294ad29c (meta) updated @tordans contributions 2022-12-28 15:23:30 -05:00
Tobias
ea83f0d174 Update README.md|s to use src/ instead ofapp/ (#4018)
Co-authored-by: Dillon Raphael <dillon@creatorsneverdie.com>
2022-12-28 15:23:25 -05:00
Blitz.js Bot
f32f6d3ac9 (meta) added @iagormoraes as contributor 2022-12-28 13:12:38 -05:00
Iagor Moraes
d5b8faa860 React Suspense on Next 13 patch fix (#4009)
* fix: add regex to support inline and non-inline codebase

- add proper regex test for package version

* chore: add changelog

* chore: update lock file

Co-authored-by: Dillon Raphael <dillon@creatorsneverdie.com>
2022-12-28 13:12:33 -05:00
Blitz.js Bot
4a6612b942 (meta) added @tordans as contributor 2022-12-28 10:13:58 -05:00
Tobias
c941d993a8 SignupForm.tsx: Improve helper comment (#4016)
This comment was helpful but could be even more helpful if it clearly stated that it referenced the "P"-Code; and link to docs to learn more.

Co-authored-by: Dillon Raphael <dillon@creatorsneverdie.com>
2022-12-28 10:13:53 -05:00
Blitz.js Bot
3633f23ceb (meta) added @a11rew as contributor 2022-12-26 18:59:00 -05:00
Andrew Glago
10f98c681d feat(cli): add href property to RouteURLObject (#3892)
* feat(cli): add href property to RouteURLObject

* Create thick-moons-fry.md

* update playwright install github action

* add browser path env variable to test stage

* revert

Co-authored-by: Dillon Raphael <dillon@creatorsneverdie.com>
2022-12-26 18:58:54 -05:00
Datner
0025856b9e support invalidate all queries (#3899)
* support invalidate all queries

* Add changeset

* Update .changeset/stupid-rabbits-jump.md

Co-authored-by: Dillon Raphael <dillon@creatorsneverdie.com>

Co-authored-by: Aleksandra <alexsandra.sikora@gmail.com>
Co-authored-by: Dillon Raphael <dillon@creatorsneverdie.com>
2022-12-20 15:09:15 -05:00
Dillon Raphael
77b7da0f38 Remove husky prepush hook & update precommit hook to only run prettier (#3984)
* Remove husky prepush hook & update precommit hook to only run prettier for full app & minimal app templates

* pnpmlock
2022-12-20 14:44:15 -05:00
github-actions[bot]
13c2642bdb Version Packages (beta) (#3992)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-12-16 14:09:41 -05:00
Brandon Bayer
03bad3175d fix Cannot read properties of null (reading 'isReady') for pnpm/yarn v3 (#4008) 2022-12-16 14:02:44 -05:00
Tom MacWright
74a14b7040 fix: Reject db.() with an error object (#4006) 2022-12-15 09:58:27 -05:00
Siddharth Suresh
6ece096134 Decouple Blitz RPC and Blitz Auth (#3943)
* inital unwrapping of blitz rpc from blitz auth

* fix linr

* Revert "fix linr"

This reverts commit 000e2c7259.

* remove duplication of code and dynamically import blitz auth if plugin is used

* return types to blitz-auth and import in rpc as types

* remove excess files from git diff

* remove todo ts-ignore

* add changeset

* better error messages

* Update odd-cars-fry.md

* switch from blitz log to console - due to import error.

* Revert "Merge branch 'rpc-without-auth' of https://github.com/blitz-js/blitz into rpc-without-auth"

This reverts commit 5b45d65b4d, reversing
changes made to b15dfa6dec.

* Revert "switch from blitz log to console - due to import error."

This reverts commit b15dfa6dec.

* Revert "better error messages"

This reverts commit 75922cb063.

* fix location of seting global variable

* better error message due to dynamic import

* allow setting csrf token in blitz rpc

* cleanup

* fix

* pnpm lock fix and update csrf api

* fix global.ts type definition

* remove change to merge

* fix pnpm-lock

* update integration-tests to work without blitz-auth

* initial working commit after switch to plugin system

* fix pnpm-lock

* readd the changeset

* update hook names

* Revert "readd the changeset"

This reverts commit 796f3f518e.

* Revert "update hook names"

This reverts commit fb127ed84e.

* Revert "fix pnpm-lock"

This reverts commit d7447b5966.

* Revert "Revert "fix pnpm-lock""

This reverts commit c2f21aa0e5.

* Revert "Revert "update hook names""

This reverts commit 4b66846b20.

* Revert "Revert "readd the changeset""

This reverts commit c95d150e64.

* add header to rpc plugin

* pnpm lock fix

* cleanup - change global hook names to prefix with __BLITZ

* initial commit suggestion - TODO Fix types

* fix most type assertions

* fix error without blitz auth

* add typea to events and middleware reducers

* implement suggestion

* Apply suggestions from code review

Co-authored-by: Brandon Bayer <b@bayer.ws>

* move onSessionCreated event from blitz-auth to blitz-rpc

* move globals to blitz core, move event listener to blitz-next

* remove middlewareCtx to Ctx

* fix imports

* improve type definition of hook types

* format

* Revert "remove middlewareCtx to Ctx"

This reverts commit 4259b4dbed.

* Revert "fix imports"

This reverts commit 7422bfaee3.

* revert changes from MiddlewareCtx to Ctx

* pnpm lock and other fixes

* remove type assertion

* merge to one `Array.reduce`

* Apply suggestions from code review

Co-authored-by: Brandon Bayer <b@bayer.ws>

* implement review suggestions

* Update packages/blitz/src/types.ts

* add unit tests

* cleanup

* Update packages/blitz/tests/plugin.test.ts

* add providers to plugin reduce

* add initial integration test for full blitz rpc+auth and custom client plugins

* test commenting out playwright install

* fixes

* remove changes related to console.log checking

* test

* try with different command

* comment

* another try

* try adding global install

* change console.log to console.info for better identification

* fix db

* lowdb import fix

* convert from lowdb to prisma

* fix blitz build error

* add custom plugin events to integration-tests

* manipulate the timing of event firing

* fix

* check

* add middleware tests

* fix

* fix commented test and cleanup

* add the migration file

Co-authored-by: Brandon Bayer <b@bayer.ws>
2022-12-13 18:44:39 -05:00
Dillon Raphael
a0596279bd Fix blitz install for recipes that use the path helper (#3995) 2022-12-09 08:32:44 -08:00
Dillon Raphael
fe2e4eb1e9 Update readme 2022-12-02 08:51:26 -05:00
Aleksandra
8c247e26e7 Switch from jest to vitest in new app templates (#3985)
* Switch from jest to vitest in new app templates

* Finish vitest setup

* Handle vitest.config.js vs vitest.config.ts

* Add proper vitest config to js templates

* Add changeset

* Update READMEs in new app templates

* Fix tests after vitest upgrade

* Update spyOn references in tests
2022-11-28 14:24:08 -05:00
Siddharth Suresh
650a157e1d fix #3989 (#3990) 2022-11-25 18:21:41 -05:00
Blitz.js Bot
9dc81fe958 (meta) added @usamaster as contributor 2022-11-24 11:22:59 -05:00
github-actions[bot]
474b5494ac Version Packages (beta) (#3977)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-11-22 16:09:29 -05:00
Dillon Raphael
b33db08286 Ensure superjson registers error classes once (#3982)
* bump superjson version & ensure superjson register

* update changeset & use error name as property for check if class has been registered

* refactor
2022-11-22 16:04:42 -05:00
Brandon Bayer
c1e0040639 transpile packages to es2015 to support older browsers (#3983) 2022-11-22 13:39:11 -05:00
Blitz.js Bot
5a7e6e0bb8 (meta) updated @medihack contributions 2022-11-21 14:30:17 -05:00
Kai Schlamp
a6f32d1d0b Export enhancePrisma for client again (#3965)
* Export enhancePrisma for client again
2022-11-21 14:30:11 -05:00
Selçuk Fatih Sevinç
c126b8191b Fix builder execute command hangs up (#3958)
* fix: builder execute command hangs up

* using "blitz install" inside recipe with addRunCommandStep causes hangs up

Co-authored-by: Selçuk Fatih Sevinç <selcuk@hub.studio>
2022-11-21 10:20:46 -05:00
Blitz.js Bot
775004f23e (meta) added @selcukfatihsevinc as contributor 2022-11-21 09:43:43 -05:00
Selçuk Fatih Sevinç
696f48c4e8 some providers need extra attributes, update for wrapAppWithProvider (#3959)
Co-authored-by: Dillon Raphael <dillon@creatorsneverdie.com>
2022-11-21 09:43:36 -05:00
Paul
942536d9ad Extend paginate.ts to support more complex pagination object (#3970)
* Extend paginate.ts to support more complex pagination object

* change pagination object based on reviewer suggestion

* changest inclusion

* update paginate test

Co-authored-by: Paul Moss <paulmoss06@gmail.com>
2022-11-18 09:50:10 -05:00
Brandon Bayer
b493c93f8b fix resolverPath:root and make it work with monorepo resolvers (#3978) 2022-11-17 21:47:17 -05:00
Dillon Raphael
b80c3d92ca Fix form paths when running blitz generate all (#3961)
* Update form paths when running blitz generate all

* pnpmlock & update changeset

* Update changeset

* pnpmlock

* update playwright
2022-11-17 17:41:11 -05:00
216 changed files with 4902 additions and 1229 deletions

View File

@@ -2913,7 +2913,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/120626?v=4",
"profile": "https://github.com/medihack",
"contributions": [
"doc"
"doc",
"code"
]
},
{
@@ -3755,6 +3756,65 @@
"code",
"test"
]
},
{
"login": "selcukfatihsevinc",
"name": "Selçuk Fatih Sevinç",
"avatar_url": "https://avatars.githubusercontent.com/u/384836?v=4",
"profile": "https://github.com/selcukfatihsevinc",
"contributions": [
"doc",
"code"
]
},
{
"login": "usamaster",
"name": "usamaster",
"avatar_url": "https://avatars.githubusercontent.com/u/5255330?v=4",
"profile": "https://github.com/usamaster",
"contributions": [
"doc"
]
},
{
"login": "a11rew",
"name": "Andrew Glago",
"avatar_url": "https://avatars.githubusercontent.com/u/87580113?v=4",
"profile": "a11rew.dev",
"contributions": [
"doc",
"code"
]
},
{
"login": "tordans",
"name": "Tobias",
"avatar_url": "https://avatars.githubusercontent.com/u/111561?v=4",
"profile": "http://tobiasjordans.de",
"contributions": [
"code",
"doc"
]
},
{
"login": "iagormoraes",
"name": "Iagor Moraes",
"avatar_url": "https://avatars.githubusercontent.com/u/13892132?v=4",
"profile": "https://www.linkedin.com/in/iagor-moraes/",
"contributions": [
"doc",
"code"
]
},
{
"login": "Trancever",
"name": "Dawid Urbaniak",
"avatar_url": "https://avatars.githubusercontent.com/u/18584155?v=4",
"profile": "https://twitter.com/trensik",
"contributions": [
"doc",
"code"
]
}
],
"contributorsPerLine": 7,

View File

@@ -0,0 +1,8 @@
---
"blitz": minor
"@blitzjs/auth": minor
"@blitzjs/next": minor
"@blitzjs/rpc": minor
---
transpile packages to es2015 to support older browsers

View File

@@ -0,0 +1,5 @@
---
"blitz": minor
---
When db.\$reset() rejects, reject with an Error object

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/generator": patch
---
Remove husky prepush hook & update precommit hook to only run prettier

View File

@@ -0,0 +1,6 @@
---
"@blitzjs/rpc": patch
"@blitzjs/generator": patch
---
Switch from jest to vitest in new app templates

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/auth": patch
---
Fixes adding authError query param in Passport adapter.

View File

@@ -0,0 +1,8 @@
---
"blitz": minor
"@blitzjs/auth": minor
"@blitzjs/next": minor
"@blitzjs/rpc": minor
---
Decoupled Blitz RPC from Blitz Auth to allow independent use.

View File

@@ -0,0 +1,5 @@
---
"blitz": minor
---
some providers need extra attributes, update for wrapAppWithProvider

View File

@@ -0,0 +1,6 @@
---
"@blitzjs/rpc": patch
"blitz": patch
---
Fix suspense error codegen patch for nextjs versions 13-13.0.6

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/generator": patch
---
Fix form paths when running blitz generate all

View File

@@ -0,0 +1,7 @@
---
"@blitzjs/auth": minor
"@blitzjs/next": minor
"@blitzjs/rpc": minor
---
fix Cannot read properties of null (reading 'isReady') for pnpm/yarn v3

View File

@@ -0,0 +1,5 @@
---
"blitz": major
---
update paginate.ts, return more params for more complex pagination control

View File

@@ -0,0 +1,5 @@
---
"blitz": patch
---
Export enhancePrisma for client again (Fixes #3964)

View File

@@ -44,7 +44,9 @@
"@blitzjs/recipe-styled-components": "0.34.0-canary.0",
"@blitzjs/recipe-tailwind": "0.34.0-canary.0",
"@blitzjs/recipe-theme-ui": "0.34.0-canary.0",
"@blitzjs/recipe-vanilla-extract": "0.34.0-canary.0"
"@blitzjs/recipe-vanilla-extract": "0.34.0-canary.0",
"test-rpc-path-root": "0.0.0",
"test-full-auth-with-rpc": "0.0.0"
},
"changesets": [
"afraid-dancers-juggle",
@@ -58,11 +60,14 @@
"breezy-moose-behave",
"bright-mangos-run",
"brown-avocados-wink",
"calm-books-push",
"calm-carpets-deny",
"calm-horses-tie",
"calm-nails-wait",
"calm-papayas-protect",
"calm-tomatoes-drive",
"chilled-carrots-own",
"chilly-candles-care",
"chilly-nails-nail",
"clean-hats-pump",
"clean-walls-wink",
@@ -72,11 +77,14 @@
"cuddly-pugs-crash",
"curly-rules-speak",
"curly-seas-serve",
"curvy-days-attend",
"cyan-bulldogs-heal",
"cyan-cars-greet",
"dirty-monkeys-greet",
"dirty-planets-chew",
"dull-rings-arrive",
"early-lamps-itch",
"eighty-apes-sleep",
"eleven-humans-sort",
"eleven-lobsters-drop",
"empty-berries-rule",
@@ -90,8 +98,10 @@
"fast-papayas-grow",
"fast-trainers-kneel",
"few-dogs-fetch",
"few-hounds-worry",
"few-shrimps-leave",
"flat-bees-approve",
"fluffy-coats-flow",
"fluffy-mangos-begin",
"fluffy-mice-wash",
"forty-timers-rhyme",
@@ -105,6 +115,7 @@
"gentle-dogs-reply",
"gentle-lions-explode",
"giant-mails-tap",
"giant-students-carry",
"gold-horses-punch",
"good-apes-drum",
"good-insects-wink",
@@ -135,6 +146,7 @@
"itchy-houses-marry",
"itchy-spoons-tan",
"khaki-ducks-cheer",
"khaki-pens-rest",
"kind-walls-suffer",
"late-steaks-give",
"lazy-maps-sort",
@@ -146,6 +158,7 @@
"little-pears-ring",
"long-bees-hope",
"long-dancers-jog",
"long-hounds-melt",
"long-lobsters-drop",
"lovely-berries-sell",
"lovely-colts-share",
@@ -154,6 +167,7 @@
"lucky-years-turn",
"mean-gorillas-reply",
"modern-cameras-pull",
"modern-games-dream",
"modern-ligers-behave",
"moody-bags-walk",
"moody-spoons-rhyme",
@@ -199,14 +213,17 @@
"red-badgers-retire",
"red-gorillas-marry",
"rich-chairs-invent",
"rich-gorillas-develop",
"rich-queens-travel",
"rotten-rocks-remember",
"rude-trainers-visit",
"serious-mugs-leave",
"shaggy-carpets-brake",
"sharp-falcons-begin",
"sharp-olives-sip",
"shy-olives-hang",
"shy-pumpkins-try",
"shy-socks-eat",
"silent-colts-reply",
"silent-lies-run",
"silly-apricots-share",
@@ -234,6 +251,7 @@
"stale-parents-yawn",
"strong-apes-reply",
"strong-keys-lie",
"stupid-rabbits-jump",
"stupid-walls-sell",
"sweet-kiwis-cross",
"swift-drinks-dress",
@@ -244,12 +262,16 @@
"tasty-news-collect",
"ten-hairs-listen",
"ten-rivers-burn",
"tender-cooks-tie",
"tender-pianos-check",
"thick-moons-fry",
"thick-parrots-float",
"thirty-countries-build",
"thirty-spies-applaud",
"three-lies-pull",
"three-toes-sell",
"tidy-clouds-smoke",
"tidy-llamas-compare",
"tough-toes-pull",
"twelve-hornets-sip",
"twelve-lemons-smile",

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/rpc": patch
---
fix: allow `GET` requests without `params` and `meta` keys

View File

@@ -0,0 +1,5 @@
---
"blitz": patch
---
Fix blitz install for recipes that use the path helper to check if ./src/pages directory is available, otherwise use ./pages

View File

@@ -0,0 +1,5 @@
---
"blitz": patch
---
using "blitz install" inside recipe with addRunCommandStep causes hangs up

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/rpc": patch
---
Support full api of tanstack invalidateQueries

View File

@@ -0,0 +1,7 @@
---
"blitz": patch
"@blitzjs/next": patch
"@blitzjs/rpc": patch
---
Fix ambigious class warning log & upgrade superjson from 1.9.1 to 1.11.0

View File

@@ -0,0 +1,6 @@
---
"@blitzjs/next": patch
"blitz": patch
---
Add an href property to the generated route manifest that will return a string of the pathname and included query params.

View File

@@ -0,0 +1,5 @@
---
"blitz": patch
---
add regex to support inline and non-inline codebase and proper next.js package version check

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/rpc": minor
---
fix resolverPath:root and make it work with monorepo resolvers

4
.github/CODEOWNERS vendored
View File

@@ -1,5 +1,5 @@
# https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners
* @beerose @dillonraphael
* @flybayer
packages/generator/templates**/* @flybayer
# packages/generator/templates**/* @flybayer

View File

@@ -8,10 +8,6 @@ concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
TURBO_TOKEN: 05de0230f01174d1f8cb4845a01dc6c895ce28f04ebef2318ab11615791b871c35eabbf8
TURBO_TEAM: foo
jobs:
lint:
name: Lint
@@ -29,11 +25,6 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile
- run: pnpm manypkg check
- name: Turborepo local server
uses: felixmosh/turborepo-gh-artifacts@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
server-token: ${{ env.TURBO_TOKEN }}
- name: Build
run: pnpm build
- name: Lint
@@ -53,12 +44,6 @@ jobs:
node-version: 16
cache: "pnpm"
- run: pnpm install --frozen-lockfile
- run: pnpm manypkg check
- name: Turborepo local server
uses: felixmosh/turborepo-gh-artifacts@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
server-token: ${{ env.TURBO_TOKEN }}
- name: Build
run: pnpm build
- name: Build Apps
@@ -94,15 +79,6 @@ jobs:
run: pnpm install --frozen-lockfile
shell: bash
- run: pnpm manypkg check
shell: bash
- name: Turborepo local server
uses: felixmosh/turborepo-gh-artifacts@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
server-token: ${{ env.TURBO_TOKEN }}
- name: Build
run: pnpm build
shell: bash
@@ -158,23 +134,16 @@ jobs:
node-version: ${{ matrix.NODE_VERSION }}
cache: "pnpm"
- name: Link Blitz CLI
run: pnpm link ./packages/blitz
shell: bash
- name: Install dependencies
run: pnpm install --frozen-lockfile
shell: bash
- run: pnpm manypkg check
- name: Install playwright
run: |
npm i -g playwright
PLAYWRIGHT_BROWSERS_PATH=$HOME/pw-browsers npx playwright install --with-deps
shell: bash
- name: Turborepo local server
uses: felixmosh/turborepo-gh-artifacts@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
server-token: ${{ env.TURBO_TOKEN }}
- name: Build
run: pnpm build
shell: bash

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-397-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-403-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">
@@ -136,8 +136,6 @@ Your financial contributions help ensure Blitz continues to be developed and mai
<tr>
<td align="center"><a href="https://twitter.com/flybayer"><img src="https://avatars3.githubusercontent.com/u/8813276?v=4" width="100px;" alt=""/><br /><sub><b>Brandon Bayer</b></sub></a><br />Creator</td>
<td align="center"><a href="http://twitter.com/dillonraphael"><img src="https://avatars.githubusercontent.com/u/3496193?v=4" width="100px;" alt=""/><br /><sub><b>Dillon Raphael</b></sub></a><br />Lead Maintainer</td>
<td align="center"><a href="http://aleksandra.codes"><img src="https://avatars.githubusercontent.com/u/9019397?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aleksandra Sikora</b></sub></a><br />Core Maintainer</td>
</tr>
</table>
@@ -617,7 +615,7 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<td align="center"><a href="https://github.com/ricardo-rp"><img src="https://avatars.githubusercontent.com/u/30808767?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ricardo Romero</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ricardo-rp" title="Documentation">📖</a></td>
<td align="center"><a href="exocortex.anothernode.com"><img src="https://avatars.githubusercontent.com/u/3286144?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Moritz Reiter</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=anothernode" title="Documentation">📖</a></td>
<td align="center"><a href="https://msich.dev"><img src="https://avatars.githubusercontent.com/u/38794918?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt Sichterman</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=msichterman" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/medihack"><img src="https://avatars.githubusercontent.com/u/120626?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kai Schlamp</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=medihack" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/medihack"><img src="https://avatars.githubusercontent.com/u/120626?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kai Schlamp</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=medihack" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=medihack" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://muyiwa.me"><img src="https://avatars.githubusercontent.com/u/6832244?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Muyiwa Olu</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=muyiwaolu" title="Code">💻</a></td>
@@ -733,6 +731,14 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<td align="center"><a href="https://github.com/janvennemann"><img src="https://avatars.githubusercontent.com/u/1406024?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jan Vennemann</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=janvennemann" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=janvennemann" title="Code">💻</a></td>
<td align="center"><a href="https://kevinjones.engineer"><img src="https://avatars.githubusercontent.com/u/20748598?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kevin Jones</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=joneskj55" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/paulm17"><img src="https://avatars.githubusercontent.com/u/387463?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Paul</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=paulm17" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=paulm17" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=paulm17" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/selcukfatihsevinc"><img src="https://avatars.githubusercontent.com/u/384836?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Selçuk Fatih Sevinç</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=selcukfatihsevinc" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=selcukfatihsevinc" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/usamaster"><img src="https://avatars.githubusercontent.com/u/5255330?v=4?s=100" width="100px;" alt=""/><br /><sub><b>usamaster</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=usamaster" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="a11rew.dev"><img src="https://avatars.githubusercontent.com/u/87580113?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andrew Glago</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=a11rew" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=a11rew" title="Code">💻</a></td>
<td align="center"><a href="http://tobiasjordans.de"><img src="https://avatars.githubusercontent.com/u/111561?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tobias</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=tordans" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=tordans" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.linkedin.com/in/iagor-moraes/"><img src="https://avatars.githubusercontent.com/u/13892132?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Iagor Moraes</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=iagormoraes" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=iagormoraes" title="Code">💻</a></td>
<td align="center"><a href="https://twitter.com/trensik"><img src="https://avatars.githubusercontent.com/u/18584155?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dawid Urbaniak</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Trancever" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=Trancever" title="Code">💻</a></td>
</tr>
</table>

View File

@@ -67,7 +67,7 @@ Here is the starting structure of your app.
```
__name__
├── app/
├── src/
│ ├── api/
│ ├── auth/
│ │ ├── components/
@@ -131,7 +131,7 @@ __name__
These files are:
- The `app/` folder is a container for most of your project. This is where youll put any pages or API routes.
- The `src/` folder is a container for most of your project. This is where youll put any pages or API routes.
- `db/` is where your database configuration goes. If youre writing models or checking migrations, this is where to go.

View File

@@ -30,7 +30,7 @@
"@hookform/error-message": "2.0.0",
"@hookform/resolvers": "2.9.10",
"@prisma/client": "4.6.0",
"blitz": "workspace:2.0.0-beta.18",
"blitz": "workspace:2.0.0-beta.21",
"next": "12.2.5",
"openid-client": "5.2.1",
"prisma": "4.6.0",

View File

@@ -4,7 +4,7 @@ TODO
This is a [Blitz.js](https://github.com/blitz-js/blitz) app.
# ****name****
# \***\*name\*\***
## Getting Started
@@ -38,7 +38,7 @@ Runs your tests using Jest.
yarn test
```
Blitz comes with a test setup using [Jest](https://jestjs.io/) and [react-testing-library](https://testing-library.com/).
Blitz comes with a test setup using [Vitest](https://vitest.dev/) and [react-testing-library](https://testing-library.com/).
## Commands
@@ -67,7 +67,7 @@ Here is the starting structure of your app.
```
__name__
├── app/
├── src/
│ ├── api/
│ ├── auth/
│ │ ├── components/
@@ -122,7 +122,7 @@ __name__
├── .eslintrc.js
├── babel.config.js
├── blitz.config.ts
├── jest.config.ts
├── vitest.config.ts
├── package.json
├── README.md
├── tsconfig.json
@@ -131,7 +131,7 @@ __name__
These files are:
- The `app/` folder is a container for most of your project. This is where youll put any pages or API routes.
- The `src/` folder is a container for most of your project. This is where youll put any pages or API routes.
- `db/` is where your database configuration goes. If youre writing models or checking migrations, this is where to go.
@@ -149,7 +149,7 @@ These files are:
- `blitz.config.ts` is for advanced custom configuration of Blitz. [Here you can learn how to use it](https://blitzjs.com/docs/blitz-config).
- `jest.config.js` contains config for Jest tests. You can [customize it if needed](https://jestjs.io/docs/en/configuration).
- `vitest.config.ts` contains config for Vitest tests. You can [customize it if needed](https://vitejs.dev/config/).
You can read more about it in the [File Structure](https://blitzjs.com/docs/file-structure) section of the documentation.

View File

@@ -1,7 +0,0 @@
const nextJest = require("@blitzjs/next/jest")
const createJestConfig = nextJest({
dir: "./",
})
module.exports = createJestConfig(customJestConfig)

View File

@@ -8,7 +8,8 @@
"lint": "next lint",
"prisma:start": "prisma generate && prisma migrate deploy",
"prisma:studio": "prisma studio",
"test:local": "jest"
"test:local": "prisma generate && vitest run --passWithNoTests",
"test:watch": "vitest"
},
"prisma": {
"schema": "db/schema.prisma"
@@ -30,7 +31,7 @@
"@hookform/error-message": "2.0.0",
"@hookform/resolvers": "2.9.10",
"@prisma/client": "4.6.0",
"blitz": "workspace:2.0.0-beta.18",
"blitz": "workspace:2.0.0-beta.21",
"next": "12.2.5",
"prisma": "4.6.0",
"react": "18.2.0",
@@ -41,25 +42,27 @@
},
"devDependencies": {
"@next/bundle-analyzer": "12.0.8",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "13.4.0",
"@testing-library/react-hooks": "8.0.1",
"@types/jest": "29.2.2",
"@types/node": "18.11.9",
"@types/preview-email": "2.0.1",
"@types/react": "18.0.25",
"@typescript-eslint/eslint-plugin": "5.42.1",
"@vitejs/plugin-react": "2.2.0",
"eslint": "8.27.0",
"eslint-config-next": "12.3.1",
"eslint-config-prettier": "8.5.0",
"husky": "8.0.2",
"jest": "29.3.0",
"jest-environment-jsdom": "29.3.0",
"jsdom": "20.0.3",
"lint-staged": "13.0.3",
"prettier": "^2.7.1",
"prettier-plugin-prisma": "4.4.0",
"pretty-quick": "3.1.3",
"preview-email": "3.0.7",
"typescript": "^4.8.4"
"typescript": "^4.8.4",
"vite-tsconfig-paths": "3.6.0",
"vitest": "0.25.3"
},
"private": true
}

View File

@@ -24,7 +24,7 @@ export const SignupForm = (props: SignupFormProps) => {
props.onSuccess?.()
} catch (error: any) {
if (error.code === "P2002" && error.meta?.target?.includes("email")) {
// This error comes from Prisma
// Error "P2002" comes from Prisma (https://www.prisma.io/docs/reference/api-reference/error-reference#p2002)
return { email: "This email is already being used" }
} else {
return { [FORM_ERROR]: error.toString() }

View File

@@ -0,0 +1,64 @@
import { vi, describe, it, beforeEach } from "vitest"
import db from "db"
import { hash256 } from "@blitzjs/auth"
import forgotPassword from "./forgotPassword"
import previewEmail from "preview-email"
import { Ctx } from "@blitzjs/next"
beforeEach(async () => {
await db.$reset()
})
const generatedToken = "plain-token"
vi.mock("@blitzjs/auth", async () => {
const auth = await vi.importActual<Record<string, unknown>>("@blitzjs/auth")!
return {
...auth,
generateToken: () => generatedToken,
}
})
vi.mock("preview-email", () => ({ default: vi.fn() }))
describe("forgotPassword mutation", () => {
it("does not throw error if user doesn't exist", async () => {
await expect(forgotPassword({ email: "no-user@email.com" }, {} as Ctx)).resolves.not.toThrow()
})
it("works correctly", async () => {
// Create test user
const user = await db.user.create({
data: {
email: "user@example.com",
tokens: {
// Create old token to ensure it's deleted
create: {
type: "RESET_PASSWORD",
hashedToken: "token",
expiresAt: new Date(),
sentTo: "user@example.com",
},
},
},
include: { tokens: true },
})
// Invoke the mutation
await forgotPassword({ email: user.email }, {} as Ctx)
const tokens = await db.token.findMany({ where: { userId: user.id } })
const token = tokens[0]
if (!user.tokens[0]) throw new Error("Missing user token")
if (!token) throw new Error("Missing token")
// delete's existing tokens
expect(tokens.length).toBe(1)
expect(token.id).not.toBe(user.tokens[0].id)
expect(token.type).toBe("RESET_PASSWORD")
expect(token.sentTo).toBe(user.email)
expect(token.hashedToken).toBe(hash256(generatedToken))
expect(token.expiresAt > new Date()).toBe(true)
expect(previewEmail).toBeCalled()
})
})

View File

@@ -0,0 +1,83 @@
import { vi, describe, it, beforeEach, expect } from "vitest"
import resetPassword from "./resetPassword"
import db from "db"
import { SecurePassword, hash256 } from "@blitzjs/auth"
beforeEach(async () => {
await db.$reset()
})
const mockCtx: any = {
session: {
$create: vi.fn(),
},
}
describe("resetPassword mutation", () => {
it("works correctly", async () => {
expect(true).toBe(true)
// Create test user
const goodToken = "randomPasswordResetToken"
const expiredToken = "expiredRandomPasswordResetToken"
const future = new Date()
future.setHours(future.getHours() + 4)
const past = new Date()
past.setHours(past.getHours() - 4)
const user = await db.user.create({
data: {
email: "user@example.com",
tokens: {
// Create old token to ensure it's deleted
create: [
{
type: "RESET_PASSWORD",
hashedToken: hash256(expiredToken),
expiresAt: past,
sentTo: "user@example.com",
},
{
type: "RESET_PASSWORD",
hashedToken: hash256(goodToken),
expiresAt: future,
sentTo: "user@example.com",
},
],
},
},
include: { tokens: true },
})
const newPassword = "newPassword"
// Non-existent token
await expect(
resetPassword({ token: "no-token", password: "", passwordConfirmation: "" }, mockCtx)
).rejects.toThrowError()
// Expired token
await expect(
resetPassword(
{ token: expiredToken, password: newPassword, passwordConfirmation: newPassword },
mockCtx
)
).rejects.toThrowError()
// Good token
await resetPassword(
{ token: goodToken, password: newPassword, passwordConfirmation: newPassword },
mockCtx
)
// Delete's the token
const numberOfTokens = await db.token.count({ where: { userId: user.id } })
expect(numberOfTokens).toBe(0)
// Updates user's password
const updatedUser = await db.user.findFirst({ where: { id: user.id } })
expect(await SecurePassword.verify(updatedUser!.hashedPassword, newPassword)).toBe(
SecurePassword.VALID
)
})
})

View File

@@ -1,6 +1,7 @@
import { AuthClientPlugin } from "@blitzjs/auth"
import { setupBlitzClient } from "@blitzjs/next"
import { BlitzRpcPlugin } from "@blitzjs/rpc"
import { BlitzCustomPlugin } from "./custom-plugin/plugin"
export const { withBlitz } = setupBlitzClient({
plugins: [
@@ -8,5 +9,6 @@ export const { withBlitz } = setupBlitzClient({
cookiePrefix: "web-cookie-prefix",
}),
BlitzRpcPlugin({}),
BlitzCustomPlugin({}),
],
})

View File

@@ -0,0 +1,38 @@
import { createClientPlugin } from "blitz"
type CustomPluginOptions = {
// ... your options
}
export const BlitzCustomPlugin = createClientPlugin<CustomPluginOptions, {}>(
(options?: CustomPluginOptions) => {
// ... your plugin code
console.log("Custom plugin loaded")
return {
events: {
onSessionCreated: async () => {
// Called when a new session is created - Usually when the user logs in or logs out
console.log("onSessionCreated in custom plugin")
},
onRpcError: async () => {
// Called when an RPC call fails
console.log("onRpcError in custom plugin")
},
},
middleware: {
beforeHttpRequest: (req) => {
//make changes to the request options before RPC call
req.headers = { ...req.headers, ...{ customHeader: "customHeaderValue" } }
return req
},
beforeHttpResponse: (res) => {
//make changes to the response before returning to the caller
return res
},
},
exports: () => ({
// ... your exports
}),
}
}
)

View File

@@ -7,7 +7,6 @@ import logout from "src/auth/mutations/logout"
import logo from "public/logo.png"
import { useMutation } from "@blitzjs/rpc"
import { Routes, BlitzPage } from "@blitzjs/next"
import { getSession, useSession } from "@blitzjs/auth"
/*
* This file is just for a pleasant getting started page for your new app.

View File

@@ -1,27 +1,32 @@
import { useCurrentUser } from "src/users/hooks/useCurrentUser"
/**
* @vitest-environment jsdom
*/
import { expect, vi, test } from "vitest"
import { render } from "test/utils"
import Home from "../src/pages/index"
jest.mock("src/users/hooks/useCurrentUser")
const mockUseCurrentUser = useCurrentUser as jest.MockedFunction<typeof useCurrentUser>
vi.mock("public/logo.png", () => ({
default: { src: "/logo.png" },
}))
describe("renders blitz documentation link", () => {
it("test", () => {
// This is an example of how to ensure a specific item is in the document
// But it's disabled by default (by test.skip) so the test doesn't fail
// when you remove the the default content from the page
test.skip("renders blitz documentation link", () => {
// This is an example of how to ensure a specific item is in the document
// But it's disabled by default (by test.skip) so the test doesn't fail
// when you remove the the default content from the page
// This is an example on how to mock api hooks when testing
mockUseCurrentUser.mockReturnValue({
// This is an example on how to mock api hooks when testing
vi.mock("src/users/hooks/useCurrentUser", () => ({
useCurrentUser: () => ({
id: 1,
name: "User",
email: "user@email.com",
role: "user",
})
}),
}))
const { getByText } = render(<Home />)
const linkElement = getByText(/Documentation/i)
expect(linkElement).toBeInTheDocument()
})
const { getByText } = render(<Home />)
const linkElement = getByText(/Documentation/i)
expect(linkElement).toBeInTheDocument()
})

View File

@@ -1,4 +1,3 @@
// This is the jest 'setupFilesAfterEnv' setup file
// It's a good place to set globals, add global before/after hooks, etc
import "@testing-library/jest-dom"
export {} // so TS doesn't complain
export {}

View File

@@ -1,3 +1,4 @@
import { vi } from "vitest"
import { render as defaultRender } from "@testing-library/react"
import { renderHook as defaultRenderHook } from "@testing-library/react-hooks"
import { NextRouter } from "next/router"
@@ -82,16 +83,16 @@ export const mockRouter: NextRouter = {
isReady: true,
isLocaleDomain: false,
isPreview: false,
push: jest.fn(),
replace: jest.fn(),
reload: jest.fn(),
back: jest.fn(),
prefetch: jest.fn(),
beforePopState: jest.fn(),
push: vi.fn(),
replace: vi.fn(),
reload: vi.fn(),
back: vi.fn(),
prefetch: vi.fn(),
beforePopState: vi.fn(),
events: {
on: jest.fn(),
off: jest.fn(),
emit: jest.fn(),
on: vi.fn(),
off: vi.fn(),
emit: vi.fn(),
},
isFallback: false,
}

View File

@@ -0,0 +1,17 @@
import { defineConfig } from "vitest/config"
import react from "@vitejs/plugin-react"
import tsconfigPaths from "vite-tsconfig-paths"
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react(), tsconfigPaths()],
test: {
dir: "./",
globals: true,
setupFiles: "./test/setup.ts",
coverage: {
reporter: ["text", "json", "html"],
},
},
})

View File

@@ -0,0 +1,2 @@
SESSION_SECRET_KEY=hsdenhJfpLHrGjgdgg3jdF8g2bYD2PaQ
HEADLESS=true

View File

@@ -0,0 +1 @@
module.exports = require("@blitzjs/next/eslint")

View File

@@ -0,0 +1,3 @@
node_modules
# Keep environment variables out of version control
*.sqlite

View File

@@ -0,0 +1,7 @@
import {enhancePrisma} from "blitz"
import {PrismaClient} from "@prisma/client"
const EnhancedPrisma = enhancePrisma(PrismaClient)
export * from "@prisma/client"
const prisma = new EnhancedPrisma()
export default prisma

View File

@@ -0,0 +1,47 @@
-- CreateTable
CREATE TABLE "User" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
"name" TEXT,
"email" TEXT NOT NULL,
"hashedPassword" TEXT,
"role" TEXT NOT NULL DEFAULT 'user'
);
-- CreateTable
CREATE TABLE "Session" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
"expiresAt" DATETIME,
"handle" TEXT NOT NULL,
"userId" INTEGER,
"hashedSessionToken" TEXT,
"antiCSRFToken" TEXT,
"publicData" TEXT,
"privateData" TEXT,
CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "Token" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
"hashedToken" TEXT NOT NULL,
"type" TEXT NOT NULL,
"expiresAt" DATETIME NOT NULL,
"sentTo" TEXT NOT NULL,
"userId" INTEGER NOT NULL,
CONSTRAINT "Token_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
-- CreateIndex
CREATE UNIQUE INDEX "Session_handle_key" ON "Session"("handle");
-- CreateIndex
CREATE UNIQUE INDEX "Token_hashedToken_type_key" ON "Token"("hashedToken", "type");

View File

@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "sqlite"

View File

@@ -0,0 +1,50 @@
datasource sqlite {
provider = "sqlite"
url = "file:./db.sqlite"
}
generator client {
provider = "prisma-client-js"
}
model User {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String?
email String @unique
hashedPassword String?
role String @default("user")
sessions Session[]
tokens Token[]
}
model Session {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
expiresAt DateTime?
handle String @unique
user User? @relation(fields: [userId], references: [id])
userId Int?
hashedSessionToken String?
antiCSRFToken String?
publicData String?
privateData String?
}
model Token {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
hashedToken String
type String
expiresAt DateTime
sentTo String
user User @relation(fields: [userId], references: [id])
userId Int
@@unique([hashedToken, type])
}

View File

@@ -0,0 +1,18 @@
import prisma from "./index"
import {SecurePassword} from "@blitzjs/auth"
const seed = async () => {
const hashedPassword = await SecurePassword.hash("abcd1234")
await prisma.user.create({
data: {
email: "test@test.com",
hashedPassword,
role: "user",
},
})
process.exit(0)
}
seed()
export default seed

View File

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

View File

@@ -0,0 +1,2 @@
const {withBlitz} = require("@blitzjs/next")
module.exports = withBlitz({})

View File

@@ -0,0 +1,62 @@
{
"name": "test-full-auth-with-rpc",
"version": "0.0.0",
"private": true,
"prisma": {
"seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} db/seed.ts",
"schema": "db/schema.prisma"
},
"scripts": {
"start:dev": "pnpm run prisma:start && blitz dev",
"test": "vitest run",
"test-watch": "vitest",
"start": "blitz start",
"lint": "next lint",
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next",
"prisma:start": "blitz prisma migrate deploy",
"prisma:studio": "prisma studio"
},
"dependencies": {
"@blitzjs/auth": "workspace:2.0.0-beta.21",
"@blitzjs/config": "workspace:2.0.0-beta.21",
"@blitzjs/next": "workspace:2.0.0-beta.21",
"@blitzjs/rpc": "workspace:2.0.0-beta.21",
"@hookform/error-message": "2.0.0",
"@hookform/resolvers": "2.9.10",
"@prisma/client": "4.6.0",
"blitz": "workspace:2.0.0-beta.21",
"delay": "5.0.0",
"next": "12.2.5",
"prisma": "4.6.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "7.39.1",
"ts-node": "10.9.1",
"zod": "3.19.1"
},
"devDependencies": {
"@next/bundle-analyzer": "12.0.8",
"@testing-library/jest-dom": "5.16.5",
"@testing-library/react": "13.4.0",
"@testing-library/react-hooks": "8.0.1",
"@types/node": "18.11.9",
"@types/preview-email": "2.0.1",
"@types/react": "18.0.25",
"@typescript-eslint/eslint-plugin": "5.42.1",
"@vitejs/plugin-react": "2.2.0",
"eslint": "8.27.0",
"eslint-config-next": "12.3.1",
"eslint-config-prettier": "8.5.0",
"husky": "8.0.2",
"jsdom": "20.0.3",
"lint-staged": "13.0.3",
"playwright": "1.28.0",
"prettier": "^2.7.1",
"prettier-plugin-prisma": "4.4.0",
"pretty-quick": "3.1.3",
"preview-email": "3.0.7",
"typescript": "^4.8.4",
"vite-tsconfig-paths": "3.6.0",
"vitest": "0.25.3"
}
}

View File

@@ -0,0 +1,14 @@
import {AuthClientPlugin} from "@blitzjs/auth"
import {setupBlitzClient} from "@blitzjs/next"
import {BlitzRpcPlugin} from "@blitzjs/rpc"
import {BlitzCustomPlugin} from "./custom-plugin/plugin"
export const {withBlitz} = setupBlitzClient({
plugins: [
AuthClientPlugin({
cookiePrefix: "web-cookie-prefix",
}),
BlitzRpcPlugin({}),
BlitzCustomPlugin({}),
],
})

View File

@@ -0,0 +1,23 @@
import type {BlitzCliConfig} from "blitz"
import {setupBlitzServer} from "@blitzjs/next"
import {AuthServerPlugin, PrismaStorage} from "@blitzjs/auth"
import db from "../db"
import {simpleRolesIsAuthorized} from "@blitzjs/auth"
import {BlitzLogger} from "blitz"
const {gSSP, gSP, api} = setupBlitzServer({
plugins: [
AuthServerPlugin({
cookiePrefix: "web-cookie-prefix",
storage: PrismaStorage(db),
isAuthorized: simpleRolesIsAuthorized,
}),
],
logger: BlitzLogger({}),
})
export {gSSP, gSP, api}
export const cliConfig: BlitzCliConfig = {
customTemplates: "app/templates",
}

View File

@@ -0,0 +1,50 @@
import {createClientPlugin} from "blitz"
type CustomPluginOptions = {
// ... your options
}
export const BlitzCustomPlugin = createClientPlugin<CustomPluginOptions, {}>(
(options?: CustomPluginOptions) => {
// ... your plugin code
console.info("Custom plugin loaded")
return {
events: {
onSessionCreated: async () => {
// ... Called when a new session is created - Usually when the user logs in or logs out
// if the document url is /custom-plugin then write message to the document
if (document.location.pathname === "/custom-plugin") {
//find the content in div id page and write message
document.getElementById("page")!.innerText = "Custom plugin Session Created"
}
},
onRpcError: async () => {
// ... Called when an RPC call fails
if (document.location.pathname === "/custom-plugin") {
document.getElementById("page")!.innerText = "Custom plugin RPC Error"
}
},
},
middleware: {
beforeHttpRequest: (req) => {
// ... make changes to the request options before RPC call
if (document.location.pathname === "/custom-plugin") {
req.headers = {...req.headers, ...{customHeader: "customHeaderValue"}}
document.getElementById("before-req")!.innerText = req.headers["customHeader"]
}
return req
},
beforeHttpResponse: (res) => {
// ... make changes to the response before returning to the caller
if (document.location.pathname === "/custom-plugin") {
document.getElementById("before-res")!.innerText = res.headers.get("content-length")!
}
return res
},
},
exports: () => ({
// ... your exports
}),
}
},
)

View File

@@ -0,0 +1,9 @@
import {BlitzLayout} from "@blitzjs/next"
const AuthenticateLayout: BlitzLayout = ({children}) => {
return <div id="layout">{children}</div>
}
AuthenticateLayout.authenticate = true
export default AuthenticateLayout

View File

@@ -0,0 +1,9 @@
import {BlitzLayout} from "@blitzjs/next"
const AuthenticateRedirectLayout: BlitzLayout = ({children}) => {
return <div id="layout">{children}</div>
}
AuthenticateRedirectLayout.authenticate = {redirectTo: "/login"}
export default AuthenticateRedirectLayout

View File

@@ -0,0 +1,9 @@
import {BlitzLayout} from "@blitzjs/next"
const RedirectAuthenticatedLayout: BlitzLayout = ({children}) => {
return <div id="layout">{children}</div>
}
RedirectAuthenticatedLayout.redirectAuthenticatedTo = "/authenticated-query"
export default RedirectAuthenticatedLayout

View File

@@ -0,0 +1,10 @@
import {setPublicDataForUser} from "@blitzjs/auth"
import {Ctx} from "blitz"
export default async function changeRole({userId, role}: any, ctx: Ctx) {
// create two sessions to be changed
await ctx.session.$create({userId, role: "USER"})
await ctx.session.$create({userId, role: "USER"})
await setPublicDataForUser(userId, {role})
}

View File

@@ -0,0 +1,6 @@
import {Ctx} from "blitz"
export default async function login(_: any, ctx: Ctx) {
await ctx.session.$create({userId: 1, role: "USER"})
return true
}

View File

@@ -0,0 +1,6 @@
import {Ctx} from "blitz"
export default async function logout(_: any, ctx: Ctx) {
await ctx.session.$revoke()
return true
}

View File

@@ -0,0 +1,29 @@
import {withBlitz} from "../blitz-client"
import {useQueryErrorResetBoundary} from "@blitzjs/rpc"
import {AppProps, ErrorBoundary, ErrorFallbackProps} from "@blitzjs/next"
if (typeof window !== "undefined") {
;(window as any).DEBUG_BLITZ = 1
}
export default withBlitz(function App({Component, pageProps}: AppProps) {
const getLayout = Component.getLayout || ((page) => page)
return (
<ErrorBoundary
FallbackComponent={RootErrorFallback}
onReset={useQueryErrorResetBoundary().reset}
>
{getLayout(<Component {...pageProps} />)}
</ErrorBoundary>
)
})
function RootErrorFallback({error}: ErrorFallbackProps) {
return (
<div>
<div id="error">{error.name}</div>
{error.statusCode} {error.message}
</div>
)
}

View File

@@ -0,0 +1,23 @@
import Document, {NextScript, Head, Html, Main} from "next/document"
class MyDocument extends Document {
// Only uncomment if you need to customize this behaviour
// static async getInitialProps(ctx: DocumentContext) {
// const initialProps = await Document.getInitialProps(ctx)
// return {...initialProps}
// }
render() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument

View File

@@ -0,0 +1,4 @@
import {rpcHandler} from "@blitzjs/rpc"
import {api} from "../../../blitz-server"
export default api(rpcHandler({onError: console.log}))

View File

@@ -0,0 +1,34 @@
import {useMutation, useQuery} from "@blitzjs/rpc"
import logout from "../mutations/logout"
import getAuthenticatedBasic from "../queries/getAuthenticatedBasic"
import {Suspense} from "react"
function Content() {
const [result] = useQuery(getAuthenticatedBasic, undefined)
const [logoutMutation] = useMutation(logout)
return (
<div>
<div id="content">{result}</div>
<button
id="logout"
onClick={async () => {
await logoutMutation()
}}
>
logout
</button>
</div>
)
}
function AuthenticatedQuery() {
return (
<div id="page">
<Suspense fallback={"Loading..."}>
<Content />
</Suspense>
</div>
)
}
export default AuthenticatedQuery

View File

@@ -0,0 +1,43 @@
import {BlitzPage} from "@blitzjs/next"
import {Suspense, useEffect} from "react"
import {useQuery} from "@blitzjs/rpc"
import getNoauthBasic from "../queries/getNoauthBasic"
const Content = () => {
const [result] = useQuery(getNoauthBasic, undefined)
return (
<>
<div id="rpc-result">{result}</div>
</>
)
}
const CustomPlugin: BlitzPage = () => {
//send the event to the plugin to create a new session
useEffect(() => {
setTimeout(() => {
const event = new Event("blitz:session-created")
document.dispatchEvent(event)
}, 100)
setTimeout(() => {
const error = new Error("RPC failed")
const rpcEvent = new CustomEvent("blitz:rpc-error", {
detail: error,
})
document.dispatchEvent(rpcEvent)
}, 2000)
})
return (
<div id="root">
<div id="page">This is the custom plugin page</div>
<div id="before-req"> Initial Content </div>
<div id="before-res"> Initial Content </div>
<Suspense fallback={"Loading..."}>
<Content />
</Suspense>
</div>
)
}
export default CustomPlugin

View File

@@ -0,0 +1,33 @@
import {gSSP} from "../blitz-server"
import {getSession} from "@blitzjs/auth"
import {GetServerSideProps} from "next"
import {Suspense} from "react"
export const getServerSideProps: GetServerSideProps = gSSP(async ({req, res}) => {
const session = await getSession(req, res)
await session.$setPublicData({role: "USER"})
return {
props: {},
}
})
function Content() {
return (
<div>
<div id="content">it works</div>
</div>
)
}
function GSSPSetPublicData() {
return (
<div id="page">
<Suspense fallback={"Loading..."}>
<Content />
</Suspense>
</div>
)
}
export default GSSPSetPublicData

View File

@@ -0,0 +1,40 @@
import {useMutation, useQuery} from "@blitzjs/rpc"
import {BlitzPage} from "@blitzjs/next"
import AuthenticateRedirectLayout from "../layouts/AuthenticateRedirectLayout"
import logout from "../mutations/logout"
import getAuthenticatedBasic from "../queries/getAuthenticatedBasic"
import {Suspense} from "react"
function Content() {
const [result] = useQuery(getAuthenticatedBasic, undefined)
const [logoutMutation] = useMutation(logout)
return (
<div>
<div id="content">{result}</div>
<button
id="logout"
onClick={async () => {
await logoutMutation()
}}
>
logout
</button>
</div>
)
}
const LayoutAuthenticateLogoutPage: BlitzPage = () => {
return (
<div id="page">
<Suspense fallback={"Loading..."}>
<Content />
</Suspense>
</div>
)
}
LayoutAuthenticateLogoutPage.getLayout = (page) => (
<AuthenticateRedirectLayout>{page}</AuthenticateRedirectLayout>
)
export default LayoutAuthenticateLogoutPage

View File

@@ -0,0 +1,40 @@
import {useMutation, useQuery} from "@blitzjs/rpc"
import {BlitzPage} from "@blitzjs/next"
import AuthenticateRedirectLayout from "../layouts/AuthenticateRedirectLayout"
import logout from "../mutations/logout"
import getAuthenticatedBasic from "../queries/getAuthenticatedBasic"
import {Suspense} from "react"
function Content() {
const [result] = useQuery(getAuthenticatedBasic, undefined)
const [logoutMutation] = useMutation(logout)
return (
<div>
<div id="content">{result}</div>
<button
id="logout"
onClick={async () => {
await logoutMutation()
}}
>
logout
</button>
</div>
)
}
const LayoutAuthenticateRedirectPage: BlitzPage = () => {
return (
<div id="page">
<Suspense fallback={"Loading redirect page..."}>
<Content />
</Suspense>
</div>
)
}
LayoutAuthenticateRedirectPage.getLayout = (page) => (
<AuthenticateRedirectLayout>{page}</AuthenticateRedirectLayout>
)
export default LayoutAuthenticateRedirectPage

View File

@@ -0,0 +1,38 @@
import {useMutation, useQuery} from "@blitzjs/rpc"
import {BlitzPage} from "@blitzjs/next"
import AuthenticateLayout from "../layouts/AuthenticateLayout"
import logout from "../mutations/logout"
import getAuthenticatedBasic from "../queries/getAuthenticatedBasic"
import {Suspense} from "react"
function Content() {
const [result] = useQuery(getAuthenticatedBasic, undefined)
const [logoutMutation] = useMutation(logout)
return (
<div>
<div id="content">{result}</div>
<button
id="logout"
onClick={async () => {
await logoutMutation()
}}
>
logout
</button>
</div>
)
}
const LayoutAuthenticatePage: BlitzPage = () => {
return (
<div id="page">
<Suspense fallback={"Loading..."}>
<Content />
</Suspense>
</div>
)
}
LayoutAuthenticatePage.getLayout = (page) => <AuthenticateLayout>{page}</AuthenticateLayout>
export default LayoutAuthenticatePage

View File

@@ -0,0 +1,10 @@
import {BlitzPage} from "@blitzjs/next"
import RedirectAuthenticatedLayout from "../layouts/RedirectAuthenticatedLayout"
const LayoutRedirectAuthenticatedPage: BlitzPage = () => <div id="page-container">Hello World</div>
LayoutRedirectAuthenticatedPage.getLayout = (page) => (
<RedirectAuthenticatedLayout>{page}</RedirectAuthenticatedLayout>
)
export default LayoutRedirectAuthenticatedPage

View File

@@ -0,0 +1,15 @@
import {BlitzPage} from "@blitzjs/next"
import AuthenticateLayout from "../layouts/AuthenticateLayout"
const LayoutUnauthenticatePage: BlitzPage = () => {
return (
<div id="page">
<p id="content">this should be rendered</p>
</div>
)
}
LayoutUnauthenticatePage.getLayout = (page) => <AuthenticateLayout>{page}</AuthenticateLayout>
LayoutUnauthenticatePage.authenticate = false
export default LayoutUnauthenticatePage

View File

@@ -0,0 +1,62 @@
import {useRouter} from "next/router"
import {useMutation, useQuery} from "@blitzjs/rpc"
import login from "../mutations/login"
import logout from "../mutations/logout"
import getCurrentUser from "../queries/getCurrentUser"
import {Suspense, useState} from "react"
function Content() {
const router = useRouter()
const [error, setError] = useState(null)
const [userId] = useQuery(getCurrentUser, null)
const [loginMutation] = useMutation(login)
const [logoutMutation] = useMutation(logout)
if (error) return <div id="error">{error}</div>
return (
<div>
<div id="content">{userId ? "logged-in" : "logged-out"}</div>
{userId ? (
<button
id="logout"
onClick={async () => {
try {
await logoutMutation()
} catch (error: any) {
setError(error.toString())
}
}}
>
logout
</button>
) : (
<button
id="login"
onClick={async () => {
await loginMutation()
const next = router.query.next ? decodeURIComponent(router.query.next as string) : null
if (next) {
await router.push(next)
}
}}
>
login
</button>
)}
</div>
)
}
function Login() {
return (
<div id="page">
<Suspense fallback="Loading...">
<Content />
</Suspense>
</div>
)
}
export default Login

View File

@@ -0,0 +1,20 @@
import {useQuery} from "@blitzjs/rpc"
import getNoauthBasic from "../queries/getNoauthBasic"
import {Suspense} from "react"
function Content() {
const [result] = useQuery(getNoauthBasic, undefined)
return <div id="content">{result}</div>
}
function NoAuthQuery() {
return (
<div id="page">
<Suspense fallback={"Loading..."}>
<Content />
</Suspense>
</div>
)
}
export default NoAuthQuery

View File

@@ -0,0 +1,37 @@
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] = useQuery(getAuthenticatedBasic, undefined)
const [logoutMutation] = useMutation(logout)
return (
<div>
<div id="content">{result}</div>
<button
id="logout"
onClick={async () => {
await logoutMutation()
}}
>
logout
</button>
</div>
)
}
const AuthLogout: BlitzPage = () => {
return (
<div id="page">
<Suspense fallback={"Loading..."}>
<Content />
</Suspense>
</div>
)
}
AuthLogout.authenticate = {redirectTo: "/login"}
export default AuthLogout

View File

@@ -0,0 +1,37 @@
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] = useQuery(getAuthenticatedBasic, undefined)
const [logoutMutation] = useMutation(logout)
return (
<div>
<div id="content">{result}</div>
<button
id="logout"
onClick={async () => {
await logoutMutation()
}}
>
logout
</button>
</div>
)
}
const AuthRedirect: BlitzPage = () => {
return (
<div id="page">
<Suspense fallback={"Loading redirect page..."}>
<Content />
</Suspense>
</div>
)
}
AuthRedirect.authenticate = {redirectTo: "/login"}
export default AuthRedirect

View File

@@ -0,0 +1,37 @@
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] = useQuery(getAuthenticatedBasic, undefined)
const [logoutMutation] = useMutation(logout)
return (
<div>
<div id="content">{result}</div>
<button
id="logout"
onClick={async () => {
await logoutMutation()
}}
>
logout
</button>
</div>
)
}
const Authenticate: BlitzPage = () => {
return (
<div id="page">
<Suspense fallback={"Loading..."}>
<Content />
</Suspense>
</div>
)
}
Authenticate.authenticate = true
export default Authenticate

View File

@@ -0,0 +1,43 @@
import {gSSP} from "../blitz-server"
import {GetServerSidePropsContext} from "next"
import {dehydrate, getQueryClient, getQueryKey, QueryClient, useQuery} from "@blitzjs/rpc"
import getNoauthBasic from "../queries/getNoauthBasic"
import {Suspense} from "react"
import {SessionContext} from "@blitzjs/auth"
function Content() {
const [result] = useQuery(getNoauthBasic, null, {
staleTime: 60 * 1000,
})
return <div id="content">{result}</div>
}
function Bomb() {
return <div id="content">somebody set up us the bomb</div>
}
export default function Page() {
return (
<div id="page">
<Suspense fallback={<Bomb />}>
<Content />
</Suspense>
</div>
)
}
type Props = {
dehydratedState: any
}
export const getServerSideProps = gSSP<Props>(async ({ctx}) => {
await getQueryClient().prefetchQuery(getQueryKey(getNoauthBasic, null), () =>
getNoauthBasic(null, ctx),
)
return {
props: {
dehydratedState: dehydrate(queryClient),
},
}
})

View File

@@ -0,0 +1,7 @@
function RedirectAuthenticated() {
return <div id="page-container">Hello World</div>
}
RedirectAuthenticated.redirectAuthenticatedTo = "/authenticated-query"
export default RedirectAuthenticated

View File

@@ -0,0 +1,39 @@
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] = useQuery(getPublicDataForUser, {userId: 1})
return (
<div id="session">
<>
<div className="userId">userId: {publicData.userId}</div>
<div className="role">role: {publicData.role}</div>
</>
</div>
)
}
function SetPublicData() {
const [changeRoleMutation] = useMutation(changeRole)
return (
<div id="page">
<button
id="change-role"
onClick={async () => {
await changeRoleMutation({userId: 1, role: "new role"})
await invalidateQuery(getPublicDataForUser)
}}
>
Set new role for user
</button>
<Suspense fallback="">
<Content />
</Suspense>
</div>
)
}
export default SetPublicData

View File

@@ -0,0 +1,8 @@
import {Ctx} from "blitz"
import delay from "delay"
export default async function getAuthenticatedBasic(_: any, ctx: Ctx) {
await delay(10)
ctx.session.$authorize()
return "authenticated-basic-result"
}

View File

@@ -0,0 +1,7 @@
import {Ctx} from "blitz"
import delay from "delay"
export default async function getNoauthBasic(_: any, ctx: Ctx) {
await delay(10)
return ctx.session.userId
}

View File

@@ -0,0 +1,7 @@
import {Ctx} from "blitz"
import delay from "delay"
export default async function getNoauthBasic(_: any, ctx: Ctx) {
await delay(10)
return "noauth-basic-result"
}

View File

@@ -0,0 +1,10 @@
import {Ctx} from "blitz"
import db from "../../db"
export default async function getPublicDataForUser({userId}: any, ctx: Ctx) {
const role = ctx.session.role
return {
userId,
role,
}
}

View File

@@ -0,0 +1,291 @@
import {describe, it, expect, beforeAll, afterAll} from "vitest"
import {
killApp,
findPort,
runBlitzCommand,
blitzLaunchApp,
blitzBuild,
blitzStart,
waitFor,
} from "../../utils/next-test-utils"
import webdriver from "../../utils/next-webdriver"
let app: any
let appPort: number
const runTests = () => {
describe("Auth", () => {
describe("custom plugin", () => {
it("custom plugin - events", async () => {
const browser = await webdriver(appPort, "/custom-plugin")
let text = await browser.elementByCss("#page").text()
await waitFor(250)
text = await browser.elementByCss("#page").text()
expect(text).toBe("Custom plugin Session Created")
await waitFor(2000)
text = await browser.elementByCss("#page").text()
expect(text).toBe("Custom plugin RPC Error")
if (browser) {
await browser.close()
}
})
it("custom plugin - middleware", async () => {
const browser = await webdriver(appPort, "/custom-plugin")
await waitFor(100)
let text = await browser.elementByCss("#before-req").text()
expect(text).toBe("customHeaderValue")
await waitFor(1000)
text = await browser.elementByCss("#before-res").text()
expect(text).toBe("55")
if (browser) {
await browser.close()
}
})
})
describe("unauthenticated", () => {
it("should render result for open query", async () => {
const browser = await webdriver(appPort, "/noauth-query")
let text = await browser.elementByCss("#page").text()
await browser.waitForElementByCss("#content")
text = await browser.elementByCss("#content").text()
expect(text).toMatch(/noauth-basic-result/)
if (browser) await browser.close()
})
it("should render error for protected query", async () => {
const browser = await webdriver(appPort, "/authenticated-query")
await browser.waitForElementByCss("#error")
let text = await browser.elementByCss("#error").text()
expect(text).toMatch(/AuthenticationError/)
if (browser) await browser.close()
})
it("should render error for protected page", async () => {
const browser = await webdriver(appPort, "/page-dot-authenticate")
await browser.waitForElementByCss("#error")
let text = await browser.elementByCss("#error").text()
expect(text).toMatch(/AuthenticationError/)
if (browser) await browser.close()
})
it("should render error for protected layout", async () => {
const browser = await webdriver(appPort, "/layout-authenticate")
await browser.waitForElementByCss("#error")
let text = await browser.elementByCss("#error").text()
expect(text).toMatch(/AuthenticationError/)
if (browser) await browser.close()
})
it("should render Page.authenticate = false even when Layout.authenticate = true", async () => {
const browser = await webdriver(appPort, "/layout-unauthenticate")
await browser.waitForElementByCss("#content")
let text = await browser.elementByCss("#content").text()
expect(text).toMatch(/this should be rendered/)
if (browser) await browser.close()
})
})
describe("authenticated", () => {
it("should login and out successfully", async () => {
const browser = await webdriver(appPort, "/login")
await browser.waitForElementByCss("#content")
let text = await browser.elementByCss("#content").text()
expect(text).toMatch(/logged-out/)
await browser.elementByCss("#login").click()
await waitFor(200)
text = await browser.elementByCss("#content").text()
expect(text).toMatch(/logged-in/)
await browser.elementByCss("#logout").click()
await waitFor(250)
text = await browser.elementByCss("#content").text()
expect(text).toMatch(/logged-out/)
if (browser) await browser.close()
})
it("should logout without infinite loop #2233", async () => {
// Login
let browser = await webdriver(appPort, "/login")
await waitFor(200)
await browser.elementByCss("#login").click()
await waitFor(200)
await browser.eval(`window.location = "/authenticated-query"`)
await browser.waitForElementByCss("#content")
let text = await browser.elementByCss("#content").text()
expect(text).toMatch(/authenticated-basic-result/)
await browser.elementByCss("#logout").click()
await waitFor(200)
await browser.waitForElementByCss("#error")
text = await browser.elementByCss("#error").text()
expect(text).toMatch(/AuthenticationError/)
if (browser) await browser.close()
})
it("Page.authenticate = {redirect} should work ", async () => {
// Login
let browser = await webdriver(appPort, "/login")
await waitFor(200)
await browser.elementByCss("#login").click()
await waitFor(200)
await browser.eval(`window.location = "/page-dot-authenticate-redirect"`)
await browser.waitForElementByCss("#content")
let text = await browser.elementByCss("#content").text()
expect(text).toMatch(/authenticated-basic-result/)
await browser.elementByCss("#logout").click()
await waitFor(500)
expect(await browser.url()).toMatch(/\/login/)
if (browser) await browser.close()
})
it("Layout.authenticate = {redirect} should work ", async () => {
// Login
let browser = await webdriver(appPort, "/login")
await waitFor(200)
await browser.elementByCss("#login").click()
await waitFor(200)
await browser.eval(`window.location = "/layout-authenticate-redirect"`)
await browser.waitForElementByCss("#content")
let text = await browser.elementByCss("#content").text()
expect(text).toMatch(/authenticated-basic-result/)
await browser.elementByCss("#logout").click()
await waitFor(500)
expect(await browser.url()).toMatch(/\/login/)
if (browser) await browser.close()
})
})
describe("prefetching", () => {
it("should prefetch from the query cache #2281", async () => {
const browser = await webdriver(appPort, "/prefetching")
await waitFor(100)
await browser.waitForElementByCss("#content")
const text = await browser.elementByCss("#content").text()
expect(text).toMatch(/noauth-basic-result/)
if (browser) await browser.close()
})
})
describe("setting public data for a user", () => {
it("should update all sessions of the user", async () => {
// Ensure logged out
const browser = await webdriver(appPort, "/login")
await waitFor(200)
let text = await browser.elementByCss("#content").text()
if (text.match(/logged-in/)) {
await browser.elementByCss("#logout").click()
await waitFor(200)
}
await browser.eval(`window.location = "/set-public-data"`)
await browser.waitForElementByCss("#change-role")
await browser.elementByCss("#change-role").click()
await waitFor(500)
await browser.waitForElementByCss(".role")
text = await browser.elementByCss(".role").text()
expect(text).toMatch(/role: new role/)
if (browser) await browser.close()
})
})
describe("Page.redirectAuthenticatedTo", () => {
it("should work when redirecting to page with useQuery", async () => {
// https://github.com/blitz-js/legacy-framework/issues/2527
// Ensure logged in
const browser = await webdriver(appPort, "/login")
await waitFor(200)
let text = await browser.elementByCss("#content").text()
if (text.match(/logged-out/)) {
await browser.elementByCss("#login").click()
await waitFor(200)
}
await browser.eval(`window.location = "/redirect-authenticated"`)
await browser.waitForElementByCss("#content")
text = await browser.elementByCss("#content").text()
expect(text).toMatch(/authenticated-basic-result/)
if (browser) await browser.close()
})
})
describe("Layout.redirectAuthenticatedTo", () => {
it("should work when redirecting to page with useQuery", async () => {
// https://github.com/blitz-js/legacy-framework/issues/2527
// Ensure logged in
const browser = await webdriver(appPort, "/login")
await waitFor(200)
let text = await browser.elementByCss("#content").text()
if (text.match(/logged-out/)) {
await browser.elementByCss("#login").click()
await waitFor(200)
}
await browser.eval(`window.location = "/layout-redirect-authenticated"`)
await browser.waitForElementByCss("#content")
text = await browser.elementByCss("#content").text()
expect(text).toMatch(/authenticated-basic-result/)
if (browser) await browser.close()
})
})
describe("setPublicData", () => {
it("it should not throw CSRF error", async () => {
// https://github.com/blitz-js/legacy-framework/issues/2448
// ensure logged out
const browser = await webdriver(appPort, "/login")
await waitFor(200)
let text = await browser.elementByCss("#content").text()
if (text.match(/logged-in/)) {
await browser.elementByCss("#logout").click()
await waitFor(200)
}
await browser.eval(`window.location = "/gssp-setpublicdata"`)
await browser.waitForElementByCss("#content")
text = await browser.elementByCss("#content").text()
expect(text).toMatch(/it works/)
if (browser) await browser.close()
})
})
})
}
describe("Auth Tests", () => {
describe("dev mode", () => {
beforeAll(async () => {
try {
await runBlitzCommand(["prisma", "migrate", "reset", "--force"])
appPort = await findPort()
app = await blitzLaunchApp(appPort, {cwd: process.cwd()})
} catch (error) {
console.log(error)
}
}, 5000 * 60 * 2)
afterAll(async () => await killApp(app))
runTests()
})
describe("server mode", () => {
beforeAll(async () => {
try {
await runBlitzCommand(["prisma", "generate"])
await runBlitzCommand(["prisma", "migrate", "deploy"])
await blitzBuild()
appPort = await findPort()
app = await blitzStart(appPort, {cwd: process.cwd()})
} catch (err) {
console.log(err)
}
}, 5000 * 60 * 2)
afterAll(async () => await killApp(app))
runTests()
})
})

View File

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

View File

@@ -0,0 +1,9 @@
/// <reference types="vitest" />
import {defineConfig} from "vitest/config"
export default defineConfig({
test: {
testTimeout: 100000,
hookTimeout: 100000,
},
})

View File

@@ -17,11 +17,11 @@
"prisma:studio": "prisma studio"
},
"dependencies": {
"@blitzjs/auth": "workspace:*",
"@blitzjs/config": "workspace:*",
"@blitzjs/next": "workspace:*",
"@blitzjs/auth": "workspace:2.0.0-beta.21",
"@blitzjs/config": "workspace:2.0.0-beta.21",
"@blitzjs/next": "workspace:2.0.0-beta.21",
"@prisma/client": "4.6.0",
"blitz": "workspace:2.0.0-beta.18",
"blitz": "workspace:2.0.0-beta.21",
"lowdb": "3.0.0",
"next": "12.2.5",
"prisma": "4.6.0",

View File

@@ -16,11 +16,11 @@
"schema": "db/schema.prisma"
},
"dependencies": {
"@blitzjs/auth": "workspace:*",
"@blitzjs/next": "workspace:*",
"@blitzjs/rpc": "workspace:*",
"@blitzjs/auth": "workspace:2.0.0-beta.21",
"@blitzjs/next": "workspace:2.0.0-beta.21",
"@blitzjs/rpc": "workspace:2.0.0-beta.21",
"@prisma/client": "4.6.0",
"blitz": "workspace:*",
"blitz": "workspace:2.0.0-beta.21",
"lowdb": "3.0.0",
"next": "12.2.5",
"prisma": "4.6.0",
@@ -28,7 +28,7 @@
"react-dom": "18.2.0"
},
"devDependencies": {
"@blitzjs/config": "workspace:*",
"@blitzjs/config": "workspace:2.0.0-beta.21",
"@next/bundle-analyzer": "12.0.8",
"@types/express": "4.17.13",
"@types/fs-extra": "9.0.13",

View File

@@ -11,10 +11,10 @@
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next"
},
"dependencies": {
"@blitzjs/config": "workspace:*",
"@blitzjs/next": "workspace:*",
"@blitzjs/rpc": "workspace:*",
"blitz": "workspace:*",
"@blitzjs/config": "workspace:2.0.0-beta.21",
"@blitzjs/next": "workspace:2.0.0-beta.21",
"@blitzjs/rpc": "workspace:2.0.0-beta.21",
"blitz": "workspace:2.0.0-beta.21",
"next": "12.2.5",
"react": "18.2.0",
"react-dom": "18.2.0"

View File

@@ -16,11 +16,11 @@
"prisma:studio": "prisma studio"
},
"dependencies": {
"@blitzjs/auth": "workspace:*",
"@blitzjs/next": "workspace:*",
"@blitzjs/rpc": "workspace:*",
"@blitzjs/auth": "workspace:2.0.0-beta.21",
"@blitzjs/next": "workspace:2.0.0-beta.21",
"@blitzjs/rpc": "workspace:2.0.0-beta.21",
"@prisma/client": "4.6.0",
"blitz": "workspace:*",
"blitz": "workspace:2.0.0-beta.21",
"lowdb": "3.0.0",
"next": "12.2.5",
"prisma": "4.6.0",
@@ -28,7 +28,7 @@
"react-dom": "18.2.0"
},
"devDependencies": {
"@blitzjs/config": "workspace:*",
"@blitzjs/config": "workspace:2.0.0-beta.21",
"@next/bundle-analyzer": "12.0.8",
"@types/express": "4.17.13",
"@types/fs-extra": "9.0.13",

View File

@@ -8,13 +8,13 @@
"clean": "rm -rf .turbo && rm -rf node_modules"
},
"dependencies": {
"@blitzjs/auth": "workspace:*",
"@blitzjs/config": "workspace:*",
"@blitzjs/next": "workspace:*",
"@blitzjs/rpc": "workspace:*",
"@blitzjs/auth": "workspace:2.0.0-beta.21",
"@blitzjs/config": "workspace:2.0.0-beta.21",
"@blitzjs/next": "workspace:2.0.0-beta.21",
"@blitzjs/rpc": "workspace:2.0.0-beta.21",
"@prisma/client": "4.6.0",
"@tanstack/react-query": "4.0.10",
"blitz": "workspace:*",
"blitz": "workspace:2.0.0-beta.21",
"next": "12.2.5",
"prisma": "4.6.0",
"react": "18.2.0",

View File

@@ -1,14 +1,8 @@
import {BlitzRpcPlugin} from "@blitzjs/rpc"
import {setupBlitzClient} from "@blitzjs/next"
import {AuthClientPlugin} from "@blitzjs/auth"
const {withBlitz} = setupBlitzClient({
plugins: [
AuthClientPlugin({
cookiePrefix: "react-query-utils-tests-cookie-prefix",
}),
BlitzRpcPlugin({}),
],
plugins: [BlitzRpcPlugin({})],
})
export {withBlitz}

View File

@@ -1,17 +1,9 @@
import {setupBlitzServer} from "@blitzjs/next"
import {AuthServerPlugin, PrismaStorage} from "@blitzjs/auth"
import {simpleRolesIsAuthorized} from "@blitzjs/auth"
import db from "../db"
import {BlitzLogger} from "blitz"
const {gSSP, gSP, api} = setupBlitzServer({
plugins: [
AuthServerPlugin({
cookiePrefix: "react-query-utils-tests-cookie-prefix",
storage: PrismaStorage(db),
isAuthorized: simpleRolesIsAuthorized,
}),
],
plugins: [],
logger: BlitzLogger({}),
})

View File

@@ -16,11 +16,10 @@
"schema": "db/schema.prisma"
},
"dependencies": {
"@blitzjs/auth": "workspace:*",
"@blitzjs/next": "workspace:*",
"@blitzjs/rpc": "workspace:*",
"@blitzjs/next": "workspace:2.0.0-beta.21",
"@blitzjs/rpc": "workspace:2.0.0-beta.21",
"@prisma/client": "4.6.0",
"blitz": "workspace:*",
"blitz": "workspace:2.0.0-beta.21",
"lowdb": "3.0.0",
"next": "12.2.5",
"prisma": "4.6.0",
@@ -28,7 +27,7 @@
"react-dom": "18.2.0"
},
"devDependencies": {
"@blitzjs/config": "workspace:*",
"@blitzjs/config": "workspace:2.0.0-beta.21",
"@next/bundle-analyzer": "12.0.8",
"@types/express": "4.17.13",
"@types/fs-extra": "9.0.13",

View File

@@ -0,0 +1,4 @@
export default async function setBasic(input, ctx) {
global.basic = input
return global.basic
}

View File

@@ -0,0 +1,12 @@
if (typeof window !== "undefined") {
throw new Error("This should not be loaded on the client")
}
export default async function getBasic() {
if (typeof window !== "undefined") {
throw new Error("This should not be loaded on the client")
}
global.basic ??= "basic-result"
return global.basic
}

View File

@@ -0,0 +1,3 @@
export default async function getBasic() {
return "nested-basic"
}

View File

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

View File

@@ -0,0 +1,7 @@
const {withBlitz} = require("@blitzjs/next")
module.exports = withBlitz({
blitz: {
resolverPath: "root",
includeRPCFolders: ["../no-suspense/app"],
},
})

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