1
0
mirror of synced 2026-02-04 12:08:33 -05:00

Compare commits

...

76 Commits

Author SHA1 Message Date
github-actions[bot]
5a64f1c39c Version Packages (beta) (#4135)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
2023-05-01 23:33:32 +05:30
Blitz.js Bot
fa30de4599 (meta) added @gjmoed as contributor 2023-05-01 13:39:26 -04:00
G.J. Moed
3d004dc415 Adjust codegen logic for suspense patch (#4138)
Co-authored-by: Brandon Bayer <b@bayer.ws>
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
2023-05-01 23:09:20 +05:30
Blitz.js Bot
08fbede75e (meta) added @dbrxnds as contributor 2023-05-01 12:30:21 -04:00
David
eda14fa8aa Add formatError property to Blitz server- & rpchandler setup (#4124)
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
2023-05-01 22:00:15 +05:30
Blitz.js Bot
7e0e0f984c (meta) added @nelsonmestevao as contributor 2023-04-19 14:27:42 -04:00
Nelson Estevão
d814c2d2d8 fix: add missing key prop to LabelSelectField (#4122)
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
2023-04-19 23:57:37 +05:30
Siddharth Suresh
29c2b029ac Fix: Add missing entry to expose next-auth adapter (#4133) 2023-04-19 23:45:39 +05:30
Siddharth Suresh
ed22706e5f fix (minor): Replace console.log with debug (#4132) 2023-04-19 23:44:46 +05:30
github-actions[bot]
3e8f04ed03 Version Packages (beta) (#4121)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
2023-04-10 19:24:42 +05:30
Siddharth Suresh
e82a79be50 Update the version of next in the new template from 13.2 to 13.3.0 (#4120)
Co-authored-by: Brandon Bayer <b@bayer.ws>
2023-04-10 18:45:54 +05:30
Blitz.js Bot
b1fdb63470 (meta) added @vitaliemiron as contributor 2023-04-07 12:46:27 -04:00
Vitalie
38d945a3fb fix: new app generated by blitz new causes Error: DYNAMIC_SERVER_USAGE (#4113)
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-04-07 16:46:22 +00:00
Blitz.js Bot
ac587b6ac3 (meta) added @maotora as contributor 2023-04-07 12:38:51 -04:00
Maotora ᕙ(⇀‸↼‶)ᕗ
c07a13eefb Fix blitz recipe paths (#3997)
Co-authored-by: Tobias <t@tobiasjordans.de>
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
2023-04-07 12:38:46 -04:00
github-actions[bot]
9f316d73f5 Version Packages (beta) (#4111)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
2023-04-03 19:26:36 +05:30
Siddharth Suresh
f84d77a425 Fix invoke type regression (#4110) 2023-04-03 08:49:55 +05:30
github-actions[bot]
f2da4f1516 Version Packages (beta) (#4083)
* Version Packages (beta)

* pnpm lock

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
2023-03-31 23:30:39 +05:30
Brandon Bayer
acc07ce943 Fix Next 13.2 compatibility (#4108)
* make everything work with next 13.2

* changeset

* update test

* fix test
2023-03-30 20:20:30 +00:00
Siddharth Suresh
ea7561b8ee feature: Multiple fields forms using templates during generation (#3869)
* initial port

* read custom template values from blitz-server

* fix unit tests

* add unit tests

* remove comments

* make db import generic

* fix blitz genrate not updating values

* cleanup

* fix parent generation in createMutation and components, and move existing pages when --parent is called

* cleanup

* Create silly-peas-work.md

* Update .changeset/silly-peas-work.md

* add types for codegen

* fix belongsTo not working

* fix pnpm-lock

* use latest blitz logging setup in generator

* show error when structure of codegen is incorrect using zod

* cleanup

* make prisma import generic

* update tests

* generic prisma to work on subsequent runs

* initial commit adding dropdown option when using belongTo and parent flag

* cleanup

* fix --parent flag

* fix type

* Update getUsers.ts

* fix duplicate

* update prop type to options for --parent or belongsTo option and add LabelSelectField

* update tests

* Update blitz-server.ts

* fix lock file and add react-final-form select component

* fix default bug for string values in #2863

* Update apps/toolkit-app/app/blitz-server.ts

* update to latest changes

* implement suggessions

* fix tests and remove custom log

* add required test and remove error if prisma does not exist

* remove error log if no prisma schema

* works without prisma

* move zod to devDeps

* fix zod version

* preWriteFile and postWriteFile hooks

* fix pnpm lock

* Update packages/generator/src/generators/template-builders/field-values-builder.ts

Co-authored-by: John Vandivier <vandivier_john@yahoo.com>

* initial revert changes to log and add better types

* minor fix

* minor fix

* Update main.yml

* fix playwright issue

* Update main.yml

* try agin

* fix env location

* fix path

* fix version

* try another way

* with deps

* fix version

* cleanup

* add new zod `datetime`

Co-authored-by: Tobias <tobias@fixmycity.de>

* pnpm lock

* update zod to 3.20.0 in generator

* update unit tests

* Create pr-release.yml

* add changeset pre exit to fix error

* update to latest

* fix syntax

* try again

* feature: Consolidate mutations schema to schemas.ts file (#4057)

* fix global install issue

* update the templates from suggestions

* merge the default and custom config

* fix custom codegen

* fix validations

* add partial type to codegen

* commit to rerun the action

---------

Co-authored-by: John Vandivier <vandivier_john@yahoo.com>
Co-authored-by: Tobias <tobias@fixmycity.de>
2023-03-29 23:34:00 +05:30
Blitz.js Bot
13639c5d1d (meta) added @jafarlihi as contributor 2023-03-29 09:49:53 -04:00
Hikmat Jafarli
afdc810d0b Fix LabeledTextField update on next-ui and chakra-ui recipes (#4106)
* Fix LabeledTextField update on next-ui and chakra-ui recipes

* Create empty-spiders-lay.md

---------

Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
2023-03-29 19:19:46 +05:30
Siddharth Suresh
37aeaa7fa2 feature: Nextjs 13 App Directory Utility Methods (#4103)
* working

* fix toolkit app

* fix add directive

* add back secure password

* changeset

* improve blitz rpc structure

* make it work

* fix most integration tests

* fix the tests

* fix import error

* fix unit test

* fix tests

* remove breaking changes

* remove another breaking change

* fix typescript declaration

* fix errorboundary redirect issues

* cleanup

* upgrade to next13

* update pnpm-lock

* add Server Plugin Export

* fix lint error

* fix build errors

* fixes

* Solve NextRouter is not mounted

* fix

* fix issues

* pnpm lock fix

* rename session function and add auth utility

* remove potential implicit warning

* fix deps and cleanup

* fix secure-password missing file

* fix possibility of crsf token cookie being null

* remove secure-password breaking changes

* Update cuddly-singers-perform.md

* rename functions and remove headers

* Revert "remove secure-password breaking changes"

This reverts commit abccf93d0c.

* unsupported auth methods in react server components

* remove authorizedContext: To be done in another PR

* add integration test for app dir

* fix duplicate package name

* Revert "remove authorizedContext: To be done in another PR"

This reverts commit 46fe8afab9.

* pnpm lock

* integration test

* remove empty then and add void operator

* add new invokeResolver function

* fix bug in useAuthenticatedBlitzContext

* Create .changeset/tall-radios-clean.md

* overload the invoke function for the new RSC usecase

* invoke works without implicit passing of arguments

* fix pnpm lock
2023-03-29 19:05:46 +05:30
Siddharth Suresh
cadefb88e4 feature: Next 13 App directory (#4079)
* working

* fix toolkit app

* fix add directive

* add back secure password

* changeset

* improve blitz rpc structure

* make it work

* fix most integration tests

* fix the tests

* fix import error

* fix unit test

* fix tests

* remove breaking changes

* remove another breaking change

* fix typescript declaration

* fix errorboundary redirect issues

* cleanup

* upgrade to next13

* update pnpm-lock

* add Server Plugin Export

* fix lint error

* fix build errors

* fixes

* Solve NextRouter is not mounted

* fix

* fix issues

* pnpm lock fix

* rename session function and add auth utility

* remove potential implicit warning

* fix deps and cleanup

* fix secure-password missing file

* fix possibility of crsf token cookie being null

* remove secure-password breaking changes

* Update cuddly-singers-perform.md

* rename functions and remove headers

* Revert "remove secure-password breaking changes"

This reverts commit abccf93d0c.

* unsupported auth methods in react server components

* remove authorizedContext: To be done in another PR

* add integration test for app dir

* fix duplicate package name

* integration test

* remove empty then and add void operator

* fix pnpm lock
2023-03-24 11:10:36 +05:30
Siddharth Suresh
6f18cbdc98 feature: Next Auth Adapter (#4046)
* initial working

* add user side callback control

* connect to blitz-auth

* better error handling

* initial working after submodule

* Create fast-adults-guess.md

* add submodule init and update to workflow

* remove internal folder

* cleanup

* ignore tests from next-auth

* add redirectUrl config and maintin consistency

* move required files back to internals folder

* remove submodule cloning

* Patch NextAuth

another time

fix import issue

fix import

add path imports for the adapters

Revert "add to blitz-auth"

This reverts commit 246e62faa5a451aad9f4a2530a159ca3457b8b75.

add to blitz-auth

pnpm lock fix

cleanup

fix codegen

remove nextauth submodule and internal folder and patch nextauth

* Revert "Patch NextAuth"

This reverts commit 31888fc643.

* switch

* DRY

* optional peerDependency

* Delete .gitmodules

* make it work with webpack alias

* fix

* split to new path

* undo unnecessary changes

* more fixes

* add strong typing to nextauth adapter (#4104)

* add strong typing to nextauth adapter

* cleanup

---------

Co-authored-by: Brandon Bayer <b@bayer.ws>
2023-03-24 09:07:11 +05:30
Blitz.js Bot
3480d90098 (meta) added @jeliasson as contributor 2023-03-21 04:18:29 -04:00
Siddharth Suresh
9529dbd6f4 Make secure password completely optional (#4085)
* secure-password breaking changes

* fix

* more fixes

* fix secure-password imports

* add codemod

* add secure-password to auth integration test

* Apply suggestions from code review

* try adding playwrigth to package.json

* without server mode

* add one to fix conficting ports

* another try

* add waitPort in the right place

* use same port

* manually kill the process

* remove the server mode

* cleanup
2023-03-18 16:48:08 +05:30
Blitz.js Bot
f443118b9d (meta) added @exKAZUu as contributor 2023-02-16 12:17:01 -05:00
Sakamoto, Kazunori
e228ba5dee fix: type error in reset-password.tsx (#4081) 2023-02-17 00:16:55 +07:00
Tobias
430f0b52dd Update to "prisma": "4.6.1" (#4062)
Co-authored-by: Brandon Bayer <b@bayer.ws>
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
2023-02-13 18:47:50 +05:30
Marcus Reinhardt
6e88a847fe fix: vulnerabilities in @blitz/auth (#4082)
* fix vulnerabilities

* Update .changeset/strong-chicken-study.md

---------

Co-authored-by: Brandon Bayer <b@bayer.ws>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-02-13 10:20:10 +00:00
Brandon Bayer
1db963a8ca update readme 2023-02-13 17:12:26 +07:00
github-actions[bot]
6374f2ff0c Version Packages (beta) (#4055)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
2023-02-09 21:44:34 +05:30
Tobias
6ec020c6d6 Remove useEffect from reset password templates (#4051)
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
Co-authored-by: Brandon Bayer <b@bayer.ws>
2023-02-09 11:19:10 +05:30
Blitz.js Bot
a3d8b287f1 (meta) added @sweetliquid as contributor 2023-02-07 03:24:20 -05:00
sweetliquid
4ed1fc1233 docs: delete duplicates of the in comments (#4073)
Co-authored-by: Brandon Bayer <b@bayer.ws>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-02-07 08:24:14 +00:00
Siddharth Suresh
3fa3c70b39 internal: Readme for the packages (#4052) 2023-02-07 15:14:58 +07:00
Blitz.js Bot
a9b1989bb0 (meta) added @jhonnymichel as contributor 2023-02-06 10:47:34 -05:00
Jhonny Michel
c3c789740a Fixing tests for blitz apps that use vitest (#4072)
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
Closes https://github.com/blitz-js/blitz/issues/4065
2023-02-06 21:17:28 +05:30
Siddharth Suresh
42a2cf951a Add secure-password as an Optional peerDependency (#4067)
Co-authored-by: Brandon Bayer <b@bayer.ws>
2023-02-06 19:11:42 +05:30
Tobias
d316d0db7f Next 13: Remove anchor tags from Link component (#4071)
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
Closes https://github.com/blitz-js/blitz/issues/4066
2023-02-06 18:52:49 +05:30
Siddharth Suresh
a8ce2325fc Fix max-width of body in new app template (#4068)
Co-authored-by: Brandon Bayer <b@bayer.ws>
2023-01-27 20:41:15 +05:30
Blitz.js Bot
f58a0e42f7 (meta) updated @tordans contributions 2023-01-26 05:23:14 -05:00
Tobias
cb63a0ea5b Guard blitz generate input against unwanted characters (#4024)
Co-authored-by: Dillon Raphael <dillon@creatorsneverdie.com>
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
Closes https://github.com/blitz-js/blitz/issues/4021
2023-01-26 15:53:08 +05:30
Siddharth Suresh
a78bd33706 internal: Publish PRs to npm (#4050) 2023-01-14 20:39:16 +05:30
bravo-kernel
79c5e86d71 Add missing Layout.tsx for generated mimimalapp (#4054) 2023-01-13 17:28:53 -05:00
github-actions[bot]
21b83fb7bf Version Packages (beta) (#4038)
* Version Packages (beta)

* pnpm lock

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
2023-01-12 10:43:33 +05:30
Tobias
14882d43fe Update package Zod to 3.20.2 (#4039)
* Update package zod to 3.20.2

* `pnpm changeset` Update zod to 3.20.2 (was 3.19.1).

Co-authored-by: Brandon Bayer <b@bayer.ws>
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
2023-01-11 11:32:02 +05:30
Tobias
989691ec87 Use src instead of app folder for blitz generate custom-template (#4033)
* Use src instead of app in `customTemplates: "src/templates"`

* Use src instead of app in `cli/commands/generate`

* Add changeset

* remove ignored packages

Co-authored-by: Brandon Bayer <b@bayer.ws>
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
2023-01-11 05:25:57 +00:00
Brandon Bayer
2703618868 change rpc route basepath includeRPC in monorepos to be one folder up (#4045)
* change rpc route basepath includeRPC in monorepos to be one folder up

* changeset

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-01-11 00:13:11 +00:00
Blitz.js Bot
44ddf5b423 (meta) updated @bravo-kernel contributions 2023-01-10 19:06:15 -05:00
bravo-kernel
bcef81fadc Add missing MockRouter prop in generated test utils (#4043)
Co-authored-by: Brandon Bayer <b@bayer.ws>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2023-01-10 19:06:10 -05:00
Dillon Raphael
7abfb9086a Redesign the index page for newly generated blitz projects (#3987)
* redesign index page for full app template

* pnpmlock

* iteration 2

* Add padding around blitz logo

* Fix more padding

* update padding for logo and button container

* increase max-width

* final draft

* address comments

Co-authored-by: Brandon Bayer <b@bayer.ws>
2023-01-11 00:04:54 +00:00
Siddharth Suresh
57101e9adf internal: fix playwright installation error by fixing version (#4047) 2023-01-10 18:57:30 -05:00
Siddharth Suresh
497b87f7fb internal: Fix playwright install issue (#4044) 2023-01-10 00:02:44 +05:30
Tobias
64a98e201d prisma/field: Guard TS warning (#4032)
The previous solution did solve the if-statement but not the line below, which still had this TS error:

```
      const relationType = Relation[_fieldName]
// ^- const _fieldName: string | undefined
//    Type 'undefined' cannot be used as an index type.ts(2538)
```

Co-authored-by: Dillon Raphael <dillon@creatorsneverdie.com>
Co-authored-by: Siddharth Suresh <siddh.suresh@gmail.com>
2023-01-09 22:08:30 +05:30
Brandon Bayer
8aa22a0b2f add currentPassword to default masked fields in the logger (#4042) 2023-01-06 17:55:07 -05:00
Brandon Bayer
145d5a02b3 fix failed localstorage access to not crash the application (#4037) 2023-01-04 18:28:31 -05:00
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
400 changed files with 11026 additions and 2628 deletions

View File

@@ -2941,7 +2941,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/230500?v=4",
"profile": "https://github.com/bravo-kernel",
"contributions": [
"code"
"code",
"doc"
]
},
{
@@ -3775,6 +3776,147 @@
"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",
"test"
]
},
{
"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"
]
},
{
"login": "jhonnymichel",
"name": "Jhonny Michel",
"avatar_url": "https://avatars.githubusercontent.com/u/7006387?v=4",
"profile": "https://github.com/jhonnymichel",
"contributions": [
"doc",
"code",
"test"
]
},
{
"login": "sweetliquid",
"name": "sweetliquid",
"avatar_url": "https://avatars.githubusercontent.com/u/18693190?v=4",
"profile": "sweetliquid.me",
"contributions": [
"code"
]
},
{
"login": "exKAZUu",
"name": "Sakamoto, Kazunori",
"avatar_url": "https://avatars.githubusercontent.com/u/436237?v=4",
"profile": "https://github.com/exKAZUu",
"contributions": [
"doc",
"code"
]
},
{
"login": "jeliasson",
"name": "Johan Eliasson",
"avatar_url": "https://avatars.githubusercontent.com/u/865493?v=4",
"profile": "https://github.com/jeliasson",
"contributions": [
"doc"
]
},
{
"login": "jafarlihi",
"name": "Hikmat Jafarli",
"avatar_url": "https://avatars.githubusercontent.com/u/43515211?v=4",
"profile": "https://github.com/jafarlihi",
"contributions": [
"doc",
"code"
]
},
{
"login": "maotora",
"name": "Maotora ᕙ(⇀‸↼‶)ᕗ",
"avatar_url": "https://avatars.githubusercontent.com/u/5174884?v=4",
"profile": "https://maotoramm.com",
"contributions": [
"doc",
"code"
]
},
{
"login": "vitaliemiron",
"name": "Vitalie",
"avatar_url": "https://avatars.githubusercontent.com/u/45145592?v=4",
"profile": "https://github.com/vitaliemiron",
"contributions": [
"doc",
"code"
]
},
{
"login": "nelsonmestevao",
"name": "Nelson Estevão",
"avatar_url": "https://avatars.githubusercontent.com/u/19409687?v=4",
"profile": "https://estevao.org",
"contributions": [
"doc",
"code"
]
},
{
"login": "dbrxnds",
"name": "David",
"avatar_url": "https://avatars.githubusercontent.com/u/32268383?v=4",
"profile": "https://github.com/dbrxnds",
"contributions": [
"doc",
"code",
"test"
]
},
{
"login": "gjmoed",
"name": "G.J. Moed",
"avatar_url": "https://avatars.githubusercontent.com/u/4458993?v=4",
"profile": "https://github.com/gjmoed",
"contributions": [
"doc",
"code"
]
}
],
"contributorsPerLine": 7,

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/generator": patch
---
Guard `blitz g` input via an allow-list of characters; throw if unwanted characters are found. Prevents to break the blitz command by accident (https://github.com/blitz-js/blitz/issues/4021).

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/generator": patch
---
Fix a type error in reset password templates.

View File

@@ -0,0 +1,6 @@
---
"@blitzjs/next": minor
"@blitzjs/rpc": minor
---
Add ability to format the error on the server before returning it to the client.

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,5 @@
---
"@blitzjs/rpc": minor
---
change rpc route basepath to be one folder higher when using includeRPC in monorepos

View File

@@ -0,0 +1,11 @@
---
"blitz": minor
"@blitzjs/auth": minor
"@blitzjs/next": minor
"@blitzjs/rpc": minor
---
- New Blitz Auth Function `getAppSession`, This function will use the cookies and headers provided by the server component and returns the current session.
- New Blitz Auth Hook `useAuthenticatedAppSession`, This hook is implemented as the replacement of the BlitzPage seurity auth utilities provided for the pages directory to work with React Server Components in the Nextjs 13 app directory
- New Blitz React Server Component Wrapper, `BlitzProvider` is to be imported from setupBlitzClient in src/blitz-client.ts and to used to ideally wrap the entire application in the `RootLayout` in the root layout.ts file of next app directory.
- Fix failing tests due to the error `NextRouter is not mounted` in next 13 blitz apps

View File

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

View File

@@ -0,0 +1,6 @@
---
"@blitzjs/recipe-chakra-ui": patch
"@blitzjs/recipe-next-ui": patch
---
Fix LabeledTextField update on next-ui and chakra-ui recipes

View File

@@ -0,0 +1,6 @@
---
"@blitzjs/auth": minor
"blitz": minor
---
feature: Next Auth Adapter

View File

@@ -0,0 +1,7 @@
---
"@blitzjs/next": minor
---
Fix Next 13.2 compatibility
This updates the suspense patch to work with Next.js 13.2+. Hopefully soon we can stop patching once Next.js catches up with all the other frameworks and properly [exposes the `onRecoverableError` react hook](https://github.com/vercel/next.js/discussions/36641).

View File

@@ -0,0 +1,6 @@
---
"blitz": patch
"@blitzjs/generator": patch
---
Consolidate mutations schema to new schema.{ts|js} file.

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,20 @@
---
"@blitzjs/auth": major
"@blitzjs/codemod": minor
---
## ⚠️ Breaking Changes for Blitz Auth
Automatically upgrade using codemod
(Make sure to git commit before running this command to avoid losing changes)
```bash
npx @blitz/codemod secure-password
```
Introduce a new import path for the Blitz wrapper `SecurePassword` to fully decouple the library from `@blitzjs/auth`
```diff
- import {SecurePassword} from "@blitzjs/auth"
+ import {SecurePassword} from "@blitzjs/auth/secure-password"
```

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/next": minor
---
Fix the DYNAMIC_SERVER_USAGE error for Next.js 13.3.1+

View File

@@ -0,0 +1,5 @@
---
"toolkit-app": patch
---
Update zod to 3.20.2 (was 3.19.1).

View File

@@ -0,0 +1,5 @@
---
"blitz": patch
---
Use `src` instead of `app` folder for `blitz generate custom-template`

View File

@@ -0,0 +1,7 @@
---
"@blitzjs/recipe-chakra-ui": patch
"@blitzjs/recipe-next-ui": patch
"@blitzjs/recipe-tailwind": patch
---
This change reflects the directory change from app/pages to src/pages for the receipts chakra-ui, next-ui, tailwind. It checks for which directories exists and is compatible with either versions.

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/generator": patch
---
For new applications, update Prisma (`prisma` and `@prisma/client`) from `4.6.0` to `4.6.1` to solve enum issue with postgresql https://github.com/prisma/prisma/issues/16180

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/rpc": patch
---
Fix return type of the `invoke` method from returning type function to return the type of resolved data

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/generator": patch
---
fix: add missing key prop to LabelSelectField

View File

@@ -0,0 +1,9 @@
---
"@blitzjs/auth": patch
"@blitzjs/next": patch
"@blitzjs/rpc": patch
"blitz": patch
"@blitzjs/generator": patch
---
Update the version of next in the new template from 13.2 to 13.3.0

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/generator": patch
---
Remove useEffect from reset password templates.

View File

@@ -0,0 +1,5 @@
---
"blitz": patch
---
The issue is that the version provided, "13.2", is not a valid SemVer version. A valid SemVer version must have three components: major, minor, and patch (e.g., "13.2.0").

View File

@@ -0,0 +1,6 @@
---
"blitz": patch
"@blitzjs/rpc": patch
---
Updates internal functions and tests to support blitz apps that run tests with vitest

View File

@@ -46,11 +46,14 @@
"@blitzjs/recipe-theme-ui": "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"
"test-full-auth-with-rpc": "0.0.0",
"next-blitz-auth": "0.1.0",
"test-app-dir": "0.0.0"
},
"changesets": [
"afraid-dancers-juggle",
"afraid-ears-repair",
"big-boats-lay",
"big-phones-bow",
"blue-flowers-peel",
"blue-pigs-tan",
@@ -66,14 +69,19 @@
"calm-nails-wait",
"calm-papayas-protect",
"calm-tomatoes-drive",
"chatty-fireants-leave",
"chatty-gifts-whisper",
"chilled-carrots-own",
"chilly-candles-care",
"chilly-nails-nail",
"clean-hats-pump",
"clean-hounds-laugh",
"clean-walls-wink",
"clever-radios-lie",
"cool-doors-invent",
"cool-horses-check",
"cuddly-pugs-crash",
"cuddly-singers-perform",
"curly-rules-speak",
"curly-seas-serve",
"curvy-days-attend",
@@ -81,30 +89,38 @@
"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",
"empty-pants-search",
"empty-spiders-lay",
"empty-turkeys-wave",
"fair-carrots-guess",
"fair-kangaroos-clean",
"fair-wombats-sneeze",
"famous-kings-explain",
"fast-adults-guess",
"fast-clocks-push",
"fast-pans-impress",
"fast-papayas-grow",
"fast-toys-wash",
"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",
"four-brooms-juggle",
"four-meals-fry",
"four-radios-tickle",
"four-sheep-judge",
"fresh-crews-chew",
"funny-cups-pay",
"fuzzy-bees-warn",
"fuzzy-dots-cross",
@@ -113,6 +129,7 @@
"gentle-lions-explode",
"giant-mails-tap",
"giant-students-carry",
"giant-timers-search",
"gold-horses-punch",
"good-apes-drum",
"good-insects-wink",
@@ -150,6 +167,7 @@
"lemon-games-press",
"lemon-pillows-switch",
"lemon-seas-push",
"lemon-teachers-jam",
"light-donkeys-double",
"light-squids-draw",
"little-pears-ring",
@@ -162,6 +180,8 @@
"lucky-cows-try",
"lucky-months-guess",
"lucky-years-turn",
"many-fans-fetch",
"mean-ears-speak",
"mean-gorillas-reply",
"modern-cameras-pull",
"modern-games-dream",
@@ -174,12 +194,15 @@
"nervous-dolls-rule",
"new-coats-turn",
"new-olives-protect",
"nice-boxes-travel",
"nice-deers-dream",
"nice-starfishes-live",
"nine-bags-rhyme",
"nine-birds-confess",
"nine-onions-admire",
"ninety-lies-press",
"ninety-pets-heal",
"ninety-pots-learn",
"ninety-rice-tickle",
"odd-bears-run",
"olive-bees-buy",
@@ -189,9 +212,12 @@
"olive-sheep-rhyme",
"orange-mirrors-tap",
"orange-zebras-reflect",
"perfect-baboons-relate",
"perfect-eyes-repeat",
"perfect-trains-double",
"plenty-bottles-swim",
"plenty-gifts-provide",
"plenty-kiwis-greet",
"polite-lizards-love",
"poor-peas-lick",
"poor-penguins-look",
@@ -200,6 +226,7 @@
"popular-teachers-pay",
"pretty-games-march",
"purple-donkeys-smash",
"purple-jars-begin",
"purple-singers-greet",
"quick-cycles-confess",
"quick-dots-fetch",
@@ -224,6 +251,7 @@
"silent-colts-reply",
"silent-lies-run",
"silly-apricots-share",
"silly-peas-work",
"silly-shoes-agree",
"six-apricots-kick",
"slimy-humans-impress",
@@ -237,6 +265,7 @@
"smooth-stingrays-drum",
"smooth-tools-train",
"soft-adults-smell",
"soft-fans-carry",
"sour-lemons-hunt",
"sour-mails-lick",
"spicy-beds-float",
@@ -247,26 +276,36 @@
"stale-jobs-drum",
"stale-parents-yawn",
"strong-apes-reply",
"strong-chicken-study",
"strong-keys-lie",
"stupid-rabbits-jump",
"stupid-walls-sell",
"sweet-kiwis-cross",
"swift-drinks-dress",
"swift-glasses-laugh",
"swift-poets-travel",
"tall-meals-learn",
"tall-radios-clean",
"tame-keys-reply",
"tame-pumpkins-nail",
"tasty-maps-fetch",
"tasty-news-collect",
"tasty-squids-sin",
"ten-hairs-listen",
"ten-rivers-burn",
"tender-cooks-tie",
"tender-pianos-check",
"thick-moons-fry",
"thick-parrots-float",
"thick-peas-jog",
"thirty-countries-build",
"thirty-spies-applaud",
"three-lies-pull",
"three-toes-sell",
"tidy-clouds-smoke",
"tidy-llamas-compare",
"tough-toes-pull",
"tricky-kids-press",
"twelve-hornets-sip",
"twelve-lemons-smile",
"twelve-needles-worry",
@@ -286,6 +325,7 @@
"wicked-rings-walk",
"wise-eels-visit",
"wise-frogs-give",
"wise-lies-relate",
"wise-rabbits-complain",
"young-birds-talk"
]

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/generator": patch
---
Fix missing MockRouter prop in test utils

View File

@@ -0,0 +1,6 @@
---
"blitz": patch
"@blitzjs/generator": patch
---
Multiple fields forms using templates during generation - TODO

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/auth": minor
---
fix failed localStorage access to not crash the application

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/auth": patch
---
Fixed security vulnerabilities in passport-adapter by upgrading `passport` and `jsonwebtoken`

View File

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

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/generator": patch
---
Update all links to follow Next 13 format without a child anchor tag.

View File

@@ -0,0 +1,5 @@
---
"blitz": minor
---
add `currentPassword` to the default fields that are masked in the logger

View File

@@ -0,0 +1,67 @@
---
"@blitzjs/auth": patch
"@blitzjs/rpc": patch
"blitz": patch
---
feature: Nextjs 13 App Directory Utility Methods
### 🔧 New Blitz Auth Hook `useAuthenticatedBlitzContext`
This hook is implemented as the replacement of the [`BlitzPage` seurity auth utilities](https://blitzjs.com/docs/authorization#secure-your-pages) provided for the pages directory to work with React Server Components in the Nextjs 13 app directory
It can be used in any asynchronous server component be it in `page.ts` or in the layouts in `layout.ts`
It uses the new [`redirect` function](https://beta.nextjs.org/docs/api-reference/redirect) to provide the required authorization in server side
#### API
```ts
useAuthenticatedBlitzContext({
redirectTo,
redirectAuthenticatedTo,
role,
}: {
redirectTo?: string | RouteUrlObject
redirectAuthenticatedTo?: string | RouteUrlObject | ((ctx: Ctx) => string | RouteUrlObject)
role?: string | string[]
}): Promise<void>
```
#### Usage
**Example Usage in React Server Component in `app` directory in Next 13**
```ts
import {getAppSession, useAuthenticatedBlitzContext} from "src/blitz-server"
...
await useAuthenticatedBlitzContext({
redirectTo: "/auth/login",
role: ["admin"],
redirectAuthenticatedTo: "/dashboard",
})
```
### 🔧 New Blitz RPC Hook `invokeResolver`
#### API
```ts
invokeResolver<T extends (...args: any) => any, TInput = FirstParam<T>>(
queryFn: T,
params: TInput,
): Promise<PromiseReturnType<T>>
```
#### Example Usage
```ts
...
import {invokeResolver, useAuthenticatedBlitzContext} from "../src/blitz-server"
import getCurrentUser from "../src/users/queries/getCurrentUser"
export default async function Home() {
await useAuthenticatedBlitzContext({
redirectTo: "/auth/login",
})
const user = await invokeResolver(getCurrentUser, null)
...
```

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/generator": patch
---
Add missing Layout.tsx for generated mimimalapp

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,7 @@
---
"@blitzjs/auth": major
---
BREAKING CHANGE: secure-password is now an `optional peerDependency`, if you are using `SecurePassword` api, you need to now install `secure-password` in your application.
This helps users who do not use SecurePassword from having native package build issues.

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/generator": minor
---
Redesign the index page for newly generated blitz projects

View File

@@ -0,0 +1,5 @@
---
"@blitzjs/auth": patch
---
Fix: Add missing entry to expose next-auth adapter in Blitz Auth

4
.github/CODEOWNERS vendored
View File

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

View File

@@ -7,6 +7,9 @@ on:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
jobs:
lint:
@@ -140,8 +143,7 @@ jobs:
- name: Install playwright
run: |
npm i -g playwright
PLAYWRIGHT_BROWSERS_PATH=$HOME/pw-browsers npx playwright install
pnpx playwright@1.28.0 install --with-deps
shell: bash
- name: Build

101
.github/workflows/pr-release.yml vendored Normal file
View File

@@ -0,0 +1,101 @@
# https://github.com/withastro/astro/blob/main/.github/workflows/snapshot-release.yml
name: Create a Snapshot Release
on:
issue_comment:
types: [created]
defaults:
run:
shell: bash
jobs:
snapshot-release:
name: Create a snapshot release of a pull request
if: ${{ github.repository_owner == 'blitz-js' && github.event.issue.pull_request && startsWith(github.event.comment.body, '!preview') }}
runs-on: ubuntu-latest
steps:
- name: "Check if user has admin access (only admins can publish snapshot releases)."
uses: "lannonbr/repo-permission-check-action@2.0.0"
with:
permission: "admin"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: resolve pr refs
id: refs
uses: eficode/resolve-pr-refs@main
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v3
with:
ref: ${{ steps.refs.outputs.head_ref }}
- name: Setup PNPM
uses: pnpm/action-setup@v2.2.1
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 16
registry-url: 'https://registry.npmjs.org'
cache: 'pnpm'
- name: Short SHA
id: vars
run: echo "sha_short=$(git rev-parse --short "$GITHUB_SHA")" >> $GITHUB_OUTPUT
- name: Extract the snapshot name from comment body
id: getSnapshotName
uses: actions/github-script@v6
with:
script: |
const splitComment = context.payload.comment.body.split(' ');
if(splitComment.length !== 2) {
return "${{ steps.vars.outputs.sha_short }}";
}
return splitComment[1].trim();
result-encoding: string
- name: Install dependencies
run: pnpm install
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
- name: Build Packages
run: pnpm run build
- name: Bump Package Versions
id: changesets
run: |
pnpm changeset pre exit
pnpm changeset version --snapshot ${{ steps.getSnapshotName.outputs.result }} > changesets.output.txt 2>&1
echo ::set-output name=result::`cat changesets.output.txt`
env:
# Needs access to run the script
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Publish Release
id: publish
run: |
pnpm run release --tag next--${{ steps.getSnapshotName.outputs.result }} > publish.output.txt 2>&1
echo ::set-output name=result::`cat publish.output.txt`
env:
# Needs access to publish to npm
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Pull Request Notification
uses: actions/github-script@v6
env:
MESSAGE: ${{ steps.publish.outputs.result }}
with:
script: |
console.log(process.env.MESSAGE);
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '```\n' + process.env.MESSAGE + '\n```',
})

5
.kodiak.toml Normal file
View File

@@ -0,0 +1,5 @@
# .kodiak.toml
# Minimal config. version is the only required field.
version = 1
merge.automerge_label = "0 - <(^_^)> - merge it! ✌️"
approve.auto_approve_usernames = ["flybayer", "depfu"]

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-399-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-413-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">
@@ -135,7 +135,15 @@ Your financial contributions help ensure Blitz continues to be developed and mai
<table>
<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://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 /></td>
<td align="center">
<a href="https://siddharthsuresh.vercel.app/">
<img src="https://avatars.githubusercontent.com/u/83594610?v=4" width="100px;" alt="Siddharth Suresh avatar" /><br />
<sub>
<b>Siddharth Suresh</b>
</sub>
</a>
</td>
</tr>
</table>
@@ -155,7 +163,6 @@ _Code ownership, pull request approvals and merging, etc_ (see [Maintainers L2](
<tr>
<td align="center"><a href="http://simonknott.de"><img src="https://avatars1.githubusercontent.com/u/14912729?v=4" width="100px;" alt=""/><br /><sub><b>Simon Knott</b></sub></a><br />SuperJSON</td>
<td align="center"><a href="http://jins.dev"><img src="https://avatars.githubusercontent.com/u/39466936?v=4" width="100px;" alt=""/><br /><sub><b>JH.Lee</b></sub></a><br />SuperJSON</td>
<td align="center"><a href="https://juanm04.com"><img src="https://avatars0.githubusercontent.com/u/16712703?v=4" width="100px;" alt=""/><br /><sub><b>Juan Martín Seery</b></sub></a><br />Website/Docs</td>
</tr>
</table>
<!-- markdownlint-enable -->
@@ -173,38 +180,6 @@ _Issue triage, pull request triage, community encouragement and moderation, etc_
<table>
<tr>
<td align="center"><a href="http://jeremyliberman.com/"><img src="https://avatars3.githubusercontent.com/u/2754163?v=4" width="100px;" alt=""/><br /><sub><b>Jeremy Liberman</b></td>
<td align="center">
<a href="https://mina.ca">
<img src="https://avatars.githubusercontent.com/mabadir" width="100px;" alt="Mina Abadir avatar" /><br />
<sub>
<b>Mina Abadir</b>
</sub>
</a>
</td>
<td align="center">
<a href="https://builtforfifty.com">
<img src="https://avatars.githubusercontent.com/abuuzayr" width="100px;" alt="Abu Uzayr avatar" /><br />
<sub>
<b>Abu Uzayr</b>
</sub>
</a>
</td>
<td align="center">
<a href="https://damilolarandolph.com/">
<img src="https://avatars.githubusercontent.com/damilolarandolph" width="100px;" alt="Damilola Randolph avatar" /><br />
<sub>
<b>Damilola Randolph</b>
</sub>
</a>
</td>
<td align="center">
<a href="https://siddharthsuresh.vercel.app/">
<img src="https://avatars.githubusercontent.com/u/83594610?v=4" width="100px;" alt="Siddharth Suresh avatar" /><br />
<sub>
<b>Siddharth Suresh</b>
</sub>
</a>
</td>
</tr>
</table>
<!-- markdownlint-enable -->
@@ -620,7 +595,7 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<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>
<td align="center"><a href="http://2hr.me/"><img src="https://avatars.githubusercontent.com/u/4346154?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rabbi Hossain</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=rabbihossain" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/bravo-kernel"><img src="https://avatars.githubusercontent.com/u/230500?v=4?s=100" width="100px;" alt=""/><br /><sub><b>bravo-kernel</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=bravo-kernel" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/bravo-kernel"><img src="https://avatars.githubusercontent.com/u/230500?v=4?s=100" width="100px;" alt=""/><br /><sub><b>bravo-kernel</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=bravo-kernel" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=bravo-kernel" title="Documentation">📖</a></td>
<td align="center"><a href="https://samholmes.net"><img src="https://avatars.githubusercontent.com/u/8385528?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sam Holmes</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sam3d" title="Code">💻</a></td>
<td align="center"><a href="https://doncicuto.medium.com"><img src="https://avatars.githubusercontent.com/u/30386061?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Miguel Cabrerizo</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=doncicuto" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=doncicuto" title="Documentation">📖</a></td>
<td align="center"><a href="http://zackhobson.com/"><img src="https://avatars.githubusercontent.com/u/12092?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zack Hobson</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=zenhob" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=zenhob" title="Documentation">📖</a></td>
@@ -734,6 +709,24 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<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> <a href="https://github.com/blitz-js/blitz/commits?author=tordans" title="Tests">⚠️</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>
<td align="center"><a href="https://github.com/jhonnymichel"><img src="https://avatars.githubusercontent.com/u/7006387?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jhonny Michel</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jhonnymichel" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=jhonnymichel" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=jhonnymichel" title="Tests">⚠️</a></td>
<td align="center"><a href="sweetliquid.me"><img src="https://avatars.githubusercontent.com/u/18693190?v=4?s=100" width="100px;" alt=""/><br /><sub><b>sweetliquid</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sweetliquid" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/exKAZUu"><img src="https://avatars.githubusercontent.com/u/436237?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sakamoto, Kazunori</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=exKAZUu" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=exKAZUu" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/jeliasson"><img src="https://avatars.githubusercontent.com/u/865493?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Johan Eliasson</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jeliasson" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/jafarlihi"><img src="https://avatars.githubusercontent.com/u/43515211?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hikmat Jafarli</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jafarlihi" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=jafarlihi" title="Code">💻</a></td>
<td align="center"><a href="https://maotoramm.com"><img src="https://avatars.githubusercontent.com/u/5174884?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Maotora ᕙ(⇀‸↼‶)ᕗ</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=maotora" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=maotora" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/vitaliemiron"><img src="https://avatars.githubusercontent.com/u/45145592?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vitalie</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=vitaliemiron" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=vitaliemiron" title="Code">💻</a></td>
<td align="center"><a href="https://estevao.org"><img src="https://avatars.githubusercontent.com/u/19409687?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nelson Estevão</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=nelsonmestevao" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=nelsonmestevao" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/dbrxnds"><img src="https://avatars.githubusercontent.com/u/32268383?v=4?s=100" width="100px;" alt=""/><br /><sub><b>David</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=dbrxnds" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=dbrxnds" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=dbrxnds" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/gjmoed"><img src="https://avatars.githubusercontent.com/u/4458993?v=4?s=100" width="100px;" alt=""/><br /><sub><b>G.J. Moed</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=gjmoed" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=gjmoed" title="Code">💻</a></td>
</tr>
</table>
<!-- markdownlint-restore -->

7
apps/next13/.env Normal file
View File

@@ -0,0 +1,7 @@
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
DATABASE_URL="file:./dev.db"

View File

@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}

38
apps/next13/.gitignore vendored Normal file
View File

@@ -0,0 +1,38 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
.vscode

117
apps/next13/CHANGELOG.md Normal file
View File

@@ -0,0 +1,117 @@
# next-blitz-auth
## 0.1.1-beta.3
### Patch Changes
- Updated dependencies [eda14fa8a]
- Updated dependencies [3d004dc41]
- Updated dependencies [29c2b029a]
- @blitzjs/next@2.0.0-beta.27
- @blitzjs/rpc@2.0.0-beta.27
- @blitzjs/auth@2.0.0-beta.27
- blitz@2.0.0-beta.27
- @blitzjs/config@2.0.0-beta.27
## 0.1.1-beta.2
### Patch Changes
- Updated dependencies [e82a79be5]
- Updated dependencies [38d945a3f]
- @blitzjs/auth@2.0.0-beta.26
- @blitzjs/next@2.0.0-beta.26
- @blitzjs/rpc@2.0.0-beta.26
- blitz@2.0.0-beta.26
- @blitzjs/config@2.0.0-beta.26
## 0.1.1-beta.1
### Patch Changes
- Updated dependencies [f84d77a42]
- @blitzjs/rpc@2.0.0-beta.25
- @blitzjs/next@2.0.0-beta.25
- @blitzjs/auth@2.0.0-beta.25
- @blitzjs/config@2.0.0-beta.25
- blitz@2.0.0-beta.25
## 0.1.1-beta.0
### Patch Changes
- 37aeaa7fa: feature: Nextjs 13 App Directory Utility Methods
### 🔧 New Blitz Auth Hook `useAuthenticatedBlitzContext`
This hook is implemented as the replacement of the [`BlitzPage` seurity auth utilities](https://blitzjs.com/docs/authorization#secure-your-pages) provided for the pages directory to work with React Server Components in the Nextjs 13 app directory
It can be used in any asynchronous server component be it in `page.ts` or in the layouts in `layout.ts`
It uses the new [`redirect` function](https://beta.nextjs.org/docs/api-reference/redirect) to provide the required authorization in server side
#### API
```ts
useAuthenticatedBlitzContext({
redirectTo,
redirectAuthenticatedTo,
role,
}: {
redirectTo?: string | RouteUrlObject
redirectAuthenticatedTo?: string | RouteUrlObject | ((ctx: Ctx) => string | RouteUrlObject)
role?: string | string[]
}): Promise<void>
```
#### Usage
**Example Usage in React Server Component in `app` directory in Next 13**
```ts
import {getAppSession, useAuthenticatedBlitzContext} from "src/blitz-server"
...
await useAuthenticatedBlitzContext({
redirectTo: "/auth/login",
role: ["admin"],
redirectAuthenticatedTo: "/dashboard",
})
```
### 🔧 New Blitz RPC Hook `invokeResolver`
#### API
```ts
invokeResolver<T extends (...args: any) => any, TInput = FirstParam<T>>(
queryFn: T,
params: TInput,
): Promise<PromiseReturnType<T>>
```
#### Example Usage
```ts
...
import {invokeResolver, useAuthenticatedBlitzContext} from "../src/blitz-server"
import getCurrentUser from "../src/users/queries/getCurrentUser"
export default async function Home() {
await useAuthenticatedBlitzContext({
redirectTo: "/auth/login",
})
const user = await invokeResolver(getCurrentUser, null)
...
```
- Updated dependencies [cadefb88e]
- Updated dependencies [6f18cbdc9]
- Updated dependencies [acc07ce94]
- Updated dependencies [ea7561b8e]
- Updated dependencies [9529dbd6f]
- Updated dependencies [ea7561b8e]
- Updated dependencies [6e88a847f]
- Updated dependencies [37aeaa7fa]
- blitz@2.0.0-beta.24
- @blitzjs/auth@2.0.0-beta.24
- @blitzjs/next@2.0.0-beta.24
- @blitzjs/rpc@2.0.0-beta.24
- @blitzjs/config@2.0.0-beta.24

26
apps/next13/README.md Normal file
View File

@@ -0,0 +1,26 @@
# Next.js 13 + Blitz Auth
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) + [`Blitz Auth`](https://blitzjs.com/docs/auth).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can go to the `/signup` page and create a new account.
## Learn More
To learn more about Next.js and Blitz.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
- [Blitz.js Documentation](https://blitzjs.com/docs/) — learn about Blitz.js.
- [Blitz Auth Documentation](https://blitzjs.com/docs/auth) — learn about Blitz Auth plugin.

View File

@@ -0,0 +1,8 @@
import {useAuthenticatedBlitzContext} from "@blitzjs/auth"
export default async function RootLayout({children}: {children: React.ReactNode}) {
await useAuthenticatedBlitzContext({
redirectAuthenticatedTo: "/",
})
return <>{children}</>
}

View File

@@ -0,0 +1,13 @@
"use client"
import {LoginForm} from "../../../src/auth/components/LoginForm"
import {useRouter} from "next/navigation"
import {useSearchParams} from "next/navigation"
const LoginPage = () => {
const router = useRouter()
const searchParams = useSearchParams()
return <LoginForm onSuccess={(_user) => {}} />
}
export default LoginPage

View File

@@ -0,0 +1,11 @@
"use client"
import {useRouter} from "next/navigation"
import SignupForm from "../../../src/auth/components/SignupForm"
const SignUp = () => {
const router = useRouter()
return <SignupForm onSuccess={() => router.push("/")} />
}
export default SignUp

24
apps/next13/app/error.tsx Normal file
View File

@@ -0,0 +1,24 @@
"use client" // Error components must be Client components
import React, {useEffect} from "react"
export default function Error({error, reset}: {error: Error; reset: () => void}) {
useEffect(() => {
// Log the error to an error reporting service
console.error(error)
}, [error])
return (
<div>
<h2>Something went wrong!</h2>
<button
onClick={
// Attempt to recover by trying to re-render the segment
() => reset()
}
>
Try again
</button>
</div>
)
}

View File

@@ -0,0 +1,57 @@
import "src/styles/globals.css"
import {BlitzProvider} from "../src/blitz-client"
import styles from "src/styles/Home.module.css"
export default function RootLayout({children}: {children: React.ReactNode}) {
return (
<html lang="en">
<head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</head>
<body>
<BlitzProvider>
<div className={styles.globe} />
<div className={styles.container}>
<div className={styles.toastContainer}>
<p>
<strong>Congrats!</strong> Your app is ready, including user sign-up and log-in.
</p>
</div>
<main className={styles.main}>
<div className={styles.wrapper}>
<div className={styles.header}>
<div className={styles.logo}>
<svg viewBox="0 0 165 66">
<path d="M104.292 56.033C104.292 56.408 104.206 56.6636 104.036 56.8C103.9 56.9363 103.627 57.0045 103.218 57.0045H99.7409C99.4001 57.0045 99.1615 56.9533 99.0251 56.8511C98.8888 56.7147 98.8206 56.4932 98.8206 56.1864L98.9229 19.8324C98.9229 19.3211 99.1444 19.0654 99.5876 19.0654H103.627C103.839 19.0654 104.292 19.0672 104.292 19.0672V19.8324V56.033ZM64.3531 57.0081C64.1145 57.0081 63.927 56.9399 63.7906 56.8035C63.6543 56.6672 63.5861 56.4968 63.5861 56.2922V19.9383C63.5861 19.3588 63.8588 19.069 64.4042 19.069H76.829C81.533 19.069 85.1463 19.9212 87.6687 21.6256C90.1912 23.2958 91.4524 25.7331 91.4524 28.9373C91.4524 30.9484 90.924 32.6528 89.8673 34.0504C88.8106 35.4138 87.1063 36.5217 84.7543 37.3739C84.6179 37.4079 84.5497 37.4932 84.5497 37.6295C84.5497 37.7318 84.6179 37.7999 84.7543 37.834C87.2767 38.5158 89.1686 39.5895 90.4298 41.0553C91.7251 42.521 92.3727 44.4469 92.3727 46.833C92.3727 50.2418 91.0945 52.7983 88.5379 54.5027C85.9814 56.1729 82.2318 57.0081 77.2892 57.0081H64.3531ZM77.5448 35.5843C79.6923 35.5843 81.516 35.1071 83.0158 34.1526C84.5157 33.1982 85.2656 31.6983 85.2656 29.6531C85.2656 27.6079 84.5157 26.0569 83.0158 25.0002C81.5501 23.9435 79.5219 23.4151 76.9313 23.4151H70.5399C70.0286 23.4151 69.7729 23.6367 69.7729 24.0798V34.8684C69.7729 35.3457 69.9604 35.5843 70.3354 35.5843H77.5448ZM77.0335 52.662C82.9647 52.662 85.9303 50.5997 85.9303 46.4751C85.9303 44.3276 85.1633 42.7255 83.6294 41.6688C82.0955 40.6121 80.0673 40.0838 77.5448 40.0838H70.591C70.2843 40.0838 70.0627 40.1349 69.9263 40.2372C69.8241 40.3394 69.7729 40.5099 69.7729 40.7485V51.895C69.7729 52.4063 69.9604 52.662 70.3354 52.662H77.0335ZM142.707 56.8624C142.81 56.9647 142.997 57.0158 143.27 57.0158H163.876C164.387 57.0158 164.643 56.7772 164.643 56.3V53.948V53.3344H163.978H149.866C149.593 53.3344 149.457 53.2492 149.457 53.0788C149.457 52.9765 149.508 52.8572 149.61 52.7208L163.876 33.8536C164.251 33.2741 164.438 32.7628 164.438 32.3197V30.479V29.9144C164.438 29.9144 164.051 29.9165 163.876 29.9165H144.241C143.866 29.9165 143.679 30.121 143.679 30.5301V32.831C143.679 33.1037 143.713 33.2911 143.781 33.3934C143.883 33.4957 144.071 33.5468 144.344 33.5468H157.075C157.382 33.5468 157.535 33.632 157.535 33.8025L157.382 34.1092L143.219 52.9765C142.946 53.3515 142.759 53.6412 142.656 53.8457C142.588 54.0502 142.554 54.3059 142.554 54.6127V56.3C142.554 56.5727 142.605 56.7602 142.707 56.8624ZM116.929 19.0676H111.51V27.7684C114.503 27.7684 116.929 25.3419 116.929 22.3486V19.0676ZM116.926 56.0308C116.926 56.4058 116.841 56.6614 116.67 56.7978C116.534 56.9341 116.278 57.0023 115.903 57.0023H112.427C112.086 57.0023 111.847 56.9512 111.711 56.8489C111.574 56.7126 111.506 56.491 111.506 56.1842V30.6699C111.506 30.3972 111.557 30.2098 111.66 30.1075C111.762 29.9712 111.949 29.903 112.222 29.903H117.028L116.926 56.0308ZM132.183 34.3137C132.183 33.9728 132.336 33.8024 132.643 33.8024H138.779C139.256 33.8024 139.495 33.5979 139.495 33.1888V30.4789V29.9165H138.881H132.745C132.439 29.9165 132.285 29.7631 132.285 29.4563V21.531V20.713L131.621 20.7129H128.093C127.752 20.7129 127.547 20.9515 127.479 21.4288L126.865 29.4563C126.865 29.7631 126.729 29.9165 126.456 29.9165H122.366C121.957 29.9165 121.752 30.1039 121.752 30.4789V33.1888C121.752 33.5979 121.974 33.8024 122.417 33.8024H126.252C126.593 33.8024 126.763 34.0069 126.763 34.416V50.6244C126.763 52.806 127.309 54.4252 128.399 55.4819C129.49 56.5045 131.16 57.0158 133.41 57.0158C135.796 57.0158 137.535 56.9306 138.625 56.7601C139.137 56.6579 139.392 56.3681 139.392 55.8909V53.6923V53.0787H138.779H135.507C134.348 53.0787 133.495 52.806 132.95 52.2606C132.439 51.7152 132.183 50.7267 132.183 49.295V34.3137Z"></path>
<path d="M0.241243 33.2639H10.9742C15.0585 33.2639 18.9054 35.1835 21.3612 38.4471L31.9483 52.5165C32.1484 52.7824 32.1786 53.1393 32.026 53.435L25.9232 65.2592C25.6304 65.8265 24.8455 65.8932 24.4612 65.3835L0.241243 33.2639Z"></path>
<path d="M42.4727 33.2822H31.7398C27.6555 33.2822 23.8086 31.3626 21.3528 28.0991L10.7656 14.0297C10.5656 13.7638 10.5354 13.4068 10.688 13.1111L16.7908 1.28696C17.0836 0.719654 17.8684 0.652924 18.2528 1.16266L42.4727 33.2822Z"></path>
</svg>
</div>
<div className={styles.buttonContainer}></div>
</div>
<div className={styles.body}>{children} </div>
</div>
</main>
<footer className={styles.footer}>
<span>Powered by</span>
<a
href="https://blitzjs.com?utm_source=blitz-new&utm_medium=app-template&utm_campaign=blitz-new"
target="_blank"
rel="noopener noreferrer"
className={styles.textLink}
>
Blitz.js
</a>
</footer>
</div>
</BlitzProvider>
</body>
</html>
)
}

47
apps/next13/app/page.tsx Normal file
View File

@@ -0,0 +1,47 @@
import Link from "next/link"
import styles from "src/styles/Home.module.css"
import Test from "./react-query"
import {invoke, useAuthenticatedBlitzContext} from "../src/blitz-server"
import getCurrentUser from "../src/users/queries/getCurrentUser"
export default async function Home() {
await useAuthenticatedBlitzContext({
redirectTo: "/auth/login",
})
const user = await invoke(getCurrentUser, null)
console.log("user", user)
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
width: "100%",
}}
>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
}}
>
<Link href={"/auth/signup"} className={styles.button}>
<strong>Sign Up</strong>
</Link>
<Link href={"/auth/login"} className={styles.loginButton}>
<strong>Login</strong>
</Link>
<div style={{height: 20}} />
<p>Server Session</p>
<p>UserId: {user?.id}</p>
<p>Email: {user?.email}</p>
<div style={{height: 20}} />
<p>Client Session</p>
<Test />
</div>
</div>
)
}

View File

@@ -0,0 +1,34 @@
"use client"
import {useQuery, useMutation} from "@blitzjs/rpc"
import logout from "../src/auth/mutations/logout"
import getCurrentUser from "../src/users/queries/getCurrentUser"
import {useTransition} from "react"
import {useRouter} from "next/navigation"
export default function Test() {
const router = useRouter()
const [user] = useQuery(getCurrentUser, null)
const [isPending, startTransition] = useTransition()
const [logoutMutation] = useMutation(logout)
console.log(user)
return (
<div>
<h1>Test</h1>
<p>{user?.email}</p>
<button
className="button small"
onClick={async () => {
await logoutMutation()
startTransition(() => {
// Refresh the current route and fetch new data from the server without
// losing client-side browser or React state.
router.refresh()
})
}}
>
Logout
</button>
</div>
)
}

View File

@@ -0,0 +1,11 @@
const {withBlitz} = require("@blitzjs/next")
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
serverComponentsExternalPackages: ["@prisma/client", "prisma"],
},
}
module.exports = withBlitz(nextConfig)

38
apps/next13/package.json Normal file
View File

@@ -0,0 +1,38 @@
{
"name": "next-blitz-auth",
"version": "0.1.1-beta.3",
"private": true,
"scripts": {
"blitz:dev": "next dev",
"blitz:build": "next build",
"blitz:start": "next start",
"lint": "next lint"
},
"dependencies": {
"@blitzjs/auth": "workspace:*",
"@blitzjs/config": "workspace:*",
"@blitzjs/next": "workspace:*",
"@blitzjs/rpc": "workspace:*",
"@hookform/error-message": "2.0.0",
"@hookform/resolvers": "2.9.10",
"@prisma/client": "^4.5.0",
"@tanstack/react-query": "4.0.10",
"blitz": "workspace:*",
"flatted": "3.2.7",
"next": "13.3.0",
"prisma": "^4.5.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "7.39.1",
"superjson": "1.11.0",
"zod": "3.20.2"
},
"devDependencies": {
"@types/node": "18.11.7",
"@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"
}
}

BIN
apps/next13/prisma/dev.db Normal file

Binary file not shown.

View File

@@ -0,0 +1,5 @@
import {PrismaClient} from "@prisma/client"
export * from "@prisma/client"
const db = new PrismaClient()
export default db

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,
"hashedSessionToken" TEXT,
"antiCSRFToken" TEXT,
"publicData" TEXT,
"privateData" TEXT,
"userId" INTEGER,
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,48 @@
/*
Warnings:
- You are about to drop the `Token` table. If the table is not empty, all the data it contains will be lost.
- You are about to drop the column `createdAt` on the `User` table. All the data in the column will be lost.
- You are about to drop the column `role` on the `User` table. All the data in the column will be lost.
- You are about to drop the column `updatedAt` on the `User` table. All the data in the column will be lost.
- You are about to drop the column `createdAt` on the `Session` table. All the data in the column will be lost.
- You are about to drop the column `updatedAt` on the `Session` table. All the data in the column will be lost.
*/
-- DropIndex
DROP INDEX "Token_hashedToken_type_key";
-- DropTable
PRAGMA foreign_keys=off;
DROP TABLE "Token";
PRAGMA foreign_keys=on;
-- RedefineTables
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_User" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" TEXT,
"email" TEXT NOT NULL,
"hashedPassword" TEXT
);
INSERT INTO "new_User" ("email", "hashedPassword", "id", "name") SELECT "email", "hashedPassword", "id", "name" FROM "User";
DROP TABLE "User";
ALTER TABLE "new_User" RENAME TO "User";
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
CREATE TABLE "new_Session" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"expiresAt" DATETIME,
"handle" TEXT NOT NULL,
"hashedSessionToken" TEXT,
"antiCSRFToken" TEXT,
"publicData" TEXT,
"privateData" TEXT,
"userId" INTEGER,
CONSTRAINT "Session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
INSERT INTO "new_Session" ("antiCSRFToken", "expiresAt", "handle", "hashedSessionToken", "id", "privateData", "publicData", "userId") SELECT "antiCSRFToken", "expiresAt", "handle", "hashedSessionToken", "id", "privateData", "publicData", "userId" FROM "Session";
DROP TABLE "Session";
ALTER TABLE "new_Session" RENAME TO "Session";
CREATE UNIQUE INDEX "Session_handle_key" ON "Session"("handle");
PRAGMA foreign_key_check;
PRAGMA foreign_keys=ON;

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,33 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
name String?
email String @unique
hashedPassword String?
sessions Session[]
}
model Session {
id Int @id @default(autoincrement())
expiresAt DateTime?
handle String @unique
hashedSessionToken String?
antiCSRFToken String?
publicData String?
privateData String?
user User? @relation(fields: [userId], references: [id])
userId Int?
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,4 @@
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,61 @@
import {AuthenticationError, PromiseReturnType} from "blitz"
import Link from "next/link"
import {LabeledTextField} from "../../core/components/LabeledTextField"
import {Form, FORM_ERROR} from "../../core/components/Form"
import login from "../../auth/mutations/login"
import {Login} from "../../auth/validations"
import {useMutation} from "@blitzjs/rpc"
import {startTransition} from "react"
import {useRouter} from "next/navigation"
type LoginFormProps = {
onSuccess?: (user: PromiseReturnType<typeof login>) => void
}
export const LoginForm = (props: LoginFormProps) => {
const [loginMutation] = useMutation(login)
const router = useRouter()
return (
<div>
<h1>Login</h1>
<Form
submitText="Login"
schema={Login}
initialValues={{email: "", password: ""}}
onSubmit={async (values) => {
try {
const user = await loginMutation(values)
props.onSuccess?.(user)
startTransition(() => {
// Refresh the current route and fetch new data from the server without
// losing client-side browser or React state.
router.refresh()
})
} catch (error: any) {
if (error instanceof AuthenticationError) {
return {[FORM_ERROR]: "Sorry, those credentials are invalid"}
} else {
return {
[FORM_ERROR]:
"Sorry, we had an unexpected error. Please try again. - " + error.toString(),
}
}
}
}}
>
<LabeledTextField name="email" label="Email" placeholder="Email" />
<LabeledTextField name="password" label="Password" placeholder="Password" type="password" />
<div>
<a>Forgot your password?</a>
</div>
</Form>
<div style={{marginTop: "1rem"}}>
Or <Link href={"/auth/signup"}>Sign Up</Link>
</div>
</div>
)
}
export default LoginForm

View File

@@ -0,0 +1,51 @@
import {LabeledTextField} from "../../core/components/LabeledTextField"
import {Form, FORM_ERROR} from "../../core/components/Form"
import signup from "../../auth/mutations/signup"
import {Signup} from "../../auth/validations"
import {useMutation} from "@blitzjs/rpc"
import {startTransition} from "react"
import {useRouter} from "next/navigation"
type SignupFormProps = {
onSuccess?: () => void
}
export const SignupForm = (props: SignupFormProps) => {
const [signupMutation] = useMutation(signup)
const router = useRouter()
return (
<div>
<h1>Create an Account</h1>
<Form
submitText="Create Account"
schema={Signup}
initialValues={{email: "", password: ""}}
onSubmit={async (values) => {
try {
await signupMutation(values)
props.onSuccess?.()
startTransition(() => {
// Refresh the current route and fetch new data from the server without
// losing client-side browser or React state.
router.refresh()
})
} catch (error: any) {
if (error.code === "P2002" && error.meta?.target?.includes("email")) {
// 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()}
}
}
}}
>
<LabeledTextField name="email" label="Email" placeholder="Email" />
<LabeledTextField name="password" label="Password" placeholder="Password" type="password" />
</Form>
</div>
)
}
export default SignupForm

View File

@@ -0,0 +1,26 @@
import {NotFoundError} from "blitz"
import db from "../../../prisma"
// import {authenticateUser} from "./login"
import {ChangePassword} from "../validations"
import {resolver} from "@blitzjs/rpc"
// import {SecurePassword} from "@blitzjs/auth"
export default resolver.pipe(
//@ts-ignore
resolver.zod(ChangePassword),
resolver.authorize(),
async ({currentPassword, newPassword}, ctx) => {
const user = await db.user.findFirst({where: {id: ctx.session.userId}})
if (!user) throw new NotFoundError()
// await authenticateUser(user.email, currentPassword)
// const hashedPassword = await SecurePassword.hash(newPassword.trim())
await db.user.update({
where: {id: user.id},
data: {hashedPassword: newPassword},
})
return true
},
)

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,40 @@
import {generateToken, hash256} from "@blitzjs/auth"
import {resolver} from "@blitzjs/rpc"
import db from "../../../prisma"
import {ForgotPassword} from "../validations"
const RESET_PASSWORD_TOKEN_EXPIRATION_IN_HOURS = 4
//@ts-ignore
export default resolver.pipe(resolver.zod(ForgotPassword), async ({email}) => {
// 1. Get the user
const user = await db.user.findFirst({where: {email: email.toLowerCase()}})
// 2. Generate the token and expiration date.
const token = generateToken()
const hashedToken = hash256(token)
const expiresAt = new Date()
expiresAt.setHours(expiresAt.getHours() + RESET_PASSWORD_TOKEN_EXPIRATION_IN_HOURS)
// 3. If user with this email was found
if (user) {
// 4. Delete any existing password reset tokens
await db.token.deleteMany({where: {type: "RESET_PASSWORD", userId: user.id}})
// 5. Save this new token in the database.
await db.token.create({
data: {
user: {connect: {id: user.id}},
type: "RESET_PASSWORD",
expiresAt,
hashedToken,
sentTo: user.email,
},
})
// 6. Send the email
} else {
// 7. If no user found wait the same time so attackers can't tell the difference
await new Promise((resolve) => setTimeout(resolve, 750))
}
// 8. Return the same result whether a password reset email was sent or not
return
})

View File

@@ -0,0 +1,31 @@
import {resolver} from "@blitzjs/rpc"
// import {AuthenticationError} from "blitz"
import db from "../../../prisma"
import {Login} from "../validations"
// export const authenticateUser = async (rawEmail: string, rawPassword: string) => {
// const {email, password} = Login.parse({email: rawEmail, password: rawPassword})
// const user = await db.user.findFirst({where: {email}})
// if (!user) throw new AuthenticationError()
// const result = await SecurePassword.verify(user.hashedPassword, password)
// if (result === SecurePassword.VALID_NEEDS_REHASH) {
// // Upgrade hashed password with a more secure hash
// const improvedHash = await SecurePassword.hash(password)
// await db.user.update({where: {id: user.id}, data: {hashedPassword: improvedHash}})
// }
// const {hashedPassword, ...rest} = user
// return rest
// }
//@ts-ignore
export default resolver.pipe(resolver.zod(Login), async ({email, password}, ctx) => {
// This throws an error if credentials are invalid
// const user = await authenticateUser(email, password)
const user = await db.user.findFirst({where: {email}})
//@ts-ignore
await ctx.session.$create({userId: user.id, role: user.role})
console.log("user", user)
return user
})

View File

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

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

@@ -0,0 +1,50 @@
import {hash256} from "@blitzjs/auth"
import db from "../../../prisma"
import {ResetPassword} from "../validations"
import login from "./login"
export class ResetPasswordError extends Error {
name = "ResetPasswordError"
message = "Reset password link is invalid or it has expired."
}
export default async function resetPassword(input: any, ctx: any) {
ResetPassword.parse(input)
// 1. Try to find this token in the database
const hashedToken = hash256(input.token)
const possibleToken = await db.token.findFirst({
where: {hashedToken, type: "RESET_PASSWORD"},
include: {user: true},
})
// 2. If token not found, error
if (!possibleToken) {
throw new ResetPasswordError()
}
const savedToken = possibleToken
// 3. Delete token so it can't be used again
await db.token.delete({where: {id: savedToken.id}})
// 4. If token has expired, error
if (savedToken.expiresAt < new Date()) {
throw new ResetPasswordError()
}
// 5. Since token is valid, now we can update the user's password
// const hashedPassword = await SecurePassword.hash(input.password.trim())
const user = await db.user.update({
where: {id: savedToken.userId},
data: {
hashedPassword: input.password,
},
})
// 6. Revoke all existing login sessions for this user
await db.session.deleteMany({where: {userId: user.id}})
// 7. Now log the user in with the new credentials
await login({email: user.email, password: input.password}, ctx)
return true
}

View File

@@ -0,0 +1,19 @@
import db from "../../../prisma"
// import {SecurePassword} from "@blitzjs/auth"
export default async function signup(input: {password: string; email: string}, ctx: any) {
const blitzContext = ctx
// const hashedPassword = await SecurePassword.hash((input.password as string) || "test-password")
const hashedPassword = (input.password as string) || "test-password"
const email = (input.email as string) || "test" + Math.random() + "@test.com"
const user = await db.user.create({
data: {email, hashedPassword},
})
await blitzContext.session.$create({
userId: user.id,
role: "user",
})
return {userId: blitzContext.session.userId, ...user, email: input.email}
}

View File

@@ -0,0 +1,42 @@
import {z} from "zod"
export const email = z
.string()
.email()
.transform((str) => str.toLowerCase().trim())
export const password = z
.string()
.min(10)
.max(100)
.transform((str) => str.trim())
export const Signup = z.object({
email,
password,
})
export const Login = z.object({
email,
password: z.string(),
})
export const ForgotPassword = z.object({
email,
})
export const ResetPassword = z
.object({
password: password,
passwordConfirmation: password,
token: z.string(),
})
.refine((data) => data.password === data.passwordConfirmation, {
message: "Passwords don't match",
path: ["passwordConfirmation"], // set the path of the error
})
export const ChangePassword = z.object({
currentPassword: z.string(),
newPassword: password,
})

View File

@@ -0,0 +1,13 @@
"use client"
import {AuthClientPlugin} from "@blitzjs/auth"
import {setupBlitzClient} from "@blitzjs/next"
import {BlitzRpcPlugin} from "@blitzjs/rpc"
export const {withBlitz, useSession, queryClient, BlitzProvider} = setupBlitzClient({
plugins: [
AuthClientPlugin({
cookiePrefix: "web-cookie-prefix",
}),
BlitzRpcPlugin({}),
],
})

View File

@@ -0,0 +1,25 @@
import type {BlitzCliConfig} from "blitz"
import {setupBlitzServer} from "@blitzjs/next"
import {AuthServerPlugin, PrismaStorage} from "@blitzjs/auth"
import db from "../prisma"
import {simpleRolesIsAuthorized} from "@blitzjs/auth"
import {BlitzLogger} from "blitz"
import {RpcServerPlugin} from "@blitzjs/rpc"
const {api, getBlitzContext, useAuthenticatedBlitzContext, invoke} = setupBlitzServer({
plugins: [
AuthServerPlugin({
cookiePrefix: "web-cookie-prefix",
storage: PrismaStorage(db),
isAuthorized: simpleRolesIsAuthorized,
}),
RpcServerPlugin({}),
],
logger: BlitzLogger({}),
})
export {api, getBlitzContext, useAuthenticatedBlitzContext, invoke}
export const cliConfig: BlitzCliConfig = {
customTemplates: "src/templates",
}

View File

@@ -0,0 +1,83 @@
import {useState, ReactNode, PropsWithoutRef} from "react"
import {FormProvider, useForm, UseFormProps} from "react-hook-form"
import {zodResolver} from "@hookform/resolvers/zod"
import {z} from "zod"
export interface FormProps<S extends z.ZodType<any, any>>
extends Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit"> {
/** All your form fields */
children?: ReactNode
/** Text to display in the submit button */
submitText?: string
schema?: S
onSubmit: (values: z.infer<S>) => Promise<void | OnSubmitResult>
initialValues?: UseFormProps<z.infer<S>>["defaultValues"]
}
interface OnSubmitResult {
FORM_ERROR?: string
[prop: string]: any
}
export const FORM_ERROR = "FORM_ERROR"
export function Form<S extends z.ZodType<any, any>>({
children,
submitText,
schema,
initialValues,
onSubmit,
...props
}: FormProps<S>) {
const ctx = useForm<z.infer<S>>({
mode: "onBlur",
resolver: schema ? zodResolver(schema) : undefined,
defaultValues: initialValues,
})
const [formError, setFormError] = useState<string | null>(null)
return (
<FormProvider {...ctx}>
<form
onSubmit={ctx.handleSubmit(async (values) => {
const result = (await onSubmit(values)) || {}
for (const [key, value] of Object.entries(result)) {
if (key === FORM_ERROR) {
setFormError(value)
} else {
ctx.setError(key as any, {
type: "submit",
message: value,
})
}
}
})}
className="form"
{...props}
>
{/* Form fields supplied as children are rendered here */}
{children}
{formError && (
<div role="alert" style={{color: "red"}}>
{formError}
</div>
)}
{submitText && (
<button type="submit" disabled={ctx.formState.isSubmitting}>
{submitText}
</button>
)}
<style global jsx>{`
.form > * + * {
margin-top: 1rem;
}
`}</style>
</form>
</FormProvider>
)
}
export default Form

View File

@@ -0,0 +1,63 @@
import {forwardRef, PropsWithoutRef, ComponentPropsWithoutRef} from "react"
import {useFormContext} from "react-hook-form"
import {ErrorMessage} from "@hookform/error-message"
export interface LabeledTextFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["input"]> {
/** Field name. */
name: string
/** Field label. */
label: string
/** Field type. Doesn't include radio buttons and checkboxes */
type?: "text" | "password" | "email" | "number"
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
labelProps?: ComponentPropsWithoutRef<"label">
}
export const LabeledTextField = forwardRef<HTMLInputElement, LabeledTextFieldProps>(
({label, outerProps, labelProps, name, ...props}, ref) => {
const {
register,
formState: {isSubmitting, errors},
} = useFormContext()
return (
<div {...outerProps}>
<label {...labelProps}>
{label}
<input disabled={isSubmitting} {...register(name)} {...props} />
</label>
<ErrorMessage
render={({message}) => (
<div role="alert" style={{color: "red"}}>
{message}
</div>
)}
errors={errors}
name={name}
/>
<style jsx>{`
label {
display: flex;
flex-direction: column;
align-items: start;
font-size: 1rem;
}
input {
font-size: 1rem;
padding: 0.25rem 0.5rem;
border-radius: 3px;
border: 1px solid purple;
appearance: none;
margin-top: 0.5rem;
}
`}</style>
</div>
)
},
)
LabeledTextField.displayName = "LabeledTextField"
export default LabeledTextField

View File

@@ -0,0 +1,8 @@
import {api} from "../../../blitz-server"
export default api((req, res, ctx) => {
// console.log("session", ctx.session)
//get cookie
console.dir("cookie", req.headers.cookie)
res.json({session: ctx.session.userId})
})

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,303 @@
.container {
display: flex;
flex-direction: column;
height: 100vh;
}
.main {
flex: 1;
padding: 0rem 1rem;
display: flex;
flex-direction: column;
}
.wrapper {
display: flex;
flex-direction: column;
gap: 2rem;
}
.frost {
background: rgba(255, 255, 255, 0.2);
border-radius: 16px;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
border: 1px solid rgba(255, 255, 255, 0.31);
}
.header {
display: flex;
flex-direction: column;
padding: 4rem 0rem 2rem 0rem;
text-align: center;
gap: 2rem;
}
.header h1 {
max-width: 620px;
align-self: center;
}
.body {
composes: frost;
border-radius: var(--border-radius);
display: flex;
padding: 1rem;
width: 100%;
flex-direction: row;
align-self: center;
max-width: var(--screen-width);
}
.instructions {
display: inline-flex;
flex-direction: column;
padding: 1rem;
width: 100%;
}
.globe {
position: fixed;
width: 350vmin;
height: 75vmin;
left: 20%;
top: 50%;
transform: translate(-50%, calc(-50% + 40px));
z-index: -1;
border-radius: 100%;
background-image: radial-gradient(
95.63% 95.63% at 95.92% 0%,
rgba(255, 255, 255, 0.62) 0%,
#8155ff38 60.42%,
#002fff5c 169%
);
filter: blur(8vmin);
}
.footer {
display: flex;
padding: 2rem 0;
justify-content: center;
align-items: center;
}
.footer span {
margin-right: 0.2rem;
}
.code {
display: flex;
align-items: center;
gap: 0.5rem;
}
.code span {
background: rgba(124, 58, 237, 50%);
border-radius: 50rem;
font-size: 14px;
font-weight: 500;
padding: 17px;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
color: rgb(57, 33, 97);
}
.code pre {
background: rgba(124, 58, 237, 12%);
border-radius: 4px;
padding: 0.7em 1.4em;
text-align: center;
}
.code code {
font-size: 0.86em;
font-weight: bold;
color: rgb(124, 58, 237);
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
Bitstream Vera Sans Mono, Courier New, monospace;
}
.toastContainer {
border: 1px solid #edff;
padding: 0 1rem;
background: #eeff;
color: #62af;
text-align: center;
}
.toastContainer strong {
color: rgb(124, 58, 237);
}
.textLink {
color: rgb(124, 58, 237);
background: linear-gradient(to right, rgba(231, 216, 246, 1), rgba(231, 216, 246, 1)),
linear-gradient(to right, rgba(99, 1, 235, 1), rgba(124, 58, 237, 1), rgba(231, 216, 246, 1));
background-size: 100% 1px, 0 1px;
background-position: 100% 100%, 0 100%;
background-repeat: no-repeat;
transition: background-size 400ms;
}
.textLink:hover,
.textLink:focus,
.textLink:active {
background-size: 0 1px, 100% 1px;
}
.arrowIcon {
box-sizing: border-box;
display: block;
width: 8px;
height: 8px;
border-top: 2px solid;
transform: scale(var(--ggs, 1));
border-right: 2px solid;
position: absolute;
right: 6px;
top: 6px;
color: #b1a5c4;
}
.arrowIcon::after {
content: "";
display: block;
box-sizing: border-box;
position: absolute;
width: 8px;
height: 2px;
background: currentColor;
transform: rotate(-45deg);
top: 2px;
right: -1px;
}
.buttonContainer {
display: flex;
flex-direction: row;
gap: 1rem;
justify-content: center;
align-items: center;
flex: 1;
}
.button {
background: linear-gradient(to top, rgb(124, 58, 237), rgb(117, 81, 236));
border: 1px solid rgb(231, 216, 246);
color: white;
text-shadow: rgba(0, 0, 0, 0.25) 0px 3px 8px;
padding: 0 24px;
height: 48px;
width: 200px;
max-width: 300px;
position: relative;
display: inline-flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
user-select: none;
white-space: nowrap;
border-radius: 0.75rem;
border-bottom-left-radius: 0px;
font-size: 15px;
transition: all 0.3s ease 0s;
cursor: pointer;
}
.button:hover {
color: white;
text-shadow: rgb(0 0 0 / 56%) 0px 3px 12px;
box-shadow: rgb(80 63 205 / 50%) 0px 1px 40px;
}
.loginButton {
composes: button;
background: rgb(248 250 252);
border: 1px solid rgb(231, 216, 246);
color: rgb(30 41 59);
text-shadow: none;
}
.loginButton:hover {
color: rgb(30 41 59);
text-shadow: none;
}
.card:hover .arrowIcon {
color: #7450ec;
}
.linkGrid {
display: flex;
flex-direction: column;
flex-wrap: wrap;
gap: 1rem;
}
.card {
composes: frost;
padding: 1rem 0rem;
text-align: center;
color: inherit;
text-decoration: none;
border-radius: 10px;
border-bottom-left-radius: 0px;
transition: color 0.15s ease, border-color 0.15s ease;
max-width: 200px;
min-width: 200px;
display: flex;
flex-direction: row;
justify-content: center;
}
.card:hover,
.card:focus,
.card:active {
color: #7450ec;
border-color: #7450ec;
}
.card h2 {
margin: 0 0 1rem 0;
font-size: 1.5rem;
}
.card p {
margin: 0;
font-size: 1.25rem;
line-height: 1.5;
}
.logo {
flex: 1;
padding: 1rem 2rem;
}
.logo svg {
height: 100%;
width: 200px;
fill: #7450ec;
}
/* MOBILE */
@media (max-width: 800px) {
.linkGrid {
width: 100%;
}
.card {
max-width: 100%;
}
.body {
flex-wrap: wrap;
}
.buttonContainer {
flex-wrap: wrap;
}
}

View File

@@ -0,0 +1,25 @@
:root {
--border-radius: 0.75rem;
--screen-width: 90vmin;
}
html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell,
Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}
a {
color: inherit;
text-decoration: none;
}
i {
font-size: 0.8rem;
}
* {
box-sizing: border-box;
}

View File

@@ -0,0 +1,7 @@
import {useQuery} from "@blitzjs/rpc"
import getCurrentUser from "../../../src/users/queries/getCurrentUser"
export const useCurrentUser = () => {
const [user] = useQuery(getCurrentUser, null)
return user
}

View File

@@ -0,0 +1,16 @@
import {Ctx} from "blitz"
import db from "../../../prisma"
export default async function getCurrentUser(input: null, ctx: Ctx) {
if (!ctx.session.userId) return null
const user = await db.user.findFirst({
where: {id: ctx.session.userId},
select: {id: true, name: true, email: true},
})
return user
}
export const config = {
httpMethod: "GET",
}

25
apps/next13/tsconfig.json Normal file
View File

@@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

12
apps/next13/types.ts Normal file
View File

@@ -0,0 +1,12 @@
import {SimpleRolesIsAuthorized} from "@blitzjs/auth"
import {User} from "./prisma"
declare module "@blitzjs/auth" {
export interface Session {
isAuthorized: SimpleRolesIsAuthorized
PublicData: {
userId: User["id"]
email: User["email"]
}
}
}

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

@@ -29,16 +29,16 @@
"@blitzjs/rpc": "workspace:*",
"@hookform/error-message": "2.0.0",
"@hookform/resolvers": "2.9.10",
"@prisma/client": "4.6.0",
"blitz": "workspace:2.0.0-beta.20",
"next": "12.2.5",
"@prisma/client": "4.6.1",
"blitz": "workspace:2.0.0-beta.27",
"next": "13.3.0",
"openid-client": "5.2.1",
"prisma": "4.6.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.19.1"
"zod": "3.20.2"
},
"devDependencies": {
"@next/bundle-analyzer": "12.0.8",

View File

@@ -40,17 +40,12 @@ export const LoginForm = (props: LoginFormProps) => {
<LabeledTextField name="email" label="Email" placeholder="Email" />
<LabeledTextField name="password" label="Password" placeholder="Password" type="password" />
<div>
<Link href={Routes.ForgotPasswordPage()} passHref>
<a>Forgot your password?</a>
</Link>
<Link href={Routes.ForgotPasswordPage()}>Forgot your password?</Link>
</div>
</Form>
<div style={{ marginTop: "1rem" }}>
Or{" "}
<Link href={Routes.SignupPage()} passHref>
<a>Sign Up</a>
</Link>
Or <Link href={Routes.SignupPage()}>Sign Up</Link>
</div>
</div>
)

View File

@@ -3,7 +3,7 @@ import db from "db"
import { authenticateUser } from "./login"
import { ChangePassword } from "../validations"
import { resolver } from "@blitzjs/rpc"
import { SecurePassword } from "@blitzjs/auth"
import { SecurePassword } from "@blitzjs/auth/secure-password"
export default resolver.pipe(
resolver.zod(ChangePassword),

View File

@@ -1,4 +1,4 @@
import { SecurePassword } from "@blitzjs/auth"
import { SecurePassword } from "@blitzjs/auth/secure-password"
import { resolver } from "@blitzjs/rpc"
import { AuthenticationError } from "blitz"
import db from "db"

View File

@@ -1,6 +1,7 @@
import { SecurePassword, hash256 } from "@blitzjs/auth"
import { hash256 } from "@blitzjs/auth"
import db from "db"
import { ResetPassword } from "../validations"
import { SecurePassword } from "@blitzjs/auth/secure-password"
import login from "./login"
export class ResetPasswordError extends Error {

View File

@@ -1,5 +1,5 @@
import db from "db"
import { SecurePassword } from "@blitzjs/auth"
import { SecurePassword } from "@blitzjs/auth/secure-password"
import { Role } from "types"
export default async function signup(input, ctx) {

View File

@@ -38,15 +38,11 @@ const UserInfo = () => {
} else {
return (
<>
<Link href={Routes.SignupPage()} passHref>
<a className="button small">
<strong>Sign Up</strong>
</a>
<Link href={Routes.SignupPage()} className="button small">
<strong>Sign Up</strong>
</Link>
<Link href={Routes.LoginPage()} passHref>
<a className="button small">
<strong>Login</strong>
</a>
<Link href={Routes.LoginPage()} className="button small">
<strong>Login</strong>
</Link>
</>
)
@@ -59,7 +55,7 @@ const Home: BlitzPage = () => {
<div className="container">
<main>
<div className="logo">
<Image src={`${logo.src}`} alt="blitzjs" width="256px" height="118px" layout="fixed" />
<Image src={`${logo.src}`} alt="blitzjs" width={256} height={118} layout="fixed" />
</div>
<p>
<strong>Congrats!</strong> Your app is ready, including user sign-up and log-in.
@@ -90,10 +86,7 @@ const Home: BlitzPage = () => {
<code>blitz dev</code>
</pre>
<p>
and go to{" "}
<Link href="/projects">
<a>/projects</a>
</Link>
and go to <Link href="/projects">/projects</Link>
</p>
</div>
<div className="buttons" style={{ marginTop: "5rem" }}>

View File

@@ -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,8 +1,4 @@
// @ts-check
const withBundleAnalyzer = require("@next/bundle-analyzer")({
enabled: process.env.ANALYZE === "true",
})
const { withNextAuthAdapter } = require("@blitzjs/auth/next-auth")
const { withBlitz } = require("@blitzjs/next")
/**
@@ -12,4 +8,4 @@ const config = {
reactStrictMode: true,
}
module.exports = withBlitz(withBundleAnalyzer(config))
module.exports = withBlitz(withNextAuthAdapter(config))

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