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

Compare commits

..

1 Commits

Author SHA1 Message Date
Brandon Bayer
4068b4493e upgrade monorepo react to v18 alpha 2021-07-05 16:37:39 -04:00
1597 changed files with 24818 additions and 48057 deletions

View File

@@ -1519,8 +1519,7 @@
"avatar_url": "https://avatars2.githubusercontent.com/u/11509865?v=4",
"profile": "http://taloranderson.com",
"contributions": [
"code",
"doc"
"code"
]
},
{
@@ -1547,8 +1546,7 @@
"avatar_url": "https://avatars0.githubusercontent.com/u/244174?v=4",
"profile": "https://github.com/piotrski",
"contributions": [
"code",
"doc"
"code"
]
},
{
@@ -2005,9 +2003,7 @@
"avatar_url": "https://avatars.githubusercontent.com/u/9019397?v=4",
"profile": "http://aleksandra.codes",
"contributions": [
"code",
"doc",
"test"
"code"
]
},
{
@@ -2853,8 +2849,7 @@
"avatar_url": "https://avatars.githubusercontent.com/u/2716058?v=4",
"profile": "http://anolilab.de",
"contributions": [
"code",
"doc"
"code"
]
},
{
@@ -2875,784 +2870,6 @@
"test",
"code"
]
},
{
"login": "ricardo-rp",
"name": "Ricardo Romero",
"avatar_url": "https://avatars.githubusercontent.com/u/30808767?v=4",
"profile": "https://github.com/ricardo-rp",
"contributions": [
"doc"
]
},
{
"login": "anothernode",
"name": "Moritz Reiter",
"avatar_url": "https://avatars.githubusercontent.com/u/3286144?v=4",
"profile": "exocortex.anothernode.com",
"contributions": [
"doc"
]
},
{
"login": "msichterman",
"name": "Matt Sichterman",
"avatar_url": "https://avatars.githubusercontent.com/u/38794918?v=4",
"profile": "https://msich.dev",
"contributions": [
"doc"
]
},
{
"login": "medihack",
"name": "Kai Schlamp",
"avatar_url": "https://avatars.githubusercontent.com/u/120626?v=4",
"profile": "https://github.com/medihack",
"contributions": [
"doc"
]
},
{
"login": "muyiwaolu",
"name": "Muyiwa Olu",
"avatar_url": "https://avatars.githubusercontent.com/u/6832244?v=4",
"profile": "https://muyiwa.me",
"contributions": [
"code"
]
},
{
"login": "rabbihossain",
"name": "Rabbi Hossain",
"avatar_url": "https://avatars.githubusercontent.com/u/4346154?v=4",
"profile": "http://2hr.me/",
"contributions": [
"doc"
]
},
{
"login": "bravo-kernel",
"name": "bravo-kernel",
"avatar_url": "https://avatars.githubusercontent.com/u/230500?v=4",
"profile": "https://github.com/bravo-kernel",
"contributions": [
"code"
]
},
{
"login": "sam3d",
"name": "Sam Holmes",
"avatar_url": "https://avatars.githubusercontent.com/u/8385528?v=4",
"profile": "https://samholmes.net",
"contributions": [
"code"
]
},
{
"login": "doncicuto",
"name": "Miguel Cabrerizo",
"avatar_url": "https://avatars.githubusercontent.com/u/30386061?v=4",
"profile": "https://doncicuto.medium.com",
"contributions": [
"code",
"doc"
]
},
{
"login": "zenhob",
"name": "Zack Hobson",
"avatar_url": "https://avatars.githubusercontent.com/u/12092?v=4",
"profile": "http://zackhobson.com/",
"contributions": [
"code",
"doc"
]
},
{
"login": "m5r",
"name": "Mokhtar",
"avatar_url": "https://avatars.githubusercontent.com/u/13026820?v=4",
"profile": "https://www.mokhtar.dev",
"contributions": [
"doc"
]
},
{
"login": "kenkuan",
"name": "Ken Kuan",
"avatar_url": "https://avatars.githubusercontent.com/u/1924968?v=4",
"profile": "https://github.com/kenkuan",
"contributions": [
"code"
]
},
{
"login": "meehawk",
"name": "meehawk",
"avatar_url": "https://avatars.githubusercontent.com/u/80167324?v=4",
"profile": "https://github.com/meehawk",
"contributions": [
"code"
]
},
{
"login": "ravindranrahul",
"name": "Rahul Ravindran",
"avatar_url": "https://avatars.githubusercontent.com/u/10168946?v=4",
"profile": "rahulravindran.in",
"contributions": [
"code"
]
},
{
"login": "s-r-x",
"name": "Ilya",
"avatar_url": "https://avatars.githubusercontent.com/u/41614937?v=4",
"profile": "https://github.com/s-r-x",
"contributions": [
"code",
"doc",
"test"
]
},
{
"login": "hashimwarren",
"name": "Hashim Warren",
"avatar_url": "https://avatars.githubusercontent.com/u/6027587?v=4",
"profile": "https://github.com/hashimwarren",
"contributions": [
"doc"
]
},
{
"login": "damilolarandolph",
"name": "Damilola Randolph",
"avatar_url": "https://avatars.githubusercontent.com/u/43427949?v=4",
"profile": "https://damilolarandolph.com",
"contributions": [
"doc"
]
},
{
"login": "mwcampbell",
"name": "Matt Campbell",
"avatar_url": "https://avatars.githubusercontent.com/u/214820?v=4",
"profile": "https://github.com/mwcampbell",
"contributions": [
"doc"
]
},
{
"login": "ratson",
"name": "(◕ᴥ◕)",
"avatar_url": "https://avatars.githubusercontent.com/u/2682937?v=4",
"profile": "https://github.com/ratson",
"contributions": [
"code"
]
},
{
"login": "maciejmyslinski",
"name": "Mat Milbury",
"avatar_url": "https://avatars.githubusercontent.com/u/11421186?v=4",
"profile": "maciejmyslinski.com",
"contributions": [
"doc"
]
},
{
"login": "andreasasprou",
"name": "Andreas Asprou",
"avatar_url": "https://avatars.githubusercontent.com/u/8077469?v=4",
"profile": "https://andreas.fyi",
"contributions": [
"code"
]
},
{
"login": "kotx",
"name": "Kot",
"avatar_url": "https://avatars.githubusercontent.com/u/33439542?v=4",
"profile": "https://github.com/kotx",
"contributions": [
"code",
"test",
"doc"
]
},
{
"login": "isaka1022",
"name": "Amane",
"avatar_url": "https://avatars.githubusercontent.com/u/28589716?v=4",
"profile": "https://github.com/isaka1022",
"contributions": [
"doc"
]
},
{
"login": "fuzzthink",
"name": "John Leung",
"avatar_url": "https://avatars.githubusercontent.com/u/20699?v=4",
"profile": "johnleung.com",
"contributions": [
"doc"
]
},
{
"login": "bcye",
"name": "Bruce",
"avatar_url": "https://avatars.githubusercontent.com/u/29666239?v=4",
"profile": "roettgers.co",
"contributions": [
"code"
]
},
{
"login": "emilygracekz",
"name": "Emily",
"avatar_url": "https://avatars.githubusercontent.com/u/57361805?v=4",
"profile": "https://github.com/emilygracekz",
"contributions": [
"code"
]
},
{
"login": "npverni",
"name": "Nathan Verni",
"avatar_url": "https://avatars.githubusercontent.com/u/3537?v=4",
"profile": "https://github.com/npverni",
"contributions": [
"doc"
]
},
{
"login": "davyengone",
"name": "Davy Engone",
"avatar_url": "https://avatars.githubusercontent.com/u/4896002?v=4",
"profile": "https://davyengone.io",
"contributions": [
"doc"
]
},
{
"login": "Fedeorlandau",
"name": "Federico Joel Orlandau",
"avatar_url": "https://avatars.githubusercontent.com/u/10283686?v=4",
"profile": "https://fedeorlandau.dev/",
"contributions": [
"doc",
"code"
]
},
{
"login": "johnmurphy01",
"name": "John Murphy",
"avatar_url": "https://avatars.githubusercontent.com/u/2939548?v=4",
"profile": "https://github.com/johnmurphy01",
"contributions": [
"doc",
"code"
]
},
{
"login": "martinsaxa",
"name": "martinsaxa",
"avatar_url": "https://avatars.githubusercontent.com/u/33789474?v=4",
"profile": "https://github.com/martinsaxa",
"contributions": [
"code"
]
},
{
"login": "ajwgeek",
"name": "Austin Walhof",
"avatar_url": "https://avatars.githubusercontent.com/u/2135600?v=4",
"profile": "https://github.com/ajwgeek",
"contributions": [
"doc"
]
},
{
"login": "g3offrey",
"name": "Geoffrey",
"avatar_url": "https://avatars.githubusercontent.com/u/11151445?v=4",
"profile": "g3offrey.dev",
"contributions": [
"code",
"doc",
"test"
]
},
{
"login": "keevan",
"name": "Kevin Pham",
"avatar_url": "https://avatars.githubusercontent.com/u/9924643?v=4",
"profile": "https://github.com/keevan",
"contributions": [
"doc"
]
},
{
"login": "kimngan-bui",
"name": "kimngan-bui",
"avatar_url": "https://avatars.githubusercontent.com/u/20723478?v=4",
"profile": "https://github.com/kimngan-bui",
"contributions": [
"doc"
]
},
{
"login": "9j",
"name": "Bahk Chanhee",
"avatar_url": "https://avatars.githubusercontent.com/u/11691670?v=4",
"profile": "world.hey.com/bach",
"contributions": [
"code"
]
},
{
"login": "Vandivier",
"name": "John Vandivier",
"avatar_url": "https://avatars.githubusercontent.com/u/5559355?v=4",
"profile": "http://www.afterecon.com/",
"contributions": [
"code",
"test",
"doc"
]
},
{
"login": "namirsab",
"name": "Namir",
"avatar_url": "https://avatars.githubusercontent.com/u/6980777?v=4",
"profile": "http://namirsab.github.io",
"contributions": [
"doc",
"code",
"test"
]
},
{
"login": "scttcper",
"name": "Scott Cooper",
"avatar_url": "https://avatars.githubusercontent.com/u/1400464?v=4",
"profile": "https://twitter.com/scttcper",
"contributions": [
"doc"
]
},
{
"login": "Abduttayyeb",
"name": "Abduttayyeb M.r",
"avatar_url": "https://avatars.githubusercontent.com/u/55306260?v=4",
"profile": "abduttayyeb.github.io",
"contributions": [
"doc"
]
},
{
"login": "maybebored",
"name": "Mayuran",
"avatar_url": "https://avatars.githubusercontent.com/u/20951181?v=4",
"profile": "https://github.com/maybebored",
"contributions": [
"code"
]
},
{
"login": "MuckHub",
"name": "Aleksei Vesselko",
"avatar_url": "https://avatars.githubusercontent.com/u/54979136?v=4",
"profile": "https://github.com/MuckHub",
"contributions": [
"doc"
]
},
{
"login": "p-siriphanthong",
"name": "Punn Siriphanthong",
"avatar_url": "https://avatars.githubusercontent.com/u/29949429?v=4",
"profile": "https://p-siriphanthong.github.io/",
"contributions": [
"code"
]
},
{
"login": "shawn-fetanat",
"name": "Shawn Fetanat",
"avatar_url": "https://avatars.githubusercontent.com/u/83679827?v=4",
"profile": "https://my-portfolio-292eb.web.app",
"contributions": [
"doc"
]
},
{
"login": "mochi-sann",
"name": "Moyuru",
"avatar_url": "https://avatars.githubusercontent.com/u/44772513?v=4",
"profile": "https://github.com/mochi-sann",
"contributions": [
"code",
"test",
"doc"
]
},
{
"login": "camsloanftc",
"name": "Cam Sloan",
"avatar_url": "https://avatars.githubusercontent.com/u/16295659?v=4",
"profile": "https://github.com/camsloanftc",
"contributions": [
"doc"
]
},
{
"login": "sitek94",
"name": "Maciek Sitkowski",
"avatar_url": "https://avatars.githubusercontent.com/u/58401630?v=4",
"profile": "https://macieksitkowski.com",
"contributions": [
"doc"
]
},
{
"login": "vivek7405",
"name": "Vivek",
"avatar_url": "https://avatars.githubusercontent.com/u/24492244?v=4",
"profile": "https://github.com/vivek7405",
"contributions": [
"doc",
"code"
]
},
{
"login": "cj",
"name": "CJ Lazell",
"avatar_url": "https://avatars.githubusercontent.com/u/1819?v=4",
"profile": "http://cj.io",
"contributions": [
"code"
]
},
{
"login": "RobertBroersma",
"name": "Robert",
"avatar_url": "https://avatars.githubusercontent.com/u/4519828?v=4",
"profile": "robertbroersma.com",
"contributions": [
"doc"
]
},
{
"login": "cbejensen",
"name": "Christian Jensen",
"avatar_url": "https://avatars.githubusercontent.com/u/12374723?v=4",
"profile": "https://christianjensen.netlify.com",
"contributions": [
"doc"
]
},
{
"login": "dvnrsn",
"name": "Devin Rasmussen",
"avatar_url": "https://avatars.githubusercontent.com/u/9112811?v=4",
"profile": "https://github.com/dvnrsn",
"contributions": [
"code"
]
},
{
"login": "devtombiz",
"name": "Thomas Brenneur",
"avatar_url": "https://avatars.githubusercontent.com/u/23282613?v=4",
"profile": "www.linkedin.com/in/devtom",
"contributions": [
"code",
"doc",
"test"
]
},
{
"login": "lucasvazq",
"name": "Lucas Vazquez",
"avatar_url": "https://avatars.githubusercontent.com/u/38964964?v=4",
"profile": "https://lucasvazq.github.io/",
"contributions": [
"code"
]
},
{
"login": "chrisj-back2work",
"name": "Chris Johnson",
"avatar_url": "https://avatars.githubusercontent.com/u/68551954?v=4",
"profile": "https://github.com/chrisj-back2work",
"contributions": [
"doc"
]
},
{
"login": "thisdotrob",
"name": "Rob Stevenson",
"avatar_url": "https://avatars.githubusercontent.com/u/12902589?v=4",
"profile": "https://github.com/thisdotrob",
"contributions": [
"doc"
]
},
{
"login": "lovethebomb",
"name": "Lucas Heymès",
"avatar_url": "https://avatars.githubusercontent.com/u/1363056?v=4",
"profile": "www.lucas.computer",
"contributions": [
"code",
"doc"
]
},
{
"login": "NorfeldtAbtion",
"name": "Lasse Norfeldt",
"avatar_url": "https://avatars.githubusercontent.com/u/53769763?v=4",
"profile": "https://github.com/NorfeldtAbtion",
"contributions": [
"doc"
]
},
{
"login": "netwarex",
"name": "Péter Nyári",
"avatar_url": "https://avatars.githubusercontent.com/u/6048614?v=4",
"profile": "https://nyaripeter.hu/",
"contributions": [
"doc",
"code"
]
},
{
"login": "5minpause",
"name": "Holger Frohloff",
"avatar_url": "https://avatars.githubusercontent.com/u/84148?v=4",
"profile": "https://www.holgerfrohloff.de",
"contributions": [
"doc"
]
},
{
"login": "basilk76",
"name": "Basil Khan",
"avatar_url": "https://avatars.githubusercontent.com/u/45275512?v=4",
"profile": "https://github.com/basilk76",
"contributions": [
"doc"
]
},
{
"login": "danestves",
"name": "Daniel Esteves",
"avatar_url": "https://avatars.githubusercontent.com/u/31737273?v=4",
"profile": "https://danestves.com/",
"contributions": [
"doc"
]
},
{
"login": "coryhouse",
"name": "Cory House",
"avatar_url": "https://avatars.githubusercontent.com/u/1688997?v=4",
"profile": "http://www.bitnative.com",
"contributions": [
"doc"
]
},
{
"login": "rockmanvnx6",
"name": "Austin (Thang Pham)",
"avatar_url": "https://avatars.githubusercontent.com/u/16440123?v=4",
"profile": "https://auspham.dev/",
"contributions": [
"doc"
]
},
{
"login": "noxify",
"name": "Marcus Reinhardt",
"avatar_url": "https://avatars.githubusercontent.com/u/521777?v=4",
"profile": "https://jammeryhq.com",
"contributions": [
"doc",
"code"
]
},
{
"login": "davidchristie",
"name": "David Christie",
"avatar_url": "https://avatars.githubusercontent.com/u/12044333?v=4",
"profile": "https://github.com/davidchristie",
"contributions": [
"doc"
]
},
{
"login": "ajanth97",
"name": "Ajanth",
"avatar_url": "https://avatars.githubusercontent.com/u/50458502?v=4",
"profile": "https://github.com/ajanth97",
"contributions": [
"doc"
]
},
{
"login": "divpreet",
"name": "Div",
"avatar_url": "https://avatars.githubusercontent.com/u/2805650?v=4",
"profile": "https://github.com/divpreet",
"contributions": [
"doc"
]
},
{
"login": "david-arteaga",
"name": "David Arteaga",
"avatar_url": "https://avatars.githubusercontent.com/u/7199015?v=4",
"profile": "https://github.com/david-arteaga",
"contributions": [
"doc"
]
},
{
"login": "MukulKolpe",
"name": "Mukul Kolpe",
"avatar_url": "https://avatars.githubusercontent.com/u/78664749?v=4",
"profile": "https://github.com/MukulKolpe",
"contributions": [
"code"
]
},
{
"login": "skotchpine",
"name": "tyler",
"avatar_url": "https://avatars.githubusercontent.com/u/13043909?v=4",
"profile": "https://github.com/skotchpine",
"contributions": [
"code"
]
},
{
"login": "SofianeDjellouli",
"name": "Sofiane Djellouli",
"avatar_url": "https://avatars.githubusercontent.com/u/38258952?v=4",
"profile": "https://github.com/SofianeDjellouli",
"contributions": [
"doc"
]
},
{
"login": "kreako",
"name": "kreako",
"avatar_url": "https://avatars.githubusercontent.com/u/65113001?v=4",
"profile": "https://github.com/kreako",
"contributions": [
"doc"
]
},
{
"login": "sarahdayan",
"name": "Sarah Dayan",
"avatar_url": "https://avatars.githubusercontent.com/u/5370675?v=4",
"profile": "https://sarahdayan.dev",
"contributions": [
"code"
]
},
{
"login": "c-ciobanu",
"name": "Cristi Ciobanu",
"avatar_url": "https://avatars.githubusercontent.com/u/33382714?v=4",
"profile": "https://github.com/c-ciobanu",
"contributions": [
"doc"
]
},
{
"login": "arpitdalal",
"name": "Arpit Dalal",
"avatar_url": "https://avatars.githubusercontent.com/u/61059807?v=4",
"profile": "https://arpitdalal.dev",
"contributions": [
"doc"
]
},
{
"login": "robertrisch",
"name": "robertrisch",
"avatar_url": "https://avatars.githubusercontent.com/u/73828816?v=4",
"profile": "https://github.com/robertrisch",
"contributions": [
"doc"
]
},
{
"login": "dineshgadge",
"name": "Dinesh Gadge",
"avatar_url": "https://avatars.githubusercontent.com/u/186976?v=4",
"profile": "https://github.com/dineshgadge",
"contributions": [
"code"
]
},
{
"login": "maltekiessling",
"name": "Malte Kießling",
"avatar_url": "https://avatars.githubusercontent.com/u/30420110?v=4",
"profile": "https://github.com/maltekiessling",
"contributions": [
"doc"
]
},
{
"login": "ospfranco",
"name": "Oscar Franco",
"avatar_url": "https://avatars.githubusercontent.com/u/1634213?v=4",
"profile": "ospfranco.com",
"contributions": [
"doc"
]
},
{
"login": "Nfinished",
"name": "Adam Trager",
"avatar_url": "https://avatars.githubusercontent.com/u/1719791?v=4",
"profile": "adamtrager.com",
"contributions": [
"code"
]
},
{
"login": "shellord",
"name": "saheenshoukath",
"avatar_url": "https://avatars.githubusercontent.com/u/2632896?v=4",
"profile": "https://saheen.codes",
"contributions": [
"doc"
]
},
{
"login": "husnuljahneer",
"name": "Husnul Jahneer",
"avatar_url": "https://avatars.githubusercontent.com/u/54552763?v=4",
"profile": "https://jahneer.me",
"contributions": [
"doc"
]
},
{
"login": "ReykCS",
"name": "Reyk",
"avatar_url": "https://avatars.githubusercontent.com/u/40463716?v=4",
"profile": "https://github.com/ReykCS",
"contributions": [
"doc"
]
}
],
"contributorsPerLine": 7,

View File

@@ -48,8 +48,6 @@ eslint.config.*
/nextjs/packages/next-codemod/**/*.js
/nextjs/packages/next-codemod/**/*.d.ts
/nextjs/packages/next-env/**/*.d.ts
/nextjs/packages/next/build/swc/tests/fixture/**
/nextjs/test/integration/async-modules/**
/nextjs/test/integration/eslint/**
/nextjs/test/integration/babel/**
/nextjs/test-timings.json

View File

@@ -1,5 +1,5 @@
module.exports = {
parser: "@babel/eslint-parser",
parser: "babel-eslint",
env: {
browser: true,
commonjs: true,
@@ -8,18 +8,10 @@ module.exports = {
},
parserOptions: {
ecmaVersion: 6,
requireConfigFile: false,
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
babelOptions: {
presets: ["@babel/preset-env", "@babel/preset-react"],
caller: {
// Eslint supports top level await when a parser for it is included. We enable the parser by default for Babel.
supportsTopLevelAwait: true,
},
},
},
plugins: ["import", "unicorn", "simple-import-sort"],
extends: ["react-app"],

2
.github/CODEOWNERS vendored
View File

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

View File

@@ -16,4 +16,4 @@ Closes: ?
## Feature Checklist
- [ ] Integration test added (see [test docs](https://blitzjs.com/docs/contributing#running-tests) if needed)
- [ ] Documentation added/updated (submit PR to [blitzjs.com repo `canary` branch](https://github.com/blitz-js/blitzjs.com/tree/canary))
- [ ] Documentation added/updated (submit PR to [blitzjs.com repo](https://github.com/blitz-js/blitzjs.com))

View File

@@ -15,10 +15,6 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "14"
- name: Count size
uses: preactjs/compressed-size-action@v2
with:

View File

@@ -30,9 +30,9 @@ jobs:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
**/node_modules
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ runner.node_version}}-yarn-v14-
${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
- name: Install dependencies
run: yarn install --frozen-lockfile --silent
env:
@@ -41,8 +41,8 @@ jobs:
run: yarn manypkg check
env:
CI: true
- name: Build packages
run: yarn build
- name: Build next.js
run: yarn build:nextjs
env:
CI: true
- name: yarn lint
@@ -50,11 +50,13 @@ jobs:
env:
CI: true
build-linux:
build:
name: Build
runs-on: ubuntu-latest
env:
BLITZ_TELEMETRY_DISABLED: 1
NEXT_TELEMETRY_DISABLED: 1
outputs:
docsChange: ${{ steps.docs-change.outputs.DOCS_CHANGE }}
steps:
- uses: actions/checkout@v2
with:
@@ -74,105 +76,55 @@ jobs:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
**/node_modules
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ runner.node_version}}-yarn-v14-
${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
- run: yarn install --frozen-lockfile --check-files
- name: Build Packages
run: yarn build
- run: node run-tests.js --timings --write-timings -g 1/1
working-directory: nextjs
- name: Check docs only change
working-directory: nextjs
run: echo ::set-output name=DOCS_CHANGE::$(node skip-docs-change.js echo 'not-docs-only-change')
id: docs-change
- run: echo ${{steps.docs-change.outputs.DOCS_CHANGE}}
- uses: actions/cache@v2
id: cache-build
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
key: ${{ github.sha }}
testBlitzPackages:
name: Blitz - Test Packages
needs: build-linux
needs: build
runs-on: ubuntu-latest
env:
BLITZ_TELEMETRY_DISABLED: 1
NEXT_TELEMETRY_DISABLED: 1
steps:
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "14"
key: ${{ github.sha }}
- name: Setup kernel to increase watchers
if: runner.os == 'Linux'
if: matrix.os == 'ubuntu-latest'
run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
- name: Test Blitz Packages
run: yarn testonly:packages
env:
CI: true
testNextPackages:
name: Next - Test Packages
defaults:
run:
working-directory: nextjs
needs: build-linux
runs-on: ubuntu-latest
env:
BLITZ_TELEMETRY_DISABLED: 1
steps:
- uses: actions/cache@v2
id: restore-build
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "14"
- name: Setup kernel to increase watchers
if: runner.os == 'Linux'
run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
- name: Test Next Packages
run: yarn testonly:packages
env:
CI: true
testBlitzExamples:
timeout-minutes: 30
name: Blitz - Test Example Apps (ubuntu-latest)
needs: build-linux
runs-on: ubuntu-latest
name: Blitz - Test Example Apps
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
env:
BLITZ_TELEMETRY_DISABLED: 1
DEBUG: blitz:session
steps:
- uses: actions/cache@v2
id: restore-build
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "14"
# Needed to get cypress binary
- run: yarn cypress install
- name: Install sass
run: yarn install -W sass
- name: Setup kernel to increase watchers
if: runner.os == 'Linux'
run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
- name: Test examples
run: yarn testonly:examples
env:
CI: true
testBlitzExamplesWin:
timeout-minutes: 30
name: Blitz - Test Example Apps (windows-latest)
runs-on: windows-latest
env:
BLITZ_TELEMETRY_DISABLED: 1
NEXT_TELEMETRY_DISABLED: 1
steps:
- uses: actions/checkout@v2
with:
@@ -182,26 +134,31 @@ jobs:
with:
node-version: "14"
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
# - name: Get yarn cache directory path
# id: yarn-cache-dir-path
# run: echo "::set-output name=dir::$(yarn cache dir)"
# - name: Cache node_modules
# id: yarn-cache
# uses: actions/cache@v2
# with:
# path: |
# ${{ steps.yarn-cache-dir-path.outputs.dir }}
# **/node_modules
# key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-${{ hashFiles('yarn.lock') }}
# restore-keys: |
# ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Cache node_modules
id: yarn-cache
uses: actions/cache@v2
with:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
**/node_modules
key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v13-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ runner.node_version}}-yarn-v13-
- run: yarn install --frozen-lockfile --check-files
# - run: yarn cpy node_modules/.blitz packages/core/node_modules/.blitz
# if: matrix.os == 'windows-latest'
- name: Build Packages
run: yarn build
# Needed to get cypress binary
- run: yarn cypress install
- name: Install sass
run: yarn install -W sass
- name: Setup kernel to increase watchers
if: matrix.os == 'ubuntu-latest'
run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
- name: Test examples
run: yarn testonly:examples
env:
@@ -213,16 +170,18 @@ jobs:
run:
working-directory: nextjs
runs-on: ubuntu-latest
needs: build-linux
needs: build
env:
BLITZ_TELEMETRY_DISABLED: 1
NEXT_TELEMETRY_DISABLED: 1
steps:
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
- run: ./scripts/check-pre-compiled.sh
key: ${{ github.sha }}
- run: ./check-pre-compiled.sh
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testUnit:
name: Nextjs - Test Unit
@@ -230,78 +189,47 @@ jobs:
run:
working-directory: nextjs
runs-on: ubuntu-latest
needs: build-linux
needs: build
env:
BLITZ_TELEMETRY_DISABLED: 1
NEXT_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
HEADLESS: true
steps:
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
- run: node run-tests.js --type unit -g 1/1
key: ${{ github.sha }}
- run: node run-tests.js --timings --type unit -g 1/1
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testIntegrationBlitz:
name: Blitz - Test Integration
needs: build-linux
runs-on: ubuntu-latest
needs: build
env:
BLITZ_TELEMETRY_DISABLED: 1
NEXT_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
HEADLESS: true
strategy:
fail-fast: false
steps:
- run: echo ${{needs.build.outputs.docsChange}}
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "14"
key: ${{ github.sha }}
# TODO: remove after we fix watchpack watching too much
- name: Setup kernel to increase watchers
if: runner.os == 'Linux'
run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
- run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
- run: xvfb-run node nextjs/run-tests.js -c 3
testIntegrationBlitzWin:
name: Blitz - Test Integration (Windows)
runs-on: windows-latest
env:
BLITZ_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
HEADLESS: true
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 25
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "14"
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
# - name: Get yarn cache directory path
# id: yarn-cache-dir-path
# run: echo "::set-output name=dir::$(yarn cache dir)"
# - name: Cache node_modules
# id: yarn-cache
# uses: actions/cache@v2
# with:
# path: |
# ${{ steps.yarn-cache-dir-path.outputs.dir }}
# **/node_modules
# key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-${{ hashFiles('yarn.lock') }}
# restore-keys: |
# ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-
- run: yarn install --frozen-lockfile --check-files
- name: Build Packages
run: yarn build
- run: node nextjs/run-tests.js
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testIntegration:
name: Nextjs - Test Integration
@@ -309,9 +237,9 @@ jobs:
run:
working-directory: nextjs
runs-on: ubuntu-latest
needs: build-linux
needs: build
env:
BLITZ_TELEMETRY_DISABLED: 1
NEXT_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
HEADLESS: true
strategy:
@@ -319,55 +247,21 @@ jobs:
matrix:
group: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
steps:
- run: echo ${{needs.build.outputs.docsChange}}
working-directory: ./
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "14"
# TODO: remove after we fix watchpack watching too much
- name: Setup kernel to increase watchers
if: runner.os == 'Linux'
run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
- run: xvfb-run node run-tests.js -g ${{ matrix.group }}/20 -c 3
key: ${{ github.sha }}
testIntegrationWin:
name: Nextjs - Test Integration (Windows)
runs-on: windows-latest
env:
BLITZ_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
HEADLESS: true
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 25
- name: Use Node.js
uses: actions/setup-node@v2
with:
node-version: "14"
- run: git fetch --depth=1 origin +refs/tags/*:refs/tags/*
# - name: Get yarn cache directory path
# id: yarn-cache-dir-path
# run: echo "::set-output name=dir::$(yarn cache dir)"
# - name: Cache node_modules
# id: yarn-cache
# uses: actions/cache@v2
# with:
# path: |
# ${{ steps.yarn-cache-dir-path.outputs.dir }}
# **/node_modules
# key: ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-${{ hashFiles('yarn.lock') }}
# restore-keys: |
# ${{ runner.os }}-${{ runner.node_version}}-yarn-v14-
- run: yarn install --frozen-lockfile --check-files
- name: Build Packages
run: yarn build
- run: node run-tests.js test/integration/basic/test/index.test.js test/integration/production/test/index.test.js test/integration/multi-pages/test/index.test.js
working-directory: nextjs
# TODO: remove after we fix watchpack watching too much
- run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
- run: xvfb-run node run-tests.js --timings -g ${{ matrix.group }}/20 -c 3
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testElectron:
name: Nextjs - Test Electron
@@ -375,24 +269,29 @@ jobs:
run:
working-directory: nextjs
runs-on: ubuntu-latest
needs: build-linux
needs: build
env:
BLITZ_TELEMETRY_DISABLED: 1
NEXT_TELEMETRY_DISABLED: 1
NEXT_TEST_JOB: 1
HEADLESS: true
TEST_ELECTRON: 1
steps:
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
key: ${{ github.sha }}
# TODO: remove after we fix watchpack watching too much
- name: Setup kernel to increase watchers
run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
- run: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
- run: cd test/integration/with-electron/app && yarn
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
- run: xvfb-run node run-tests.js test/integration/with-electron/test/index.test.js
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testsPass:
name: thank you, next
@@ -402,12 +301,9 @@ jobs:
checkPrecompiled,
testIntegration,
testIntegrationBlitz,
testIntegrationBlitzWin,
testUnit,
testBlitzPackages,
testNextPackages,
testBlitzExamples,
testBlitzExamplesWin,
]
steps:
- run: exit 0
@@ -418,18 +314,20 @@ jobs:
run:
working-directory: nextjs
runs-on: ubuntu-latest
needs: build-linux
needs: build
env:
HEADLESS: true
BROWSER_NAME: "firefox"
BLITZ_TELEMETRY_DISABLED: 1
NEXT_TELEMETRY_DISABLED: 1
steps:
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
key: ${{ github.sha }}
- run: node run-tests.js -c 1 test/integration/production/test/index.test.js
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testSafari:
name: Nextjs - Test Safari (production)
@@ -437,21 +335,23 @@ jobs:
run:
working-directory: nextjs
runs-on: ubuntu-latest
needs: build-linux
needs: build
env:
BROWSERSTACK: true
BROWSER_NAME: "safari"
BLITZ_TELEMETRY_DISABLED: 1
NEXT_TELEMETRY_DISABLED: 1
SKIP_LOCAL_SELENIUM_SERVER: true
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
steps:
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
key: ${{ github.sha }}
- run: '[[ -z "$BROWSERSTACK_ACCESS_KEY" ]] && echo "Skipping for PR" || node run-tests.js -c 1 test/integration/production/test/index.test.js'
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
testSafariOld:
name: Nextjs - Test Safari 10.1 (nav)
@@ -459,19 +359,21 @@ jobs:
run:
working-directory: nextjs
runs-on: ubuntu-latest
needs: [build-linux, testSafari]
needs: [build, testSafari]
env:
BROWSERSTACK: true
LEGACY_SAFARI: true
BROWSERNAME: "safari"
BLITZ_TELEMETRY_DISABLED: 1
NEXT_TELEMETRY_DISABLED: 1
SKIP_LOCAL_SELENIUM_SERVER: true
BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }}
BROWSERSTACK_ACCESS_KEY: ${{ secrets.BROWSERSTACK_ACCESS_KEY }}
steps:
- uses: actions/cache@v2
if: ${{needs.build.outputs.docsChange != 'docs only change'}}
id: restore-build
with:
path: ./*
key: ${{ runner.os }}-${{ github.sha }}
key: ${{ github.sha }}
- run: '[[ -z "$BROWSERSTACK_ACCESS_KEY" ]] && echo "Skipping for PR" || node run-tests.js test/integration/production-nav/test/index.test.js'
if: ${{needs.build.outputs.docsChange != 'docs only change'}}

3
.gitignore vendored
View File

@@ -30,7 +30,4 @@ examples/auth2
db.sqlite-journal
test/integration/**/db.json
test/**/*/out
test/**/blitz-env.d.ts
examples/**/blitz-env.d.ts
.blitz**

View File

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

View File

@@ -1 +1 @@
14.18.1
12.20.0

View File

@@ -4,12 +4,6 @@
## Notes For Core Team
### To Publish a new NPM Package under `@blitzjs/` namespace
1. cd into the package directory
2. Run `npm publish --tag danger --access public`
- `--access public` is required because scoped packages are set to private by default
### Syncing Next.js Fork
1. Run `yarn push-nextjs`
@@ -25,12 +19,11 @@
6. Resolve all merge conflicts and complete merge
7. Run `yarn` and make sure all builds complete
8. Run `yarn lint` and fix any issues
9. Commit all changes to finish merge
10. `git push`
4. Run `yarn pull-nextjs`
9. `git push`
4. Run `yarn pull next-nextjs`
5. Run `yarn`
6. Run `yarn manypkg check` and optionally `yarn manypkg fix` to fix any issues
7. Under `nextjs/`, run `./scripts/check-pre-compiled.sh` and commit the changes
7. Under `nextjs/`, run `./check-pre-compiled.sh` and commit the changes
8. Run `yarn build:nextjs`
9. Run `yarn lint` - fix any issues
10. Run `yarn build` - fix any issues
@@ -40,52 +33,3 @@
14. Any doc updates needed?
15. Merge PR
16. `yarn push-nextjs`
#### Troubleshooting
##### yarn lint - Failed to load parser
Caused by invalid version of `@babel/eslint-parser`. `7.13.14` is a working version. I think it may be an incompatibility between this version and the version of eslint?
- change version of eslint-parser
- run `yarn --check-files`
- run `./scripts/check-pre-compiled.sh` from `./nextjs/`
- run `yarn build:nextjs` from root
- Try linting again
```
~/c/blitz> yarn lint
yarn run v1.22.10
$ eslint --ext ".js,.ts,.tsx" .
Oops! Something went wrong! :(
ESLint: 7.21.0
Error: Failed to load parser './parser.js' declared in 'examples/auth/.eslintrc.js » eslint-config-blitz » eslint-config-next': Cannot find module '@babel/parser'
at webpackEmptyContext (/Users/b/c/blitz/nextjs/packages/next/dist/compiled/babel/bundle.js:1:33258)
at Object.73139 (/Users/b/c/blitz/nextjs/packages/next/dist/compiled/babel/bundle.js:2194:783181)
at __nccwpck_require__ (/Users/b/c/blitz/nextjs/packages/next/dist/compiled/babel/bundle.js:2194:1065271)
at Object.eslintParser (/Users/b/c/blitz/nextjs/packages/next/dist/compiled/babel/bundle.js:1:43676)
at Object.<anonymous> (/Users/b/c/blitz/nextjs/packages/next/dist/compiled/babel/eslint-parser.js:1:100)
at Module._compile (/Users/b/c/blitz/node_modules/v8-compile-cache/v8-compile-cache.js:192:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
at Module.load (internal/modules/cjs/loader.js:863:32)
at Function.Module._load (internal/modules/cjs/loader.js:708:14)
at Module.require (internal/modules/cjs/loader.js:887:19)
error Command failed with exit code 2.
```
##### Failed to compile - LICENSE
This error occurs sometimes when you import code from packages/next/build/utils.ts into some other code like config-shared.ts. Solution is to move the code into another file.
```
Failed to compile.
../../../packages/next/dist/compiled/webpack/LICENSE
Module parse failed: Unexpected token (1:10)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See webpack.js.org/concepts#loaders
> Copyright JS Foundation and other contributors
|
| Permission is hereby granted, free of charge, to any person obtaining
```

189
README.md
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-388-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-304-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/canary/LICENSE">
<img alt="" src="https://img.shields.io/npm/l/blitz.svg?style=for-the-badge&labelColor=000000&color=blue">
@@ -22,7 +22,7 @@
<h1 align="center">The Fullstack React Framework</h1>
<h5 align="center">"Zero-API" Data Layer — Built on Next.js — Inspired by Ruby on Rails</h3>
<h3 align="center"><a href="https://blitzjs.com/docs/get-started" target="_blank">Read the Documentation</a></h3>
<h3 align="center"><a href="https://blitzjs.com" target="_blank">Read the Documentation</a></h3>
<br>
“Zero-API” data layer **lets you import server code directly into your React components** instead of having to manually add API endpoints and do client-side fetching and caching.
@@ -107,11 +107,20 @@ Your financial contributions help ensure Blitz continues to be developed and mai
<table>
<tr>
<td><a aria-label="React Bricks" href="https://reactbricks.com/?utm_source=blitzjs&utm_medium=sponsorship&utm_campaign=blitzjs_sponsorship">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/reactbricks_icon.svg" width="40px"/>
</a></td>
<td><a aria-label="Andreas Asprou" href="https://andreas.fyi">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/andreas.jpg" width="40px"/>
</a></td>
<td><a aria-label="MeetKai" href="https://meetkai.com/?ref=blitzjs">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/meetkai.png" width="40px"/>
<td><a aria-label="Robert Malko" href="https://github.com/malkomalko">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/rob_blitz.jpg" width="40px"/>
</a></td>
<td><a aria-label="Digas" href="https://digsas.com">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/digsas.svg" width="40px"/>
</a></td>
<td><a aria-label="userTrack" href="https://www.usertrack.net/?ref=blitzjs">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/usertrack.png" width="40px"/>
</a></td>
</tr>
</table>
@@ -126,26 +135,16 @@ Your financial contributions help ensure Blitz continues to be developed and mai
</a></td>
<td><a aria-label="RIT" href="https://rit-inc.co.jp/?utm_source=BlitzJS&utm_medium=sponsorship&utm_campaign=BlitzJS_Sponsorship_2021">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/rit_logo.png" width="200px">
</a></td>
<td><a aria-label="Boostry" href="https://boostry.co.jp/?utm_source=BlitzJS&utm_medium=sponsorship&utm_campaign=BlitzJS_Sponsorship_2021">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/boostry.svg" width="200px">
</a></td>
</tr>
</table>
### 🥈 Silver Sponsors
<table>
<tr>
<td>
<a aria-label="Fauna" href="https://dashboard.fauna.com/accounts/register?utm_source=BlitzJS&utm_medium=sponsorship&utm_campaign=BlitzJS_Sponsorship_2020">
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/Fauna_Logo_Blue.png" width="300px">
</a>
</td>
</tr>
</table>
### 🏆 Gold Sponsors
@@ -167,8 +166,6 @@ 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://aleksandra.codes"><img src="https://avatars.githubusercontent.com/u/9019397?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aleksandra Sikora</b></sub></a><br />Lead Maintainer</td>
</tr>
</table>
<!-- markdownlint-enable -->
@@ -185,6 +182,7 @@ _Code ownership, pull request approvals and merging, etc_ (see [Maintainers L2](
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="http://robdrosenberg.com"><img src="https://avatars0.githubusercontent.com/u/20813991?v=4" width="100px;" alt=""/><br /><sub><b>Robert Rosenberg</b></sub></a><br />Website/Docs</td>
<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="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>
@@ -204,6 +202,25 @@ _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://twitter.com/nitaking_"><img src="https://avatars2.githubusercontent.com/u/10850034?v=4" width="100px;" alt=""/><br /><sub><b>Satoshi Nitawaki</b></sub></a></td>
<td align="center"><a href="https://github.com/engelkes-finstreet"><img src="https://avatars0.githubusercontent.com/u/36962022?s=460&u=34cfc4a3d6da0a87026f6068c371779c68daa3a2&v=4" width="100px;" alt=""/><br /><sub><b>Patrick Engelkes</b></sub></a></td>
<td align="center"><a href="https://twitter.com/myrondavis"><img src="https://avatars2.githubusercontent.com/u/1430136?v=4" width="100px;" alt=""/><br /><sub><b>Myron Davis</b></sub></a></td>
<td align="center"><a href="https://twitter.com/NaReto1125_"><img src="https://avatars.githubusercontent.com/reo777" width="100px;" alt=""/><br /><sub><b>Reo Ishiyama</b></sub></a></td>
<td align="center"><a href="https://github.com/malkomalko"><img src="https://avatars.githubusercontent.com/malkomalko" width="100px;" alt=""/><br /><sub><b>Robert Malko</b></sub></a></td>
</tr>
<tr>
<td align="center">
<a href="https://kevinlangleyjr.com">
<img
src="https://avatars.githubusercontent.com/u/877634?v=4"
width="100px;"
alt=""
/><br />
<sub>
<b>Kevin Langley Jr.</b>
</sub>
</a>
</td>
<td align="center">
<a href="https://mina.ca">
<img src="https://avatars.githubusercontent.com/mabadir" width="100px;" alt="Mina Abadir avatar" /><br />
@@ -212,30 +229,6 @@ _Issue triage, pull request triage, community encouragement and moderation, etc_
</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://www.saheen.me/">
<img src="https://avatars.githubusercontent.com/shellord" width="100px;" alt="Saheen Shoukath avatar" /><br />
<sub>
<b>Saheen Shoukath</b>
</sub>
</a>
</td>
</tr>
</table>
<!-- markdownlint-enable -->
@@ -455,12 +448,12 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<td align="center"><a href="https://github.com/leggsimon"><img src="https://avatars2.githubusercontent.com/u/11544418?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Simon Legg</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=leggsimon" title="Documentation">📖</a></td>
<td align="center"><a href="https://robsoriano.com"><img src="https://avatars3.githubusercontent.com/u/13049130?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Robert Soriano</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=wobsoriano" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/benediktms"><img src="https://avatars2.githubusercontent.com/u/48836135?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Benedikt Schnatterbeck</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=benediktms" title="Code">💻</a></td>
<td align="center"><a href="http://taloranderson.com"><img src="https://avatars2.githubusercontent.com/u/11509865?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Talor Anderson</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Talor-A" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=Talor-A" title="Documentation">📖</a></td>
<td align="center"><a href="http://taloranderson.com"><img src="https://avatars2.githubusercontent.com/u/11509865?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Talor Anderson</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Talor-A" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/akirabaruah"><img src="https://avatars2.githubusercontent.com/u/6751517?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Akira Baruah</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=akirabaruah" title="Code">💻</a></td>
<td align="center"><a href="https://chriswray.dev/"><img src="https://avatars0.githubusercontent.com/u/53663762?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christopher Wray</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=cwray-tech" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/piotrski"><img src="https://avatars0.githubusercontent.com/u/244174?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Piotrek Tomczewski</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=piotrski" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=piotrski" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/piotrski"><img src="https://avatars0.githubusercontent.com/u/244174?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Piotrek Tomczewski</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=piotrski" title="Code">💻</a></td>
<td align="center"><a href="http://raph.site"><img src="https://avatars3.githubusercontent.com/u/1575946?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Raphaël Huchet</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=rap2hpoutre" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=rap2hpoutre" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=rap2hpoutre" title="Code">💻</a></td>
<td align="center"><a href="http://kattcorp.com"><img src="https://avatars1.githubusercontent.com/u/459267?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Alex Johansson</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=KATT" title="Code">💻</a></td>
<td align="center"><a href="http://davidmazza.com"><img src="https://avatars0.githubusercontent.com/u/120893?v=4?s=100" width="100px;" alt=""/><br /><sub><b>David Mazza</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=dmzza" title="Code">💻</a></td>
@@ -523,7 +516,7 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<td align="center"><a href="https://brianypliu.com"><img src="https://avatars.githubusercontent.com/u/3888780?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Brian Liu</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=LBrian" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="http://aleksandra.codes"><img src="https://avatars.githubusercontent.com/u/9019397?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aleksandra Sikora</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=beerose" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=beerose" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=beerose" title="Tests">⚠️</a></td>
<td align="center"><a href="http://aleksandra.codes"><img src="https://avatars.githubusercontent.com/u/9019397?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aleksandra Sikora</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=beerose" title="Code">💻</a></td>
<td align="center"><a href="https://juanm04.com"><img src="https://avatars.githubusercontent.com/u/16712703?v=4?s=100" width="100px;" alt=""/><br /><sub><b>JuanM04</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=JuanM04" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=JuanM04" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=JuanM04" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/arenddeboer"><img src="https://avatars.githubusercontent.com/u/7022204?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Arend de Boer</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=arenddeboer" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/fmilani"><img src="https://avatars.githubusercontent.com/u/1580375?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Felipe Milani</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=fmilani" title="Documentation">📖</a></td>
@@ -640,117 +633,9 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
<td align="center"><a href="https://www.kevinpeters.net/about/"><img src="https://avatars.githubusercontent.com/u/12736734?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kevin Peters</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=igeligel" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="http://anolilab.de"><img src="https://avatars.githubusercontent.com/u/2716058?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Bannert</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=prisis" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=prisis" title="Documentation">📖</a></td>
<td align="center"><a href="http://anolilab.de"><img src="https://avatars.githubusercontent.com/u/2716058?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Bannert</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=prisis" title="Code">💻</a></td>
<td align="center"><a href="https://benjakugler96.github.io/"><img src="https://avatars.githubusercontent.com/u/53273645?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Benja Kugler</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=benjakugler96" title="Code">💻</a></td>
<td align="center"><a href="https://semeniuc.ml/"><img src="https://avatars.githubusercontent.com/u/3838856?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Eric Semeniuc</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=esemeniuc" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=esemeniuc" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/ricardo-rp"><img src="https://avatars.githubusercontent.com/u/30808767?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ricardo Romero</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ricardo-rp" title="Documentation">📖</a></td>
<td align="center"><a href="exocortex.anothernode.com"><img src="https://avatars.githubusercontent.com/u/3286144?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Moritz Reiter</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=anothernode" title="Documentation">📖</a></td>
<td align="center"><a href="https://msich.dev"><img src="https://avatars.githubusercontent.com/u/38794918?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt Sichterman</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=msichterman" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/medihack"><img src="https://avatars.githubusercontent.com/u/120626?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kai Schlamp</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=medihack" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://muyiwa.me"><img src="https://avatars.githubusercontent.com/u/6832244?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Muyiwa Olu</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=muyiwaolu" title="Code">💻</a></td>
<td align="center"><a href="http://2hr.me/"><img src="https://avatars.githubusercontent.com/u/4346154?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rabbi Hossain</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=rabbihossain" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/bravo-kernel"><img src="https://avatars.githubusercontent.com/u/230500?v=4?s=100" width="100px;" alt=""/><br /><sub><b>bravo-kernel</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=bravo-kernel" title="Code">💻</a></td>
<td align="center"><a href="https://samholmes.net"><img src="https://avatars.githubusercontent.com/u/8385528?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sam Holmes</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sam3d" title="Code">💻</a></td>
<td align="center"><a href="https://doncicuto.medium.com"><img src="https://avatars.githubusercontent.com/u/30386061?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Miguel Cabrerizo</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=doncicuto" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=doncicuto" title="Documentation">📖</a></td>
<td align="center"><a href="http://zackhobson.com/"><img src="https://avatars.githubusercontent.com/u/12092?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zack Hobson</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=zenhob" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=zenhob" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.mokhtar.dev"><img src="https://avatars.githubusercontent.com/u/13026820?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mokhtar</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=m5r" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/kenkuan"><img src="https://avatars.githubusercontent.com/u/1924968?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ken Kuan</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=kenkuan" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/meehawk"><img src="https://avatars.githubusercontent.com/u/80167324?v=4?s=100" width="100px;" alt=""/><br /><sub><b>meehawk</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=meehawk" title="Code">💻</a></td>
<td align="center"><a href="rahulravindran.in"><img src="https://avatars.githubusercontent.com/u/10168946?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rahul Ravindran</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ravindranrahul" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/s-r-x"><img src="https://avatars.githubusercontent.com/u/41614937?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ilya</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=s-r-x" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=s-r-x" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=s-r-x" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/hashimwarren"><img src="https://avatars.githubusercontent.com/u/6027587?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Hashim Warren</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=hashimwarren" title="Documentation">📖</a></td>
<td align="center"><a href="https://damilolarandolph.com"><img src="https://avatars.githubusercontent.com/u/43427949?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Damilola Randolph</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=damilolarandolph" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/mwcampbell"><img src="https://avatars.githubusercontent.com/u/214820?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt Campbell</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=mwcampbell" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/ratson"><img src="https://avatars.githubusercontent.com/u/2682937?v=4?s=100" width="100px;" alt=""/><br /><sub><b>(◕ᴥ◕)</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ratson" title="Code">💻</a></td>
<td align="center"><a href="maciejmyslinski.com"><img src="https://avatars.githubusercontent.com/u/11421186?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mat Milbury</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=maciejmyslinski" title="Documentation">📖</a></td>
<td align="center"><a href="https://andreas.fyi"><img src="https://avatars.githubusercontent.com/u/8077469?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andreas Asprou</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=andreasasprou" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/kotx"><img src="https://avatars.githubusercontent.com/u/33439542?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kot</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=kotx" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=kotx" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=kotx" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/isaka1022"><img src="https://avatars.githubusercontent.com/u/28589716?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amane</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=isaka1022" title="Documentation">📖</a></td>
<td align="center"><a href="johnleung.com"><img src="https://avatars.githubusercontent.com/u/20699?v=4?s=100" width="100px;" alt=""/><br /><sub><b>John Leung</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=fuzzthink" title="Documentation">📖</a></td>
<td align="center"><a href="roettgers.co"><img src="https://avatars.githubusercontent.com/u/29666239?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bruce</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=bcye" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/emilygracekz"><img src="https://avatars.githubusercontent.com/u/57361805?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Emily</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=emilygracekz" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/npverni"><img src="https://avatars.githubusercontent.com/u/3537?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nathan Verni</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=npverni" title="Documentation">📖</a></td>
<td align="center"><a href="https://davyengone.io"><img src="https://avatars.githubusercontent.com/u/4896002?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Davy Engone</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=davyengone" title="Documentation">📖</a></td>
<td align="center"><a href="https://fedeorlandau.dev/"><img src="https://avatars.githubusercontent.com/u/10283686?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Federico Joel Orlandau</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Fedeorlandau" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=Fedeorlandau" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/johnmurphy01"><img src="https://avatars.githubusercontent.com/u/2939548?v=4?s=100" width="100px;" alt=""/><br /><sub><b>John Murphy</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=johnmurphy01" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=johnmurphy01" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/martinsaxa"><img src="https://avatars.githubusercontent.com/u/33789474?v=4?s=100" width="100px;" alt=""/><br /><sub><b>martinsaxa</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=martinsaxa" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/ajwgeek"><img src="https://avatars.githubusercontent.com/u/2135600?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Austin Walhof</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ajwgeek" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="g3offrey.dev"><img src="https://avatars.githubusercontent.com/u/11151445?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Geoffrey</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=g3offrey" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=g3offrey" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=g3offrey" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/keevan"><img src="https://avatars.githubusercontent.com/u/9924643?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kevin Pham</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=keevan" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/kimngan-bui"><img src="https://avatars.githubusercontent.com/u/20723478?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kimngan-bui</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=kimngan-bui" title="Documentation">📖</a></td>
<td align="center"><a href="world.hey.com/bach"><img src="https://avatars.githubusercontent.com/u/11691670?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Bahk Chanhee</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=9j" title="Code">💻</a></td>
<td align="center"><a href="http://www.afterecon.com/"><img src="https://avatars.githubusercontent.com/u/5559355?v=4?s=100" width="100px;" alt=""/><br /><sub><b>John Vandivier</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Vandivier" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=Vandivier" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=Vandivier" title="Documentation">📖</a></td>
<td align="center"><a href="http://namirsab.github.io"><img src="https://avatars.githubusercontent.com/u/6980777?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Namir</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=namirsab" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=namirsab" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=namirsab" title="Tests">⚠️</a></td>
<td align="center"><a href="https://twitter.com/scttcper"><img src="https://avatars.githubusercontent.com/u/1400464?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Scott Cooper</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=scttcper" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="abduttayyeb.github.io"><img src="https://avatars.githubusercontent.com/u/55306260?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Abduttayyeb M.r</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Abduttayyeb" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/maybebored"><img src="https://avatars.githubusercontent.com/u/20951181?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mayuran</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=maybebored" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/MuckHub"><img src="https://avatars.githubusercontent.com/u/54979136?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aleksei Vesselko</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=MuckHub" title="Documentation">📖</a></td>
<td align="center"><a href="https://p-siriphanthong.github.io/"><img src="https://avatars.githubusercontent.com/u/29949429?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Punn Siriphanthong</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=p-siriphanthong" title="Code">💻</a></td>
<td align="center"><a href="https://my-portfolio-292eb.web.app"><img src="https://avatars.githubusercontent.com/u/83679827?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Shawn Fetanat</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=shawn-fetanat" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/mochi-sann"><img src="https://avatars.githubusercontent.com/u/44772513?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Moyuru</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=mochi-sann" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=mochi-sann" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=mochi-sann" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/camsloanftc"><img src="https://avatars.githubusercontent.com/u/16295659?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Cam Sloan</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=camsloanftc" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://macieksitkowski.com"><img src="https://avatars.githubusercontent.com/u/58401630?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Maciek Sitkowski</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sitek94" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/vivek7405"><img src="https://avatars.githubusercontent.com/u/24492244?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Vivek</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=vivek7405" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=vivek7405" title="Code">💻</a></td>
<td align="center"><a href="http://cj.io"><img src="https://avatars.githubusercontent.com/u/1819?v=4?s=100" width="100px;" alt=""/><br /><sub><b>CJ Lazell</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=cj" title="Code">💻</a></td>
<td align="center"><a href="robertbroersma.com"><img src="https://avatars.githubusercontent.com/u/4519828?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Robert</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=RobertBroersma" title="Documentation">📖</a></td>
<td align="center"><a href="https://christianjensen.netlify.com"><img src="https://avatars.githubusercontent.com/u/12374723?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christian Jensen</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=cbejensen" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/dvnrsn"><img src="https://avatars.githubusercontent.com/u/9112811?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Devin Rasmussen</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=dvnrsn" title="Code">💻</a></td>
<td align="center"><a href="www.linkedin.com/in/devtom"><img src="https://avatars.githubusercontent.com/u/23282613?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Thomas Brenneur</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=devtombiz" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=devtombiz" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=devtombiz" title="Tests">⚠️</a></td>
</tr>
<tr>
<td align="center"><a href="https://lucasvazq.github.io/"><img src="https://avatars.githubusercontent.com/u/38964964?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lucas Vazquez</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=lucasvazq" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/chrisj-back2work"><img src="https://avatars.githubusercontent.com/u/68551954?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Chris Johnson</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=chrisj-back2work" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/thisdotrob"><img src="https://avatars.githubusercontent.com/u/12902589?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rob Stevenson</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=thisdotrob" title="Documentation">📖</a></td>
<td align="center"><a href="www.lucas.computer"><img src="https://avatars.githubusercontent.com/u/1363056?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lucas Heymès</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=lovethebomb" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=lovethebomb" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/NorfeldtAbtion"><img src="https://avatars.githubusercontent.com/u/53769763?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Lasse Norfeldt</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=NorfeldtAbtion" title="Documentation">📖</a></td>
<td align="center"><a href="https://nyaripeter.hu/"><img src="https://avatars.githubusercontent.com/u/6048614?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Péter Nyári</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=netwarex" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=netwarex" title="Code">💻</a></td>
<td align="center"><a href="https://www.holgerfrohloff.de"><img src="https://avatars.githubusercontent.com/u/84148?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Holger Frohloff</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=5minpause" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/basilk76"><img src="https://avatars.githubusercontent.com/u/45275512?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Basil Khan</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=basilk76" title="Documentation">📖</a></td>
<td align="center"><a href="https://danestves.com/"><img src="https://avatars.githubusercontent.com/u/31737273?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Esteves</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=danestves" title="Documentation">📖</a></td>
<td align="center"><a href="http://www.bitnative.com"><img src="https://avatars.githubusercontent.com/u/1688997?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Cory House</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=coryhouse" title="Documentation">📖</a></td>
<td align="center"><a href="https://auspham.dev/"><img src="https://avatars.githubusercontent.com/u/16440123?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Austin (Thang Pham)</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=rockmanvnx6" title="Documentation">📖</a></td>
<td align="center"><a href="https://jammeryhq.com"><img src="https://avatars.githubusercontent.com/u/521777?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Marcus Reinhardt</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=noxify" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=noxify" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/davidchristie"><img src="https://avatars.githubusercontent.com/u/12044333?v=4?s=100" width="100px;" alt=""/><br /><sub><b>David Christie</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=davidchristie" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/ajanth97"><img src="https://avatars.githubusercontent.com/u/50458502?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ajanth</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ajanth97" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/divpreet"><img src="https://avatars.githubusercontent.com/u/2805650?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Div</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=divpreet" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/david-arteaga"><img src="https://avatars.githubusercontent.com/u/7199015?v=4?s=100" width="100px;" alt=""/><br /><sub><b>David Arteaga</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=david-arteaga" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/MukulKolpe"><img src="https://avatars.githubusercontent.com/u/78664749?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mukul Kolpe</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=MukulKolpe" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/skotchpine"><img src="https://avatars.githubusercontent.com/u/13043909?v=4?s=100" width="100px;" alt=""/><br /><sub><b>tyler</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=skotchpine" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/SofianeDjellouli"><img src="https://avatars.githubusercontent.com/u/38258952?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sofiane Djellouli</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=SofianeDjellouli" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/kreako"><img src="https://avatars.githubusercontent.com/u/65113001?v=4?s=100" width="100px;" alt=""/><br /><sub><b>kreako</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=kreako" title="Documentation">📖</a></td>
<td align="center"><a href="https://sarahdayan.dev"><img src="https://avatars.githubusercontent.com/u/5370675?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sarah Dayan</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sarahdayan" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/c-ciobanu"><img src="https://avatars.githubusercontent.com/u/33382714?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Cristi Ciobanu</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=c-ciobanu" title="Documentation">📖</a></td>
<td align="center"><a href="https://arpitdalal.dev"><img src="https://avatars.githubusercontent.com/u/61059807?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Arpit Dalal</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=arpitdalal" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/robertrisch"><img src="https://avatars.githubusercontent.com/u/73828816?v=4?s=100" width="100px;" alt=""/><br /><sub><b>robertrisch</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=robertrisch" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/dineshgadge"><img src="https://avatars.githubusercontent.com/u/186976?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dinesh Gadge</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=dineshgadge" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/maltekiessling"><img src="https://avatars.githubusercontent.com/u/30420110?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Malte Kießling</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=maltekiessling" title="Documentation">📖</a></td>
<td align="center"><a href="ospfranco.com"><img src="https://avatars.githubusercontent.com/u/1634213?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Oscar Franco</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ospfranco" title="Documentation">📖</a></td>
<td align="center"><a href="adamtrager.com"><img src="https://avatars.githubusercontent.com/u/1719791?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Adam Trager</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Nfinished" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://saheen.codes"><img src="https://avatars.githubusercontent.com/u/2632896?v=4?s=100" width="100px;" alt=""/><br /><sub><b>saheenshoukath</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=shellord" title="Documentation">📖</a></td>
<td align="center"><a href="https://jahneer.me"><img src="https://avatars.githubusercontent.com/u/54552763?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Husnul Jahneer</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=husnuljahneer" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/ReykCS"><img src="https://avatars.githubusercontent.com/u/40463716?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Reyk</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ReykCS" title="Documentation">📖</a></td>
</tr>
</table>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 143.5 42.09"><defs><style>.cls-1{fill:none;}.cls-2{fill:#d71526;}</style></defs><title>アセット 15</title><g id="レイヤー_2" data-name="レイヤー 2"><g id="レイヤー_1-2" data-name="レイヤー 1"><path d="M21.87,20A13.2,13.2,0,0,1,34.92,6.83c6.44,0,10.88,4.74,10.88,11a13.21,13.21,0,0,1-13,13.21C26.31,31.05,21.87,26.32,21.87,20Zm20.22-2.1c0-4.34-2.9-7.71-7.27-7.71-5.17,0-9.25,4.51-9.25,9.71,0,4.34,2.91,7.71,7.28,7.71A9.52,9.52,0,0,0,42.09,17.94Z"/><path d="M47.67,20a13.2,13.2,0,0,1,13-13.21c6.44,0,10.88,4.74,10.88,11a13.21,13.21,0,0,1-13,13.21C52.11,31.05,47.67,26.32,47.67,20Zm20.22-2.1c0-4.34-2.9-7.71-7.27-7.71-5.17,0-9.25,4.51-9.25,9.71,0,4.34,2.91,7.71,7.28,7.71C63.85,27.65,67.89,23.14,67.89,17.94Z"/><path d="M72.84,24.81a9.7,9.7,0,0,0,6.41,3c2.4,0,4.07-1.4,4.07-3.57,0-1.57-.94-2.64-3.3-3.87l-1.37-.71a6.56,6.56,0,0,1-4.07-6.14c0-3.9,3.2-6.7,7.47-6.7A12.23,12.23,0,0,1,88.57,8.9l-.68,3.51-.23-.18A10.16,10.16,0,0,0,82,10c-2.2,0-3.84,1.4-3.84,3.3,0,1.17.57,2.37,2.51,3.34l1.33.67C85.46,19.07,87,21,87,24c0,4.3-3.11,7.1-7.61,7.1a11.56,11.56,0,0,1-7.45-2.8l.71-3.65Z"/><path d="M106.27,10.63h-5.85l-3.91,20H92.94l3.91-20H91l.66-3.37h15.32Z"/><path d="M115,21.54l5.27,9.08h-4.14l-5.3-9.74-1.91,9.74h-3.57L109.9,7.26h4.77c4.67,0,7.68,2.54,7.68,6.47S119.44,20.74,115,21.54Zm-3.84-2.37h1.33c3.51,0,6.18-2.17,6.18-5.07,0-2.3-1.7-3.7-4.44-3.7h-1.37Z"/><line class="cls-1" x1="72.32" y1="24.47" x2="72.69" y2="24.81"/><path d="M15.4,16.76l-.76-.31.78-.27C19,15,21.06,12.35,21.06,9.23c0-3.92-3.19-6.65-7.75-6.65H6L.5,30.62H9c5.94,0,10.42-3.48,10.42-8.08A6,6,0,0,0,15.4,16.76ZM8.93,5.68H12.3c2.94,0,4.77,1.55,4.77,4,0,3-2.58,5.18-6,5.18H7.13ZM9.1,27.52H4.75L6.59,18h3.82c3.05,0,5,1.7,5,4.32C15.43,25.34,12.76,27.52,9.1,27.52Z"/><polygon class="cls-2" points="134.09 25.12 132.58 21.09 132.54 20.97 132.49 20.86 127.39 7.26 123.39 7.26 130.13 25.3 121.55 42.09 125.56 42.09 131.87 29.85 131.93 29.73 131.98 29.61 134.06 25.58 134.12 25.47 134.18 25.35 134.14 25.24 134.09 25.12"/><polygon points="139.5 7.26 132.65 20.76 132.65 20.76 132.54 20.98 132.58 21.09 134.09 25.12 134.14 25.24 134.18 25.35 143.5 7.26 139.5 7.26"/><rect class="cls-1" width="143" height="42"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

24
assets/digsas.svg Normal file
View File

@@ -0,0 +1,24 @@
<svg width="128" height="128" viewBox="0 0 128 128" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<path d="M79.4831 1.95572C70.2813 -0.81923 55.2811 -0.617415 46.1549 2.4098L18.6125 11.5167C9.48627 14.5313 9.38542 19.7784 18.3856 23.1588L49.9743 35.028C58.9744 38.4084 73.6217 38.194 82.5084 34.5487L110.883 22.9192C119.782 19.2739 119.53 14.0267 110.316 11.2518L79.4831 1.95572Z" fill="url(#paint0_linear)"/>
<path d="M84.235 38.6101C75.3357 42.2554 68.0625 53.1029 68.0625 62.727V113.635C68.0625 123.259 74.9071 127.245 83.2644 122.489L109.282 107.706C117.639 102.951 124.912 91.208 125.442 81.6092L127.837 37.8281C128.366 28.2167 121.509 23.3479 112.609 26.9932L84.235 38.6101Z" fill="url(#paint1_linear)"/>
<path d="M0.0071345 37.8409C-0.257575 28.2295 6.877 23.1211 15.8771 26.5015L47.4658 38.3707C56.466 41.7511 63.8274 52.3842 63.8274 62.0082V112.916C63.8274 122.54 56.882 126.715 48.386 122.212L17.0998 105.6C8.60392 101.085 1.44415 89.5306 1.16683 79.9192L0.0071345 37.8409Z" fill="url(#paint2_linear)"/>
</g>
<defs>
<linearGradient id="paint0_linear" x1="63.9326" y1="0" x2="63.9326" y2="124.497" gradientUnits="userSpaceOnUse">
<stop stop-color="#036EB8"/>
<stop offset="1" stop-color="#469196"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="63.9326" y1="0" x2="63.9326" y2="124.497" gradientUnits="userSpaceOnUse">
<stop stop-color="#036EB8"/>
<stop offset="1" stop-color="#469196"/>
</linearGradient>
<linearGradient id="paint2_linear" x1="63.9326" y1="0" x2="63.9326" y2="124.497" gradientUnits="userSpaceOnUse">
<stop stop-color="#036EB8"/>
<stop offset="1" stop-color="#469196"/>
</linearGradient>
<clipPath id="clip0">
<rect width="128" height="128" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 980 979.97"><path d="M139.38,0c-185.82-3.54-185.82,277,0,273.46H251.44C437.25,277,437.25-3.5,251.44,0ZM729.25,353.24c-184.92-2.62-184.92,276.1,0,273.48H841.31c184.92,2.62,184.92-276.1,0-273.48ZM138.69,706.46c-184.92-2.61-184.92,276.1,0,273.49H250.75c184.91,2.61,184.91-276.1,0-273.49Z" fill="#b43278"/><path d="M583.47,0c-185.82-3.54-185.82,277,0,273.46H840.61c185.81,3.54,185.81-277,0-273.46ZM138.7,353.24c-184.92-2.62-184.92,276.1,0,273.48H395.85c184.92,2.62,184.92-276.1,0-273.48ZM584.13,706.46c-184.91-2.61-184.91,276.1,0,273.49H841.3c184.92,2.61,184.92-276.1,0-273.49Z" fill="#f65a8e"/></svg>

After

Width:  |  Height:  |  Size: 650 B

BIN
assets/rob_blitz.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

BIN
assets/usertrack.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -22,7 +22,7 @@ assert(process.env.AUTH0_DOMAIN, "You must provide the AUTH0_DOMAIN env variable
assert(process.env.AUTH0_CLIENT_ID, "You must provide the AUTH0_CLIENT_ID env variable")
assert(process.env.AUTH0_CLIENT_SECRET, "You must provide the AUTH0_CLIENT_SECRET env variable")
export default passportAuth(({ctx, req, res}) => ({
export default passportAuth((ctx) => ({
successRedirectUrl: "/",
strategies: [
{

View File

@@ -25,7 +25,7 @@ export const LoginForm = (props: LoginFormProps) => {
try {
await loginMutation(values)
props.onSuccess?.()
} catch (error: any) {
} catch (error) {
if (error instanceof AuthenticationError) {
return {[FORM_ERROR]: "Sorry, those credentials are invalid"}
} else {

View File

@@ -24,7 +24,7 @@ export const SignupForm = (props: SignupFormProps) => {
try {
await signupMutation(values)
props.onSuccess?.()
} catch (error: any) {
} catch (error) {
if (error.code === "P2002" && error.meta?.target?.includes("email")) {
// This error comes from Prisma
return {email: "This email is already being used"}

View File

@@ -8,8 +8,8 @@ beforeEach(async () => {
})
const generatedToken = "plain-token"
jest.mock("next/stdlib-server", () => ({
...jest.requireActual<object>("next/stdlib-server")!,
jest.mock("@blitzjs/core/server", () => ({
...jest.requireActual<object>("@blitzjs/core/server")!,
generateToken: () => generatedToken,
}))
jest.mock("preview-email", () => jest.fn())

View File

@@ -30,7 +30,7 @@ const ResetPasswordPage: BlitzPage = () => {
onSubmit={async (values) => {
try {
await resetPasswordMutation(values)
} catch (error: any) {
} catch (error) {
if (error.name === "ResetPasswordError") {
return {
[FORM_ERROR]: error.message,

View File

@@ -1,7 +1,7 @@
import {useSession, useRouter, useMutation, Head, BlitzLayout} from "blitz"
import {useSession, useRouter, useMutation, Head} from "blitz"
import logout from "app/auth/mutations/logout"
const Layout: BlitzLayout<{title?: string}> = ({title, children}) => {
export default function Layout({title, children}: {title?: string; children: React.ReactNode}) {
const session = useSession({suspense: false})
const router = useRouter()
const [logoutMutation] = useMutation(logout)
@@ -16,8 +16,8 @@ const Layout: BlitzLayout<{title?: string}> = ({title, children}) => {
{session.userId && (
<button
onClick={async () => {
await logoutMutation()
router.push("/")
await logoutMutation()
}}
>
Logout
@@ -28,5 +28,3 @@ const Layout: BlitzLayout<{title?: string}> = ({title, children}) => {
</>
)
}
export default Layout

View File

@@ -1,8 +1,8 @@
import {render} from "test/utils"
import Home from "./index"
jest.mock("next/data-client", () => ({
...jest.requireActual<object>("next/data-client")!,
jest.mock("@blitzjs/core", () => ({
...jest.requireActual<object>("@blitzjs/core")!,
useQuery: () => [
{
id: 1,
@@ -24,4 +24,4 @@ test("renders blitz documentation link", () => {
const element = getByText(/powered by blitz/i)
// @ts-ignore
expect(element).toBeInTheDocument()
})
})

View File

@@ -6,14 +6,12 @@ import {
useRouterQuery,
useMutation,
invoke,
Image,
useQuery,
BlitzPage,
} from "blitz"
import getUser from "app/users/queries/getUser"
import trackView from "app/users/mutations/trackView"
import Layout from "app/core/layouts/Layout"
import logo from "public/logo.png"
import {Routes} from ".blitz"
@@ -90,7 +88,7 @@ const Home: BlitzPage = () => (
<main>
<div className="logo">
<Image src={logo} alt="blitz.js" width={400} height={200} />
<img src="/logo.png" alt="blitz.js" />
</div>
<Suspense fallback={"Loading..."}>

View File

@@ -45,7 +45,7 @@ export const EditProject = () => {
})
await setQueryData(updated)
router.push(`/projects/${updated.id}`)
} catch (error: any) {
} catch (error) {
console.error(error)
return {
[FORM_ERROR]: error.toString(),

View File

@@ -24,7 +24,7 @@ const NewProjectPage: BlitzPage = () => {
try {
const project = await createProjectMutation(values)
router.push(Routes.ShowProjectPage({projectId: project.id}))
} catch (error: any) {
} catch (error) {
console.error(error)
return {
[FORM_ERROR]: error.toString(),

View File

@@ -23,7 +23,7 @@ export const getServerSideProps: GetServerSideProps = async ({req, res}) => {
{res, req},
)
return {props: {user}}
} catch (error: any) {
} catch (error) {
if (error.name === "NotFoundError") {
res.statusCode = 404
res.end()
@@ -46,10 +46,7 @@ export const getServerSideProps: GetServerSideProps = async ({req, res}) => {
}
}
const PageSSR: BlitzPage<InferGetServerSidePropsType<typeof getServerSideProps>> = ({
user,
error,
}) => {
const Test: BlitzPage<InferGetServerSidePropsType<typeof getServerSideProps>> = ({user, error}) => {
const router = useRouter()
const [logoutMutation] = useMutation(logout)
@@ -72,4 +69,4 @@ const PageSSR: BlitzPage<InferGetServerSidePropsType<typeof getServerSideProps>>
)
}
export default PageSSR
export default Test

View File

@@ -1,13 +0,0 @@
import {Ctx} from "blitz"
import db from "db"
export default async function currentUserQuery(_ = null, {session}: Ctx) {
if (!session.userId) return null
const user = await db.user.findFirst({
where: {id: session.userId},
select: {id: true, name: true, email: true, role: true},
})
return user
}

View File

@@ -37,69 +37,4 @@ module.exports = withBundleAnalyzer({
return config
},
*/
codegen: {
templateDir: "./my-templates",
fieldTypeMap: {
string: {
component: "LabeledTextField",
inputType: "text",
zodType: "string",
prismaType: "String",
},
boolean: {
component: "LabeledTextField",
inputType: "text",
zodType: "boolean",
prismaType: "Boolean",
},
int: {
component: "LabeledTextField",
inputType: "number",
zodType: "number",
prismaType: "Int",
},
number: {
component: "LabeledTextField",
inputType: "number",
zodType: "number",
prismaType: "Int",
},
bigint: {
component: "LabeledTextField",
inputType: "number",
zodType: "number",
prismaType: "BigInt",
},
float: {
component: "LabeledTextField",
inputType: "number",
zodType: "number",
prismaType: "Float",
},
decimal: {
component: "LabeledTextField",
inputType: "number",
zodType: "number",
prismaType: "Decimal",
},
datetime: {
component: "LabeledTextField",
inputType: "string",
zodType: "string",
prismaType: "DateTime",
},
uuid: {
component: "LabeledTextField",
inputType: "text",
zodType: "string().uuid",
prismaType: "Uuid",
},
json: {
component: "LabeledTextField",
inputType: "text",
zodType: "any",
prismaType: "Json",
},
},
},
})

View File

@@ -23,7 +23,6 @@ describe("index page", () => {
cy.location("pathname").should("equal", "/")
cy.contains("button", "Logout")
cy.wait(1000)
})
it("allows the user to log in", () => {
@@ -43,7 +42,6 @@ describe("index page", () => {
cy.location("pathname").should("equal", "/")
cy.wait(1000)
cy.contains("button", "Logout")
cy.wait(1000)
})
it("allows the user to logout", () => {

View File

@@ -5,7 +5,6 @@
"dev": "blitz dev",
"build": "blitz build",
"start": "blitz start",
"console": "blitz console",
"studio": "blitz prisma studio",
"lint": "eslint --ignore-path .gitignore --ext .js,.ts,.tsx .",
"analyze": "cross-env ANALYZE=true blitz build",
@@ -30,14 +29,14 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.45.2",
"blitz": "0.38.3-canary.1",
"final-form": "4.20.1",
"passport-auth0": "1.4.0",
"passport-github2": "0.1.12",
"passport-twitter": "1.0.4",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
"react-final-form": "6.5.2"
},
"devDependencies": {
@@ -49,7 +48,7 @@
"@types/passport-github2": "1.2.4",
"@types/passport-twitter": "1.0.36",
"@types/preview-email": "2.0.0",
"@types/react": "17.0.2",
"@types/react": "17.0.13",
"cross-env": "7.0.3",
"cypress": "6.2.1",
"eslint": "7.21.0",

View File

@@ -17,6 +17,6 @@
"downlevelIteration": true,
"jsx": "preserve"
},
"exclude": ["node_modules", "cypress", "test"],
"exclude": ["node_modules", "cypress"],
"include": ["**/*.ts", "**/*.tsx"]
}

View File

@@ -1,3 +1,14 @@
module.exports = {
extends: "blitz",
parser: "@typescript-eslint/parser",
env: {
es2020: true,
},
extends: ["react-app", "plugin:jsx-a11y/recommended"],
plugins: ["@typescript-eslint", "jsx-a11y"],
rules: {
"import/no-anonymous-default-export": "error",
"import/no-webpack-loader-syntax": "off",
"react/react-in-jsx-scope": "off", // React is always in scope with Blitz
"jsx-a11y/anchor-is-valid": "off", //Doesn't play well with Blitz/Next <Link> usage
},
}

View File

@@ -1,6 +1,12 @@
import {Head, BlitzLayout} from "blitz"
import {ReactNode} from "react"
import {Head} from "blitz"
const Layout: BlitzLayout<{title?: string}> = ({title, children}) => {
type LayoutProps = {
title?: string
children: ReactNode
}
const Layout = ({title, children}: LayoutProps) => {
return (
<>
<Head>

View File

@@ -1,9 +1,8 @@
import {Link, BlitzPage, useMutation, Image} from "blitz"
import {Link, BlitzPage, useMutation} from "blitz"
import Layout from "app/layouts/Layout"
import logout from "app/auth/mutations/logout"
import {useCurrentUser} from "app/hooks/useCurrentUser"
import {Suspense} from "react"
import logo from "public/logo.png"
/*
* This file is just for a pleasant getting started page for your new app.
@@ -55,7 +54,7 @@ const Home: BlitzPage = () => {
<div className="container">
<main>
<div className="logo">
<Image src={logo} alt="blitz.js" />
<img src="/logo.png" alt="blitz.js" />
</div>
<p>
<strong>Congrats!</strong> Your app is ready, including user sign-up and log-in.

View File

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

View File

@@ -31,11 +31,11 @@
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.45.2",
"blitz": "0.38.3-canary.1",
"final-form": "4.20.1",
"prisma": "2.24.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react": "18.0.0-alpha-ed6c091fe-20210701",
"react-dom": "18.0.0-alpha-ed6c091fe-20210701",
"react-final-form": "6.5.2",
"secure-password": "4.0.0"
},
@@ -43,7 +43,7 @@
"@cypress/skip-test": "2.6.0",
"@testing-library/react": "11.2.5",
"@testing-library/react-hooks": "^4.0.1",
"@types/react": "17.0.2",
"@types/react": "17.0.13",
"@types/secure-password": "3.1.0",
"cypress": "6.2.1",
"eslint": "7.21.0",

View File

@@ -1,7 +1,7 @@
import blitz from "blitz/custom-server"
import {createServer} from "http"
import {parse} from "url"
import {log} from "next/dist/server/lib/logging"
import {log} from "@blitzjs/display"
const {PORT = "3000"} = process.env
const dev = process.env.NODE_ENV !== "production"

View File

@@ -19,5 +19,5 @@
"tsBuildInfoFile": ".tsbuildinfo"
},
"exclude": ["node_modules"],
"include": ["blitz-env.d.ts", "**/*.ts", "**/*.tsx"]
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
}

View File

@@ -1,11 +0,0 @@
# https://EditorConfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

View File

@@ -1,3 +0,0 @@
# This env file should be checked into source control
# This is the place for default values for all environments
# Values in `.env.local` and `.env.production` will override these values

View File

@@ -1,3 +0,0 @@
module.exports = {
extends: ["blitz"],
}

View File

@@ -1,56 +0,0 @@
# dependencies
node_modules
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
.pnp.*
.npm
web_modules/
# blitz
/.blitz/
/.next/
*.sqlite
*.sqlite-journal
.now
.blitz**
blitz-log.log
# misc
.DS_Store
# local env files
.env.local
.env.*.local
.envrc
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Testing
.coverage
*.lcov
.nyc_output
lib-cov
# Caches
*.tsbuildinfo
.eslintcache
.node_repl_history
.yarn-integrity
# Serverless directories
.serverless/
# Stores VSCode versions used for testing VSCode extensions
.vscode-test

View File

@@ -1,7 +0,0 @@
save-exact=true
legacy-peer-deps=true
public-hoist-pattern[]=next
public-hoist-pattern[]=secure-password
public-hoist-pattern[]=*jest*
public-hoist-pattern[]=@testing-library/*

View File

@@ -1,9 +0,0 @@
.gitkeep
.env*
*.ico
*.lock
db/migrations
.next
.blitz
.yarn
.pnp*

View File

@@ -1,25 +0,0 @@
# **cypress**
This is an example [Cypress](https://www.cypress.io/) integration.
## Getting Started
Migrate the database:
```
blitz prisma migrate dev
```
Run e2e tests:
```
yarn test:e2e
```
Open Cypress dashboard:
```
yarn cypress:open
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

View File

@@ -1,49 +0,0 @@
import { AuthenticationError, Link, useMutation } from "blitz"
import { LabeledTextField } from "app/core/components/LabeledTextField"
import { Form, FORM_ERROR } from "app/core/components/Form"
import login from "app/auth/mutations/login"
import { Login } from "app/auth/validations"
type LoginFormProps = {
onSuccess?: () => 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 {
await loginMutation(values)
props.onSuccess?.()
} 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" />
</Form>
<div style={{ marginTop: "1rem" }}>
Or <Link href="signup">Sign Up</Link>
</div>
</div>
)
}
export default LoginForm

View File

@@ -1,43 +0,0 @@
import { useMutation } from "blitz"
import { LabeledTextField } from "app/core/components/LabeledTextField"
import { Form, FORM_ERROR } from "app/core/components/Form"
import signup from "app/auth/mutations/signup"
import { Signup } from "app/auth/validations"
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")) {
// This error comes from Prisma
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,23 +0,0 @@
import { NotFoundError, SecurePassword, resolver } from "blitz"
import db from "db"
import { authenticateUser } from "./login"
import { ChangePassword } from "../validations"
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,56 +0,0 @@
import { hash256, Ctx } from "blitz"
import forgotPassword from "./forgotPassword"
import db from "db"
import previewEmail from "preview-email"
beforeEach(async () => {
await db.$reset()
})
const generatedToken = "plain-token"
jest.mock("next/stdlib-server", () => ({
...jest.requireActual<object>("next/stdlib-server")!,
generateToken: () => generatedToken,
}))
jest.mock("preview-email", () => jest.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]
// 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,41 +0,0 @@
import { resolver, generateToken, hash256 } from "blitz"
import db from "db"
import { forgotPasswordMailer } from "mailers/forgotPasswordMailer"
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
await forgotPasswordMailer({ to: user.email, token }).send()
} 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 { resolver, SecurePassword, AuthenticationError } from "blitz"
import db from "db"
import { Login } from "../validations"
import { Role } from "types"
export const authenticateUser = async (rawEmail: string, rawPassword: string) => {
const email = rawEmail.toLowerCase().trim()
const password = rawPassword.trim()
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)
await ctx.session.$create({ userId: user.id, role: user.role as 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,82 +0,0 @@
import resetPassword from "./resetPassword"
import db from "db"
import { hash256, SecurePassword } from "blitz"
beforeEach(async () => {
await db.$reset()
})
const mockCtx: any = {
session: {
$create: jest.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,47 +0,0 @@
import { resolver, SecurePassword, hash256 } from "blitz"
import db from "db"
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 resolver.pipe(resolver.zod(ResetPassword), async ({ password, token }, ctx) => {
// 1. Try to find this token in the database
const hashedToken = hash256(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(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 }, ctx)
return true
})

View File

@@ -1,15 +0,0 @@
import { resolver, SecurePassword } from "blitz"
import db from "db"
import { Signup } from "app/auth/validations"
import { Role } from "types"
export default resolver.pipe(resolver.zod(Signup), async ({ email, password }, ctx) => {
const hashedPassword = await SecurePassword.hash(password.trim())
const user = await db.user.create({
data: { email: email.toLowerCase().trim(), hashedPassword, role: "USER" },
select: { id: true, name: true, email: true, role: true },
})
await ctx.session.$create({ userId: user.id, role: user.role as Role })
return user
})

View File

@@ -1,48 +0,0 @@
import { BlitzPage, useMutation } from "blitz"
import Layout from "app/core/layouts/Layout"
import { LabeledTextField } from "app/core/components/LabeledTextField"
import { Form, FORM_ERROR } from "app/core/components/Form"
import { ForgotPassword } from "app/auth/validations"
import forgotPassword from "app/auth/mutations/forgotPassword"
const ForgotPasswordPage: BlitzPage = () => {
const [forgotPasswordMutation, { isSuccess }] = useMutation(forgotPassword)
return (
<div>
<h1>Forgot your password?</h1>
{isSuccess ? (
<div>
<h2>Request Submitted</h2>
<p>
If your email is in our system, you will receive instructions to reset your password
shortly.
</p>
</div>
) : (
<Form
submitText="Send Reset Password Instructions"
schema={ForgotPassword}
initialValues={{ email: "" }}
onSubmit={async (values) => {
try {
await forgotPasswordMutation(values)
} catch (error: any) {
return {
[FORM_ERROR]: "Sorry, we had an unexpected error. Please try again.",
}
}
}}
>
<LabeledTextField name="email" label="Email" placeholder="Email" />
</Form>
)}
</div>
)
}
ForgotPasswordPage.redirectAuthenticatedTo = "/"
ForgotPasswordPage.getLayout = (page) => <Layout title="Forgot Your Password?">{page}</Layout>
export default ForgotPasswordPage

View File

@@ -1,23 +0,0 @@
import { useRouter, BlitzPage } from "blitz"
import Layout from "app/core/layouts/Layout"
import { LoginForm } from "app/auth/components/LoginForm"
const LoginPage: BlitzPage = () => {
const router = useRouter()
return (
<div>
<LoginForm
onSuccess={() => {
const next = router.query.next ? decodeURIComponent(router.query.next as string) : "/"
router.push(next)
}}
/>
</div>
)
}
LoginPage.redirectAuthenticatedTo = "/"
LoginPage.getLayout = (page) => <Layout title="Log In">{page}</Layout>
export default LoginPage

View File

@@ -1,61 +0,0 @@
import { BlitzPage, useRouterQuery, Link, useMutation } from "blitz"
import Layout from "app/core/layouts/Layout"
import { LabeledTextField } from "app/core/components/LabeledTextField"
import { Form, FORM_ERROR } from "app/core/components/Form"
import { ResetPassword } from "app/auth/validations"
import resetPassword from "app/auth/mutations/resetPassword"
import { Routes } from ".blitz"
const ResetPasswordPage: BlitzPage = () => {
const query = useRouterQuery()
const [resetPasswordMutation, { isSuccess }] = useMutation(resetPassword)
return (
<div>
<h1>Set a New Password</h1>
{isSuccess ? (
<div>
<h2>Password Reset Successfully</h2>
<p>
Go to the <Link href={Routes.Home()}>homepage</Link>
</p>
</div>
) : (
<Form
submitText="Reset Password"
schema={ResetPassword}
initialValues={{ password: "", passwordConfirmation: "", token: query.token as string }}
onSubmit={async (values) => {
try {
await resetPasswordMutation(values)
} catch (error: any) {
if (error.name === "ResetPasswordError") {
return {
[FORM_ERROR]: error.message,
}
} else {
return {
[FORM_ERROR]: "Sorry, we had an unexpected error. Please try again.",
}
}
}
}}
>
<LabeledTextField name="password" label="New Password" type="password" />
<LabeledTextField
name="passwordConfirmation"
label="Confirm New Password"
type="password"
/>
</Form>
)}
</div>
)
}
ResetPasswordPage.redirectAuthenticatedTo = "/"
ResetPasswordPage.getLayout = (page) => <Layout title="Reset Your Password">{page}</Layout>
export default ResetPasswordPage

View File

@@ -1,20 +0,0 @@
import { useRouter, BlitzPage } from "blitz"
import Layout from "app/core/layouts/Layout"
import { SignupForm } from "app/auth/components/SignupForm"
import { Routes } from ".blitz"
const SignupPage: BlitzPage = () => {
const router = useRouter()
return (
<div>
<SignupForm onSuccess={() => router.push(Routes.Home())} />
</div>
)
}
SignupPage.redirectAuthenticatedTo = "/"
SignupPage.getLayout = (page) => <Layout title="Sign Up">{page}</Layout>
export default SignupPage

View File

@@ -1,33 +0,0 @@
import { z } from "zod"
const password = z.string().min(10).max(100)
export const Signup = z.object({
email: z.string().email(),
password,
})
export const Login = z.object({
email: z.string().email(),
password: z.string(),
})
export const ForgotPassword = z.object({
email: z.string().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,53 +0,0 @@
import { ReactNode, PropsWithoutRef } from "react"
import { Form as FinalForm, FormProps as FinalFormProps } from "react-final-form"
import { z } from "zod"
import { validateZodSchema } from "blitz"
export { FORM_ERROR } from "final-form"
export interface FormProps<S extends z.ZodType<any, any>>
extends Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit"> {
/** All your form fields */
children?: ReactNode
/** Text to display in the submit button */
submitText?: string
schema?: S
onSubmit: FinalFormProps<z.infer<S>>["onSubmit"]
initialValues?: FinalFormProps<z.infer<S>>["initialValues"]
}
export function Form<S extends z.ZodType<any, any>>({
children,
submitText,
schema,
initialValues,
onSubmit,
...props
}: FormProps<S>) {
return (
<FinalForm
initialValues={initialValues}
validate={validateZodSchema(schema)}
onSubmit={onSubmit}
render={({ handleSubmit, submitting, submitError }) => (
<form onSubmit={handleSubmit} className="form" {...props}>
{/* Form fields supplied as children are rendered here */}
{children}
{submitError && (
<div role="alert" style={{ color: "red" }}>
{submitError}
</div>
)}
{submitText && (
<button type="submit" disabled={submitting}>
{submitText}
</button>
)}
</form>
)}
/>
)
}
export default Form

View File

@@ -1,49 +0,0 @@
import { forwardRef, ComponentPropsWithoutRef, PropsWithoutRef } from "react"
import { useField, UseFieldConfig } from "react-final-form"
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">
fieldProps?: UseFieldConfig<string>
}
export const LabeledTextField = forwardRef<HTMLInputElement, LabeledTextFieldProps>(
({ name, label, outerProps, fieldProps, labelProps, ...props }, ref) => {
const {
input,
meta: { touched, error, submitError, submitting },
} = useField(name, {
parse:
props.type === "number"
? (Number as any)
: // Converting `""` to `null` ensures empty values will be set to null in the DB
(v) => (v === "" ? null : v),
...fieldProps,
})
const normalizedError = Array.isArray(error) ? error.join(", ") : error || submitError
return (
<div {...outerProps}>
<label {...labelProps}>
{label}
<input {...input} disabled={submitting} {...props} ref={ref} />
</label>
{touched && normalizedError && (
<div role="alert" style={{ color: "red" }}>
{normalizedError}
</div>
)}
</div>
)
}
)
export default LabeledTextField

View File

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

View File

@@ -1,22 +0,0 @@
import { ReactNode } from "react"
import { Head } from "blitz"
type LayoutProps = {
title?: string
children: ReactNode
}
const Layout = ({ title, children }: LayoutProps) => {
return (
<>
<Head>
<title>{title || "cypress"}</title>
<link rel="icon" href="/favicon.ico" />
</Head>
{children}
</>
)
}
export default Layout

View File

@@ -1,19 +0,0 @@
import { Head, ErrorComponent } from "blitz"
// ------------------------------------------------------
// This page is rendered if a route match is not found
// ------------------------------------------------------
export default function Page404() {
const statusCode = 404
const title = "This page could not be found"
return (
<>
<Head>
<title>
{statusCode}: {title}
</title>
</Head>
<ErrorComponent statusCode={statusCode} title={title} />
</>
)
}

View File

@@ -1,40 +0,0 @@
import {
AppProps,
ErrorBoundary,
ErrorComponent,
AuthenticationError,
AuthorizationError,
ErrorFallbackProps,
useQueryErrorResetBoundary,
} from "blitz"
import LoginForm from "app/auth/components/LoginForm"
export default function App({ Component, pageProps }: AppProps) {
const getLayout = Component.getLayout || ((page) => page)
return (
<ErrorBoundary
FallbackComponent={RootErrorFallback}
onReset={useQueryErrorResetBoundary().reset}
>
{getLayout(<Component {...pageProps} />)}
</ErrorBoundary>
)
}
function RootErrorFallback({ error, resetErrorBoundary }: ErrorFallbackProps) {
if (error instanceof AuthenticationError) {
return <LoginForm onSuccess={resetErrorBoundary} />
} else if (error instanceof AuthorizationError) {
return (
<ErrorComponent
statusCode={error.statusCode}
title="Sorry, you are not authorized to access this"
/>
)
} else {
return (
<ErrorComponent statusCode={error.statusCode || 400} title={error.message || error.name} />
)
}
}

View File

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

View File

@@ -1,27 +0,0 @@
import { render } from "test/utils"
import Home from "./index"
jest.mock("next/data-client", () => ({
...jest.requireActual<object>("next/data-client")!,
useQuery: () => [
{
id: 1,
name: "User",
email: "user@email.com",
role: "user",
},
],
}))
test("renders blitz documentation link", () => {
// This is an example of how to ensure a specific item is in the document
// But it's disabled by default (by test.skip) so the test doesn't fail
// when you remove the the default content from the page
// This is an example on how to mock api hooks when testing
const { getByText } = render(<Home />)
const element = getByText(/powered by blitz/i)
// @ts-ignore
expect(element).toBeInTheDocument()
})

View File

@@ -1,274 +0,0 @@
import { Suspense } from "react"
import { Image, Link, BlitzPage, useMutation } from "blitz"
import Layout from "app/core/layouts/Layout"
import { useCurrentUser } from "app/core/hooks/useCurrentUser"
import logout from "app/auth/mutations/logout"
import logo from "public/logo.png"
import { Routes } from ".blitz"
/*
* This file is just for a pleasant getting started page for your new app.
* You can delete everything in here and start from scratch if you like.
*/
const UserInfo = () => {
const currentUser = useCurrentUser()
const [logoutMutation] = useMutation(logout)
if (currentUser) {
return (
<>
<button
className="button small"
onClick={async () => {
await logoutMutation()
}}
>
Logout
</button>
<div>
User id: <code>{currentUser.id}</code>
<br />
User role: <code>{currentUser.role}</code>
</div>
</>
)
} else {
return (
<>
<Link href={Routes.SignupPage()}>
<a className="button small">
<strong>Sign Up</strong>
</a>
</Link>
<Link href={Routes.LoginPage()}>
<a className="button small">
<strong>Login</strong>
</a>
</Link>
</>
)
}
}
const Home: BlitzPage = () => {
return (
<div className="container">
<main>
<div className="logo">
<Image src={logo} alt="blitzjs" />
</div>
<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>
<footer>
<a
href="https://blitzjs.com?utm_source=blitz-new&utm_medium=app-template&utm_campaign=blitz-new"
target="_blank"
rel="noopener noreferrer"
>
Powered by 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>
)
}
Home.suppressFirstRenderFlicker = true
Home.getLayout = (page) => <Layout title="Home">{page}</Layout>
export default Home

View File

@@ -1,13 +0,0 @@
import { Ctx } from "blitz"
import db from "db"
export default async function getCurrentUser(_ = null, { session }: Ctx) {
if (!session.userId) return null
const user = await db.user.findFirst({
where: { id: session.userId },
select: { id: true, name: true, email: true, role: true },
})
return user
}

View File

@@ -1,4 +0,0 @@
module.exports = {
presets: ["blitz/babel"],
plugins: [],
}

View File

@@ -1,19 +0,0 @@
import { BlitzConfig, sessionMiddleware, simpleRolesIsAuthorized } from "blitz"
const config: BlitzConfig = {
middleware: [
sessionMiddleware({
cookiePrefix: "cypress-example",
isAuthorized: simpleRolesIsAuthorized,
}),
],
/* Uncomment this to customize the webpack config
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
// Note: we provide webpack above so you should not `require` it
// Perform customizations to webpack config
// Important: return the modified config
return config
},
*/
}
module.exports = config

View File

@@ -1,11 +0,0 @@
{
"baseUrl": "http://localhost:3099",
"integrationFolder": "test/e2e",
"fixturesFolder": false,
"nodeVersion": "system",
"defaultCommandTimeout": 12000,
"pageLoadTimeout": 120000,
"ignoreTestFiles": ["tsconfig.json"],
"chromeWebSecurity": false,
"video": false
}

View File

@@ -1,10 +0,0 @@
module.exports = {
plugins: ["cypress"],
env: {
"cypress/globals": true,
},
extends: ["plugin:cypress/recommended"],
rules: {
"cypress/no-unnecessary-waiting": "off",
},
}

View File

@@ -1,22 +0,0 @@
declare namespace Cypress {
export interface Chainable {
// task for totally resetting the database
task(event: "db:reset", options?: Partial<Loggable & Timeoutable>): Chainable<boolean>
// task for deleting db data without dropping tables
task(event: "db:clear", options?: Partial<Loggable & Timeoutable>): Chainable<boolean>
// task for seeding db with essential data for tests
task(event: "db:seed", options?: Partial<Loggable & Timeoutable>): Chainable<boolean>
// task for creating a new factory
task(
event: "factory",
args: { name: string; attrs?: any },
options?: Partial<Loggable & Timeoutable>
): Chainable<any>
/**
* Logs-in user by using API request
*/
login({ email: string, password: string }): Chainable<Response>
}
}

View File

@@ -1,55 +0,0 @@
process.env.NODE_ENV = "test"
import { loadEnvConfig } from "@blitzjs/env"
loadEnvConfig()
import "./register-ts-paths"
import db from "db"
import seed from "db/seeds"
import { factory } from "test/factories"
let dbSetup = false
const pluginConfig: Cypress.PluginConfig = (on, _config) => {
on("task", {
factory,
"db:reset": async () => {
if (!dbSetup) {
try {
// Only need to do this once at startup
console.log("Resetting database...")
await db.$reset()
console.log("Database reset.")
dbSetup = true
} catch (error) {
console.error(error)
throw new Error("Failed to set up database in cypress/plugins/index.ts")
}
}
return true
},
// for Postgres
// "db:clear": () => {
// Delete all data without dropping tables, so migration isn't required
// await db.$executeRaw`
// do
// $$
// declare
// l_stmt text;
// begin
// select 'truncate ' || string_agg(format('%I.%I', schemaname, tablename), ',')
// into l_stmt from pg_tables
// where schemaname in ('public');
// execute l_stmt;
// end;
// $$
// `
// return true
// },
"db:seed": async () => {
await seed()
return true
},
})
}
export default pluginConfig

View File

@@ -1,2 +0,0 @@
// @ts-ignore
require("tsconfig-paths").register()

View File

@@ -1,10 +0,0 @@
import "@testing-library/cypress/add-commands"
Cypress.Commands.add("login", ({ email, password }) => {
return cy.request("POST", `/api/rpc/login`, {
params: {
email,
password,
},
})
})

View File

@@ -1,24 +0,0 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
import "./commands"
before(() => {
cy.task("db:reset")
})
beforeEach(() => {
// you can clear the database here
cy.task("db:seed")
})

View File

@@ -1,10 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"types": ["cypress", "@types/testing-library__cypress"],
"isolatedModules": false,
"tsBuildInfoFile": ".tsbuildinfo.test"
},
"exclude": ["node_modules"],
"include": ["**/*.ts"]
}

View File

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

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,
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,
FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateIndex
CREATE UNIQUE INDEX "User.email_unique" ON "User"("email");
-- CreateIndex
CREATE UNIQUE INDEX "Session.handle_unique" ON "Session"("handle");
-- CreateIndex
CREATE UNIQUE INDEX "Token.hashedToken_type_unique" 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,65 +0,0 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
datasource db {
provider = "sqlite"
url = "file:./db.sqlite"
}
generator client {
provider = "prisma-client-js"
}
// --------------------------------------
model User {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String?
email String @unique
hashedPassword String?
role String @default("USER")
tokens Token[]
sessions Session[]
}
model Session {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
expiresAt DateTime?
handle String @unique
hashedSessionToken String?
antiCSRFToken String?
publicData String?
privateData String?
user User? @relation(fields: [userId], references: [id])
userId Int?
}
model Token {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
hashedToken String
type String
// See note below about TokenType enum
// type TokenType
expiresAt DateTime
sentTo String
user User @relation(fields: [userId], references: [id])
userId Int
@@unique([hashedToken, type])
}
// NOTE: It's highly recommended to use an enum for the token type
// but enums only work in Postgres.
// See: https://blitzjs.com/docs/database-overview#switch-to-postgre-sql
// enum TokenType {
// RESET_PASSWORD
// }

View File

@@ -1,16 +0,0 @@
// import db from "./index"
/*
* This seed function is executed when you run `blitz db seed`.
*
* Probably you want to use a library like https://chancejs.com
* or https://github.com/Marak/Faker.js to easily generate
* realistic data.
*/
const seed = async () => {
// for (let i = 0; i < 5; i++) {
// await db.project.create({ data: { name: "Project " + i } })
// }
}
export default seed

View File

@@ -1,7 +0,0 @@
import type { Config } from "@jest/types"
const config: Config.InitialOptions = {
preset: "blitz",
}
export default config

View File

@@ -1,45 +0,0 @@
/* TODO - You need to add a mailer integration in `integrations/` and import here.
*
* The integration file can be very simple. Instantiate the email client
* and then export it. That way you can import here and anywhere else
* and use it straight away.
*/
import previewEmail from "preview-email"
type ResetPasswordMailer = {
to: string
token: string
}
export function forgotPasswordMailer({ to, token }: ResetPasswordMailer) {
// In production, set APP_ORIGIN to your production server origin
const origin = process.env.APP_ORIGIN || process.env.BLITZ_DEV_SERVER_ORIGIN
const resetUrl = `${origin}/reset-password?token=${token}`
const msg = {
from: "TODO@example.com",
to,
subject: "Your Password Reset Instructions",
html: `
<h1>Reset Your Password</h1>
<h3>NOTE: You must set up a production email integration in mailers/forgotPasswordMailer.ts</h3>
<a href="${resetUrl}">
Click here to set a new password
</a>
`,
}
return {
async send() {
if (process.env.NODE_ENV === "production") {
// TODO - send the production email, like this:
// await postmark.sendEmail(msg)
throw new Error("No production email implementation in mailers/forgotPasswordMailer")
} else {
// Preview email in the browser
await previewEmail(msg)
}
},
}
}

View File

@@ -1,62 +0,0 @@
{
"name": "@examples/cypress",
"version": "0.41.1",
"scripts": {
"dev": "blitz dev",
"build": "blitz build",
"start": "blitz start",
"studio": "blitz prisma studio",
"lint": "eslint --ignore-path .gitignore --ext .js,.ts,.tsx .",
"cy:open": "cypress open",
"cy:run": "cypress run",
"test:server": "blitz prisma migrate deploy && blitz build && blitz start -p 3099",
"test:e2e": "cross-env NODE_ENV=test start-server-and-test test:server http://localhost:3099 cy:run",
"test:jest": "jest --passWithNoTests",
"test": "blitz codegen && prisma generate && yarn test:jest && yarn test:e2e"
},
"prisma": {
"schema": "db/schema.prisma"
},
"prettier": {
"semi": false,
"printWidth": 100
},
"lint-staged": {
"*.{js,ts,tsx}": [
"eslint --fix"
]
},
"husky": {
"hooks": {
"pre-commit": "tsc && lint-staged && pretty-quick --staged",
"pre-push": "npm run lint && npm run test"
}
},
"dependencies": {
"@prisma/client": "2.24.1",
"blitz": "0.45.2",
"final-form": "4.20.1",
"react": "0.0.0-experimental-6a589ad71",
"react-dom": "0.0.0-experimental-6a589ad71",
"react-final-form": "6.5.2",
"zod": "3.10.1"
},
"devDependencies": {
"@testing-library/cypress": "8.0.1",
"@types/preview-email": "2.0.0",
"@types/react": "17.0.2",
"@types/testing-library__cypress": "5.0.9",
"chance": "1.1.8",
"cross-env": "7.0.3",
"cypress": "6.2.1",
"eslint": "7.21.0",
"husky": "5.1.2",
"lint-staged": "10.5.4",
"prettier": "2.2.1",
"pretty-quick": "3.1.0",
"preview-email": "3.0.3",
"prisma": "2.24.1",
"start-server-and-test": "1.11.7"
},
"private": true
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -1,3 +0,0 @@
module.exports = {
extends: ["../../cypress/.eslintrc.js"],
}

View File

@@ -1,35 +0,0 @@
import { User } from "test/factories"
describe("Login", () => {
describe("with an email that doesnt exist", () => {
it("shows an error", () => {
const email = "nowayshouldIexist@example.com"
const password = "test1234"
cy.visit("/login").wait(100)
cy.findByLabelText(/email/i).type(email)
cy.findByLabelText(/password/i).type(password)
cy.findAllByRole("button", { name: /login/i }).click()
cy.findByText(/invalid/i).should("exist")
})
})
describe("with valid credentials", () => {
it("logs in", () => {
const attrs = { password: "superstrongpassword" }
cy.visit("/login").wait(100)
cy.task("factory", { name: "user", attrs }).then((user: User) => {
cy.findByLabelText(/email/i).type(user.email)
cy.findByLabelText(/password/i).type(attrs.password)
cy.findAllByRole("button", { name: /login/i }).click()
cy.location("pathname").should("equal", "/")
cy.findByText(/logout/i).should("exist")
})
})
})
})

View File

@@ -1,14 +0,0 @@
describe("Signup", () => {
it("creates new account", () => {
const attrs = { email: "blitz@example.com", password: "superstrongpassword" }
cy.visit("/signup").wait(100)
cy.findByLabelText(/email/i).type(attrs.email)
cy.findByLabelText(/password/i).type(attrs.password)
cy.findAllByRole("button", { name: /create account/i }).click()
cy.location("pathname").should("equal", "/")
cy.findByText(/logout/i).should("exist")
})
})

View File

@@ -1,9 +0,0 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"types": ["cypress", "@types/testing-library__cypress"],
"isolatedModules": false
},
"exclude": ["node_modules"],
"include": ["**/*.ts", "../../cypress/**/*.ts"]
}

View File

@@ -1,16 +0,0 @@
import { user } from "./user"
export * from "./user"
export const Factories = {
user,
}
export function factory<T extends keyof typeof Factories>({
name,
attrs,
}: {
name: T
attrs: Parameters<typeof Factories[T]>[0]
}) {
return Factories[name](attrs)
}

View File

@@ -1,22 +0,0 @@
import { PromiseReturnType } from "next/types/utils"
import signup from "app/auth/mutations/signup"
import Chance from "chance"
const chance = new Chance()
const ctx = {
session: { $create: () => {} },
}
type UserAttributes = {
email?: string
password: string
}
export const user = async ({ email = chance.email(), password }: UserAttributes) => {
const user = await signup({ email, password }, ctx as any)
return user
}
export type User = PromiseReturnType<typeof user>

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