Compare commits
279 Commits
authorize-
...
v0.25.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
539f457207 | ||
|
|
383e856e33 | ||
|
|
7d05d4e4c4 | ||
|
|
1555d09a45 | ||
|
|
05bf388d8d | ||
|
|
41ad93b327 | ||
|
|
56b18e40df | ||
|
|
e2acb1a6a1 | ||
|
|
680c44180c | ||
|
|
158b6684a7 | ||
|
|
2a4a209de9 | ||
|
|
4f862f04b0 | ||
|
|
7eb7943b55 | ||
|
|
bf009c2e3e | ||
|
|
94ff1da4de | ||
|
|
a6f4ca0068 | ||
|
|
533e0cbaae | ||
|
|
25df2c0c29 | ||
|
|
c4d759304d | ||
|
|
a856304062 | ||
|
|
be7d0ee723 | ||
|
|
91aebf44bc | ||
|
|
6d45d52f7a | ||
|
|
c451a5d55e | ||
|
|
646e8ae0f6 | ||
|
|
28ded0c1b1 | ||
|
|
8c9de5a1de | ||
|
|
a3c468b779 | ||
|
|
6907e92d14 | ||
|
|
418173849b | ||
|
|
087230e800 | ||
|
|
1ccfc7e5ba | ||
|
|
cdbe9e3cef | ||
|
|
a254b70139 | ||
|
|
c3c0e55597 | ||
|
|
26f8e97b25 | ||
|
|
353e4efea6 | ||
|
|
ae934bc6b7 | ||
|
|
8ebb383764 | ||
|
|
8f7b064cee | ||
|
|
73fa209e9f | ||
|
|
3372307112 | ||
|
|
c1e771d8a7 | ||
|
|
0dc2891387 | ||
|
|
819929e2f6 | ||
|
|
e76f23dc3d | ||
|
|
33c6d8e5e1 | ||
|
|
f927aa05ee | ||
|
|
2efbe7bd51 | ||
|
|
c0e88cb509 | ||
|
|
cb8c268a14 | ||
|
|
6df771c86e | ||
|
|
dbef6f9389 | ||
|
|
f4eaebb52a | ||
|
|
4df2dfd5fc | ||
|
|
f20de5ad53 | ||
|
|
005edc089a | ||
|
|
ddab8d063d | ||
|
|
308744681b | ||
|
|
291b988c05 | ||
|
|
7fdd97bb7d | ||
|
|
02af10133c | ||
|
|
de01a52886 | ||
|
|
cbcbeefd40 | ||
|
|
7083da0297 | ||
|
|
83b08f00eb | ||
|
|
3e7bf85750 | ||
|
|
e9d626d495 | ||
|
|
bc9983a31e | ||
|
|
c798d39c4b | ||
|
|
0394ced3ff | ||
|
|
fc40c9dc23 | ||
|
|
728ef2d2a6 | ||
|
|
bc725db4ec | ||
|
|
6cd3bb32a7 | ||
|
|
14faf68a0b | ||
|
|
e7bdafc2c5 | ||
|
|
241a62e465 | ||
|
|
5118be3ddd | ||
|
|
eebe8bcdfb | ||
|
|
e4983c6f2e | ||
|
|
3d3bb20365 | ||
|
|
77f9e60a9c | ||
|
|
66111f74bf | ||
|
|
c2bb7728b2 | ||
|
|
d5c2fa15e0 | ||
|
|
f93208e75f | ||
|
|
660c7fbb5e | ||
|
|
bcb88c72ea | ||
|
|
b81a3dd314 | ||
|
|
51bdaa118a | ||
|
|
59cf61a26a | ||
|
|
876eb8327f | ||
|
|
018e462ce8 | ||
|
|
74cde8a871 | ||
|
|
bc9f0e9d85 | ||
|
|
683c251693 | ||
|
|
1d02efb21d | ||
|
|
f35da93d6d | ||
|
|
cd2e29b286 | ||
|
|
82e4f7fd95 | ||
|
|
99e64fa2e0 | ||
|
|
9b0dd2ccaa | ||
|
|
0235395e54 | ||
|
|
67ba766a87 | ||
|
|
85216555fc | ||
|
|
25ebbc919b | ||
|
|
312dc3a1a9 | ||
|
|
f31d2a9770 | ||
|
|
0199605d07 | ||
|
|
092775a3f2 | ||
|
|
aea6c88b1e | ||
|
|
846194a5b1 | ||
|
|
814ed2d59a | ||
|
|
41106588ff | ||
|
|
6f50d77756 | ||
|
|
99bf898cdc | ||
|
|
4ef7d81018 | ||
|
|
37ce99a37a | ||
|
|
2f3be902e4 | ||
|
|
968f1d0cb9 | ||
|
|
0b103bccca | ||
|
|
406b643f94 | ||
|
|
33c7bec41f | ||
|
|
3d827c8506 | ||
|
|
b04c6d7469 | ||
|
|
242e2eadee | ||
|
|
08303d337b | ||
|
|
be861c7919 | ||
|
|
092045e807 | ||
|
|
1e0f17c93a | ||
|
|
310079b3bc | ||
|
|
a81252aeb4 | ||
|
|
cc58c72d94 | ||
|
|
2162e1c6b4 | ||
|
|
d46d860338 | ||
|
|
c65360de09 | ||
|
|
9873fc22de | ||
|
|
e6954fbca8 | ||
|
|
048ba5f5cb | ||
|
|
bd1063a965 | ||
|
|
ae6b22f4f0 | ||
|
|
f45d2d5ee3 | ||
|
|
7bc8a249b4 | ||
|
|
742ff71a97 | ||
|
|
9291ae3b38 | ||
|
|
5a5656078b | ||
|
|
ea815e83fa | ||
|
|
869c00c950 | ||
|
|
a670693e9d | ||
|
|
5de91ad57b | ||
|
|
31899458de | ||
|
|
dce462ba53 | ||
|
|
5ebed4b05d | ||
|
|
13353793af | ||
|
|
3583a59aa8 | ||
|
|
1c5aee7c67 | ||
|
|
c87883dbe8 | ||
|
|
7d84561690 | ||
|
|
3f43ffd4fe | ||
|
|
1ac2092129 | ||
|
|
579807ff20 | ||
|
|
566e8be3c3 | ||
|
|
1b9eb77964 | ||
|
|
9f24ba10b2 | ||
|
|
f5237c31c4 | ||
|
|
3ddb3870b9 | ||
|
|
763252a5ed | ||
|
|
6a37f32322 | ||
|
|
48e27be1a7 | ||
|
|
90df4e8409 | ||
|
|
3b46d96ec8 | ||
|
|
13c5a9b802 | ||
|
|
e6ddebadf5 | ||
|
|
1bb4cf33ff | ||
|
|
36dfbe42f5 | ||
|
|
6c06f0b62c | ||
|
|
a83536be21 | ||
|
|
07f9e26827 | ||
|
|
c5e6221ebb | ||
|
|
2b0fe98cf5 | ||
|
|
58386ffe2c | ||
|
|
23fc27027a | ||
|
|
e4c00094e5 | ||
|
|
a357fd0445 | ||
|
|
c43967984b | ||
|
|
e47d947dc0 | ||
|
|
ffb54ec064 | ||
|
|
08abc33494 | ||
|
|
34722f952c | ||
|
|
4003b8ac01 | ||
|
|
160b5fc062 | ||
|
|
b722c39f79 | ||
|
|
8da7bd7cd4 | ||
|
|
712cb172eb | ||
|
|
d623d8cc33 | ||
|
|
5ca38ca6d8 | ||
|
|
db0128c971 | ||
|
|
856aa53843 | ||
|
|
f9c3f82b27 | ||
|
|
97d5f396de | ||
|
|
760fba77ab | ||
|
|
f83ce0bd72 | ||
|
|
7425952616 | ||
|
|
7fac0134b3 | ||
|
|
df46939fe3 | ||
|
|
9e88b11496 | ||
|
|
c427ae23d4 | ||
|
|
cb849c5ba9 | ||
|
|
6e777dd72a | ||
|
|
80ab4876f2 | ||
|
|
cd0bf1f970 | ||
|
|
5f5a5c8ef7 | ||
|
|
9a1e0d0de7 | ||
|
|
fb44203510 | ||
|
|
010057b34c | ||
|
|
575e862ae3 | ||
|
|
aed6b8875a | ||
|
|
10b6f859fd | ||
|
|
9ac856c0ee | ||
|
|
1ff7f36482 | ||
|
|
df150da37e | ||
|
|
eb7409c0b3 | ||
|
|
1411a1d366 | ||
|
|
ec95cb40de | ||
|
|
b502d7ea1e | ||
|
|
74bf2a9e4c | ||
|
|
1ee637c367 | ||
|
|
c08771b57e | ||
|
|
8a468e4f79 | ||
|
|
23a33f1c3d | ||
|
|
b3767861a2 | ||
|
|
65acfff0ff | ||
|
|
ab3fc26409 | ||
|
|
7b7039e0e3 | ||
|
|
e93f24452c | ||
|
|
63c9375331 | ||
|
|
adfb486004 | ||
|
|
5828736369 | ||
|
|
40a93ee62d | ||
|
|
8fa82c7661 | ||
|
|
141003df89 | ||
|
|
6ef7b8a2de | ||
|
|
6ade33b849 | ||
|
|
02d3aa8259 | ||
|
|
1ae2bb3ee3 | ||
|
|
d84c73d2bb | ||
|
|
89b55971f1 | ||
|
|
fd1856bc7b | ||
|
|
e6dbbababb | ||
|
|
3e2b5ddc8e | ||
|
|
1b974a0371 | ||
|
|
8bf9667a15 | ||
|
|
94bd4c166c | ||
|
|
4ad9f9bdc9 | ||
|
|
13e1526ef5 | ||
|
|
ab3021a371 | ||
|
|
3e506c1dce | ||
|
|
85356ca8e8 | ||
|
|
530ce851e4 | ||
|
|
d953ef795a | ||
|
|
7fcb0945a2 | ||
|
|
ab4670c21b | ||
|
|
1ae7bf77b2 | ||
|
|
63e3fe1ccb | ||
|
|
280a2b5c4f | ||
|
|
bf2734d907 | ||
|
|
07341c14d3 | ||
|
|
e150b67cf4 | ||
|
|
1a1722168c | ||
|
|
7f266b0c98 | ||
|
|
6e92a2dfde | ||
|
|
66cd1ec650 | ||
|
|
7c4916324e | ||
|
|
d747e34853 | ||
|
|
3afab440c8 | ||
|
|
e576e6332c | ||
|
|
60d0c9d0bf | ||
|
|
8f800d388b |
@@ -353,11 +353,12 @@
|
||||
"profile": "https://github.com/ntgussoni",
|
||||
"contributions": [
|
||||
"test",
|
||||
"code"
|
||||
"code",
|
||||
"review"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "skn0tt",
|
||||
"login": "Skn0tt",
|
||||
"name": "Simon Knott",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/14912729?v=4",
|
||||
"profile": "http://simonknott.de",
|
||||
@@ -565,15 +566,6 @@
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jletey",
|
||||
"name": "John Letey",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/62398724?v=4",
|
||||
"profile": "https://github.com/jletey",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "pixelmord",
|
||||
"name": "Andreas Adam",
|
||||
@@ -617,7 +609,8 @@
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/1329874?v=4",
|
||||
"profile": "https://jamiedavenport.dev",
|
||||
"contributions": [
|
||||
"code"
|
||||
"code",
|
||||
"maintenance"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -896,7 +889,8 @@
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/8602086?v=4",
|
||||
"profile": "http://ricardotrejos.tech",
|
||||
"contributions": [
|
||||
"code"
|
||||
"code",
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -979,7 +973,8 @@
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/37571416?v=4",
|
||||
"profile": "https://github.com/clgeoio",
|
||||
"contributions": [
|
||||
"code"
|
||||
"code",
|
||||
"test"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -990,6 +985,543 @@
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "nitaking",
|
||||
"name": "Satoshi Nitawaki",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/10850034?v=4",
|
||||
"profile": "https://twitter.com/nitaking_",
|
||||
"contributions": [
|
||||
"code",
|
||||
"maintenance",
|
||||
"question",
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sirmyron",
|
||||
"name": "sirmyron",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/1430136?v=4",
|
||||
"profile": "https://github.com/sirmyron",
|
||||
"contributions": [
|
||||
"doc",
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "engelkes-finstreet",
|
||||
"name": "engelkes-finstreet",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/36962022?v=4",
|
||||
"profile": "https://github.com/engelkes-finstreet",
|
||||
"contributions": [
|
||||
"doc",
|
||||
"code",
|
||||
"maintenance"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "PixelsCommander",
|
||||
"name": "Denis Radin",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/810671?v=4",
|
||||
"profile": "http://twitter.com/pixelscommander",
|
||||
"contributions": [
|
||||
"review",
|
||||
"code",
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "xiaoyu-tamu",
|
||||
"name": "Michael Li",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/33362998?v=4",
|
||||
"profile": "https://github.com/xiaoyu-tamu",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "yuta0801",
|
||||
"name": "yuta0801",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/21266306?v=4",
|
||||
"profile": "https://github.com/yuta0801",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Obii-bit",
|
||||
"name": "Obadja Ris",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/67339820?v=4",
|
||||
"profile": "https://github.com/Obii-bit",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "JoseRFelix",
|
||||
"name": "Jose Felix ",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/21092519?v=4",
|
||||
"profile": "http://jfelix.info",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "johncantrell97",
|
||||
"name": "John Cantrell",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/41305919?v=4",
|
||||
"profile": "https://github.com/johncantrell97",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "cktang88",
|
||||
"name": "Kwuang Tang",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/10319942?v=4",
|
||||
"profile": "http://kwuang.me",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "johnletey",
|
||||
"name": "John Letey",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/62398724?v=4",
|
||||
"profile": "https://github.com/johnletey",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ditorojuan",
|
||||
"name": "Juan Di Toro",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/22530892?v=4",
|
||||
"profile": "https://github.com/ditorojuan",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "taylorcjohnson",
|
||||
"name": "Taylor Johnson",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/10552296?v=4",
|
||||
"profile": "https://github.com/taylorcjohnson",
|
||||
"contributions": [
|
||||
"code",
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "tsriram",
|
||||
"name": "Sriram Thiagarajan",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/450559?v=4",
|
||||
"profile": "https://twitter.com/tsriram",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sergiodxa",
|
||||
"name": "Sergio Xalambrí",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/1312018?v=4",
|
||||
"profile": "https://sergiodxa.com",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "doeixd",
|
||||
"name": "Patrick G",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/13461122?v=4",
|
||||
"profile": "https://github.com/doeixd",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "hardfire",
|
||||
"name": "अभिनाश (Avinash)",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/513457?v=4",
|
||||
"profile": "http://avinash.com.np",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "enricoschaaf",
|
||||
"name": "Enrico Schaaf",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/54645197?v=4",
|
||||
"profile": "http://enricoschaaf.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "kitze",
|
||||
"name": "Kitze",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/1160594?v=4",
|
||||
"profile": "http://kitze.io",
|
||||
"contributions": [
|
||||
"ideas"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "drmas",
|
||||
"name": "Mohamed Shaban",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/644440?v=4",
|
||||
"profile": "https://github.com/drmas",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jorisre",
|
||||
"name": "Joris",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/7545547?v=4",
|
||||
"profile": "https://github.com/jorisre",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Kamshak",
|
||||
"name": "Valentin Funk",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/337968?v=4",
|
||||
"profile": "https://github.com/Kamshak",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "lukebennett",
|
||||
"name": "Luke Bennett",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/135390?v=4",
|
||||
"profile": "https://lukebennett.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "hmajid2301",
|
||||
"name": "Haseeb Majid",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/998807?v=4",
|
||||
"profile": "https://haseebmajid.dev",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "phillippschmedt",
|
||||
"name": "Phillipp Schmedt",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/16028406?v=4",
|
||||
"profile": "https://github.com/phillippschmedt",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "hasparus",
|
||||
"name": "Piotr Monwid-Olechnowicz",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/15332326?v=4",
|
||||
"profile": "https://haspar.us",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "mizchi",
|
||||
"name": "Kotaro Chikuba",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/73962?v=4",
|
||||
"profile": "https://mizchi.dev",
|
||||
"contributions": [
|
||||
"code",
|
||||
"test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "konradkalemba",
|
||||
"name": "Konrad Kalemba",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/8682104?v=4",
|
||||
"profile": "https://github.com/konradkalemba",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Alucard17",
|
||||
"name": "Alucard17",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/26205172?v=4",
|
||||
"profile": "https://github.com/Alucard17",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Dohxis",
|
||||
"name": "Domantas Mauruča",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/8768909?v=4",
|
||||
"profile": "https://github.com/Dohxis",
|
||||
"contributions": [
|
||||
"test",
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sandulat",
|
||||
"name": "Stratulat Alexandru",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/7345874?v=4",
|
||||
"profile": "https://sandulat.com/",
|
||||
"contributions": [
|
||||
"code",
|
||||
"maintenance"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "aericson",
|
||||
"name": "André Ericson",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/692542?v=4",
|
||||
"profile": "https://github.com/aericson",
|
||||
"contributions": [
|
||||
"code",
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "cajotafer",
|
||||
"name": "Carlos Fernández",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/41461969?v=4",
|
||||
"profile": "http://Cajotafer.com",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Kosai106",
|
||||
"name": "Kevin Østerkilde",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/6379824?v=4",
|
||||
"profile": "https://oesterkilde.dk/",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "aaronfulkerson",
|
||||
"name": "aaronfulkerson",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/31112737?v=4",
|
||||
"profile": "https://github.com/aaronfulkerson",
|
||||
"contributions": [
|
||||
"code",
|
||||
"question"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "alexnaiman",
|
||||
"name": "Alexandru Naiman",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/25799714?v=4",
|
||||
"profile": "https://github.com/alexnaiman",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "davidlutta",
|
||||
"name": "David Ezekiel Lutta",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/14890315?v=4",
|
||||
"profile": "https://davidlutta.github.io/portfolio/",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "wanjuntham",
|
||||
"name": "wanjuntham",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/49380551?v=4",
|
||||
"profile": "https://github.com/wanjuntham",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "nahue",
|
||||
"name": "Victor Nahuel Chaves",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/96837?v=4",
|
||||
"profile": "http://www.nahuelchaves.xyz",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "peter50216",
|
||||
"name": "Peter Shih",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/891109?v=4",
|
||||
"profile": "https://github.com/peter50216",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sewerynkalemba",
|
||||
"name": "Seweryn Kalemba",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/37031328?v=4",
|
||||
"profile": "http://seweryn.kale.mba",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "nksaraf",
|
||||
"name": "Nikhil Saraf",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/11255148?v=4",
|
||||
"profile": "https://nksaraf.github.io",
|
||||
"contributions": [
|
||||
"code",
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "zanedb",
|
||||
"name": "Zane",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/16865690?v=4",
|
||||
"profile": "https://zane.sh",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "dulcehc",
|
||||
"name": "Dulce Hernández",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/19391835?v=4",
|
||||
"profile": "https://github.com/dulcehc",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "markhaehnel",
|
||||
"name": "Mark Hähnel",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/1516205?v=4",
|
||||
"profile": "https://markhaehnel.de",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "nemesv",
|
||||
"name": "Viktor Nemes",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/251330?v=4",
|
||||
"profile": "http://stackoverflow.com/users/872395/nemesv",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "goleary",
|
||||
"name": "Gabe O'Leary",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/16123225?v=4",
|
||||
"profile": "http://gabeoleary.com",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "machadolucasvp",
|
||||
"name": "Lucas Machado",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/44952113?v=4",
|
||||
"profile": "https://github.com/machadolucasvp",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "maciekgrzybek",
|
||||
"name": "maciek_grzybek",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/16546428?v=4",
|
||||
"profile": "https://github.com/maciekgrzybek",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "mweibel",
|
||||
"name": "Michael Weibel",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/307427?v=4",
|
||||
"profile": "https://github.com/mweibel",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "isoppp",
|
||||
"name": "Hiroki Isogai",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/16318727?v=4",
|
||||
"profile": "https://isoppp.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "matamatanot",
|
||||
"name": "matamatanot",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/39780486?v=4",
|
||||
"profile": "https://github.com/matamatanot",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "ericsakmar",
|
||||
"name": "Eric Sakmar",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/5620709?v=4",
|
||||
"profile": "https://github.com/ericsakmar",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "leggsimon",
|
||||
"name": "Simon Legg",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/11544418?v=4",
|
||||
"profile": "https://github.com/leggsimon",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "wobsoriano",
|
||||
"name": "Robert Soriano",
|
||||
"avatar_url": "https://avatars3.githubusercontent.com/u/13049130?v=4",
|
||||
"profile": "https://robsoriano.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "benediktms",
|
||||
"name": "Benedikt Schnatterbeck",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/48836135?v=4",
|
||||
"profile": "https://github.com/benediktms",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Talor-A",
|
||||
"name": "Talor Anderson",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/11509865?v=4",
|
||||
"profile": "http://taloranderson.com",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "akirabaruah",
|
||||
"name": "Akira Baruah",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/6751517?v=4",
|
||||
"profile": "https://github.com/akirabaruah",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
29
.eslintrc.js
29
.eslintrc.js
@@ -8,7 +8,7 @@ module.exports = {
|
||||
},
|
||||
project: `./tsconfig.json`,
|
||||
},
|
||||
plugins: ["@typescript-eslint", "import", "unicorn"],
|
||||
plugins: ["@typescript-eslint", "import", "unicorn", "simple-import-sort"],
|
||||
extends: ["react-app"],
|
||||
rules: {
|
||||
"react/react-in-jsx-scope": "off", // React is always in scope with Blitz
|
||||
@@ -24,7 +24,32 @@ module.exports = {
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"no-use-before-define": ["error", {functions: false, classes: false}],
|
||||
// note you must disable the base rule as it can report incorrect errors
|
||||
"no-use-before-define": "off",
|
||||
"@typescript-eslint/no-use-before-define": ["error"],
|
||||
// note you must disable the base rule as it can report incorrect errors
|
||||
"no-redeclare": "off",
|
||||
"@typescript-eslint/no-redeclare": ["error"],
|
||||
"simple-import-sort/sort": [
|
||||
"warn",
|
||||
{
|
||||
groups: [
|
||||
[
|
||||
// Side effect imports.
|
||||
"^\\u0000",
|
||||
// Packages.
|
||||
// Things that start with a letter (or digit or underscore), or `@` followed by a letter.
|
||||
"^@?\\w",
|
||||
// Absolute imports and other imports such as Vue-style `@/foo`.
|
||||
// Anything that does not start with a dot.
|
||||
"^[^.]",
|
||||
// Relative imports.
|
||||
// Anything that starts with a dot.
|
||||
"^\\.",
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
ignorePatterns: ["packages/cli/", "packages/generator/templates", ".eslintrc.js"],
|
||||
overrides: [
|
||||
|
||||
12
.github/workflows/main.yml
vendored
12
.github/workflows/main.yml
vendored
@@ -32,9 +32,9 @@ jobs:
|
||||
**/node_modules
|
||||
/home/runner/.cache/Cypress
|
||||
C:\Users\runneradmin\AppData\Local\Cypress\Cache
|
||||
key: ${{ runner.os }}-yarn-v2-${{ hashFiles('yarn.lock') }}
|
||||
key: ${{ runner.os }}-yarn-v4-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-v2-
|
||||
${{ runner.os }}-yarn-v4-
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile --silent
|
||||
env:
|
||||
@@ -66,9 +66,9 @@ jobs:
|
||||
${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
/home/runner/.cache/Cypress
|
||||
C:\Users\runneradmin\AppData\Local\Cypress\Cache
|
||||
key: ${{ runner.os }}-yarn-v2-${{ hashFiles('yarn.lock') }}
|
||||
key: ${{ runner.os }}-yarn-v4-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-v2-
|
||||
${{ runner.os }}-yarn-v4-
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile --silent
|
||||
env:
|
||||
@@ -107,9 +107,9 @@ jobs:
|
||||
${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
/home/runner/.cache/Cypress
|
||||
C:\Users\runneradmin\AppData\Local\Cypress\Cache
|
||||
key: ${{ runner.os }}-yarn-v2-${{ hashFiles('yarn.lock') }}
|
||||
key: ${{ runner.os }}-yarn-v4-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-v2-
|
||||
${{ runner.os }}-yarn-v4-
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile --silent
|
||||
env:
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -19,3 +19,6 @@ dist
|
||||
**/.env.*.local
|
||||
**/.envrc
|
||||
.blitz-*
|
||||
.blitz-cli-cache
|
||||
.vscode
|
||||
.tsbuildinfo
|
||||
|
||||
1
.node-version
Normal file
1
.node-version
Normal file
@@ -0,0 +1 @@
|
||||
12.16.1
|
||||
105
MAINTAINERS.md
105
MAINTAINERS.md
@@ -1,104 +1 @@
|
||||
# ❤️ Blitz Maintainers
|
||||
|
||||
Aside from the core team, there are two levels of maintainers, described below.
|
||||
|
||||
## Becoming a Maintainer
|
||||
|
||||
We always need more level 1 maintainers! The main requirement is that you can show empathy when communicating online. We'll train you as needed on the other specifics. **This is a great role if you have limited time, because you can spend just as much time as you have without any ongoing responsibilities (unlike level 2)**
|
||||
|
||||
Level 2 maintainers have a much higher responsibility, so usually you will spend time as a level 1 maintainer before moving to level 2.
|
||||
|
||||
Please DM a core team member (Brandon Bayer, Rudi Yardley, or Dylan Brookes) in Slack if you're interested in becoming an official maintainer!
|
||||
|
||||
## Level 1 Maintainers
|
||||
|
||||
Level 1 maintainers are critical for a healthy Blitz community and project. They take a lot of burden off the core team and level 2 maintainers so they can focus on higher level things with longer term impact.
|
||||
|
||||
The primary responsibilities of level 1 maintainers are:
|
||||
|
||||
- Being a friendly, welcoming voice for the Blitz community
|
||||
- Issue triage
|
||||
- Pull request triage
|
||||
- Monitor and answer the `#-help` slack channel
|
||||
- Community encouragement
|
||||
- Community moderation
|
||||
- Tracking and ensuring progress of key issues
|
||||
|
||||
## Level 2 Maintainers
|
||||
|
||||
Level 2 maintainers are the backbone of the project. They are watchdogs over the code, ensuring code quality, correctness, and security. They also facilitate a rapid pace of progress.
|
||||
|
||||
The primary responsibilities of level 2 maintainers are:
|
||||
|
||||
- Code ownership over specific parts of the project
|
||||
- Maintaining and improving the architecture of what they own
|
||||
- Final pull request reviews
|
||||
- Merging pull requests
|
||||
- Tracking and ensuring progress of open pull requests
|
||||
|
||||
## ⚠️ Fundamentals
|
||||
|
||||
Maintainers are the face of the project and the front-line touch point for the community. Therefore maintainers have the very important responsibility of making people feel welcome, valued, understood, and appreciated.
|
||||
|
||||
**Please take time to read and understand everything outlined in this [guide on building welcoming communities](https://opensource.guide/building-community)**
|
||||
|
||||
Some especially important points:
|
||||
|
||||
- **Gratitude:** immediately express gratitude when someone opens an issue or PR. This takes effort/time and we appreciate it
|
||||
- **Responsiveness:** during issue/PR triage, even if we can’t do a full review right away, leave a comment thanking them and saying we’ll review it soon
|
||||
- **Understanding:** it's critical to ensure you understand exactly what someone is saying before you respond. Ask plenty of questions if needed. It's very bad if someone has to reply to your response and say "actually I was asking about X"
|
||||
- In fact, at least one question is almost always required before you can respond appropriately — whether in Github or in Slack
|
||||
|
||||
## Slack
|
||||
|
||||
- All `#-*` channels are for Blitz users
|
||||
- All `#dev-*` channels are for Blitz internal development
|
||||
|
||||
If someone that's not a maintainer post in the wrong area, that's fine. Don't tell them they posted in the wrong place. But as a maintainer, you should for sure post in the right channel :)
|
||||
|
||||
## Issue Triage
|
||||
|
||||
#### If a bug report:
|
||||
|
||||
- Does it have enough information? Versions? Logs? Some way to reproduce?
|
||||
- Has this already been fixed in a previous release?
|
||||
- Is there already an existing issue for this?
|
||||
|
||||
### If a feature/change request:
|
||||
|
||||
- Is it clear what the request is and what the benefit will be?
|
||||
- Is this an obvious win for Blitz? Then accept it
|
||||
- If not obvious, then pull in a core team member or level 2 maintainer for more review
|
||||
|
||||
### Actions
|
||||
|
||||
1. Add tags:
|
||||
- Add a `kind/*` tag
|
||||
- Add a `scope/*` tag
|
||||
- Add a `status/*` tag
|
||||
- Add a good first/second issue tag if appropriate
|
||||
|
||||
## Pull Request Triage
|
||||
|
||||
- Are the changes covered by tests?
|
||||
- Do the changes look ok? Make sure there's no obvious issues
|
||||
|
||||
### Actions
|
||||
|
||||
1. Kindly request any changes if needed
|
||||
2. Else add a Github approval so that level 2 maintainers know it's already had an initial review
|
||||
|
||||
## Final PR Review & Merging (Level 2 maintainers)
|
||||
|
||||
As a level 2 maintainer, it is your responsibility to make sure broken code and regressions never reach the canary branch.
|
||||
|
||||
1. Ensure the PR'ed code fully works as intended and that there are no regressions in related code
|
||||
1. If not fully covered by automated tests, you need to pull down the code locally and manually verify everything (the Github CLI helps with this!)
|
||||
2. During squash & merge:
|
||||
1. Change the commit title to be public friendly - this exact text will go in the release notes
|
||||
2. Add the commit type in the description, in parenthesis like `(patch)`. Commit types:
|
||||
- `major` - major breaking change
|
||||
- `minor` - minor feature addition
|
||||
- `patch` - patches, bug fixes, perf improvements, etc
|
||||
- `example` - change to an example app
|
||||
- `meta` - internal meta change related to the Blitz repo/project
|
||||
This document has moved here: https://blitzjs.com/docs/maintainers
|
||||
|
||||
141
README.md
141
README.md
@@ -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-103-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-160-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">
|
||||
@@ -40,7 +40,9 @@ You need Node.js 12 or newer
|
||||
|
||||
#### Install Blitz
|
||||
|
||||
Run `npm install -g blitz`
|
||||
Run `npm install -g blitz` or `yarn global add blitz`
|
||||
|
||||
_You can alternatively use [`npx`](https://www.npmjs.com/package/npx)_
|
||||
|
||||
#### Create a New App
|
||||
|
||||
@@ -51,6 +53,12 @@ Run `npm install -g blitz`
|
||||
|
||||
<br><br>
|
||||
|
||||
<a aria-label="Bytes Newsletter" href="https://ui.dev/bytes/?r=blitzjs">
|
||||
<img alt="Bytes Newsletter" src="https://files-8wtskjofb.vercel.app/smarter-16x1.jpg">
|
||||
</a>
|
||||
|
||||
<br><br>
|
||||
|
||||

|
||||
|
||||
<br><br>
|
||||
@@ -116,23 +124,36 @@ Your financial contributions help ensure Blitz continues to be developed and mai
|
||||
|
||||
👉 View options and contribute at [GitHub Sponsors](https://github.com/sponsors/blitz-js), [PayPal](https://paypal.me/thebayers), or [Open Collective](https://opencollective.com/blitzjs)
|
||||
|
||||
|
||||
### 🌱 Seedling Sponsors
|
||||
|
||||
<a aria-label="React Bricks" href="https://reactbricks.com/?utm_source=blitzjs&utm_medium=sponsorship&utm_campaign=blitzjs_sponsorship">
|
||||
<img alt="" src="https://reactbricks.com/reactbricks_icon.svg" width="30px">
|
||||
</a>
|
||||
|
||||
### 🥉 Bronze Sponsors
|
||||
|
||||
—
|
||||
<a aria-label="Your Company" href="#">
|
||||
<img alt="" src="https://dummyimage.com/1000x330/efe8ff/000000.png&text=Your+Logo+Here" width="100px">
|
||||
</a>
|
||||
|
||||
### 🥈 Silver Sponsors
|
||||
|
||||
<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="175px">
|
||||
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/canary/assets/Fauna_Logo_Blue.png" width="200px">
|
||||
</a>
|
||||
|
||||
### 🏆 Gold Sponsors
|
||||
|
||||
—
|
||||
<a aria-label="Your Company" href="#">
|
||||
<img alt="" src="https://dummyimage.com/1000x330/efe8ff/000000.png&text=Your+Logo+Here" width="300px">
|
||||
</a>
|
||||
|
||||
### 💎 Diamond Sponsors
|
||||
|
||||
—
|
||||
<a aria-label="Your Company" href="#">
|
||||
<img alt="" src="https://dummyimage.com/1000x330/efe8ff/000000.png&text=Your+Logo+Here" width="400px">
|
||||
</a>
|
||||
|
||||
<br>
|
||||
|
||||
@@ -162,6 +183,7 @@ _Code ownership, pull request approvals and merging, etc_ (see [MAINTAINERS.md](
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/aem"><img src="https://avatars0.githubusercontent.com/u/1909883?v=4" width="100px;" alt=""/><br /><sub><b>Adam Markon</b></sub></a><br />CLI</td>
|
||||
<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>
|
||||
</tr>
|
||||
</table>
|
||||
<!-- markdownlint-enable -->
|
||||
@@ -180,14 +202,15 @@ _Issue triage, pull request triage, community encouragement and moderation, etc_
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/LoriKarikari"><img src="https://avatars1.githubusercontent.com/u/7902980?v=4" width="100px;" alt=""/><br /><sub><b>Lori Karikari</b></sub></a></td>
|
||||
<td align="center"><a href="https://corey-brown.com"><img src="https://avatars1.githubusercontent.com/u/12791148?v=4" width="100px;" alt=""/><br /><sub><b>Corey Brown</b></sub></a></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></td>
|
||||
<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="http://jagascript.com"><img src="https://avatars0.githubusercontent.com/u/4562878?v=4" width="100px;" alt=""/><br /><sub><b>Jaga Santagostino</b></sub></a></td>
|
||||
<td align="center"><a href="https://simonpeterdebbarma.com"><img src="https://avatars3.githubusercontent.com/u/31207418?v=4" width="100px;" alt=""/><br /><sub><b>Simon Debbarma</b></sub></a></td>
|
||||
<td align="center"><a href="https://github.com/jclancy93"><img src="https://avatars2.githubusercontent.com/u/7850202?v=4" width="100px;" alt=""/><br /><sub><b>Jack Clancy</b></sub></a></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://twitter.com/sandulat"><img src="https://avatars2.githubusercontent.com/u/7345874?v=4" width="100px;" alt=""/><br /><sub><b>Alexandru Stratulat</b></sub></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://twitter.com/ivandevp"><img src="https://avatars3.githubusercontent.com/u/9284690?v=4" width="100px;" alt=""/><br /><sub><b>Ivan Medina</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/jdavenport97"><img src="https://avatars2.githubusercontent.com/u/1329874?v=4" width="100px;" alt=""/><br /><sub><b>Jamie Davenport</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>
|
||||
</tr>
|
||||
</table>
|
||||
<!-- markdownlint-enable -->
|
||||
@@ -247,10 +270,10 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
|
||||
<td align="center"><a href="https://mikeattara.com"><img src="https://avatars1.githubusercontent.com/u/31483629?v=4" width="100px;" alt=""/><br /><sub><b>Mike Perry Y Attara</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=mikeattara" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://devanthe.dev"><img src="https://avatars0.githubusercontent.com/u/354652?v=4" width="100px;" alt=""/><br /><sub><b>Devan</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=DevanB" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/jclancy93"><img src="https://avatars2.githubusercontent.com/u/7850202?v=4" width="100px;" alt=""/><br /><sub><b>Jack Clancy</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jclancy93" title="Code">💻</a> <a href="#maintenance-jclancy93" title="Maintenance">🚧</a></td>
|
||||
<td align="center"><a href="https://github.com/ntgussoni"><img src="https://avatars0.githubusercontent.com/u/10161067?v=4" width="100px;" alt=""/><br /><sub><b>Nicolas Torres</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ntgussoni" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=ntgussoni" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/ntgussoni"><img src="https://avatars0.githubusercontent.com/u/10161067?v=4" width="100px;" alt=""/><br /><sub><b>Nicolas Torres</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ntgussoni" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=ntgussoni" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/pulls?q=is%3Apr+reviewed-by%3Antgussoni" title="Reviewed Pull Requests">👀</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://simonknott.de"><img src="https://avatars1.githubusercontent.com/u/14912729?v=4" width="100px;" alt=""/><br /><sub><b>Simon Knott</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=skn0tt" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=skn0tt" title="Tests">⚠️</a> <a href="#maintenance-skn0tt" title="Maintenance">🚧</a></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 /><a href="https://github.com/blitz-js/blitz/commits?author=Skn0tt" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=Skn0tt" title="Tests">⚠️</a> <a href="#maintenance-Skn0tt" title="Maintenance">🚧</a></td>
|
||||
<td align="center"><a href="http://jagascript.com"><img src="https://avatars0.githubusercontent.com/u/4562878?v=4" width="100px;" alt=""/><br /><sub><b>Jaga Santagostino</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=kandros" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=kandros" title="Documentation">📖</a> <a href="#maintenance-kandros" title="Maintenance">🚧</a></td>
|
||||
<td align="center"><a href="http://www.joaoportela.com"><img src="https://avatars0.githubusercontent.com/u/1010018?v=4" width="100px;" alt=""/><br /><sub><b>João Portela</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jportela" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://dajin.dev"><img src="https://avatars0.githubusercontent.com/u/7122182?v=4" width="100px;" alt=""/><br /><sub><b>Da-Jin Chu</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=dajinchu" title="Code">💻</a></td>
|
||||
@@ -278,70 +301,142 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/pgrimaud"><img src="https://avatars1.githubusercontent.com/u/1866496?v=4" width="100px;" alt=""/><br /><sub><b>Pierre Grimaud</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=pgrimaud" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jletey"><img src="https://avatars1.githubusercontent.com/u/62398724?v=4" width="100px;" alt=""/><br /><sub><b>John Letey</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jletey" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://pixelmord.github.io"><img src="https://avatars2.githubusercontent.com/u/224168?v=4" width="100px;" alt=""/><br /><sub><b>Andreas Adam</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=pixelmord" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://kevo.dev"><img src="https://avatars3.githubusercontent.com/u/15717067?v=4" width="100px;" alt=""/><br /><sub><b>Kevin Tovar</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=kevotovar" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://anteprimorac.com.hr"><img src="https://avatars0.githubusercontent.com/u/972083?v=4" width="100px;" alt=""/><br /><sub><b>Ante Primorac</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=anteprimorac" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=anteprimorac" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="http://mykalmachon.dev"><img src="https://avatars1.githubusercontent.com/u/7844994?v=4" width="100px;" alt=""/><br /><sub><b>Mykal Machon</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=MykalMachon" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://jamiedavenport.dev"><img src="https://avatars2.githubusercontent.com/u/1329874?v=4" width="100px;" alt=""/><br /><sub><b>Jamie Davenport</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jamiedavenport" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://jamiedavenport.dev"><img src="https://avatars2.githubusercontent.com/u/1329874?v=4" width="100px;" alt=""/><br /><sub><b>Jamie Davenport</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jamiedavenport" title="Code">💻</a> <a href="#maintenance-jamiedavenport" title="Maintenance">🚧</a></td>
|
||||
<td align="center"><a href="https://cloudnweb.dev/"><img src="https://avatars0.githubusercontent.com/u/17050715?v=4" width="100px;" alt=""/><br /><sub><b>GaneshMani</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ganeshmani" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://cloudnweb.dev/"><img src="https://avatars0.githubusercontent.com/u/17050715?v=4" width="100px;" alt=""/><br /><sub><b>GaneshMani</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ganeshmani" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://ramonmorcillo.com"><img src="https://avatars3.githubusercontent.com/u/31936665?v=4" width="100px;" alt=""/><br /><sub><b>reymon359</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=reymon359" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/gregory-vasquez-96413b184/"><img src="https://avatars1.githubusercontent.com/u/36422346?v=4" width="100px;" alt=""/><br /><sub><b>gvasquez11</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=gvasquez11" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/josemiguelo"><img src="https://avatars1.githubusercontent.com/u/15330034?v=4" width="100px;" alt=""/><br /><sub><b> José Miguel Ochoa</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=josemiguelo" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/osirvent"><img src="https://avatars2.githubusercontent.com/u/5927133?v=4" width="100px;" alt=""/><br /><sub><b>Oscar Sirvent</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=osirvent" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=osirvent" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/donni106"><img src="https://avatars0.githubusercontent.com/u/1942953?v=4" width="100px;" alt=""/><br /><sub><b>Daniel Molnar</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=donni106" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=donni106" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/exclipy"><img src="https://avatars1.githubusercontent.com/u/508799?v=4" width="100px;" alt=""/><br /><sub><b>Kevin Wu Won</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=exclipy" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/tehnuge"><img src="https://avatars1.githubusercontent.com/u/1928236?v=4" width="100px;" alt=""/><br /><sub><b>John Duong</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=tehnuge" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/tehnuge"><img src="https://avatars1.githubusercontent.com/u/1928236?v=4" width="100px;" alt=""/><br /><sub><b>John Duong</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=tehnuge" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://noahfleischmann.com"><img src="https://avatars0.githubusercontent.com/u/23707137?v=4" width="100px;" alt=""/><br /><sub><b>Noah Fleischmann</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=fnoah" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/toshi1127"><img src="https://avatars3.githubusercontent.com/u/32378535?v=4" width="100px;" alt=""/><br /><sub><b>Matsumoto Toshi</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=toshi1127" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=toshi1127" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/simonedelmann"><img src="https://avatars2.githubusercontent.com/u/2821076?v=4" width="100px;" alt=""/><br /><sub><b>Simon Edelmann</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=simonedelmann" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://shaun.church"><img src="https://avatars3.githubusercontent.com/u/571764?v=4" width="100px;" alt=""/><br /><sub><b>Shaun Church</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=shaunchurch" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=shaunchurch" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://styfle.dev"><img src="https://avatars1.githubusercontent.com/u/229881?v=4" width="100px;" alt=""/><br /><sub><b>Steven</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=styfle" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/SigurdMW"><img src="https://avatars3.githubusercontent.com/u/6359003?v=4" width="100px;" alt=""/><br /><sub><b>Sigurd Moland Wahl</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=SigurdMW" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://brianandrews.dev/"><img src="https://avatars1.githubusercontent.com/u/6384100?v=4" width="100px;" alt=""/><br /><sub><b>Brian Andrews</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sbardian" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://brianandrews.dev/"><img src="https://avatars1.githubusercontent.com/u/6384100?v=4" width="100px;" alt=""/><br /><sub><b>Brian Andrews</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sbardian" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="http://garrisonsnelling.com"><img src="https://avatars0.githubusercontent.com/u/5100597?v=4" width="100px;" alt=""/><br /><sub><b>Garrison Snelling</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=garrisons" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/tylangesmith"><img src="https://avatars1.githubusercontent.com/u/22609577?v=4" width="100px;" alt=""/><br /><sub><b>Ty Lange-Smith</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=tylangesmith" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://rubenmoya.dev"><img src="https://avatars3.githubusercontent.com/u/905225?v=4" width="100px;" alt=""/><br /><sub><b>Rubén Moya</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=rubenmoya" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=rubenmoya" title="Tests">⚠️</a></td>
|
||||
<td align="center"><a href="https://github.com/robertgrzonka"><img src="https://avatars0.githubusercontent.com/u/35585466?v=4" width="100px;" alt=""/><br /><sub><b>robertgrzonka</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=robertgrzonka" title="Code">💻</a> <a href="#infra-robertgrzonka" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
||||
<td align="center"><a href="https://github.com/agoxlea"><img src="https://avatars3.githubusercontent.com/u/1240841?v=4" width="100px;" alt=""/><br /><sub><b>Alex Orr</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=agoxlea" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://christse.io"><img src="https://avatars1.githubusercontent.com/u/250450?v=4" width="100px;" alt=""/><br /><sub><b>Chris Tse</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=chris-tse" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://twitter.com/nettofarah"><img src="https://avatars1.githubusercontent.com/u/270688?v=4" width="100px;" alt=""/><br /><sub><b>Netto Farah</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=nettofarah" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://twitter.com/nettofarah"><img src="https://avatars1.githubusercontent.com/u/270688?v=4" width="100px;" alt=""/><br /><sub><b>Netto Farah</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=nettofarah" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/rohanjulka19"><img src="https://avatars0.githubusercontent.com/u/19673968?v=4" width="100px;" alt=""/><br /><sub><b>Rohan Julka</b></sub></a><br /><a href="#infra-rohanjulka19" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
|
||||
<td align="center"><a href="https://www.ivansantos.me"><img src="https://avatars3.githubusercontent.com/u/301291?v=4" width="100px;" alt=""/><br /><sub><b>Ivan Santos</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=pragmaticivan" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://able.bio"><img src="https://avatars0.githubusercontent.com/u/12991390?v=4" width="100px;" alt=""/><br /><sub><b>Soumyajit Pathak</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=drenther" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://www.sebastiankurpiel.com"><img src="https://avatars2.githubusercontent.com/u/16307737?v=4" width="100px;" alt=""/><br /><sub><b>Sebastian Kurpiel</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=SebastianKurp" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/scisteffan"><img src="https://avatars2.githubusercontent.com/u/2676185?v=4" width="100px;" alt=""/><br /><sub><b>Steffan</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=scisteffan" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=scisteffan" title="Documentation">📖</a> <a href="#financial-scisteffan" title="Financial">💵</a></td>
|
||||
<td align="center"><a href="https://github.com/kripod"><img src="https://avatars3.githubusercontent.com/u/14854048?v=4" width="100px;" alt=""/><br /><sub><b>Kristóf Poduszló</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=kripod" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Weilbyte"><img src="https://avatars1.githubusercontent.com/u/43392677?v=4" width="100px;" alt=""/><br /><sub><b>Weilbyte</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Weilbyte" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=Weilbyte" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/Weilbyte"><img src="https://avatars1.githubusercontent.com/u/43392677?v=4" width="100px;" alt=""/><br /><sub><b>Weilbyte</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Weilbyte" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=Weilbyte" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="http://ricardotrejos.tech"><img src="https://avatars1.githubusercontent.com/u/8602086?v=4" width="100px;" alt=""/><br /><sub><b>Ricardo Trejos</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=cardotrejos" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://ricardotrejos.tech"><img src="https://avatars1.githubusercontent.com/u/8602086?v=4" width="100px;" alt=""/><br /><sub><b>Ricardo Trejos</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=cardotrejos" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=cardotrejos" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://gkaragkiaouris.tech/"><img src="https://avatars0.githubusercontent.com/u/8822835?v=4" width="100px;" alt=""/><br /><sub><b>George Karagkiaouris</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=karaggeorge" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=karaggeorge" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://www.linkedin.com/in/brady-pascoe-3bba6b13a/"><img src="https://avatars0.githubusercontent.com/u/18705892?v=4" width="100px;" alt=""/><br /><sub><b>Brady Pascoe</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=bpas247" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://www.yeahcoach.com"><img src="https://avatars1.githubusercontent.com/u/761766?v=4" width="100px;" alt=""/><br /><sub><b>Jirka Svoboda</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=svobik7" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/alan2207"><img src="https://avatars3.githubusercontent.com/u/12713315?v=4" width="100px;" alt=""/><br /><sub><b>Alan Alickovic</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=alan2207" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=alan2207" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://yngve.hoiseth.net"><img src="https://avatars0.githubusercontent.com/u/8469540?v=4" width="100px;" alt=""/><br /><sub><b>Yngve Høiseth</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=yhoiseth" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://twitter.com/bruno_crosier"><img src="https://avatars1.githubusercontent.com/u/18399089?v=4" width="100px;" alt=""/><br /><sub><b>Bruno Crosier</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=brunocrosier" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://twitter.com/bruno_crosier"><img src="https://avatars1.githubusercontent.com/u/18399089?v=4" width="100px;" alt=""/><br /><sub><b>Bruno Crosier</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=brunocrosier" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/jschepmans"><img src="https://avatars2.githubusercontent.com/u/5782977?v=4" width="100px;" alt=""/><br /><sub><b>Johan Schepmans</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jschepmans" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://twitter.com/dillonraphael"><img src="https://avatars0.githubusercontent.com/u/3496193?v=4" width="100px;" alt=""/><br /><sub><b>Dillon Raphael</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=dillonraphael" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/clgeoio"><img src="https://avatars2.githubusercontent.com/u/37571416?v=4" width="100px;" alt=""/><br /><sub><b>Cody G</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=clgeoio" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/clgeoio"><img src="https://avatars2.githubusercontent.com/u/37571416?v=4" width="100px;" alt=""/><br /><sub><b>Cody G</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=clgeoio" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=clgeoio" title="Tests">⚠️</a></td>
|
||||
<td align="center"><a href="https://github.com/madflow"><img src="https://avatars0.githubusercontent.com/u/183248?v=4" width="100px;" alt=""/><br /><sub><b>madflow</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=madflow" title="Documentation">📖</a></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><br /><a href="https://github.com/blitz-js/blitz/commits?author=nitaking" title="Code">💻</a> <a href="#maintenance-nitaking" title="Maintenance">🚧</a> <a href="#question-nitaking" title="Answering Questions">💬</a> <a href="https://github.com/blitz-js/blitz/commits?author=nitaking" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/sirmyron"><img src="https://avatars2.githubusercontent.com/u/1430136?v=4" width="100px;" alt=""/><br /><sub><b>sirmyron</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sirmyron" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=sirmyron" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/engelkes-finstreet"><img src="https://avatars1.githubusercontent.com/u/36962022?v=4" width="100px;" alt=""/><br /><sub><b>engelkes-finstreet</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=engelkes-finstreet" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=engelkes-finstreet" title="Code">💻</a> <a href="#maintenance-engelkes-finstreet" title="Maintenance">🚧</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://twitter.com/pixelscommander"><img src="https://avatars2.githubusercontent.com/u/810671?v=4" width="100px;" alt=""/><br /><sub><b>Denis Radin</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/pulls?q=is%3Apr+reviewed-by%3APixelsCommander" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/blitz-js/blitz/commits?author=PixelsCommander" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=PixelsCommander" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/xiaoyu-tamu"><img src="https://avatars3.githubusercontent.com/u/33362998?v=4" width="100px;" alt=""/><br /><sub><b>Michael Li</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=xiaoyu-tamu" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/yuta0801"><img src="https://avatars2.githubusercontent.com/u/21266306?v=4" width="100px;" alt=""/><br /><sub><b>yuta0801</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=yuta0801" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Obii-bit"><img src="https://avatars2.githubusercontent.com/u/67339820?v=4" width="100px;" alt=""/><br /><sub><b>Obadja Ris</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Obii-bit" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="http://jfelix.info"><img src="https://avatars2.githubusercontent.com/u/21092519?v=4" width="100px;" alt=""/><br /><sub><b>Jose Felix </b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=JoseRFelix" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/johncantrell97"><img src="https://avatars3.githubusercontent.com/u/41305919?v=4" width="100px;" alt=""/><br /><sub><b>John Cantrell</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=johncantrell97" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://kwuang.me"><img src="https://avatars1.githubusercontent.com/u/10319942?v=4" width="100px;" alt=""/><br /><sub><b>Kwuang Tang</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=cktang88" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/johnletey"><img src="https://avatars1.githubusercontent.com/u/62398724?v=4" width="100px;" alt=""/><br /><sub><b>John Letey</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=johnletey" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/ditorojuan"><img src="https://avatars0.githubusercontent.com/u/22530892?v=4" width="100px;" alt=""/><br /><sub><b>Juan Di Toro</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ditorojuan" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/taylorcjohnson"><img src="https://avatars0.githubusercontent.com/u/10552296?v=4" width="100px;" alt=""/><br /><sub><b>Taylor Johnson</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=taylorcjohnson" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=taylorcjohnson" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://twitter.com/tsriram"><img src="https://avatars3.githubusercontent.com/u/450559?v=4" width="100px;" alt=""/><br /><sub><b>Sriram Thiagarajan</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=tsriram" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://sergiodxa.com"><img src="https://avatars2.githubusercontent.com/u/1312018?v=4" width="100px;" alt=""/><br /><sub><b>Sergio Xalambrí</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sergiodxa" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/doeixd"><img src="https://avatars3.githubusercontent.com/u/13461122?v=4" width="100px;" alt=""/><br /><sub><b>Patrick G</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=doeixd" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://avinash.com.np"><img src="https://avatars3.githubusercontent.com/u/513457?v=4" width="100px;" alt=""/><br /><sub><b>अभिनाश (Avinash)</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=hardfire" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://enricoschaaf.com"><img src="https://avatars1.githubusercontent.com/u/54645197?v=4" width="100px;" alt=""/><br /><sub><b>Enrico Schaaf</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=enricoschaaf" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://kitze.io"><img src="https://avatars0.githubusercontent.com/u/1160594?v=4" width="100px;" alt=""/><br /><sub><b>Kitze</b></sub></a><br /><a href="#ideas-kitze" title="Ideas, Planning, & Feedback">🤔</a></td>
|
||||
<td align="center"><a href="https://github.com/drmas"><img src="https://avatars3.githubusercontent.com/u/644440?v=4" width="100px;" alt=""/><br /><sub><b>Mohamed Shaban</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=drmas" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/jorisre"><img src="https://avatars1.githubusercontent.com/u/7545547?v=4" width="100px;" alt=""/><br /><sub><b>Joris</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=jorisre" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Kamshak"><img src="https://avatars3.githubusercontent.com/u/337968?v=4" width="100px;" alt=""/><br /><sub><b>Valentin Funk</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Kamshak" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://lukebennett.com"><img src="https://avatars1.githubusercontent.com/u/135390?v=4" width="100px;" alt=""/><br /><sub><b>Luke Bennett</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=lukebennett" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://haseebmajid.dev"><img src="https://avatars0.githubusercontent.com/u/998807?v=4" width="100px;" alt=""/><br /><sub><b>Haseeb Majid</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=hmajid2301" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/phillippschmedt"><img src="https://avatars0.githubusercontent.com/u/16028406?v=4" width="100px;" alt=""/><br /><sub><b>Phillipp Schmedt</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=phillippschmedt" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://haspar.us"><img src="https://avatars0.githubusercontent.com/u/15332326?v=4" width="100px;" alt=""/><br /><sub><b>Piotr Monwid-Olechnowicz</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=hasparus" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://mizchi.dev"><img src="https://avatars2.githubusercontent.com/u/73962?v=4" width="100px;" alt=""/><br /><sub><b>Kotaro Chikuba</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=mizchi" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=mizchi" title="Tests">⚠️</a></td>
|
||||
<td align="center"><a href="https://github.com/konradkalemba"><img src="https://avatars0.githubusercontent.com/u/8682104?v=4" width="100px;" alt=""/><br /><sub><b>Konrad Kalemba</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=konradkalemba" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Alucard17"><img src="https://avatars1.githubusercontent.com/u/26205172?v=4" width="100px;" alt=""/><br /><sub><b>Alucard17</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Alucard17" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/Dohxis"><img src="https://avatars2.githubusercontent.com/u/8768909?v=4" width="100px;" alt=""/><br /><sub><b>Domantas Mauruča</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Dohxis" title="Tests">⚠️</a> <a href="https://github.com/blitz-js/blitz/commits?author=Dohxis" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://sandulat.com/"><img src="https://avatars0.githubusercontent.com/u/7345874?v=4" width="100px;" alt=""/><br /><sub><b>Stratulat Alexandru</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sandulat" title="Code">💻</a> <a href="#maintenance-sandulat" title="Maintenance">🚧</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/aericson"><img src="https://avatars3.githubusercontent.com/u/692542?v=4" width="100px;" alt=""/><br /><sub><b>André Ericson</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=aericson" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=aericson" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="http://Cajotafer.com"><img src="https://avatars2.githubusercontent.com/u/41461969?v=4" width="100px;" alt=""/><br /><sub><b>Carlos Fernández</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=cajotafer" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://oesterkilde.dk/"><img src="https://avatars1.githubusercontent.com/u/6379824?v=4" width="100px;" alt=""/><br /><sub><b>Kevin Østerkilde</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Kosai106" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/aaronfulkerson"><img src="https://avatars0.githubusercontent.com/u/31112737?v=4" width="100px;" alt=""/><br /><sub><b>aaronfulkerson</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=aaronfulkerson" title="Code">💻</a> <a href="#question-aaronfulkerson" title="Answering Questions">💬</a></td>
|
||||
<td align="center"><a href="https://github.com/alexnaiman"><img src="https://avatars3.githubusercontent.com/u/25799714?v=4" width="100px;" alt=""/><br /><sub><b>Alexandru Naiman</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=alexnaiman" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://davidlutta.github.io/portfolio/"><img src="https://avatars2.githubusercontent.com/u/14890315?v=4" width="100px;" alt=""/><br /><sub><b>David Ezekiel Lutta</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=davidlutta" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/wanjuntham"><img src="https://avatars1.githubusercontent.com/u/49380551?v=4" width="100px;" alt=""/><br /><sub><b>wanjuntham</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=wanjuntham" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://www.nahuelchaves.xyz"><img src="https://avatars3.githubusercontent.com/u/96837?v=4" width="100px;" alt=""/><br /><sub><b>Victor Nahuel Chaves</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=nahue" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/peter50216"><img src="https://avatars3.githubusercontent.com/u/891109?v=4" width="100px;" alt=""/><br /><sub><b>Peter Shih</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=peter50216" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://seweryn.kale.mba"><img src="https://avatars3.githubusercontent.com/u/37031328?v=4" width="100px;" alt=""/><br /><sub><b>Seweryn Kalemba</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=sewerynkalemba" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://nksaraf.github.io"><img src="https://avatars2.githubusercontent.com/u/11255148?v=4" width="100px;" alt=""/><br /><sub><b>Nikhil Saraf</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=nksaraf" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=nksaraf" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://zane.sh"><img src="https://avatars0.githubusercontent.com/u/16865690?v=4" width="100px;" alt=""/><br /><sub><b>Zane</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=zanedb" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/dulcehc"><img src="https://avatars1.githubusercontent.com/u/19391835?v=4" width="100px;" alt=""/><br /><sub><b>Dulce Hernández</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=dulcehc" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://markhaehnel.de"><img src="https://avatars2.githubusercontent.com/u/1516205?v=4" width="100px;" alt=""/><br /><sub><b>Mark Hähnel</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=markhaehnel" title="Code">💻</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="http://stackoverflow.com/users/872395/nemesv"><img src="https://avatars0.githubusercontent.com/u/251330?v=4" width="100px;" alt=""/><br /><sub><b>Viktor Nemes</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=nemesv" title="Code">💻</a></td>
|
||||
<td align="center"><a href="http://gabeoleary.com"><img src="https://avatars1.githubusercontent.com/u/16123225?v=4" width="100px;" alt=""/><br /><sub><b>Gabe O'Leary</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=goleary" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/machadolucasvp"><img src="https://avatars0.githubusercontent.com/u/44952113?v=4" width="100px;" alt=""/><br /><sub><b>Lucas Machado</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=machadolucasvp" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/maciekgrzybek"><img src="https://avatars2.githubusercontent.com/u/16546428?v=4" width="100px;" alt=""/><br /><sub><b>maciek_grzybek</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=maciekgrzybek" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/mweibel"><img src="https://avatars1.githubusercontent.com/u/307427?v=4" width="100px;" alt=""/><br /><sub><b>Michael Weibel</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=mweibel" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://isoppp.com"><img src="https://avatars0.githubusercontent.com/u/16318727?v=4" width="100px;" alt=""/><br /><sub><b>Hiroki Isogai</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=isoppp" title="Code">💻</a></td>
|
||||
<td align="center"><a href="https://github.com/matamatanot"><img src="https://avatars2.githubusercontent.com/u/39780486?v=4" width="100px;" alt=""/><br /><sub><b>matamatanot</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=matamatanot" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="https://github.com/ericsakmar"><img src="https://avatars3.githubusercontent.com/u/5620709?v=4" width="100px;" alt=""/><br /><sub><b>Eric Sakmar</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=ericsakmar" title="Documentation">📖</a></td>
|
||||
<td align="center"><a href="https://github.com/leggsimon"><img src="https://avatars2.githubusercontent.com/u/11544418?v=4" 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" 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" 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" 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" 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>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- markdownlint-enable -->
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
||||
@@ -2,6 +2,7 @@ import {passportAuth} from "blitz"
|
||||
import db from "db"
|
||||
import {Strategy as TwitterStrategy} from "passport-twitter"
|
||||
import {Strategy as GitHubStrategy} from "passport-github2"
|
||||
import {Strategy as Auth0Strategy} from "passport-auth0"
|
||||
|
||||
function assert(condition: any, message: string): asserts condition {
|
||||
if (!condition) throw new Error(message)
|
||||
@@ -16,8 +17,13 @@ assert(
|
||||
assert(process.env.GITHUB_CLIENT_ID, "You must provide the GITHUB_CLIENT_ID env variable")
|
||||
assert(process.env.GITHUB_CLIENT_SECRET, "You must provide the GITHUB_CLIENT_SECRET env variable")
|
||||
|
||||
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({
|
||||
successRedirectUrl: "/",
|
||||
authenticateOptions: {scope: "openid email profile"}, //used for Auth0Strategy - without an empty profile is returned
|
||||
strategies: [
|
||||
new TwitterStrategy(
|
||||
{
|
||||
@@ -85,5 +91,41 @@ export default passportAuth({
|
||||
done(null, {publicData})
|
||||
},
|
||||
),
|
||||
new Auth0Strategy(
|
||||
{
|
||||
domain: process.env.AUTH0_DOMAIN,
|
||||
clientID: process.env.AUTH0_CLIENT_ID,
|
||||
clientSecret: process.env.AUTH0_CLIENT_SECRET,
|
||||
callbackURL:
|
||||
process.env.NODE_ENV === "production"
|
||||
? "https://auth-example-flybayer.blitzjs.vercel.app/api/auth/auth0/callback"
|
||||
: "http://localhost:3000/api/auth/auth0/callback",
|
||||
},
|
||||
async function (_token, _tokenSecret, extraParams, profile, done) {
|
||||
const email = profile.emails && profile.emails[0]?.value
|
||||
|
||||
if (!email) {
|
||||
// This can happen if you haven't enabled email access in your twitter app permissions
|
||||
return done(new Error("GitHub OAuth response doesn't have email."))
|
||||
}
|
||||
|
||||
const user = await db.user.upsert({
|
||||
where: {email},
|
||||
create: {
|
||||
email,
|
||||
name: profile.displayName,
|
||||
},
|
||||
update: {email},
|
||||
})
|
||||
|
||||
const publicData = {
|
||||
userId: user.id,
|
||||
roles: [user.role],
|
||||
source: "auth0",
|
||||
githubUsername: profile.username,
|
||||
}
|
||||
done(undefined, {publicData})
|
||||
},
|
||||
),
|
||||
],
|
||||
})
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import React from "react"
|
||||
import {Link, useMutation, AuthenticationError} from "blitz"
|
||||
import {LabeledTextField} from "app/components/LabeledTextField"
|
||||
import {Form, FORM_ERROR} from "app/components/Form"
|
||||
import login from "app/auth/mutations/login"
|
||||
import {LoginInput, LoginInputType} from "app/auth/validations"
|
||||
import {LoginInput} from "app/auth/validations"
|
||||
|
||||
type LoginFormProps = {
|
||||
onSuccess?: () => void
|
||||
}
|
||||
|
||||
export const LoginForm = (props: LoginFormProps) => {
|
||||
const [loginMutation] = useMutation(login)
|
||||
return (
|
||||
<div>
|
||||
<h1>Login</h1>
|
||||
|
||||
<Form<LoginInputType>
|
||||
submitText="Log In"
|
||||
<Form
|
||||
submitText="Login"
|
||||
schema={LoginInput}
|
||||
initialValues={{email: undefined, password: undefined}}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await login({email: values.email, password: values.password})
|
||||
await loginMutation(values)
|
||||
props.onSuccess && props.onSuccess()
|
||||
} catch (error) {
|
||||
if (error.name === "AuthenticationError") {
|
||||
if (error instanceof AuthenticationError) {
|
||||
return {[FORM_ERROR]: "Sorry, those credentials are invalid"}
|
||||
} else {
|
||||
return {
|
||||
@@ -36,6 +36,9 @@ export const LoginForm = (props: LoginFormProps) => {
|
||||
<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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import {SessionContext} from "blitz"
|
||||
import {Ctx} from "blitz"
|
||||
import {authenticateUser} from "app/auth/auth-utils"
|
||||
import {LoginInput, LoginInputType} from "../validations"
|
||||
|
||||
export default async function login(input: LoginInputType, ctx: {session?: SessionContext} = {}) {
|
||||
export default async function login(input: LoginInputType, {session}: Ctx) {
|
||||
// This throws an error if input is invalid
|
||||
const {email, password} = LoginInput.parse(input)
|
||||
|
||||
// This throws an error if credentials are invalid
|
||||
const user = await authenticateUser(email, password)
|
||||
|
||||
await ctx.session!.create({userId: user.id, roles: [user.role]})
|
||||
await session.create({userId: user.id, roles: [user.role]})
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {SessionContext} from "blitz"
|
||||
import {Ctx} from "blitz"
|
||||
|
||||
export default async function logout(_ = null, ctx: {session?: SessionContext} = {}) {
|
||||
return await ctx.session!.revoke()
|
||||
export default async function logout(_: any, {session}: Ctx) {
|
||||
return await session.revoke()
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import {Ctx} from "blitz"
|
||||
import db from "db"
|
||||
import {SessionContext} from "blitz"
|
||||
import {hashPassword} from "app/auth/auth-utils"
|
||||
import {SignupInput, SignupInputType} from "app/auth/validations"
|
||||
|
||||
export default async function signup(input: SignupInputType, ctx: {session?: SessionContext} = {}) {
|
||||
export default async function signup(input: SignupInputType, {session}: Ctx) {
|
||||
// This throws an error if input is invalid
|
||||
const {email, password} = SignupInput.parse(input)
|
||||
|
||||
@@ -13,7 +13,7 @@ export default async function signup(input: SignupInputType, ctx: {session?: Ses
|
||||
select: {id: true, name: true, email: true, role: true},
|
||||
})
|
||||
|
||||
await ctx.session!.create({userId: user.id, roles: [user.role]})
|
||||
await session.create({userId: user.id, roles: [user.role]})
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react"
|
||||
import {Head, useRouter, BlitzPage} from "blitz"
|
||||
import {LoginForm} from "app/auth/components/LoginForm"
|
||||
|
||||
@@ -8,7 +7,7 @@ const SignupPage: BlitzPage = () => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>Log In</title>
|
||||
<title>Login</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React from "react"
|
||||
import {Head, useRouter, BlitzPage} from "blitz"
|
||||
import {Head, useRouter, BlitzPage, useMutation} from "blitz"
|
||||
import {Form, FORM_ERROR} from "app/components/Form"
|
||||
import {LabeledTextField} from "app/components/LabeledTextField"
|
||||
import signup from "app/auth/mutations/signup"
|
||||
import {SignupInput, SignupInputType} from "app/auth/validations"
|
||||
import {SignupInput} from "app/auth/validations"
|
||||
|
||||
const SignupPage: BlitzPage = () => {
|
||||
const router = useRouter()
|
||||
const [signupMutation] = useMutation(signup)
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -18,12 +18,12 @@ const SignupPage: BlitzPage = () => {
|
||||
<div>
|
||||
<h1>Create an Account</h1>
|
||||
|
||||
<Form<SignupInputType>
|
||||
<Form
|
||||
submitText="Create Account"
|
||||
schema={SignupInput}
|
||||
onSubmit={async (values) => {
|
||||
try {
|
||||
await signup({email: values.email, password: values.password})
|
||||
await signupMutation(values)
|
||||
router.push("/")
|
||||
} catch (error) {
|
||||
if (error.code === "P2002" && error.meta?.target?.includes("email")) {
|
||||
|
||||
@@ -1,28 +1,28 @@
|
||||
import React, {ReactNode, PropsWithoutRef} from "react"
|
||||
import {ReactNode, PropsWithoutRef} from "react"
|
||||
import {Form as FinalForm, FormProps as FinalFormProps} from "react-final-form"
|
||||
import * as z from "zod"
|
||||
export {FORM_ERROR} from "final-form"
|
||||
|
||||
type FormProps<FormValues> = {
|
||||
type FormProps<S extends z.ZodType<any, any>> = {
|
||||
/** All your form fields */
|
||||
children: ReactNode
|
||||
/** Text to display in the submit button */
|
||||
submitText: string
|
||||
onSubmit: FinalFormProps<FormValues>["onSubmit"]
|
||||
initialValues?: FinalFormProps<FormValues>["initialValues"]
|
||||
schema?: z.ZodType<any, any>
|
||||
onSubmit: FinalFormProps<z.infer<S>>["onSubmit"]
|
||||
initialValues?: FinalFormProps<z.infer<S>>["initialValues"]
|
||||
schema?: S
|
||||
} & Omit<PropsWithoutRef<JSX.IntrinsicElements["form"]>, "onSubmit">
|
||||
|
||||
export function Form<FormValues extends Record<string, unknown>>({
|
||||
export function Form<S extends z.ZodType<any, any>>({
|
||||
children,
|
||||
submitText,
|
||||
schema,
|
||||
initialValues,
|
||||
onSubmit,
|
||||
...props
|
||||
}: FormProps<FormValues>) {
|
||||
}: FormProps<S>) {
|
||||
return (
|
||||
<FinalForm<FormValues>
|
||||
<FinalForm
|
||||
initialValues={initialValues}
|
||||
validate={(values) => {
|
||||
if (!schema) return
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {PropsWithoutRef} from "react"
|
||||
import {forwardRef, PropsWithoutRef} from "react"
|
||||
import {useField} from "react-final-form"
|
||||
|
||||
export interface LabeledTextFieldProps extends PropsWithoutRef<JSX.IntrinsicElements["input"]> {
|
||||
@@ -11,7 +11,7 @@ export interface LabeledTextFieldProps extends PropsWithoutRef<JSX.IntrinsicElem
|
||||
outerProps?: PropsWithoutRef<JSX.IntrinsicElements["div"]>
|
||||
}
|
||||
|
||||
export const LabeledTextField = React.forwardRef<HTMLInputElement, LabeledTextFieldProps>(
|
||||
export const LabeledTextField = forwardRef<HTMLInputElement, LabeledTextFieldProps>(
|
||||
({name, label, outerProps, ...props}, ref) => {
|
||||
const {
|
||||
input,
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import {useSession, useRouter} from "blitz"
|
||||
import {useSession, useRouter, useMutation} from "blitz"
|
||||
import logout from "app/auth/mutations/logout"
|
||||
|
||||
export default function Layout({children}: {children: React.ReactNode}) {
|
||||
const session = useSession()
|
||||
const router = useRouter()
|
||||
const [logoutMutation] = useMutation(logout)
|
||||
return (
|
||||
<div>
|
||||
{session.userId && (
|
||||
<button
|
||||
onClick={async () => {
|
||||
router.push("/")
|
||||
await logout()
|
||||
await logoutMutation()
|
||||
}}
|
||||
>
|
||||
Logout
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
import {AppProps, ErrorComponent} from "blitz"
|
||||
import {AppProps, ErrorComponent, useRouter, AuthenticationError, AuthorizationError} from "blitz"
|
||||
import {ErrorBoundary} from "react-error-boundary"
|
||||
import {queryCache} from "react-query"
|
||||
import LoginForm from "app/auth/components/LoginForm"
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
window["DEBUG_BLITZ"] = 1
|
||||
}
|
||||
|
||||
export default function App({Component, pageProps}: AppProps) {
|
||||
const router = useRouter()
|
||||
return (
|
||||
<ErrorBoundary
|
||||
FallbackComponent={RootErrorFallback}
|
||||
resetKeys={[router.asPath]}
|
||||
onReset={() => {
|
||||
// This ensures the Blitz useQuery hooks will automatically refetch
|
||||
// data any time you reset the error boundary
|
||||
@@ -19,9 +25,9 @@ export default function App({Component, pageProps}: AppProps) {
|
||||
}
|
||||
|
||||
function RootErrorFallback({error, resetErrorBoundary}) {
|
||||
if (error.name === "AuthenticationError") {
|
||||
if (error instanceof AuthenticationError) {
|
||||
return <LoginForm onSuccess={resetErrorBoundary} />
|
||||
} else if (error.name === "AuthorizationError") {
|
||||
} else if (error instanceof AuthorizationError) {
|
||||
return (
|
||||
<ErrorComponent
|
||||
statusCode={error.statusCode}
|
||||
|
||||
20
examples/auth/app/pages/index.test.tsx
Normal file
20
examples/auth/app/pages/index.test.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import {render} from "test/utils"
|
||||
|
||||
import Home from "./index"
|
||||
import {useCurrentUser} from "app/hooks/useCurrentUser"
|
||||
|
||||
jest.mock("app/hooks/useCurrentUser")
|
||||
const mockUseCurrentUser = useCurrentUser as jest.MockedFunction<typeof useCurrentUser>
|
||||
|
||||
test("renders blitz documentation link", () => {
|
||||
mockUseCurrentUser.mockReturnValue({
|
||||
id: 1,
|
||||
name: "User",
|
||||
email: "user@email.com",
|
||||
role: "user",
|
||||
})
|
||||
|
||||
const {getByText} = render(<Home />)
|
||||
const element = getByText(/powered by blitz/i)
|
||||
expect(element).toBeInTheDocument()
|
||||
})
|
||||
@@ -1,9 +1,10 @@
|
||||
import {Suspense} from "react"
|
||||
import {Head, Link, useSession, useRouterQuery} from "blitz"
|
||||
import {Head, Link, useSession, useRouterQuery, useMutation, invoke} from "blitz"
|
||||
import getUser from "app/users/queries/getUser"
|
||||
import trackView from "app/users/mutations/trackView"
|
||||
import Layout from "app/layouts/Layout"
|
||||
import {useCurrentUser} from "app/hooks/useCurrentUser"
|
||||
// import getUsers from "app/users/queries/getUsers"
|
||||
|
||||
const CurrentUserInfo = () => {
|
||||
const currentUser = useCurrentUser()
|
||||
@@ -11,12 +12,21 @@ const CurrentUserInfo = () => {
|
||||
return <pre>{JSON.stringify(currentUser, null, 2)}</pre>
|
||||
}
|
||||
|
||||
// const Users = () => {
|
||||
// const [users] = useQuery(getUsers, {})
|
||||
//
|
||||
// return <pre style={{maxWidth: "30rem"}}>{JSON.stringify(users, null, 2)}</pre>
|
||||
// }
|
||||
|
||||
const UserStuff = () => {
|
||||
const session = useSession()
|
||||
const query = useRouterQuery()
|
||||
const [trackViewMutation] = useMutation(trackView)
|
||||
|
||||
if (session.isLoading) return <div>Loading...</div>
|
||||
|
||||
console.log(session.views)
|
||||
|
||||
return (
|
||||
<div>
|
||||
{!session.userId && (
|
||||
@@ -25,7 +35,7 @@ const UserStuff = () => {
|
||||
<Link href="/signup">Sign Up</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Link href="/login">Log In</Link>
|
||||
<Link href="/login">Login</Link>
|
||||
</div>
|
||||
<a href="/api/auth/twitter" style={{display: "block"}}>
|
||||
Login with Twitter
|
||||
@@ -40,10 +50,15 @@ const UserStuff = () => {
|
||||
<Suspense fallback="Loading...">
|
||||
<CurrentUserInfo />
|
||||
</Suspense>
|
||||
{/*
|
||||
<Suspense fallback="Loading...">
|
||||
<Users />
|
||||
</Suspense>
|
||||
*/}
|
||||
<button
|
||||
onClick={async () => {
|
||||
try {
|
||||
const user = await getUser({where: {id: session.userId as number}})
|
||||
const user = await invoke(getUser, {where: {id: session.userId as number}})
|
||||
alert(JSON.stringify(user))
|
||||
} catch (error) {
|
||||
alert("error: " + JSON.stringify(error))
|
||||
@@ -55,7 +70,7 @@ const UserStuff = () => {
|
||||
<button
|
||||
onClick={async () => {
|
||||
try {
|
||||
await trackView()
|
||||
await trackViewMutation()
|
||||
} catch (error) {
|
||||
alert("error: " + error)
|
||||
console.log(error)
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import * as React from "react"
|
||||
import {FC} from "react"
|
||||
import {getSessionContext} from "@blitzjs/server"
|
||||
import {
|
||||
ssrQuery,
|
||||
invokeWithMiddleware,
|
||||
useRouter,
|
||||
GetServerSideProps,
|
||||
PromiseReturnType,
|
||||
ErrorComponent as ErrorPage,
|
||||
useMutation,
|
||||
AuthenticationError,
|
||||
AuthorizationError,
|
||||
} from "blitz"
|
||||
import getUser from "app/users/queries/getUser"
|
||||
import logout from "app/auth/mutations/logout"
|
||||
@@ -30,9 +33,9 @@ export const getServerSideProps: GetServerSideProps<PageProps> = async ({req, re
|
||||
const session = await getSessionContext(req, res)
|
||||
console.log("Session id:", session.userId)
|
||||
try {
|
||||
const user = await ssrQuery(
|
||||
const user = await invokeWithMiddleware(
|
||||
getUser,
|
||||
{where: {id: Number(session.userId)}, select: {id: true}},
|
||||
{where: {id: Number(session.userId)}},
|
||||
{res, req},
|
||||
)
|
||||
return {props: {user}}
|
||||
@@ -41,11 +44,10 @@ export const getServerSideProps: GetServerSideProps<PageProps> = async ({req, re
|
||||
res.statusCode = 404
|
||||
res.end()
|
||||
return {props: {}}
|
||||
} else if (error.name === "AuthenticationError") {
|
||||
res.writeHead(302, {location: "/login"})
|
||||
res.end()
|
||||
} else if (error instanceof AuthenticationError) {
|
||||
res.writeHead(302, {location: "/login"}).end()
|
||||
return {props: {}}
|
||||
} else if (error.name === "AuthorizationError") {
|
||||
} else if (error instanceof AuthorizationError) {
|
||||
return {
|
||||
props: {
|
||||
error: {
|
||||
@@ -60,8 +62,9 @@ export const getServerSideProps: GetServerSideProps<PageProps> = async ({req, re
|
||||
}
|
||||
}
|
||||
|
||||
const Test: React.FC<PageProps> = ({user, error}: PageProps) => {
|
||||
const Test: FC<PageProps> = ({user, error}: PageProps) => {
|
||||
const router = useRouter()
|
||||
const [logoutMutation] = useMutation(logout)
|
||||
|
||||
if (error) {
|
||||
return <ErrorPage statusCode={error.statusCode} title={error.message} />
|
||||
@@ -72,7 +75,7 @@ const Test: React.FC<PageProps> = ({user, error}: PageProps) => {
|
||||
<div>Logged in user id: {user?.id}</div>
|
||||
<button
|
||||
onClick={async () => {
|
||||
await logout()
|
||||
await logoutMutation()
|
||||
router.push("/")
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import React from "react"
|
||||
|
||||
type UserFormProps = {
|
||||
initialValues: any
|
||||
onSubmit: React.FormEventHandler<HTMLFormElement>
|
||||
}
|
||||
|
||||
const UserForm = ({initialValues, onSubmit}: UserFormProps) => {
|
||||
return (
|
||||
<form
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault()
|
||||
onSubmit(event)
|
||||
}}
|
||||
>
|
||||
<div>Put your form fields here. But for now, just click submit</div>
|
||||
<div>{JSON.stringify(initialValues)}</div>
|
||||
<button>Submit</button>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
|
||||
export default UserForm
|
||||
@@ -1,10 +0,0 @@
|
||||
import db, {UserCreateArgs} from "db"
|
||||
|
||||
type CreateUserInput = {
|
||||
data: UserCreateArgs["data"]
|
||||
}
|
||||
export default async function createUser({data}: CreateUserInput, ctx: Record<any, any> = {}) {
|
||||
const user = await db.user.create({data})
|
||||
|
||||
return user
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import db, {UserDeleteArgs} from "db"
|
||||
|
||||
type DeleteUserInput = {
|
||||
where: UserDeleteArgs["where"]
|
||||
}
|
||||
|
||||
export default async function deleteUser({where}: DeleteUserInput, ctx: Record<any, any> = {}) {
|
||||
const user = await db.user.delete({where})
|
||||
|
||||
return user
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import {SessionContext} from "blitz"
|
||||
import {Ctx} from "blitz"
|
||||
|
||||
export default async function trackView(_ = null, ctx: {session?: SessionContext} = {}) {
|
||||
const currentViews = ctx.session!.publicData.views || 0
|
||||
await ctx.session!.setPublicData({views: currentViews + 1})
|
||||
await ctx.session!.setPrivateData({views: currentViews + 1})
|
||||
export default async function trackView(_ = null, {session}: Ctx) {
|
||||
const currentViews = session.publicData.views || 0
|
||||
await session.setPublicData({views: currentViews + 1})
|
||||
await session.setPrivateData({views: currentViews + 1})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import db, {UserUpdateArgs} from "db"
|
||||
|
||||
type UpdateUserInput = {
|
||||
where: UserUpdateArgs["where"]
|
||||
data: UserUpdateArgs["data"]
|
||||
}
|
||||
|
||||
export default async function updateUser(
|
||||
{where, data}: UpdateUserInput,
|
||||
ctx: Record<any, any> = {},
|
||||
) {
|
||||
const user = await db.user.update({where, data})
|
||||
|
||||
return user
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import React, {Suspense} from "react"
|
||||
import {Head, Link, useRouter, useQuery, useParam, BlitzPage} from "blitz"
|
||||
import getUser from "app/users/queries/getUser"
|
||||
import deleteUser from "app/users/mutations/deleteUser"
|
||||
|
||||
export const User = () => {
|
||||
const router = useRouter()
|
||||
const userId = useParam("userId", "number")
|
||||
const [user] = useQuery(getUser, {where: {id: userId}})
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>User {user.id}</h1>
|
||||
<pre>{JSON.stringify(user, null, 2)}</pre>
|
||||
|
||||
{
|
||||
<Link href="/users/[userId]/edit" as={`/users/${user.id}/edit`}>
|
||||
<a>Edit</a>
|
||||
</Link>
|
||||
}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={async () => {
|
||||
if (window.confirm("This will be deleted")) {
|
||||
await deleteUser({where: {id: user.id}})
|
||||
router.push("/users")
|
||||
}
|
||||
}}
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const ShowUserPage: BlitzPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<Head>
|
||||
<title>User</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
|
||||
<main>
|
||||
<p>
|
||||
{
|
||||
<Link href="/users">
|
||||
<a>Users</a>
|
||||
</Link>
|
||||
}
|
||||
</p>
|
||||
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<User />
|
||||
</Suspense>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ShowUserPage
|
||||
@@ -1,63 +0,0 @@
|
||||
import React, {Suspense} from "react"
|
||||
import {Head, Link, useRouter, useQuery, useParam, BlitzPage} from "blitz"
|
||||
import getUser from "app/users/queries/getUser"
|
||||
import updateUser from "app/users/mutations/updateUser"
|
||||
import UserForm from "app/users/components/UserForm"
|
||||
|
||||
export const EditUser = () => {
|
||||
const router = useRouter()
|
||||
const userId = useParam("userId", "number")
|
||||
const [user, {mutate}] = useQuery(getUser, {where: {id: userId}})
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Edit User {user.id}</h1>
|
||||
<pre>{JSON.stringify(user)}</pre>
|
||||
|
||||
<UserForm
|
||||
initialValues={user}
|
||||
onSubmit={async () => {
|
||||
try {
|
||||
const updated = await updateUser({
|
||||
where: {id: user.id},
|
||||
data: {name: "MyNewName"},
|
||||
})
|
||||
mutate(updated)
|
||||
alert("Success!" + JSON.stringify(updated))
|
||||
router.push("/users/[userId]", `/users/${updated.id}`)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
alert("Error creating user " + JSON.stringify(error, null, 2))
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const EditUserPage: BlitzPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<Head>
|
||||
<title>Edit User</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
|
||||
<main>
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<EditUser />
|
||||
</Suspense>
|
||||
|
||||
<p>
|
||||
{
|
||||
<Link href="/users">
|
||||
<a>Users</a>
|
||||
</Link>
|
||||
}
|
||||
</p>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default EditUserPage
|
||||
@@ -1,49 +1,60 @@
|
||||
import React, {Suspense} from "react"
|
||||
import {Head, Link, useQuery, BlitzPage} from "blitz"
|
||||
import getUsers from "app/users/queries/getUsers"
|
||||
import {Suspense} from "react"
|
||||
import Layout from "app/layouts/Layout"
|
||||
import {Link, usePaginatedQuery, useRouter, BlitzPage} from "blitz"
|
||||
import getUsers from "app/users/queries/getUsers"
|
||||
|
||||
const ITEMS_PER_PAGE = 100
|
||||
|
||||
export const UsersList = () => {
|
||||
const [users] = useQuery(getUsers, {orderBy: {id: "desc"}})
|
||||
const router = useRouter()
|
||||
const page = Number(router.query.page) || 0
|
||||
const [{users, hasMore}] = usePaginatedQuery(getUsers, {
|
||||
orderBy: {id: "asc"},
|
||||
skip: ITEMS_PER_PAGE * page,
|
||||
take: ITEMS_PER_PAGE,
|
||||
})
|
||||
|
||||
const goToPreviousPage = () => router.push({query: {page: page - 1}})
|
||||
const goToNextPage = () => router.push({query: {page: page + 1}})
|
||||
|
||||
return (
|
||||
<ul>
|
||||
{users?.map((user) => (
|
||||
<li key={user.id}>
|
||||
<Link href="/users/[userId]" as={`/users/${user.id}`}>
|
||||
<a>{user.email}</a>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div>
|
||||
<ul>
|
||||
{users.map((user) => (
|
||||
<li key={user.id}>
|
||||
<Link href="/users/[userId]" as={`/users/${user.id}`}>
|
||||
<a>{user.email}</a>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<button disabled={page === 0} onClick={goToPreviousPage}>
|
||||
Previous
|
||||
</button>
|
||||
<button disabled={!hasMore} onClick={goToNextPage}>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const UsersPage: BlitzPage = () => {
|
||||
return (
|
||||
<Layout>
|
||||
<Head>
|
||||
<title>Users</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
<div>
|
||||
<p>
|
||||
<Link href="/users/new">
|
||||
<a>Create User</a>
|
||||
</Link>
|
||||
</p>
|
||||
|
||||
<main>
|
||||
<h1>Users</h1>
|
||||
|
||||
<p>
|
||||
{
|
||||
<Link href="/users/new">
|
||||
<a>Create User</a>
|
||||
</Link>
|
||||
}
|
||||
</p>
|
||||
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<UsersList />
|
||||
</Suspense>
|
||||
</main>
|
||||
</Layout>
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<UsersList />
|
||||
</Suspense>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
UsersPage.getLayout = (page) => <Layout>{page}</Layout>
|
||||
|
||||
export default UsersPage
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
import React from "react"
|
||||
import {Head, Link, useRouter, BlitzPage} from "blitz"
|
||||
import createUser from "app/users/mutations/createUser"
|
||||
import UserForm from "app/users/components/UserForm"
|
||||
|
||||
const NewUserPage: BlitzPage = () => {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Head>
|
||||
<title>New User</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
|
||||
<main>
|
||||
<h1>Create New User </h1>
|
||||
|
||||
<UserForm
|
||||
initialValues={{}}
|
||||
onSubmit={async () => {
|
||||
try {
|
||||
const user = await createUser({data: {name: "MyName"}})
|
||||
alert("Success!" + JSON.stringify(user))
|
||||
router.push("/users/[userId]", `/users/${user.id}`)
|
||||
} catch (error) {
|
||||
alert("Error creating user " + JSON.stringify(error, null, 2))
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<p>
|
||||
{
|
||||
<Link href="/users">
|
||||
<a>Users</a>
|
||||
</Link>
|
||||
}
|
||||
</p>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default NewUserPage
|
||||
@@ -1,11 +1,11 @@
|
||||
import {Ctx} from "blitz"
|
||||
import db from "db"
|
||||
import {SessionContext} from "blitz"
|
||||
|
||||
export default async function getCurrentUser(_ = null, ctx: {session?: SessionContext} = {}) {
|
||||
if (!ctx.session?.userId) return null
|
||||
export default async function getCurrentUser(_ = null, ctx: Ctx) {
|
||||
if (!ctx.session.userId) return null
|
||||
|
||||
const user = await db.user.findOne({
|
||||
where: {id: ctx.session!.userId},
|
||||
where: {id: ctx.session.userId},
|
||||
select: {id: true, name: true, email: true, role: true},
|
||||
})
|
||||
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
import {Ctx, NotFoundError} from "blitz"
|
||||
import db, {FindOneUserArgs} from "db"
|
||||
import {SessionContext, NotFoundError} from "blitz"
|
||||
|
||||
type GetUserInput = {
|
||||
where: FindOneUserArgs["where"]
|
||||
select?: FindOneUserArgs["select"]
|
||||
// Only available if a model relationship exists
|
||||
// include?: FindOneUserArgs['include']
|
||||
}
|
||||
|
||||
export default async function getUser(
|
||||
{where, select}: GetUserInput,
|
||||
ctx: {session?: SessionContext} = {},
|
||||
) {
|
||||
ctx.session?.authorize(["admin", "user"])
|
||||
export default async function getUser({where}: GetUserInput, ctx: Ctx) {
|
||||
ctx.session.authorize()
|
||||
console.log(ctx.session.userId)
|
||||
|
||||
const user = await db.user.findOne({where, select})
|
||||
const user = await db.user.findOne({where})
|
||||
|
||||
if (!user) throw new NotFoundError(`User with id ${where.id} does not exist`)
|
||||
|
||||
return user
|
||||
const {hashedPassword, ...rest} = user
|
||||
|
||||
return rest
|
||||
}
|
||||
|
||||
@@ -1,29 +1,26 @@
|
||||
import {Ctx} from "blitz"
|
||||
import db, {FindManyUserArgs} from "db"
|
||||
import {SessionContext} from "blitz"
|
||||
|
||||
type GetUsersInput = {
|
||||
where?: FindManyUserArgs["where"]
|
||||
orderBy?: FindManyUserArgs["orderBy"]
|
||||
cursor?: FindManyUserArgs["cursor"]
|
||||
take?: FindManyUserArgs["take"]
|
||||
skip?: FindManyUserArgs["skip"]
|
||||
// Only available if a model relationship exists
|
||||
// include?: FindManyUserArgs['include']
|
||||
}
|
||||
type GetUsersInput = Pick<FindManyUserArgs, "where" | "orderBy" | "skip" | "take">
|
||||
|
||||
export default async function getUsers(
|
||||
{where, orderBy, cursor, take, skip}: GetUsersInput,
|
||||
ctx: {session?: SessionContext} = {},
|
||||
) {
|
||||
ctx.session?.authorize(["admin"])
|
||||
export default async function getUsers({where, orderBy, skip = 0, take}: GetUsersInput, ctx: Ctx) {
|
||||
ctx.session.authorize()
|
||||
|
||||
const users = await db.user.findMany({
|
||||
where,
|
||||
orderBy,
|
||||
cursor,
|
||||
take,
|
||||
skip,
|
||||
})
|
||||
|
||||
return users
|
||||
const count = await db.user.count()
|
||||
const hasMore = typeof take === "number" ? skip + take < count : false
|
||||
const nextPage = hasMore ? {take, skip: skip + take!} : null
|
||||
|
||||
return {
|
||||
users,
|
||||
nextPage,
|
||||
hasMore,
|
||||
count,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ module.exports = withBundleAnalyzer({
|
||||
middleware: [
|
||||
sessionMiddleware({
|
||||
unstable_isAuthorized: unstable_simpleRolesIsAuthorized,
|
||||
// sessionExpiryMinutes: 1,
|
||||
sessionExpiryMinutes: 4,
|
||||
}),
|
||||
],
|
||||
/*
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:3099",
|
||||
"defaultCommandTimeout": 10000,
|
||||
"video": false
|
||||
"video": false,
|
||||
"chromeWebSecurity": false
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ describe("index page", () => {
|
||||
})
|
||||
|
||||
it("goes to the login page", () => {
|
||||
cy.contains("a", "Log In").click()
|
||||
cy.contains("a", /login/i).click()
|
||||
cy.location("pathname").should("equal", "/login")
|
||||
})
|
||||
|
||||
@@ -30,11 +30,11 @@ describe("index page", () => {
|
||||
cy.signup(user)
|
||||
|
||||
cy.contains("button", "Logout").click()
|
||||
cy.contains("a", "Log In").click()
|
||||
cy.contains("a", /login/i).click()
|
||||
|
||||
cy.contains("Email").find("input").type(user.email)
|
||||
cy.contains("Password").find("input").type(user.password)
|
||||
cy.contains("button", "Log In").click()
|
||||
cy.contains("button", /login/i).click()
|
||||
|
||||
cy.location("pathname").should("equal", "/")
|
||||
cy.contains("button", "Logout")
|
||||
@@ -48,7 +48,7 @@ describe("index page", () => {
|
||||
cy.contains("button", "Logout").click()
|
||||
|
||||
cy.location("pathname").should("equal", "/")
|
||||
cy.contains("a", "Log In")
|
||||
cy.contains("a", /login/i)
|
||||
})
|
||||
|
||||
it("tracks anonymous sessions", () => {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
//@ts-ignore
|
||||
module.exports = (on, config) => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
|
||||
30
examples/auth/jest.config.js
Normal file
30
examples/auth/jest.config.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const {pathsToModuleNameMapper} = require("ts-jest/utils")
|
||||
const {compilerOptions} = require("./tsconfig")
|
||||
|
||||
module.exports = {
|
||||
// Test setup file
|
||||
setupFilesAfterEnv: ["<rootDir>/test/setup.ts"],
|
||||
// Add type checking to Typescript test files
|
||||
preset: "ts-jest",
|
||||
testEnvironment: "jest-environment-jsdom-fourteen",
|
||||
// Automatically clear mock calls and instances between every test
|
||||
clearMocks: true,
|
||||
testPathIgnorePatterns: ["/node_modules/", "/.blitz/", "/.next/", "<rootDir>/db/migrations"],
|
||||
transformIgnorePatterns: ["[/\\\\]node_modules[/\\\\].+\\.(ts|tsx)$"],
|
||||
transform: {
|
||||
"^.+\\.(ts|tsx)$": "babel-jest",
|
||||
},
|
||||
// This makes absolute imports work
|
||||
moduleDirectories: ["node_modules", "<rootDir>"],
|
||||
modulePathIgnorePatterns: ["<rootDir>/.blitz", "<rootDir>/.next", "<rootDir>/cypress"],
|
||||
moduleNameMapper: {
|
||||
// This ensures any path aliases in tsconfig also work in jest
|
||||
...pathsToModuleNameMapper(compilerOptions.paths || {}),
|
||||
"\\.(css|less|sass|scss)$": "identity-obj-proxy",
|
||||
"\\.(gif|ttf|eot|svg|png|jpg|jpeg)$": "<rootDir>/test/__mocks__/fileMock.js",
|
||||
},
|
||||
watchPlugins: ["jest-watch-typeahead/filename", "jest-watch-typeahead/testname"],
|
||||
// Coverage output
|
||||
coverageDirectory: ".coverage",
|
||||
collectCoverageFrom: ["**/*.{js,jsx,ts,tsx}", "!**/*.d.ts", "!**/node_modules/**"],
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@examples/auth",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.25.0",
|
||||
"scripts": {
|
||||
"start": "blitz start",
|
||||
"studio": "blitz db studio",
|
||||
@@ -9,12 +9,17 @@
|
||||
"analyze": "cross-env ANALYZE=true blitz build",
|
||||
"cy:open": "cypress open",
|
||||
"cy:run": "cypress run",
|
||||
"test:start": "blitz db migrate && blitz start --production -p 3099",
|
||||
"test": "cross-env NODE_ENV=test start-server-and-test test:start http://localhost:3099 cy:run"
|
||||
"test": "prisma generate && yarn test:jest && yarn test:e2e",
|
||||
"test:jest": "jest",
|
||||
"test:server": "blitz db migrate && blitz start --production -p 3099",
|
||||
"test:e2e": "cross-env NODE_ENV=test start-server-and-test test:server http://localhost:3099 cy:run"
|
||||
},
|
||||
"browserslist": [
|
||||
"defaults"
|
||||
],
|
||||
"prisma": {
|
||||
"schema": "db/schema.prisma"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
"printWidth": 100,
|
||||
@@ -33,14 +38,15 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/cli": "2.4.1",
|
||||
"@prisma/client": "2.4.1",
|
||||
"blitz": "0.21.2-canary.1",
|
||||
"@prisma/cli": "2.10.0",
|
||||
"@prisma/client": "2.10.0",
|
||||
"blitz": "0.25.0",
|
||||
"final-form": "4.20.1",
|
||||
"passport-auth0": "1.3.3",
|
||||
"passport-github2": "0.1.11",
|
||||
"passport-twitter": "1.0.4",
|
||||
"react": "0.0.0-experimental-7f28234f8",
|
||||
"react-dom": "0.0.0-experimental-7f28234f8",
|
||||
"react": "0.0.0-experimental-4ead6b530",
|
||||
"react-dom": "0.0.0-experimental-4ead6b530",
|
||||
"react-error-boundary": "2.3.1",
|
||||
"react-final-form": "6.5.1",
|
||||
"secure-password": "4.0.0",
|
||||
@@ -49,6 +55,11 @@
|
||||
"devDependencies": {
|
||||
"@cypress/skip-test": "2.5.0",
|
||||
"@next/bundle-analyzer": "latest",
|
||||
"@testing-library/jest-dom": "5.11.4",
|
||||
"@testing-library/react": "11.1.0",
|
||||
"@testing-library/react-hooks": "3.4.2",
|
||||
"@types/jest": "26.0.14",
|
||||
"@types/passport-auth0": "1.0.4",
|
||||
"@types/passport-github2": "1.2.4",
|
||||
"@types/passport-twitter": "1.0.36",
|
||||
"@types/react": "16.9.38",
|
||||
@@ -67,10 +78,14 @@
|
||||
"eslint-plugin-react": "7.20.5",
|
||||
"eslint-plugin-react-hooks": "4.0.8",
|
||||
"husky": "4.2.5",
|
||||
"jest": "26.5.3",
|
||||
"jest-environment-jsdom-fourteen": "1.0.1",
|
||||
"jest-watch-typeahead": "0.6.1",
|
||||
"lint-staged": "10.2.13",
|
||||
"prettier": "2.0.5",
|
||||
"pretty-quick": "2.0.1",
|
||||
"start-server-and-test": "1.11.2",
|
||||
"ts-jest": "26.4.1",
|
||||
"typescript": "3.9.5"
|
||||
},
|
||||
"private": true
|
||||
|
||||
1
examples/auth/test/__mocks__/fileMock.js
Normal file
1
examples/auth/test/__mocks__/fileMock.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = "test-file-stub"
|
||||
6
examples/auth/test/setup.ts
Normal file
6
examples/auth/test/setup.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import "@testing-library/jest-dom/extend-expect"
|
||||
require("dotenv-flow").config({silent: true})
|
||||
88
examples/auth/test/utils.tsx
Normal file
88
examples/auth/test/utils.tsx
Normal file
@@ -0,0 +1,88 @@
|
||||
import {RouterContext, BlitzRouter} from "blitz"
|
||||
import {render as defaultRender} from "@testing-library/react"
|
||||
import {renderHook as defaultRenderHook} from "@testing-library/react-hooks"
|
||||
|
||||
export * from "@testing-library/react"
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// This file customizes the render() and renderHook() test functions provided
|
||||
// by React testing library. It adds a router context wrapper with a mocked router.
|
||||
//
|
||||
// You should always import `render` and `renderHook` from this file
|
||||
//
|
||||
// This is the place to add any other context providers you need while testing.
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
// --------------------------------------------------
|
||||
// render()
|
||||
// --------------------------------------------------
|
||||
// Override the default test render with our own
|
||||
//
|
||||
// You can override the router mock like this:
|
||||
//
|
||||
// const { baseElement } = render(<MyComponent />, {
|
||||
// router: { pathname: '/my-custom-pathname' },
|
||||
// });
|
||||
// --------------------------------------------------
|
||||
export function render(ui: RenderUI, {wrapper, router, ...options}: RenderOptions = {}) {
|
||||
if (!wrapper) {
|
||||
// Add a default context wrapper if one isn't supplied from the test
|
||||
wrapper = ({children}) => (
|
||||
<RouterContext.Provider value={{...mockRouter, ...router}}>{children}</RouterContext.Provider>
|
||||
)
|
||||
}
|
||||
return defaultRender(ui, {wrapper, ...options})
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// renderHook()
|
||||
// --------------------------------------------------
|
||||
// Override the default test renderHook with our own
|
||||
//
|
||||
// You can override the router mock like this:
|
||||
//
|
||||
// const result = renderHook(() => myHook(), {
|
||||
// router: { pathname: '/my-custom-pathname' },
|
||||
// });
|
||||
// --------------------------------------------------
|
||||
export function renderHook(
|
||||
hook: RenderHook,
|
||||
{wrapper, router, ...options}: RenderHookOptions = {},
|
||||
) {
|
||||
if (!wrapper) {
|
||||
// Add a default context wrapper if one isn't supplied from the test
|
||||
wrapper = ({children}) => (
|
||||
<RouterContext.Provider value={{...mockRouter, ...router}}>{children}</RouterContext.Provider>
|
||||
)
|
||||
}
|
||||
return defaultRenderHook(hook, {wrapper, ...options})
|
||||
}
|
||||
|
||||
export const mockRouter: BlitzRouter = {
|
||||
basePath: "",
|
||||
pathname: "/",
|
||||
route: "/",
|
||||
asPath: "/",
|
||||
params: {},
|
||||
query: {},
|
||||
push: jest.fn(),
|
||||
replace: jest.fn(),
|
||||
reload: jest.fn(),
|
||||
back: jest.fn(),
|
||||
prefetch: jest.fn(),
|
||||
beforePopState: jest.fn(),
|
||||
events: {
|
||||
on: jest.fn(),
|
||||
off: jest.fn(),
|
||||
emit: jest.fn(),
|
||||
},
|
||||
isFallback: false,
|
||||
}
|
||||
|
||||
type DefaultParams = Parameters<typeof defaultRender>
|
||||
type RenderUI = DefaultParams[0]
|
||||
type RenderOptions = DefaultParams[1] & {router?: Partial<BlitzRouter>}
|
||||
|
||||
type DefaultHookParams = Parameters<typeof defaultRenderHook>
|
||||
type RenderHook = DefaultHookParams[0]
|
||||
type RenderHookOptions = DefaultHookParams[1] & {router?: Partial<BlitzRouter>}
|
||||
12
examples/auth/types.ts
Normal file
12
examples/auth/types.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import {DefaultCtx, SessionContext, DefaultPublicData} from "blitz"
|
||||
import {User} from "db"
|
||||
|
||||
declare module "blitz" {
|
||||
export interface Ctx extends DefaultCtx {
|
||||
session: SessionContext
|
||||
}
|
||||
export interface PublicData extends DefaultPublicData {
|
||||
userId: User["id"]
|
||||
views?: number
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "no-prisma",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.25.0",
|
||||
"scripts": {
|
||||
"start": "blitz start",
|
||||
"build": "blitz build",
|
||||
@@ -26,10 +26,10 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"blitz": "0.21.2-canary.1",
|
||||
"blitz": "0.25.0",
|
||||
"knex": "0.21.2",
|
||||
"react": "0.0.0-experimental-7f28234f8",
|
||||
"react-dom": "0.0.0-experimental-7f28234f8",
|
||||
"react": "0.0.0-experimental-4ead6b530",
|
||||
"react-dom": "0.0.0-experimental-4ead6b530",
|
||||
"sqlite3": "5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -29,7 +29,7 @@ export const EditProject = () => {
|
||||
},
|
||||
})
|
||||
alert("Success!" + JSON.stringify(updated))
|
||||
router.push("/projects/[id]", `/projects/${updated.id}`)
|
||||
router.push(`/projects/${updated.id}`)
|
||||
} catch (error) {
|
||||
alert("Error creating project " + JSON.stringify(error, null, 2))
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ const NewProjectPage = () => {
|
||||
},
|
||||
})
|
||||
alert("Success!" + JSON.stringify(project))
|
||||
router.push("/projects/[id]", `/projects/${project.id}`)
|
||||
router.push(`/projects/${project.id}`)
|
||||
} catch (error) {
|
||||
alert("Error creating project " + JSON.stringify(error, null, 2))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@examples/plain-js",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.25.0",
|
||||
"scripts": {
|
||||
"start": "blitz start",
|
||||
"build": "blitz db migrate && blitz build",
|
||||
@@ -29,11 +29,11 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/cli": "2.4.1",
|
||||
"@prisma/client": "2.4.1",
|
||||
"blitz": "0.21.2-canary.1",
|
||||
"react": "0.0.0-experimental-7f28234f8",
|
||||
"react-dom": "0.0.0-experimental-7f28234f8"
|
||||
"@prisma/cli": "2.10.0",
|
||||
"@prisma/client": "2.10.0",
|
||||
"blitz": "0.25.0",
|
||||
"react": "0.0.0-experimental-4ead6b530",
|
||||
"react-dom": "0.0.0-experimental-4ead6b530"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "16.9.35",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,14 +6,16 @@ import ProductForm from "app/products/components/ProductForm"
|
||||
function Product() {
|
||||
const router = useRouter()
|
||||
const id = useParam("id", "number")
|
||||
const [product, {mutate}] = useQuery(getProduct, {where: {id}})
|
||||
const [product] = useQuery(getProduct, {where: {id}})
|
||||
|
||||
// Here to test for https://github.com/blitz-js/blitz/issues/1443
|
||||
if (!product) throw new Error("useQuery did not throw!")
|
||||
|
||||
return (
|
||||
<ProductForm
|
||||
product={product}
|
||||
onSuccess={(updatedProduct) => {
|
||||
mutate(updatedProduct)
|
||||
router.push("/admin/products")
|
||||
onSuccess={async () => {
|
||||
await router.push("/admin/products")
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -1,28 +1,54 @@
|
||||
import {Suspense} from "react"
|
||||
import {useQuery, Link, useRouterQuery} from "blitz"
|
||||
import {Suspense, useState} from "react"
|
||||
import {useQuery, Link, useRouterQuery, invalidateQuery, setQueryData} from "blitz"
|
||||
import getProducts from "app/products/queries/getProducts"
|
||||
import getProduct from "app/products/queries/getProduct"
|
||||
// import getProduct from "app/products/queries/getProduct"
|
||||
|
||||
function reversedProductList(productsList) {
|
||||
return {...productsList, products: [...productsList.products].reverse()}
|
||||
}
|
||||
|
||||
function ProductsList() {
|
||||
const {orderby = "id", order = "desc"} = useRouterQuery()
|
||||
|
||||
const [{products}] = useQuery(getProducts, {
|
||||
const [refetch, setRefetch] = useState(false)
|
||||
const params = {
|
||||
orderBy: {
|
||||
[Array.isArray(orderby) ? orderby[0] : orderby]: order,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const [{products}] = useQuery(getProducts, params)
|
||||
|
||||
return (
|
||||
<ul>
|
||||
{products.map((product) => (
|
||||
<li key={product.id}>
|
||||
<Link href="/admin/products/[id]" as={`/admin/products/${product.id}`}>
|
||||
<a onMouseEnter={() => getProduct({where: {id: product.id}})}>{product.name}</a>
|
||||
</Link>{" "}
|
||||
- Created: {product.createdAt.toISOString()}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<>
|
||||
<button onClick={() => setQueryData(getProducts, params, reversedProductList, {refetch})}>
|
||||
Reverse
|
||||
</button>
|
||||
<label>
|
||||
<input
|
||||
name="refetch"
|
||||
type="checkbox"
|
||||
checked={refetch}
|
||||
onChange={(event) => setRefetch(event.target.checked)}
|
||||
/>
|
||||
Refetch
|
||||
</label>
|
||||
|
||||
<ul>
|
||||
{products.map((product) => (
|
||||
<li key={product.id}>
|
||||
<Link href="/admin/products/[id]" as={`/admin/products/${product.id}`}>
|
||||
<a
|
||||
// Disable until prefetch api added
|
||||
//onMouseEnter={() => getProduct({where: {id: product.id}})}
|
||||
>
|
||||
{product.name}
|
||||
</a>
|
||||
</Link>{" "}
|
||||
- Created: {product.createdAt.toISOString()}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,6 +57,8 @@ function AdminProducts() {
|
||||
<div>
|
||||
<h1>Products</h1>
|
||||
|
||||
<button onClick={() => invalidateQuery(getProducts)}>Invalidate query</button>
|
||||
|
||||
<p>
|
||||
<Link href="/admin/products/new">
|
||||
<a>Create Product</a>
|
||||
|
||||
@@ -2,6 +2,10 @@ import {AppProps, ErrorComponent} from "blitz"
|
||||
import {ErrorBoundary} from "react-error-boundary"
|
||||
import {queryCache} from "react-query"
|
||||
|
||||
if (typeof window !== "undefined") {
|
||||
window["DEBUG_BLITZ"] = 1
|
||||
}
|
||||
|
||||
export default function App({Component, pageProps}: AppProps) {
|
||||
return (
|
||||
<ErrorBoundary
|
||||
|
||||
@@ -2,6 +2,7 @@ import {Form, Field} from "react-final-form"
|
||||
import {Product, ProductCreateInput, ProductUpdateInput} from "db"
|
||||
import createProduct from "../mutations/createProduct"
|
||||
import updateProduct from "../mutations/updateProduct"
|
||||
import {useMutation} from "blitz"
|
||||
|
||||
type ProductInput = ProductCreateInput | Product
|
||||
|
||||
@@ -16,13 +17,15 @@ type ProductFormProps = {
|
||||
}
|
||||
|
||||
function ProductForm({product, style, onSuccess, ...props}: ProductFormProps) {
|
||||
const [createProductMutation] = useMutation(createProduct)
|
||||
const [updateProductMutation] = useMutation(updateProduct)
|
||||
return (
|
||||
<Form
|
||||
initialValues={product || {name: null, handle: null, description: null, price: null}}
|
||||
onSubmit={async (data: any) => {
|
||||
if (isNew(data)) {
|
||||
try {
|
||||
const product = await createProduct({data})
|
||||
const product = await createProductMutation({data})
|
||||
onSuccess(product)
|
||||
} catch (error) {
|
||||
alert("Error creating product " + JSON.stringify(error, null, 2))
|
||||
@@ -32,7 +35,7 @@ function ProductForm({product, style, onSuccess, ...props}: ProductFormProps) {
|
||||
// Can't update id
|
||||
const id = data.id
|
||||
delete data.id
|
||||
const product = await updateProduct({where: {id}, data})
|
||||
const product = await updateProductMutation({where: {id}, data})
|
||||
onSuccess(product)
|
||||
} catch (error) {
|
||||
alert("Error updating product " + JSON.stringify(error, null, 2))
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import db, {ProductUpdateArgs} from "db"
|
||||
import {Ctx} from "blitz"
|
||||
|
||||
type UpdateProductInput = {
|
||||
where: ProductUpdateArgs["where"]
|
||||
data: ProductUpdateArgs["data"]
|
||||
}
|
||||
|
||||
export default async function updateProduct({where, data}: UpdateProductInput) {
|
||||
export default async function updateProduct({where, data}: UpdateProductInput, _ctx: Ctx) {
|
||||
const product = await db.product.update({where, data})
|
||||
|
||||
return product
|
||||
|
||||
@@ -10,7 +10,7 @@ type StaticProps = {
|
||||
}
|
||||
|
||||
export const getStaticProps: GetStaticProps<StaticProps> = async (ctx) => {
|
||||
const product = await getProduct({where: {handle: ctx.params!.handle as string}})
|
||||
const product = await getProduct({where: {handle: ctx.params!.handle as string}}, {} as any)
|
||||
const dataString = superjson.stringify(product)
|
||||
return {
|
||||
props: {dataString},
|
||||
|
||||
@@ -16,7 +16,9 @@ const Products = () => {
|
||||
{groupedProducts.map((group, i) => (
|
||||
<Fragment key={i}>
|
||||
{group.products.map((product) => (
|
||||
<p key={product.id}>{product.name}</p>
|
||||
<p key={product.id} data-test="productName">
|
||||
{product.name}
|
||||
</p>
|
||||
))}
|
||||
</Fragment>
|
||||
))}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {useMemo} from "react"
|
||||
import {ssrQuery, GetServerSideProps, Link, BlitzPage, PromiseReturnType} from "blitz"
|
||||
import {invokeWithMiddleware, GetServerSideProps, Link, BlitzPage, PromiseReturnType} from "blitz"
|
||||
import getProducts from "app/products/queries/getProducts"
|
||||
import superjson from "superjson"
|
||||
|
||||
@@ -10,7 +10,7 @@ type PageProps = {
|
||||
type Products = PromiseReturnType<typeof getProducts>
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async ({req, res}) => {
|
||||
const products = await ssrQuery(getProducts, {orderBy: {id: "desc"}}, {req, res})
|
||||
const products = await invokeWithMiddleware(getProducts, {orderBy: {id: "desc"}}, {req, res})
|
||||
const dataString = superjson.stringify(products)
|
||||
return {
|
||||
props: {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {NotFoundError} from "blitz"
|
||||
import {NotFoundError, Ctx} from "blitz"
|
||||
import db, {FindOneProductArgs} from "db"
|
||||
|
||||
type GetProductInput = {
|
||||
@@ -7,7 +7,7 @@ type GetProductInput = {
|
||||
// include?: FindOneProductArgs['include']
|
||||
}
|
||||
|
||||
export default async function getProduct({where}: GetProductInput) {
|
||||
export default async function getProduct({where}: GetProductInput, _ctx: Ctx) {
|
||||
const product = await db.product.findOne({where})
|
||||
|
||||
if (!product) throw new NotFoundError()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:3099",
|
||||
"defaultCommandTimeout": 10000,
|
||||
"video": false
|
||||
"video": false,
|
||||
"chromeWebSecurity": false
|
||||
}
|
||||
|
||||
@@ -54,4 +54,14 @@ describe("products#ssr page", () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe("products#infinite page", () => {
|
||||
beforeEach(() => {
|
||||
cy.visit("/products/infinite")
|
||||
})
|
||||
|
||||
it("shows 3 products", () => {
|
||||
cy.get('[data-test="productName"]').should("have.length", 3)
|
||||
})
|
||||
})
|
||||
|
||||
export {}
|
||||
|
||||
30
examples/store/db/seeds.ts
Normal file
30
examples/store/db/seeds.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import db from "./index"
|
||||
|
||||
const randomString = (len: number, offset = 3) => {
|
||||
let output = ""
|
||||
|
||||
for (let i = 0; i < len + Math.ceil((Math.random() - 0.5) * offset); i++) {
|
||||
const ascii = Math.floor(Math.random() * 26) + (i % 2 === 0 ? 97 : 65)
|
||||
output += String.fromCharCode(ascii)
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
const randomProduct = () => {
|
||||
return {
|
||||
name: randomString(10),
|
||||
handle: randomString(6, 0),
|
||||
description: Array.from(new Array(10), () => randomString(10)).join(" "),
|
||||
price: Math.floor(Math.random() * 10000),
|
||||
}
|
||||
}
|
||||
|
||||
const seed = async () => {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
await db.product.create({data: randomProduct()})
|
||||
}
|
||||
await db.user.create({data: {email: randomString(5) + "@bar.com", name: "Foobar"}})
|
||||
}
|
||||
|
||||
export default seed
|
||||
@@ -1,13 +1,16 @@
|
||||
{
|
||||
"name": "@examples/store",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.25.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "blitz db migrate && blitz build",
|
||||
"cy:open": "cypress open",
|
||||
"cy:run": "cypress run",
|
||||
"test:start": "blitz db migrate && blitz start --production -p 3099",
|
||||
"test": "start-server-and-test test:start http://localhost:3099 cy:run"
|
||||
"test:server": "blitz db migrate && blitz db seed && blitz start --production -p 3099",
|
||||
"test": "start-server-and-test test:server http://localhost:3099 cy:run"
|
||||
},
|
||||
"prisma": {
|
||||
"schema": "db/schema.prisma"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
@@ -16,15 +19,14 @@
|
||||
"trailingComma": "all"
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/cli": "2.4.1",
|
||||
"@prisma/client": "2.4.1",
|
||||
"blitz": "0.21.2-canary.1",
|
||||
"@prisma/cli": "2.10.0",
|
||||
"@prisma/client": "2.10.0",
|
||||
"blitz": "0.25.0",
|
||||
"final-form": "4.19.1",
|
||||
"react": "0.0.0-experimental-7f28234f8",
|
||||
"react-dom": "0.0.0-experimental-7f28234f8",
|
||||
"react": "0.0.0-experimental-4ead6b530",
|
||||
"react-dom": "0.0.0-experimental-4ead6b530",
|
||||
"react-error-boundary": "2.3.1",
|
||||
"react-final-form": "6.4.0",
|
||||
"superjson": "1.2.1",
|
||||
"typescript": "3.8.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
module.exports = {
|
||||
presets: ["next/babel"],
|
||||
plugins: [],
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
es2020: true,
|
||||
},
|
||||
extends: ["react-app", "plugin:jsx-a11y/recommended"],
|
||||
plugins: ["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
|
||||
},
|
||||
}
|
||||
54
examples/tailwind/.gitignore
vendored
54
examples/tailwind/.gitignore
vendored
@@ -1,54 +0,0 @@
|
||||
# dependencies
|
||||
node_modules
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.pnp.*
|
||||
.npm
|
||||
web_modules/
|
||||
|
||||
# blitz
|
||||
/.blitz/
|
||||
/.next/
|
||||
*.sqlite
|
||||
.now
|
||||
.blitz-console-history
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
||||
# local env files
|
||||
.env
|
||||
.envrc
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
# 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
|
||||
@@ -1 +0,0 @@
|
||||
save-exact=true
|
||||
@@ -1,6 +0,0 @@
|
||||
.gitkeep
|
||||
.env
|
||||
*.ico
|
||||
*.lock
|
||||
db/migrations
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# Blitz Tailwind Example
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Start the dev server
|
||||
|
||||
```
|
||||
blitz start
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see Tailwind in use
|
||||
@@ -1,29 +0,0 @@
|
||||
import {Link} from "blitz"
|
||||
|
||||
const links = [
|
||||
{href: "https://github.com/blitz-js/blitz", label: "GitHub"},
|
||||
{href: "https://github.com/blitz-js/blitz/blob/canary/USER_GUIDE.md", label: "Docs"},
|
||||
]
|
||||
|
||||
export default function Nav() {
|
||||
return (
|
||||
<nav>
|
||||
<ul className="flex justify-between items-center p-8">
|
||||
<li>
|
||||
<Link href="/">
|
||||
<a className="text-blue-500 no-underline">Home</a>
|
||||
</Link>
|
||||
</li>
|
||||
<ul className="flex justify-between items-center">
|
||||
{links.map(({href, label}) => (
|
||||
<li key={`${href}${label}`} className="ml-4">
|
||||
<a href={href} className="btn-blue no-underline">
|
||||
{label}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</ul>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import "app/styles/index.css"
|
||||
|
||||
export default function MyApp({Component, pageProps}) {
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import {Document, Html, DocumentHead, Main, BlitzScript /*DocumentContext*/} from "@blitzjs/core"
|
||||
|
||||
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
|
||||
@@ -1,14 +0,0 @@
|
||||
import Nav from "app/components/nav"
|
||||
|
||||
const TailWindExamplePage = () => {
|
||||
return (
|
||||
<div>
|
||||
<Nav />
|
||||
<div className="hero">
|
||||
<h1 className="title">Blitz.js + Tailwind CSS</h1>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TailWindExamplePage
|
||||
@@ -1,3 +0,0 @@
|
||||
.btn-blue {
|
||||
@apply bg-blue-500 text-white font-bold py-2 px-4 rounded;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
@import "./button.css";
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
.hero {
|
||||
width: 100%;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
padding-top: 80px;
|
||||
line-height: 1.15;
|
||||
font-size: 48px;
|
||||
}
|
||||
|
||||
.title,
|
||||
.description {
|
||||
text-align: center;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
module.exports = {
|
||||
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
|
||||
},
|
||||
webpackDevMiddleware: (config) => {
|
||||
// Perform customizations to webpack dev middleware config
|
||||
// Important: return the modified config
|
||||
return config
|
||||
},
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import {PrismaClient} from "@prisma/client"
|
||||
export * from "@prisma/client"
|
||||
|
||||
let prisma: PrismaClient
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
prisma = new PrismaClient()
|
||||
} else {
|
||||
// Ensure the prisma instance is re-used during hot-reloading
|
||||
// Otherwise, a new client will be created on every reload
|
||||
globalThis["prisma"] = globalThis["prisma"] || new PrismaClient()
|
||||
prisma = globalThis["prisma"]
|
||||
}
|
||||
|
||||
export default prisma
|
||||
@@ -1,20 +0,0 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
datasource postgresql {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------
|
||||
|
||||
//model Project {
|
||||
// id Int @default(autoincrement()) @id
|
||||
// name String
|
||||
//}
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
{
|
||||
"name": "tailwind",
|
||||
"version": "0.21.2-canary.1",
|
||||
"scripts": {
|
||||
"build": "blitz db migrate && blitz build",
|
||||
"lint": "eslint --ignore-path .gitignore --ext .js,.ts,.tsx .",
|
||||
"test": "echo \"No tests yet\""
|
||||
},
|
||||
"browserslist": [
|
||||
"defaults"
|
||||
],
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
"printWidth": 100,
|
||||
"bracketSpacing": false,
|
||||
"trailingComma": "all"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged && pretty-quick --staged",
|
||||
"pre-push": "blitz test"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,ts,tsx}": [
|
||||
"eslint --fix",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/cli": "2.4.1",
|
||||
"@prisma/client": "2.4.1",
|
||||
"blitz": "0.21.2-canary.1",
|
||||
"react": "0.0.0-experimental-7f28234f8",
|
||||
"react-dom": "0.0.0-experimental-7f28234f8",
|
||||
"typescript": "3.8.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "16.9.34",
|
||||
"@typescript-eslint/eslint-plugin": "2.29.0",
|
||||
"@typescript-eslint/parser": "2.29.0",
|
||||
"babel-eslint": "10.1.0",
|
||||
"eslint": "7.6.0",
|
||||
"eslint-config-react-app": "5.2.1",
|
||||
"eslint-plugin-flowtype": "5.2.0",
|
||||
"eslint-plugin-import": "2.22.0",
|
||||
"eslint-plugin-jsx-a11y": "6.3.1",
|
||||
"eslint-plugin-react": "7.20.5",
|
||||
"eslint-plugin-react-hooks": "4.0.8",
|
||||
"husky": "4.2.5",
|
||||
"lint-staged": "10.2.13",
|
||||
"postcss-preset-env": "6.7.0",
|
||||
"prettier": "2.0.5",
|
||||
"pretty-quick": "2.0.1",
|
||||
"tailwindcss": "1.4.0"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
plugins: ["tailwindcss", "postcss-preset-env"],
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 556 B |
Binary file not shown.
|
Before Width: | Height: | Size: 30 KiB |
@@ -1,8 +0,0 @@
|
||||
module.exports = {
|
||||
purge: ["./**/{pages,components}/**/*.{js,jsx,ts,tsx}"],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
variants: {},
|
||||
plugins: [],
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"baseUrl": "./",
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve"
|
||||
},
|
||||
"exclude": ["node_modules"],
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.25.0",
|
||||
"packages": ["packages/*"],
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
|
||||
12
package.json
12
package.json
@@ -27,7 +27,7 @@
|
||||
"test:packages": "yarn run build && yarn testonly:packages",
|
||||
"test:examples": "yarn run build && yarn testonly:examples",
|
||||
"testonly": "yarn test:packages && yarn test:examples",
|
||||
"testonly:packages": "lerna run test --stream --scope @blitzjs/*",
|
||||
"testonly:packages": "lerna run test --scope blitz && lerna run test --stream --scope @blitzjs/*",
|
||||
"testonly:examples": "lerna run test --stream --scope @examples/* --concurrency 1",
|
||||
"reset": "rimraf node_modules && git clean -xfd packages && yarn",
|
||||
"publish-prep": "lerna run clean && yarn && yarn build",
|
||||
@@ -81,12 +81,13 @@
|
||||
"@types/vinyl": "2.0.4",
|
||||
"@types/vinyl-fs": "2.4.11",
|
||||
"@types/webpack": "4.41.13",
|
||||
"@typescript-eslint/eslint-plugin": "2.x",
|
||||
"@typescript-eslint/parser": "2.x",
|
||||
"@typescript-eslint/eslint-plugin": "4.3.1-alpha.1",
|
||||
"@typescript-eslint/parser": "4.3.1-alpha.1",
|
||||
"@wessberg/cjs-to-esm-transformer": "0.0.22",
|
||||
"@wessberg/rollup-plugin-ts": "1.3.3",
|
||||
"babel-eslint": "10.x",
|
||||
"babel-jest": "26.3.0",
|
||||
"concurrently": "5.3.0",
|
||||
"cpy-cli": "3.1.1",
|
||||
"cross-env": "7.0.2",
|
||||
"debug": "4.1.1",
|
||||
@@ -94,12 +95,15 @@
|
||||
"directory-tree": "2.2.4",
|
||||
"eslint": "7.7.0",
|
||||
"eslint-config-react-app": "5.2.1",
|
||||
"eslint-plugin-es": "mysticatea/eslint-plugin-es",
|
||||
"eslint-plugin-es5": "1.5.0",
|
||||
"eslint-plugin-flowtype": "5.2.0",
|
||||
"eslint-plugin-import": "2.22.0",
|
||||
"eslint-plugin-jsx-a11y": "6.3.1",
|
||||
"eslint-plugin-prettier": "3.1.4",
|
||||
"eslint-plugin-react": "7.20.6",
|
||||
"eslint-plugin-react-hooks": "4.1.0",
|
||||
"eslint-plugin-simple-import-sort": "5.0.3",
|
||||
"eslint-plugin-unicorn": "21.0.0",
|
||||
"husky": "4.2.5",
|
||||
"isomorphic-unfetch": "3.0.0",
|
||||
@@ -130,7 +134,7 @@
|
||||
"ts-jest": "24.3.0",
|
||||
"tsdx": "0.13.3",
|
||||
"tslib": "1.11.1",
|
||||
"typescript": "3.8.3",
|
||||
"typescript": "4.0.3",
|
||||
"wait-on": "4.0.2"
|
||||
},
|
||||
"husky": {
|
||||
|
||||
@@ -10,7 +10,9 @@ if (process.env.INSPECT_BRK === 'true') {
|
||||
try {
|
||||
const cliBin = require.resolve('../dist/cli')
|
||||
const binArgs = process.argv.slice(2)
|
||||
spawn.sync('node', [...nodeOpts, cliBin, ...binArgs], { stdio: 'inherit' })
|
||||
const result = spawn.sync('node', [...nodeOpts, cliBin, ...binArgs], { stdio: 'inherit' })
|
||||
process.exit(result.status)
|
||||
} catch (e) {
|
||||
console.error('Blitz is not available yet, make sure "yarn build" or "yarn dev" has completed compiling')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
{
|
||||
"name": "blitz",
|
||||
"description": "Blitz is a Rails-like framework for monolithic, full-stack React apps — built on Next.js",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.25.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
"predev": "wait-on ../core/dist/packages/core/src/index.d.ts && wait-on ../server/dist/packages/server/src/index.d.ts && wait-on ../generator/dist/packages/generator/src/index.d.ts && wait-on ../cli/lib/src/index.js",
|
||||
"dev": "rollup -c rollup.config.js --watch",
|
||||
"build": "rollup -c rollup.config.js"
|
||||
"build": "rollup -c rollup.config.js",
|
||||
"test": "tsdx test"
|
||||
},
|
||||
"author": {
|
||||
"name": "Brandon Bayer",
|
||||
@@ -39,11 +40,11 @@
|
||||
"url": "https://github.com/blitz-js/blitz"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/cli": "0.21.2-canary.1",
|
||||
"@blitzjs/core": "0.21.2-canary.1",
|
||||
"@blitzjs/generator": "0.21.2-canary.1",
|
||||
"@blitzjs/installer": "0.21.2-canary.1",
|
||||
"@blitzjs/server": "0.21.2-canary.1",
|
||||
"@blitzjs/cli": "0.25.0",
|
||||
"@blitzjs/core": "0.25.0",
|
||||
"@blitzjs/generator": "0.25.0",
|
||||
"@blitzjs/installer": "0.25.0",
|
||||
"@blitzjs/server": "0.25.0",
|
||||
"envinfo": "7.7.2",
|
||||
"os-name": "3.1.0",
|
||||
"pkg-dir": "4.2.0",
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import pkg from "./package.json"
|
||||
import typescript from "@wessberg/rollup-plugin-ts"
|
||||
import commonjs from "rollup-plugin-commonjs"
|
||||
import external from "rollup-plugin-peer-deps-external"
|
||||
import resolve from "rollup-plugin-node-resolve"
|
||||
import json from "rollup-plugin-json"
|
||||
import resolve from "rollup-plugin-node-resolve"
|
||||
import external from "rollup-plugin-peer-deps-external"
|
||||
import pkg from "./package.json"
|
||||
|
||||
const common = {
|
||||
external: [
|
||||
|
||||
@@ -1,23 +1,28 @@
|
||||
import * as path from "path"
|
||||
import resolveFrom from "resolve-from"
|
||||
import pkgDir from "pkg-dir"
|
||||
import chalk from "chalk"
|
||||
import * as path from "path"
|
||||
import pkgDir from "pkg-dir"
|
||||
import resolveFrom from "resolve-from"
|
||||
import {parseSemver} from "../utils/parse-semver"
|
||||
|
||||
async function main() {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
`You are using alpha software - if you have any problems, please open an issue here:
|
||||
https://github.com/blitz-js/blitz/issues/new/choose\n`,
|
||||
),
|
||||
)
|
||||
const options = require("minimist")(process.argv.slice(2))
|
||||
|
||||
if (options._[0] !== "autocomplete:script" || Object.keys(options).length > 1) {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
`You are using alpha software - if you have any problems, please open an issue here:
|
||||
https://github.com/blitz-js/blitz/issues/new/choose\n`,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
if (parseSemver(process.version).major < 12) {
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
`You are using an unsupported version of Node.js. Consider switching to v12 or newer.\n`,
|
||||
`You are using an unsupported version of Node.js. Please switch to v12 or newer.\n`,
|
||||
),
|
||||
)
|
||||
process.exit()
|
||||
}
|
||||
|
||||
const globalBlitzPath = resolveFrom(__dirname, "blitz")
|
||||
@@ -37,7 +42,6 @@ async function main() {
|
||||
|
||||
const cli = require(cliPkgPath)
|
||||
|
||||
const options = require("minimist")(process.argv.slice(2))
|
||||
const hasVersionFlag = options._.length === 0 && (options.v || options.version)
|
||||
const hasVerboseFlag = options._.length === 0 && (options.V || options.verbose)
|
||||
|
||||
|
||||
@@ -3,7 +3,11 @@ import {parseSemver} from "./parse-semver"
|
||||
describe("parseSemver", () => {
|
||||
describe("when given a non-semver-string", () => {
|
||||
it("throws", () => {
|
||||
expect(() => parseSemver("non-semver")).toThrow()
|
||||
expect(parseSemver("non-semver")).toEqual({
|
||||
major: NaN,
|
||||
minor: undefined,
|
||||
patch: undefined,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
20
packages/blitz/test/bin.test.ts
Normal file
20
packages/blitz/test/bin.test.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import spawn from "cross-spawn"
|
||||
import path from "path"
|
||||
|
||||
const blitzBin = path.resolve(__dirname, "../bin/blitz")
|
||||
const exampleProject = path.resolve(__dirname, "../../../examples/auth")
|
||||
|
||||
describe("Binary blitz", () => {
|
||||
it("should return exit code 0 if command is successful", () => {
|
||||
const result = spawn.sync(blitzBin, ["--version"], {
|
||||
cwd: exampleProject,
|
||||
})
|
||||
expect(result.status).toBe(0)
|
||||
})
|
||||
it("should return exit code 1 if command is unsuccessful", () => {
|
||||
const result = spawn.sync(blitzBin, ["install", "notExistingRecipe"], {
|
||||
cwd: exampleProject,
|
||||
})
|
||||
expect(result.status).toBe(1)
|
||||
})
|
||||
})
|
||||
@@ -1,3 +0,0 @@
|
||||
it.skip("todo", () => {
|
||||
expect(true).toBe(true)
|
||||
})
|
||||
@@ -8,6 +8,8 @@
|
||||
"downlevelIteration": true,
|
||||
"paths": {
|
||||
"*": ["src/*", "node_modules/*"]
|
||||
}
|
||||
},
|
||||
"incremental": true,
|
||||
"tsBuildInfoFile": ".tsbuildinfo"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@blitzjs/cli",
|
||||
"description": "Blitz.js CLI",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.25.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"b": "./bin/run",
|
||||
@@ -30,14 +30,15 @@
|
||||
"/lib"
|
||||
],
|
||||
"dependencies": {
|
||||
"@blitzjs/display": "0.21.2-canary.1",
|
||||
"@blitzjs/repl": "0.21.2-canary.1",
|
||||
"@blitzjs/display": "0.25.0",
|
||||
"@blitzjs/repl": "0.25.0",
|
||||
"@oclif/command": "1.5.20",
|
||||
"@oclif/config": "1.15.1",
|
||||
"@oclif/plugin-autocomplete": "0.2.0",
|
||||
"@oclif/plugin-help": "2.2.3",
|
||||
"@oclif/plugin-not-found": "1.2.3",
|
||||
"@prisma/sdk": "2.6.0",
|
||||
"@prisma/sdk": "2.10.0",
|
||||
"@salesforce/lazy-require": "0.3.2",
|
||||
"camelcase": "6.0.0",
|
||||
"chalk": "4.0.0",
|
||||
"cross-spawn": "7.0.3",
|
||||
@@ -54,15 +55,16 @@
|
||||
"rimraf": "3.0.2",
|
||||
"tar": "6.0.2",
|
||||
"ts-node": "8.9.0",
|
||||
"tsconfig-paths": "3.9.0"
|
||||
"tsconfig-paths": "3.9.0",
|
||||
"v8-compile-cache": "2.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blitzjs/generator": "0.21.2-canary.1",
|
||||
"@blitzjs/installer": "0.21.2-canary.1",
|
||||
"@blitzjs/server": "0.21.2-canary.1",
|
||||
"@blitzjs/generator": "0.25.0",
|
||||
"@blitzjs/installer": "0.25.0",
|
||||
"@blitzjs/server": "0.25.0",
|
||||
"@oclif/dev-cli": "1.22.2",
|
||||
"@oclif/test": "1.2.5",
|
||||
"@prisma/cli": "2.4.1",
|
||||
"@prisma/cli": "2.10.0",
|
||||
"nock": "13.0.0-beta.3",
|
||||
"stdout-stderr": "0.1.13"
|
||||
},
|
||||
|
||||
@@ -3,11 +3,21 @@ import chalk from "chalk"
|
||||
|
||||
import {isBlitzRoot, IsBlitzRootError} from "./utils/is-blitz-root"
|
||||
|
||||
const whitelistGlobal = ["-h", "--help", "help", "new", "autocomplete", "autocomplete:script"]
|
||||
const commandAllowListGlobal = [
|
||||
"-h",
|
||||
"--help",
|
||||
"help",
|
||||
"new",
|
||||
"autocomplete",
|
||||
"autocomplete:script",
|
||||
]
|
||||
const argumentAllowListGlobal = ["-h", "--help", "help"]
|
||||
|
||||
export const hook: Hook<"init"> = async function (options) {
|
||||
const {id} = options
|
||||
if (id && whitelistGlobal.includes(id)) return
|
||||
const {argv, id} = options
|
||||
if (argv.length > 0 && argumentAllowListGlobal.some((arg) => argv.includes(arg))) return
|
||||
if (id && commandAllowListGlobal.includes(id)) return
|
||||
if (id === "db" && argv.length === 0) return
|
||||
|
||||
const {err, message, depth} = await isBlitzRoot()
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user