1
0
mirror of synced 2026-02-07 12:00:13 -05:00

Compare commits

..

20 Commits
next13 ... docs

Author SHA1 Message Date
Siddharth Suresh
ee99c5739c start adding index page / twoslash and add community docs 2023-03-02 23:27:22 +05:30
Siddharth Suresh
de5b6eb9a9 add introduction pages 2023-03-02 17:57:53 +05:30
Siddharth Suresh
d86bb0cf83 init nextra 2023-03-02 15:12:27 +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
189 changed files with 14005 additions and 12504 deletions

View File

@@ -3794,7 +3794,8 @@
"profile": "http://tobiasjordans.de",
"contributions": [
"code",
"doc"
"doc",
"test"
]
},
{
@@ -3816,6 +3817,36 @@
"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"
]
}
],
"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,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/generator": patch
---
Remove useEffect from reset password templates.

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

@@ -51,6 +51,7 @@
"changesets": [
"afraid-dancers-juggle",
"afraid-ears-repair",
"big-boats-lay",
"big-phones-bow",
"blue-flowers-peel",
"blue-pigs-tan",
@@ -195,9 +196,11 @@
"olive-sheep-rhyme",
"orange-mirrors-tap",
"orange-zebras-reflect",
"perfect-baboons-relate",
"perfect-eyes-repeat",
"perfect-trains-double",
"plenty-bottles-swim",
"plenty-kiwis-greet",
"polite-lizards-love",
"poor-peas-lick",
"poor-penguins-look",
@@ -260,18 +263,21 @@
"stupid-walls-sell",
"sweet-kiwis-cross",
"swift-drinks-dress",
"swift-glasses-laugh",
"swift-poets-travel",
"tall-meals-learn",
"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",

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/generator": patch
---
Update all links to follow Next 13 format without a child anchor tag.

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

@@ -1,6 +1,6 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
pnpm manypkg check
# pnpm manypkg check
# pnpm lint
pnpm pretty-quick --staged
# pnpm pretty-quick --staged

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-403-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-406-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 -->
@@ -736,9 +711,12 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
</tr>
<tr>
<td align="center"><a href="a11rew.dev"><img src="https://avatars.githubusercontent.com/u/87580113?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andrew Glago</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=a11rew" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=a11rew" title="Code">💻</a></td>
<td align="center"><a href="http://tobiasjordans.de"><img src="https://avatars.githubusercontent.com/u/111561?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tobias</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=tordans" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=tordans" title="Documentation">📖</a></td>
<td align="center"><a href="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>
</table>

View File

@@ -1,7 +0,0 @@
# 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

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

View File

@@ -1,38 +0,0 @@
# 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

View File

@@ -1,26 +0,0 @@
# 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

@@ -1,22 +0,0 @@
"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) => {
const next = searchParams.get("next")
? decodeURIComponent(searchParams.get("next") as string)
: "/"
return router.push(next)
}}
/>
)
}
export default LoginPage

View File

@@ -1,11 +0,0 @@
"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

View File

@@ -1,24 +0,0 @@
"use client" // Error components must be Client components
import {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

@@ -1,57 +0,0 @@
import "src/styles/globals.css"
import BlitzProvider from "./provider"
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>
)
}

View File

@@ -1,39 +0,0 @@
import Link from "next/link"
import Test from "./react-query"
import styles from "src/styles/Home.module.css"
// import { getSessionContext } from "@blitzjs/auth"
// import getCurrentUser from "../src/users/queries/getCurrentUser"
export default async function Home() {
// const ctx = await getSessionContext()
// console.log(ctx)
// const user = getCurrentUser(null, ctx)
console.log(user)
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "column",
width: "100%",
}}
>
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
flexDirection: "row",
}}
>
<Link href={"/auth/signup"} className={styles.button}>
<strong>Sign Up</strong>
</Link>
<Link href={"/auth/login"} className={styles.loginButton}>
<strong>Login</strong>
</Link>
</div>
<Test />
</div>
)
}

View File

@@ -1,15 +0,0 @@
"use client"
import {queryClient, RSC_BlitzProvider} from "../src/blitz-client"
type Props = {
children: React.ReactNode
}
globalThis.__BLITZ_RSC = true
const BlitzProvider = ({children}: Props) => (
<RSC_BlitzProvider client={queryClient}>{children}</RSC_BlitzProvider>
)
export default BlitzProvider

View File

@@ -1,15 +0,0 @@
"use client"
import {useQuery} from "@blitzjs/rpc"
import getCurrentUser from "../src/users/queries/getCurrentUser"
export default function Test() {
const [user] = useQuery(getCurrentUser, undefined)
console.log(user)
return (
<div>
<h1>Test</h1>
<p>{user?.email}</p>
</div>
)
}

View File

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

View File

@@ -1,33 +0,0 @@
{
"name": "next-blitz-auth",
"version": "0.1.0",
"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:*",
"@prisma/client": "^4.5.0",
"@tanstack/react-query": "4.0.10",
"blitz": "workspace:*",
"next": "13.1.2",
"prisma": "^4.5.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"superjson": "1.11.0"
},
"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"
}
}

Binary file not shown.

View File

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

View File

@@ -1,47 +0,0 @@
-- 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

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

View File

@@ -1,33 +0,0 @@
// 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.

Before

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -1,4 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,53 +0,0 @@
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"
type LoginFormProps = {
onSuccess?: (user: PromiseReturnType<typeof login>) => void
}
export const LoginForm = (props: LoginFormProps) => {
const [loginMutation] = useMutation(login)
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)
} 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

@@ -1,42 +0,0 @@
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"
type SignupFormProps = {
onSuccess?: () => void
}
export const SignupForm = (props: SignupFormProps) => {
const [signupMutation] = useMutation(signup)
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?.()
} 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

@@ -1,25 +0,0 @@
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(
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},
})
return true
},
)

View File

@@ -1,64 +0,0 @@
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

@@ -1,40 +0,0 @@
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
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

@@ -1,31 +0,0 @@
import {SecurePassword} from "@blitzjs/auth"
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
}
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)
//@ts-ignore
await ctx.session.$create({userId: user.id, role: user.role})
return user
})

View File

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

View File

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

View File

@@ -1,48 +0,0 @@
import {SecurePassword, 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},
})
// 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

@@ -1,19 +0,0 @@
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 email = (input.email as string) || "test" + Math.random() + "@test.com"
const user = await db.user.create({
data: {email, hashedPassword, role: "user"},
select: {id: true, name: true, email: true, role: true},
})
await blitzContext.session.$create({
userId: user.id,
role: user.role,
})
return {userId: blitzContext.session.userId, ...user, email: input.email}
}

View File

@@ -1,42 +0,0 @@
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

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

View File

@@ -1,23 +0,0 @@
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"
const {gSSP, gSP, api} = setupBlitzServer({
plugins: [
AuthServerPlugin({
cookiePrefix: "web-cookie-prefix",
storage: PrismaStorage(db),
isAuthorized: simpleRolesIsAuthorized,
}),
],
logger: BlitzLogger({}),
})
export {gSSP, gSP, api}
export const cliConfig: BlitzCliConfig = {
customTemplates: "src/templates",
}

View File

@@ -1,83 +0,0 @@
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

@@ -1,61 +0,0 @@
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>
)
},
)
export default LabeledTextField

View File

@@ -1,8 +0,0 @@
import {AppProps} from "@blitzjs/next"
import {withBlitz} from "../blitz-client"
function MyApp({Component, pageProps}: AppProps) {
return <Component {...pageProps} />
}
export default withBlitz(MyApp, true)

View File

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

View File

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

View File

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

View File

@@ -1,12 +0,0 @@
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

@@ -29,11 +29,11 @@
"@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.22",
"next": "13.1.2",
"@prisma/client": "4.6.1",
"blitz": "workspace:2.0.0-beta.23",
"next": "12.2.5",
"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",

View File

@@ -40,16 +40,16 @@ 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 href={Routes.ForgotPasswordPage()}>
Forgot your password?
</Link>
</div>
</Form>
<div style={{ marginTop: "1rem" }}>
Or{" "}
<Link href={Routes.SignupPage()} passHref>
<a>Sign Up</a>
<Link href={Routes.SignupPage()}>
Sign Up
</Link>
</div>
</div>

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

@@ -30,10 +30,10 @@
"@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.22",
"next": "13.1.2",
"prisma": "4.6.0",
"@prisma/client": "4.6.1",
"blitz": "workspace:2.0.0-beta.23",
"next": "12.2.5",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "7.39.1",

View File

@@ -40,16 +40,16 @@ 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 href={Routes.ForgotPasswordPage()}>
Forgot your password?
</Link>
</div>
</Form>
<div style={{ marginTop: "1rem" }}>
Or{" "}
<Link href={Routes.SignupPage()} passHref>
<a>Sign Up</a>
<Link href={Routes.SignupPage()}>
Sign Up
</Link>
</div>
</div>

View File

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

View File

@@ -1,6 +1,6 @@
import { ErrorFallbackProps, ErrorComponent, ErrorBoundary, AppProps } from "@blitzjs/next"
import { AuthenticationError, AuthorizationError } from "blitz"
import React from "react"
import "src/styles/globals.css"
import { withBlitz } from "src/blitz-client"
function RootErrorFallback({ error }: ErrorFallbackProps) {

View File

@@ -10,14 +10,10 @@ import { useMutation } from "@blitzjs/rpc"
import Link from "next/link"
const ResetPasswordPage: BlitzPage = () => {
const [token, setToken] = useState("")
const router = useRouter()
const token = router.query.token?.toString()
const [resetPasswordMutation, { isSuccess }] = useMutation(resetPassword)
useEffect(() => {
setToken(router.query.token as string)
}, [router.isReady])
return (
<div>
<h1>Set a New Password</h1>

View File

@@ -1,12 +1,11 @@
import { Suspense } from "react"
import Image from "next/image"
import Link from "next/link"
import Layout from "src/core/layouts/Layout"
import { useCurrentUser } from "src/users/hooks/useCurrentUser"
import logout from "src/auth/mutations/logout"
import logo from "public/logo.png"
import { useMutation } from "@blitzjs/rpc"
import { Routes, BlitzPage } from "@blitzjs/next"
import styles from "src/styles/Home.module.css"
/*
* This file is just for a pleasant getting started page for your new app.
@@ -21,7 +20,7 @@ const UserInfo = () => {
return (
<>
<button
className="button small"
className={styles.button}
onClick={async () => {
await logoutMutation()
}}
@@ -38,15 +37,11 @@ const UserInfo = () => {
} else {
return (
<>
<Link href={Routes.SignupPage()} passHref>
<a className="button small">
<strong>Sign Up</strong>
</a>
<Link href={Routes.SignupPage()} className={styles.button}>
<strong>Sign Up</strong>
</Link>
<Link href={Routes.LoginPage()} passHref>
<a className="button small">
<strong>Login</strong>
</a>
<Link href={Routes.LoginPage()} className={styles.loginButton}>
<strong>Login</strong>
</Link>
</>
)
@@ -56,216 +51,142 @@ const UserInfo = () => {
const Home: BlitzPage = () => {
return (
<Layout title="Home">
<div className="container">
<main>
<div className="logo">
<Image src={`${logo.src}`} alt="blitzjs" width="256px" height="118px" layout="fixed" />
</div>
<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 className="buttons" style={{ marginTop: "1rem", marginBottom: "1rem" }}>
<Suspense fallback="Loading...">
<UserInfo />
</Suspense>
</div>
<p>
<strong>
To add a new model to your app, <br />
run the following in your terminal:
</strong>
</p>
<pre>
<code>blitz generate all project name:string</code>
</pre>
<div style={{ marginBottom: "1rem" }}>(And select Yes to run prisma migrate)</div>
<div>
<p>
Then <strong>restart the server</strong>
</p>
<pre>
<code>Ctrl + c</code>
</pre>
<pre>
<code>blitz dev</code>
</pre>
<p>
and go to{" "}
<Link href="/projects">
<a>/projects</a>
</Link>
</p>
</div>
<div className="buttons" style={{ marginTop: "5rem" }}>
<a
className="button"
href="https://blitzjs.com/docs/getting-started?utm_source=blitz-new&utm_medium=app-template&utm_campaign=blitz-new"
target="_blank"
rel="noopener noreferrer"
>
Documentation
</a>
<a
className="button-outline"
href="https://github.com/blitz-js/blitz"
target="_blank"
rel="noopener noreferrer"
>
Github Repo
</a>
<a
className="button-outline"
href="https://discord.blitzjs.com"
target="_blank"
rel="noopener noreferrer"
>
Discord Community
</a>
</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>
<h1>Your database & authentication is ready. Try it by signing up.</h1>
{/* Auth */}
<div className={styles.buttonContainer}>
<Suspense fallback="Loading...">
<UserInfo />
</Suspense>
</div>
</div>
<div className={styles.body}>
{/* Instructions */}
<div className={styles.instructions}>
<p>
<strong>Add a new model by running the following in your terminal:</strong>
</p>
<div>
<div className={styles.code}>
<span>1</span>
<pre>
<code>blitz generate all project</code>
</pre>
</div>
<div className={styles.code}>
<span>2</span>
<pre>
<code>Ctrl + c</code>
</pre>
</div>
<div className={styles.code}>
<span>3</span>
<pre>
<code>blitz dev</code>
</pre>
</div>
<div className={styles.code}>
<span>4</span>
<pre>
<code>
Go to{" "}
<Link href="/projects" className={styles.textLink}>
/projects
</Link>
</code>
</pre>
</div>
</div>
</div>
{/* Links */}
<div className={styles.linkGrid}>
<a
href="https://blitzjs.com/docs/getting-started?utm_source=blitz-new&utm_medium=app-template&utm_campaign=blitz-new"
target="_blank"
rel="noopener noreferrer"
className={styles.card}
>
Blitz Docs
<span className={styles.arrowIcon} />
</a>
<a
href="https://nextjs.org/docs/getting-started"
target="_blank"
rel="noopener noreferrer"
className={styles.card}
>
Next.js Docs
<span className={styles.arrowIcon} />
</a>
<a
href="https://github.com/blitz-js/blitz"
target="_blank"
rel="noopener noreferrer"
className={styles.card}
>
Github Repo
<span className={styles.arrowIcon} />
</a>
<a
href="https://twitter.com/blitz_js"
target="_blank"
rel="noopener noreferrer"
className={styles.card}
>
Blitz Twitter
<span className={styles.arrowIcon} />
</a>
<a
href="https://discord.blitzjs.com"
target="_blank"
rel="noopener noreferrer"
className={styles.card}
>
Discord Community
<span className={styles.arrowIcon} />
</a>
</div>
</div>
</div>
</main>
<footer>
<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}
>
Powered by Blitz.js
Blitz.js
</a>
</footer>
<style jsx global>{`
@import url("https://fonts.googleapis.com/css2?family=Libre+Franklin:wght@300;700&display=swap");
html,
body {
padding: 0;
margin: 0;
font-family: "Libre Franklin", -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}
* {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
box-sizing: border-box;
}
.container {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
main {
padding: 5rem 0;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
main p {
font-size: 1.2rem;
}
p {
text-align: center;
}
footer {
width: 100%;
height: 60px;
border-top: 1px solid #eaeaea;
display: flex;
justify-content: center;
align-items: center;
background-color: #45009d;
}
footer a {
display: flex;
justify-content: center;
align-items: center;
}
footer a {
color: #f4f4f4;
text-decoration: none;
}
.logo {
margin-bottom: 2rem;
}
.logo img {
width: 300px;
}
.buttons {
display: grid;
grid-auto-flow: column;
grid-gap: 0.5rem;
}
.button {
font-size: 1rem;
background-color: #6700eb;
padding: 1rem 2rem;
color: #f4f4f4;
text-align: center;
}
.button.small {
padding: 0.5rem 1rem;
}
.button:hover {
background-color: #45009d;
}
.button-outline {
border: 2px solid #6700eb;
padding: 1rem 2rem;
color: #6700eb;
text-align: center;
}
.button-outline:hover {
border-color: #45009d;
color: #45009d;
}
pre {
background: #fafafa;
border-radius: 5px;
padding: 0.75rem;
text-align: center;
}
code {
font-size: 0.9rem;
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
Bitstream Vera Sans Mono, Courier New, monospace;
}
.grid {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
max-width: 800px;
margin-top: 3rem;
}
@media (max-width: 600px) {
.grid {
width: 100%;
flex-direction: column;
}
}
`}</style>
</div>
</Layout>
)

View File

@@ -9,6 +9,7 @@
padding: 0rem 1rem;
display: flex;
flex-direction: column;
justify-content: space-evenly;
}
.wrapper {
@@ -47,7 +48,7 @@
width: 100%;
flex-direction: row;
align-self: center;
max-width: var(--screen-width);
max-width: calc(min(var(--screen-width), 700px));
}
.instructions {

View File

@@ -14,7 +14,7 @@ vi.mock("public/logo.png", () => ({
test.skip("renders blitz documentation link", () => {
// This is an example of how to ensure a specific item is in the document
// But it's disabled by default (by test.skip) so the test doesn't fail
// when you remove the the default content from the page
// when you remove the default content from the page
// This is an example on how to mock api hooks when testing
vi.mock("src/users/hooks/useCurrentUser", () => ({
@@ -27,6 +27,6 @@ test.skip("renders blitz documentation link", () => {
}))
const { getByText } = render(<Home />)
const linkElement = getByText(/Documentation/i)
const linkElement = getByText(/Blitz Docs/i)
expect(linkElement).toBeInTheDocument()
})

View File

@@ -20,16 +20,16 @@
"@blitzjs/config": "workspace:*",
"@blitzjs/next": "workspace:*",
"@blitzjs/rpc": "workspace:*",
"@prisma/client": "4.6.0",
"@prisma/client": "4.6.1",
"@types/jest": "29.2.2",
"@types/passport-twitter": "1.0.37",
"blitz": "workspace:*",
"jest": "29.3.0",
"jest-environment-jsdom": "29.3.0",
"next": "13.1.2",
"next": "12.2.5",
"passport-mock-strategy": "2.0.0",
"passport-twitter": "1.0.4",
"prisma": "4.6.0",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"ts-node": "10.9.1"

BIN
docs/.github/screenshot.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 868 KiB

2
docs/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.next
node_modules

21
docs/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Shu Ding
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

23
docs/README.md Normal file
View File

@@ -0,0 +1,23 @@
# Nextra Docs Template
This is a template for creating documentation with [Nextra](https://nextra.site).
[**Live Demo →**](https://nextra-docs-template.vercel.app)
[![](.github/screenshot.png)](https://nextra-docs-template.vercel.app)
## Quick Start
Click the button to clone this repository and deploy it on Vercel:
[![](https://vercel.com/button)](https://vercel.com/new/clone?s=https%3A%2F%2Fgithub.com%2Fshuding%2Fnextra-docs-template&showOptionalTeamCreation=false)
## Local Development
First, run `pnpm i` to install the dependencies.
Then, run `pnpm dev` to start the development server and visit localhost:3000.
## License
This project is licensed under the MIT License.

5
docs/next-env.d.ts vendored Normal file
View File

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

14
docs/next.config.js Normal file
View File

@@ -0,0 +1,14 @@
const remarkShikiTwoslash = require('remark-shiki-twoslash')
const withNextra = require('nextra')({
theme: 'nextra-theme-docs',
themeConfig: './theme.config.tsx',
// Not working yet
remarkPlugins: [
[
remarkShikiTwoslash
]
]
})
module.exports = withNextra()

43
docs/package.json Normal file
View File

@@ -0,0 +1,43 @@
{
"name": "nextra-docs-template",
"version": "0.0.1",
"description": "Nextra docs template",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"repository": {
"type": "git",
"url": "git+https://github.com/shuding/nextra-docs-template.git"
},
"author": "Shu Ding <g@shud.in>",
"license": "MIT",
"bugs": {
"url": "https://github.com/shuding/nextra-docs-template/issues"
},
"homepage": "https://github.com/shuding/nextra-docs-template#readme",
"dependencies": {
"@blitzjs/auth": "workspace:2.0.0-beta.23",
"@blitzjs/next": "workspace:2.0.0-beta.23",
"@blitzjs/rpc": "workspace:2.0.0-beta.23",
"@mdx-js/loader": "2.3.0",
"@mdx-js/react": "2.3.0",
"@next/mdx": "13.2.3",
"@octokit/rest": "19.0.7",
"blitz": "workspace:2.0.0-beta.23",
"next": "^13.0.6",
"nextra": "latest",
"nextra-theme-docs": "latest",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"remark-shiki-twoslash": "3.1.1"
},
"devDependencies": {
"@types/node": "18.11.10",
"autoprefixer": "10.4.13",
"postcss": "8.4.21",
"tailwindcss": "3.2.7",
"typescript": "^4.9.3"
}
}

2172
docs/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

6
docs/postcss.config.js Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@@ -0,0 +1,6 @@
.counter {
border: 1px solid #ccc;
border-radius: 5px;
padding: 2px 6px;
margin: 12px 0 0;
}

View File

@@ -0,0 +1,24 @@
// Example from https://beta.reactjs.org/learn
import { useState } from 'react'
import styles from './counters.module.css'
function MyButton() {
const [count, setCount] = useState(0)
function handleClick() {
setCount(count + 1)
}
return (
<div>
<button onClick={handleClick} className={styles.counter}>
Clicked {count} times
</button>
</div>
)
}
export default function MyApp() {
return <MyButton />
}

5
docs/src/pages/_app.mdx Normal file
View File

@@ -0,0 +1,5 @@
import "../styles/nextra.css";
export default function App({ Component, pageProps }) {
return <Component {...pageProps} />
}

38
docs/src/pages/_meta.json Normal file
View File

@@ -0,0 +1,38 @@
{
"index": {
"title": "Home",
"theme": {
"layout": "raw"
}
},
"docs": {
"title": "Documentation",
"type": "page"
},
"tutorial": {
"title": "Tutorial",
"type": "page"
},
"showcase": {
"title": "Showcase",
"type": "page"
},
"releases": {
"title": "Releases ↗",
"type": "page",
"href": "https://github.com/blitz-js/blitz/releases",
"newWindow": true
},
"swag": {
"title": "Swag ↗",
"type": "page",
"href": "https://store.blitzjs.com/",
"newWindow": true
},
"deploy": {
"title": "Deploy With Flightcontrol ↗",
"type": "page",
"href": "https://flightcontrol.dev/?ref=blitzjs",
"newWindow": true
}
}

View File

@@ -0,0 +1,44 @@
{
"introduction": "Introduction",
"community": "Community",
"basics": "Basics",
"framweworks": "Framework Adapters",
"blitz-auth": "Blitz Auth",
"blitz-rpc": "Blitz RPC",
"blitz-recipies": "Blitz Recipies",
"blitz-generator": "Blitz Generator",
"backend-architecture": "Backend Architecture",
"databse": "Database",
"cli" : "CLI",
"migration":"Migration Guides",
"docs": {
"title": "Documentation",
"type": "page"
},
"tutorial": {
"title": "Tutorial",
"type": "page"
},
"showcase": {
"title": "Showcase",
"type": "page"
},
"releases": {
"title": "Releases ↗",
"type": "page",
"href" : "https://github.com/blitz-js/blitz/releases",
"newWindow": true
},
"swag": {
"title": "Swag ↗",
"type": "page",
"href" : "https://store.blitzjs.com/",
"newWindow": true
},
"deploy": {
"title": "Deploy With Flightcontrol ↗",
"type": "page",
"href": "https://flightcontrol.dev/?ref=blitzjs",
"newWindow": true
}
}

View File

@@ -0,0 +1,9 @@
{
"how-the-community-operates": "How the Community Operates",
"manifesto": "Manifesto",
"history": "History",
"contributing": "How to Contribute",
"maintainers": "Being a Maintainers",
"code-of-conduct": "Code of Conduct",
"translations": "Doc Translations"
}

View File

@@ -0,0 +1,111 @@
# The Blitz Community Code of Conduct
The Blitz core members take this CoC very serious. All members,
contributors and volunteers in this community are required to act
according to the following Code of Conduct to keep Blitz a positive,
growing project and community and help us provide and ensure a safe
environment for everyone.
## When Something Happens
If you see a Code of Conduct violation, follow these steps:
1. Let the person know that what they did is not appropriate and ask them
to stop and/or edit their message(s).
2. That person should immediately stop the behavior and correct the issue.
3. If this doesnt happen, or if youre uncomfortable speaking up, contact
Brandon Bayer ([Twitter](https://twitter.com/flybayer) |
[Email](mailto:b@bayer.ws)).
When reporting, please include any relevant details, links, screenshots,
context, or other information that may be used to better understand and
resolve the situation.
The core members will prioritize the well-being and comfort of the
recipients of the violation over the comfort of the violator.
## What We Believe and How We Act
- We are committed to providing a friendly, safe and welcoming environment
for everyone, regardless of age, body size, culture, ethnicity, gender
expression, gender identity, level of experience, nationality, personal
ability or disability, physical appearance, physical or mental
difference, race, religion, set of skills, sexual orientation,
socio-economic status, and subculture. We welcome people regardless of
these or other attributes.
- We are better together. We are more alike than different.
- Our community is based on mutual respect, tolerance, and encouragement.
- We believe that a diverse community where people treat each other with
respect is stronger, more vibrant and has more potential contributors
and more sources for ideas. We aim for more diversity.
- We are kind, welcoming and courteous to everyone.
- Were respectful of others, their positions, their skills, their
commitments and their efforts.
- Were attentive in our communications, whether in person or online, and
were tactful when approaching differing views.
- We are aware that language shapes reality. Thus, we use inclusive,
gender-neutral language in the documents we provide and when we talk to
people. When referring to a group of people, we aim to use
gender-neutral terms like “team”, “folks”, “everyone”. (For details, we
recommend
[this post](https://modelviewculture.com/pieces/gendered-language-feature-or-bug-in-software-documentation)).
- We respect that people have differences of opinion and criticize
constructively.
- We value people over code.
## Don'ts
- Dont discriminate against anyone.
- Sexism and racism of any kind (including sexist and racist “jokes”),
demeaning or insulting behaviour and harassment are seen as direct
violations to this Code of Conduct. Harassment includes offensive verbal
comments related to age, body size, culture, ethnicity, gender
expression, gender identity, level of experience, nationality, personal
ability or disability, physical appearance, physical or mental
difference, race, religion, set of skills, sexual orientation,
socio-economic status, and subculture. Harassment also includes sexual
images in public spaces, deliberate intimidation, stalking, following,
harassing photography or recording, inappropriate physical contact, and
unwelcome sexual attention.
- On Discord and other online or offline communications channels, don't
use overtly sexual nicknames or other nicknames that might detract from
a friendly, safe and welcoming environment for all.
- Dont be mean or rude.
- Respect that some individuals and cultures consider the casual use of
profanity offensive and off-putting.
- Unwelcome / non-consensual sexual advances over Discord or any other
channels related with this community are not okay.
- Derailing, tone arguments and otherwise playing on peoples desires to
be nice are not welcome, especially in discussions about violations to
this Code of Conduct.
- Please avoid unstructured critique.
- Likewise any spamming, trolling, flaming, baiting or other
attention-stealing behavior is not welcome.
- Sponsors of Blitz are also subject to this Code of Conduct. In
particular, sponsors are required to not use sexualized images,
activities, or other material which is not according to this Code of
Conduct.
## Consequences for Violations to this Code of Conduct
If a participant engages in any behavior violating this Code of Conduct,
the core members of this community will take any action they deem
appropriate, starting with a gentle warning and then escalating as needed
to expulsion from the community, exclusion from any interaction and loss
of all rights in this community.
## Decisions About Consequences of Violations
Decisions about consequences of violations of this Code of Conduct are
made by this communitys core members and may not be discussed with the
person responsible for the violation.
## For Questions or Feedback
If you have any questions or feedback on this Code of Conduct, were happy
to hear from you.
## Thanks for Inspiration
- [Hoodie](https://github.com/hoodiehq/hoodie)
- [WeAllJS](https://wealljs.org/code-of-conduct)

View File

@@ -0,0 +1,268 @@
# How to Contribute
import { Callout, Tab, Tabs, Steps } from 'nextra-theme-docs'
👋 We're so excited you're interested in helping with Blitz! We happy to
help you get started, even if you don't have any previous open-source
experience
## First Things First
1. New to open source? take a look at
[How to Contribute to an Open Source Project on GitHub](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github)
2. Familiarize yourself with the
[Blitz Code of Conduct](./code-of-conduct)
3. Learn [how the community operates](./how-the-community-operates)
## What to Work On?
Issues with the label
[`status/ready-to-work-on`](https://github.com/blitz-js/blitz/labels/status%2Fready-to-work-on)
are the best place to start.
We also label issues as `good first issue` and `good second issue` when
appropriate.
If you find one that looks interesting and no one else is already working
on it, comment in the issue that you are going to work on it. But only
claim an issue if you can start work on it within a couple days.
Please ask as many questions as you need, either directly in the issue or
in Discord. We're happy to help!
The Blitzjs.com website and documentation repo also has issues with
[`ready to work on | help wanted`](https://github.com/blitz-js/blitzjs.com/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22ready+to+work+on+%7C+help+wanted%22).
### Things that are ALWAYS welcome
- Adding tests
- Improved documentation
- Improved error messages
- Improved logging (i.e. more clear, more beautiful)
- Performance or security improvements
- Educational content like blogs, videos, courses
If there's some other way you'd like to contribute, ask us about it in
Discord!
After you contribute in any way, please add yourself as a contributor via
the
[@all-contributors bot](https://allcontributors.org/docs/en/bot/usage)!
## Our Codebase is a Garden
The Blitz codebase is like a community garden. There's a lot of beautiful
plants and vegetables, but it won't take long until you find some weeds!
When you find weeds, please remove them. Minor refactoring is always
encouraged. If you'd like to do some major refactoring, it's best to first
either open an issue or check with us in Discord. Most likely we'll agree
with you.
## What to Expect After Submitting a PR
A Blitz maintainer will review your PR, usually within a couple days.
If your PR changes user facing code, make sure you also made a PR to the
docs repo, otherwise this will block your PR from being merged.
You also need to add tests to cover the changes you made.
Once all the requirements are met and the maintainer is happy with your
code, they will merge it to the canary branch. It will then be included in
the next Blitz release.
Lastly, you will be added the all-contributors list as an official Blitz
contributor. **Congratulations!!**
## Project Management
We use a
[GitHub Project Board](https://github.com/blitz-js/blitz/projects/4) to
track all issues and PRs.
## Commit Access
We give liberal commit access to the Blitz repo to anyone who is a
half-way regular contributor. This allows you to push branches directly to
the Blitz repo without using a fork.
We'll often give someone access if we notice they are regularly
contributing. But you're also welcome to ask for access if you are
regularly helping but haven't been given access yet.
In the main Blitz repo, code reviews by code owners are required to merge
PRs.
But in the docs repo, anyone can merge PRs once someone else has approved
the PR.
## Development Setup
Make sure you're using Node 14 — Next uses `node-sass` which does not work
with newer Node versions.
<Steps>
### Fork [the blitz repo](https://github.com/blitz-js/blitz)
### Clone your forked repo
```sh
# replace USERNAME below with your GitHub username
git clone git@github.com:USERNAME/blitz.git
cd blitz
```
### (Optional, macOS only) Install required packages for
`sodium-native`
If you spot any issues related to `sodium-native`, run the following
command to fix it:
```sh
brew install autoconf automake
```
### Install dependencies
```sh
pnpm i
```
### Start the package server. This **must be running** for any package
development or example development
```sh
pnpm dev
```
</Steps>
## Running Tests
### Blitz.js Tests
#### Unit Tests
Most Blitz packages in `packages/` have vitest unit tests.
- Run tests in a single package by running `pnpm test` inside that package
folder (like `packages/blitz-next`)
- Run all unit tests from the repo root by running `pnpm test`. (Make sure
you have ran `pnpm build` or `pnpm dev` prior to running this). Note:
this will run all tests, including integration tests.
#### Integration Tests
Blitz integration tests are inside the root `integration-tests/` folder.
Make sure you have `chromedriver` installed for your Chrome version. You
can install it with
- `brew install --cask chromedriver` on Mac OS X
- `chocolatey install chromedriver` on Windows
- Or manually download the version that matches your installed chrome
version (if there's no match, download a version under it, but not
above) from the
[chromedriver repo](https://chromedriver.storage.googleapis.com/index.html)
and add the binary to `<blitz-repo>/node_modules/.bin`
You can run all tests (both unit tests and integration tests) by running
`pnpm test` from the repo root.
You can manually run the integration app by running `blitz dev` inside the
integration test folder, like `integration-tests/auth/`.
### Testing Development Version of Blitz Inside an App
<Callout>
Currently, to test the local dev version of Blitz, you can test an app
inside the `blitz/apps/` folder. In there, the blitz dependency will
automatically use the local dev version. We use it for development
testing. You must also make sure you are running `pnpm dev` in the `blitz`
folder at the same time.
</Callout>
#### Link the Blitz CLI (Optional)
The following will link the development CLI as a local binary so you can
use it anywhere for testing.
```sh
pnpm link ./packages/blitz
```
## Doing A Releas
We use the [changesets](https://github.com/changesets/changesets) package
& a forked version of their GitHub action which can be found here:
[GitHub - blitz-js/changesets-action](https://github.com/blitz-js/changesets-action).
Every user facing PR should have a changeset. When that PR gets approved
and merged to the `main` branch the "release" PR with the name
`Version packages (beta)` is automatically created or updated. This PR
updates each internal package's changelog & each blitz package's version
by incrementing it in the `package.json` files.
Once the auto generated PR accumulates enough changesets, It's time to do
a release by merging this PR into the `main` branch. To trigger the
release action, you must squash and merge the PR without waiting for the
requirements to be met, bypassing the branch protections rule. This is
because the CI doesn't run on PR's generated by a github action. Once you
merge this PR, it will generate the release action and publish on npm &
create a release on GitHub.
The auto generated release on GitHub, still requires some manual cleaning.
It's recommended to remove some "fluff" like:
```
Updated dependencies [3b213a3]
@blitzjs/rpc@2.0.0-beta.18
```
It's also important to note, that since we haven't done a stable release
yet that we're in a pre-release mode set with the `changesets` package. So
with that being said, you will need to uncheck the `Set as a pre-release`
checkbox while editing the release on Github, and selecting
`Set as the latest release` checkbox.
While on the category of being in prerelease mode with the `changesets`
package, when published to npm we also want to ensure that each package
gets tagged with `latest`. This requires manual work and the correct npm
permissions. _This is mostly for our internal team._ For each package run:
```shell
npm dist-tag add blitz@2.0.0-beta.18 latest
npm dist-tag add @blitzs/auth@2.0.0-beta.18 latest
npm dist-tag add @blitzs/rpc@2.0.0-beta.18 latest
npm dist-tag add @blitzs/next@2.0.0-beta.18 latest
```
For more information about `changesets` pre-release mode, you can read
their documentation here:
[changesets/prereleases.md at main · changesets/changesets · GitHub](https://github.com/changesets/changesets/blob/main/docs/prereleases.md)
## Troubleshooting
If you run into issues that should be documented here, please submit a PR!
❤️
#### Git errors
Are you unable to commit? Do you get errors like `command not found` or
`stdin is not a tty`? That's probably a Husky error! Try checking their
[troubleshoot guide](https://typicode.github.io/husky/#/?id=troubleshoot).
#### Preconstruct errors
If you run into symlink and EPERM errors when trying to run Preconstruct
on Windows, you may need to enable
[Windows Developer Mode](https://www.howtogeek.com/292914/what-is-developer-mode-in-windows-10/)
so that Preconstruct can create symlinks.
#### Missing files in Windows
If you have errors about missing files even after you run `pnpm build`,
try cloning again your repository with the configuration `core.symlinks`
set to `true` like this: `git clone -c core.symlinks=true <URL>`.

View File

@@ -0,0 +1,47 @@
# Community History
All throughout 2019, Brandon Bayer was wanting something like Ruby on
Rails but for Javascript and React. If you search Twitter history, you'll
see him tweeting about this every so often, saying things like "_someone
please make this so I don't have to._" 😂
Finally in February 2020, Brandon had a phone call with a Ruby on Rails
developer friend. This call sparked him to finally try making Rails for
React. It seemed like good timing with all the new features in Next.js and
Prisma 2 being released in beta.
One week later, Brandon
[officially announced Blitz on February 17, 2020](https://twitter.com/flybayer/status/1229425878481793024).
At the time he only had a couple hundred lines of prototype code. But the
idea resonated with so many people, that many jumped in and helped
architect and build the very first alpha version.
In other words, Brandon essentially built the Blitz community before
building the project.
This turned out to be a great decision.
[38 amazing people](https://github.com/blitz-js/blitz/tree/ab6f60571ad61eef6be55e9684f2e243fa902e8d#contributors-)
contributed to the first alpha which was
[released on April 24, 2020](https://twitter.com/flybayer/status/1253649008540569600).
**The official beta version, 0.30.0, was
[released on the 1 year anniversary, February 17, 2021](https://twitter.com/flybayer/status/1362048912476016642)!**
In March 2021, we made the decision to fork Next.js, with an expectation
that Blitz would start to carve out a small portion of Next.js users. But
that hasn't happened. In fact, we think the fork has hurt adoption and our
growth has stagnated that year.
In December 2021, we proposed to pivot Blitz to a fullstack,
framework-agnostic toolkit that preserves the world-class DX and features
we adore but brings it to all Next.js users and optionally Remix,
SvelteKit, Nuxt, etc. You can read the RFC
[here](https://github.com/blitz-js/blitz/discussions/3075).
Soon after the pivot proposal, we started working on it, and released the
first alpha version in May 2022. Brandon has announced it for the first
time during React Miami conference. You can check out the recording
[here](https://www.youtube.com/watch?v=TWkjl_jg3Jk&ab_channel=JSWORLDConference).
Currently the core team is working towards the stable version of the
Blitz.js Toolkit.

View File

@@ -0,0 +1,151 @@
# How the Community Operates
## 🤝 Blitz is a Community Project
Blitz [was initially started by Brandon Bayer](./community-history), but
from the very beginning it's always been a community project. 38 people
contributed to the very first alpha version!
All other contributors help in their free time. We now have
[over 350 total contributors](https://github.com/blitz-js/blitz#contributors-)!
**Because Blitz is a community project, the entire community gets to help
shape Blitz and where it goes in the future.**
## Where to Ask Questions
First, search [the Blitz Discord](https://discord.blitzjs.com) and
[the GitHub repo](https://github.com/blitz-js/blitz) to see if someone has
already asked your question.
Next,
[post your question in our Discussion Forum](https://github.com/blitz-js/blitz/discussions).
This is much better than Discord as it's easier for people to find and
link to.
Then you're welcome to post a link to your Discussion thread in Discord,
because GitHub Discussions don't have a Discord notification integration
yet.
🙏 As you gain experience with Blitz, please help answer other peoples
questions!
## How to Report a Bug
First,
[search existing GitHub issues](https://github.com/blitz-js/blitz/issues?q=is%3Aissue)
so see if someone has already reported your issue.
If not, then please
[open a new issue](https://github.com/blitz-js/blitz/issues/new/choose)!
Someone will usually reply to your new issue within a day or two.
If you want to report an issue for the legacy Blitz framework, please do
it in [this repository](https://github.com/blitz-js/legacy-framework).
## Roadmap
Currently the core team is working on getting the Blitz Toolkit to the
stable version, which mostly means smoothing rough edges and fixing bugs.
However, anyone else is more than welcome to continue adding major
features!
Our [GitHub issues](https://github.com/blitz-js/blitz/issues) are where
you can find our roadmap. Many planned features have GitHub issues, but
not necessarily all of them do.
## How to Propose Features/Changes
We love ideas and suggestions for how to make Blitz better! But please
keep in mind we have a lot more feature ideas than contributor time to
make them all happen. So it'd be great if you can make a PR too!
### Minor Changes
For minor changes like adding a new CLI flag or something, simply
[open a new GitHub issue](https://github.com/blitz-js/blitz/issues/new/choose).
### Everything Else: RFCs
For any other features, even as small as adding a single new React hook,
please post your request as an RFC (Request for Comments) as a
[GitHub Discussion Thread](https://github.com/blitz-js/blitz/discussions/category_choices).
To post an RFC, do the following:
- Start the title with `[RFC]`
- Include the following sections
- `### What do you want and why?`
- `### How is this different from what you are currently doing?`
- `### Possible implementation(s)`
- After posting, please also share it in Discord in
`#request-for-comments`.
## Your Role
As a member of the Blitz community, we value your input, ideas,
suggestions, and help!
Please feel very welcome to comment on any GitHub issue, pull request,
RFC, etc! The community as a whole gets to shape where Blitz goes!
As you gain experience, we greatly appreciate your help including but not
limited to, answering people's questions, reviewing PRs, improving
documentation, submitting PRs, etc.
## How to Level Up in the Community
You can gain respect and influence in our community by being regularly
involved, being helpful, and being nice.
We have two official maintainer levels you can read about below, but you
are more than welcome to do the work of a maintainer before being
acknowledged as such. In fact doing the work of a maintainer is one of the
best ways to level up in the community.
Another great way to level up is by teaching people about Blitz and
helping them be successful Blitz developers. This can by blog posts,
videos, courses, etc.
## NPM Releases
Currently we have automated alpha releases for every commit to the `main``
barnch.
## Finances
[Flightcontrol](http://flightcontrol.dev/) is paying Aleksandra Sikora for
her Lead Maintainer role, and Dillon Raphael for his Senior Blitz.js
Maintainer role.
We also **really appreciate when companies who use Blitz pay their
employees** to contribute to Blitz, either part-time or full-time!
## Core Team
The Blitz core team consists of people who are deeply invested in Blitz.
The core team has GitHub, Discord, and npm admin permissions. People can
become core members by starting as a level 1 maintainer, becoming a level
2 maintainer, and then on to the core team.
## L2 Maintainers
Level 2 maintainers are the backbone of the community and are responsible
for reviewing and merging PRs. They are watchdogs over the code, ensuring
code quality, correctness, and security. They also help facilitate a rapid
pace of progress.
For more details, see [Being an L2 Maintainer](./maintainers)
## L1 Maintainers
Level 1 maintainers primarily help manage the community and triage issues.
They are critical for a healthy Blitz community. They take a lot of burden
off the core team and level 2 maintainers so they can focus on higher
level things with longer term impact.
For more details, see [Being an L1 Maintainer](./maintainers)

View File

@@ -0,0 +1,167 @@
# ❤️ Blitz Maintainers
Aside from the core team, there are two levels of maintainers, described
below.
## Becoming a Maintainer
We always need more level 1 maintainers! The main requirement is that you
can show empathy when communicating online. We'll train you as needed on
the other specifics. **This is a great role if you have limited time,
because you can spend as much time as you have without any ongoing
responsibilities (unlike level 2)**
Level 2 maintainers have a much higher responsibility, so usually you will
spend time as a level 1 maintainer before moving to level 2.
Please DM a core team member (Brandon Bayer) in Discord if you're
interested in becoming an official maintainer!
## Level 1 Maintainers
Level 1 maintainers are critical for a healthy Blitz community and
project. They take a lot of burden off the core team and level 2
maintainers so they can focus on higher level things with longer term
impact.
The primary responsibilities of level 1 maintainers are:
- Being a friendly, welcoming voice for the Blitz community
- Issue triage
- Pull request triage
- Monitor and answer the Discord help channels
- Following up on assigned issues to make sure they are being worked on
- Following up on in-progress PRs to make sure they don't get stuck
- Community encouragement
- Community moderation
## Level 2 Maintainers
Level 2 maintainers are the backbone of the project. They are watchdogs
over the code, ensuring code quality, correctness, and security. They also
facilitate a rapid pace of progress.
The primary responsibilities of level 2 maintainers are:
- Code ownership over specific parts of the project
- Maintaining and improving the architecture of what they own
- Final pull request reviews
- Merging pull requests
- Tracking and ensuring progress of open pull requests
## Retiring
Maintainers may retire from their role at any time without any shame or
guilt. Simply let a core team member know!
## ⚠️ Fundamentals
Maintainers are the face of the project and the front-line touch point for
the community. Therefore maintainers have the very important
responsibility of making people feel welcome, valued, understood, and
appreciated.
**Please take time to read and understand everything outlined in this
[guide on building welcoming communities](https://opensource.guide/building-community)**
Some especially important points:
- **Gratitude:** immediately express gratitude when someone opens an issue
or PR. This takes effort/time and we appreciate it
- **Responsiveness:** during issue/PR triage, even if we cant do a full
review right away, leave a comment thanking them and saying well review
it soon
- Our goal is to respond to all issues and PRs within 2 days, but
ideally within 1 day.
- **Understanding:** it's critical to ensure you understand exactly what
someone is saying before you respond. Ask plenty of questions if needed.
It's very bad if someone has to reply to your response and say "actually
I was asking about X"
- In fact, at least one question is almost always required before you
can respond appropriately  — whether in GitHub or in Discord
### Resources
- [How to Be Helpful Online](https://nedbatchelder.com/blog/202009/how_to_be_helpful_online.html)
- [How to Start Reviewing Code](https://shubheksha.com/posts/2019/03/how-to-start-reviewing-code/)
## Monitoring Discord
- We want every single question to get a response, ideally within a day,
or 2 at max. But this doesn't mean you have to solve their problem. For
example, if they ask about some random library you know nothing about,
you can respond saying you aren't familiar with that, but that they
could try looking for examples/docs on using it with nextjs, since the
integration would the same.
- Ensure threads are used as much as possible to keep channels organized.
Even if there are a few messages about a topic in the main channel and
the issue/question is not resolved, go ahead and create a thread and
respond in the thread.
- If someone reports something that's likely a bug, kindly ask them to
open an issue on Github
- If someone requests a feature or change, kindly ask them to open a
feature request issue on Github
- If you notice some type of DX issue or opportunity for improvement in
any conversation, please open an issue on Github for this. Making lots
of tiny improvements over the long has compounding returns
- If someone asks a question about something that either doesn't have docs
or isn't documented well, then take a minute to go add the docs for
that. And then paste a link to the new docs you added.
## Issue Triage
#### If a bug report:
- Does it have enough information? Versions? Logs? Some way to reproduce?
- Has this already been fixed in a previous release?
- Is there already an existing issue for this?
### If a feature/change request:
- Is it clear what the request is and what the benefit will be?
- Is this an obvious win for Blitz? Then accept it
- If not obvious, then pull in a core team member or level 2 maintainer
for more review
### Actions
1. Add tags:
- Add a `status/*` tag
- Add a `kind/*` tag
- Add a `scope/*` tag
- Add a good first/second issue tag if appropriate
## Pull Request Triage
- Are the changes covered by tests?
- Do the changes look ok? Make sure there's no obvious issues
- If applicable, has a PR been opened to update the docs?
### Actions
1. Kindly request any changes if needed
2. Else add a GitHub approval so that level 2 maintainers know it's
already had an initial review
## Final PR Review & Merging (Level 2 maintainers)
As a level 2 maintainer, it is your responsibility to make sure broken
code and regressions never reach the canary branch.
1. Ensure the PR'ed code fully works as intended and that there are no
regressions in related code
1. If not fully covered by automated tests, you need to pull down the
code locally and manually verify everything (the GitHub CLI helps
with this!)
2. During squash & merge:
1. Change the commit title to be public friendly - this exact text will
go in the release notes
2. Add the commit type in the description, in parenthesis like
`(patch)`. Commit types:
- `major` - major breaking change
- `minor` - minor feature addition
- `patch` - patches, bug fixes, perf improvements, etc
- `newapp` - changes to the new app template
- `recipe` - changes to a Blitz recipe
- `example` - change to an example app
- `meta` - internal meta change related to the Blitz repo/project

View File

@@ -0,0 +1,95 @@
# The Blitz.js Manifesto
## Background
Technology follows a repeating cycle of bundling and unbundling. Created
in 2005, Ruby on Rails became a major bundling force. It made web
application development easier and more accessible than ever before. This
benefited everyone, from those learning programming to seniors building
production systems.
A major unbundling happened in 2013 with the release of React because it
is hyper focused on the rendering layer. As React grew in popularity, so
did the choices for all the other parts, leaving developers with hundreds
of decisions to make when starting a new app. While this has contributed
to JavaScript Fatigue, it's been a powerful driving force for rapid
frontend innovation.
Now, in 2020, is the perfect time for another major bundling. Developers
are yearning for an easier, simpler way to build web applications.
Beginners want a guiding hand for building a robust app. And seniors want
a framework that removes mundane tasks and provides a highly scalable
architecture.
Hence the creation of Blitz.
## What is Blitz For?
Blitz is for building tiny to large fullstack database-backed applications
that have one or more graphical user interfaces like web or mobile apps.
## Foundational Principles
1. Fullstack & Monolithic
2. Convention over Configuration
3. Loose Opinions
4. Easy to Start, Easy to Scale
5. Community over Code
### 1. Fullstack & Monolithic
A fullstack, monolithic application is simpler than an application where
frontend and backend are developed and deployed separately. Monolithic
doesn't mean it will be slow or hard to scale to large teams. Monolithic
doesn't mean there isn't separation of concerns. Monolithic means you can
reason about your app as a single entity.
### 2. Convention over Configuration
Starting a new fullstack React app is currently too hard. You have to
spend days on things like configuring eslint, prettier, husky, vitest,
cypress, typescript, deciding on a file structure, setting up a database,
adding authentication and authorization, setting up a router, defining
routing conventions, and setting up your styling library.
Blitz makes as many decisions and does as much work for you as possible.
This makes it lightning fast to start real development. It also greatly
benefits the community. Common project structure and architectural
patterns make it easy to move from Blitz app to Blitz app and immediately
feel at home.
Convention over configuration doesn't mean no configuration. It means
configuration is optional. Blitz will provide all the escape hatches you
need for bespoke customization.
### 3. Loose Opinions
Blitz is opinionated. The out-of-the-box experience guides you on a path
perfect for most applications. However, Blitz isn't arrogant. It
understands there are very good reasons for deviating from convention, and
it allows you to do so. For example, Blitz has a conventional file
structure, but, with few exceptions, doesn't _enforce_ it.
And when there's not community consensus, `blitz new` prompts you to
choose.
### 4. Easy to Start, Easy to Scale
A framework that's only easy for one end of an application lifecycle is
not a good framework. Both starting and scaling must be easy.
Easy to start includes being easy for beginners and being easy to migrate
existing Next.js apps to Blitz.
Scaling is important in all forms: lines of code, number of people working
in the codebase, and code execution.
### 5. Community over Code
The Blitz community is the most important aspect of the framework, by far.
We have a comprehensive [Code of Conduct](./code-of-conduct).
We are all in this together, from the youngest to the oldest. We are all
more similar than we are different. We can and should solve problems
together. We should learn from other communities, not compete against
them.

View File

@@ -0,0 +1,11 @@
# Help Us Translate Blitz Docs
Blitz.js is used by many people arround the world, and we want them to be
comfortable navigating the documentation and using Blitz.
In the [languages](/languages) page, you'll see the translation progress
of each language. You can click on **Contribute** and create a Pull
Request with your contribution!
If your language isn't being translated and you want to work on it, read
[these instructions](https://github.com/blitz-js/blitzjs.com-translation/blob/main/README.md).

View File

@@ -0,0 +1,5 @@
{
"why-blitz": "Why Blitz?",
"learning": "Learning Path",
"nextjs": "With Existing Nextjs App"
}

View File

@@ -0,0 +1,110 @@
import { Callout } from 'nextra-theme-docs'
# Learning Path
Want to get better at developing applications using Blitz, but don't know
where to start? You've come to the right spot.
This document is inspired by the
[Frontend Developer Roadmap](https://roadmap.sh/frontend). It curates
material on concepts & ideas, tools & libraries and history & trivia
useful to become better at building applications. It is tailored to Blitz,
but most will happily apply elsewhere.
<Callout>
Links marked with 🥷 are advanced. If you're dipping your toes into web
development, it's totally OK to skip them.
</Callout>
## React
- [React for Beginners A React.js Handbook for Front End Developers](https://www.freecodecamp.org/news/react-beginner-handbook) -
Big introduction into React, including Function Components and Hooks.
- 📺
[freeCodeCamp's Full React Course 2020](https://www.youtube.com/watch?v=4UZrsTqkcW4) -
10hrs video introduction to React.
- 📺
[The Beginner's Guide to React](https://egghead.io/courses/the-beginner-s-guide-to-react) -
Kent C. Dodds short introduction to React, including Function
Components.
## Databases & Data Modeling
- [Prisma's Data Guide: Data Modeling](https://www.prisma.io/dataguide/datamodeling) -
A great introduction on constructing a good database schema for your
application.
- [What is Prisma?](https://www.prisma.io/docs/concepts/overview/what-is-prisma) -
A high-level overview on what Prisma is & how it works.
- 🥷
[Zero-Downtime Deployments with Data Migrations](https://engineering.wework.com/zero-downtime-deployments-with-data-migrations-2e337df48b8f) -
How to change your database schema without causing downtimes.
- Want to contribute to this part? Submit your favourite learning
materials in a PR! Here's some ideas for content we know we're missing:
- a guide on building multi-tenant applications
## Integrations
- Want to contribute to this part? Submit your favourite learning
materials in a PR! Here's some ideas for content we know we're missing:
- sending emails
- how to hook up stripe
- how to hook up Paddle
- what payment provider to choose
## Background Processing & Cron Jobs
- Want to contribute to this part? Submit your favourite learning
materials in a PR! Here's some ideas for content we know we're missing:
- how Cron expressions work
- what to use background processing for
- implementing cron jobs
## Testing
Automated tests are a great way of verifying that your application works -
and who doesn't want working software?
- 💸 [Testing Javascript](https://testingjavascript.com) - A thorough
curriculum on everything test-related. By Kent C. Dodds.
- Want to contribute to this part? Submit your favourite learning
materials in a PR! Here's some ideas for content we know we're missing:
- Introduction to the testing pyramid
- unit testing using Vitest
- writing code to be testable
- cypress guide
## Software Architecture
As your application grows bigger, some structure may be neccessary.
There's a million ways on how to structure your project, here's some good
guidance:
- Want to contribute to this part? Submit your favourite learning
materials in a PR! Here's some ideas for content we know we're missing:
- 🥷 TODO: a good guide on onion / clear architecture
## Soft Skills
Building software is highly communicative and rarely a solo effort.
Working in a team requires soft skills.
- [How to Make Your Code Reviewer Fall in Love with You](https://mtlynch.io/code-review-love/) -
Code Reviews are a great when done well, and awful when not. Read this
article to 1-up your own PRs!
- Want to contribute to this part? Submit your favourite learning
materials in a PR!
## Building Products
Building a product is more than building an application. Finding the right
business model, evaluating ideas, getting valuable feedback, building a
customer base - all of this is very different from building software. If
you're building a product (there's a fair share of entrepreneurs amongst
Blitz users!), this is for you:
- [The Mom Test](http://momtestbook.com) - A book on getting honest
customer feedback.
- Want to contribute to this part? Submit your favourite learning
materials in a PR!

View File

@@ -0,0 +1,123 @@
# Add Blitz.js to an Existing Next.js Project
import {Callout, Tab, Tabs, Steps} from "nextra-theme-docs"
If you have an existing Next.js project and would like to use some or all
of Blitz Toolkit, this page will provide you with information on setting
it up. A few steps are required, and we'll go through them one by one.
## Installing Blitz
<Steps>
### Adding required dependencies
<Tabs items={["pnpm", "npm", "yarn"]}>
<Tab>
```sh
pnpm add blitz @blitzjs/next
```
</Tab>
<Tab>
```sh
npm i blitz @blitzjs/next
```
</Tab>
<Tab>
```sh
yarn add blitz @blitzjs/next
```
</Tab>
</Tabs>
### Blitz server setup
If you want to use Blitz's server functionalities like auth, middlewares,
rpc, you'd need to create a `blitz-server.ts` file somewhere in your
project, e.g. in `src/blitz-server.ts`. We'll cover how to add plugins
later.
```ts twoslash
import {setupBlitzServer} from "@blitzjs/next"
const {
/* plugins' exports */
} = setupBlitzServer({
plugins: [
// plugins will go here
],
})
```
### Blitz client setup
Now, if you want Blitz's client functionalities, you'll have to create a
`blitz-client.ts` file. It can be next to the `blitz-server.ts` in
`src/blitz-client.ts`.
```ts twoslash
import {setupBlitzClient} from "@blitzjs/next"
export const {withBlitz} = setupBlitzClient({
plugins: [
// plugins will go here
],
})
```
The `withBlitz` function will be needed to wrap your components with
Blitz's client side functionality.
### Use `withBlitz` in your App component
To use Blitz on the client, you also have to use the `withBlitz` function
in your App component.
```ts twoslash
import {withBlitz} from "src/blitz-client"
function App({Component, pageProps}: AppProps) {
return <Component {...pageProps} />
}
export default withBlitz(App)
```
### Modifying `next.config.js` file
Next.js requires you to manually type out page locations. Blitz comes with
a [Route Manifest](./route-manifest), so you can do:
```ts twoslashx
<Link href={Routes.ProductsPage({ productId: 123 })} />
// instead of
<Link href={`/products/${123}`} />
```
To enable it, you have to wrap your config with `withBlitz` in the
`next.config.js` file:
```js
const {withBlitz} = require("@blitzjs/next")
module.exports = withBlitz()
```
### Adding plugins
Now that you're all set with the basic setup, you can add plugins that you
want to use in your app. There are a few places to check out:
1. [`@blitzjs/auth`](./auth-setup) — it covers how to setup auth plugin as
well as how to use Blitz auth system.
2. [`@blitzjs/rpc`](./rpc-setup) — check it out to learn how to set up
Blitz's Zero API Layer and to learn more about it.
</Steps>
Finally, you can check out more detailed information about the
[`@blitzjs/next` adapter](./blitzjs-next) to learn how to use Blitz
functionalities inside of `getServerSideProps`, `getStaticProps`, Next API
Routes, and other places.

View File

@@ -0,0 +1,72 @@
import { Callout, Tab, Tabs, Steps } from 'nextra-theme-docs'
## Get Started With Blitz
### Set Up Your Computer
You need Node.js 16 or newer. You can verify this by running `node -v` in
your terminal. If you don't have Node or need a newer version, we
recommend using a node version manager like
[fnm](https://github.com/Schniz/fnm). That will allow you to change node
versions and even have different versions for each project.
### Install Blitz
<Tabs items={['pnpm', 'npm', 'yarn']}>
<Tab>
```bash
pnpm add -g blitz
```
</Tab>
<Tab>
```bash
npm i -g blitz
```
</Tab>
<Tab>
```bash
yarn add -g blitz
```
</Tab>
</Tabs>
### Create a New App
1. `blitz new myAppName`
2. `cd myAppName`
3. `blitz dev`
4. View your brand new app at
[http://localhost:3000](http://localhost:3000)
## 👋 Welcome to the Blitz Community
The Blitz community is warm, safe, diverse, inclusive, and fun!
[Join our Discord Community](https://discord.blitzjs.com) where we help
each other build Blitz apps. It's also where we collaborate on building
Blitz itself.
For questions and longer form discussions,
[post in our forum.](https://github.com/blitz-js/blitz/discussions)
For a full introduction, read
[How the Community Operates](./how-the-community-operates). This details
everything, including how to get help, how to report bugs, how to suggest
new features, etc.
#### 🤝 You are invited to help make Blitz the best it can be!
We have an awesome community that's working together to make Blitz the
best framework the world has ever seen.
How you can help:
1. Report bugs by
[opening an issue on GitHub](https://github.com/blitz-js/blitz/issues/new/choose)
1. Contribute code:
[Read the contributing guide so see how to get started](./contributing).
1. [Sponsorships & donations](https://github.com/blitz-js/blitz#financial-contributors),
which start at $5/month
1. Any other way you want! We totally appreciate any type of contribution,
such as documentation, videos, blog posts, etc. If you have an unusual
idea, feel free to run it past us in Discord! :)

View File

@@ -0,0 +1,3 @@
{
"v2": "Upgrading to v2 - Blitz Toolkit"
}

View File

@@ -0,0 +1,281 @@
# Upgrading Your Blitz App to Blitz 2.0
If you have an existing Blitz.js app, and would like to upgrade it to the
Blitz 2.0, you can use our `@blitzjs/codemod` package:
```sh
npx @blitzjs/codemod upgrade-legacy
```
After running the above command, your Blitz app will be upgraded to the
Blitz 2.0. If you face any issues with the codemod — let us know! You can
also check out the manual upgrade guide below.
## Manual Upgrade Steps
Below, we're going to list down the steps performed by the codemod in case
you want to do some of them or all of them manually. Also, in case
something goes wrong with the codemod tool, you can follow these steps to
upgrade your app:
### Rename the `blitz.config.ts` file to `next.config.js`
Inside of the config file, you'll also need to wrap the config with
`withBlitz` function imported from `@blitzjs/next`:
```js
// @ts-check
const { withBlitz } = require("@blitzjs/next")
/**
* @type {import('@blitzjs/next').BlitzConfig}
**/
const config = {}
module.exports = withBlitz(config)
```
### Update dependencies in `package.json`
1. Update `react`, `react-dom` to the latest versions.
2. Install `@blitzjs/next`, `@blitzjs/rpc`, `@blitzjs/auth`.
3. Set `blitz` version to `latest`.
4. Upgrade `next` to the latest version.
### Update project's named imports
Now, for most of the things previously imported from `blitz` package,
you'd need to update the import to the new packages. Use the following
list as a reference:
| Import | Source Package |
| ----------------------------- | --------------- |
| `NextApiHandler` | `next` |
| `NextApiRequest` | `next` |
| `NextApiResponse` | `next` |
| `GetServerSideProps` | `next` |
| `InferGetServerSidePropsType` | `next` |
| `GetServerSidePropsContext` | `next` |
| `useRouterQuery`: | `next/router` |
| `useRouter` | `next/router` |
| `Router` | `next/router` |
| `Link` | `next/link` |
| `Image` | `next/image` |
| `Script` | `next/script` |
| `Document` | `next/document` |
| `DocumentHead` | `next/document` |
| `Html` | `next/document` |
| `Main` | `next/document` |
| `Head` | `next/head` |
| `App` | `next/app` |
| `dynamic` | `next/dynamic` |
| `noSSR` | `next/dynamic` |
| `getConfig` | `next/config` |
| `setConfig` | `next/config` |
| `ErrorBoundary` | `@blitzjs/next` |
| `ErrorFallbackProps` | `@blitzjs/next` |
| `useParam` | `@blitzjs/next` |
| `Routes` | `@blitzjs/next` |
| `ErrorComponent` | `@blitzjs/next` |
| `AppProps` | `@blitzjs/next` |
| `BlitzPage` | `@blitzjs/next` |
| `BlitzLayout` | `@blitzjs/next` |
| `invokeWithMiddleware` | `@blitzjs/rpc` |
| `resolver` | `@blitzjs/rpc` |
| `useQuery` | `@blitzjs/rpc` |
| `usePaginatedQuery` | `@blitzjs/rpc` |
| `useInfiniteQuery` | `@blitzjs/rpc` |
| `useMutation` | `@blitzjs/rpc` |
| `queryClient` | `@blitzjs/rpc` |
| `getQueryKey` | `@blitzjs/rpc` |
| `getInfiniteQueryKey` | `@blitzjs/rpc` |
| `invalidateQuery` | `@blitzjs/rpc` |
| `setQueryData` | `@blitzjs/rpc` |
| `useQueryErrorResetBoundary` | `@blitzjs/rpc` |
| `QueryClient` | `@blitzjs/rpc` |
| `dehydrate` | `@blitzjs/rpc` |
| `invoke` | `@blitzjs/rpc` |
| `getAntiCSRFToken` | `@blitzjs/auth` |
| `passportAuth` | `@blitzjs/auth` |
| `sessionMiddleware` | `@blitzjs/auth` |
| `simpleRolesIsAuthorized` | `@blitzjs/auth` |
| `getSession` | `@blitzjs/auth` |
| `setPublicDataForUser` | `@blitzjs/auth` |
| `SecurePassword` | `@blitzjs/auth` |
| `hash256` | `@blitzjs/auth` |
| `generateToken` | `@blitzjs/auth` |
| `useAuthenticatedSession` | `@blitzjs/auth` |
| `useRedirectAuthenticated` | `@blitzjs/auth` |
| `useSession` | `@blitzjs/auth` |
| `useAuthorize` | `@blitzjs/auth` |
| `AuthenticatedSessionContext` | `@blitzjs/auth` |
### Update project's default imports
There are also some default imports that you'll need to update. Use the
following list as a reference:
| Default Import | Source Package |
| -------------- | -------------- |
| `Link` | `next/link` |
| `Image` | `next/image` |
| `Head` | `next/head` |
| `dynamic` | `next/dynamic` |
### Change `queryClient` import to `getQueryClient`
If you imported `queryClient` from `blitz`, you'd need to change it to the
following code:
```diff
- import { queryClient } from 'blitz'
+ import { getQueryClient } from '@blitzjs/rpc'
+ const queryClient = getQueryClient()
```
### Update `BlitzApiRequest`, `BlitzApiResponse`, `BlitzApiHandler`
`blitz` no longer exports `BlitzApiRequest`, `BlitzApiResponse`,
`BlitzApiHandler`. You'll need to update your imports to the following:
```diff
- import { BlitzApiRequest } from 'blitz'
+ import { NextApiRequest } from 'next'
- import { BlitzApiResponse } from 'blitz'
+ import { NextApiResponse } from 'next'
- import { BlitzApiHandler } from 'blitz'
+ import { NextApiHandler } from 'next'
```
### Create `blitz-server.ts` and `blitz-client.ts`
To configure the plugins, you'd need to add the following files to your
project:
1. `blitz-server.ts`:
```ts
import { setupBlitzServer } from "@blitzjs/next"
import {
AuthServerPlugin,
PrismaStorage,
simpleRolesIsAuthorized,
} from "@blitzjs/auth"
import { db } from "db"
const { gSSP, gSP, api } = setupBlitzServer({
plugins: [
AuthServerPlugin({
cookiePrefix: "blitz-app",
storage: PrismaStorage(db),
isAuthorized: simpleRolesIsAuthorized,
}),
],
})
export { gSSP, gSP, api }
```
2. `blitz-client.ts`:
```ts
import { AuthClientPlugin } from "@blitzjs/auth"
import { setupBlitzClient } from "@blitzjs/next"
import { BlitzRpcPlugin } from "@blitzjs/rpc"
export const { withBlitz } = setupBlitzClient({
plugins: [
AuthClientPlugin({
cookiePrefix: "blitz-app",
}),
BlitzRpcPlugin(),
],
})
```
### Create API Route for the Zero-API Layer
To setup the Zero-API layer, you'd need to create a
`src/pages/api/rpc/[[...blitz]].ts` file with the following content:
```ts
import { rpcHandler } from "@blitzjs/rpc"
import { api } from "src/blitz-server"
export default api(rpcHandler())
```
### Remove `babel.config.js`
It's not needed anymore.
### Move all pages to `src/pages` directory
Having pages in separate directories in not supported with Next.js. They
now have to be consolidated in the top level `pages` directory, or we
recommend placing it in the `src` directory.
### Move API Routes to `src/pages/api` directory
All your API Routes have to be inside of the `src/pages/api` directory.
### Wrap your App component with `withBlitz`
To use Blitz on the client, you also have to use the `withBlitz` function
in your App component.
```ts
import { withBlitz } from "src/blitz-client"
function App({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}
export default withBlitz(App)
```
### Convert `useRouterQuery` to `useRouter`
Blitz no longer exports `useRouterQuery`. You'll need to use the
`useRouter` function instead.
```ts
import { useRouter } from "next/router"
```
### Wrapping `getServerSideProps`, `getStaticProps`, and API Routes
If you want to access the Blitz context inside of the
`getServerSideProps`, `getStaticProps`, and API Routes, you'll need to
wrap them with corresponding functions: `gSSP`, `gSP`, and `api` imported
from `@blitzjs/next`.
To learn more about it, follow the [`@blitzjs/next` docs](./blitzjs-next).
### Replacing `queryClient` with `getQueryClient` function
If you're using `queryClient` in your code, you can replace it with the
following code:
```ts
import { getQueryClient } from "@blitzjs/rpc"
const queryClient = getQueryClient()
```
### `types.ts` changes
In your `types.ts` file, you'll need to change the module that is being
augmented:
```diff
- declare module "@blitzjs/auth" {
+ declare module "@blitzjs/auth" {
export interface Session {
// ...
}
}
```

440
docs/src/pages/index.tsx Normal file
View File

@@ -0,0 +1,440 @@
import {Octokit} from "@octokit/rest"
import Image from "next/image"
import Link from "next/link"
import {useEffect, useState} from "react"
import {ButtonLink} from "@/components/ButtonLink"
import {Header} from "@/components/Header"
import {Feature} from "@/components/home/Feature"
import {FeatureIcon} from "@/components/home/FeatureIcon"
import {FeatureIconTitle} from "@/components/home/FeatureIconTitle"
import {Footer} from "@/components/home/Footer"
import {Hand} from "@/components/home/Hand"
import {HeroCode} from "@/components/home/HeroCode"
import {StyledLink} from "@/components/home/StyledLink"
import {VideoPlayer} from "@/components/home/VideoPlayer"
import Scrollbar from "@/components/Scrollbar"
import {SocialCards} from "@/components/SocialCards"
import {SponsorPack} from "@/components/SponsorPack"
import {getGitHubFile} from "@/utils/getGitHubFile"
const Home = ({randomContributors}) => {
const [navIsOpen, setNavIsOpen] = useState(false)
useEffect(() => {
document.body.style.overflow = navIsOpen ? "hidden" : "unset"
}, [navIsOpen])
return (
<div>
<SocialCards imageUrl="/social-homepage.png" />
<div className="overflow-hidden">
<div>
<a name="top" aria-hidden>
{null}
</a>
<div className="relative grid grid-cols-1 pb-1 md:pb-3 gap-y-24 xl:gap-y-44">
<div className="z-30 text-white col-span-full">
<Header
className="px-6 mx-auto max-w-7xl"
onNavToggle={(isOpen) => {
setNavIsOpen(isOpen)
}}
/>
</div>
<div
className={
"absolute w-full h-full row-start-1 row-end-5 background-to-video rounded-bl-3xl xl:rounded-bl-4xl bg-gradient-to-b from-purple-mid to-purple-primary dark:from-black dark:to-purple-off-black " +
(navIsOpen ? "z-20 fixed" : "-z-10")
}
></div>
<div className="relative -mt-6 text-white col-span-full">
<div className="grid grid-cols-1 gap-10 px-6 mx-auto max-w-7xl lg:grid-cols-2 md:gap-6 xl:-mt-10">
<div className="z-10 lg:w-full">
<div className="flex flex-col -mt-8 lg:mt-16 xl:mt-10">
{/* html is ordered for SEO, then we use flex to flip display order for design */}
<h2 className="order-last font-medium text-2xl xl:text-3xl font-secondary xl:font-medium text-transparent bg-clip-text bg-gradient-to-r from-yellow-200 to-yellow-400 dark:from-yellow-100 dark:to-yellow-300">
The Missing Fullstack Toolkit for Next.js
</h2>
<h3 className="font-medium text-7xl font-secondary xl:text-8xl xl:font-medium text-transparent bg-clip-text bg-gradient-to-r from-blue-gradient-white to-blue-gradient-light-blue tracking-tight xl:tracking-tighter mb-4 xl:mb-8 ">
Ship. Fast.
</h3>
</div>
<p className="mt-6 xl:mt-8 text-lg xl:text-2xl xl:font-medium text-off-white lg:text-transparent lg:bg-clip-text lg:bg-gradient-to-r lg:from-blue-gradient-white lg:to-blue-gradient-light-blue ">
Blitz picks up where Next.js leaves off, providing battle-tested libraries and
conventions for shipping and scaling world wide applications.
</p>
<div className="flex space-x-4 mt-10">
<ButtonLink className="w-2/3 lg:w-auto rounded-tl-xl" href="/docs/why-blitz">
Learn to Blitz
</ButtonLink>
<ButtonLink
href="https://github.com/blitz-js/blitz"
target="_blank"
rel="noopener noreferrer"
variant="outline"
className="w-1/3 lg:w-auto rounded-r-xl"
>
GitHub
</ButtonLink>
</div>
</div>
<div className="relative lg:col-span-1">
<Hand variant="hero-squiggle" className="lg:hidden -right-6 -top-36" />
<Hand variant="hero-rightarm" className="hidden lg:block -left-36 top-32" />
<Hand
variant="hero-righthand"
className="z-20 hidden lg:block -left-4"
style={{top: "15.2rem"}}
/>
<Hand
variant="hero-leftarm"
className="hidden lg:block"
style={{top: "30rem", right: "-4.8rem"}}
/>
<Hand
variant="hero-lefthand"
style={{top: "26.6rem", right: "-2.2em"}}
className="z-20 hidden lg:block"
/>
<HeroCode className="z-10" />
</div>
</div>
</div>
<div className="z-10 px-6 mx-auto space-y-12 text-lg text-center text-white lg:space-y-0 lg:space-x-12 lg:flex lg:text-left max-w-7xl xl:font-mediumxl:text-xl">
<FeatureIcon icon="layers" heading="Typesafe API Layer">
Build and iterate on features 10x faster with Blitz RPC than REST, GraphQL, or
vanilla API routes. Read and write data from the client with full typesafety and
without messing with HTTP or serialization.
</FeatureIcon>
<FeatureIcon icon="lighteningBolt" heading="Authentication">
Powerful, flexible, and battle tested authentication and authorization for Next.js.
You get more control with simpler APIs than alternatives. Easily add social third
party integrations like Google, Github, and Auth0.
</FeatureIcon>
<FeatureIcon icon="graphUp" heading="Conventions & Codegen">
Set up a new app in 2 mins instead of 2 weeks. Everything will be set up for you
including auth, user signup, forgot password, and your form library of choice.
</FeatureIcon>
</div>
<div className="grid w-full gap-5 px-6 mx-auto text-white xl:gap-10 max-w-7xl lg:grid-cols-2">
<Link href="/#" passHref>
<StyledLink className="flex items-center justify-between pb-1 text-lg border-b border-opacity-50 border-blue-mid lg:col-span-2 font-secondary xl:text-xl">
<span>Top Videos</span>
{/*
<span className="flex items-center">
<span className="hidden mr-2 lg:block">View News</span>{" "}
<BsArrowRight size="1.5rem" />
</span>
*/}
</StyledLink>
</Link>
<VideoPlayer url="https://www.youtube.com/watch?v=8D8yox2clug" />
<VideoPlayer url="https://www.youtube.com/watch?v=TWkjl_jg3Jk" />
</div>
<div className="relative w-full mx-auto space-y-10 lg:space-y-20 xl:space-y-36 max-w-7xl">
<h2 className="px-6 text-3xl font-semibold xl:text-5xl xl:w-1/2">
Everything You Need For Production Apps
</h2>
<div className="w-full">
<Hand
variant="concepts-right"
className="hidden lg:block lg:-top-24 lg:-right-96 lg:w-8/12 xl:-top-14"
/>
<Scrollbar className="lg:hidden" thumbHeight="4px">
<div className="grid pb-4 ml-6 features-grid lg:gap-y-14">
<Feature title="Built for Monoliths and Services">
<p>
You can manage everything from the database to your frontend all inside a
single app. Only one thing to develop. Only one thing to deploy.
</p>
<p>Or not. Your choice.</p>
</Feature>
<Feature title="Loose Opinions">
<p>
The out-of-the-box experience guides you on a path perfect for most
applications. But when you need to go off the beaten path, you are totally
free to do so.
</p>
<p>
And nearly everything is pluggable. For example, we don&apos;t mandate which
styling or form libraries you use.
</p>
</Feature>
<Feature title="Convention over Configuration">
<p>
Blitz does all the boring set up and configuration for you. The common
project structure and architectural patterns make it easy to move from one
Blitz app to another and immediately feel at home.
</p>
</Feature>
<Feature title="Easy to Start, Easy to Scale">
<p>Easy for beginners and easy to migrate existing Next.js apps to Blitz.</p>
<p>
Easy to scale in all forms: lines of code, number of people working in the
codebase, and code execution.
</p>
</Feature>
</div>
</Scrollbar>
</div>
</div>
<div className="absolute w-full h-full row-start-6 lg:h-codesandbox lg:mt-80 row-end-10 md:row-end-10 rounded-bl-3xl rounded-tr-3xl lg:rounded-bl-4xl lg:rounded-tr-4xl bg-gradient-to-b from-purple-mid to-purple-primary dark:from-purple-off-black dark:to-black"></div>
<div className="relative hidden w-full px-6 mx-auto space-y-10 max-w-7xl lg:block">
<h3 className="pb-1 text-xs border-b border-opacity-50 font-secondary border-blue-mid">
Blitz CodeSandbox Example
</h3>
<div>
<Hand variant="sandbox-right" style={{right: "-13.2rem", bottom: "-35rem"}} />
<a
target="_blank"
rel="noopener noreferrer"
href="https://codesandbox.io/s/blitzjs-2-0-codesandbox-demo-b5v8xy?file=/app/blitz-server.ts"
className="h-sandbox xl:h-xl-sandbox block relative"
>
<Image
src="/img/sandbox-pic.png"
layout="fill"
className="object-cover"
alt="Codesandbox placeholder"
/>
<div className="absolute inset-0 bg-gray-800 opacity-0 hover:opacity-70 flex items-center justify-center text-white text-6xl font-bold">
Click to Open in New Tab
</div>
</a>
</div>
</div>
<div className="lg:hidden">{/*spacer div*/}</div>
<div className="relative flex flex-col px-6 mx-auto text-white lg:flex-row max-w-7xl space-y-14 lg:space-x-24 lg:space-y-0 xl:space-x-40">
<div className="space-y-14 lg:w-1/2">
<h2 className="z-10 font-medium text-transparent text-5xl-squashed font-secondary bg-clip-text bg-gradient-to-r from-blue-gradient-white to-blue-gradient-light-blue xl:text-6xl">
We Love Our Community!
</h2>
<div className="z-10 grid grid-cols-5 gap-1 md:grid-cols-6 lg:grid-cols-5 grid-rows-8 overflow-clip">
{randomContributors.map((contributor, i) => (
<a
href={`https://github.com/${contributor.login}`}
key={i}
target="_blank"
rel="noopener noreferrer"
>
<Image
layout="intrinsic"
width="100%"
height="100%"
src={contributor.avatar_url}
alt={contributor.name}
title={contributor.name}
className="w-full"
/>
</a>
))}
</div>
</div>
<div className="grid grid-cols-1 text-lg lg:relative gap-14 md:grid-cols-2 lg:row-span-2 lg:grid-cols-1 xl:text-xl lg:w-1/2">
<Hand variant="community-squiggle" className="xl:hidden -right-18" />
<div className="z-10 flex flex-col justify-between space-y-6 lg:justify-end">
<div className="flex flex-col space-y-6 lg:h-auto lg:text-transparent text-off-white">
<p className="lg:bg-gradient-to-r lg:from-blue-gradient-white lg:to-blue-gradient-light-blue lg:bg-clip-text">
Our community is warm, safe, inclusive, and fun!
<br />
Please read our{" "}
<Link href="/docs/code-of-conduct" passHref>
<StyledLink className="underline text-off-white hover:text-blue-light">
Code of Conduct
</StyledLink>
</Link>
.
</p>
</div>
<ButtonLink
href="https://discord.blitzjs.com/"
target="_blank"
rel="noopener noreferrer"
className="rounded-bl-none rounded-xl lg:w-max"
>
Join our Discord Community
</ButtonLink>
</div>
<div className="z-10 flex flex-col justify-between space-y-6 lg:justify-start">
<div className="flex flex-col space-y-6 lg:h-auto lg:text-transparent text-off-white lg:bg-clip-text lg:bg-gradient-to-r lg:from-blue-gradient-white lg:to-blue-gradient-light-blue">
<p className="lg:bg-gradient-to-r lg:from-blue-gradient-white lg:to-blue-gradient-light-blue lg:bg-clip-text">
We are all in this together, from the youngest to the oldest. We are all more
similar than we are different. We love to work together.
</p>
<p className="lg:bg-gradient-to-r lg:from-blue-gradient-white lg:to-blue-gradient-light-blue lg:bg-clip-text">
We invite you to help make Blitz the best JavaScript application layer
we&apos;ve ever had!
</p>
</div>
<Link href="/docs/contributing" passHref>
<ButtonLink className="rounded-bl-none rounded-xl lg:w-max">
Learn How to Contribute
</ButtonLink>
</Link>
</div>
</div>
</div>
<div className="z-10 w-full mx-auto text-white space-y-7 max-w-7xl">
<h2 className="px-6 text-2xl font-medium text-white font-secondary lg:text-3xl">
Architecture Diagram
</h2>
<div className="w-full">
<Scrollbar className="lg:hidden" thumbHeight="4px" thumbColor="white">
<div className="px-6 architecture-diagram" style={{paddingBottom: "2px"}}>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src="img/architecture.svg" alt="Architecture diagram" />
</div>
</Scrollbar>
</div>
</div>
<div className="relative col-span-full">
<Hand variant="features-squiggle" className="-right-6 -top-10 xl:hidden -z-10" />
</div>
<div className="absolute w-full h-full row-start-8 row-end-19 xl:row-end-19 -z-20 bg-purple-mid dark:bg-purple-off-black"></div>
<div className="relative px-6 mx-auto my-6 space-y-12 text-white xl:my-0 max-w-7xl xl:space-y-36">
<h2 className="text-3xl font-semibold lg:text-transparent lg:bg-clip-text lg:bg-gradient-to-r lg:from-blue-gradient-white lg:to-blue-gradient-light-blue xl:text-5xl">
Everything End-to-End From <br className="hidden xl:block" />
the Database to the Frontend
</h2>
<div className="grid gap-12 md:grid-cols-2 xl:grid-cols-3">
<Hand
variant="features-right"
className="hidden xl:block xl:-top-40 xl:-right-52"
/>
<FeatureIconTitle icon="thumbsUp" title="Authentication & Authorization">
Blitz authentication is super easy and secure. Works with any identity provider,
including self-hosted username and password and third-parties like Auth0.
</FeatureIconTitle>
<FeatureIconTitle icon="database" title="Database Agnostic">
You can use any database you want. Prisma is the default database client, but you
can remove that and use anything else like Fauna or DynamoDB.
</FeatureIconTitle>
<FeatureIconTitle icon="fileCode" title="Recipes">
One command to install code and/or packages into your blitz app. Examples: `blitz
install tailwind` or `blitz install chakra-ui`. Recipes can be created by anyone.
</FeatureIconTitle>
<FeatureIconTitle icon="plugin" title="Backend Architecture">
Blitz is set up for server intensive tasks like sending emails, cron jobs,
background processing, generating PDFs, etc. Currently we have minimal backend
guides, but are working on developing more patterns and adding more docs.
</FeatureIconTitle>
<FeatureIconTitle icon="typescript" title="First Class TypeScript Support">
Blitz is built with TypeScript and the Blitz data layer is fully end-to-end
typesafe. All types are completely static without needing a separate type
generation process!
</FeatureIconTitle>
<FeatureIconTitle icon="scaffolding" title="Code Scaffolding">
Blitz code scaffolding is great for both prototyping and for building real apps!
You can override templates with your own.
</FeatureIconTitle>
</div>
</div>
<div className="absolute w-full h-full bg-white dark:bg-black row-start-11 row-end-13 rounded-tr-3xl xl:rounded-tr-4xl -z-10" />
<div className="relative col-span-full">
<Hand
variant="sponsors-squiggle"
className="-right-24 xl:hidden"
style={{top: "-5.3rem"}}
/>
</div>
<div className="px-6 mx-auto text-center max-w-7xl ">
<div className="space-y-7 xl:space-y-10">
<h2 className="relative text-3xl font-semibold xl:text-5xl">
<Hand
variant="sponsors-left"
className="hidden xl:block -left-80 pointer-events-none"
style={{top: "-18.05rem"}}
/>
Our Sponsors
</h2>
<p className="text-lg xl:text-xl">
Your financial contributions help ensure Blitz continues to be developed and{" "}
<br className="hidden lg:block" />
maintained! We have monthly sponsorship options starting at $5/month.
</p>
<div>
<ButtonLink
variant="solid-dark"
href="https://github.com/sponsors/blitz-js"
className="mx-auto rounded-bl-none rounded-xl lg:w-max md:w-1/3 lg:m-auto lg:mt-4 xl:mt-18"
target="_blank"
rel="noopener noreferrer"
>
Support Blitz
</ButtonLink>
</div>
</div>
<div className="xl:max-w-2xl mx-auto">
<SponsorPack />
</div>
</div>
<div className="w-full px-6 mx-auto space-y-12 text-white lg:space-x-4 lg:space-y-0 lg:flex lg:items-center max-w-7xl">
<h2 className="pr-2 text-3xl font-semibold lg:w-full lg:text-transparent lg:bg-clip-text lg:bg-gradient-to-r lg:from-blue-gradient-white lg:to-blue-gradient-light-blue xl:text-5xl">
So What Should I Do Now?
</h2>
<div className="flex flex-col w-full space-y-4 md:flex-row md:space-y-0 md:space-x-2 min-h-10">
<ButtonLink
href="/docs/get-started"
className="w-full text-lg py-18 rounded-t-2xl md:rounded-tr-none"
>
Try Blitz in Under 5 Mins
</ButtonLink>
<ButtonLink
target="_blank"
rel="noopener noreferrer"
href="https://discord.blitzjs.com"
className="w-full text-lg py-18 rounded-br-2xl md:rounded-tr-2xl"
>
Join Discord
</ButtonLink>
</div>
</div>
<Footer className="dark:bg-purple-off-black bg-purple-mid text-white" />
</div>
</div>
</div>
</div>
)
}
const getStaticProps = async () => {
const MAX_CONTRIBUTORS = 30
const octokit = new Octokit({
auth: process.env.GITHUB_AUTH_TOKEN,
})
const {contributors} = await getGitHubFile({
octokit,
owner: "blitz-js",
repo: "blitz",
path: ".all-contributorsrc",
json: true,
})
let randomIndexes = []
while (randomIndexes.length < MAX_CONTRIBUTORS) {
var r = Math.floor(Math.random() * contributors.length)
if (randomIndexes.indexOf(r) === -1) randomIndexes.push(r)
}
let randomContributors = randomIndexes.map((i) => contributors[i])
return {
props: {randomContributors},
revalidate: 60 * 30, // 30 minutes
}
}
Home.meta = {
title: "Blitz.js - The Missing Fullstack Toolkit for Next.js",
description: `Blitz picks up where Next.js leaves off, providing battle-tested libraries and conventions for shipping and scaling world wide applications.`,
}
export default Home
export {getStaticProps}

828
docs/src/styles/nextra.css Normal file
View File

@@ -0,0 +1,828 @@
:root {
--docs-accent-color: #9580ff;
--docs-accent-color-opacity: #9580ff60;
--docs-accent-color-link: #9580ff;
--docs-light-bg: #e5e5e560;
--docs-light-bg-hover: #d0d0d060;
--docs-dark-bg: #2a2a2a90;
--docs-dark-bg-hover: #2a2a2a60;
--nextra-navbar-height: 8rem;
}
html[class~="dark"] {
--nextra-primary-hue: 267;
--nextra-primary-hue-saturation: 100%;
--nextra-primary-hue-lightness: 75%;
--docs-secondary-bg: var(--docs-dark-bg);
--docs-secondary-bg-hover: var(--docs-dark-bg-hover);
}
html[class~="light"] {
--docs-accent-color: #644be1;
--docs-dark-bg: #e5e5e560;
--docs-secondary-bg: var(--docs-light-bg);
--docs-secondary-bg-hover: var(--docs-light-bg-hover);
}
/* General
------------------------ */
html,
body,
kbd {
font-family: "Inter", "Helvetica Neue", "Helvetica", "Arial", "sans-serif";
-webkit-font-smoothing: "antialiased";
}
html {
font-size: 17px;
}
.nextra-nav-container nav {
height: 7rem;
}
aside {
height: calc(100vh - 7rem);
top: calc(7rem + 4px) !important;
}
.nextra-nav-container nav {
box-sizing: border-box;
padding: 0 2.5rem;
}
.nextra-sidebar-container {
box-sizing: border-box;
padding-left: 1rem;
}
.nextra-toc {
padding-right: 1rem;
}
@media (max-width: 640px) {
.nextra-nav-container {
padding: 0;
}
.nextra-nav-container nav {
padding: 0 2rem;
}
aside {
top: 0;
height: 100%;
}
.nextra-sidebar-container {
padding-top: 0;
}
}
.nextra-breadcrumb {
display: none !important;
}
/* General colors
------------------------ */
html[class~="dark"] .dark\:nx-text-gray-400,
html[class~="dark"] .nx-text-gray-500 {
color: #999 !important;
}
html[class~=dark] .folderAsHeader .nextra-sidebar-container ul li a {
color: #c5c5c5;
font-size: 1.05rem;
}
html[class~=dark] .dark\:nx-bg-\[linear-gradient\(1deg\,\#383838\,\#212121\)\]{
background: rgba(14,0,29)
}
html[class~="dark"] .dark\:bg-dark {
background-color: #0e0e0e;
}
html[class~="light"] body {
color: #0e0e0e;
}
html[class~="dark"] body {
color: #c5c5c5;
}
html[class~="dark"] p strong,
html[class~="dark"] h1,
html[class~="dark"] h2,
html[class~="dark"] h3,
html[class~="dark"] h4 {
color: #fff;
}
/* Link
------------------------ */
p a,
p li a {
text-decoration: underline;
text-decoration-thickness: 1px;
text-underline-offset: 0.01em;
text-decoration-color: var(--docs-accent-color-opacity);
}
p a:hover,
p li a:hover {
text-decoration-color: var(--docs-accent-color-link);
}
/* Nav
------------------------ */
.nextra-nav-container {
border-top: 4px solid var(--docs-accent-color);
}
.nextra-nav-container .nextra-nav-container-blur {
border: none;
box-shadow: none !important;
}
.nx-max-w-\[90rem\] {
max-width: 164rem !important;
}
/* Search Input
------------------------ */
html[class~="dark"] .nextra-search input,
html[class~="dark"] .nextra-search input:focus {
background-color: #110024;
border-color: #252525ff;
}
html[class~="dark"] .nextra-search input::placeholder {
color: #e5e5e560;
}
/* Sidebar
------------------------ */
.nextra-sidebar-container-menu {
border: none;
}
.nextra-sidebar-container > div {
margin-top: 10px;
padding-top: 0;
}
.nextra-toc-meta,
.nextra-sidebar-container-menu {
box-shadow: none !important;
}
.nextra-sidebar-container .nextra-scrollbar + div {
border-width: 0;
height: 4rem;
}
.nextra-toc ul li a,
.nextra-sidebar-container ul li.active > a,
.nextra-sidebar-container ul li.active > a:hover {
font-weight: normal;
}
html[class~="light"] .nextra-sidebar-container ul li a {
color: #0e0e0e;
}
html[class~="light"] .nextra-sidebar-container ul li a:hover,
html[class~="light"] .nextra-sidebar-container ul li.active > a:hover {
background-color: var(--docs-light-bg);
}
html[class~="dark"] .nextra-sidebar-container ul li a:hover,
html[class~="dark"] .nextra-sidebar-container ul li.active > a:hover {
background-color: var(--docs-dark-bg);
}
html[class~="dark"] .folderAsHeader .nextra-sidebar-container ul li a {
color: rgb(197, 197, 197);
font-size: 1.05rem;
}
html[class~="dark"] .folderAsHeader .nextra-sidebar-container ul li ul li a {
color: #999999;
font-size: 0.875rem;
}
html[class~="dark"] .folderAsHeader .nextra-sidebar-container ul li.active > a,
html[class~="dark"] .nextra-toc ul li a[aria-selected="true"],
html[class~="light"] .folderAsHeader .nextra-sidebar-container ul li.active > a,
html[class~="light"] .nextra-toc ul li a[aria-selected="true"] {
color: var(--docs-accent-color);
background-color: transparent;
}
html[class~="dark"] .nextra-sidebar-container ul li.active > a:hover,
html[class~="dark"] .nextra-toc ul li a[aria-selected="true"]:hover {
color: var(--docs-accent-color);
}
html[class~="dark"] .nx-text-primary-500,
html[class~="dark"] .nx-text-primary-600 {
color: var(--docs-accent-color);
}
html[class~="light"] .nx-text-primary-500,
html[class~="light"] .nx-text-primary-600 {
color: var(--docs-accent-color);
}
@media (max-width: 640px) {
html[class~="dark"] .folderAsHeader .nextra-sidebar-container ul li.active > a {
color: currentColor;
text-align: left;
}
.folderAsHeader .nextra-sidebar-container ul ul li a {
justify-content: normal;
}
}
/* Remove lines when you apply `.folderAsHeader` the class in the doc
*/
.folderAsHeader .nextra-sidebar-container ul ul {
padding-left: 0;
margin-left: 0;
margin: 0.3rem 0 1.2rem 0;
}
.folderAsHeader .nextra-sidebar-container ul div {
padding-left: 0;
}
.folderAsHeader .nextra-sidebar-container ul ul::before {
content: none;
}
.folderAsHeader .nextra-sidebar-container ul li a {
font-size: 16px;
}
/* arrow dropdown */
.folderAsHeader .nextra-sidebar-container a svg {
transition: opacity 100ms;
opacity: 0;
}
.folderAsHeader .nextra-sidebar-container a:hover svg {
opacity: 1;
}
svg:hover {
background: transparent !important;
}
/* Bold only on the header */
.folderAsHeader .nextra-sidebar-container ul > li > a,
.folderAsHeader .nextra-sidebar-container ul > li > a:hover {
font-weight: 600;
cursor: default;
line-height: 1.3;
}
.folderAsHeader .nextra-sidebar-container ul > li li a,
.folderAsHeader .nextra-sidebar-container ul > li li a:hover {
font-weight: normal;
cursor: pointer;
}
.folderAsHeader .nextra-sidebar-container ul li ul li a {
font-size: 14px;
}
.wip {
position: relative;
display: flex;
opacity: 0.5;
}
.wip:after {
content: "WIP";
border-radius: 2px;
padding: 2px;
font-size: 9px;
line-height: 13px;
position: absolute;
right: 0;
top: 50%;
transform: translate(0, -35%);
opacity: 0.6;
}
/* Content
------------------------ */
main div.mt-12 {
display: none;
}
.nextra-breadcrumb {
pointer-events: none;
display: none;
}
.nextra-navigation-links {
margin-top: 6rem;
padding-bottom: 4rem;
border: none;
}
html[class~="dark"] article p a,
html[class~="dark"] article li a,
html[class~="dark"] .dark\:hover\:text-primary-500:hover,
html[class~="light"] article p a,
html[class~="light"] article li a,
html[class~="light"] .dark\:hover\:text-primary-500:hover {
color: var(--docs-accent-color-link) !important;
}
/* Keyboard Shortcut
------------------------ */
p kbd {
border-radius: 4px;
font-size: 13px;
padding: 6px;
padding-bottom: 7px;
line-height: 14px;
font-weight: bold;
}
html[class~="light"] p kbd {
color: rgb(75, 85, 99);
background: rgb(75 85 99 / 12%);
box-shadow: rgb(75 85 99 / 24%) 0px -2px 0px inset;
}
html[class~="dark"] p kbd {
background: rgb(42 42 42);
box-shadow: rgb(255 255 255 / 12%) 0px -2px 0px inset;
color: #c5c5c5;
}
/* Inline Code Snippet
------------------------ */
html[class~="light"] p code {
background-color: var(--docs-light-bg);
border: solid 1px #e5e7eb;
}
html[class~="dark"] p code {
background-color: var(--docs-dark-bg);
border: solid 1px #373737;
color: #c5c5c5;
}
/* Callout
------------------------ */
.nextra-callout {
box-sizing: border-box;
border-radius: 6px;
padding: 16px;
display: flex;
align-items: flex-start;
}
.nextra-callout .pr-2 {
padding-right: 1rem;
}
html[class~="light"] .nextra-callout {
color: rgb(65 65 65 / 90%);
background-color: var(--docs-light-bg);
border: none !important;
}
html[class~="dark"] .nextra-callout {
border: none !important;
background: var(--docs-dark-bg) !important;
color: #999999 !important;
}
html[class~="dark"] .nextra-callout h4 {
color: #fff;
}
html[class~="light"] .nextra-callout h4 {
color: #000;
}
/* CTA Container
------------------------ */
.ctaContainer {
display: flex;
gap: 1.3rem;
margin: 2rem 0;
}
@media (max-width: 920px) {
.ctaContainer {
flex-direction: column;
}
}
/* Headings
------------------------ */
.cbs article h1 {
font-size: 3.5rem;
margin-top: 0;
line-height: 100%;
letter-spacing: -0.05em;
font-weight: bold;
}
@media (max-width: 640px) {
.cbs article h1 {
font-size: 3rem;
}
}
.cbs article h2 {
border: none;
font-size: 2rem;
line-height: 120%;
letter-spacing: -0.025em;
font-weight: bold;
}
.cbs article h2 .nx-absolute,
.cbs article h3 .nx-absolute {
margin-top: -7rem;
}
.cbs article h1:first-of-type {
margin-top: -0.16em;
}
.cbs article h2 {
margin-top: 2em;
}
.cbs article h2 + p:not(:first-child),
.cbs article h3 + p:not(:first-child) {
margin-top: 0.6rem;
}
.cbs article h3 {
margin-top: 1.5em;
}
.cbs article img {
border-radius: 4px;
}
.cbs article .subheading-anchor {
margin-top: -110px;
}
/* Code Snippet
------------------------ */
html[class~="light"] article pre {
background-color: var(--docs-light-bg);
border: solid 1px #e5e7eb;
}
html[class~="dark"] article pre {
background-color: var(--docs-dark-bg);
border: solid 1px #2a2a2a;
}
.blitz-logo {
display: inline;
padding-top: 0.5rem;
padding-bottom: 0.5rem;
width: auto;
height: 3rem;
fill: currentColor;
}
html[class~=dark] body {
background-color: rgba(14,0,29,var(--tw-bg-opacity))
}
html[class~=dark] .dark\:nx-bg-dark{
background-color: rgba(14,0,29,var(--tw-bg-opacity)) !important;
}
/* Start of Shiki Twoslash CSS:
Code blocks structurally look like:
<pre class='shiki lsp twoslash [theme-name]'>
<div class='language-id'>[lang-id]</div>
<div class='code-container'>
<code>[the code as a series of spans]</code>
<a href='playground...'>Try</a> (optional)
</div>
</pre>
*/
pre {
/* In theory shiki will overwrite these, but this is to make sure there are defaults regardless */
background-color: white;
color: black;
/* Give it some space to breathe */
padding: 12px;
/* All code samples get a grey border, twoslash ones get a different color */
border-left: 1px solid #999;
border-bottom: 1px solid #999;
margin-bottom: 3rem;
/* Important to allow the code to move horizontally; */
overflow-x: auto;
position: relative;
}
pre.shiki {
overflow-x: auto;
}
pre.shiki:hover .dim {
opacity: 1;
}
pre.shiki div.dim {
opacity: 0.5;
}
pre.shiki div.dim, pre.shiki div.highlight {
margin: 0;
padding: 0;
}
pre.shiki div.highlight {
opacity: 1;
background-color: #f1f8ff;
}
pre.shiki div.line {
min-height: 1rem;
}
/** Don't show the language identifiers */
pre.shiki .language-id{
display: none;
}
/* Visually differentiates twoslash code samples */
pre.twoslash {
border-color: #719af4;
}
/** When you mouse over the pre, show the underlines */
pre.twoslash:hover data-lsp {
border-color: #747474;
}
/** The tooltip-like which provides the LSP response */
pre.twoslash data-lsp:hover::before {
content: attr(lsp);
position: absolute;
transform: translate(0, 1rem);
background-color: #3f3f3f;
color: #fff;
text-align: left;
padding: 5px 8px;
border-radius: 2px;
font-family: "JetBrains Mono", Menlo, Monaco, Consolas, Courier New, monospace;
font-size: 14px;
white-space: pre-wrap;
z-index: 100;
}
pre .code-container {
overflow: auto;
}
/* The try button */
pre .code-container > a {
position: absolute;
right: 8px;
bottom: 8px;
border-radius: 4px;
border: 1px solid #719af4;
padding: 0 8px;
color: #719af4;
text-decoration: none;
opacity: 0;
transition-timing-function: ease;
transition: opacity 0.3s;
}
/* Respect no animations */
@media (prefers-reduced-motion: reduce) {
pre .code-container > a {
transition: none;
}
}
pre .code-container > a:hover {
color: white;
background-color: #719af4;
}
pre .code-container:hover a {
opacity: 1;
}
pre code {
font-size: 15px;
font-family: "JetBrains Mono", Menlo, Monaco, Consolas, Courier New, monospace;;
white-space: pre;
-webkit-overflow-scrolling: touch;
}
pre code a {
text-decoration: none;
}
pre data-err {
/* Extracted from VS Code */
background: url("data:image/svg+xml,%3Csvg%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%20viewBox%3D'0%200%206%203'%20enable-background%3D'new%200%200%206%203'%20height%3D'3'%20width%3D'6'%3E%3Cg%20fill%3D'%23c94824'%3E%3Cpolygon%20points%3D'5.5%2C0%202.5%2C3%201.1%2C3%204.1%2C0'%2F%3E%3Cpolygon%20points%3D'4%2C0%206%2C2%206%2C0.6%205.4%2C0'%2F%3E%3Cpolygon%20points%3D'0%2C2%201%2C3%202.4%2C3%200%2C0.6'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") repeat-x bottom left;
padding-bottom: 3px;
}
pre .query {
margin-bottom: 10px;
color: #137998;
display: inline-block;
}
/* In order to have the 'popped out' style design and to not break the layout
/* we need to place a fake and un-selectable copy of the error which _isn't_ broken out
/* behind the actual error message.
/* This sections keeps both of those two in in sync */
pre .error, pre .error-behind {
margin-left: -14px;
margin-top: 8px;
margin-bottom: 4px;
padding: 6px;
padding-left: 14px;
width: calc(100% - 20px);
white-space: pre-wrap;
display: block;
}
pre .error {
position: absolute;
background-color: #fee;
border-left: 2px solid #bf1818;
/* Give the space to the error code */
display: flex;
align-items: center;
color: black;
}
pre .error .code {
display: none;
}
pre .error-behind {
user-select: none;
visibility: transparent;
color: #fee;
}
/* Queries */
pre .arrow {
/* Transparent background */
background-color: #eee;
position: relative;
top: -7px;
margin-left: 0.1rem;
/* Edges */
border-left: 1px solid #eee;
border-top: 1px solid #eee;
transform: translateY(25%) rotate(45deg);
/* Size */
height: 8px;
width: 8px;
}
pre .popover {
margin-bottom: 10px;
background-color: #eee;
display: inline-block;
padding: 0 0.5rem 0.3rem;
margin-top: 10px;
border-radius: 3px;
}
/* Completion */
pre .inline-completions ul.dropdown {
display: inline-block;
position: absolute;
width: 240px;
background-color: gainsboro;
color: grey;
padding-top: 4px;
font-family: var(--code-font);
font-size: 0.8rem;
margin: 0;
padding: 0;
border-left: 4px solid #4b9edd;
}
pre .inline-completions ul.dropdown::before {
background-color: #4b9edd;
width: 2px;
position: absolute;
top: -1.2rem;
left: -3px;
content: " ";
}
pre .inline-completions ul.dropdown li {
overflow-x: hidden;
padding-left: 4px;
margin-bottom: 4px;
}
pre .inline-completions ul.dropdown li.deprecated {
text-decoration: line-through;
}
pre .inline-completions ul.dropdown li span.result-found {
color: #4b9edd;
}
pre .inline-completions ul.dropdown li span.result {
width: 100px;
color: black;
display: inline-block;
}
.dark-theme .markdown pre {
background-color: #d8d8d8;
border-color: #ddd;
filter: invert(98%) hue-rotate(180deg);
}
data-lsp {
/* Ensures there's no 1px jump when the hover happens */
border-bottom: 1px dotted transparent;
/* Fades in unobtrusively */
transition-timing-function: ease;
transition: border-color 0.3s;
}
/* Respect people's wishes to not have animations */
@media (prefers-reduced-motion: reduce) {
data-lsp {
transition: none;
}
}
/** Annotations support, providing a tool for meta commentary */
.tag-container {
position: relative;
}
.tag-container .twoslash-annotation {
position: absolute;
font-family: "JetBrains Mono", Menlo, Monaco, Consolas, Courier New, monospace;
right: -10px;
/** Default annotation text to 200px */
width: 200px;
color: #187abf;
background-color: #fcf3d9 bb;
}
.tag-container .twoslash-annotation p {
text-align: left;
font-size: 0.8rem;
line-height: 0.9rem;
}
.tag-container .twoslash-annotation svg {
float: left;
margin-left: -44px;
}
.tag-container .twoslash-annotation.left {
right: auto;
left: -200px;
}
.tag-container .twoslash-annotation.left svg {
float: right;
margin-right: -5px;
}
/** Support for showing console log/warn/errors inline */
pre .logger {
display: flex;
align-items: center;
color: black;
padding: 6px;
padding-left: 8px;
width: calc(100% - 19px);
white-space: pre-wrap;
}
pre .logger svg {
margin-right: 9px;
}
pre .logger.error-log {
background-color: #fee;
border-left: 2px solid #bf1818;
}
pre .logger.warn-log {
background-color: #ffe;
border-left: 2px solid #eae662;
}
pre .logger.log-log {
background-color: #e9e9e9;
border-left: 2px solid #ababab;
}
pre .logger.log-log svg {
margin-left: 6px;
margin-right: 9px;
}

6
docs/tailwind.config.js Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
content: [
"./src/**/*.{md,mdx,css,js,jsx}",
"./theme.config.jsx",
],
};

85
docs/theme.config.tsx Normal file
View File

@@ -0,0 +1,85 @@
const Logo = (props) => {
return (
<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 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 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" />
</svg>
)
}
import {useConfig} from "nextra-theme-docs"
const OG_IMAGE_URL = "https://codesandbox.io/docs/projects/og-image.jpg"
export default {
project: {
link: 'https://github.com/blitz-js/blitz',
},
footer: {component: null},
feedback: {content: null},
editLink: {text: "Edit this page on GitHub →"},
docsRepositoryBase: "https://github.com/blitz-js/blitz",
useNextSeoProps() {
return {
titleTemplate: "%s Blitzjs",
}
},
head() {
const {frontMatter} = useConfig()
return (
<>
{/* Favicons, meta */}
<meta httpEquiv="Content-Language" content="en" />
<meta
name="description"
content={
frontMatter.description ||
"Experience the future of web development and build projects anywhere and anytime with your team."
}
/>
<meta
name="og:description"
content={
frontMatter.description ||
"Experience the future of web development and build projects anywhere and anytime with your team."
}
/>
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@blitzjs" />
<meta name="twitter:image" content={OG_IMAGE_URL} />
<meta
name="og:title"
content={frontMatter.title ? frontMatter.title + " Blitz" : "Blitz Documentation"}
/>
<meta name="og:image" content={OG_IMAGE_URL} />
</>
)
},
logo: (
<svg viewBox="0 0 165 66" className="blitz-logo">
<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 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 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" />
</svg>
),
banner: {
key: "2.0-release",
text: (
<a href="https://flightcontrol.dev/?ref=blitzjs" target="_blank">
🚀 Announcing Flightcontrol - Easily Deploy Blitz.js and Next.js to AWS 🚀
</a>
),
dismissible: false
},
sidebar: {
toggleButton: true,
},
chat: {
link: 'https://discord.blitzjs.com',
},
}

View File

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

View File

@@ -17,17 +17,17 @@
"prisma:studio": "prisma studio"
},
"dependencies": {
"@blitzjs/auth": "workspace:2.0.0-beta.22",
"@blitzjs/config": "workspace:2.0.0-beta.22",
"@blitzjs/next": "workspace:2.0.0-beta.22",
"@blitzjs/rpc": "workspace:2.0.0-beta.22",
"@blitzjs/auth": "workspace:2.0.0-beta.23",
"@blitzjs/config": "workspace:2.0.0-beta.23",
"@blitzjs/next": "workspace:2.0.0-beta.23",
"@blitzjs/rpc": "workspace:2.0.0-beta.23",
"@hookform/error-message": "2.0.0",
"@hookform/resolvers": "2.9.10",
"@prisma/client": "4.6.0",
"blitz": "workspace:2.0.0-beta.22",
"@prisma/client": "4.6.1",
"blitz": "workspace:2.0.0-beta.23",
"delay": "5.0.0",
"next": "13.1.2",
"prisma": "4.6.0",
"next": "12.2.5",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "7.39.1",

View File

@@ -17,14 +17,14 @@
"prisma:studio": "prisma studio"
},
"dependencies": {
"@blitzjs/auth": "workspace:2.0.0-beta.22",
"@blitzjs/config": "workspace:2.0.0-beta.22",
"@blitzjs/next": "workspace:2.0.0-beta.22",
"@prisma/client": "4.6.0",
"blitz": "workspace:2.0.0-beta.22",
"@blitzjs/auth": "workspace:2.0.0-beta.23",
"@blitzjs/config": "workspace:2.0.0-beta.23",
"@blitzjs/next": "workspace:2.0.0-beta.23",
"@prisma/client": "4.6.1",
"blitz": "workspace:2.0.0-beta.23",
"lowdb": "3.0.0",
"next": "13.1.2",
"prisma": "4.6.0",
"next": "12.2.5",
"prisma": "4.6.1",
"react": "18.2.0",
"react-dom": "18.2.0"
},

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