Compare commits
78 Commits
authorize-
...
v0.23.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15a349e3a4 | ||
|
|
51c1192574 | ||
|
|
f79a0cdb4c | ||
|
|
f3eabbde4e | ||
|
|
0261672219 | ||
|
|
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 |
@@ -357,7 +357,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "skn0tt",
|
||||
"login": "Skn0tt",
|
||||
"name": "Simon Knott",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/14912729?v=4",
|
||||
"profile": "http://simonknott.de",
|
||||
@@ -565,15 +565,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",
|
||||
@@ -896,7 +887,8 @@
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/8602086?v=4",
|
||||
"profile": "http://ricardotrejos.tech",
|
||||
"contributions": [
|
||||
"code"
|
||||
"code",
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -990,6 +982,174 @@
|
||||
"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"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "sirmyron",
|
||||
"name": "sirmyron",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/1430136?v=4",
|
||||
"profile": "https://github.com/sirmyron",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "engelkes-finstreet",
|
||||
"name": "engelkes-finstreet",
|
||||
"avatar_url": "https://avatars1.githubusercontent.com/u/36962022?v=4",
|
||||
"profile": "https://github.com/engelkes-finstreet",
|
||||
"contributions": [
|
||||
"code",
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
4
.github/workflows/main.yml
vendored
4
.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-v3-${{ hashFiles('yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-v2-
|
||||
${{ runner.os }}-yarn-v3-
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile --silent
|
||||
env:
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -19,3 +19,4 @@ dist
|
||||
**/.env.*.local
|
||||
**/.envrc
|
||||
.blitz-*
|
||||
.blitz-cli-cache
|
||||
|
||||
@@ -52,7 +52,7 @@ Some especially important points:
|
||||
## Slack
|
||||
|
||||
- All `#-*` channels are for Blitz users
|
||||
- All `#dev-*` channels are for Blitz internal development
|
||||
- All `#contributor-*` 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 :)
|
||||
|
||||
|
||||
65
README.md
65
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-120-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">
|
||||
@@ -116,23 +116,35 @@ 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>
|
||||
|
||||
@@ -188,6 +200,7 @@ _Issue triage, pull request triage, community encouragement and moderation, etc_
|
||||
</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://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>
|
||||
</tr>
|
||||
</table>
|
||||
<!-- markdownlint-enable -->
|
||||
@@ -250,7 +263,7 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
|
||||
<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>
|
||||
</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 +291,92 @@ 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://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/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></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></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="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=engelkes-finstreet" title="Documentation">📖</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>
|
||||
</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,4 +1,5 @@
|
||||
import React from "react"
|
||||
import {Link} from "blitz"
|
||||
import {LabeledTextField} from "app/components/LabeledTextField"
|
||||
import {Form, FORM_ERROR} from "app/components/Form"
|
||||
import login from "app/auth/mutations/login"
|
||||
@@ -12,7 +13,6 @@ export const LoginForm = (props: LoginFormProps) => {
|
||||
return (
|
||||
<div>
|
||||
<h1>Login</h1>
|
||||
|
||||
<Form<LoginInputType>
|
||||
submitText="Log In"
|
||||
schema={LoginInput}
|
||||
@@ -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,12 +1,14 @@
|
||||
import {AppProps, ErrorComponent} from "blitz"
|
||||
import {AppProps, ErrorComponent, useRouter} from "blitz"
|
||||
import {ErrorBoundary} from "react-error-boundary"
|
||||
import {queryCache} from "react-query"
|
||||
import LoginForm from "app/auth/components/LoginForm"
|
||||
|
||||
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
|
||||
|
||||
@@ -15,7 +15,7 @@ export default async function getUsers(
|
||||
{where, orderBy, cursor, take, skip}: GetUsersInput,
|
||||
ctx: {session?: SessionContext} = {},
|
||||
) {
|
||||
ctx.session?.authorize(["admin"])
|
||||
ctx.session!.authorize(["admin"])
|
||||
|
||||
const users = await db.user.findMany({
|
||||
where,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@examples/auth",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"scripts": {
|
||||
"start": "blitz start",
|
||||
"studio": "blitz db studio",
|
||||
@@ -35,8 +35,9 @@
|
||||
"dependencies": {
|
||||
"@prisma/cli": "2.4.1",
|
||||
"@prisma/client": "2.4.1",
|
||||
"blitz": "0.21.2-canary.1",
|
||||
"blitz": "0.23.2",
|
||||
"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",
|
||||
@@ -49,6 +50,7 @@
|
||||
"devDependencies": {
|
||||
"@cypress/skip-test": "2.5.0",
|
||||
"@next/bundle-analyzer": "latest",
|
||||
"@types/passport-auth0": "1.0.4",
|
||||
"@types/passport-github2": "1.2.4",
|
||||
"@types/passport-twitter": "1.0.36",
|
||||
"@types/react": "16.9.38",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "no-prisma",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"scripts": {
|
||||
"start": "blitz start",
|
||||
"build": "blitz build",
|
||||
@@ -26,7 +26,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"blitz": "0.21.2-canary.1",
|
||||
"blitz": "0.23.2",
|
||||
"knex": "0.21.2",
|
||||
"react": "0.0.0-experimental-7f28234f8",
|
||||
"react-dom": "0.0.0-experimental-7f28234f8",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@examples/plain-js",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"scripts": {
|
||||
"start": "blitz start",
|
||||
"build": "blitz db migrate && blitz build",
|
||||
@@ -31,7 +31,7 @@
|
||||
"dependencies": {
|
||||
"@prisma/cli": "2.4.1",
|
||||
"@prisma/client": "2.4.1",
|
||||
"blitz": "0.21.2-canary.1",
|
||||
"blitz": "0.23.2",
|
||||
"react": "0.0.0-experimental-7f28234f8",
|
||||
"react-dom": "0.0.0-experimental-7f28234f8"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@examples/store",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "blitz db migrate && blitz build",
|
||||
@@ -18,7 +18,7 @@
|
||||
"dependencies": {
|
||||
"@prisma/cli": "2.4.1",
|
||||
"@prisma/client": "2.4.1",
|
||||
"blitz": "0.21.2-canary.1",
|
||||
"blitz": "0.23.2",
|
||||
"final-form": "4.19.1",
|
||||
"react": "0.0.0-experimental-7f28234f8",
|
||||
"react-dom": "0.0.0-experimental-7f28234f8",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tailwind",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"scripts": {
|
||||
"build": "blitz db migrate && blitz build",
|
||||
"lint": "eslint --ignore-path .gitignore --ext .js,.ts,.tsx .",
|
||||
@@ -30,7 +30,7 @@
|
||||
"dependencies": {
|
||||
"@prisma/cli": "2.4.1",
|
||||
"@prisma/client": "2.4.1",
|
||||
"blitz": "0.21.2-canary.1",
|
||||
"blitz": "0.23.2",
|
||||
"react": "0.0.0-experimental-7f28234f8",
|
||||
"react-dom": "0.0.0-experimental-7f28234f8",
|
||||
"typescript": "3.8.3"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"packages": ["packages/*"],
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
"prepack": "cpy README.md packages/blitz/",
|
||||
"postpack": "rimraf packages/blitz/README.md",
|
||||
"publish-canary": "yarn run publish-prep && lerna publish --force-publish --preid canary --pre-dist-tag canary",
|
||||
"publish-latest": "yarn run publish-prep && lerna publish --force-publish",
|
||||
"publish-latest": "yarn run publish-prep && lerna publish --force-publish --allow-branch v*",
|
||||
"publish-danger": "lerna publish --canary --pre-dist-tag danger --preid danger.$(git rev-parse --short HEAD) --allow-branch * --force-publish",
|
||||
"danger:push-all": "git push --no-verify && git push --no-verify --tags"
|
||||
},
|
||||
@@ -94,6 +94,8 @@
|
||||
"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",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"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.23.2",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
@@ -39,11 +39,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.23.2",
|
||||
"@blitzjs/core": "0.23.2",
|
||||
"@blitzjs/generator": "0.23.2",
|
||||
"@blitzjs/installer": "0.23.2",
|
||||
"@blitzjs/server": "0.23.2",
|
||||
"envinfo": "7.7.2",
|
||||
"os-name": "3.1.0",
|
||||
"pkg-dir": "4.2.0",
|
||||
|
||||
@@ -5,12 +5,16 @@ import chalk from "chalk"
|
||||
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(
|
||||
@@ -37,7 +41,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)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@blitzjs/cli",
|
||||
"description": "Blitz.js CLI",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"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.23.2",
|
||||
"@blitzjs/repl": "0.23.2",
|
||||
"@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",
|
||||
"@salesforce/lazy-require": "0.3.2",
|
||||
"camelcase": "6.0.0",
|
||||
"chalk": "4.0.0",
|
||||
"cross-spawn": "7.0.3",
|
||||
@@ -54,12 +55,13 @@
|
||||
"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.23.2",
|
||||
"@blitzjs/installer": "0.23.2",
|
||||
"@blitzjs/server": "0.23.2",
|
||||
"@oclif/dev-cli": "1.22.2",
|
||||
"@oclif/test": "1.2.5",
|
||||
"@prisma/cli": "2.4.1",
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import {Command} from "@oclif/command"
|
||||
import {build} from "@blitzjs/server"
|
||||
import {runPrismaGeneration} from "./db"
|
||||
|
||||
export class Build extends Command {
|
||||
static description = "Create a production build"
|
||||
@@ -12,7 +10,7 @@ export class Build extends Command {
|
||||
}
|
||||
|
||||
try {
|
||||
await build(config, runPrismaGeneration({silent: true, failSilently: true}))
|
||||
await require("@blitzjs/server").build(config)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
process.exit(1) // clean up?
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
import {runRepl} from "@blitzjs/repl"
|
||||
import {Command} from "@oclif/command"
|
||||
import path from "path"
|
||||
import fs from "fs"
|
||||
import pkgDir from "pkg-dir"
|
||||
import {log} from "@blitzjs/display"
|
||||
import chalk from "chalk"
|
||||
|
||||
import {setupTsnode} from "../utils/setup-ts-node"
|
||||
import {runPrismaGeneration} from "./db"
|
||||
|
||||
const projectRoot = pkgDir.sync() || process.cwd()
|
||||
const isTypescript = fs.existsSync(path.join(projectRoot, "tsconfig.json"))
|
||||
const projectRoot = require("pkg-dir").sync() || process.cwd()
|
||||
const isTypescript = require("fs").existsSync(require("path").join(projectRoot, "tsconfig.json"))
|
||||
|
||||
export class Console extends Command {
|
||||
static description = "Run the Blitz console REPL"
|
||||
@@ -22,19 +13,17 @@ export class Console extends Command {
|
||||
}
|
||||
|
||||
async run() {
|
||||
const {log} = require("@blitzjs/display")
|
||||
const chalk = require("chalk")
|
||||
log.branded("You have entered the Blitz console")
|
||||
console.log(chalk.yellow("Tips: - Exit by typing .exit or pressing Ctrl-D"))
|
||||
console.log(chalk.yellow(" - Use your db like this: await db.project.findMany()"))
|
||||
console.log(chalk.yellow(" - Use your queries/mutations like this: await getProjects({})"))
|
||||
|
||||
const spinner = log.spinner("Loading your code").start()
|
||||
if (isTypescript) {
|
||||
setupTsnode()
|
||||
require("../utils/setup-ts-node").setupTsnode()
|
||||
}
|
||||
|
||||
await runPrismaGeneration({silent: true, failSilently: true})
|
||||
spinner.succeed()
|
||||
|
||||
runRepl(Console.replOptions)
|
||||
require("@blitzjs/repl").runRepl(Console.replOptions)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,7 @@
|
||||
import {resolveBinAsync} from "@blitzjs/server"
|
||||
import {log} from "@blitzjs/display"
|
||||
import {Command, flags} from "@oclif/command"
|
||||
import chalk from "chalk"
|
||||
import {spawn} from "cross-spawn"
|
||||
import {prompt} from "enquirer"
|
||||
import * as fs from "fs"
|
||||
import * as path from "path"
|
||||
import {promisify} from "util"
|
||||
import {projectRoot} from "../utils/get-project-root"
|
||||
import pEvent from "p-event"
|
||||
import {getConfig, getSchema} from "@prisma/sdk"
|
||||
import {log} from "@blitzjs/display"
|
||||
|
||||
const getPrismaBin = () => resolveBinAsync("@prisma/cli", "prisma")
|
||||
const getPrismaBin = () => require("@blitzjs/server").resolveBinAsync("@prisma/cli", "prisma")
|
||||
let prismaBin: string
|
||||
let schemaArg: string
|
||||
|
||||
@@ -26,11 +16,11 @@ const runPrisma = async (args: string[], silent = false) => {
|
||||
}
|
||||
}
|
||||
|
||||
const cp = spawn(prismaBin, args, {
|
||||
const cp = require("cross-spawn").spawn(prismaBin, args, {
|
||||
stdio: silent ? "ignore" : "inherit",
|
||||
env: process.env,
|
||||
})
|
||||
const code = await pEvent(cp, "exit", {rejectionEvents: []})
|
||||
const code = await require("p-event")(cp, "exit", {rejectionEvents: []})
|
||||
|
||||
return code === 0
|
||||
}
|
||||
@@ -69,16 +59,17 @@ const runMigrateUp = async ({silent = false} = {}) => {
|
||||
return runPrismaGeneration({silent})
|
||||
}
|
||||
|
||||
export const runMigrate = async (name?: string) => {
|
||||
export const runMigrate = async (flags: object = {}) => {
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
return runMigrateUp()
|
||||
}
|
||||
// @ts-ignore escape:TS7053
|
||||
const nestedFlags = Object.keys(flags).map((key) => [`--${key}`, flags[key]])
|
||||
const options = ([] as string[]).concat(...nestedFlags)
|
||||
|
||||
const silent = Boolean(name)
|
||||
const args = ["migrate", "save", schemaArg, "--create-db", "--experimental"]
|
||||
if (name) {
|
||||
args.push("--name", name)
|
||||
}
|
||||
const silent = options.includes("--name")
|
||||
|
||||
const args = ["migrate", "save", schemaArg, "--create-db", "--experimental", ...options]
|
||||
|
||||
const success = await runPrisma(args, silent)
|
||||
|
||||
@@ -131,8 +122,12 @@ export async function resetMysql(connectionString: string, db: any): Promise<voi
|
||||
|
||||
export async function resetSqlite(connectionString: string): Promise<void> {
|
||||
const relativePath = connectionString.replace(/^file:/, "").replace(/^(?:\.\.[\\/])+/, "")
|
||||
const dbPath = path.join(projectRoot, "db", relativePath)
|
||||
const unlink = promisify(fs.unlink)
|
||||
const dbPath = require("path").join(
|
||||
require("../utils/get-project-root").projectRoot,
|
||||
"db",
|
||||
relativePath,
|
||||
)
|
||||
const unlink = require("util").promisify(require("fs").unlink)
|
||||
try {
|
||||
// delete database from folder
|
||||
await unlink(dbPath)
|
||||
@@ -156,17 +151,21 @@ export function getDbName(connectionString: string): string {
|
||||
export class Db extends Command {
|
||||
static description = `Run database commands
|
||||
|
||||
${chalk.bold("migrate")} Run any needed migrations via Prisma 2 and generate Prisma Client.
|
||||
${require("chalk").bold(
|
||||
"migrate",
|
||||
)} Run any needed migrations via Prisma 2 and generate Prisma Client.
|
||||
|
||||
${chalk.bold(
|
||||
${require("chalk").bold(
|
||||
"introspect",
|
||||
)} Will introspect the database defined in db/schema.prisma and automatically generate a complete schema.prisma file for you. Lastly, it'll generate Prisma Client.
|
||||
|
||||
${chalk.bold(
|
||||
${require("chalk").bold(
|
||||
"studio",
|
||||
)} Open the Prisma Studio UI at http://localhost:5555 so you can easily see and change data in your database.
|
||||
|
||||
${chalk.bold("reset")} Reset the database and run a fresh migration via Prisma 2.
|
||||
${require("chalk").bold(
|
||||
"reset",
|
||||
)} Reset the database and run a fresh migration via Prisma 2. You can also pass --force to skip all the user prompts.
|
||||
`
|
||||
|
||||
static args = [
|
||||
@@ -182,21 +181,25 @@ ${chalk.bold("reset")} Reset the database and run a fresh migration via Prisma
|
||||
help: flags.help({char: "h"}),
|
||||
// Used by `new` command to perform the initial migration
|
||||
name: flags.string({hidden: true}),
|
||||
// Used by `reset` command to skip the confirmation prompt
|
||||
force: flags.boolean({char: "f", hidden: true}),
|
||||
}
|
||||
|
||||
static strict = false
|
||||
|
||||
async run() {
|
||||
const {args, flags} = this.parse(Db)
|
||||
const command = args["command"]
|
||||
|
||||
// Needs to happen at run-time since the `new` command needs to change the cwd before running
|
||||
const schemaPath = path.join(process.cwd(), "db", "schema.prisma")
|
||||
const schemaPath = require("path").join(process.cwd(), "db", "schema.prisma")
|
||||
schemaArg = `--schema=${schemaPath}`
|
||||
|
||||
if (command === "migrate" || command === "m") {
|
||||
try {
|
||||
return await runMigrate(flags.name)
|
||||
return await runMigrate(flags)
|
||||
} catch (error) {
|
||||
if (flags.name) {
|
||||
if (Object.keys(flags).length > 0) {
|
||||
throw error
|
||||
} else {
|
||||
process.exit(1)
|
||||
@@ -214,41 +217,45 @@ ${chalk.bold("reset")} Reset the database and run a fresh migration via Prisma
|
||||
}
|
||||
|
||||
if (command === "reset") {
|
||||
const spinner = log.spinner("Loading your database").start()
|
||||
await runPrismaGeneration({silent: true, failSilently: true})
|
||||
spinner.succeed()
|
||||
const forceSkipConfirmation = flags.force
|
||||
|
||||
const {confirm} = await prompt<{confirm: string}>({
|
||||
type: "confirm",
|
||||
name: "confirm",
|
||||
message: "Are you sure you want to reset your database and erase ALL data?",
|
||||
})
|
||||
if (!forceSkipConfirmation) {
|
||||
const {confirm} = await require("enquirer").prompt({
|
||||
type: "confirm",
|
||||
name: "confirm",
|
||||
message: "Are you sure you want to reset your database and erase ALL data?",
|
||||
})
|
||||
|
||||
if (!confirm) {
|
||||
return
|
||||
if (!confirm) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.progress("Resetting your database...")
|
||||
const {projectRoot} = require("../utils/get-project-root")
|
||||
const prismaClientPath = require.resolve("@prisma/client", {paths: [projectRoot]})
|
||||
const {PrismaClient} = require(prismaClientPath)
|
||||
const db = new PrismaClient()
|
||||
const schemaPath = path.join(projectRoot, "db/schema.prisma")
|
||||
const datamodel = await getSchema(schemaPath)
|
||||
const config = await getConfig({datamodel})
|
||||
const schemaPath = require("path").join(projectRoot, "db/schema.prisma")
|
||||
const datamodel = await require("@prisma/sdk").getSchema(schemaPath)
|
||||
const config = await require("@prisma/sdk").getConfig({datamodel})
|
||||
const dataSource = config.datasources[0]
|
||||
const providerType = dataSource.activeProvider
|
||||
const connectionString = dataSource.url.value
|
||||
|
||||
if (providerType === "postgresql") {
|
||||
resetPostgres(connectionString, db)
|
||||
await resetPostgres(connectionString, db)
|
||||
return
|
||||
} else if (providerType === "mysql") {
|
||||
resetMysql(connectionString, db)
|
||||
await resetMysql(connectionString, db)
|
||||
return
|
||||
} else if (providerType === "sqlite") {
|
||||
resetSqlite(connectionString)
|
||||
await resetSqlite(connectionString)
|
||||
return
|
||||
} else {
|
||||
this.log("Could not find a valid database configuration")
|
||||
log.error("Could not find a valid database configuration")
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if (command === "help") {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import {Command} from "../command"
|
||||
import {flags} from "@oclif/command"
|
||||
import * as fs from "fs"
|
||||
import * as path from "path"
|
||||
import enquirer from "enquirer"
|
||||
import _pluralize from "pluralize"
|
||||
import {log} from "@blitzjs/display"
|
||||
import {
|
||||
PageGenerator,
|
||||
MutationGenerator,
|
||||
@@ -13,15 +10,13 @@ import {
|
||||
QueryGenerator,
|
||||
} from "@blitzjs/generator"
|
||||
import {PromptAbortedError} from "../errors/prompt-aborted"
|
||||
import {log} from "@blitzjs/display"
|
||||
import camelCase from "camelcase"
|
||||
import pkgDir from "pkg-dir"
|
||||
|
||||
const debug = require("debug")("blitz:generate")
|
||||
|
||||
const pascalCase = (str: string) => camelCase(str, {pascalCase: true})
|
||||
|
||||
const projectRoot = pkgDir.sync() || process.cwd()
|
||||
const isTypescript = fs.existsSync(path.join(projectRoot, "tsconfig.json"))
|
||||
const pascalCase = (str: string) => require("camelcase")(str, {pascalCase: true})
|
||||
const getIsTypescript = () =>
|
||||
require("fs").existsSync(
|
||||
require("path").join(require("../utils/get-project-root").projectRoot, "tsconfig.json"),
|
||||
)
|
||||
|
||||
enum ResourceType {
|
||||
All = "all",
|
||||
@@ -46,18 +41,18 @@ interface Args {
|
||||
}
|
||||
|
||||
function pluralize(input: string): string {
|
||||
return _pluralize.isPlural(input) ? input : _pluralize.plural(input)
|
||||
return require("pluralize").isPlural(input) ? input : require("pluralize").plural(input)
|
||||
}
|
||||
|
||||
function singular(input: string): string {
|
||||
return _pluralize.isSingular(input) ? input : _pluralize.singular(input)
|
||||
return require("pluralize").isSingular(input) ? input : require("pluralize").singular(input)
|
||||
}
|
||||
|
||||
function modelName(input: string = "") {
|
||||
return camelCase(singular(input))
|
||||
return require("camelcase")(singular(input))
|
||||
}
|
||||
function modelNames(input: string = "") {
|
||||
return camelCase(pluralize(input))
|
||||
return require("camelcase")(pluralize(input))
|
||||
}
|
||||
function ModelName(input: string = "") {
|
||||
return pascalCase(singular(input))
|
||||
@@ -157,31 +152,33 @@ export class Generate extends Command {
|
||||
]
|
||||
|
||||
async promptForTargetDirectory(paths: string[]): Promise<string> {
|
||||
return enquirer
|
||||
.prompt<{directory: string}>({
|
||||
return require("enquirer")
|
||||
.prompt({
|
||||
name: "directory",
|
||||
type: "select",
|
||||
message: "Please select a target directory:",
|
||||
choices: paths,
|
||||
})
|
||||
.then((resp) => resp.directory)
|
||||
.then((resp: any) => resp.directory)
|
||||
}
|
||||
|
||||
async genericConfirmPrompt(message: string): Promise<boolean> {
|
||||
return enquirer
|
||||
.prompt<{continue: string}>({
|
||||
return require("enquirer")
|
||||
.prompt({
|
||||
name: "continue",
|
||||
type: "select",
|
||||
message: message,
|
||||
choices: ["Yes", "No"],
|
||||
})
|
||||
.then((resp) => resp.continue === "Yes")
|
||||
.then((resp: any) => resp.continue === "Yes")
|
||||
}
|
||||
|
||||
async handleNoContext(message: string): Promise<void> {
|
||||
const shouldCreateNewRoot = await this.genericConfirmPrompt(message)
|
||||
if (!shouldCreateNewRoot) {
|
||||
log.error("Could not determine proper location for files. Aborting.")
|
||||
require("@blitzjs/display").log.error(
|
||||
"Could not determine proper location for files. Aborting.",
|
||||
)
|
||||
this.exit(0)
|
||||
}
|
||||
}
|
||||
@@ -192,7 +189,7 @@ export class Generate extends Command {
|
||||
if (modelSegments.length > 1) {
|
||||
return {
|
||||
model: modelSegments[modelSegments.length - 1],
|
||||
context: path.join(...modelSegments.slice(0, modelSegments.length - 1)),
|
||||
context: require("path").join(...modelSegments.slice(0, modelSegments.length - 1)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,7 +198,7 @@ export class Generate extends Command {
|
||||
|
||||
return {
|
||||
model: modelName,
|
||||
context: path.join(...contextSegments),
|
||||
context: require("path").join(...contextSegments),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,7 +219,7 @@ export class Generate extends Command {
|
||||
const generators = generatorMap[args.type]
|
||||
for (const GeneratorClass of generators) {
|
||||
const generator = new GeneratorClass({
|
||||
destinationRoot: path.resolve(),
|
||||
destinationRoot: require("path").resolve(),
|
||||
extraArgs: argv.slice(2).filter((arg) => !arg.startsWith("-")),
|
||||
modelName: singularRootContext,
|
||||
modelNames: modelNames(singularRootContext),
|
||||
@@ -232,9 +229,10 @@ export class Generate extends Command {
|
||||
parentModels: modelNames(flags.parent),
|
||||
ParentModel: ModelName(flags.parent),
|
||||
ParentModels: ModelNames(flags.parent),
|
||||
rawInput: model,
|
||||
dryRun: flags["dry-run"],
|
||||
context: context,
|
||||
useTs: isTypescript,
|
||||
useTs: getIsTypescript(),
|
||||
})
|
||||
await generator.run()
|
||||
}
|
||||
|
||||
@@ -1,22 +1,14 @@
|
||||
import {Command} from "../command"
|
||||
import * as path from "path"
|
||||
import {RecipeExecutor} from "@blitzjs/installer"
|
||||
import _got from "got"
|
||||
import type {RecipeExecutor} from "@blitzjs/installer"
|
||||
import {log} from "@blitzjs/display"
|
||||
import {dedent} from "../utils/dedent"
|
||||
import {Stream} from "stream"
|
||||
import {promisify} from "util"
|
||||
import tar from "tar"
|
||||
import {mkdirSync, readFileSync, existsSync} from "fs-extra"
|
||||
import rimraf from "rimraf"
|
||||
import spawn from "cross-spawn"
|
||||
import * as os from "os"
|
||||
import {setupTsnode} from "../utils/setup-ts-node"
|
||||
|
||||
const pipeline = promisify(Stream.pipeline)
|
||||
|
||||
async function got(url: string) {
|
||||
return _got(url).catch((e) => Boolean(console.error(e)) || e)
|
||||
return require("got")(url).catch((e: any) => Boolean(console.error(e)) || e)
|
||||
}
|
||||
|
||||
async function gotJSON(url: string) {
|
||||
@@ -28,7 +20,7 @@ async function isUrlValid(url: string) {
|
||||
}
|
||||
|
||||
function requireJSON(file: string) {
|
||||
return JSON.parse(readFileSync(file).toString("utf-8"))
|
||||
return JSON.parse(require("fs-extra").readFileSync(file).toString("utf-8"))
|
||||
}
|
||||
|
||||
const GH_ROOT = "https://github.com/"
|
||||
@@ -115,10 +107,13 @@ export class Install extends Command {
|
||||
defaultBranch: string,
|
||||
subdirectory?: string,
|
||||
): Promise<string> {
|
||||
const recipeDir = path.join(os.tmpdir(), `blitz-recipe-${repoFullName.replace("/", "-")}`)
|
||||
const recipeDir = require("path").join(
|
||||
require("os").tmpdir(),
|
||||
`blitz-recipe-${repoFullName.replace("/", "-")}`,
|
||||
)
|
||||
// clean up from previous run in case of error
|
||||
rimraf.sync(recipeDir)
|
||||
mkdirSync(recipeDir)
|
||||
require("rimraf").sync(recipeDir)
|
||||
require("fs-extra").mkdirSync(recipeDir)
|
||||
process.chdir(recipeDir)
|
||||
|
||||
const repoName = repoFullName.split("/")[1]
|
||||
@@ -127,8 +122,8 @@ export class Install extends Command {
|
||||
const extractPath = subdirectory ? [`${repoName}-${defaultBranch}/${subdirectory}`] : undefined
|
||||
const depth = subdirectory ? subdirectory.split("/").length + 1 : 1
|
||||
await pipeline(
|
||||
_got.stream(`${CODE_ROOT}${repoFullName}/tar.gz/${defaultBranch}`),
|
||||
tar.extract({strip: depth}, extractPath),
|
||||
require("got").stream(`${CODE_ROOT}${repoFullName}/tar.gz/${defaultBranch}`),
|
||||
require("tar").extract({strip: depth}, extractPath),
|
||||
)
|
||||
|
||||
return recipeDir
|
||||
@@ -149,9 +144,11 @@ export class Install extends Command {
|
||||
}
|
||||
|
||||
async run() {
|
||||
setupTsnode()
|
||||
require("../utils/setup-ts-node").setupTsnode()
|
||||
const {args} = this.parse(Install)
|
||||
const pkgManager = existsSync(path.resolve("yarn.lock")) ? "yarn" : "npm"
|
||||
const pkgManager = require("fs-extra").existsSync(require("path").resolve("yarn.lock"))
|
||||
? "yarn"
|
||||
: "npm"
|
||||
const originalCwd = process.cwd()
|
||||
const recipeInfo = this.normalizeRecipePath(args.recipe)
|
||||
|
||||
@@ -178,21 +175,21 @@ export class Install extends Command {
|
||||
|
||||
spinner = log.spinner("Installing package.json dependencies").start()
|
||||
await new Promise((resolve) => {
|
||||
const installProcess = spawn(pkgManager, ["install"])
|
||||
const installProcess = require("cross-spawn")(pkgManager, ["install"])
|
||||
installProcess.on("exit", resolve)
|
||||
})
|
||||
spinner.stop()
|
||||
|
||||
const recipePackageMain = requireJSON("./package.json").main
|
||||
const recipeEntry = path.resolve(recipePackageMain)
|
||||
const recipeEntry = require("path").resolve(recipePackageMain)
|
||||
process.chdir(originalCwd)
|
||||
|
||||
await this.installRecipeAtPath(recipeEntry)
|
||||
|
||||
rimraf.sync(recipeRepoPath)
|
||||
require("rimraf").sync(recipeRepoPath)
|
||||
}
|
||||
} else {
|
||||
await this.installRecipeAtPath(path.resolve(args.recipe))
|
||||
await this.installRecipeAtPath(require("path").resolve(args.recipe))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
import * as path from "path"
|
||||
import {flags} from "@oclif/command"
|
||||
import {Command} from "../command"
|
||||
import {AppGenerator, AppGeneratorOptions} from "@blitzjs/generator"
|
||||
import type {AppGeneratorOptions} from "@blitzjs/generator"
|
||||
import chalk from "chalk"
|
||||
import hasbin from "hasbin"
|
||||
import {log} from "@blitzjs/display"
|
||||
const debug = require("debug")("blitz:new")
|
||||
|
||||
import {PromptAbortedError} from "../errors/prompt-aborted"
|
||||
import {Db} from "./db"
|
||||
|
||||
export interface Flags {
|
||||
ts: boolean
|
||||
@@ -60,8 +57,8 @@ export class New extends Command {
|
||||
debug("flags: ", flags)
|
||||
|
||||
try {
|
||||
const destinationRoot = path.resolve(args.name)
|
||||
const appName = path.basename(destinationRoot)
|
||||
const destinationRoot = require("path").resolve(args.name)
|
||||
const appName = require("path").basename(destinationRoot)
|
||||
|
||||
const formChoices: Array<{name: AppGeneratorOptions["form"]; message?: string}> = [
|
||||
{name: "React Final Form", message: "React Final Form (recommended)"},
|
||||
@@ -78,7 +75,7 @@ export class New extends Command {
|
||||
|
||||
const {"dry-run": dryRun, "skip-install": skipInstall, npm} = flags
|
||||
|
||||
const generator = new AppGenerator({
|
||||
const generator = new (require("@blitzjs/generator").AppGenerator)({
|
||||
destinationRoot,
|
||||
appName,
|
||||
dryRun,
|
||||
@@ -105,7 +102,7 @@ export class New extends Command {
|
||||
try {
|
||||
// Required in order for DATABASE_URL to be available
|
||||
require("dotenv-expand")(require("dotenv-flow").config({silent: true}))
|
||||
await Db.run(["migrate", "--name", "Initial Migration"])
|
||||
await require("./db").Db.run(["migrate", "--name", "Initial Migration"])
|
||||
spinner.succeed()
|
||||
} catch {
|
||||
spinner.fail()
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
import {dev, prod} from "@blitzjs/server"
|
||||
import {Command, flags} from "@oclif/command"
|
||||
import fs from "fs"
|
||||
import path from "path"
|
||||
import pkgDir from "pkg-dir"
|
||||
import {runPrismaGeneration} from "./db"
|
||||
|
||||
const projectRoot = pkgDir.sync() || process.cwd()
|
||||
const isTypescript = fs.existsSync(path.join(projectRoot, "tsconfig.json"))
|
||||
|
||||
export class Start extends Command {
|
||||
static description = "Start a development server"
|
||||
@@ -24,24 +17,26 @@ export class Start extends Command {
|
||||
char: "H",
|
||||
description: "Set server hostname",
|
||||
}),
|
||||
inspect: flags.boolean({
|
||||
description: "Enable the Node.js inspector",
|
||||
}),
|
||||
}
|
||||
|
||||
async run() {
|
||||
|
||||
const {flags} = this.parse(Start)
|
||||
|
||||
const config = {
|
||||
rootFolder: process.cwd(),
|
||||
port: flags.port,
|
||||
hostname: flags.hostname,
|
||||
isTypescript,
|
||||
inspect: flags.inspect,
|
||||
}
|
||||
|
||||
try {
|
||||
if (flags.production) {
|
||||
await prod(config, runPrismaGeneration({silent: true, failSilently: true}))
|
||||
await prod(config)
|
||||
} else {
|
||||
await dev(config, runPrismaGeneration({silent: true, failSilently: true}))
|
||||
await dev(config)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {spawn} from "cross-spawn"
|
||||
import {Command} from "@oclif/command"
|
||||
import hasYarn from "has-yarn"
|
||||
|
||||
export class Test extends Command {
|
||||
static description = "Run project tests"
|
||||
@@ -20,7 +19,7 @@ export class Test extends Command {
|
||||
if (watch) {
|
||||
watchMode = watch === "watch" || watch === "w"
|
||||
}
|
||||
const packageManager = hasYarn() ? "yarn" : "npm"
|
||||
const packageManager = require("has-yarn")() ? "yarn" : "npm"
|
||||
|
||||
if (watchMode) spawn(packageManager, ["test:watch"], {stdio: "inherit"})
|
||||
else spawn(packageManager, ["test"], {stdio: "inherit"})
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
require("v8-compile-cache")
|
||||
const cacheFile = require("path").join(__dirname, ".blitzjs-cli-cache")
|
||||
const lazyLoad = require("@salesforce/lazy-require").default.create(cacheFile)
|
||||
lazyLoad.start()
|
||||
import {run as oclifRun} from "@oclif/command"
|
||||
|
||||
// Load the .env environment variable so it's available for all commands
|
||||
|
||||
@@ -37,30 +37,11 @@ jest.mock(
|
||||
}),
|
||||
)
|
||||
|
||||
jest.mock(
|
||||
"../../src/commands/db",
|
||||
jest.fn(() => {
|
||||
return {
|
||||
runPrismaGeneration: jest.fn(),
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
describe("Console command", () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks()
|
||||
})
|
||||
|
||||
it("runs PrismaGeneration", async () => {
|
||||
await Console.prototype.run()
|
||||
expect(db.runPrismaGeneration).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("runs PrismaGeneration with silent allowed", async () => {
|
||||
await Console.prototype.run()
|
||||
expect(db.runPrismaGeneration).toHaveBeenCalledWith({silent: true, failSilently: true})
|
||||
})
|
||||
|
||||
it("runs repl", async () => {
|
||||
await Console.prototype.run()
|
||||
expect(repl.runRepl).toHaveBeenCalled()
|
||||
|
||||
@@ -17,6 +17,7 @@ let migrateSaveParams: any[]
|
||||
let migrateUpDevParams: any[]
|
||||
let migrateUpProdParams: any[]
|
||||
let migrateSaveWithNameParams: any[]
|
||||
let migrateSaveWithUnknownParams: any[]
|
||||
beforeAll(async () => {
|
||||
schemaArg = `--schema=${path.join(process.cwd(), "db", "schema.prisma")}`
|
||||
prismaBin = await resolveBinAsync("@prisma/cli", "prisma")
|
||||
@@ -41,6 +42,11 @@ beforeAll(async () => {
|
||||
["migrate", "save", schemaArg, "--create-db", "--experimental", "--name", "name"],
|
||||
{stdio: "ignore", env: process.env},
|
||||
]
|
||||
migrateSaveWithUnknownParams = [
|
||||
prismaBin,
|
||||
["migrate", "save", schemaArg, "--create-db", "--experimental"],
|
||||
{stdio: "inherit", env: process.env},
|
||||
]
|
||||
})
|
||||
|
||||
describe("Db command", () => {
|
||||
@@ -76,6 +82,13 @@ describe("Db command", () => {
|
||||
expect(onSpy).toHaveBeenCalledTimes(3)
|
||||
}
|
||||
|
||||
function expectDbMigrateWithUnknownFlag() {
|
||||
expect(spawn).toBeCalledWith(...migrateSaveWithUnknownParams)
|
||||
expect(spawn).toHaveBeenCalledTimes(3)
|
||||
|
||||
expect(onSpy).toHaveBeenCalledTimes(3)
|
||||
}
|
||||
|
||||
it("runs db help when no command given", async () => {
|
||||
// When running the help command oclif exits with code 0
|
||||
// Unfortantely it treats this as an exception and throws accordingly
|
||||
@@ -137,6 +150,18 @@ describe("Db command", () => {
|
||||
expectProductionDbMigrateOutcome()
|
||||
})
|
||||
|
||||
it("runs db migrate silently with the right args when name flag is used", async () => {
|
||||
await Db.run(["migrate", "--name", "name"])
|
||||
|
||||
expectDbMigrateWithNameOutcome()
|
||||
})
|
||||
|
||||
it("runs db migrate. (with unknown flags)", async () => {
|
||||
await Db.run(["migrate", "--hoge", "aaa"])
|
||||
|
||||
expectDbMigrateWithUnknownFlag()
|
||||
})
|
||||
|
||||
it("runs db introspect", async () => {
|
||||
await Db.run(["introspect"])
|
||||
|
||||
@@ -164,10 +189,4 @@ describe("Db command", () => {
|
||||
|
||||
expect(spawn.mock.calls.length).toBe(0)
|
||||
})
|
||||
|
||||
it("runs db migrate silently with the right args when name flag is used", async () => {
|
||||
await Db.run(["migrate", "--name", "name"])
|
||||
|
||||
expectDbMigrateWithNameOutcome()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"sourceMap": false,
|
||||
"esModuleInterop": true,
|
||||
"types": [],
|
||||
"noEmit": false,
|
||||
"lib": ["dom", "dom.iterable", "ES2018"]
|
||||
},
|
||||
"include": ["src/**/*", "types"],
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"config"
|
||||
],
|
||||
"author": "Fran Zekan <zekan.fran369@gmail.com>",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
|
||||
17
packages/core/.eslintrc.js
Normal file
17
packages/core/.eslintrc.js
Normal file
@@ -0,0 +1,17 @@
|
||||
module.exports = {
|
||||
extends: ["../../.eslintrc.js"],
|
||||
plugins: ["es5", "es"],
|
||||
rules: {
|
||||
"es5/no-for-of": "error",
|
||||
"es/no-object-fromentries": "error",
|
||||
"es5/no-generators": "error",
|
||||
"es5/no-typeof-symbol": "error",
|
||||
"es5/no-es6-methods": "error",
|
||||
"es5/no-es6-static-methods": [
|
||||
"error",
|
||||
{
|
||||
exceptMethods: ["Object.assign"],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@blitzjs/core",
|
||||
"description": "Blitz.js core functionality",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
@@ -40,11 +40,13 @@
|
||||
"url": "https://github.com/blitz-js/blitz"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/config": "0.21.2-canary.1",
|
||||
"@blitzjs/display": "0.21.2-canary.1",
|
||||
"@blitzjs/config": "0.23.2",
|
||||
"@blitzjs/display": "0.23.2",
|
||||
"bad-behavior": "1.0.1",
|
||||
"cookie-session": "1.4.0",
|
||||
"deepmerge": "4.2.2",
|
||||
"lodash": "^4.17.19",
|
||||
"lodash-es": "^4.17.15",
|
||||
"passport": "0.4.1",
|
||||
"pretty-ms": "6.0.1",
|
||||
"react-query": "2.5.11",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {NextPage, NextComponentType} from "next"
|
||||
import {NextPage, NextComponentType, NextPageContext} from "next"
|
||||
import {AppProps as NextAppProps} from "next/app"
|
||||
|
||||
export * from "./use-query"
|
||||
@@ -49,10 +49,10 @@ export {default as dynamic} from "next/dynamic"
|
||||
|
||||
export {default as ErrorComponent} from "next/error"
|
||||
|
||||
export type BlitzComponentType = NextComponentType
|
||||
export type BlitzComponentType<C = NextPageContext, IP = {}, P = {}> = NextComponentType<C, IP, P>
|
||||
|
||||
export interface AppProps extends NextAppProps {
|
||||
Component: BlitzComponentType & {
|
||||
export interface AppProps<P = {}> extends NextAppProps<P> {
|
||||
Component: BlitzComponentType<NextPageContext, any, P> & {
|
||||
getLayout?: (component: JSX.Element) => JSX.Element
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
/* eslint-disable es5/no-for-of -- file only used on the server */
|
||||
/* eslint-disable es5/no-es6-methods -- file only used on the server */
|
||||
import {BlitzApiRequest, BlitzApiResponse} from "."
|
||||
import {IncomingMessage, ServerResponse} from "http"
|
||||
import {EnhancedResolverModule} from "./rpc"
|
||||
import {getConfig} from "@blitzjs/config"
|
||||
import {log} from "@blitzjs/display"
|
||||
|
||||
export interface MiddlewareRequest extends BlitzApiRequest {}
|
||||
export interface MiddlewareRequest extends BlitzApiRequest {
|
||||
protocol?: string
|
||||
}
|
||||
export interface MiddlewareResponse extends BlitzApiResponse {
|
||||
/**
|
||||
* This will be passed as the second argument to Blitz queries/mutations.
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import {BlitzApiRequest, BlitzApiResponse} from "."
|
||||
/* eslint-disable es5/no-for-of -- file only used on the server */
|
||||
/* eslint-disable es5/no-es6-methods -- file only used on the server */
|
||||
import {BlitzApiRequest, BlitzApiResponse, ConnectMiddleware} from "."
|
||||
import {
|
||||
getAllMiddlewareForModule,
|
||||
handleRequestWithMiddleware,
|
||||
@@ -7,14 +9,17 @@ import {
|
||||
} from "./middleware"
|
||||
import {SessionContext, PublicData} from "./supertokens"
|
||||
import {log} from "@blitzjs/display"
|
||||
import passport, {Strategy} from "passport"
|
||||
import passport, {AuthenticateOptions, Strategy} from "passport"
|
||||
import cookieSession from "cookie-session"
|
||||
import {isLocalhost} from "./utils/index"
|
||||
import {secureProxyMiddleware} from "./secure-proxy-middleware"
|
||||
|
||||
export type BlitzPassportConfig = {
|
||||
successRedirectUrl?: string
|
||||
errorRedirectUrl?: string
|
||||
authenticateOptions?: AuthenticateOptions
|
||||
strategies: Required<Strategy>[]
|
||||
secureProxy?: boolean
|
||||
}
|
||||
|
||||
export type VerifyCallbackResult = {
|
||||
@@ -34,19 +39,23 @@ const INTERNAL_REDIRECT_URL_KEY = "_redirectUrl"
|
||||
|
||||
export function passportAuth(config: BlitzPassportConfig) {
|
||||
return async function authHandler(req: BlitzApiRequest, res: BlitzApiResponse) {
|
||||
const cookieSessionMiddleware = cookieSession({
|
||||
secret: process.env.SESSION_SECRET_KEY || "default-dev-secret",
|
||||
secure: process.env.NODE_ENV === "production" && !isLocalhost(req),
|
||||
})
|
||||
|
||||
const passportMiddleware = passport.initialize()
|
||||
|
||||
const middleware: Middleware[] = [
|
||||
// TODO - fix TS type - shouldn't need `any` here
|
||||
connectMiddleware(
|
||||
cookieSession({
|
||||
secret: process.env.SESSION_SECRET_KEY || "default-dev-secret",
|
||||
secure: process.env.NODE_ENV === "production" && !isLocalhost(req),
|
||||
}) as any,
|
||||
),
|
||||
// TODO - fix TS type - shouldn't need `any` here
|
||||
connectMiddleware(passport.initialize() as any),
|
||||
connectMiddleware(cookieSessionMiddleware as ConnectMiddleware),
|
||||
connectMiddleware(passportMiddleware as ConnectMiddleware),
|
||||
connectMiddleware(passport.session()),
|
||||
]
|
||||
|
||||
if (config.secureProxy) {
|
||||
middleware.push(secureProxyMiddleware)
|
||||
}
|
||||
|
||||
if (!req.query.auth.length) {
|
||||
return res.status(404).end()
|
||||
}
|
||||
@@ -71,7 +80,9 @@ export function passportAuth(config: BlitzPassportConfig) {
|
||||
return next()
|
||||
})
|
||||
}
|
||||
middleware.push(connectMiddleware(passport.authenticate(strategy.name)))
|
||||
middleware.push(
|
||||
connectMiddleware(passport.authenticate(strategy.name, {...config.authenticateOptions})),
|
||||
)
|
||||
} else if (req.query.auth[1] === "callback") {
|
||||
log.info(`Processing callback for ${strategy.name}...`)
|
||||
middleware.push(
|
||||
|
||||
@@ -19,7 +19,7 @@ type Options = {
|
||||
resultOfGetFetchMore?: any
|
||||
}
|
||||
|
||||
export async function executeRpcCall(url: string, params: any, opts: Options = {}) {
|
||||
export function executeRpcCall(url: string, params: any, opts: Options = {}) {
|
||||
if (typeof window === "undefined") return
|
||||
|
||||
const headers: Record<string, any> = {
|
||||
@@ -46,56 +46,70 @@ export async function executeRpcCall(url: string, params: any, opts: Options = {
|
||||
serialized = serialize(params)
|
||||
}
|
||||
|
||||
const result = await window.fetch(url, {
|
||||
method: "POST",
|
||||
headers,
|
||||
credentials: "include",
|
||||
redirect: "follow",
|
||||
body: JSON.stringify({
|
||||
// TODO remove `|| null` once superjson allows `undefined`
|
||||
params: serialized.json || null,
|
||||
meta: {
|
||||
params: serialized.meta,
|
||||
},
|
||||
}),
|
||||
})
|
||||
// Create a new AbortController instance for this request
|
||||
const controller = new AbortController()
|
||||
|
||||
if (result.headers) {
|
||||
for (const [name] of result.headers.entries()) {
|
||||
if (name.toLowerCase() === HEADER_PUBLIC_DATA_TOKEN) publicDataStore.updateState()
|
||||
if (name.toLowerCase() === HEADER_SESSION_REVOKED) publicDataStore.clear()
|
||||
if (name.toLowerCase() === HEADER_CSRF_ERROR) {
|
||||
throw new CSRFTokenMismatchError()
|
||||
const promise: CancellablePromise<any> = window
|
||||
.fetch(url, {
|
||||
method: "POST",
|
||||
headers,
|
||||
credentials: "include",
|
||||
redirect: "follow",
|
||||
body: JSON.stringify({
|
||||
// TODO remove `|| null` once superjson allows `undefined`
|
||||
params: serialized.json || null,
|
||||
meta: {
|
||||
params: serialized.meta,
|
||||
},
|
||||
}),
|
||||
signal: controller.signal,
|
||||
})
|
||||
.then(async (result) => {
|
||||
if (result.headers) {
|
||||
if (result.headers.get(HEADER_PUBLIC_DATA_TOKEN)) {
|
||||
publicDataStore.updateState()
|
||||
}
|
||||
if (result.headers.get(HEADER_SESSION_REVOKED)) {
|
||||
publicDataStore.clear()
|
||||
}
|
||||
if (result.headers.get(HEADER_CSRF_ERROR)) {
|
||||
throw new CSRFTokenMismatchError()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let payload
|
||||
try {
|
||||
payload = await result.json()
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to parse json from request to ${url}`)
|
||||
}
|
||||
let payload
|
||||
try {
|
||||
payload = await result.json()
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to parse json from request to ${url}`)
|
||||
}
|
||||
|
||||
if (payload.error) {
|
||||
const error = deserializeError(payload.error)
|
||||
// We don't clear the publicDataStore for anonymous users
|
||||
if (error.name === "AuthenticationError" && publicDataStore.getData().userId) {
|
||||
publicDataStore.clear()
|
||||
}
|
||||
throw error
|
||||
} else {
|
||||
const data =
|
||||
payload.result === undefined
|
||||
? undefined
|
||||
: deserialize({json: payload.result, meta: payload.meta?.result})
|
||||
if (payload.error) {
|
||||
const error = deserializeError(payload.error)
|
||||
// We don't clear the publicDataStore for anonymous users
|
||||
if (error.name === "AuthenticationError" && publicDataStore.getData().userId) {
|
||||
publicDataStore.clear()
|
||||
}
|
||||
throw error
|
||||
} else {
|
||||
const data =
|
||||
payload.result === undefined
|
||||
? undefined
|
||||
: deserialize({json: payload.result, meta: payload.meta?.result})
|
||||
|
||||
if (!opts.fromQueryHook) {
|
||||
const queryKey = getQueryKey(url, params)
|
||||
queryCache.setQueryData(queryKey, data)
|
||||
}
|
||||
return data
|
||||
}
|
||||
if (!opts.fromQueryHook) {
|
||||
const queryKey = getQueryKey(url, params)
|
||||
queryCache.setQueryData(queryKey, data)
|
||||
}
|
||||
return data
|
||||
}
|
||||
})
|
||||
|
||||
// Disable react-query request cancellation for now
|
||||
// Having too many weird bugs with it enabled
|
||||
// promise.cancel = () => controller.abort()
|
||||
|
||||
return promise
|
||||
}
|
||||
|
||||
executeRpcCall.warm = (url: string) => {
|
||||
@@ -113,13 +127,18 @@ interface ResolverEnhancement {
|
||||
apiUrl: string
|
||||
}
|
||||
}
|
||||
|
||||
interface CancellablePromise<T> extends Promise<T> {
|
||||
cancel?: Function
|
||||
}
|
||||
|
||||
export interface RpcFunction {
|
||||
(params: any, opts: any): Promise<any>
|
||||
(params: any, opts: any): CancellablePromise<any>
|
||||
}
|
||||
export interface EnhancedRpcFunction extends RpcFunction, ResolverEnhancement {}
|
||||
|
||||
export interface EnhancedResolverModule extends ResolverEnhancement {
|
||||
(input: any, ctx: Record<string, any>): Promise<unknown>
|
||||
(input: any, ctx: Record<string, any>): CancellablePromise<unknown>
|
||||
middleware?: Middleware[]
|
||||
}
|
||||
|
||||
|
||||
54
packages/core/src/secure-proxy-middleware.test.ts
Normal file
54
packages/core/src/secure-proxy-middleware.test.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
// @ts-ignore
|
||||
import {Request} from "express"
|
||||
|
||||
import {secureProxyMiddleware} from "./secure-proxy-middleware"
|
||||
import {Socket} from "net"
|
||||
|
||||
// @ts-ignore
|
||||
let reqSecure: Request = {
|
||||
connection: new Socket(),
|
||||
method: "GET",
|
||||
url: "/stuff?q=thing",
|
||||
headers: {
|
||||
"x-forwarded-proto": "https",
|
||||
},
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
let reqHttp: Request = {
|
||||
connection: new Socket(),
|
||||
method: "GET",
|
||||
url: "/stuff?q=thing",
|
||||
headers: {
|
||||
"x-forwarded-proto": "http",
|
||||
},
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
let reqNoHeader: Request = {
|
||||
connection: new Socket(),
|
||||
method: "GET",
|
||||
url: "/stuff?q=thing",
|
||||
}
|
||||
|
||||
const res = {}
|
||||
|
||||
describe("secure proxy middleware", () => {
|
||||
it("should set https protocol if X-Forwarded-Proto is https", () => {
|
||||
// @ts-ignore
|
||||
secureProxyMiddleware(reqSecure, res, () => null)
|
||||
expect(reqSecure.protocol).toEqual("https")
|
||||
})
|
||||
|
||||
it("should set http protocol if X-Forwarded-Proto is absent", () => {
|
||||
// @ts-ignore
|
||||
secureProxyMiddleware(reqNoHeader, res, () => null)
|
||||
expect(reqNoHeader.protocol).toEqual("http")
|
||||
})
|
||||
|
||||
it("should set http protocol if X-Forwarded-Proto is http", () => {
|
||||
// @ts-ignore
|
||||
secureProxyMiddleware(reqHttp, res, () => null)
|
||||
expect(reqHttp.protocol).toEqual("http")
|
||||
})
|
||||
})
|
||||
23
packages/core/src/secure-proxy-middleware.ts
Normal file
23
packages/core/src/secure-proxy-middleware.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import {Middleware, MiddlewareRequest, MiddlewareResponse} from "middleware"
|
||||
|
||||
export const secureProxyMiddleware: Middleware = function (
|
||||
req: MiddlewareRequest,
|
||||
_res: MiddlewareResponse,
|
||||
next: (error?: Error) => void,
|
||||
) {
|
||||
req.protocol = getProtocol(req)
|
||||
next()
|
||||
}
|
||||
|
||||
function getProtocol(req: MiddlewareRequest) {
|
||||
// @ts-ignore
|
||||
// For some reason there is no encrypted on socket while it is expected
|
||||
if (req.connection.encrypted) {
|
||||
return "https"
|
||||
}
|
||||
const forwardedProto = req.headers && (req.headers["x-forwarded-proto"] as string)
|
||||
if (forwardedProto) {
|
||||
return forwardedProto.split(/\s*,\s*/)[0]
|
||||
}
|
||||
return "http"
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
InfiniteQueryResult,
|
||||
InfiniteQueryOptions,
|
||||
} from "react-query"
|
||||
import {useIsDevPrerender, emptyQueryFn, retryFunction} from "./use-query"
|
||||
import {emptyQueryFn, retryFunction} from "./use-query"
|
||||
import {PromiseReturnType, InferUnaryParam, QueryFn} from "./types"
|
||||
import {getQueryCacheFunctions, QueryCacheFunctions, getInfiniteQueryKey} from "./utils/query-cache"
|
||||
import {EnhancedRpcFunction} from "./rpc"
|
||||
@@ -14,6 +14,8 @@ type RestQueryResult<T extends QueryFn> = Omit<
|
||||
> &
|
||||
QueryCacheFunctions<PromiseReturnType<T>[]>
|
||||
|
||||
const isServer = typeof window === "undefined"
|
||||
|
||||
export function useInfiniteQuery<T extends QueryFn>(
|
||||
queryFn: T,
|
||||
params: InferUnaryParam<T> | (() => InferUnaryParam<T>),
|
||||
@@ -29,9 +31,7 @@ export function useInfiniteQuery<T extends QueryFn>(
|
||||
)
|
||||
}
|
||||
|
||||
const queryRpcFn = useIsDevPrerender()
|
||||
? emptyQueryFn
|
||||
: ((queryFn as unknown) as EnhancedRpcFunction)
|
||||
const queryRpcFn = isServer ? emptyQueryFn : ((queryFn as unknown) as EnhancedRpcFunction)
|
||||
|
||||
const queryKey = getInfiniteQueryKey(queryFn, params)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
PaginatedQueryResult,
|
||||
QueryOptions,
|
||||
} from "react-query"
|
||||
import {useIsDevPrerender, emptyQueryFn, retryFunction} from "./use-query"
|
||||
import {emptyQueryFn, retryFunction} from "./use-query"
|
||||
import {PromiseReturnType, InferUnaryParam, QueryFn} from "./types"
|
||||
import {QueryCacheFunctions, getQueryCacheFunctions, getQueryKey} from "./utils/query-cache"
|
||||
import {EnhancedRpcFunction} from "./rpc"
|
||||
@@ -14,10 +14,12 @@ type RestQueryResult<T extends QueryFn> = Omit<
|
||||
> &
|
||||
QueryCacheFunctions<PromiseReturnType<T>>
|
||||
|
||||
const isServer = typeof window === "undefined"
|
||||
|
||||
export function usePaginatedQuery<T extends QueryFn>(
|
||||
queryFn: T,
|
||||
params: InferUnaryParam<T> | (() => InferUnaryParam<T>),
|
||||
options?: QueryOptions<PaginatedQueryResult<PromiseReturnType<T>>>,
|
||||
options?: QueryOptions<PromiseReturnType<T>>,
|
||||
): [PromiseReturnType<T>, RestQueryResult<T>] {
|
||||
if (typeof queryFn === "undefined") {
|
||||
throw new Error("usePaginatedQuery is missing the first argument - it must be a query function")
|
||||
@@ -29,9 +31,7 @@ export function usePaginatedQuery<T extends QueryFn>(
|
||||
)
|
||||
}
|
||||
|
||||
const queryRpcFn = useIsDevPrerender()
|
||||
? emptyQueryFn
|
||||
: ((queryFn as unknown) as EnhancedRpcFunction)
|
||||
const queryRpcFn = isServer ? emptyQueryFn : ((queryFn as unknown) as EnhancedRpcFunction)
|
||||
|
||||
const queryKey = getQueryKey(queryFn, params)
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {useRouter} from "next/router"
|
||||
import {useRouterQuery} from "./use-router-query"
|
||||
import {fromPairs} from "lodash"
|
||||
|
||||
type ParsedUrlQueryValue = string | string[] | undefined
|
||||
|
||||
@@ -31,7 +32,7 @@ function areQueryValuesEqual(value1: ParsedUrlQueryValue, value2: ParsedUrlQuery
|
||||
}
|
||||
|
||||
export function extractRouterParams(routerQuery: ParsedUrlQuery, query: ParsedUrlQuery) {
|
||||
return Object.fromEntries(
|
||||
return fromPairs(
|
||||
Object.entries(routerQuery).filter(
|
||||
([key, value]) =>
|
||||
typeof query[key] === "undefined" || !areQueryValuesEqual(value, query[key]),
|
||||
@@ -51,9 +52,9 @@ export function useParams(returnType?: "string" | "number" | "array") {
|
||||
|
||||
if (returnType === "string") {
|
||||
const params: Record<string, string> = {}
|
||||
for (const [key, value] of Object.entries(rawParams)) {
|
||||
if (typeof value === "string") {
|
||||
params[key] = value
|
||||
for (const key in rawParams) {
|
||||
if (typeof rawParams[key] === "string") {
|
||||
params[key] = rawParams[key] as string
|
||||
}
|
||||
}
|
||||
return params
|
||||
@@ -61,9 +62,9 @@ export function useParams(returnType?: "string" | "number" | "array") {
|
||||
|
||||
if (returnType === "number") {
|
||||
const params: Record<string, number> = {}
|
||||
for (const [key, value] of Object.entries(rawParams)) {
|
||||
if (value) {
|
||||
params[key] = Number(value)
|
||||
for (const key in rawParams) {
|
||||
if (rawParams[key]) {
|
||||
params[key] = Number(rawParams[key])
|
||||
}
|
||||
}
|
||||
return params
|
||||
@@ -71,9 +72,9 @@ export function useParams(returnType?: "string" | "number" | "array") {
|
||||
|
||||
if (returnType === "array") {
|
||||
const params: Record<string, Array<string | undefined>> = {}
|
||||
for (const [key, value] of Object.entries(rawParams)) {
|
||||
if (Array.isArray(value)) {
|
||||
params[key] = value
|
||||
for (const key in rawParams) {
|
||||
if (Array.isArray(rawParams[key])) {
|
||||
params[key] = rawParams[key] as Array<string | undefined>
|
||||
}
|
||||
}
|
||||
return params
|
||||
|
||||
@@ -19,17 +19,6 @@ export const emptyQueryFn: EnhancedRpcFunction = (() => {
|
||||
|
||||
const isServer = typeof window === "undefined"
|
||||
|
||||
// NOTE - this is only for use inside useQuery
|
||||
export const useIsDevPrerender = () => {
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
return false
|
||||
} else {
|
||||
// useQuery is only for client-side data fetching, so if it's running on the
|
||||
// server, it's for pre-render
|
||||
return isServer
|
||||
}
|
||||
}
|
||||
|
||||
export const retryFunction = (failureCount: number, error: any) => {
|
||||
if (process.env.NODE_ENV !== "production") return false
|
||||
|
||||
@@ -42,7 +31,7 @@ export const retryFunction = (failureCount: number, error: any) => {
|
||||
export function useQuery<T extends QueryFn>(
|
||||
queryFn: T,
|
||||
params: InferUnaryParam<T> | (() => InferUnaryParam<T>),
|
||||
options?: QueryOptions<QueryResult<PromiseReturnType<T>>>,
|
||||
options?: QueryOptions<PromiseReturnType<T>>,
|
||||
): [PromiseReturnType<T>, RestQueryResult<T>] {
|
||||
if (typeof queryFn === "undefined") {
|
||||
throw new Error("useQuery is missing the first argument - it must be a query function")
|
||||
@@ -54,9 +43,7 @@ export function useQuery<T extends QueryFn>(
|
||||
)
|
||||
}
|
||||
|
||||
const queryRpcFn = useIsDevPrerender()
|
||||
? emptyQueryFn
|
||||
: ((queryFn as unknown) as EnhancedRpcFunction)
|
||||
const queryRpcFn = isServer ? emptyQueryFn : ((queryFn as unknown) as EnhancedRpcFunction)
|
||||
|
||||
const queryKey = getQueryKey(queryFn, params)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@blitzjs/display",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"description": "Display package for the Blitz CLI",
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@blitzjs/file-pipeline",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"description": "Display package for the Blitz CLI",
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import {pipe} from "../streams"
|
||||
import {createPipeline} from "../pipeline"
|
||||
import {pathExists, ensureDir, remove} from "fs-extra"
|
||||
import {through} from "../streams"
|
||||
import {createDisplay} from "../display"
|
||||
import {READY, ERROR_THROWN} from "../events"
|
||||
import {Stage} from "../types"
|
||||
import {ensureDir, pathExists, remove} from "fs-extra"
|
||||
import {Transform} from "stream"
|
||||
import {createDisplay} from "../display"
|
||||
import {ERROR_THROWN, READY} from "../events"
|
||||
import {createPipeline} from "../pipeline"
|
||||
import {pipe, through} from "../streams"
|
||||
import {Stage} from "../types"
|
||||
|
||||
type FSStreamer = {stream: NodeJS.ReadWriteStream}
|
||||
|
||||
@@ -17,7 +16,6 @@ type SynchronizeFilesOptions = {
|
||||
source?: FSStreamer
|
||||
writer?: FSStreamer
|
||||
noclean?: boolean
|
||||
isTypescript?: boolean
|
||||
}
|
||||
|
||||
const defaultBus = through.obj()
|
||||
@@ -42,7 +40,6 @@ export async function transformFiles(
|
||||
source,
|
||||
writer,
|
||||
noclean = false,
|
||||
isTypescript = true,
|
||||
} = options
|
||||
|
||||
// HACK: cleaning the dev folder on every restart means we do more work than necessary
|
||||
@@ -59,7 +56,6 @@ export async function transformFiles(
|
||||
include,
|
||||
ignore,
|
||||
watch,
|
||||
isTypescript,
|
||||
}
|
||||
const fileTransformPipeline = createPipeline(config, stages, bus, source, writer)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {Writable} from "stream"
|
||||
import {FileCache} from "./helpers/file-cache"
|
||||
import File from "vinyl"
|
||||
import {FileCache} from "./helpers/file-cache"
|
||||
|
||||
export type EventedFile = {
|
||||
event: "add" | "change" | "unlink" | "unlinkDir"
|
||||
@@ -21,7 +21,6 @@ export type StageConfig = {
|
||||
include: string[]
|
||||
ignore: string[]
|
||||
watch: boolean
|
||||
isTypescript: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@blitzjs/generator",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"description": "File generation for the Blitz CLI",
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"license": "MIT",
|
||||
@@ -36,7 +36,7 @@
|
||||
"dependencies": {
|
||||
"@babel/core": "7.9.0",
|
||||
"@babel/plugin-transform-typescript": "7.9.4",
|
||||
"@blitzjs/display": "0.21.2-canary.1",
|
||||
"@blitzjs/display": "0.23.2",
|
||||
"@types/jscodeshift": "0.7.1",
|
||||
"chalk": "4.0.0",
|
||||
"cross-spawn": "7.0.3",
|
||||
@@ -48,7 +48,7 @@
|
||||
"jscodeshift": "0.10.0",
|
||||
"mem-fs": "1.1.3",
|
||||
"mem-fs-editor": "6.0.0",
|
||||
"node-fetch": "2.6.0",
|
||||
"node-fetch": "2.6.1",
|
||||
"pluralize": "8.0.0",
|
||||
"recast": "0.19.1",
|
||||
"username": "5.1.0",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import {Generator, GeneratorOptions} from "../generator"
|
||||
import {join} from "path"
|
||||
import {camelCaseToKebabCase} from "../utils/kebab-case"
|
||||
|
||||
export interface PageGeneratorOptions extends GeneratorOptions {
|
||||
ModelName: string
|
||||
@@ -51,9 +52,10 @@ export class PageGenerator extends Generator<PageGeneratorOptions> {
|
||||
}
|
||||
|
||||
getTargetDirectory() {
|
||||
const kebabCaseModelName = camelCaseToKebabCase(this.options.modelNames)
|
||||
const parent = this.options.parentModels
|
||||
? `${this.options.parentModels}/__parentModelParam__/`
|
||||
: ""
|
||||
return `app/${this.getModelNamesPath()}/pages/${parent}${this.options.modelNames}`
|
||||
return `app/${this.getModelNamesPath()}/pages/${parent}${kebabCaseModelName}`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import {Generator, GeneratorOptions} from "../generator"
|
||||
import {join} from "path"
|
||||
|
||||
export interface QueryGeneratorOptions extends GeneratorOptions {
|
||||
modelName: string
|
||||
rawInput: string
|
||||
}
|
||||
|
||||
export class QueryGenerator extends Generator<QueryGeneratorOptions> {
|
||||
@@ -12,7 +12,7 @@ export class QueryGenerator extends Generator<QueryGeneratorOptions> {
|
||||
// eslint-disable-next-line require-await
|
||||
async getTemplateValues() {
|
||||
return {
|
||||
modelName: this.options.modelName,
|
||||
rawInput: this.options.rawInput,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
3
packages/generator/src/utils/kebab-case.ts
Normal file
3
packages/generator/src/utils/kebab-case.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export function camelCaseToKebabCase(transformString: string) {
|
||||
return transformString.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, "$1-$2").toLowerCase()
|
||||
}
|
||||
@@ -6,6 +6,7 @@ type NpmDepResponse = {versions: Record<string, PackageInformation>}
|
||||
export const fetchAllVersions = async (dependency: string) => {
|
||||
const res = await got(`https://registry.npmjs.org/${dependency}`, {
|
||||
retry: {limit: 3},
|
||||
timeout: 3000,
|
||||
responseType: "json",
|
||||
}).json<NpmDepResponse>()
|
||||
return Object.keys(res.versions)
|
||||
@@ -16,6 +17,7 @@ type NpmDistTagsResponse = {latest: string; canary: string}
|
||||
export const fetchDistTags = async (dependency: string) => {
|
||||
const res = await got(`https://registry.npmjs.org/-/package/${dependency}/dist-tags`, {
|
||||
retry: {limit: 3},
|
||||
timeout: 3000,
|
||||
responseType: "json",
|
||||
}).json<NpmDistTagsResponse>()
|
||||
return res
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# This env file should NOT be checked into source control
|
||||
# This is the place for values that changed for every developer
|
||||
|
||||
# SQLite is ready to go out of the box, but you can switch to Postgres easily
|
||||
# by swapping the DATABASE_URL.
|
||||
# SQLite is ready to go out of the box, but you can switch to Postgres
|
||||
# by first changing the provider from "sqlite" to "postgres" in the Prisma
|
||||
# schema file and by second swapping the DATABASE_URL below.
|
||||
DATABASE_URL="file:./db.sqlite"
|
||||
# DATABASE_URL=postgresql://__username__@localhost:5432/__name__
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# THIS FILE SHOULD NOT BE CHECKED INTO YOUR VERSION CONTROL SYSTEM
|
||||
|
||||
# SQLite is ready to go out of the box, but you can switch to Postgres easily
|
||||
# by swapping the DATABASE_URL.
|
||||
# SQLite is ready to go out of the box, but you can switch to Postgres
|
||||
# by first changing the provider from "sqlite" to "postgres" in the Prisma
|
||||
# schema file and by second swapping the DATABASE_URL below.
|
||||
DATABASE_URL="file:./db_test.sqlite"
|
||||
# DATABASE_URL=postgresql://__username__@localhost:5432/__name___test
|
||||
|
||||
@@ -18,6 +18,8 @@ export const LabeledTextField = React.forwardRef<HTMLInputElement, LabeledTextFi
|
||||
meta: {touched, error, submitError, submitting},
|
||||
} = useField(name)
|
||||
|
||||
const normalizedError = Array.isArray(error) ? error.join(", ") : error || submitError
|
||||
|
||||
return (
|
||||
<div {...outerProps}>
|
||||
<label>
|
||||
@@ -25,9 +27,9 @@ export const LabeledTextField = React.forwardRef<HTMLInputElement, LabeledTextFi
|
||||
<input {...input} disabled={submitting} {...props} ref={ref} />
|
||||
</label>
|
||||
|
||||
{touched && (error || submitError) && (
|
||||
{touched && normalizedError && (
|
||||
<div role="alert" style={{color: "red"}}>
|
||||
{error || submitError}
|
||||
{normalizedError}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ export const verifyPassword = async (hashedPassword: string, password: string) =
|
||||
}
|
||||
|
||||
export const authenticateUser = async (email: string, password: string) => {
|
||||
const user = await db.user.findOne({ where: { email } })
|
||||
const user = await db.user.findOne({ where: { email: email.toLowerCase() } })
|
||||
|
||||
if (!user || !user.hashedPassword) throw new AuthenticationError()
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React from "react"
|
||||
import { Link } from "blitz"
|
||||
import { LabeledTextField } from "app/components/LabeledTextField"
|
||||
import { Form, FORM_ERROR } from "app/components/Form"
|
||||
import login from "app/auth/mutations/login"
|
||||
@@ -36,6 +37,10 @@ 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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export default async function signup(
|
||||
|
||||
const hashedPassword = await hashPassword(password)
|
||||
const user = await db.user.create({
|
||||
data: { email, hashedPassword, role: "user" },
|
||||
data: { email: email.toLowerCase(), hashedPassword, role: "user" },
|
||||
select: { id: true, name: true, email: true, role: true },
|
||||
})
|
||||
|
||||
|
||||
@@ -6,15 +6,17 @@ type LayoutProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
const Layout = ({ title, children }: LayoutProps) => (
|
||||
<>
|
||||
<Head>
|
||||
<title>{title || "__name__"}</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
const Layout = ({ title, children }: LayoutProps) => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{title || "__name__"}</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
|
||||
{children}
|
||||
</>
|
||||
)
|
||||
{children}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Layout
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import { AppProps, ErrorComponent } from "blitz"
|
||||
import { AppProps, ErrorComponent, useRouter } from "blitz"
|
||||
import { ErrorBoundary, FallbackProps } from "react-error-boundary"
|
||||
import { queryCache } from "react-query"
|
||||
import LoginForm from "app/auth/components/LoginForm"
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
const getLayout = Component.getLayout || ((page) => page)
|
||||
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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
datasource db {
|
||||
provider = ["sqlite", "postgres"]
|
||||
provider = "sqlite"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
|
||||
@@ -12,14 +12,17 @@
|
||||
"browserslist": [
|
||||
"defaults"
|
||||
],
|
||||
"prisma": {
|
||||
"schema": "db/schema.prisma"
|
||||
},
|
||||
"prettier": {
|
||||
"semi": false,
|
||||
"printWidth": 100
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged && pretty-quick --staged",
|
||||
"pre-push": "blitz test"
|
||||
"pre-commit": "tsc && lint-staged && pretty-quick --staged",
|
||||
"pre-push": "npm lint && npm test"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
@@ -39,13 +42,13 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@testing-library/jest-dom": "5.x",
|
||||
"@testing-library/react": "10.x",
|
||||
"@testing-library/react": "11.x",
|
||||
"@testing-library/react-hooks": "3.x",
|
||||
"@types/jest": "26.x",
|
||||
"@types/react": "16.x",
|
||||
"@types/secure-password": "3.x",
|
||||
"@typescript-eslint/eslint-plugin": "3.x",
|
||||
"@typescript-eslint/parser": "3.x",
|
||||
"@typescript-eslint/eslint-plugin": "4.x",
|
||||
"@typescript-eslint/parser": "4.x",
|
||||
"babel-eslint": "10.x",
|
||||
"eslint": "7.x",
|
||||
"eslint-config-react-app": "5.x",
|
||||
@@ -61,8 +64,8 @@
|
||||
"react-test-renderer": "16.x",
|
||||
"lint-staged": "10.x",
|
||||
"prettier": "2.x",
|
||||
"pretty-quick": "2.x",
|
||||
"typescript": "3.x",
|
||||
"pretty-quick": "3.x",
|
||||
"typescript": "4.x",
|
||||
"ts-jest": "26.x"
|
||||
},
|
||||
"private": true
|
||||
|
||||
@@ -3,3 +3,4 @@
|
||||
// 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 })
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import {SessionContext} from "blitz"
|
||||
import db from "db"
|
||||
|
||||
export default async function __modelName__(__, ctx: {session?: SessionContext} = {}) {
|
||||
return ctx
|
||||
}
|
||||
6
packages/generator/templates/query/__rawInput__.ts
Normal file
6
packages/generator/templates/query/__rawInput__.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import {SessionContext} from "blitz"
|
||||
import db from "db"
|
||||
|
||||
export default async function __rawInput__(__, ctx: {session?: SessionContext} = {}) {
|
||||
return ctx
|
||||
}
|
||||
31
packages/generator/test/utils/kebab-case.test.ts
Normal file
31
packages/generator/test/utils/kebab-case.test.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import {camelCaseToKebabCase} from "../../src/utils/kebab-case"
|
||||
|
||||
describe("kebabCase utility function", () => {
|
||||
describe("transform a camelCase string to kebab case", () => {
|
||||
it("works for 2 word camelCase", () => {
|
||||
const result = camelCaseToKebabCase("testResult")
|
||||
|
||||
expect(result).toBe("test-result")
|
||||
})
|
||||
|
||||
it("works for multiple camelCase words", () => {
|
||||
const result = camelCaseToKebabCase("longTestStringResult")
|
||||
|
||||
expect(result).toBe("long-test-string-result")
|
||||
})
|
||||
})
|
||||
|
||||
describe("do not transform strings that are not camelCase", () => {
|
||||
it("does not modify a kebabCase string", () => {
|
||||
const result = camelCaseToKebabCase("test-result")
|
||||
|
||||
expect(result).toBe("test-result")
|
||||
})
|
||||
|
||||
it("does not modify single word string", () => {
|
||||
const result = camelCaseToKebabCase("testresult")
|
||||
|
||||
expect(result).toBe("testresult")
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@blitzjs/installer",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"description": "Package installation for the Blitz CLI",
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"license": "MIT",
|
||||
@@ -36,8 +36,8 @@
|
||||
"dependencies": {
|
||||
"@babel/core": "7.9.0",
|
||||
"@babel/plugin-transform-typescript": "7.9.4",
|
||||
"@blitzjs/display": "0.21.2-canary.1",
|
||||
"@blitzjs/generator": "0.21.2-canary.1",
|
||||
"@blitzjs/display": "0.23.2",
|
||||
"@blitzjs/generator": "0.23.2",
|
||||
"@types/jscodeshift": "0.7.1",
|
||||
"chokidar": "3.4.2",
|
||||
"cross-spawn": "7.0.3",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@blitzjs/repl",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"description": "Repl package for Blitz CLI",
|
||||
"homepage": "https://github.com/blitz-js/blitz/packages/repl/#readme",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@blitzjs/server",
|
||||
"description": "Blitz.js server functionality",
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"next-patched": "./bin/next-patched"
|
||||
@@ -29,9 +29,9 @@
|
||||
"module": "dist/server.esm.js",
|
||||
"types": "dist/packages/server/src/index.d.ts",
|
||||
"dependencies": {
|
||||
"@blitzjs/config": "0.21.2-canary.1",
|
||||
"@blitzjs/display": "0.21.2-canary.1",
|
||||
"@blitzjs/file-pipeline": "0.21.2-canary.1",
|
||||
"@blitzjs/config": "0.23.2",
|
||||
"@blitzjs/display": "0.23.2",
|
||||
"@blitzjs/file-pipeline": "0.23.2",
|
||||
"b64-lite": "1.4.0",
|
||||
"cookie": "0.4.1",
|
||||
"cross-spawn": "7.0.3",
|
||||
@@ -44,7 +44,8 @@
|
||||
"gulp-if": "3.0.0",
|
||||
"hasha": "5.2.0",
|
||||
"jsonwebtoken": "8.5.1",
|
||||
"lodash": "4.17.19",
|
||||
"lodash": "^4.17.19",
|
||||
"lodash-es": "^4.17.15",
|
||||
"merge-stream": "2.0.0",
|
||||
"nanoid": "3.1.10",
|
||||
"next": "9.5.3",
|
||||
@@ -66,7 +67,7 @@
|
||||
"vinyl-fs": "3.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blitzjs/core": "0.21.2-canary.1",
|
||||
"@blitzjs/core": "0.23.2",
|
||||
"next-transpile-modules": "3.2.0"
|
||||
},
|
||||
"gitHead": "d3b9fce0bdd251c2b1890793b0aa1cd77c1c0922"
|
||||
|
||||
@@ -16,6 +16,10 @@ export async function getInputArtefactsHash() {
|
||||
".profile.d",
|
||||
".cache",
|
||||
".config",
|
||||
"test",
|
||||
"tests",
|
||||
"spec",
|
||||
"specs",
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {move, pathExists, remove} from "fs-extra"
|
||||
import {resolve} from "path"
|
||||
import {move, remove, pathExists} from "fs-extra"
|
||||
import {ServerConfig, normalize} from "./config"
|
||||
import {nextBuild} from "./next-utils"
|
||||
import {saveBuild} from "./build-hash"
|
||||
import {normalize, ServerConfig} from "./config"
|
||||
import {nextBuild} from "./next-utils"
|
||||
import {configureStages} from "./stages"
|
||||
|
||||
export async function build(
|
||||
@@ -18,19 +18,19 @@ export async function build(
|
||||
include,
|
||||
watch,
|
||||
isTypescript,
|
||||
...stageConfig
|
||||
writeManifestFile,
|
||||
} = await normalize(config)
|
||||
|
||||
const src = rootFolder
|
||||
const stages = configureStages(stageConfig)
|
||||
const dest = buildFolder
|
||||
const options = {
|
||||
ignore,
|
||||
include,
|
||||
watch,
|
||||
isTypescript,
|
||||
}
|
||||
await Promise.all([transformFiles(src, stages, dest, options), readyForNextBuild])
|
||||
const stages = configureStages({isTypescript, writeManifestFile})
|
||||
|
||||
await Promise.all([
|
||||
transformFiles(rootFolder, stages, buildFolder, {
|
||||
ignore,
|
||||
include,
|
||||
watch,
|
||||
}),
|
||||
readyForNextBuild,
|
||||
])
|
||||
|
||||
await nextBuild(nextBin, buildFolder)
|
||||
|
||||
|
||||
@@ -1,36 +1,55 @@
|
||||
import {resolve} from "path"
|
||||
import {resolveBinAsync} from "./resolve-bin-async"
|
||||
import {transformFiles} from "@blitzjs/file-pipeline"
|
||||
import {promises} from "fs"
|
||||
import {join, resolve} from "path"
|
||||
import {parseChokidarRulesFromGitignore} from "./parse-chokidar-rules-from-gitignore"
|
||||
import {resolveBinAsync} from "./resolve-bin-async"
|
||||
|
||||
type Synchronizer = typeof transformFiles
|
||||
type ServerEnvironment = "dev" | "prod"
|
||||
|
||||
export type ServerConfig = {
|
||||
rootFolder: string
|
||||
buildFolder?: string
|
||||
devFolder?: string
|
||||
// -
|
||||
isTypescript?: boolean
|
||||
watch?: boolean
|
||||
// -
|
||||
transformFiles?: Synchronizer
|
||||
writeManifestFile?: boolean
|
||||
// -
|
||||
port?: number
|
||||
hostname?: string
|
||||
interceptNextErrors?: boolean
|
||||
devFolder?: string
|
||||
buildFolder?: string
|
||||
writeManifestFile?: boolean
|
||||
watch?: boolean
|
||||
transformFiles?: Synchronizer
|
||||
isTypescript?: boolean
|
||||
inspect?: boolean
|
||||
// –
|
||||
env?: ServerEnvironment
|
||||
}
|
||||
|
||||
type NormalizedConfig = Omit<ServerConfig, "interceptNextErrors"> & {
|
||||
ignore: string[]
|
||||
include: string[]
|
||||
nextBin: string
|
||||
devFolder: string
|
||||
type NormalizedConfig = ServerConfig & {
|
||||
buildFolder: string
|
||||
devFolder: string
|
||||
// -
|
||||
isTypescript: boolean
|
||||
watch: boolean
|
||||
// -
|
||||
transformFiles: Synchronizer
|
||||
writeManifestFile: boolean
|
||||
watch: boolean
|
||||
isTypescript: boolean
|
||||
// -
|
||||
ignore: string[]
|
||||
include: string[]
|
||||
// -
|
||||
nextBin: string
|
||||
env: ServerEnvironment
|
||||
}
|
||||
|
||||
const defaults = {
|
||||
env: "prod" as ServerEnvironment,
|
||||
// -
|
||||
buildFolder: ".blitz/caches/build",
|
||||
devFolder: ".blitz/caches/dev",
|
||||
// -
|
||||
writeManifestFile: true,
|
||||
// -
|
||||
ignoredPaths: [
|
||||
"./build/**/*",
|
||||
"./.blitz-*/**/*",
|
||||
@@ -50,29 +69,56 @@ const defaults = {
|
||||
"dist/**/*",
|
||||
"node_modules/**/*",
|
||||
"cypress/**/*",
|
||||
"test/**/*",
|
||||
"tests/**/*",
|
||||
"spec/**/*",
|
||||
"specs/**/*",
|
||||
"**/*.test.*",
|
||||
"**/*.spec.*",
|
||||
],
|
||||
includePaths: ["**/*"],
|
||||
devFolder: ".blitz/caches/dev",
|
||||
buildFolder: ".blitz/caches/build",
|
||||
nextBinPatched: "./node_modules/.bin/next-patched",
|
||||
writeManifestFile: true,
|
||||
}
|
||||
|
||||
export async function normalize(config: ServerConfig): Promise<NormalizedConfig> {
|
||||
const nextBinOrig = await resolveBinAsync("next")
|
||||
const nextBinPatched = await resolveBinAsync("@blitzjs/server", "next-patched")
|
||||
const git = parseChokidarRulesFromGitignore(resolve(process.cwd(), config.rootFolder))
|
||||
const rootFolder = resolve(process.cwd(), config.rootFolder)
|
||||
const git = parseChokidarRulesFromGitignore(rootFolder)
|
||||
|
||||
const env = config.env || defaults.env
|
||||
|
||||
return {
|
||||
...config,
|
||||
buildFolder: resolve(config.rootFolder, config.buildFolder ?? defaults.buildFolder),
|
||||
devFolder: resolve(config.rootFolder, config.devFolder ?? defaults.devFolder),
|
||||
env,
|
||||
// -
|
||||
rootFolder,
|
||||
buildFolder: resolve(rootFolder, config.buildFolder ?? defaults.buildFolder),
|
||||
devFolder: resolve(rootFolder, config.devFolder ?? defaults.devFolder),
|
||||
// -
|
||||
isTypescript: config.isTypescript ?? (await getIsTypescript(rootFolder)),
|
||||
watch: config.watch ?? env === "dev",
|
||||
// -
|
||||
transformFiles: config.transformFiles ?? transformFiles,
|
||||
writeManifestFile: config.writeManifestFile ?? defaults.writeManifestFile,
|
||||
// -
|
||||
ignore: defaults.ignoredPaths.concat(git.ignoredPaths),
|
||||
include: defaults.includePaths.concat(git.includePaths),
|
||||
nextBin: resolve(config.rootFolder, config.interceptNextErrors ? nextBinPatched : nextBinOrig),
|
||||
transformFiles: config.transformFiles ?? transformFiles,
|
||||
watch: config.watch ?? false,
|
||||
writeManifestFile: config.writeManifestFile ?? defaults.writeManifestFile,
|
||||
isTypescript: config.isTypescript ?? true,
|
||||
// -
|
||||
nextBin: await getNextBin(rootFolder, env === "dev"),
|
||||
}
|
||||
}
|
||||
|
||||
async function getNextBin(rootFolder: string, usePatched: boolean = false): Promise<string> {
|
||||
// do not await for both bin-pkg because just one is used at a time
|
||||
const nextBinPkg = usePatched ? "@blitzjs/server" : "next"
|
||||
const nextBinExec = usePatched ? "next-patched" : undefined
|
||||
const nextBin = await resolveBinAsync(nextBinPkg, nextBinExec)
|
||||
return resolve(rootFolder, nextBin)
|
||||
}
|
||||
|
||||
async function getIsTypescript(rootFolder: string): Promise<boolean> {
|
||||
try {
|
||||
await promises.access(join(rootFolder, "tsconfig.json"))
|
||||
return true
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
import {resolve} from "path"
|
||||
import {ServerConfig, normalize} from "./config"
|
||||
import {normalize, ServerConfig} from "./config"
|
||||
import {nextStartDev} from "./next-utils"
|
||||
import {configureStages} from "./stages"
|
||||
|
||||
export async function dev(
|
||||
{watch = true, ...config}: ServerConfig,
|
||||
readyForNextDev: Promise<any> = Promise.resolve(),
|
||||
) {
|
||||
export async function dev(config: ServerConfig, readyForNextDev: Promise<any> = Promise.resolve()) {
|
||||
const {
|
||||
//
|
||||
rootFolder,
|
||||
transformFiles,
|
||||
nextBin,
|
||||
@@ -16,27 +11,21 @@ export async function dev(
|
||||
ignore,
|
||||
include,
|
||||
isTypescript,
|
||||
...stagesConfig
|
||||
} = await normalize({
|
||||
...config,
|
||||
interceptNextErrors: true,
|
||||
})
|
||||
|
||||
const src = resolve(rootFolder)
|
||||
const stages = configureStages(stagesConfig)
|
||||
const dest = resolve(rootFolder, devFolder)
|
||||
const options = {
|
||||
ignore,
|
||||
include,
|
||||
writeManifestFile,
|
||||
watch,
|
||||
isTypescript,
|
||||
}
|
||||
} = await normalize({...config, env: "dev"})
|
||||
|
||||
const stages = configureStages({writeManifestFile, isTypescript})
|
||||
|
||||
const [{manifest}] = await Promise.all([
|
||||
transformFiles(src, stages, dest, options),
|
||||
transformFiles(rootFolder, stages, devFolder, {
|
||||
ignore,
|
||||
include,
|
||||
watch,
|
||||
}),
|
||||
// Ensure next does not start until parallel processing completes
|
||||
readyForNextDev,
|
||||
])
|
||||
|
||||
await nextStartDev(nextBin, dest, manifest, devFolder, config)
|
||||
await nextStartDev(nextBin, devFolder, manifest, devFolder, config)
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ function createOutputTransformer(manifest: Manifest, devFolder: string) {
|
||||
|
||||
async function createCommandAndPort(config: ServerConfig, command: string) {
|
||||
let spawnCommand: string[] = [command]
|
||||
let spawnEnv: NodeJS.ProcessEnv = process.env
|
||||
let availablePort: number
|
||||
|
||||
availablePort = await detect({port: config.port ? config.port : 3000})
|
||||
@@ -41,7 +42,11 @@ async function createCommandAndPort(config: ServerConfig, command: string) {
|
||||
spawnCommand = spawnCommand.concat(["-H", `${config.hostname}`])
|
||||
}
|
||||
|
||||
return {spawnCommand, availablePort}
|
||||
if (config.inspect) {
|
||||
spawnEnv = {...spawnEnv, NODE_OPTIONS: "--inspect"}
|
||||
}
|
||||
|
||||
return {spawnCommand, spawnEnv, availablePort}
|
||||
}
|
||||
|
||||
export async function nextStartDev(
|
||||
@@ -52,7 +57,7 @@ export async function nextStartDev(
|
||||
config: ServerConfig,
|
||||
) {
|
||||
const transform = createOutputTransformer(manifest, devFolder).stream
|
||||
const {spawnCommand, availablePort} = await createCommandAndPort(config, "dev")
|
||||
const {spawnCommand, spawnEnv, availablePort} = await createCommandAndPort(config, "dev")
|
||||
|
||||
return new Promise((res, rej) => {
|
||||
if (config.port && availablePort !== config.port) {
|
||||
@@ -61,6 +66,7 @@ export async function nextStartDev(
|
||||
} else {
|
||||
spawn(nextBin, spawnCommand, {
|
||||
cwd,
|
||||
env: spawnEnv,
|
||||
stdio: [process.stdin, transform.pipe(process.stdout), transform.pipe(process.stderr)],
|
||||
})
|
||||
.on("exit", (code: number) => {
|
||||
@@ -86,7 +92,7 @@ export function nextBuild(nextBin: string, cwd: string) {
|
||||
}
|
||||
|
||||
export async function nextStart(nextBin: string, cwd: string, config: ServerConfig) {
|
||||
const {spawnCommand, availablePort} = await createCommandAndPort(config, "start")
|
||||
const {spawnCommand, spawnEnv, availablePort} = await createCommandAndPort(config, "start")
|
||||
|
||||
return new Promise((res, rej) => {
|
||||
if (config.port && availablePort !== config.port) {
|
||||
@@ -95,10 +101,11 @@ export async function nextStart(nextBin: string, cwd: string, config: ServerConf
|
||||
} else {
|
||||
spawn(nextBin, spawnCommand, {
|
||||
cwd,
|
||||
env: spawnEnv,
|
||||
stdio: "inherit",
|
||||
})
|
||||
.on("exit", (code: number) => {
|
||||
code === 0 ? res() : rej(`'next build' failed with status code: ${code}`)
|
||||
code === 0 ? res() : rej(`'next start' failed with status code: ${code}`)
|
||||
})
|
||||
.on("error", (err) => {
|
||||
console.error(err)
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import {createStageRelative} from "./relative"
|
||||
import {createStagePages} from "./pages"
|
||||
import {createStageRpc} from "./rpc"
|
||||
import {createStageConfig} from "./config"
|
||||
import {createStageManifest} from "./manifest"
|
||||
import {createStagePages} from "./pages"
|
||||
import {createStageRelative} from "./relative"
|
||||
import {createStageRpc} from "./rpc"
|
||||
|
||||
type StagesConfig = {writeManifestFile: boolean; isTypescript: boolean}
|
||||
|
||||
// These create pipeline stages that are run as the business rules for Blitz
|
||||
// Read this folders README for more information
|
||||
export const configureStages = (config: {writeManifestFile: boolean}) => [
|
||||
export const configureStages = (config: StagesConfig) => [
|
||||
// Order is important
|
||||
createStageRelative,
|
||||
createStagePages,
|
||||
createStageRpc,
|
||||
createStageRpc(config.isTypescript),
|
||||
createStageConfig,
|
||||
createStageManifest(config.writeManifestFile),
|
||||
]
|
||||
|
||||
@@ -5,7 +5,7 @@ import {handleErrors, DuplicatePathError} from "./errors"
|
||||
import flow from "lodash/flow"
|
||||
|
||||
export function pagesPathTransformer(path: string) {
|
||||
const regex = /(?:[\\/]?app[\\/].*?[\\/]?)(pages[\\/].+(?<!test)\.(m?[tj]sx?|mdx))$/
|
||||
const regex = /(?:[\\/]?app[\\/].*?[\\/]?)(pages[\\/].+(?<!\.test)\.(m?[tj]sx?|mdx))$/
|
||||
return (regex.exec(path) || [])[1] || path
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,11 @@ describe("createPagesPathTransformer", () => {
|
||||
input: normalize("/User/foo/bar/app/users/pages/one/two/three.tsx"),
|
||||
expected: normalize("pages/one/two/three.tsx"),
|
||||
},
|
||||
{
|
||||
name: "Transforms app/pages/test.tsx",
|
||||
input: normalize("app/pages/test.tsx"),
|
||||
expected: normalize("pages/test.tsx"),
|
||||
},
|
||||
]
|
||||
|
||||
tests.forEach(({name, input, expected}) => {
|
||||
|
||||
@@ -59,51 +59,52 @@ export const config = {
|
||||
/**
|
||||
* Returns a Stage that manages generating the internal RPC commands and handlers
|
||||
*/
|
||||
export const createStageRpc: Stage = function configure({config: {src, isTypescript = true}}) {
|
||||
const fileTransformer = absolutePathTransform(src)
|
||||
export const createStageRpc = (isTypescript = true): Stage =>
|
||||
function configure({config: {src}}) {
|
||||
const fileTransformer = absolutePathTransform(src)
|
||||
|
||||
const getResolverPath = fileTransformer(resolverPath)
|
||||
const getApiHandlerPath = fileTransformer(apiHandlerPath)
|
||||
const getResolverPath = fileTransformer(resolverPath)
|
||||
const getApiHandlerPath = fileTransformer(apiHandlerPath)
|
||||
|
||||
const stream = transform.file((file, {next, push}) => {
|
||||
if (!isResolverPath(file.path)) {
|
||||
return file
|
||||
}
|
||||
const stream = transform.file((file, {next, push}) => {
|
||||
if (!isResolverPath(file.path)) {
|
||||
return file
|
||||
}
|
||||
|
||||
const originalPath = resolutionPath(src, file.path)
|
||||
const resolverImportPath = resolverPath(originalPath)
|
||||
const {resolverType, resolverName} = extractTemplateVars(resolverImportPath)
|
||||
const originalPath = resolutionPath(src, file.path)
|
||||
const resolverImportPath = resolverPath(originalPath)
|
||||
const {resolverType, resolverName} = extractTemplateVars(resolverImportPath)
|
||||
|
||||
// Original function -> _resolvers path
|
||||
push(
|
||||
new File({
|
||||
path: getResolverPath(file.path),
|
||||
contents: file.contents,
|
||||
hash: file.hash + ":1",
|
||||
}),
|
||||
)
|
||||
// Original function -> _resolvers path
|
||||
push(
|
||||
new File({
|
||||
path: getResolverPath(file.path),
|
||||
contents: file.contents,
|
||||
hash: file.hash + ":1",
|
||||
}),
|
||||
)
|
||||
|
||||
// File API route handler
|
||||
push(
|
||||
new File({
|
||||
path: getApiHandlerPath(file.path),
|
||||
contents: Buffer.from(apiHandlerTemplate(originalPath, isTypescript)),
|
||||
hash: file.hash + ":2",
|
||||
}),
|
||||
)
|
||||
// File API route handler
|
||||
push(
|
||||
new File({
|
||||
path: getApiHandlerPath(file.path),
|
||||
contents: Buffer.from(apiHandlerTemplate(originalPath, isTypescript)),
|
||||
hash: file.hash + ":2",
|
||||
}),
|
||||
)
|
||||
|
||||
// Isomorphic client
|
||||
const isomorphicHandlerFile = file.clone()
|
||||
isomorphicHandlerFile.contents = Buffer.from(
|
||||
isomorhicHandlerTemplate(resolverImportPath, resolverName, resolverType, isTypescript),
|
||||
)
|
||||
push(isomorphicHandlerFile)
|
||||
// Isomorphic client
|
||||
const isomorphicHandlerFile = file.clone()
|
||||
isomorphicHandlerFile.contents = Buffer.from(
|
||||
isomorhicHandlerTemplate(resolverImportPath, resolverName, resolverType, isTypescript),
|
||||
)
|
||||
push(isomorphicHandlerFile)
|
||||
|
||||
return next()
|
||||
})
|
||||
return next()
|
||||
})
|
||||
|
||||
return {stream}
|
||||
}
|
||||
return {stream}
|
||||
}
|
||||
|
||||
function removeExt(filePath: string) {
|
||||
return filePath.replace(/[.][^./\s]+$/, "")
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {StageConfig, StageArgs} from "@blitzjs/file-pipeline/dist/packages/file-pipeline/src/types"
|
||||
import {FileCache} from "@blitzjs/file-pipeline"
|
||||
|
||||
import {through, pipeline} from "../streams"
|
||||
import {StageArgs, StageConfig} from "@blitzjs/file-pipeline/dist/packages/file-pipeline/src/types"
|
||||
import {pipeline, through} from "../streams"
|
||||
|
||||
export function mockStageArgs(a: {entries?: string[]; cwd?: string}): StageArgs {
|
||||
const config: StageConfig = {
|
||||
@@ -11,7 +10,6 @@ export function mockStageArgs(a: {entries?: string[]; cwd?: string}): StageArgs
|
||||
include: [],
|
||||
src: "",
|
||||
watch: false,
|
||||
isTypescript: true,
|
||||
}
|
||||
return {
|
||||
getInputCache() {
|
||||
|
||||
@@ -310,11 +310,11 @@ export const getSessionSecretKey = () => {
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
assert(
|
||||
process.env.SESSION_SECRET_KEY,
|
||||
"You must provide the SESSION_SECRET_KEY environment variable in production. This used to sign and verify JWTs.",
|
||||
"You must provide the SESSION_SECRET_KEY environment variable in production. This used to sign and verify tokens. It should be 32 chars long.",
|
||||
)
|
||||
assert(
|
||||
process.env.SESSION_SECRET_KEY.length >= 32,
|
||||
"The SESSION_SECRET_KEY environment variable must be at least 32 bytes for sufficent JWT security",
|
||||
"The SESSION_SECRET_KEY environment variable must be at least 32 bytes for sufficent token security",
|
||||
)
|
||||
|
||||
return process.env.SESSION_SECRET_KEY
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/node_modules/release/bin/release.js b/node_modules/release/bin/release.js
|
||||
index a5ab985..ce9475a 100755
|
||||
index a5ab985..e324528 100755
|
||||
--- a/node_modules/release/bin/release.js
|
||||
+++ b/node_modules/release/bin/release.js
|
||||
@@ -52,25 +52,37 @@ let githubConnection;
|
||||
@@ -52,25 +52,49 @@ let githubConnection;
|
||||
let repoDetails;
|
||||
|
||||
const changeTypes = [
|
||||
@@ -44,6 +44,18 @@ index a5ab985..ce9475a 100755
|
||||
+ description: 'backwards-compatible bug fix',
|
||||
+ },
|
||||
+ {
|
||||
+ handle: 'newapp',
|
||||
+ name: 'New App Template',
|
||||
+ pluralName: '⚡️ Changes to the New App Template',
|
||||
+ description: 'change to new app template',
|
||||
+ },
|
||||
+ {
|
||||
+ handle: 'recipe',
|
||||
+ name: 'Recipe',
|
||||
+ pluralName: '👩🍳 Recipes',
|
||||
+ description: 'change to a recipe',
|
||||
+ },
|
||||
+ {
|
||||
+ handle: 'example',
|
||||
+ name: 'Example App',
|
||||
+ pluralName: '👀 Changes to Example Apps',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@blitzjs/recipe-chakra",
|
||||
"private": true,
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"description": "The Blitz Recipe for installing Chakra UI",
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"@blitzjs/installer": "0.21.2-canary.1",
|
||||
"@blitzjs/installer": "0.23.2",
|
||||
"jscodeshift": "0.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@blitzjs/recipe-emotion",
|
||||
"private": true,
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"description": "The Blitz Recipe for installing Emotion",
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"@blitzjs/installer": "0.21.2-canary.1",
|
||||
"@blitzjs/installer": "0.23.2",
|
||||
"jscodeshift": "0.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@blitzjs/recipe-material-ui",
|
||||
"private": true,
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"description": "The Blitz Recipe for installing Material-UI",
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"@blitzjs/installer": "0.21.2-canary.1",
|
||||
"@blitzjs/installer": "0.23.2",
|
||||
"jscodeshift": "0.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@blitzjs/recipe-render",
|
||||
"private": true,
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"description": "The Blitz Recipe for adding render.yaml",
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
@@ -22,6 +22,6 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"@blitzjs/installer": "0.21.2-canary.1"
|
||||
"@blitzjs/installer": "0.23.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,12 @@ services:
|
||||
name: blitzapp
|
||||
env: node
|
||||
plan: starter
|
||||
buildCommand: yarn; blitz db migrate; blitz build
|
||||
startCommand: blitz start --production -H 0.0.0.0
|
||||
buildCommand: yarn --frozen-lockfile --prod=false; blitz db migrate; blitz build
|
||||
# If you have an out of memory error, change startCommand to "yarn next start"
|
||||
startCommand: blitz start --production
|
||||
envVars:
|
||||
# ⚠️ You must set SESSION_SECRET_KEY env var through the UI.
|
||||
# Add this env name, then a "generate" button will appear in the value box
|
||||
- key: NODE_ENV
|
||||
value: production
|
||||
- key: DATABASE_URL
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@blitzjs/recipe-tailwind",
|
||||
"private": true,
|
||||
"version": "0.21.2-canary.1",
|
||||
"version": "0.23.2",
|
||||
"description": "The Blitz Recipe for installing Tailwind CSS",
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"@blitzjs/installer": "0.21.2-canary.1",
|
||||
"@blitzjs/installer": "0.23.2",
|
||||
"jscodeshift": "0.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
module.exports = {
|
||||
future: "all",
|
||||
purge: ["{app,pages}/**/*.{js,jsx,ts,tsx}"],
|
||||
theme: {},
|
||||
variants: {},
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"moduleResolution": "node",
|
||||
"jsx": "react",
|
||||
"esModuleInterop": true
|
||||
"esModuleInterop": true,
|
||||
"noEmit": true
|
||||
}
|
||||
}
|
||||
|
||||
61
yarn.lock
61
yarn.lock
@@ -3649,6 +3649,14 @@
|
||||
estree-walker "^2.0.1"
|
||||
picomatch "^2.2.2"
|
||||
|
||||
"@salesforce/lazy-require@0.3.2":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@salesforce/lazy-require/-/lazy-require-0.3.2.tgz#0d3b5a697e639a4b2357c9b18d6dd883a620c57c"
|
||||
integrity sha512-T1M9mcf9CYBihe4kYwnOuuGS32Eg4mjqZbto5gXJi1qQxmG/zdrQ6pv5zHD8nfbZb1d1hQzTW0y+cCvwcWV6qw==
|
||||
dependencies:
|
||||
debug "^3.2.6"
|
||||
tslib "^1.10.0"
|
||||
|
||||
"@samverschueren/stream-to-observable@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f"
|
||||
@@ -4191,6 +4199,14 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
|
||||
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
|
||||
|
||||
"@types/passport-auth0@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/passport-auth0/-/passport-auth0-1.0.4.tgz#f92c357a3a2a6fa5f10744555a45c5e9a6e36469"
|
||||
integrity sha512-Qq1YRz1kuhFMHn43btY/RZ3pxV84ogOwhDfPWVcgGqgHYRWf5rTtV3tvcwPRFFh3Z72JkJhQ/9bbxnTFoV2ytg==
|
||||
dependencies:
|
||||
"@types/express" "*"
|
||||
"@types/passport" "*"
|
||||
|
||||
"@types/passport-github2@1.2.4":
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/passport-github2/-/passport-github2-1.2.4.tgz#f56c386d1fe6435e359430e57adc1747a627bd86"
|
||||
@@ -8457,6 +8473,18 @@ eslint-plugin-cypress@2.11.1:
|
||||
dependencies:
|
||||
globals "^11.12.0"
|
||||
|
||||
eslint-plugin-es5@1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-es5/-/eslint-plugin-es5-1.5.0.tgz#aab19af3d4798f7924bba309bc4f87087280fbba"
|
||||
integrity sha512-Qxmfo7v2B7SGAEURJo0dpBweFf+JU15kSyALfiB2rXWcBuJ96r6X9kFHXFnhdopPHCaHjoQs1xQPUJVbGMb1AA==
|
||||
|
||||
eslint-plugin-es@mysticatea/eslint-plugin-es:
|
||||
version "3.0.1"
|
||||
resolved "https://codeload.github.com/mysticatea/eslint-plugin-es/tar.gz/5a90374a2e19fb7247e3140b277a42ec693276c1"
|
||||
dependencies:
|
||||
eslint-utils "^2.0.0"
|
||||
regexpp "^3.0.0"
|
||||
|
||||
eslint-plugin-flowtype@5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.2.0.tgz#a4bef5dc18f9b2bdb41569a4ab05d73805a3d261"
|
||||
@@ -12581,6 +12609,11 @@ locate-path@^5.0.0:
|
||||
dependencies:
|
||||
p-locate "^4.1.0"
|
||||
|
||||
lodash-es@^4.17.15:
|
||||
version "4.17.15"
|
||||
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78"
|
||||
integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==
|
||||
|
||||
lodash._reinterpolate@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
|
||||
@@ -13672,6 +13705,11 @@ node-fetch@2.6.0, node-fetch@^2.1.1, node-fetch@^2.2.0, node-fetch@^2.3.0, node-
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd"
|
||||
integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==
|
||||
|
||||
node-fetch@2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||
|
||||
node-gyp-build@^4.2.0:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.2.2.tgz#3f44b65adaafd42fb6c3d81afd630e45c847eb66"
|
||||
@@ -14642,6 +14680,15 @@ pascalcase@^0.1.1:
|
||||
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
|
||||
integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
|
||||
|
||||
passport-auth0@1.3.3:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/passport-auth0/-/passport-auth0-1.3.3.tgz#d377f9aea2f6e89af0318a6364a847e80966bb88"
|
||||
integrity sha512-rcjT0fV6HnJuSb8REwREl42/K5LpGK+doekDgEQbtT/pNwLAjfobSMiQ3RbTP1CkiEcDVRucGucuDSfgqHX/Vg==
|
||||
dependencies:
|
||||
passport-oauth "^1.0.0"
|
||||
passport-oauth2 "^1.5.0"
|
||||
request "^2.88.0"
|
||||
|
||||
passport-github2@0.1.11:
|
||||
version "0.1.11"
|
||||
resolved "https://registry.yarnpkg.com/passport-github2/-/passport-github2-0.1.11.tgz#c92b56f3c38a44e766aac7e9e7c1384c5e93c999"
|
||||
@@ -14658,7 +14705,7 @@ passport-oauth1@1.x.x:
|
||||
passport-strategy "1.x.x"
|
||||
utils-merge "1.x.x"
|
||||
|
||||
passport-oauth2@1.x.x:
|
||||
passport-oauth2@1.x.x, passport-oauth2@^1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.5.0.tgz#64babbb54ac46a4dcab35e7f266ed5294e3c4108"
|
||||
integrity sha512-kqBt6vR/5VlCK8iCx1/KpY42kQ+NEHZwsSyt4Y6STiNjU+wWICG1i8ucc1FapXDGO15C5O5VZz7+7vRzrDPXXQ==
|
||||
@@ -14669,6 +14716,14 @@ passport-oauth2@1.x.x:
|
||||
uid2 "0.0.x"
|
||||
utils-merge "1.x.x"
|
||||
|
||||
passport-oauth@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/passport-oauth/-/passport-oauth-1.0.0.tgz#90aff63387540f02089af28cdad39ea7f80d77df"
|
||||
integrity sha1-kK/2M4dUDwIImvKM2tOep/gNd98=
|
||||
dependencies:
|
||||
passport-oauth1 "1.x.x"
|
||||
passport-oauth2 "1.x.x"
|
||||
|
||||
passport-strategy@1.x.x:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
|
||||
@@ -18482,7 +18537,7 @@ tslib@1.11.1:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35"
|
||||
integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==
|
||||
|
||||
tslib@^1, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
|
||||
tslib@^1, tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
|
||||
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
|
||||
@@ -18950,7 +19005,7 @@ uuid@^7.0.2, uuid@^7.0.3:
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b"
|
||||
integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==
|
||||
|
||||
v8-compile-cache@^2.0.3:
|
||||
v8-compile-cache@2.1.1, v8-compile-cache@^2.0.3:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"
|
||||
integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==
|
||||
|
||||
Reference in New Issue
Block a user