Compare commits
58 Commits
@blitzjs/a
...
@blitzjs/c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57add5f1c5 | ||
|
|
3f239e78b6 | ||
|
|
3bf90c167c | ||
|
|
56bd32b553 | ||
|
|
2711291e97 | ||
|
|
ab29c5bf3f | ||
|
|
a096f2cd80 | ||
|
|
ded16b325b | ||
|
|
4494662d6d | ||
|
|
9a0ba87d15 | ||
|
|
c80ce51d36 | ||
|
|
b505933a16 | ||
|
|
d53da39cbf | ||
|
|
e1055f7366 | ||
|
|
3b10b13e6b | ||
|
|
25601754a4 | ||
|
|
e0cfa328ec | ||
|
|
f02469aac8 | ||
|
|
2f3c552ac3 | ||
|
|
721461a7b9 | ||
|
|
3193bdea48 | ||
|
|
318e9740d6 | ||
|
|
0df368308b | ||
|
|
ad94bee56a | ||
|
|
5a14306f7b | ||
|
|
6e8eeb1514 | ||
|
|
5e61a16815 | ||
|
|
77555468f3 | ||
|
|
22e402af01 | ||
|
|
19afc57530 | ||
|
|
b7dab1d800 | ||
|
|
ee7bf87ec0 | ||
|
|
451ead089c | ||
|
|
5d9570f7f4 | ||
|
|
178c152b2c | ||
|
|
bbe1a54d7a | ||
|
|
9b075dbb47 | ||
|
|
60a4d90c86 | ||
|
|
a674897601 | ||
|
|
5a587a6c31 | ||
|
|
744242f25b | ||
|
|
0f5297f1aa | ||
|
|
76a2544f9d | ||
|
|
6f44c2334e | ||
|
|
8a417533f6 | ||
|
|
6f54841b7a | ||
|
|
e8f564ea66 | ||
|
|
71b9950037 | ||
|
|
28a79040e4 | ||
|
|
dd604c7675 | ||
|
|
0a8d4bfdaf | ||
|
|
f25aac08c0 | ||
|
|
a09685a63a | ||
|
|
595f400e9a | ||
|
|
6f333ee643 | ||
|
|
956a739e83 | ||
|
|
47722e0456 | ||
|
|
2f5c8a3a0d |
@@ -4014,6 +4014,96 @@
|
|||||||
"doc",
|
"doc",
|
||||||
"code"
|
"code"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "LeonMueller-OneAndOnly",
|
||||||
|
"name": "Leonidas",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/77194479?v=4",
|
||||||
|
"profile": "https://flow-office.eu/",
|
||||||
|
"contributions": [
|
||||||
|
"doc",
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "Doc0x1",
|
||||||
|
"name": "Doc0x1",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/19937034?v=4",
|
||||||
|
"profile": "https://hacknex.us",
|
||||||
|
"contributions": [
|
||||||
|
"doc",
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "lmisea",
|
||||||
|
"name": "Luis Isea",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/106825636?v=4",
|
||||||
|
"profile": "https://github.com/lmisea",
|
||||||
|
"contributions": [
|
||||||
|
"doc",
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "gengjiawen",
|
||||||
|
"name": "Jiawen Geng",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/3759816?v=4",
|
||||||
|
"profile": "https://www.gengjiawen.com",
|
||||||
|
"contributions": [
|
||||||
|
"doc",
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "timneutkens",
|
||||||
|
"name": "Tim Neutkens",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/6324199?v=4",
|
||||||
|
"profile": "https://timn.tech",
|
||||||
|
"contributions": [
|
||||||
|
"doc",
|
||||||
|
"code",
|
||||||
|
"test"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "RedYetiDev",
|
||||||
|
"name": "Aviv Keller",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/38299977?v=4",
|
||||||
|
"profile": "https://redyetidev.github.io",
|
||||||
|
"contributions": [
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "bezalel6",
|
||||||
|
"name": "bezalel6",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/51681171?v=4",
|
||||||
|
"profile": "https://github.com/bezalel6",
|
||||||
|
"contributions": [
|
||||||
|
"doc",
|
||||||
|
"code"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "cherniavskii",
|
||||||
|
"name": "Andrew Cherniavskii",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/13808724?v=4",
|
||||||
|
"profile": "cherniavskii.com",
|
||||||
|
"contributions": [
|
||||||
|
"doc"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"login": "doe-base",
|
||||||
|
"name": "Daniel Idoko",
|
||||||
|
"avatar_url": "https://avatars.githubusercontent.com/u/95912955?v=4",
|
||||||
|
"profile": "https://danielidoko-r3zt.vercel.app/",
|
||||||
|
"contributions": [
|
||||||
|
"doc",
|
||||||
|
"code",
|
||||||
|
"test"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"contributorsPerLine": 7,
|
"contributorsPerLine": 7,
|
||||||
|
|||||||
24
.github/workflows/main.yml
vendored
24
.github/workflows/main.yml
vendored
@@ -17,13 +17,13 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: pnpm/action-setup@v2.2.4
|
- uses: pnpm/action-setup@v4.0.0
|
||||||
with:
|
with:
|
||||||
version: 8.6.5
|
version: 8.6.6
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 20
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: pnpm install --frozen-lockfile
|
run: pnpm install --frozen-lockfile
|
||||||
@@ -38,13 +38,13 @@ jobs:
|
|||||||
name: Build
|
name: Build
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: pnpm/action-setup@v2.2.4
|
- uses: pnpm/action-setup@v4.0.0
|
||||||
with:
|
with:
|
||||||
version: 8.6.5
|
version: 8.6.6
|
||||||
- name: Setup node
|
- name: Setup node
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 20
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
- run: pnpm install --frozen-lockfile
|
- run: pnpm install --frozen-lockfile
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -68,14 +68,14 @@ jobs:
|
|||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Setup PNPM
|
- name: Setup PNPM
|
||||||
uses: pnpm/action-setup@v2.2.4
|
uses: pnpm/action-setup@v4.0.0
|
||||||
with:
|
with:
|
||||||
version: 8.6.5
|
version: 8.6.6
|
||||||
|
|
||||||
- name: Setup node@16
|
- name: Setup node@16
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 20
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
@@ -129,15 +129,15 @@ jobs:
|
|||||||
|
|
||||||
- name: Setup PNPM
|
- name: Setup PNPM
|
||||||
if: matrix.folder != 'next-13-app-dir' || matrix.os != 'windows-latest'
|
if: matrix.folder != 'next-13-app-dir' || matrix.os != 'windows-latest'
|
||||||
uses: pnpm/action-setup@v2.2.4
|
uses: pnpm/action-setup@v4.0.0
|
||||||
with:
|
with:
|
||||||
version: 8.6.5
|
version: 8.6.6
|
||||||
|
|
||||||
- name: Setup node@18
|
- name: Setup node@18
|
||||||
if: matrix.folder != 'next-13-app-dir' || matrix.os != 'windows-latest'
|
if: matrix.folder != 'next-13-app-dir' || matrix.os != 'windows-latest'
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 20
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
|||||||
26
.github/workflows/pr-release.yml
vendored
26
.github/workflows/pr-release.yml
vendored
@@ -22,23 +22,29 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: resolve pr refs
|
- name: Fetch PR information
|
||||||
id: refs
|
id: pr_info
|
||||||
uses: eficode/resolve-pr-refs@main
|
env:
|
||||||
with:
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
run: |
|
||||||
|
pr="$(gh api repos/${{ github.repository }}/pulls/${{ github.event.issue.number }})"
|
||||||
|
head_sha="$(echo "$pr" | jq -r .head.sha)"
|
||||||
|
|
||||||
|
echo "head_sha=$head_sha" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: ${{ steps.refs.outputs.head_ref }}
|
ref: ${{ steps.pr_info.outputs.head_sha }}
|
||||||
|
|
||||||
- name: Setup PNPM
|
- name: Setup PNPM
|
||||||
uses: pnpm/action-setup@v2.2.1
|
uses: pnpm/action-setup@646cdf48217256a3d0b80361c5a50727664284f2
|
||||||
|
with:
|
||||||
|
version: 8.9.0
|
||||||
|
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 20
|
||||||
registry-url: "https://registry.npmjs.org"
|
registry-url: "https://registry.npmjs.org"
|
||||||
cache: "pnpm"
|
cache: "pnpm"
|
||||||
|
|
||||||
|
|||||||
21
.github/workflows/release.yml
vendored
21
.github/workflows/release.yml
vendored
@@ -19,12 +19,12 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Repo
|
- name: Checkout Repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Setup Node.js 16.x
|
- name: Setup Node.js 20.x
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 16.x
|
node-version: 20.x
|
||||||
|
|
||||||
- name: Creating .npmrc
|
- name: Creating .npmrc
|
||||||
run: |
|
run: |
|
||||||
@@ -37,8 +37,10 @@ jobs:
|
|||||||
- name: Pre-publish
|
- name: Pre-publish
|
||||||
uses: pnpm/action-setup@646cdf48217256a3d0b80361c5a50727664284f2
|
uses: pnpm/action-setup@646cdf48217256a3d0b80361c5a50727664284f2
|
||||||
with:
|
with:
|
||||||
version: 6.32.6
|
version: 8.9.0
|
||||||
- run: pnpm install --no-frozen-lockfile
|
- run: pnpm install
|
||||||
|
env:
|
||||||
|
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
||||||
- run: pnpm build
|
- run: pnpm build
|
||||||
|
|
||||||
- name: Create Release Pull Request
|
- name: Create Release Pull Request
|
||||||
@@ -49,10 +51,3 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
|
||||||
# - name: Github Release
|
|
||||||
# uses: release-drafter/release-drafter@v5.19.0
|
|
||||||
# with:
|
|
||||||
# config-name: release-drafter.yml
|
|
||||||
# env:
|
|
||||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
16.13.2
|
|
||||||
16
README.md
16
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==">
|
<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>
|
</a>
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
<!-- 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-423-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-432-17BB8A.svg?style=for-the-badge&labelColor=000000"></a>
|
||||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||||
<a aria-label="License" href="https://github.com/blitz-js/blitz/blob/main/LICENSE">
|
<a aria-label="License" href="https://github.com/blitz-js/blitz/blob/main/LICENSE">
|
||||||
<img alt="" src="https://img.shields.io/npm/l/blitz.svg?style=for-the-badge&labelColor=000000&color=blue">
|
<img alt="" src="https://img.shields.io/npm/l/blitz.svg?style=for-the-badge&labelColor=000000&color=blue">
|
||||||
@@ -79,6 +79,9 @@ Your financial contributions help ensure Blitz continues to be developed and mai
|
|||||||
</a></td>
|
</a></td>
|
||||||
<td><a aria-label="Simon Lammes" href="https://github.com/simon-lammes">
|
<td><a aria-label="Simon Lammes" href="https://github.com/simon-lammes">
|
||||||
<img alt="" src="https://avatars.githubusercontent.com/u/46446421?v=4" width="40px"/>
|
<img alt="" src="https://avatars.githubusercontent.com/u/46446421?v=4" width="40px"/>
|
||||||
|
</a></td>
|
||||||
|
<td><a aria-label="Route Optimizer and Route Planning Software" href="https://route4me.com">
|
||||||
|
<img alt="" src="https://raw.githubusercontent.com/blitz-js/blitz/main/assets/route4me.png" width="40px"/>
|
||||||
</a></td>
|
</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@@ -747,6 +750,17 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
|
|||||||
<td align="center"><a href="https://github.com/Zamfi99"><img src="https://avatars.githubusercontent.com/u/19189337?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zamfira Costin-Andrei</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Zamfi99" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=Zamfi99" title="Code">💻</a></td>
|
<td align="center"><a href="https://github.com/Zamfi99"><img src="https://avatars.githubusercontent.com/u/19189337?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Zamfira Costin-Andrei</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Zamfi99" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=Zamfi99" title="Code">💻</a></td>
|
||||||
<td align="center"><a href="https://github.com/potikhanovsergey"><img src="https://avatars.githubusercontent.com/u/71494201?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sergey</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=potikhanovsergey" title="Documentation">📖</a></td>
|
<td align="center"><a href="https://github.com/potikhanovsergey"><img src="https://avatars.githubusercontent.com/u/71494201?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sergey</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=potikhanovsergey" title="Documentation">📖</a></td>
|
||||||
<td align="center"><a href="https://github.com/papsavas"><img src="https://avatars.githubusercontent.com/u/50584606?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Savvas Papageorgiadis</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=papsavas" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=papsavas" title="Code">💻</a></td>
|
<td align="center"><a href="https://github.com/papsavas"><img src="https://avatars.githubusercontent.com/u/50584606?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Savvas Papageorgiadis</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=papsavas" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=papsavas" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://flow-office.eu/"><img src="https://avatars.githubusercontent.com/u/77194479?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Leonidas</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=LeonMueller-OneAndOnly" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=LeonMueller-OneAndOnly" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://hacknex.us"><img src="https://avatars.githubusercontent.com/u/19937034?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Doc0x1</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=Doc0x1" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=Doc0x1" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/lmisea"><img src="https://avatars.githubusercontent.com/u/106825636?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Luis Isea</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=lmisea" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=lmisea" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://www.gengjiawen.com"><img src="https://avatars.githubusercontent.com/u/3759816?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jiawen Geng</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=gengjiawen" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=gengjiawen" title="Code">💻</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="center"><a href="https://timn.tech"><img src="https://avatars.githubusercontent.com/u/6324199?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tim Neutkens</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=timneutkens" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=timneutkens" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=timneutkens" title="Tests">⚠️</a></td>
|
||||||
|
<td align="center"><a href="https://redyetidev.github.io"><img src="https://avatars.githubusercontent.com/u/38299977?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aviv Keller</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=RedYetiDev" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="https://github.com/bezalel6"><img src="https://avatars.githubusercontent.com/u/51681171?v=4?s=100" width="100px;" alt=""/><br /><sub><b>bezalel6</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=bezalel6" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=bezalel6" title="Code">💻</a></td>
|
||||||
|
<td align="center"><a href="cherniavskii.com"><img src="https://avatars.githubusercontent.com/u/13808724?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Andrew Cherniavskii</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=cherniavskii" title="Documentation">📖</a></td>
|
||||||
|
<td align="center"><a href="https://danielidoko-r3zt.vercel.app/"><img src="https://avatars.githubusercontent.com/u/95912955?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Idoko</b></sub></a><br /><a href="https://github.com/blitz-js/blitz/commits?author=doe-base" title="Documentation">📖</a> <a href="https://github.com/blitz-js/blitz/commits?author=doe-base" title="Code">💻</a> <a href="https://github.com/blitz-js/blitz/commits?author=doe-base" title="Tests">⚠️</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,131 @@
|
|||||||
# next-blitz-auth
|
# next-blitz-auth
|
||||||
|
|
||||||
|
## 0.1.14
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- blitz@2.1.2
|
||||||
|
- @blitzjs/auth@2.1.2
|
||||||
|
- @blitzjs/next@2.1.2
|
||||||
|
- @blitzjs/rpc@2.1.2
|
||||||
|
- @blitzjs/config@2.1.2
|
||||||
|
|
||||||
|
## 0.1.13
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [9a0ba87d1]
|
||||||
|
- @blitzjs/rpc@2.1.1
|
||||||
|
- blitz@2.1.1
|
||||||
|
- @blitzjs/next@2.1.1
|
||||||
|
- @blitzjs/auth@2.1.1
|
||||||
|
- @blitzjs/config@2.1.1
|
||||||
|
|
||||||
|
## 0.1.12
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [d53da39cb]
|
||||||
|
- Updated dependencies [3b10b13e6]
|
||||||
|
- blitz@2.1.0
|
||||||
|
- @blitzjs/auth@2.1.0
|
||||||
|
- @blitzjs/next@2.1.0
|
||||||
|
- @blitzjs/rpc@2.1.0
|
||||||
|
- @blitzjs/config@2.1.0
|
||||||
|
|
||||||
|
## 0.1.11
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [318e9740d]
|
||||||
|
- @blitzjs/auth@2.0.10
|
||||||
|
- blitz@2.0.10
|
||||||
|
- @blitzjs/rpc@2.0.10
|
||||||
|
- @blitzjs/next@2.0.10
|
||||||
|
- @blitzjs/config@2.0.10
|
||||||
|
|
||||||
|
## 0.1.10
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [5a14306f7]
|
||||||
|
- @blitzjs/next@2.0.9
|
||||||
|
- @blitzjs/rpc@2.0.9
|
||||||
|
- blitz@2.0.9
|
||||||
|
- @blitzjs/auth@2.0.9
|
||||||
|
- @blitzjs/config@2.0.9
|
||||||
|
|
||||||
|
## 0.1.9
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [5e61a1681]
|
||||||
|
- Updated dependencies [77555468f]
|
||||||
|
- @blitzjs/next@2.0.8
|
||||||
|
- blitz@2.0.8
|
||||||
|
- @blitzjs/auth@2.0.8
|
||||||
|
- @blitzjs/rpc@2.0.8
|
||||||
|
- @blitzjs/config@2.0.8
|
||||||
|
|
||||||
|
## 0.1.8
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [ee7bf87ec]
|
||||||
|
- Updated dependencies [178c152b2]
|
||||||
|
- blitz@2.0.7
|
||||||
|
- @blitzjs/next@2.0.7
|
||||||
|
- @blitzjs/rpc@2.0.7
|
||||||
|
- @blitzjs/auth@2.0.7
|
||||||
|
- @blitzjs/config@2.0.7
|
||||||
|
|
||||||
|
## 0.1.7
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [76a2544f9]
|
||||||
|
- Updated dependencies [5a587a6c3]
|
||||||
|
- blitz@2.0.6
|
||||||
|
- @blitzjs/auth@2.0.6
|
||||||
|
- @blitzjs/next@2.0.6
|
||||||
|
- @blitzjs/rpc@2.0.6
|
||||||
|
- @blitzjs/config@2.0.6
|
||||||
|
|
||||||
|
## 0.1.6
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [6f54841b7]
|
||||||
|
- Updated dependencies [8a417533f]
|
||||||
|
- @blitzjs/auth@2.0.5
|
||||||
|
- blitz@2.0.5
|
||||||
|
- @blitzjs/rpc@2.0.5
|
||||||
|
- @blitzjs/next@2.0.5
|
||||||
|
- @blitzjs/config@2.0.5
|
||||||
|
|
||||||
|
## 0.1.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [dd604c767]
|
||||||
|
- Updated dependencies [28a79040e]
|
||||||
|
- @blitzjs/auth@2.0.4
|
||||||
|
- blitz@2.0.4
|
||||||
|
- @blitzjs/next@2.0.4
|
||||||
|
- @blitzjs/rpc@2.0.4
|
||||||
|
- @blitzjs/config@2.0.4
|
||||||
|
|
||||||
|
## 0.1.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [2f5c8a3a0]
|
||||||
|
- @blitzjs/next@2.0.3
|
||||||
|
- @blitzjs/rpc@2.0.3
|
||||||
|
- blitz@2.0.3
|
||||||
|
- @blitzjs/auth@2.0.3
|
||||||
|
- @blitzjs/config@2.0.3
|
||||||
|
|
||||||
## 0.1.3
|
## 0.1.3
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
const {withBlitz} = require("@blitzjs/next")
|
const {withBlitz} = require("@blitzjs/next")
|
||||||
|
|
||||||
|
const loaderClient = require.resolve("@blitzjs/rpc/dist/loader-client.cjs")
|
||||||
|
const loaderServer = require.resolve("@blitzjs/rpc/dist/loader-server.cjs")
|
||||||
|
const loaderServerResolvers = require.resolve("@blitzjs/rpc/dist/loader-server-resolvers.cjs")
|
||||||
|
|
||||||
|
console.log("loaderClient", loaderClient)
|
||||||
|
console.log("loaderServer", loaderServer)
|
||||||
|
console.log("loaderServerResolvers", loaderServerResolvers)
|
||||||
|
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {}
|
const nextConfig = {}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "next-blitz-auth",
|
"name": "next-blitz-auth",
|
||||||
"version": "0.1.3",
|
"version": "0.1.14",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"blitz:dev": "next dev",
|
"blitz:dev": "next dev",
|
||||||
@@ -12,17 +12,17 @@
|
|||||||
"schema": "prisma/schema.prisma"
|
"schema": "prisma/schema.prisma"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/auth": "2.0.2",
|
"@blitzjs/auth": "2.1.2",
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@blitzjs/next": "2.0.2",
|
"@blitzjs/next": "2.1.2",
|
||||||
"@blitzjs/rpc": "2.0.2",
|
"@blitzjs/rpc": "2.1.2",
|
||||||
"@hookform/error-message": "2.0.0",
|
"@hookform/error-message": "2.0.0",
|
||||||
"@hookform/resolvers": "2.9.10",
|
"@hookform/resolvers": "2.9.10",
|
||||||
"@prisma/client": "^4.5.0",
|
"@prisma/client": "^4.5.0",
|
||||||
"@tanstack/react-query": "4.0.10",
|
"@tanstack/react-query": "4.0.10",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"flatted": "3.2.7",
|
"flatted": "3.2.7",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"prisma": "^4.5.0",
|
"prisma": "^4.5.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
|
|||||||
Binary file not shown.
4
apps/next13/src/app/api/rpc/[[...blitz]]/route.ts
Normal file
4
apps/next13/src/app/api/rpc/[[...blitz]]/route.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import {rpcAppHandler} from "@blitzjs/rpc"
|
||||||
|
import {withBlitzAuth} from "src/blitz-server"
|
||||||
|
|
||||||
|
export const {GET, POST, HEAD} = withBlitzAuth(rpcAppHandler())
|
||||||
@@ -6,26 +6,27 @@ import {simpleRolesIsAuthorized} from "@blitzjs/auth"
|
|||||||
import {BlitzLogger} from "blitz"
|
import {BlitzLogger} from "blitz"
|
||||||
import {RpcServerPlugin} from "@blitzjs/rpc"
|
import {RpcServerPlugin} from "@blitzjs/rpc"
|
||||||
|
|
||||||
const {api, getBlitzContext, useAuthenticatedBlitzContext, invoke} = setupBlitzServer({
|
const {api, getBlitzContext, useAuthenticatedBlitzContext, invoke, withBlitzAuth} =
|
||||||
plugins: [
|
setupBlitzServer({
|
||||||
AuthServerPlugin({
|
plugins: [
|
||||||
cookiePrefix: "web-cookie-prefix",
|
AuthServerPlugin({
|
||||||
storage: PrismaStorage(db),
|
cookiePrefix: "web-cookie-prefix",
|
||||||
isAuthorized: simpleRolesIsAuthorized,
|
storage: PrismaStorage(db),
|
||||||
}),
|
isAuthorized: simpleRolesIsAuthorized,
|
||||||
RpcServerPlugin({
|
}),
|
||||||
logging: {
|
RpcServerPlugin({
|
||||||
disablelevel: "debug",
|
logging: {
|
||||||
},
|
disablelevel: "debug",
|
||||||
onInvokeError(error) {
|
},
|
||||||
console.log("onInvokeError", error)
|
onInvokeError(error) {
|
||||||
},
|
console.log("onInvokeError", error)
|
||||||
}),
|
},
|
||||||
],
|
}),
|
||||||
logger: BlitzLogger({}),
|
],
|
||||||
})
|
logger: BlitzLogger({}),
|
||||||
|
})
|
||||||
|
|
||||||
export {api, getBlitzContext, useAuthenticatedBlitzContext, invoke}
|
export {api, getBlitzContext, useAuthenticatedBlitzContext, invoke, withBlitzAuth}
|
||||||
|
|
||||||
export const cliConfig: BlitzCliConfig = {
|
export const cliConfig: BlitzCliConfig = {
|
||||||
customTemplates: "src/templates",
|
customTemplates: "src/templates",
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
import {rpcHandler} from "@blitzjs/rpc"
|
|
||||||
import {api} from "../../../blitz-server"
|
|
||||||
|
|
||||||
export default api(rpcHandler({onError: (error, ctx) => console.log(error)}))
|
|
||||||
@@ -12,5 +12,5 @@ export default async function getCurrentUser(input: null, ctx: Ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const config = {
|
export const config = {
|
||||||
httpMethod: "GET",
|
httpMethod: "POST",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,15 +23,15 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/auth": "2.0.2",
|
"@blitzjs/auth": "2.1.2",
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@blitzjs/next": "2.0.2",
|
"@blitzjs/next": "2.1.2",
|
||||||
"@blitzjs/rpc": "2.0.2",
|
"@blitzjs/rpc": "2.1.2",
|
||||||
"@hookform/error-message": "2.0.0",
|
"@hookform/error-message": "2.0.0",
|
||||||
"@hookform/resolvers": "2.9.10",
|
"@hookform/resolvers": "2.9.10",
|
||||||
"@prisma/client": "4.6.1",
|
"@prisma/client": "4.6.1",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"openid-client": "5.2.1",
|
"openid-client": "5.2.1",
|
||||||
"prisma": "4.6.1",
|
"prisma": "4.6.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ declare module "@blitzjs/auth" {
|
|||||||
PublicData: {
|
PublicData: {
|
||||||
userId: User["id"]
|
userId: User["id"]
|
||||||
role: Role
|
role: Role
|
||||||
views?: number
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,16 +24,16 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/auth": "2.0.2",
|
"@blitzjs/auth": "2.1.2",
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@blitzjs/next": "2.0.2",
|
"@blitzjs/next": "2.1.2",
|
||||||
"@blitzjs/rpc": "2.0.2",
|
"@blitzjs/rpc": "2.1.2",
|
||||||
"@hookform/error-message": "2.0.0",
|
"@hookform/error-message": "2.0.0",
|
||||||
"@hookform/resolvers": "2.9.10",
|
"@hookform/resolvers": "2.9.10",
|
||||||
"@prisma/client": "4.6.1",
|
"@prisma/client": "4.6.1",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"next-auth": "4.18.7",
|
"next-auth": "4.24.7",
|
||||||
"prisma": "4.6.1",
|
"prisma": "4.6.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
|
|||||||
@@ -11,15 +11,11 @@ const LoginPage: BlitzPage = () => {
|
|||||||
<LoginForm
|
<LoginForm
|
||||||
onSuccess={(_user) => {
|
onSuccess={(_user) => {
|
||||||
const next = router.query.next ? decodeURIComponent(router.query.next as string) : "/"
|
const next = router.query.next ? decodeURIComponent(router.query.next as string) : "/"
|
||||||
// return router.push(next)
|
return router.push(next)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
LoginPage.authenticate = {
|
|
||||||
redirectTo: "/",
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LoginPage
|
export default LoginPage
|
||||||
@@ -9,7 +9,6 @@ declare module "@blitzjs/auth" {
|
|||||||
PublicData: {
|
PublicData: {
|
||||||
userId: User["id"]
|
userId: User["id"]
|
||||||
role: Role
|
role: Role
|
||||||
views?: number
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,17 +16,17 @@
|
|||||||
"schema": "./db/schema.prisma"
|
"schema": "./db/schema.prisma"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/auth": "2.0.2",
|
"@blitzjs/auth": "2.1.2",
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@blitzjs/next": "2.0.2",
|
"@blitzjs/next": "2.1.2",
|
||||||
"@blitzjs/rpc": "2.0.2",
|
"@blitzjs/rpc": "2.1.2",
|
||||||
"@prisma/client": "4.6.1",
|
"@prisma/client": "4.6.1",
|
||||||
"@types/jest": "29.2.2",
|
"@types/jest": "29.2.2",
|
||||||
"@types/passport-twitter": "1.0.37",
|
"@types/passport-twitter": "1.0.37",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"jest": "29.3.0",
|
"jest": "29.3.0",
|
||||||
"jest-environment-jsdom": "29.3.0",
|
"jest-environment-jsdom": "29.3.0",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"passport-mock-strategy": "2.0.0",
|
"passport-mock-strategy": "2.0.0",
|
||||||
"passport-twitter": "1.0.4",
|
"passport-twitter": "1.0.4",
|
||||||
"prisma": "4.6.1",
|
"prisma": "4.6.1",
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ declare module "@blitzjs/auth" {
|
|||||||
PublicData: {
|
PublicData: {
|
||||||
userId: User["id"]
|
userId: User["id"]
|
||||||
role: Role
|
role: Role
|
||||||
views?: number
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
assets/route4me.png
Normal file
BIN
assets/route4me.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
@@ -17,16 +17,16 @@
|
|||||||
"prisma:studio": "prisma studio"
|
"prisma:studio": "prisma studio"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/auth": "2.0.2",
|
"@blitzjs/auth": "2.1.2",
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@blitzjs/next": "2.0.2",
|
"@blitzjs/next": "2.1.2",
|
||||||
"@blitzjs/rpc": "2.0.2",
|
"@blitzjs/rpc": "2.1.2",
|
||||||
"@hookform/error-message": "2.0.0",
|
"@hookform/error-message": "2.0.0",
|
||||||
"@hookform/resolvers": "2.9.10",
|
"@hookform/resolvers": "2.9.10",
|
||||||
"@prisma/client": "4.6.1",
|
"@prisma/client": "4.6.1",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"delay": "5.0.0",
|
"delay": "5.0.0",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"prisma": "4.6.1",
|
"prisma": "4.6.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
|
|||||||
@@ -79,11 +79,13 @@ const runTests = () => {
|
|||||||
let text = await browser.elementByCss("#content").text()
|
let text = await browser.elementByCss("#content").text()
|
||||||
expect(text).toMatch(/logged-out/)
|
expect(text).toMatch(/logged-out/)
|
||||||
await browser.elementByCss("#login").click()
|
await browser.elementByCss("#login").click()
|
||||||
await waitFor(200)
|
await waitFor(7500)
|
||||||
text = await browser.elementByCss("#content").text()
|
text = await browser.elementByCss("#content").text()
|
||||||
|
|
||||||
expect(text).toMatch(/logged-in/)
|
expect(text).toMatch(/logged-in/)
|
||||||
|
|
||||||
await browser.elementByCss("#logout").click()
|
await browser.elementByCss("#logout").click()
|
||||||
await waitFor(250)
|
await waitFor(5000)
|
||||||
text = await browser.elementByCss("#content").text()
|
text = await browser.elementByCss("#content").text()
|
||||||
expect(text).toMatch(/logged-out/)
|
expect(text).toMatch(/logged-out/)
|
||||||
|
|
||||||
@@ -93,16 +95,16 @@ const runTests = () => {
|
|||||||
it("should logout without infinite loop #2233", async () => {
|
it("should logout without infinite loop #2233", async () => {
|
||||||
// Login
|
// Login
|
||||||
let browser = await webdriver(appPort, "/login")
|
let browser = await webdriver(appPort, "/login")
|
||||||
await waitFor(200)
|
await waitFor(5000)
|
||||||
await browser.elementByCss("#login").click()
|
await browser.elementByCss("#login").click()
|
||||||
await waitFor(200)
|
await waitFor(5000)
|
||||||
|
|
||||||
await browser.eval(`window.location = "/authenticated-query"`)
|
await browser.eval(`window.location = "/authenticated-query"`)
|
||||||
await browser.waitForElementByCss("#content")
|
await browser.waitForElementByCss("#content")
|
||||||
let text = await browser.elementByCss("#content").text()
|
let text = await browser.elementByCss("#content").text()
|
||||||
expect(text).toMatch(/authenticated-basic-result/)
|
expect(text).toMatch(/authenticated-basic-result/)
|
||||||
await browser.elementByCss("#logout").click()
|
await browser.elementByCss("#logout").click()
|
||||||
await waitFor(200)
|
await waitFor(5000)
|
||||||
await browser.waitForElementByCss("#error")
|
await browser.waitForElementByCss("#error")
|
||||||
text = await browser.elementByCss("#error").text()
|
text = await browser.elementByCss("#error").text()
|
||||||
if (mode === "server") {
|
if (mode === "server") {
|
||||||
@@ -115,9 +117,9 @@ const runTests = () => {
|
|||||||
|
|
||||||
it("Page.authenticate = {role} should throw authentication error ", async () => {
|
it("Page.authenticate = {role} should throw authentication error ", async () => {
|
||||||
let browser = await webdriver(appPort, "/login")
|
let browser = await webdriver(appPort, "/login")
|
||||||
await waitFor(200)
|
await waitFor(5000)
|
||||||
await browser.elementByCss("#login").click()
|
await browser.elementByCss("#login").click()
|
||||||
await waitFor(200)
|
await waitFor(5000)
|
||||||
await browser.eval(`window.location = "/page-dot-authenticate-role"`)
|
await browser.eval(`window.location = "/page-dot-authenticate-role"`)
|
||||||
await browser.waitForElementByCss("#error")
|
await browser.waitForElementByCss("#error")
|
||||||
let text = await browser.elementByCss("#error").text()
|
let text = await browser.elementByCss("#error").text()
|
||||||
@@ -169,7 +171,7 @@ const runTests = () => {
|
|||||||
let text = await browser.elementByCss("#content").text()
|
let text = await browser.elementByCss("#content").text()
|
||||||
expect(text).toMatch(/authenticated-basic-result/)
|
expect(text).toMatch(/authenticated-basic-result/)
|
||||||
await browser.elementByCss("#logout").click()
|
await browser.elementByCss("#logout").click()
|
||||||
await waitFor(500)
|
await waitFor(5000)
|
||||||
|
|
||||||
expect(await browser.url()).toMatch(/\/login/)
|
expect(await browser.url()).toMatch(/\/login/)
|
||||||
if (browser) await browser.close()
|
if (browser) await browser.close()
|
||||||
@@ -275,7 +277,7 @@ const runTests = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("Auth Tests", () => {
|
describe("Auth Tests", () => {
|
||||||
describe("dev mode", () => {
|
describe("dev mode - webpack", () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
mode = "dev"
|
mode = "dev"
|
||||||
try {
|
try {
|
||||||
@@ -290,6 +292,21 @@ describe("Auth Tests", () => {
|
|||||||
runTests()
|
runTests()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("dev mode - turbo", () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
mode = "dev"
|
||||||
|
try {
|
||||||
|
await runBlitzCommand(["prisma", "migrate", "reset", "--force"])
|
||||||
|
appPort = await findPort()
|
||||||
|
app = await blitzLaunchApp(appPort, {cwd: process.cwd()}, true)
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}, 5000 * 60 * 2)
|
||||||
|
afterAll(async () => await killApp(app))
|
||||||
|
runTests()
|
||||||
|
})
|
||||||
|
|
||||||
describe("server mode", () => {
|
describe("server mode", () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
mode = "server"
|
mode = "server"
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ declare module "@blitzjs/auth" {
|
|||||||
PublicData: {
|
PublicData: {
|
||||||
userId: User["id"]
|
userId: User["id"]
|
||||||
role: Role
|
role: Role
|
||||||
views?: number
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,13 +17,13 @@
|
|||||||
"prisma:studio": "prisma studio"
|
"prisma:studio": "prisma studio"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/auth": "2.0.2",
|
"@blitzjs/auth": "2.1.2",
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@blitzjs/next": "2.0.2",
|
"@blitzjs/next": "2.1.2",
|
||||||
"@prisma/client": "4.6.1",
|
"@prisma/client": "4.6.1",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"lowdb": "3.0.0",
|
"lowdb": "3.0.0",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"prisma": "4.6.1",
|
"prisma": "4.6.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
|
|||||||
@@ -21,14 +21,11 @@ export const authenticateUser = async (email: string, password: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default api(async (req, res, ctx) => {
|
export default api(async (req, res, ctx) => {
|
||||||
const blitzContext = ctx
|
|
||||||
|
|
||||||
const user = await authenticateUser(req.query.email as string, req.query.password as string)
|
const user = await authenticateUser(req.query.email as string, req.query.password as string)
|
||||||
|
await ctx.session.$create({
|
||||||
await blitzContext.session.$create({
|
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
role: user.role as Role,
|
role: user.role as Role,
|
||||||
})
|
})
|
||||||
|
|
||||||
res.status(200).json({email: req.query.email, userId: blitzContext.session.userId})
|
res.status(200).json({email: req.query.email, userId: ctx.session.userId})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ declare module "@blitzjs/auth" {
|
|||||||
PublicData: {
|
PublicData: {
|
||||||
userId: User["id"]
|
userId: User["id"]
|
||||||
role: Role
|
role: Role
|
||||||
views?: number
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,19 +16,19 @@
|
|||||||
"schema": "db/schema.prisma"
|
"schema": "db/schema.prisma"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/auth": "2.0.2",
|
"@blitzjs/auth": "2.1.2",
|
||||||
"@blitzjs/next": "2.0.2",
|
"@blitzjs/next": "2.1.2",
|
||||||
"@blitzjs/rpc": "2.0.2",
|
"@blitzjs/rpc": "2.1.2",
|
||||||
"@prisma/client": "4.6.1",
|
"@prisma/client": "4.6.1",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"lowdb": "3.0.0",
|
"lowdb": "2.1.0",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"prisma": "4.6.1",
|
"prisma": "4.6.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0"
|
"react-dom": "18.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@next/bundle-analyzer": "12.0.8",
|
"@next/bundle-analyzer": "12.0.8",
|
||||||
"@types/express": "4.17.13",
|
"@types/express": "4.17.13",
|
||||||
"@types/fs-extra": "9.0.13",
|
"@types/fs-extra": "9.0.13",
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ declare module "@blitzjs/auth" {
|
|||||||
PublicData: {
|
PublicData: {
|
||||||
userId: User["id"]
|
userId: User["id"]
|
||||||
role: Role
|
role: Role
|
||||||
views?: number
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,11 +11,11 @@
|
|||||||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next"
|
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@blitzjs/next": "2.0.2",
|
"@blitzjs/next": "2.1.2",
|
||||||
"@blitzjs/rpc": "2.0.2",
|
"@blitzjs/rpc": "2.1.2",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0"
|
"react-dom": "18.2.0"
|
||||||
},
|
},
|
||||||
|
|||||||
15
integration-tests/next-13-app-dir/app/api/logout/route.ts
Normal file
15
integration-tests/next-13-app-dir/app/api/logout/route.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import {withBlitzAuth} from "../../../src/blitz-server"
|
||||||
|
|
||||||
|
export const {POST} = withBlitzAuth({
|
||||||
|
POST: async (_request, _params, ctx) => {
|
||||||
|
const session = ctx.session
|
||||||
|
await session.$revoke()
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
userId: session.userId,
|
||||||
|
}),
|
||||||
|
{status: 200},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
11
integration-tests/next-13-app-dir/app/api/noauth/route.ts
Normal file
11
integration-tests/next-13-app-dir/app/api/noauth/route.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import {H} from "@blitzjs/auth/dist/index-0ecbee46"
|
||||||
|
import {withBlitzAuth} from "../../../src/blitz-server"
|
||||||
|
|
||||||
|
const emptyResponse = async () => {
|
||||||
|
return new Response(null, {status: 200})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const {POST, HEAD} = withBlitzAuth({
|
||||||
|
POST: emptyResponse,
|
||||||
|
HEAD: emptyResponse,
|
||||||
|
})
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import {rpcAppHandler} from "@blitzjs/rpc"
|
||||||
|
import {withBlitzAuth} from "../../../../src/blitz-server"
|
||||||
|
|
||||||
|
export const {GET, POST, HEAD} = withBlitzAuth(rpcAppHandler())
|
||||||
38
integration-tests/next-13-app-dir/app/api/signin/route.ts
Normal file
38
integration-tests/next-13-app-dir/app/api/signin/route.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import {withBlitzAuth} from "../../../src/blitz-server"
|
||||||
|
import prisma from "../../../db/index"
|
||||||
|
import {Role} from "../../../types"
|
||||||
|
|
||||||
|
export const authenticateUser = async (email: string, password: string) => {
|
||||||
|
const user = await prisma.user.findFirst({where: {email}})
|
||||||
|
|
||||||
|
if (!user) throw new Error("Authentication Error")
|
||||||
|
await prisma.user.update({where: {id: user.id}, data: {hashedPassword: password}})
|
||||||
|
|
||||||
|
const {hashedPassword, ...rest} = user
|
||||||
|
return rest
|
||||||
|
}
|
||||||
|
|
||||||
|
export const {POST} = withBlitzAuth({
|
||||||
|
POST: async (request: Request, context, ctx) => {
|
||||||
|
const {searchParams} = new URL(request.url)
|
||||||
|
const user = await authenticateUser(
|
||||||
|
searchParams.get("email") as string,
|
||||||
|
searchParams.get("password") as string,
|
||||||
|
)
|
||||||
|
|
||||||
|
await ctx.session.$create({
|
||||||
|
userId: user.id,
|
||||||
|
role: user.role as Role,
|
||||||
|
})
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({email: searchParams.get("email"), userId: ctx.session.userId}),
|
||||||
|
{
|
||||||
|
status: 200,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import {useQuery, useMutation} from "@blitzjs/rpc"
|
|
||||||
import logout from "../src/auth/mutations/logout"
|
|
||||||
import getCurrentUser from "../src/users/queries/getCurrentUser"
|
|
||||||
import {useTransition} from "react"
|
|
||||||
import {useRouter} from "next/navigation"
|
|
||||||
|
|
||||||
export default function Test() {
|
|
||||||
const router = useRouter()
|
|
||||||
const [user] = useQuery(getCurrentUser, null)
|
|
||||||
const [isPending, startTransition] = useTransition()
|
|
||||||
const [logoutMutation] = useMutation(logout)
|
|
||||||
console.log(user)
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<h1>Test</h1>
|
|
||||||
<p>{user?.email}</p>
|
|
||||||
<button
|
|
||||||
className="button small"
|
|
||||||
onClick={async () => {
|
|
||||||
await logoutMutation()
|
|
||||||
startTransition(() => {
|
|
||||||
// Refresh the current route and fetch new data from the server without
|
|
||||||
// losing client-side browser or React state.
|
|
||||||
router.refresh()
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Logout
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
/// <reference types="next/navigation-types/compat/navigation" />
|
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||||
|
|||||||
@@ -17,14 +17,14 @@
|
|||||||
"prisma:studio": "prisma studio"
|
"prisma:studio": "prisma studio"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/auth": "2.0.2",
|
"@blitzjs/auth": "2.1.2",
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@blitzjs/next": "2.0.2",
|
"@blitzjs/next": "2.1.2",
|
||||||
"@blitzjs/rpc": "2.0.2",
|
"@blitzjs/rpc": "2.1.2",
|
||||||
"@prisma/client": "4.6.1",
|
"@prisma/client": "4.6.1",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"lowdb": "3.0.0",
|
"lowdb": "2.1.0",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"prisma": "4.6.1",
|
"prisma": "4.6.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
@@ -45,6 +45,6 @@
|
|||||||
"node-fetch": "3.2.3",
|
"node-fetch": "3.2.3",
|
||||||
"playwright": "1.28.0",
|
"playwright": "1.28.0",
|
||||||
"ts-node": "10.9.1",
|
"ts-node": "10.9.1",
|
||||||
"typescript": "^4.8.4"
|
"typescript": "^4.9.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import {api} from "../../src/blitz-server"
|
|
||||||
|
|
||||||
export default api(async (_req, res, ctx) => {
|
|
||||||
const blitzContext = ctx
|
|
||||||
|
|
||||||
await blitzContext.session.$revoke()
|
|
||||||
|
|
||||||
res.status(200).json({userId: blitzContext.session.userId})
|
|
||||||
})
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
import {api} from "../../src/blitz-server"
|
|
||||||
|
|
||||||
export default api(async (_req, res, ctx) => {
|
|
||||||
res.status(200).end()
|
|
||||||
})
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import {rpcHandler} from "@blitzjs/rpc"
|
|
||||||
import {api} from "../../../src/blitz-server"
|
|
||||||
|
|
||||||
export default api(rpcHandler({onError: (error, ctx) => console.log(error)}))
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import {api} from "../../src/blitz-server"
|
|
||||||
import prisma from "../../db/index"
|
|
||||||
import {SecurePassword} from "@blitzjs/auth/secure-password"
|
|
||||||
import {Role} from "../../types"
|
|
||||||
|
|
||||||
export const authenticateUser = async (email: string, password: string) => {
|
|
||||||
const user = await prisma.user.findFirst({where: {email}})
|
|
||||||
|
|
||||||
if (!user) throw new Error("Authentication Error")
|
|
||||||
|
|
||||||
const result = await SecurePassword.verify(user.hashedPassword, password)
|
|
||||||
|
|
||||||
if (result === SecurePassword.VALID_NEEDS_REHASH) {
|
|
||||||
// Upgrade hashed password with a more secure hash
|
|
||||||
const improvedHash = await SecurePassword.hash(password)
|
|
||||||
await prisma.user.update({where: {id: user.id}, data: {hashedPassword: improvedHash}})
|
|
||||||
}
|
|
||||||
|
|
||||||
const {hashedPassword, ...rest} = user
|
|
||||||
return rest
|
|
||||||
}
|
|
||||||
|
|
||||||
export default api(async (req, res, ctx) => {
|
|
||||||
const blitzContext = ctx
|
|
||||||
|
|
||||||
const user = await authenticateUser(req.query.email as string, req.query.password as string)
|
|
||||||
|
|
||||||
await blitzContext.session.$create({
|
|
||||||
userId: user.id,
|
|
||||||
role: user.role as Role,
|
|
||||||
})
|
|
||||||
|
|
||||||
res.status(200).json({email: req.query.email, userId: blitzContext.session.userId})
|
|
||||||
})
|
|
||||||
@@ -3,16 +3,16 @@ import {AuthServerPlugin, PrismaStorage} from "@blitzjs/auth"
|
|||||||
import db from "../db"
|
import db from "../db"
|
||||||
import {simpleRolesIsAuthorized} from "@blitzjs/auth"
|
import {simpleRolesIsAuthorized} from "@blitzjs/auth"
|
||||||
import {BlitzLogger} from "blitz"
|
import {BlitzLogger} from "blitz"
|
||||||
|
import {RpcServerPlugin} from "@blitzjs/rpc"
|
||||||
|
|
||||||
const {api, getBlitzContext} = setupBlitzServer({
|
export const {api, getBlitzContext, withBlitzAuth} = setupBlitzServer({
|
||||||
plugins: [
|
plugins: [
|
||||||
AuthServerPlugin({
|
AuthServerPlugin({
|
||||||
cookiePrefix: "auth-tests-cookie-prefix",
|
cookiePrefix: "auth-tests-cookie-prefix",
|
||||||
storage: PrismaStorage(db),
|
storage: PrismaStorage(db),
|
||||||
isAuthorized: simpleRolesIsAuthorized,
|
isAuthorized: simpleRolesIsAuthorized,
|
||||||
}),
|
}),
|
||||||
|
RpcServerPlugin({}),
|
||||||
],
|
],
|
||||||
logger: BlitzLogger({}),
|
logger: BlitzLogger({}),
|
||||||
})
|
})
|
||||||
|
|
||||||
export {api, getBlitzContext}
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ const runTests = (mode?: string) => {
|
|||||||
"should render result for open query",
|
"should render result for open query",
|
||||||
async () => {
|
async () => {
|
||||||
const res = await fetch(`http://localhost:${appPort}/api/noauth`, {
|
const res = await fetch(`http://localhost:${appPort}/api/noauth`, {
|
||||||
method: "GET",
|
method: "POST",
|
||||||
headers: {"Content-Type": "application/json; charset=utf-8"},
|
headers: {"Content-Type": "application/json; charset=utf-8"},
|
||||||
})
|
})
|
||||||
expect(res.status).toBe(200)
|
expect(res.status).toBe(200)
|
||||||
@@ -67,7 +67,7 @@ const runTests = (mode?: string) => {
|
|||||||
|
|
||||||
it("sets correct cookie", async () => {
|
it("sets correct cookie", async () => {
|
||||||
const res = await fetch(`http://localhost:${appPort}/api/noauth`, {
|
const res = await fetch(`http://localhost:${appPort}/api/noauth`, {
|
||||||
method: "GET",
|
method: "POST",
|
||||||
headers: {"Content-Type": "application/json; charset=utf-8"},
|
headers: {"Content-Type": "application/json; charset=utf-8"},
|
||||||
})
|
})
|
||||||
const cookieHeader = res.headers.get("Set-Cookie")
|
const cookieHeader = res.headers.get("Set-Cookie")
|
||||||
@@ -94,6 +94,8 @@ const runTests = (mode?: string) => {
|
|||||||
async () => {
|
async () => {
|
||||||
const browser = await webdriver(appPort, "/react-query")
|
const browser = await webdriver(appPort, "/react-query")
|
||||||
|
|
||||||
|
await browser.refresh()
|
||||||
|
|
||||||
browser.waitForElementByCss("#button", 0)
|
browser.waitForElementByCss("#button", 0)
|
||||||
await browser.elementByCss("#button").click()
|
await browser.elementByCss("#button").click()
|
||||||
|
|
||||||
@@ -133,7 +135,7 @@ const runTests = (mode?: string) => {
|
|||||||
|
|
||||||
it("does not require CSRF header on HEAD requests", async () => {
|
it("does not require CSRF header on HEAD requests", async () => {
|
||||||
const res = await fetch(`http://localhost:${appPort}/api/noauth`, {
|
const res = await fetch(`http://localhost:${appPort}/api/noauth`, {
|
||||||
method: "GET",
|
method: "POST",
|
||||||
headers: {"Content-Type": "application/json; charset=utf-8"},
|
headers: {"Content-Type": "application/json; charset=utf-8"},
|
||||||
})
|
})
|
||||||
const cookieHeader = res.headers.get("Set-Cookie")
|
const cookieHeader = res.headers.get("Set-Cookie")
|
||||||
@@ -153,7 +155,7 @@ const runTests = (mode?: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("Auth Tests", () => {
|
describe("Auth Tests", () => {
|
||||||
describe("dev mode", async () => {
|
describe("dev mode - webpack", async () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
try {
|
try {
|
||||||
await runBlitzCommand(["prisma", "migrate", "reset", "--force"])
|
await runBlitzCommand(["prisma", "migrate", "reset", "--force"])
|
||||||
@@ -169,19 +171,19 @@ describe("Auth Tests", () => {
|
|||||||
runTests()
|
runTests()
|
||||||
})
|
})
|
||||||
|
|
||||||
// describe("server mode", () => {
|
describe("dev mode - turbo", async () => {
|
||||||
// beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
// try {
|
try {
|
||||||
// await runBlitzCommand(["prisma", "generate"])
|
await runBlitzCommand(["prisma", "migrate", "reset", "--force"])
|
||||||
// await runBlitzCommand(["prisma", "migrate", "deploy"])
|
appPort = await findPort()
|
||||||
// await blitzBuild()
|
app = await blitzLaunchApp(appPort, {cwd: process.cwd()}, true)
|
||||||
// // appPort = await findPort()
|
} catch (error) {
|
||||||
// app = await blitzStart(appPort, {cwd: process.cwd()})
|
console.log(error)
|
||||||
// } catch (err) {
|
}
|
||||||
// console.log(err)
|
}, 5000 * 60 * 2)
|
||||||
// }
|
afterAll(async () => {
|
||||||
// }, 5000 * 60 * 2)
|
await killApp(app)
|
||||||
// afterAll(async () => await killApp(app))
|
})
|
||||||
// runTests()
|
runTests()
|
||||||
// })
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ declare module "@blitzjs/auth" {
|
|||||||
PublicData: {
|
PublicData: {
|
||||||
userId: User["id"]
|
userId: User["id"]
|
||||||
role: Role
|
role: Role
|
||||||
views?: number
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,19 +16,19 @@
|
|||||||
"prisma:studio": "prisma studio"
|
"prisma:studio": "prisma studio"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/auth": "2.0.2",
|
"@blitzjs/auth": "2.1.2",
|
||||||
"@blitzjs/next": "2.0.2",
|
"@blitzjs/next": "2.1.2",
|
||||||
"@blitzjs/rpc": "2.0.2",
|
"@blitzjs/rpc": "2.1.2",
|
||||||
"@prisma/client": "4.6.1",
|
"@prisma/client": "4.6.1",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"lowdb": "3.0.0",
|
"lowdb": "3.0.0",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"prisma": "4.6.1",
|
"prisma": "4.6.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0"
|
"react-dom": "18.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@next/bundle-analyzer": "12.0.8",
|
"@next/bundle-analyzer": "12.0.8",
|
||||||
"@types/express": "4.17.13",
|
"@types/express": "4.17.13",
|
||||||
"@types/fs-extra": "9.0.13",
|
"@types/fs-extra": "9.0.13",
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ declare module "@blitzjs/auth" {
|
|||||||
PublicData: {
|
PublicData: {
|
||||||
userId: User["id"]
|
userId: User["id"]
|
||||||
role: Role
|
role: Role
|
||||||
views?: number
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,14 @@
|
|||||||
"clean": "rm -rf .turbo && rm -rf node_modules"
|
"clean": "rm -rf .turbo && rm -rf node_modules"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/auth": "2.0.2",
|
"@blitzjs/auth": "2.1.2",
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@blitzjs/next": "2.0.2",
|
"@blitzjs/next": "2.1.2",
|
||||||
"@blitzjs/rpc": "2.0.2",
|
"@blitzjs/rpc": "2.1.2",
|
||||||
"@prisma/client": "4.6.1",
|
"@prisma/client": "4.6.1",
|
||||||
"@tanstack/react-query": "4.0.10",
|
"@tanstack/react-query": "4.0.10",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"prisma": "4.6.1",
|
"prisma": "4.6.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0"
|
"react-dom": "18.2.0"
|
||||||
|
|||||||
@@ -16,18 +16,18 @@
|
|||||||
"schema": "db/schema.prisma"
|
"schema": "db/schema.prisma"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/next": "2.0.2",
|
"@blitzjs/next": "2.1.2",
|
||||||
"@blitzjs/rpc": "2.0.2",
|
"@blitzjs/rpc": "2.1.2",
|
||||||
"@prisma/client": "4.6.1",
|
"@prisma/client": "4.6.1",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"lowdb": "3.0.0",
|
"lowdb": "3.0.0",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"prisma": "4.6.1",
|
"prisma": "4.6.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0"
|
"react-dom": "18.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@next/bundle-analyzer": "12.0.8",
|
"@next/bundle-analyzer": "12.0.8",
|
||||||
"@types/express": "4.17.13",
|
"@types/express": "4.17.13",
|
||||||
"@types/fs-extra": "9.0.13",
|
"@types/fs-extra": "9.0.13",
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next"
|
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@blitzjs/next": "2.0.2",
|
"@blitzjs/next": "2.1.2",
|
||||||
"@blitzjs/rpc": "2.0.2",
|
"@blitzjs/rpc": "2.1.2",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0"
|
"react-dom": "18.2.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next"
|
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@blitzjs/next": "2.0.2",
|
"@blitzjs/next": "2.1.2",
|
||||||
"@blitzjs/rpc": "2.0.2",
|
"@blitzjs/rpc": "2.1.2",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0"
|
"react-dom": "18.2.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,19 +16,19 @@
|
|||||||
"schema": "db/schema.prisma"
|
"schema": "db/schema.prisma"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/auth": "2.0.2",
|
"@blitzjs/auth": "2.1.2",
|
||||||
"@blitzjs/next": "2.0.2",
|
"@blitzjs/next": "2.1.2",
|
||||||
"@blitzjs/rpc": "2.0.2",
|
"@blitzjs/rpc": "2.1.2",
|
||||||
"@prisma/client": "4.6.1",
|
"@prisma/client": "4.6.1",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"lowdb": "3.0.0",
|
"lowdb": "3.0.0",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"prisma": "4.6.1",
|
"prisma": "4.6.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0"
|
"react-dom": "18.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@next/bundle-analyzer": "12.0.8",
|
"@next/bundle-analyzer": "12.0.8",
|
||||||
"@types/express": "4.17.13",
|
"@types/express": "4.17.13",
|
||||||
"@types/fs-extra": "9.0.13",
|
"@types/fs-extra": "9.0.13",
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ declare module "@blitzjs/auth" {
|
|||||||
PublicData: {
|
PublicData: {
|
||||||
userId: User["id"]
|
userId: User["id"]
|
||||||
role: Role
|
role: Role
|
||||||
views?: number
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -233,6 +233,7 @@ export function runBlitzCommandDev(argv, stdOut, opts: RunNextCommandDevOptions
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
console.log(`Running command "blitz ${argv.join(" ")}"`)
|
||||||
const instance = spawn("node", [blitzBin, ...argv], {
|
const instance = spawn("node", [blitzBin, ...argv], {
|
||||||
cwd,
|
cwd,
|
||||||
env,
|
env,
|
||||||
@@ -294,8 +295,8 @@ export function runBlitzCommandDev(argv, stdOut, opts: RunNextCommandDevOptions
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Blitz Utils
|
// Blitz Utils
|
||||||
export function blitzLaunchApp(port, opts: RunNextCommandDevOptions) {
|
export function blitzLaunchApp(port, opts: RunNextCommandDevOptions, turbo = false) {
|
||||||
return runBlitzCommandDev(["dev", "-p", port], undefined, opts)
|
return runBlitzCommandDev(["dev", "-p", port, turbo ? "--turbo" : ""], undefined, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function blitzBuild(args = [], opts = {}): any {
|
export function blitzBuild(args = [], opts = {}): any {
|
||||||
@@ -437,7 +438,7 @@ export function runNextCommandDev(argv, stdOut, opts: RunNextCommandDevOptions =
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (opts.stdout !== false) {
|
if (opts.stdout !== false) {
|
||||||
process.stdout.write(message)
|
process.stdout.write(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -923,4 +924,5 @@ interface RunNextCommandDevOptions {
|
|||||||
nodeArgs?: []
|
nodeArgs?: []
|
||||||
bootupMarker?: any
|
bootupMarker?: any
|
||||||
nextStart?: boolean
|
nextStart?: boolean
|
||||||
|
turbo?: boolean
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@blitzjs/config": "workspace:2.0.2",
|
"@blitzjs/config": "workspace:2.1.2",
|
||||||
"@blitzjs/next": "workspace:2.0.2",
|
"@blitzjs/next": "workspace:2.1.2",
|
||||||
"@blitzjs/rpc": "workspace:2.0.2",
|
"@blitzjs/rpc": "workspace:2.1.2",
|
||||||
"@tanstack/react-query": "4.13.0",
|
"@tanstack/react-query": "4.13.0",
|
||||||
"@testing-library/react": "13.4.0",
|
"@testing-library/react": "13.4.0",
|
||||||
"@types/express": "4.17.13",
|
"@types/express": "4.17.13",
|
||||||
|
|||||||
10
package.json
10
package.json
@@ -29,9 +29,9 @@
|
|||||||
"husky": "8.0.2",
|
"husky": "8.0.2",
|
||||||
"jsdom": "^19.0.0",
|
"jsdom": "^19.0.0",
|
||||||
"lint-staged": "13.0.3",
|
"lint-staged": "13.0.3",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"only-allow": "1.1.0",
|
"only-allow": "1.1.0",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.8.8",
|
||||||
"prettier-plugin-prisma": "4.4.0",
|
"prettier-plugin-prisma": "4.4.0",
|
||||||
"pretty-quick": "3.1.3",
|
"pretty-quick": "3.1.3",
|
||||||
"turbo": "1.10.9",
|
"turbo": "1.10.9",
|
||||||
@@ -47,7 +47,11 @@
|
|||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"patchedDependencies": {
|
"patchedDependencies": {
|
||||||
"next-auth@4.18.7": "patches/next-auth@4.18.7.patch"
|
"next-auth@4.24.7": "patches/next-auth@4.24.7.patch"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"@types/mime": "3.0.4",
|
||||||
|
"next": "14.3.0-canary.28"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,133 @@
|
|||||||
# @blitzjs/auth
|
# @blitzjs/auth
|
||||||
|
|
||||||
|
## 2.1.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- blitz@2.1.2
|
||||||
|
|
||||||
|
## 2.1.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [9a0ba87d1]
|
||||||
|
- blitz@2.1.1
|
||||||
|
|
||||||
|
## 2.1.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 3b10b13e6: feat: add blitz auth support for the Web `Request` API standard
|
||||||
|
|
||||||
|
Usage using the new `withBlitzAuth` adapter in the App Router:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import {withBlitzAuth} from "app/blitz-server"
|
||||||
|
|
||||||
|
export const {POST} = withBlitzAuth({
|
||||||
|
POST: async (_request, _params, ctx) => {
|
||||||
|
const session = ctx.session
|
||||||
|
await session.$revoke()
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
userId: session.userId,
|
||||||
|
}),
|
||||||
|
{status: 200},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
feat: New Blitz RPC handler meant to with the next.js app router `route.ts` files
|
||||||
|
|
||||||
|
Usage using the new `rpcAppHandler` function
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// app/api/rpc/[[...blitz]]/route.ts
|
||||||
|
import {rpcAppHandler} from "@blitzjs/rpc"
|
||||||
|
import {withBlitzAuth} from "app/blitz-server"
|
||||||
|
|
||||||
|
// Usage with blitz auth
|
||||||
|
export const {GET, POST, HEAD} = withBlitzAuth(rpcAppHandler())
|
||||||
|
|
||||||
|
// Standalone usage
|
||||||
|
export const {GET, POST, HEAD} = rpcAppHandler()
|
||||||
|
```
|
||||||
|
|
||||||
|
chore: Update the app directory starter
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [d53da39cb]
|
||||||
|
- Updated dependencies [3b10b13e6]
|
||||||
|
- blitz@2.1.0
|
||||||
|
|
||||||
|
## 2.0.10
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 318e9740d: feat: support next-auth version 4.24.7
|
||||||
|
- Updated dependencies [318e9740d]
|
||||||
|
- blitz@2.0.10
|
||||||
|
|
||||||
|
## 2.0.9
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [5a14306f7]
|
||||||
|
- blitz@2.0.9
|
||||||
|
|
||||||
|
## 2.0.8
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 77555468f: fix: add missing host while initialising the next-auth adapter
|
||||||
|
- Updated dependencies [5e61a1681]
|
||||||
|
- Updated dependencies [77555468f]
|
||||||
|
- blitz@2.0.8
|
||||||
|
|
||||||
|
## 2.0.7
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [ee7bf87ec]
|
||||||
|
- Updated dependencies [178c152b2]
|
||||||
|
- blitz@2.0.7
|
||||||
|
|
||||||
|
## 2.0.6
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 5a587a6c3: Fix bundling issue that occurs in vercel due to the way imports were handled internally
|
||||||
|
- Updated dependencies [76a2544f9]
|
||||||
|
- blitz@2.0.6
|
||||||
|
|
||||||
|
## 2.0.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 6f54841b7: fix: getBlitzContext() can only be used in React Server Components in Nextjs 13 or higher
|
||||||
|
- 8a417533f: fix: remove restriction to use `secure` cookies in localhost / during development following spec in [developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#restrict_access_to_cookies)
|
||||||
|
- Updated dependencies [6f54841b7]
|
||||||
|
- blitz@2.0.5
|
||||||
|
|
||||||
|
## 2.0.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- dd604c767: perf: add filter to select only non expired sessions
|
||||||
|
- Updated dependencies [dd604c767]
|
||||||
|
- Updated dependencies [28a79040e]
|
||||||
|
- blitz@2.0.4
|
||||||
|
|
||||||
|
## 2.0.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [2f5c8a3a0]
|
||||||
|
- blitz@2.0.3
|
||||||
|
|
||||||
## 2.0.2
|
## 2.0.2
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@blitzjs/auth",
|
"name": "@blitzjs/auth",
|
||||||
"version": "2.0.2",
|
"version": "2.1.2",
|
||||||
"homepage": "https://blitzjs.com/",
|
"homepage": "https://blitzjs.com/",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
"url": "0.11.0"
|
"url": "0.11.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"next": "*",
|
"next": "*",
|
||||||
"next-auth": "*",
|
"next-auth": "*",
|
||||||
"secure-password": "4.0.0"
|
"secure-password": "4.0.0"
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@testing-library/react": "13.4.0",
|
"@testing-library/react": "13.4.0",
|
||||||
"@testing-library/react-hooks": "8.0.1",
|
"@testing-library/react-hooks": "8.0.1",
|
||||||
"@types/cookie": "0.4.1",
|
"@types/cookie": "0.4.1",
|
||||||
@@ -75,9 +75,9 @@
|
|||||||
"@types/jsonwebtoken": "8.5.8",
|
"@types/jsonwebtoken": "8.5.8",
|
||||||
"@types/react": "18.0.25",
|
"@types/react": "18.0.25",
|
||||||
"@types/react-dom": "17.0.14",
|
"@types/react-dom": "17.0.14",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"next-auth": "4.18.7",
|
"next-auth": "4.24.7",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"secure-password": "4.0.0",
|
"secure-password": "4.0.0",
|
||||||
|
|||||||
@@ -161,6 +161,8 @@ export const useSession = (options: UseSessionOptions = {}): ClientSession => {
|
|||||||
if (isServer) {
|
if (isServer) {
|
||||||
const e = new Error()
|
const e = new Error()
|
||||||
e.name = "Rendering Suspense fallback..."
|
e.name = "Rendering Suspense fallback..."
|
||||||
|
;(e as any).digest = "DYNAMIC_SERVER_USAGE"
|
||||||
|
e.message = "DYNAMIC_SERVER_USAGE"
|
||||||
delete e.stack
|
delete e.stack
|
||||||
throw e
|
throw e
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -107,13 +107,8 @@ export function NextAuthAdapter<P extends Provider[]>(
|
|||||||
providerId = providerId.split("?")[0]
|
providerId = providerId.split("?")[0]
|
||||||
}
|
}
|
||||||
const {options, cookies} = await init({
|
const {options, cookies} = await init({
|
||||||
// @ts-ignore
|
|
||||||
url: new URL(
|
|
||||||
// @ts-ignore
|
|
||||||
internalRequest.url!,
|
|
||||||
process.env.APP_ORIGIN || process.env.BLITZ_DEV_SERVER_ORIGIN,
|
|
||||||
),
|
|
||||||
authOptions: config as unknown as AuthOptions,
|
authOptions: config as unknown as AuthOptions,
|
||||||
|
origin: internalRequest.origin,
|
||||||
action,
|
action,
|
||||||
providerId,
|
providerId,
|
||||||
callbackUrl: req.body?.callbackUrl ?? (req.query?.callbackUrl as string),
|
callbackUrl: req.body?.callbackUrl ?? (req.query?.callbackUrl as string),
|
||||||
|
|||||||
@@ -47,7 +47,12 @@ async function readJSONBody(
|
|||||||
// prettier-ignore
|
// prettier-ignore
|
||||||
const actions = [ "providers", "session", "csrf", "login", "signout", "callback", "verify-request", "error", "_log"]
|
const actions = [ "providers", "session", "csrf", "login", "signout", "callback", "verify-request", "error", "_log"]
|
||||||
|
|
||||||
export async function toInternalRequest(req: Request): Promise<RequestInternal | Error> {
|
export async function toInternalRequest(req: Request): Promise<
|
||||||
|
| (RequestInternal & {
|
||||||
|
url: URL
|
||||||
|
})
|
||||||
|
| Error
|
||||||
|
> {
|
||||||
try {
|
try {
|
||||||
// TODO: url.toString() should not include action and providerId
|
// TODO: url.toString() should not include action and providerId
|
||||||
// see init.ts
|
// see init.ts
|
||||||
@@ -69,17 +74,28 @@ export async function toInternalRequest(req: Request): Promise<RequestInternal |
|
|||||||
providerId = providerIdOrAction
|
providerId = providerIdOrAction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const headers = Object.fromEntries(req.headers)
|
||||||
|
const detectOrigin = (host?: string, proto?: string) => {
|
||||||
|
if (process.env.VERCEL ?? process.env.FLIGHTCONTROL ?? process.env.AUTH_TRUST_HOST)
|
||||||
|
return `${proto === "http" ? "http" : "https"}://${host}`
|
||||||
|
|
||||||
|
return process.env.NEXTAUTH_URL
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
//@ts-ignore
|
|
||||||
url,
|
url,
|
||||||
action,
|
action,
|
||||||
providerId,
|
providerId,
|
||||||
method: req.method ?? "GET",
|
method: req.method ?? "GET",
|
||||||
headers: Object.fromEntries(req.headers),
|
headers,
|
||||||
body: req.body ? await readJSONBody(req.body) : undefined,
|
body: req.body ? await readJSONBody(req.body) : undefined,
|
||||||
cookies: parseCookie(req.headers.get("cookie") ?? "") ?? {},
|
cookies: parseCookie(req.headers.get("cookie") ?? "") ?? {},
|
||||||
error: url.searchParams.get("error") ?? undefined,
|
error: url.searchParams.get("error") ?? undefined,
|
||||||
query: Object.fromEntries(url.searchParams),
|
query: Object.fromEntries(url.searchParams),
|
||||||
|
origin: detectOrigin(
|
||||||
|
headers["x-forwarded-host"] ?? headers.host,
|
||||||
|
headers["x-forwarded-proto"],
|
||||||
|
),
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return error as Error
|
return error as Error
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {RequestMiddleware, Ctx, createServerPlugin} from "blitz"
|
import {RequestMiddleware, Ctx, createServerPlugin} from "blitz"
|
||||||
import {assert} from "blitz"
|
import {assert} from "blitz"
|
||||||
import {IncomingMessage, ServerResponse} from "http"
|
import type {IncomingMessage, ServerResponse} from "http"
|
||||||
import {PublicData, SessionModel, SessionConfigMethods} from "../shared/types"
|
import {PublicData, SessionModel, SessionConfigMethods} from "../shared/types"
|
||||||
import {getBlitzContext, getSession, useAuthenticatedBlitzContext} from "./auth-sessions"
|
import {getBlitzContext, getSession, useAuthenticatedBlitzContext} from "./auth-sessions"
|
||||||
|
|
||||||
@@ -22,7 +22,9 @@ interface IsAuthorized {
|
|||||||
interface PrismaClientWithSession {
|
interface PrismaClientWithSession {
|
||||||
session: {
|
session: {
|
||||||
findFirst(args?: {where?: {handle?: SessionModel["handle"]}}): Promise<SessionModel | null>
|
findFirst(args?: {where?: {handle?: SessionModel["handle"]}}): Promise<SessionModel | null>
|
||||||
findMany(args?: {where?: {userId?: PublicData["userId"]}}): Promise<SessionModel[]>
|
findMany(args?: {
|
||||||
|
where?: {userId?: PublicData["userId"]; expiresAt?: {gt?: Date}}
|
||||||
|
}): Promise<SessionModel[]>
|
||||||
create(args: {
|
create(args: {
|
||||||
data: SessionModel & {
|
data: SessionModel & {
|
||||||
userId?: any
|
userId?: any
|
||||||
@@ -42,7 +44,7 @@ export const PrismaStorage = <Client extends PrismaClientWithSession>(
|
|||||||
): SessionConfigMethods => {
|
): SessionConfigMethods => {
|
||||||
return {
|
return {
|
||||||
getSession: (handle) => db.session.findFirst({where: {handle}}),
|
getSession: (handle) => db.session.findFirst({where: {handle}}),
|
||||||
getSessions: (userId) => db.session.findMany({where: {userId}}),
|
getSessions: (userId) => db.session.findMany({where: {userId, expiresAt: {gt: new Date()}}}),
|
||||||
createSession: (session) => {
|
createSession: (session) => {
|
||||||
let user
|
let user
|
||||||
if (session.userId) {
|
if (session.userId) {
|
||||||
@@ -128,11 +130,28 @@ export const AuthServerPlugin = createServerPlugin((options: AuthPluginOptions)
|
|||||||
if (!globalThis.__BLITZ_GET_RSC_CONTEXT) {
|
if (!globalThis.__BLITZ_GET_RSC_CONTEXT) {
|
||||||
globalThis.__BLITZ_GET_RSC_CONTEXT = getBlitzContext
|
globalThis.__BLITZ_GET_RSC_CONTEXT = getBlitzContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Handler = (request: Request, context: any, ctx: Ctx) => Promise<Response> | Response
|
||||||
|
function withBlitzAuth<T extends {[method: string]: Handler}>(handlers: T): T {
|
||||||
|
return Object.fromEntries(
|
||||||
|
Object.entries(handlers).map(([method, handler]) => [
|
||||||
|
method,
|
||||||
|
async (request: Request, params: unknown) => {
|
||||||
|
const session = await getSession(request)
|
||||||
|
const response = await handler(request, params, {session})
|
||||||
|
session.setSession(response)
|
||||||
|
return response
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
) as unknown as T
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
requestMiddlewares: [authPluginSessionMiddleware()],
|
requestMiddlewares: [authPluginSessionMiddleware()],
|
||||||
exports: () => ({
|
exports: () => ({
|
||||||
getBlitzContext,
|
getBlitzContext,
|
||||||
useAuthenticatedBlitzContext,
|
useAuthenticatedBlitzContext,
|
||||||
|
withBlitzAuth,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
import {expect, describe, it} from "vitest"
|
|
||||||
import {setCookie} from "./auth-sessions"
|
|
||||||
import cookie from "cookie"
|
|
||||||
import {ServerResponse} from "http"
|
|
||||||
|
|
||||||
describe("blitz-auth", () => {
|
|
||||||
describe("setCookie", () => {
|
|
||||||
it("works with empty start", async () => {
|
|
||||||
const res = new ServerResponse({} as any)
|
|
||||||
setCookie(res, cookie.serialize("A", "a-value", {}))
|
|
||||||
expect(res.getHeader("Set-Cookie")).toBe("A=a-value")
|
|
||||||
})
|
|
||||||
|
|
||||||
it("works with string start", async () => {
|
|
||||||
const res = new ServerResponse({} as any)
|
|
||||||
res.setHeader("Set-Cookie", cookie.serialize("A", "a-value", {}))
|
|
||||||
setCookie(res, cookie.serialize("B", "b-value", {}))
|
|
||||||
expect(res.getHeader("Set-Cookie")).toEqual(["A=a-value", "B=b-value"])
|
|
||||||
})
|
|
||||||
|
|
||||||
it("works with array start for new name", async () => {
|
|
||||||
const res = new ServerResponse({} as any)
|
|
||||||
res.setHeader("Set-Cookie", [
|
|
||||||
cookie.serialize("A", "a-value", {}),
|
|
||||||
cookie.serialize("B", "b-value", {}),
|
|
||||||
])
|
|
||||||
setCookie(res, cookie.serialize("C", "c-value", {}))
|
|
||||||
expect(res.getHeader("Set-Cookie")).toEqual(["A=a-value", "B=b-value", "C=c-value"])
|
|
||||||
})
|
|
||||||
|
|
||||||
it("works with array start for existing name", async () => {
|
|
||||||
const res = new ServerResponse({} as any)
|
|
||||||
res.setHeader("Set-Cookie", [
|
|
||||||
cookie.serialize("A", "a-value", {}),
|
|
||||||
cookie.serialize("B", "b-value", {}),
|
|
||||||
])
|
|
||||||
setCookie(res, cookie.serialize("A", "new-a-value", {}))
|
|
||||||
expect(res.getHeader("Set-Cookie")).toEqual(["A=new-a-value", "B=b-value"])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import {fromBase64, toBase64} from "b64-lite"
|
import {fromBase64, toBase64} from "b64-lite"
|
||||||
import cookie, {parse} from "cookie"
|
import cookie, {parse} from "cookie"
|
||||||
import {IncomingMessage, ServerResponse} from "http"
|
import jsonwebtoken from "jsonwebtoken"
|
||||||
import {sign as jwtSign, verify as jwtVerify} from "jsonwebtoken"
|
|
||||||
import {
|
import {
|
||||||
assert,
|
assert,
|
||||||
isPast,
|
isPast,
|
||||||
@@ -13,9 +12,9 @@ import {
|
|||||||
AuthorizationError,
|
AuthorizationError,
|
||||||
CSRFTokenMismatchError,
|
CSRFTokenMismatchError,
|
||||||
log,
|
log,
|
||||||
|
AuthenticatedCtx,
|
||||||
baseLogger,
|
baseLogger,
|
||||||
chalk,
|
chalk,
|
||||||
AuthenticatedCtx,
|
|
||||||
} from "blitz"
|
} from "blitz"
|
||||||
import {
|
import {
|
||||||
EmptyPublicData,
|
EmptyPublicData,
|
||||||
@@ -39,12 +38,69 @@ import {
|
|||||||
AuthenticatedSessionContext,
|
AuthenticatedSessionContext,
|
||||||
} from "../shared"
|
} from "../shared"
|
||||||
import {generateToken, hash256} from "./auth-utils"
|
import {generateToken, hash256} from "./auth-utils"
|
||||||
import {Socket} from "net"
|
|
||||||
import {UrlObject} from "url"
|
|
||||||
import {formatWithValidation} from "../shared/url-utils"
|
import {formatWithValidation} from "../shared/url-utils"
|
||||||
|
|
||||||
export function isLocalhost(req: any): boolean {
|
import type {UrlObject} from "url"
|
||||||
let {host} = req.headers
|
import type {IncomingMessage, ServerResponse} from "http"
|
||||||
|
|
||||||
|
function splitCookiesString(cookiesString: string) {
|
||||||
|
if (!cookiesString) return []
|
||||||
|
let cookiesStrings = []
|
||||||
|
let pos = 0
|
||||||
|
let start
|
||||||
|
let ch
|
||||||
|
let lastComma
|
||||||
|
let nextStart
|
||||||
|
let cookiesSeparatorFound
|
||||||
|
function skipWhitespace() {
|
||||||
|
while (pos < cookiesString.length && /\s/.test(cookiesString.charAt(pos))) {
|
||||||
|
pos += 1
|
||||||
|
}
|
||||||
|
return pos < cookiesString.length
|
||||||
|
}
|
||||||
|
function notSpecialChar() {
|
||||||
|
ch = cookiesString.charAt(pos)
|
||||||
|
return ch !== "=" && ch !== ";" && ch !== ","
|
||||||
|
}
|
||||||
|
while (pos < cookiesString.length) {
|
||||||
|
start = pos
|
||||||
|
cookiesSeparatorFound = false
|
||||||
|
while (skipWhitespace()) {
|
||||||
|
ch = cookiesString.charAt(pos)
|
||||||
|
if (ch === ",") {
|
||||||
|
lastComma = pos
|
||||||
|
pos += 1
|
||||||
|
skipWhitespace()
|
||||||
|
nextStart = pos
|
||||||
|
while (pos < cookiesString.length && notSpecialChar()) {
|
||||||
|
pos += 1
|
||||||
|
}
|
||||||
|
if (pos < cookiesString.length && cookiesString.charAt(pos) === "=") {
|
||||||
|
cookiesSeparatorFound = true
|
||||||
|
pos = nextStart
|
||||||
|
cookiesStrings.push(cookiesString.substring(start, lastComma))
|
||||||
|
start = pos
|
||||||
|
} else {
|
||||||
|
pos = lastComma + 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pos += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!cookiesSeparatorFound || pos >= cookiesString.length) {
|
||||||
|
cookiesStrings.push(cookiesString.substring(start, cookiesString.length))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cookiesStrings
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isLocalhost(req: IncomingMessage | Request): boolean {
|
||||||
|
let host: string | undefined
|
||||||
|
if (req instanceof Request) {
|
||||||
|
host = req.headers.get("host") || ""
|
||||||
|
} else {
|
||||||
|
host = req.headers.host || ""
|
||||||
|
}
|
||||||
let localhost = false
|
let localhost = false
|
||||||
if (host) {
|
if (host) {
|
||||||
host = host.split(":")[0]
|
host = host.split(":")[0]
|
||||||
@@ -69,7 +125,8 @@ export function getCookieParser(headers: {[key: string]: undefined | string | st
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const debug = require("debug")("blitz:session")
|
import Debug from "debug"
|
||||||
|
const debug = Debug("blitz:session")
|
||||||
|
|
||||||
export interface SimpleRolesIsAuthorized<RoleType = string> {
|
export interface SimpleRolesIsAuthorized<RoleType = string> {
|
||||||
({ctx, args}: {ctx: any; args: [roleOrRoles?: RoleType | RoleType[]]}): boolean
|
({ctx, args}: {ctx: any; args: [roleOrRoles?: RoleType | RoleType[]]}): boolean
|
||||||
@@ -131,14 +188,6 @@ type AuthedSessionKernel = {
|
|||||||
}
|
}
|
||||||
type SessionKernel = AnonSessionKernel | AuthedSessionKernel
|
type SessionKernel = AnonSessionKernel | AuthedSessionKernel
|
||||||
|
|
||||||
function ensureApiRequest(
|
|
||||||
req: IncomingMessage & {[key: string]: any},
|
|
||||||
): asserts req is IncomingMessage & {cookies: {[key: string]: string}} {
|
|
||||||
if (!("cookies" in req)) {
|
|
||||||
// Cookie parser isn't include inside getServerSideProps, so we have to add it
|
|
||||||
req.cookies = getCookieParser(req.headers)()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function ensureMiddlewareResponse(
|
function ensureMiddlewareResponse(
|
||||||
res: ServerResponse & {[key: string]: any},
|
res: ServerResponse & {[key: string]: any},
|
||||||
): asserts res is ServerResponse & {blitzCtx: Ctx} {
|
): asserts res is ServerResponse & {blitzCtx: Ctx} {
|
||||||
@@ -147,71 +196,126 @@ function ensureMiddlewareResponse(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function convertRequestToHeader(req: IncomingMessage | Request): Headers {
|
||||||
|
const headersFromRequest = req.headers
|
||||||
|
if (headersFromRequest instanceof Headers) {
|
||||||
|
return headersFromRequest
|
||||||
|
} else {
|
||||||
|
const headers = new Headers()
|
||||||
|
Object.entries(headersFromRequest).forEach(([key, value]) => {
|
||||||
|
if (value) {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
headers.append(key, value.join(","))
|
||||||
|
} else {
|
||||||
|
headers.append(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return headers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCookiesFromHeader(headers: Headers) {
|
||||||
|
const cookieHeader = headers.get("Cookie")
|
||||||
|
if (cookieHeader) {
|
||||||
|
return cookie.parse(cookieHeader)
|
||||||
|
} else {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getSession(req: Request): Promise<SessionContext>
|
||||||
|
export async function getSession(req: Request, res: never, isRsc: boolean): Promise<SessionContext>
|
||||||
|
export async function getSession(req: IncomingMessage, res: ServerResponse): Promise<SessionContext>
|
||||||
export async function getSession(
|
export async function getSession(
|
||||||
req: IncomingMessage,
|
req: IncomingMessage,
|
||||||
res: ServerResponse,
|
res: ServerResponse,
|
||||||
appDir = false,
|
isRsc: boolean,
|
||||||
|
): Promise<SessionContext>
|
||||||
|
export async function getSession(
|
||||||
|
req: IncomingMessage | Request,
|
||||||
|
res?: ServerResponse,
|
||||||
|
isRsc?: boolean,
|
||||||
): Promise<SessionContext> {
|
): Promise<SessionContext> {
|
||||||
ensureApiRequest(req)
|
const headers = convertRequestToHeader(req)
|
||||||
ensureMiddlewareResponse(res)
|
if (res) {
|
||||||
|
ensureMiddlewareResponse(res)
|
||||||
debug("cookiePrefix", globalThis.__BLITZ_SESSION_COOKIE_PREFIX)
|
debug("cookiePrefix", globalThis.__BLITZ_SESSION_COOKIE_PREFIX)
|
||||||
|
if (res.blitzCtx.session) {
|
||||||
if (res.blitzCtx.session) {
|
debug("Returning existing session")
|
||||||
debug("Returning existing session")
|
return res.blitzCtx.session
|
||||||
return res.blitzCtx.session
|
}
|
||||||
}
|
}
|
||||||
|
const method = req.method
|
||||||
let sessionKernel = await getSessionKernel(req, res)
|
let sessionKernel = await getSessionKernel({headers, method})
|
||||||
|
|
||||||
if (sessionKernel) {
|
if (sessionKernel) {
|
||||||
debug("Got existing session", sessionKernel)
|
debug("Got existing session", sessionKernel)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sessionKernel) {
|
if (!sessionKernel) {
|
||||||
debug("No session found, creating anonymous session")
|
sessionKernel = await createAnonymousSession({headers})
|
||||||
sessionKernel = await createAnonymousSession(req, res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const sessionContext = makeProxyToPublicData(
|
const sessionContext = makeProxyToPublicData(
|
||||||
new SessionContextClass(req, res, sessionKernel, appDir),
|
new SessionContextClass(headers, sessionKernel, !!isRsc, res),
|
||||||
)
|
)
|
||||||
debug("New session context")
|
debug("New session context")
|
||||||
res.blitzCtx.session = sessionContext
|
if (res) {
|
||||||
|
;(res as any).blitzCtx = {
|
||||||
|
session: sessionContext,
|
||||||
|
}
|
||||||
|
sessionContext.setSession(res)
|
||||||
|
}
|
||||||
return sessionContext
|
return sessionContext
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getBlitzContext(): Promise<Ctx> {
|
|
||||||
const {headers, cookies} = await import("next/headers").catch(() => {
|
|
||||||
throw new Error(
|
|
||||||
"getBlitzContext() can only be used in React Server Components in Nextjs 13 or higher",
|
|
||||||
)
|
|
||||||
})
|
|
||||||
const req = new IncomingMessage(new Socket()) as IncomingMessage & {
|
|
||||||
cookies: {[key: string]: string}
|
|
||||||
}
|
|
||||||
req.headers = Object.fromEntries(headers())
|
|
||||||
const csrfToken = cookies().get(COOKIE_CSRF_TOKEN())
|
|
||||||
if (csrfToken) {
|
|
||||||
req.headers[HEADER_CSRF] = csrfToken.value
|
|
||||||
}
|
|
||||||
req.cookies = Object.fromEntries(
|
|
||||||
cookies()
|
|
||||||
.getAll()
|
|
||||||
.map((c: {name: string; value: string}) => [c.name, c.value]),
|
|
||||||
)
|
|
||||||
const res = new ServerResponse(req)
|
|
||||||
const session = await getSession(req, res, true)
|
|
||||||
const ctx: Ctx = {
|
|
||||||
session,
|
|
||||||
}
|
|
||||||
return ctx
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RouteUrlObject extends Pick<UrlObject, "pathname" | "query" | "href"> {
|
interface RouteUrlObject extends Pick<UrlObject, "pathname" | "query" | "href"> {
|
||||||
pathname: string
|
pathname: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const makeProxyToPublicData = <T extends SessionContextClass>(ctxClass: T): T => {
|
||||||
|
return new Proxy(ctxClass, {
|
||||||
|
get(target, prop, receiver) {
|
||||||
|
if (prop in target || prop === "then") {
|
||||||
|
return Reflect.get(target, prop, receiver)
|
||||||
|
} else {
|
||||||
|
return Reflect.get(target.$publicData, prop, receiver)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getBlitzContext(): Promise<Ctx> {
|
||||||
|
try {
|
||||||
|
const {headers, cookies} = require("next/headers")
|
||||||
|
const reqHeader = Object.fromEntries(headers())
|
||||||
|
const csrfToken = cookies().get(COOKIE_CSRF_TOKEN())
|
||||||
|
if (csrfToken) {
|
||||||
|
reqHeader[HEADER_CSRF] = csrfToken.value
|
||||||
|
}
|
||||||
|
const session = await getSession(
|
||||||
|
{
|
||||||
|
headers: new Headers(reqHeader),
|
||||||
|
method: "POST",
|
||||||
|
} as Request,
|
||||||
|
null as never,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
const ctx: Ctx = {
|
||||||
|
session,
|
||||||
|
}
|
||||||
|
return ctx
|
||||||
|
} catch (e) {
|
||||||
|
if ((e as NodeJS.ErrnoException).code === "MODULE_NOT_FOUND") {
|
||||||
|
throw new Error(
|
||||||
|
"Usage of `getBlitzContext` is supported only in next.js 13.0.0 and above. Please upgrade your next.js version.",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function useAuthenticatedBlitzContext({
|
export async function useAuthenticatedBlitzContext({
|
||||||
redirectTo,
|
redirectTo,
|
||||||
redirectAuthenticatedTo,
|
redirectAuthenticatedTo,
|
||||||
@@ -227,70 +331,63 @@ export async function useAuthenticatedBlitzContext({
|
|||||||
})
|
})
|
||||||
const ctx: Ctx = await getBlitzContext()
|
const ctx: Ctx = await getBlitzContext()
|
||||||
const userId = ctx.session.userId
|
const userId = ctx.session.userId
|
||||||
const {redirect} = await import("next/navigation").catch(() => {
|
try {
|
||||||
throw new Error(
|
const {redirect} = require("next/navigation")
|
||||||
"useAuthenticatedBlitzContext() can only be used in React Server Components in Nextjs 13 or higher",
|
if (userId) {
|
||||||
)
|
debug("[useAuthenticatedBlitzContext] User is authenticated")
|
||||||
})
|
if (redirectAuthenticatedTo) {
|
||||||
if (userId) {
|
if (typeof redirectAuthenticatedTo === "function") {
|
||||||
debug("[useAuthenticatedBlitzContext] User is authenticated")
|
redirectAuthenticatedTo = redirectAuthenticatedTo(ctx)
|
||||||
if (redirectAuthenticatedTo) {
|
}
|
||||||
if (typeof redirectAuthenticatedTo === "function") {
|
const redirectUrl =
|
||||||
redirectAuthenticatedTo = redirectAuthenticatedTo(ctx)
|
typeof redirectAuthenticatedTo === "string"
|
||||||
|
? redirectAuthenticatedTo
|
||||||
|
: formatWithValidation(redirectAuthenticatedTo)
|
||||||
|
debug("[useAuthenticatedBlitzContext] Redirecting to", redirectUrl)
|
||||||
|
if (role) {
|
||||||
|
try {
|
||||||
|
ctx.session.$authorize(role)
|
||||||
|
} catch (e) {
|
||||||
|
log.info("Authentication Redirect: " + customChalk.dim(`Role ${role}`), redirectTo)
|
||||||
|
redirect(redirectUrl)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.info("Authentication Redirect: " + customChalk.dim("(Authenticated)"), redirectUrl)
|
||||||
|
redirect(redirectUrl)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const redirectUrl =
|
if (redirectTo && role) {
|
||||||
typeof redirectAuthenticatedTo === "string"
|
debug("[useAuthenticatedBlitzContext] redirectTo and role are both defined.")
|
||||||
? redirectAuthenticatedTo
|
|
||||||
: formatWithValidation(redirectAuthenticatedTo)
|
|
||||||
debug("[useAuthenticatedBlitzContext] Redirecting to", redirectUrl)
|
|
||||||
if (role) {
|
|
||||||
try {
|
try {
|
||||||
ctx.session.$authorize(role)
|
ctx.session.$authorize(role)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.info("Authentication Redirect: " + customChalk.dim(`Role ${role}`), redirectTo)
|
log.error("Authorization Error: " + (e as Error).message)
|
||||||
redirect(redirectUrl)
|
if (typeof redirectTo !== "string") {
|
||||||
|
redirectTo = formatWithValidation(redirectTo)
|
||||||
|
}
|
||||||
|
log.info("Authorization Redirect: " + customChalk.dim(`Role ${role}`), redirectTo)
|
||||||
|
redirect(redirectTo)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
log.info("Authentication Redirect: " + customChalk.dim("(Authenticated)"), redirectUrl)
|
|
||||||
redirect(redirectUrl)
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
if (redirectTo && role) {
|
debug("[useAuthenticatedBlitzContext] User is not authenticated")
|
||||||
debug("[useAuthenticatedBlitzContext] redirectTo and role are both defined.")
|
if (redirectTo) {
|
||||||
try {
|
|
||||||
ctx.session.$authorize(role)
|
|
||||||
} catch (e) {
|
|
||||||
log.error("Authorization Error: " + (e as Error).message)
|
|
||||||
if (typeof redirectTo !== "string") {
|
if (typeof redirectTo !== "string") {
|
||||||
redirectTo = formatWithValidation(redirectTo)
|
redirectTo = formatWithValidation(redirectTo)
|
||||||
}
|
}
|
||||||
log.info("Authorization Redirect: " + customChalk.dim(`Role ${role}`), redirectTo)
|
log.info("Authentication Redirect: " + customChalk.dim("(Not authenticated)"), redirectTo)
|
||||||
redirect(redirectTo)
|
redirect(redirectTo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
return ctx as AuthenticatedCtx
|
||||||
debug("[useAuthenticatedBlitzContext] User is not authenticated")
|
} catch (e) {
|
||||||
if (redirectTo) {
|
if ((e as NodeJS.ErrnoException).code === "MODULE_NOT_FOUND") {
|
||||||
if (typeof redirectTo !== "string") {
|
throw new Error(
|
||||||
redirectTo = formatWithValidation(redirectTo)
|
"Usage of `useAuthenticatedBlitzContext` is supported only in next.js 13.0.0 and above. Please upgrade your next.js version.",
|
||||||
}
|
)
|
||||||
log.info("Authentication Redirect: " + customChalk.dim("(Not authenticated)"), redirectTo)
|
|
||||||
redirect(redirectTo)
|
|
||||||
}
|
}
|
||||||
|
throw e
|
||||||
}
|
}
|
||||||
return ctx as AuthenticatedCtx
|
|
||||||
}
|
|
||||||
|
|
||||||
const makeProxyToPublicData = <T extends SessionContextClass>(ctxClass: T): T => {
|
|
||||||
return new Proxy(ctxClass, {
|
|
||||||
get(target, prop, receiver) {
|
|
||||||
if (prop in target || prop === "then") {
|
|
||||||
return Reflect.get(target, prop, receiver)
|
|
||||||
} else {
|
|
||||||
return Reflect.get(target.$publicData, prop, receiver)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NotSupportedMessage = async (method: string) => {
|
const NotSupportedMessage = async (method: string) => {
|
||||||
@@ -300,21 +397,27 @@ const NotSupportedMessage = async (method: string) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class SessionContextClass implements SessionContext {
|
export class SessionContextClass implements SessionContext {
|
||||||
private _req: IncomingMessage & {cookies: {[key: string]: string}}
|
private _headers: Headers
|
||||||
private _res: ServerResponse & {blitzCtx: Ctx}
|
|
||||||
private _kernel: SessionKernel
|
private _kernel: SessionKernel
|
||||||
private _appDir: boolean
|
private _isRsc: boolean
|
||||||
|
private _response?: ServerResponse
|
||||||
|
|
||||||
constructor(
|
private static headersToIncludeInResponse = [
|
||||||
req: IncomingMessage & {cookies: {[key: string]: string}},
|
HEADER_CSRF,
|
||||||
res: ServerResponse & {blitzCtx: Ctx},
|
HEADER_CSRF_ERROR,
|
||||||
kernel: SessionKernel,
|
HEADER_PUBLIC_DATA_TOKEN,
|
||||||
appDir: boolean,
|
HEADER_SESSION_CREATED,
|
||||||
) {
|
]
|
||||||
this._req = req
|
|
||||||
this._res = res
|
constructor(headers: Headers, kernel: SessionKernel, isRsc: boolean, response?: ServerResponse) {
|
||||||
|
this._headers = headers
|
||||||
this._kernel = kernel
|
this._kernel = kernel
|
||||||
this._appDir = appDir
|
this._isRsc = isRsc
|
||||||
|
this._response = response
|
||||||
|
}
|
||||||
|
|
||||||
|
$antiCSRFToken() {
|
||||||
|
return this._kernel.antiCSRFToken
|
||||||
}
|
}
|
||||||
|
|
||||||
get $handle() {
|
get $handle() {
|
||||||
@@ -342,38 +445,69 @@ export class SessionContextClass implements SessionContext {
|
|||||||
$isAuthorized(...args: IsAuthorizedArgs) {
|
$isAuthorized(...args: IsAuthorizedArgs) {
|
||||||
if (!this.userId) return false
|
if (!this.userId) return false
|
||||||
|
|
||||||
return global.sessionConfig.isAuthorized({ctx: this._res.blitzCtx, args})
|
return global.sessionConfig.isAuthorized({
|
||||||
|
ctx: {
|
||||||
|
session: this as AuthenticatedSessionContext,
|
||||||
|
},
|
||||||
|
args,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
$thisIsAuthorized(...args: IsAuthorizedArgs): this is AuthenticatedSessionContext {
|
$thisIsAuthorized(...args: IsAuthorizedArgs): this is AuthenticatedSessionContext {
|
||||||
return this.$isAuthorized(...args)
|
return this.$isAuthorized(...args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSession(response: Response | ServerResponse) {
|
||||||
|
if (this._isRsc) {
|
||||||
|
void NotSupportedMessage("setSession")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const cookieHeaders = this._headers.get("set-cookie")
|
||||||
|
if (response instanceof Response) {
|
||||||
|
response.headers.set("Set-Cookie", cookieHeaders!)
|
||||||
|
} else {
|
||||||
|
response.setHeader("Set-Cookie", splitCookiesString(cookieHeaders!))
|
||||||
|
}
|
||||||
|
|
||||||
|
const headers = this._headers.entries()
|
||||||
|
for (const [key, value] of headers) {
|
||||||
|
if (SessionContextClass.headersToIncludeInResponse.includes(key)) {
|
||||||
|
if (response instanceof Response) {
|
||||||
|
response.headers.set(key, value)
|
||||||
|
} else {
|
||||||
|
response.setHeader(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async $create(publicData: PublicData, privateData?: Record<any, any>) {
|
async $create(publicData: PublicData, privateData?: Record<any, any>) {
|
||||||
if (this._appDir) {
|
if (this._isRsc) {
|
||||||
void NotSupportedMessage("$create")
|
void NotSupportedMessage("$create")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this._kernel = await createNewSession({
|
this._kernel = await createNewSession({
|
||||||
req: this._req,
|
headers: this._headers,
|
||||||
res: this._res,
|
|
||||||
publicData,
|
publicData,
|
||||||
privateData,
|
privateData,
|
||||||
jwtPayload: this._kernel.jwtPayload,
|
jwtPayload: this._kernel.jwtPayload,
|
||||||
anonymous: false,
|
anonymous: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (this._response) this.setSession(this._response)
|
||||||
}
|
}
|
||||||
|
|
||||||
async $revoke() {
|
async $revoke() {
|
||||||
if (this._appDir) {
|
if (this._isRsc) {
|
||||||
void NotSupportedMessage("$revoke")
|
void NotSupportedMessage("$revoke")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this._kernel = await revokeSession(this._req, this._res, this.$handle)
|
this._kernel = await revokeSession(this._headers, this.$handle)
|
||||||
|
if (this._response) this.setSession(this._response)
|
||||||
}
|
}
|
||||||
|
|
||||||
async $revokeAll() {
|
async $revokeAll() {
|
||||||
if (this._appDir) {
|
if (this._isRsc) {
|
||||||
void NotSupportedMessage("$revokeAll")
|
void NotSupportedMessage("$revokeAll")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -385,25 +519,28 @@ export class SessionContextClass implements SessionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async $setPublicData(data: Record<any, any>) {
|
async $setPublicData(data: Record<any, any>) {
|
||||||
if (this._appDir) {
|
if (this._isRsc) {
|
||||||
void NotSupportedMessage("$setPublicData")
|
void NotSupportedMessage("$setPublicData")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (this.userId) {
|
if (this.userId) {
|
||||||
await syncPubicDataFieldsForUserIfNeeded(this.userId, data)
|
await syncPubicDataFieldsForUserIfNeeded(this.userId, data)
|
||||||
}
|
}
|
||||||
this._kernel.publicData = await setPublicData(this._req, this._res, this._kernel, data)
|
this._kernel.publicData = await setPublicData(this._headers, this._kernel, data)
|
||||||
|
if (this._response) this.setSession(this._response)
|
||||||
}
|
}
|
||||||
|
|
||||||
async $getPrivateData() {
|
async $getPrivateData() {
|
||||||
return (await getPrivateData(this.$handle)) || {}
|
return (await getPrivateData(this.$handle)) || {}
|
||||||
}
|
}
|
||||||
$setPrivateData(data: Record<any, any>) {
|
|
||||||
if (this._appDir) {
|
async $setPrivateData(data: Record<any, any>) {
|
||||||
|
if (this._isRsc) {
|
||||||
void NotSupportedMessage("$setPrivateData")
|
void NotSupportedMessage("$setPrivateData")
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
return setPrivateData(this._kernel, data)
|
await setPrivateData(this._kernel, data)
|
||||||
|
if (this._response) this.setSession(this._response)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,7 +632,7 @@ const JWT_ANONYMOUS_SUBJECT = "anonymous"
|
|||||||
const JWT_ALGORITHM = "HS256"
|
const JWT_ALGORITHM = "HS256"
|
||||||
|
|
||||||
const createAnonymousSessionToken = (payload: AnonymousSessionPayload) => {
|
const createAnonymousSessionToken = (payload: AnonymousSessionPayload) => {
|
||||||
return jwtSign({[JWT_NAMESPACE]: payload}, getSessionSecretKey() || "", {
|
return jsonwebtoken.sign({[JWT_NAMESPACE]: payload}, getSessionSecretKey() || "", {
|
||||||
algorithm: JWT_ALGORITHM,
|
algorithm: JWT_ALGORITHM,
|
||||||
issuer: JWT_ISSUER,
|
issuer: JWT_ISSUER,
|
||||||
audience: JWT_AUDIENCE,
|
audience: JWT_AUDIENCE,
|
||||||
@@ -509,7 +646,7 @@ const parseAnonymousSessionToken = (token: string) => {
|
|||||||
const secret = getSessionSecretKey()
|
const secret = getSessionSecretKey()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const fullPayload = jwtVerify(token, secret!, {
|
const fullPayload = jsonwebtoken.verify(token, secret!, {
|
||||||
algorithms: [JWT_ALGORITHM],
|
algorithms: [JWT_ALGORITHM],
|
||||||
issuer: JWT_ISSUER,
|
issuer: JWT_ISSUER,
|
||||||
audience: JWT_AUDIENCE,
|
audience: JWT_AUDIENCE,
|
||||||
@@ -526,136 +663,127 @@ const parseAnonymousSessionToken = (token: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const setCookie = (res: ServerResponse, cookieStr: string) => {
|
const cookieOptions = (headers: Headers, expires: Date, httpOnly: boolean) => {
|
||||||
const getCookieName = (c: string) => c.split("=", 2)[0]
|
return {
|
||||||
const appendCookie = () => append(res, "Set-Cookie", cookieStr)
|
path: "/",
|
||||||
|
secure:
|
||||||
const cookiesHeader = res.getHeader("Set-Cookie")
|
global.sessionConfig.secureCookies &&
|
||||||
const cookieName = getCookieName(cookieStr)
|
!isLocalhost({
|
||||||
|
headers,
|
||||||
if (typeof cookiesHeader !== "string" && !Array.isArray(cookiesHeader)) {
|
} as Request),
|
||||||
appendCookie()
|
sameSite: global.sessionConfig.sameSite,
|
||||||
return
|
domain: global.sessionConfig.domain,
|
||||||
|
expires: new Date(expires),
|
||||||
|
httpOnly,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof cookiesHeader === "string") {
|
function replaceOrAppendValueInSetCookieHeader(
|
||||||
if (cookieName === getCookieName(cookiesHeader)) {
|
headers: Headers,
|
||||||
res.setHeader("Set-Cookie", cookieStr)
|
cookieName: string,
|
||||||
|
newValue: string,
|
||||||
|
): string {
|
||||||
|
const cookies = headers.get("set-cookie")
|
||||||
|
if (!cookies) return newValue
|
||||||
|
const cookiesAsArray = splitCookiesString(cookies!)
|
||||||
|
for (let i = 0; i < cookiesAsArray.length; i++) {
|
||||||
|
const cookie = cookiesAsArray[i]
|
||||||
|
if (cookie?.startsWith(cookieName)) {
|
||||||
|
cookiesAsArray[i] = newValue
|
||||||
|
return cookiesAsArray.join(", ")
|
||||||
} else {
|
} else {
|
||||||
appendCookie()
|
if (i === cookiesAsArray.length - 1) {
|
||||||
}
|
cookiesAsArray.push(newValue)
|
||||||
} else {
|
return cookiesAsArray.join(", ")
|
||||||
for (let i = 0; i < cookiesHeader.length; i++) {
|
|
||||||
if (cookieName === getCookieName(cookiesHeader[i] || "")) {
|
|
||||||
cookiesHeader[i] = cookieStr
|
|
||||||
res.setHeader("Set-Cookie", cookiesHeader)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
appendCookie()
|
|
||||||
}
|
}
|
||||||
|
return cookiesAsArray.filter(Boolean).join(", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
const setHeader = (res: ServerResponse, name: string, value: string) => {
|
const setSessionCookie = (headers: Headers, sessionToken: string, expiresAt: Date) => {
|
||||||
res.setHeader(name, value)
|
const sessionCookie = cookie.serialize(
|
||||||
if ("_blitz" in res) {
|
COOKIE_SESSION_TOKEN(),
|
||||||
;(res as any)._blitz[name] = value
|
sessionToken,
|
||||||
}
|
cookieOptions(headers, expiresAt, true),
|
||||||
}
|
|
||||||
|
|
||||||
const setSessionCookie = (
|
|
||||||
req: IncomingMessage,
|
|
||||||
res: ServerResponse,
|
|
||||||
sessionToken: string,
|
|
||||||
expiresAt: Date,
|
|
||||||
) => {
|
|
||||||
setCookie(
|
|
||||||
res,
|
|
||||||
cookie.serialize(COOKIE_SESSION_TOKEN(), sessionToken, {
|
|
||||||
path: "/",
|
|
||||||
httpOnly: true,
|
|
||||||
secure: global.sessionConfig.secureCookies && !isLocalhost(req),
|
|
||||||
sameSite: global.sessionConfig.sameSite,
|
|
||||||
domain: global.sessionConfig.domain,
|
|
||||||
expires: expiresAt,
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
}
|
const newCookies = replaceOrAppendValueInSetCookieHeader(
|
||||||
|
headers,
|
||||||
const setAnonymousSessionCookie = (
|
COOKIE_SESSION_TOKEN(),
|
||||||
req: IncomingMessage,
|
sessionCookie,
|
||||||
res: ServerResponse,
|
|
||||||
token: string,
|
|
||||||
expiresAt: Date,
|
|
||||||
) => {
|
|
||||||
setCookie(
|
|
||||||
res,
|
|
||||||
cookie.serialize(COOKIE_ANONYMOUS_SESSION_TOKEN(), token, {
|
|
||||||
path: "/",
|
|
||||||
httpOnly: true,
|
|
||||||
secure: global.sessionConfig.secureCookies && !isLocalhost(req),
|
|
||||||
sameSite: global.sessionConfig.sameSite,
|
|
||||||
domain: global.sessionConfig.domain,
|
|
||||||
expires: expiresAt,
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
|
headers.set("Set-Cookie", newCookies)
|
||||||
}
|
}
|
||||||
|
|
||||||
const setCSRFCookie = (
|
const setAnonymousSessionCookie = (headers: Headers, token: string, expiresAt: Date) => {
|
||||||
req: IncomingMessage,
|
const anonCookie = cookie.serialize(
|
||||||
res: ServerResponse,
|
COOKIE_ANONYMOUS_SESSION_TOKEN(),
|
||||||
antiCSRFToken: string,
|
token,
|
||||||
expiresAt: Date,
|
cookieOptions(headers, expiresAt, true),
|
||||||
) => {
|
)
|
||||||
|
const newCookies = replaceOrAppendValueInSetCookieHeader(
|
||||||
|
headers,
|
||||||
|
COOKIE_ANONYMOUS_SESSION_TOKEN(),
|
||||||
|
anonCookie,
|
||||||
|
)
|
||||||
|
headers.set("Set-Cookie", newCookies)
|
||||||
|
}
|
||||||
|
|
||||||
|
const setCSRFCookie = (headers: Headers, antiCSRFToken: string, expiresAt: Date) => {
|
||||||
debug("setCSRFCookie", antiCSRFToken)
|
debug("setCSRFCookie", antiCSRFToken)
|
||||||
assert(antiCSRFToken !== undefined, "Internal error: antiCSRFToken is being set to undefined")
|
assert(antiCSRFToken !== undefined, "Internal error: antiCSRFToken is being set to undefined")
|
||||||
setCookie(
|
const csrfCookie = cookie.serialize(
|
||||||
res,
|
COOKIE_CSRF_TOKEN(),
|
||||||
cookie.serialize(COOKIE_CSRF_TOKEN(), antiCSRFToken, {
|
antiCSRFToken,
|
||||||
path: "/",
|
cookieOptions(headers, expiresAt, false),
|
||||||
secure: global.sessionConfig.secureCookies && !isLocalhost(req),
|
|
||||||
sameSite: global.sessionConfig.sameSite,
|
|
||||||
domain: global.sessionConfig.domain,
|
|
||||||
expires: expiresAt,
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const newCookies = replaceOrAppendValueInSetCookieHeader(headers, COOKIE_CSRF_TOKEN(), csrfCookie)
|
||||||
|
headers.set("Set-Cookie", newCookies)
|
||||||
}
|
}
|
||||||
|
|
||||||
const setPublicDataCookie = (
|
const setPublicDataCookie = (headers: Headers, publicDataToken: string, expiresAt: Date) => {
|
||||||
req: IncomingMessage,
|
headers.set(HEADER_PUBLIC_DATA_TOKEN, "updated")
|
||||||
res: ServerResponse,
|
const publicDataCookie = cookie.serialize(
|
||||||
publicDataToken: string,
|
COOKIE_PUBLIC_DATA_TOKEN(),
|
||||||
expiresAt: Date,
|
publicDataToken,
|
||||||
) => {
|
cookieOptions(headers, expiresAt, false),
|
||||||
setHeader(res, HEADER_PUBLIC_DATA_TOKEN, "updated")
|
|
||||||
setCookie(
|
|
||||||
res,
|
|
||||||
cookie.serialize(COOKIE_PUBLIC_DATA_TOKEN(), publicDataToken, {
|
|
||||||
path: "/",
|
|
||||||
secure: global.sessionConfig.secureCookies && !isLocalhost(req),
|
|
||||||
sameSite: global.sessionConfig.sameSite,
|
|
||||||
domain: global.sessionConfig.domain,
|
|
||||||
expires: expiresAt,
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
|
const newCookies = replaceOrAppendValueInSetCookieHeader(
|
||||||
|
headers,
|
||||||
|
COOKIE_PUBLIC_DATA_TOKEN(),
|
||||||
|
publicDataCookie,
|
||||||
|
)
|
||||||
|
headers.set("Set-Cookie", newCookies)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------
|
// --------------------------------
|
||||||
// Get Session
|
// Get Session
|
||||||
// --------------------------------
|
// --------------------------------
|
||||||
async function getSessionKernel(
|
async function getSessionKernel({
|
||||||
req: IncomingMessage & {cookies: {[key: string]: string}},
|
headers,
|
||||||
res: ServerResponse,
|
method,
|
||||||
): Promise<SessionKernel | null> {
|
}: {
|
||||||
const anonymousSessionToken = req.cookies[COOKIE_ANONYMOUS_SESSION_TOKEN()]
|
headers: Headers
|
||||||
const sessionToken = req.cookies[COOKIE_SESSION_TOKEN()] // for essential method
|
method: string | undefined
|
||||||
const idRefreshToken = req.cookies[COOKIE_REFRESH_TOKEN()] // for advanced method
|
}): Promise<SessionKernel | null> {
|
||||||
|
const cookies = getCookiesFromHeader(headers)
|
||||||
|
const anonymousSessionToken = cookies[COOKIE_ANONYMOUS_SESSION_TOKEN()]
|
||||||
|
const sessionToken = cookies[COOKIE_SESSION_TOKEN()] // for essential method
|
||||||
|
const idRefreshToken = cookies[COOKIE_REFRESH_TOKEN()] // for advanced method
|
||||||
|
const antiCSRFToken = headers.get(HEADER_CSRF)
|
||||||
|
debug("getSessionKernel", {
|
||||||
|
anonymousSessionToken,
|
||||||
|
sessionToken,
|
||||||
|
idRefreshToken,
|
||||||
|
antiCSRFToken,
|
||||||
|
})
|
||||||
|
|
||||||
const enableCsrfProtection =
|
const enableCsrfProtection =
|
||||||
req.method !== "GET" &&
|
method !== "GET" &&
|
||||||
req.method !== "OPTIONS" &&
|
method !== "OPTIONS" &&
|
||||||
req.method !== "HEAD" &&
|
method !== "HEAD" &&
|
||||||
!process.env.DANGEROUSLY_DISABLE_CSRF_PROTECTION
|
!process.env.DANGEROUSLY_DISABLE_CSRF_PROTECTION
|
||||||
const antiCSRFToken = req.headers[HEADER_CSRF] as string | undefined
|
|
||||||
|
|
||||||
if (sessionToken) {
|
if (sessionToken) {
|
||||||
debug("[getSessionKernel] Request has sessionToken")
|
debug("[getSessionKernel] Request has sessionToken")
|
||||||
@@ -698,7 +826,7 @@ async function getSessionKernel(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
setHeader(res, HEADER_CSRF_ERROR, "true")
|
headers.set(HEADER_CSRF_ERROR, "true")
|
||||||
throw new CSRFTokenMismatchError()
|
throw new CSRFTokenMismatchError()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -710,7 +838,7 @@ async function getSessionKernel(
|
|||||||
* But only renew with non-GET requests because a GET request could be from a
|
* But only renew with non-GET requests because a GET request could be from a
|
||||||
* browser level navigation
|
* browser level navigation
|
||||||
*/
|
*/
|
||||||
if (req.method !== "GET") {
|
if (method !== "GET") {
|
||||||
// The publicData in the DB could have been updated since this client last made
|
// The publicData in the DB could have been updated since this client last made
|
||||||
// a request. If so, then we generate a new access token
|
// a request. If so, then we generate a new access token
|
||||||
const hasPublicDataChanged =
|
const hasPublicDataChanged =
|
||||||
@@ -733,8 +861,7 @@ async function getSessionKernel(
|
|||||||
|
|
||||||
if (hasPublicDataChanged || hasQuarterExpiryTimePassed) {
|
if (hasPublicDataChanged || hasQuarterExpiryTimePassed) {
|
||||||
await refreshSession(
|
await refreshSession(
|
||||||
req,
|
headers,
|
||||||
res,
|
|
||||||
{
|
{
|
||||||
handle,
|
handle,
|
||||||
publicData: JSON.parse(persistedSession.publicData || ""),
|
publicData: JSON.parse(persistedSession.publicData || ""),
|
||||||
@@ -774,7 +901,7 @@ async function getSessionKernel(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
setHeader(res, HEADER_CSRF_ERROR, "true")
|
headers.set(HEADER_CSRF_ERROR, "true")
|
||||||
throw new CSRFTokenMismatchError()
|
throw new CSRFTokenMismatchError()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -795,16 +922,14 @@ async function getSessionKernel(
|
|||||||
// Create Session
|
// Create Session
|
||||||
// --------------------------------
|
// --------------------------------
|
||||||
interface CreateNewAnonSession {
|
interface CreateNewAnonSession {
|
||||||
req: IncomingMessage
|
headers: Headers
|
||||||
res: ServerResponse
|
|
||||||
publicData: EmptyPublicData
|
publicData: EmptyPublicData
|
||||||
privateData?: Record<any, any>
|
privateData?: Record<any, any>
|
||||||
anonymous: true
|
anonymous: true
|
||||||
jwtPayload?: JwtPayload
|
jwtPayload?: JwtPayload
|
||||||
}
|
}
|
||||||
interface CreateNewAuthedSession {
|
interface CreateNewAuthedSession {
|
||||||
req: IncomingMessage
|
headers: Headers
|
||||||
res: ServerResponse
|
|
||||||
publicData: PublicData
|
publicData: PublicData
|
||||||
privateData?: Record<any, any>
|
privateData?: Record<any, any>
|
||||||
anonymous: false
|
anonymous: false
|
||||||
@@ -814,7 +939,6 @@ interface CreateNewAuthedSession {
|
|||||||
async function createNewSession(
|
async function createNewSession(
|
||||||
args: CreateNewAnonSession | CreateNewAuthedSession,
|
args: CreateNewAnonSession | CreateNewAuthedSession,
|
||||||
): Promise<SessionKernel> {
|
): Promise<SessionKernel> {
|
||||||
const {req, res} = args
|
|
||||||
assert(args.publicData.userId !== undefined, "You must provide publicData.userId")
|
assert(args.publicData.userId !== undefined, "You must provide publicData.userId")
|
||||||
|
|
||||||
const antiCSRFToken = createAntiCSRFToken()
|
const antiCSRFToken = createAntiCSRFToken()
|
||||||
@@ -835,12 +959,12 @@ async function createNewSession(
|
|||||||
new Date(),
|
new Date(),
|
||||||
global.sessionConfig.anonSessionExpiryMinutes as number,
|
global.sessionConfig.anonSessionExpiryMinutes as number,
|
||||||
)
|
)
|
||||||
setAnonymousSessionCookie(req, res, anonymousSessionToken, expiresAt)
|
setAnonymousSessionCookie(args.headers, anonymousSessionToken, expiresAt)
|
||||||
setCSRFCookie(req, res, antiCSRFToken, expiresAt)
|
setCSRFCookie(args.headers, antiCSRFToken, expiresAt)
|
||||||
setPublicDataCookie(req, res, publicDataToken, expiresAt)
|
setPublicDataCookie(args.headers, publicDataToken, expiresAt)
|
||||||
// Clear the essential session cookie in case it was previously set
|
// Clear the essential session cookie in case it was previously set
|
||||||
setSessionCookie(req, res, "", new Date(0))
|
setSessionCookie(args.headers, "", new Date(0))
|
||||||
setHeader(res, HEADER_SESSION_CREATED, "true")
|
args.headers.set(HEADER_SESSION_CREATED, "true")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handle,
|
handle,
|
||||||
@@ -891,12 +1015,13 @@ async function createNewSession(
|
|||||||
privateData: JSON.stringify(newPrivateData),
|
privateData: JSON.stringify(newPrivateData),
|
||||||
})
|
})
|
||||||
|
|
||||||
setSessionCookie(req, res, sessionToken, expiresAt)
|
setSessionCookie(args.headers, sessionToken, expiresAt)
|
||||||
setCSRFCookie(req, res, antiCSRFToken, expiresAt)
|
debug("Session created", {handle, publicData: newPublicData, expiresAt})
|
||||||
setPublicDataCookie(req, res, publicDataToken, expiresAt)
|
setCSRFCookie(args.headers, antiCSRFToken, expiresAt)
|
||||||
|
setPublicDataCookie(args.headers, publicDataToken, expiresAt)
|
||||||
// Clear the anonymous session cookie in case it was previously set
|
// Clear the anonymous session cookie in case it was previously set
|
||||||
setAnonymousSessionCookie(req, res, "", new Date(0))
|
setAnonymousSessionCookie(args.headers, "", new Date(0))
|
||||||
setHeader(res, HEADER_SESSION_CREATED, "true")
|
args.headers.set(HEADER_SESSION_CREATED, "true")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
handle,
|
handle,
|
||||||
@@ -914,10 +1039,9 @@ async function createNewSession(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createAnonymousSession(req: IncomingMessage, res: ServerResponse) {
|
async function createAnonymousSession({headers}: {headers: Headers}) {
|
||||||
return await createNewSession({
|
return await createNewSession({
|
||||||
req,
|
headers,
|
||||||
res,
|
|
||||||
publicData: {userId: null},
|
publicData: {userId: null},
|
||||||
anonymous: true,
|
anonymous: true,
|
||||||
})
|
})
|
||||||
@@ -928,8 +1052,7 @@ async function createAnonymousSession(req: IncomingMessage, res: ServerResponse)
|
|||||||
// --------------------------------
|
// --------------------------------
|
||||||
|
|
||||||
async function refreshSession(
|
async function refreshSession(
|
||||||
req: IncomingMessage,
|
headers: Headers,
|
||||||
res: ServerResponse,
|
|
||||||
sessionKernel: SessionKernel,
|
sessionKernel: SessionKernel,
|
||||||
{publicDataChanged}: {publicDataChanged: boolean},
|
{publicDataChanged}: {publicDataChanged: boolean},
|
||||||
) {
|
) {
|
||||||
@@ -943,8 +1066,8 @@ async function refreshSession(
|
|||||||
const publicDataToken = createPublicDataToken(sessionKernel.publicData)
|
const publicDataToken = createPublicDataToken(sessionKernel.publicData)
|
||||||
|
|
||||||
const expiresAt = addYears(new Date(), 30)
|
const expiresAt = addYears(new Date(), 30)
|
||||||
setAnonymousSessionCookie(req, res, anonymousSessionToken, expiresAt)
|
setAnonymousSessionCookie(headers, anonymousSessionToken, expiresAt)
|
||||||
setPublicDataCookie(req, res, publicDataToken, expiresAt)
|
setPublicDataCookie(headers, publicDataToken, expiresAt)
|
||||||
} else if (global.sessionConfig.method === "essential" && "sessionToken" in sessionKernel) {
|
} else if (global.sessionConfig.method === "essential" && "sessionToken" in sessionKernel) {
|
||||||
const expiresAt = addMinutes(new Date(), global.sessionConfig.sessionExpiryMinutes as number)
|
const expiresAt = addMinutes(new Date(), global.sessionConfig.sessionExpiryMinutes as number)
|
||||||
|
|
||||||
@@ -952,7 +1075,7 @@ async function refreshSession(
|
|||||||
if (publicDataChanged) {
|
if (publicDataChanged) {
|
||||||
debug("Public data has changed")
|
debug("Public data has changed")
|
||||||
const publicDataToken = createPublicDataToken(sessionKernel.publicData)
|
const publicDataToken = createPublicDataToken(sessionKernel.publicData)
|
||||||
setPublicDataCookie(req, res, publicDataToken, expiresAt)
|
setPublicDataCookie(headers, publicDataToken, expiresAt)
|
||||||
await global.sessionConfig.updateSession(sessionKernel.handle, {
|
await global.sessionConfig.updateSession(sessionKernel.handle, {
|
||||||
expiresAt,
|
expiresAt,
|
||||||
publicData: JSON.stringify(sessionKernel.publicData),
|
publicData: JSON.stringify(sessionKernel.publicData),
|
||||||
@@ -994,12 +1117,7 @@ async function syncPubicDataFieldsForUserIfNeeded(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function revokeSession(
|
async function revokeSession(headers: Headers, handle: string, anonymous: boolean = false) {
|
||||||
req: IncomingMessage,
|
|
||||||
res: ServerResponse,
|
|
||||||
handle: string,
|
|
||||||
anonymous: boolean = false,
|
|
||||||
) {
|
|
||||||
debug("Revoking session", handle)
|
debug("Revoking session", handle)
|
||||||
if (!anonymous) {
|
if (!anonymous) {
|
||||||
try {
|
try {
|
||||||
@@ -1012,7 +1130,9 @@ async function revokeSession(
|
|||||||
// This fixes race condition where all client side queries get refreshed
|
// This fixes race condition where all client side queries get refreshed
|
||||||
// in parallel and each creates a new anon session
|
// in parallel and each creates a new anon session
|
||||||
// https://github.com/blitz-js/blitz/issues/2746
|
// https://github.com/blitz-js/blitz/issues/2746
|
||||||
return createAnonymousSession(req, res)
|
return createAnonymousSession({
|
||||||
|
headers,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function revokeAllSessionsForUser(userId: PublicData["userId"]) {
|
async function revokeAllSessionsForUser(userId: PublicData["userId"]) {
|
||||||
@@ -1078,8 +1198,7 @@ async function setPrivateData(sessionKernel: SessionKernel, data: Record<any, an
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function setPublicData(
|
async function setPublicData(
|
||||||
req: IncomingMessage,
|
headers: Headers,
|
||||||
res: ServerResponse,
|
|
||||||
sessionKernel: SessionKernel,
|
sessionKernel: SessionKernel,
|
||||||
data: Record<any, any>,
|
data: Record<any, any>,
|
||||||
) {
|
) {
|
||||||
@@ -1091,7 +1210,7 @@ async function setPublicData(
|
|||||||
...data,
|
...data,
|
||||||
} as PublicData
|
} as PublicData
|
||||||
|
|
||||||
await refreshSession(req, res, {...sessionKernel, publicData}, {publicDataChanged: true})
|
await refreshSession(headers, {...sessionKernel, publicData}, {publicDataChanged: true})
|
||||||
return publicData
|
return publicData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ export {
|
|||||||
getSession,
|
getSession,
|
||||||
isLocalhost,
|
isLocalhost,
|
||||||
setPublicDataForUser,
|
setPublicDataForUser,
|
||||||
setCookie,
|
|
||||||
simpleRolesIsAuthorized,
|
simpleRolesIsAuthorized,
|
||||||
getBlitzContext,
|
|
||||||
} from "./auth-sessions"
|
} from "./auth-sessions"
|
||||||
export type {AnonymousSessionPayload, SimpleRolesIsAuthorized} from "./auth-sessions"
|
export type {AnonymousSessionPayload, SimpleRolesIsAuthorized} from "./auth-sessions"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
//@ts-nocheck
|
//@ts-nocheck
|
||||||
import {Ctx} from "blitz"
|
import type {Ctx} from "blitz"
|
||||||
|
import type {ServerResponse} from "http"
|
||||||
|
|
||||||
export interface Session {
|
export interface Session {
|
||||||
// isAuthorize can be injected here
|
// isAuthorize can be injected here
|
||||||
@@ -66,6 +67,12 @@ export interface SessionContextBase {
|
|||||||
$getPrivateData: () => Promise<Record<any, any>>
|
$getPrivateData: () => Promise<Record<any, any>>
|
||||||
$setPrivateData: (data: Record<any, any>) => Promise<void>
|
$setPrivateData: (data: Record<any, any>) => Promise<void>
|
||||||
$setPublicData: (data: Partial<Omit<PublicData, "userId">>) => Promise<void>
|
$setPublicData: (data: Partial<Omit<PublicData, "userId">>) => Promise<void>
|
||||||
|
/**
|
||||||
|
* This function is only for manual session handling
|
||||||
|
*
|
||||||
|
* Instead use {@link https://blitzjs.com/docs/auth-server#with-blitz-auth-api withBlitzAuth} to handle session creation and update
|
||||||
|
*/
|
||||||
|
setSession: (res: Response | ServerResponse) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
// Could be anonymous
|
// Could be anonymous
|
||||||
|
|||||||
@@ -1,5 +1,152 @@
|
|||||||
# @blitzjs/next
|
# @blitzjs/next
|
||||||
|
|
||||||
|
## 2.1.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- blitz@2.1.2
|
||||||
|
- @blitzjs/rpc@2.1.2
|
||||||
|
|
||||||
|
## 2.1.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [9a0ba87d1]
|
||||||
|
- @blitzjs/rpc@2.1.1
|
||||||
|
- blitz@2.1.1
|
||||||
|
|
||||||
|
## 2.1.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 3b10b13e6: feat: add blitz auth support for the Web `Request` API standard
|
||||||
|
|
||||||
|
Usage using the new `withBlitzAuth` adapter in the App Router:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import {withBlitzAuth} from "app/blitz-server"
|
||||||
|
|
||||||
|
export const {POST} = withBlitzAuth({
|
||||||
|
POST: async (_request, _params, ctx) => {
|
||||||
|
const session = ctx.session
|
||||||
|
await session.$revoke()
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
userId: session.userId,
|
||||||
|
}),
|
||||||
|
{status: 200},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
feat: New Blitz RPC handler meant to with the next.js app router `route.ts` files
|
||||||
|
|
||||||
|
Usage using the new `rpcAppHandler` function
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// app/api/rpc/[[...blitz]]/route.ts
|
||||||
|
import {rpcAppHandler} from "@blitzjs/rpc"
|
||||||
|
import {withBlitzAuth} from "app/blitz-server"
|
||||||
|
|
||||||
|
// Usage with blitz auth
|
||||||
|
export const {GET, POST, HEAD} = withBlitzAuth(rpcAppHandler())
|
||||||
|
|
||||||
|
// Standalone usage
|
||||||
|
export const {GET, POST, HEAD} = rpcAppHandler()
|
||||||
|
```
|
||||||
|
|
||||||
|
chore: Update the app directory starter
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [d53da39cb]
|
||||||
|
- Updated dependencies [3b10b13e6]
|
||||||
|
- blitz@2.1.0
|
||||||
|
- @blitzjs/rpc@2.1.0
|
||||||
|
|
||||||
|
## 2.0.10
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [318e9740d]
|
||||||
|
- blitz@2.0.10
|
||||||
|
- @blitzjs/rpc@2.0.10
|
||||||
|
|
||||||
|
## 2.0.9
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 5a14306f7: fix export `enhancePrisma` in client
|
||||||
|
- Updated dependencies [5a14306f7]
|
||||||
|
- @blitzjs/rpc@2.0.9
|
||||||
|
- blitz@2.0.9
|
||||||
|
|
||||||
|
## 2.0.8
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 5e61a1681: bug: merge existing and custom blitz turbo configs
|
||||||
|
- Updated dependencies [5e61a1681]
|
||||||
|
- Updated dependencies [77555468f]
|
||||||
|
- blitz@2.0.8
|
||||||
|
- @blitzjs/rpc@2.0.8
|
||||||
|
|
||||||
|
## 2.0.7
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- ee7bf87ec: Turbopack support for Blitz
|
||||||
|
|
||||||
|
This PR includes the changes required to make the Blitz loaders work with Turbopack.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm blitz dev --turbo
|
||||||
|
```
|
||||||
|
|
||||||
|
- Updated dependencies [ee7bf87ec]
|
||||||
|
- Updated dependencies [178c152b2]
|
||||||
|
- blitz@2.0.7
|
||||||
|
- @blitzjs/rpc@2.0.7
|
||||||
|
|
||||||
|
## 2.0.6
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [76a2544f9]
|
||||||
|
- blitz@2.0.6
|
||||||
|
- @blitzjs/rpc@2.0.6
|
||||||
|
|
||||||
|
## 2.0.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [6f54841b7]
|
||||||
|
- blitz@2.0.5
|
||||||
|
- @blitzjs/rpc@2.0.5
|
||||||
|
|
||||||
|
## 2.0.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 28a79040e: feat: export `BlitzServerMiddleware` from blitz-next with stronger types
|
||||||
|
- Updated dependencies [dd604c767]
|
||||||
|
- Updated dependencies [28a79040e]
|
||||||
|
- blitz@2.0.4
|
||||||
|
- @blitzjs/rpc@2.0.4
|
||||||
|
|
||||||
|
## 2.0.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 2f5c8a3a0: Address missing sodium native prebuilds required to use secure-password during server rendering
|
||||||
|
- Updated dependencies [2f5c8a3a0]
|
||||||
|
- @blitzjs/rpc@2.0.3
|
||||||
|
- blitz@2.0.3
|
||||||
|
|
||||||
## 2.0.2
|
## 2.0.2
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@blitzjs/next",
|
"name": "@blitzjs/next",
|
||||||
"version": "2.0.2",
|
"version": "2.1.2",
|
||||||
"homepage": "https://blitzjs.com/",
|
"homepage": "https://blitzjs.com/",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -29,8 +29,9 @@
|
|||||||
"eslint.js"
|
"eslint.js"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/rpc": "2.0.2",
|
"@blitzjs/rpc": "2.1.2",
|
||||||
"@types/hoist-non-react-statics": "3.3.1",
|
"@types/hoist-non-react-statics": "3.3.1",
|
||||||
|
"copy-webpack-plugin": "11.0.0",
|
||||||
"debug": "4.3.3",
|
"debug": "4.3.3",
|
||||||
"fs-extra": "10.0.1",
|
"fs-extra": "10.0.1",
|
||||||
"hoist-non-react-statics": "3.3.2",
|
"hoist-non-react-statics": "3.3.2",
|
||||||
@@ -38,13 +39,13 @@
|
|||||||
"supports-color": "8.1.1"
|
"supports-color": "8.1.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"next": "*",
|
"next": "*",
|
||||||
"react": "*",
|
"react": "*",
|
||||||
"tslog": "4.9.0"
|
"tslog": "4.9.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@testing-library/dom": "8.13.0",
|
"@testing-library/dom": "8.13.0",
|
||||||
"@testing-library/jest-dom": "5.16.3",
|
"@testing-library/jest-dom": "5.16.3",
|
||||||
"@testing-library/react": "13.4.0",
|
"@testing-library/react": "13.4.0",
|
||||||
@@ -55,10 +56,10 @@
|
|||||||
"@types/react": "18.0.25",
|
"@types/react": "18.0.25",
|
||||||
"@types/react-dom": "17.0.14",
|
"@types/react-dom": "17.0.14",
|
||||||
"@types/testing-library__react-hooks": "4.0.0",
|
"@types/testing-library__react-hooks": "4.0.0",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"cross-spawn": "7.0.3",
|
"cross-spawn": "7.0.3",
|
||||||
"find-up": "4.1.0",
|
"find-up": "4.1.0",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"next-router-mock": "0.9.1",
|
"next-router-mock": "0.9.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ function codegen() {
|
|||||||
const defaultIndexJsPath = path.join(dotBlitzDir, "index.js")
|
const defaultIndexJsPath = path.join(dotBlitzDir, "index.js")
|
||||||
const defaultIndexBrowserJSPath = path.join(dotBlitzDir, "index-browser.js")
|
const defaultIndexBrowserJSPath = path.join(dotBlitzDir, "index-browser.js")
|
||||||
const defaultIndexDTSPath = path.join(dotBlitzDir, "index.d.ts")
|
const defaultIndexDTSPath = path.join(dotBlitzDir, "index.d.ts")
|
||||||
|
const emptyJSPath = path.join(dotBlitzDir, "turbopack-empty.js")
|
||||||
|
|
||||||
if (!fs.existsSync(defaultIndexJsPath)) {
|
if (!fs.existsSync(defaultIndexJsPath)) {
|
||||||
await copyFile(path.join(__dirname, "default-index.js"), defaultIndexJsPath)
|
await copyFile(path.join(__dirname, "default-index.js"), defaultIndexJsPath)
|
||||||
@@ -181,6 +182,10 @@ function codegen() {
|
|||||||
if (!fs.existsSync(defaultIndexDTSPath)) {
|
if (!fs.existsSync(defaultIndexDTSPath)) {
|
||||||
await copyFile(path.join(__dirname, "default-index.d.ts"), defaultIndexDTSPath)
|
await copyFile(path.join(__dirname, "default-index.d.ts"), defaultIndexDTSPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!fs.existsSync(emptyJSPath)) {
|
||||||
|
await copyFile(path.join(__dirname, "turbopack-empty.js"), emptyJSPath)
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
}
|
}
|
||||||
|
|||||||
1
packages/blitz-next/scripts/turbopack-empty.js
Normal file
1
packages/blitz-next/scripts/turbopack-empty.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export {}
|
||||||
@@ -22,11 +22,13 @@ import {
|
|||||||
RouteUrlObject,
|
RouteUrlObject,
|
||||||
startWatcher,
|
startWatcher,
|
||||||
stopWatcher,
|
stopWatcher,
|
||||||
|
RequestMiddleware,
|
||||||
} from "blitz"
|
} from "blitz"
|
||||||
import {
|
import {
|
||||||
getInfiniteQueryKey,
|
getInfiniteQueryKey,
|
||||||
getQueryKey,
|
getQueryKey,
|
||||||
installWebpackConfig,
|
installWebpackConfig,
|
||||||
|
installTurboConfig,
|
||||||
InstallWebpackConfigOptions,
|
InstallWebpackConfigOptions,
|
||||||
ResolverPathOptions,
|
ResolverPathOptions,
|
||||||
DefaultOptions,
|
DefaultOptions,
|
||||||
@@ -38,6 +40,9 @@ import {withSuperJsonProps} from "./superjson"
|
|||||||
import {ParsedUrlQuery} from "querystring"
|
import {ParsedUrlQuery} from "querystring"
|
||||||
import {PreviewData} from "next/types"
|
import {PreviewData} from "next/types"
|
||||||
import {resolveHref} from "next/dist/client/resolve-href"
|
import {resolveHref} from "next/dist/client/resolve-href"
|
||||||
|
import fs from "fs"
|
||||||
|
import path from "path"
|
||||||
|
import CopyPlugin from "copy-webpack-plugin"
|
||||||
|
|
||||||
export * from "./index-browser"
|
export * from "./index-browser"
|
||||||
|
|
||||||
@@ -238,6 +243,7 @@ export interface BlitzConfig extends NextConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function withBlitz(nextConfig: BlitzConfig = {}): NextConfig {
|
export function withBlitz(nextConfig: BlitzConfig = {}): NextConfig {
|
||||||
if (
|
if (
|
||||||
process.env.NODE_ENV !== "production" &&
|
process.env.NODE_ENV !== "production" &&
|
||||||
@@ -268,6 +274,31 @@ export function withBlitz(nextConfig: BlitzConfig = {}): NextConfig {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (!process.env.TURBOPACK) {
|
||||||
|
try {
|
||||||
|
const sodiumNativePath = fs.realpathSync(
|
||||||
|
path.join(require.resolve("sodium-native"), ".."),
|
||||||
|
)
|
||||||
|
const dotNextDirectory = `${process.cwd()}/.next`
|
||||||
|
config.plugins.push(
|
||||||
|
new CopyPlugin({
|
||||||
|
patterns: [
|
||||||
|
{
|
||||||
|
//dev
|
||||||
|
from: `${sodiumNativePath}/prebuilds/`,
|
||||||
|
to: `${dotNextDirectory}/server/vendor-chunks/prebuilds/`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//prod
|
||||||
|
from: `${sodiumNativePath}/prebuilds/`,
|
||||||
|
to: `${dotNextDirectory}/server/chunks/prebuilds/`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof nextConfig.webpack === "function") {
|
if (typeof nextConfig.webpack === "function") {
|
||||||
return nextConfig.webpack(config, options)
|
return nextConfig.webpack(config, options)
|
||||||
}
|
}
|
||||||
@@ -275,6 +306,26 @@ export function withBlitz(nextConfig: BlitzConfig = {}): NextConfig {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (process.env.TURBOPACK) {
|
||||||
|
const blitzTurboConfig = installTurboConfig()
|
||||||
|
config.experimental = {
|
||||||
|
...config.experimental,
|
||||||
|
turbo: {
|
||||||
|
loaders: {
|
||||||
|
...config.experimental?.turbo?.loaders,
|
||||||
|
},
|
||||||
|
resolveAlias: {
|
||||||
|
...config.experimental?.turbo?.resolveAlias,
|
||||||
|
...blitzTurboConfig.resolveAlias,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
...config.experimental?.turbo?.rules,
|
||||||
|
...blitzTurboConfig.rules,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const {blitz, ...rest} = config
|
const {blitz, ...rest} = config
|
||||||
return rest
|
return rest
|
||||||
}
|
}
|
||||||
@@ -323,3 +374,15 @@ declare module "blitz" {
|
|||||||
prefetchInfiniteQuery: PrefetchQueryFn
|
prefetchInfiniteQuery: PrefetchQueryFn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const BlitzServerMiddleware = <
|
||||||
|
TMiddleware extends RequestMiddleware<NextApiRequest, BlitzNextApiResponse> = RequestMiddleware<
|
||||||
|
NextApiRequest,
|
||||||
|
BlitzNextApiResponse
|
||||||
|
>,
|
||||||
|
>(
|
||||||
|
middleware: TMiddleware,
|
||||||
|
): BlitzServerPlugin<{}> => ({
|
||||||
|
requestMiddlewares: [middleware],
|
||||||
|
exports: () => ({}),
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,5 +1,140 @@
|
|||||||
# @blitzjs/rpc
|
# @blitzjs/rpc
|
||||||
|
|
||||||
|
## 2.1.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- blitz@2.1.2
|
||||||
|
|
||||||
|
## 2.1.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 9a0ba87d1: fix: make sure blitz superjson custom error registers in rpc handler
|
||||||
|
- Updated dependencies [9a0ba87d1]
|
||||||
|
- blitz@2.1.1
|
||||||
|
|
||||||
|
## 2.1.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 3b10b13e6: feat: add blitz auth support for the Web `Request` API standard
|
||||||
|
|
||||||
|
Usage using the new `withBlitzAuth` adapter in the App Router:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import {withBlitzAuth} from "app/blitz-server"
|
||||||
|
|
||||||
|
export const {POST} = withBlitzAuth({
|
||||||
|
POST: async (_request, _params, ctx) => {
|
||||||
|
const session = ctx.session
|
||||||
|
await session.$revoke()
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
userId: session.userId,
|
||||||
|
}),
|
||||||
|
{status: 200},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
feat: New Blitz RPC handler meant to with the next.js app router `route.ts` files
|
||||||
|
|
||||||
|
Usage using the new `rpcAppHandler` function
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// app/api/rpc/[[...blitz]]/route.ts
|
||||||
|
import {rpcAppHandler} from "@blitzjs/rpc"
|
||||||
|
import {withBlitzAuth} from "app/blitz-server"
|
||||||
|
|
||||||
|
// Usage with blitz auth
|
||||||
|
export const {GET, POST, HEAD} = withBlitzAuth(rpcAppHandler())
|
||||||
|
|
||||||
|
// Standalone usage
|
||||||
|
export const {GET, POST, HEAD} = rpcAppHandler()
|
||||||
|
```
|
||||||
|
|
||||||
|
chore: Update the app directory starter
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [d53da39cb]
|
||||||
|
- Updated dependencies [3b10b13e6]
|
||||||
|
- blitz@2.1.0
|
||||||
|
|
||||||
|
## 2.0.10
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [318e9740d]
|
||||||
|
- blitz@2.0.10
|
||||||
|
|
||||||
|
## 2.0.9
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 5a14306f7: fix export `enhancePrisma` in client
|
||||||
|
- Updated dependencies [5a14306f7]
|
||||||
|
- blitz@2.0.9
|
||||||
|
|
||||||
|
## 2.0.8
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [5e61a1681]
|
||||||
|
- Updated dependencies [77555468f]
|
||||||
|
- blitz@2.0.8
|
||||||
|
|
||||||
|
## 2.0.7
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- ee7bf87ec: Turbopack support for Blitz
|
||||||
|
|
||||||
|
This PR includes the changes required to make the Blitz loaders work with Turbopack.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm blitz dev --turbo
|
||||||
|
```
|
||||||
|
|
||||||
|
- Updated dependencies [ee7bf87ec]
|
||||||
|
- Updated dependencies [178c152b2]
|
||||||
|
- blitz@2.0.7
|
||||||
|
|
||||||
|
## 2.0.6
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [76a2544f9]
|
||||||
|
- blitz@2.0.6
|
||||||
|
|
||||||
|
## 2.0.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [6f54841b7]
|
||||||
|
- blitz@2.0.5
|
||||||
|
|
||||||
|
## 2.0.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [dd604c767]
|
||||||
|
- Updated dependencies [28a79040e]
|
||||||
|
- blitz@2.0.4
|
||||||
|
|
||||||
|
## 2.0.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 2f5c8a3a0: Address missing sodium native prebuilds required to use secure-password during server rendering
|
||||||
|
- Updated dependencies [2f5c8a3a0]
|
||||||
|
- blitz@2.0.3
|
||||||
|
|
||||||
## 2.0.2
|
## 2.0.2
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@blitzjs/rpc",
|
"name": "@blitzjs/rpc",
|
||||||
"version": "2.0.2",
|
"version": "2.1.2",
|
||||||
"homepage": "https://blitzjs.com/",
|
"homepage": "https://blitzjs.com/",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -37,19 +37,19 @@
|
|||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@tanstack/query-core": "4.24.4",
|
"@tanstack/query-core": "4.24.4",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"next": "*",
|
"next": "*",
|
||||||
"react": "*"
|
"react": "*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@blitzjs/auth": "2.0.2",
|
"@blitzjs/auth": "2.1.2",
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@tanstack/query-core": "4.24.4",
|
"@tanstack/query-core": "4.24.4",
|
||||||
"@types/debug": "4.1.7",
|
"@types/debug": "4.1.7",
|
||||||
"@types/react": "18.0.25",
|
"@types/react": "18.0.25",
|
||||||
"@types/react-dom": "17.0.14",
|
"@types/react-dom": "17.0.14",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"next": "14.0.4",
|
"next": "14.3.0-canary.28",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"typescript": "^4.8.4",
|
"typescript": "^4.8.4",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {assert, Ctx, ResolverConfig} from "blitz"
|
import {assert, Ctx, ResolverConfig, registerBlitzErrorClasses} from "blitz"
|
||||||
import {NextApiRequest, NextApiResponse} from "next"
|
import {NextApiRequest, NextApiResponse} from "next"
|
||||||
import {resolve} from "path"
|
import {resolve} from "path"
|
||||||
import {deserialize, parse, serialize as superjsonSerialize} from "superjson"
|
import {deserialize, parse, serialize as superjsonSerialize} from "superjson"
|
||||||
@@ -119,6 +119,7 @@ export interface InstallWebpackConfigOptions {
|
|||||||
[key: string]: boolean | string
|
[key: string]: boolean | string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
plugins: any[]
|
||||||
module: {
|
module: {
|
||||||
rules: WebpackRule[]
|
rules: WebpackRule[]
|
||||||
}
|
}
|
||||||
@@ -156,6 +157,51 @@ export function installWebpackConfig({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function installTurboConfig() {
|
||||||
|
return {
|
||||||
|
resolveAlias: {
|
||||||
|
"cross-spawn": {browser: ".blitz/turbopack-empty.js"},
|
||||||
|
"npm-which": {browser: ".blitz/turbopack-empty.js"},
|
||||||
|
fs: {browser: ".blitz/turbopack-empty.js"},
|
||||||
|
child_process: {browser: ".blitz/turbopack-empty.js"},
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
"**/*...blitz*.{jsx,tsx,js,ts}": {
|
||||||
|
default: {
|
||||||
|
loaders: [{loader: loaderServer, options: {}}],
|
||||||
|
as: "*.ts",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"**/*...blitz*/route.{jsx,tsx,js,ts}": {
|
||||||
|
default: {
|
||||||
|
loaders: [{loader: loaderServer, options: {}}],
|
||||||
|
as: "*.ts",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"**/{queries,mutations}/**": {
|
||||||
|
browser: {
|
||||||
|
loaders: [
|
||||||
|
{
|
||||||
|
loader: loaderClient,
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
as: "*.ts",
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
loaders: [
|
||||||
|
{
|
||||||
|
loader: loaderServerResolvers,
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
as: "*.ts",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
// END LOADER
|
// END LOADER
|
||||||
// ----------
|
// ----------
|
||||||
@@ -187,12 +233,13 @@ async function getResolverMap(): Promise<ResolverFiles | null | undefined> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface RpcConfig {
|
interface RpcConfig {
|
||||||
onError?: (error: Error, ctx: Ctx) => void
|
onError?: (error: Error, ctx?: Ctx) => void
|
||||||
formatError?: (error: Error, ctx: Ctx) => Error
|
formatError?: (error: Error, ctx?: Ctx) => Error
|
||||||
logging?: RpcLoggerOptions
|
logging?: RpcLoggerOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
export function rpcHandler(config: RpcConfig) {
|
export function rpcHandler(config?: RpcConfig) {
|
||||||
|
registerBlitzErrorClasses()
|
||||||
return async function handleRpcRequest(req: NextApiRequest, res: NextApiResponse, ctx: Ctx) {
|
return async function handleRpcRequest(req: NextApiRequest, res: NextApiResponse, ctx: Ctx) {
|
||||||
const resolverMap = await getResolverMap()
|
const resolverMap = await getResolverMap()
|
||||||
assert(resolverMap, "No query or mutation resolvers found")
|
assert(resolverMap, "No query or mutation resolvers found")
|
||||||
@@ -204,7 +251,7 @@ export function rpcHandler(config: RpcConfig) {
|
|||||||
const relativeRoutePath = (req.query.blitz as string[])?.join("/")
|
const relativeRoutePath = (req.query.blitz as string[])?.join("/")
|
||||||
const routePath = "/" + relativeRoutePath
|
const routePath = "/" + relativeRoutePath
|
||||||
const resolverName = routePath.replace(/(\/api\/rpc)?\//, "")
|
const resolverName = routePath.replace(/(\/api\/rpc)?\//, "")
|
||||||
const rpcLogger = new RpcLogger(resolverName, config.logging)
|
const rpcLogger = new RpcLogger(resolverName, config?.logging)
|
||||||
|
|
||||||
const loadableResolver = resolverMap?.[routePath]?.resolver
|
const loadableResolver = resolverMap?.[routePath]?.resolver
|
||||||
if (!loadableResolver) {
|
if (!loadableResolver) {
|
||||||
@@ -263,6 +310,7 @@ export function rpcHandler(config: RpcConfig) {
|
|||||||
|
|
||||||
rpcLogger.timer.initNextJsSerialization()
|
rpcLogger.timer.initNextJsSerialization()
|
||||||
;(res as any).blitzResult = result
|
;(res as any).blitzResult = result
|
||||||
|
ctx?.session?.setSession(res)
|
||||||
res.json({
|
res.json({
|
||||||
result: serializedResult.json,
|
result: serializedResult.json,
|
||||||
error: null,
|
error: null,
|
||||||
@@ -282,16 +330,18 @@ export function rpcHandler(config: RpcConfig) {
|
|||||||
error.stack = ""
|
error.stack = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
config.onError?.(error, ctx)
|
config?.onError?.(error, ctx)
|
||||||
rpcLogger.error(error)
|
rpcLogger.error(error)
|
||||||
|
|
||||||
if (!error.statusCode) {
|
if (!error.statusCode) {
|
||||||
error.statusCode = 500
|
error.statusCode = 500
|
||||||
}
|
}
|
||||||
|
|
||||||
const formattedError = config.formatError?.(error, ctx) ?? error
|
const formattedError = config?.formatError?.(error, ctx) ?? error
|
||||||
const serializedError = superjsonSerialize(formattedError)
|
const serializedError = superjsonSerialize(formattedError)
|
||||||
|
|
||||||
|
ctx?.session?.setSession(res)
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
result: null,
|
result: null,
|
||||||
error: serializedError.json,
|
error: serializedError.json,
|
||||||
@@ -309,3 +359,129 @@ export function rpcHandler(config: RpcConfig) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Params = Record<string, unknown>
|
||||||
|
|
||||||
|
export function rpcAppHandler(config?: RpcConfig) {
|
||||||
|
registerBlitzErrorClasses()
|
||||||
|
async function handleRpcRequest(req: Request, context: {params: Params}, ctx?: Ctx) {
|
||||||
|
const session = ctx?.session
|
||||||
|
const resolverMap = await getResolverMap()
|
||||||
|
assert(resolverMap, "No query or mutation resolvers found")
|
||||||
|
|
||||||
|
assert(
|
||||||
|
Array.isArray(context.params.blitz),
|
||||||
|
"It seems your Blitz RPC endpoint file is not named [[...blitz]].(jt)s. Please ensure it is",
|
||||||
|
)
|
||||||
|
|
||||||
|
const relativeRoutePath = (context.params.blitz as string[])?.join("/")
|
||||||
|
const routePath = "/" + relativeRoutePath
|
||||||
|
const resolverName = routePath.replace(/(\/api\/rpc)?\//, "")
|
||||||
|
const rpcLogger = new RpcLogger(resolverName, config?.logging)
|
||||||
|
|
||||||
|
const loadableResolver = resolverMap?.[routePath]?.resolver
|
||||||
|
if (!loadableResolver) {
|
||||||
|
throw new Error("No resolver for path: " + routePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
const {default: resolver, config: resolverConfig} = await loadableResolver()
|
||||||
|
|
||||||
|
if (!resolver) {
|
||||||
|
throw new Error("No default export for resolver path: " + routePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolverConfigWithDefaults = {...defaultConfig, ...resolverConfig}
|
||||||
|
|
||||||
|
if (req.method === "HEAD") {
|
||||||
|
// We used to initiate database connection here
|
||||||
|
return new Response(null, {status: 200})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
req.method === "POST" ||
|
||||||
|
(req.method === "GET" && resolverConfigWithDefaults.httpMethod === "GET")
|
||||||
|
) {
|
||||||
|
const body = await req.json()
|
||||||
|
if (req.method === "POST" && typeof body.params === "undefined") {
|
||||||
|
const error = {message: "Request body is missing the `params` key"}
|
||||||
|
rpcLogger.error(error.message)
|
||||||
|
return new Response(JSON.stringify({result: null, error}), {status: 400})
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const data = deserialize({
|
||||||
|
json:
|
||||||
|
req.method === "POST"
|
||||||
|
? body.params
|
||||||
|
: context.params.params
|
||||||
|
? parse(`${context.params.params}`)
|
||||||
|
: undefined,
|
||||||
|
meta:
|
||||||
|
req.method === "POST"
|
||||||
|
? body.meta?.params
|
||||||
|
: context.params.meta
|
||||||
|
? parse(`${context.params.meta}`)
|
||||||
|
: undefined,
|
||||||
|
})
|
||||||
|
rpcLogger.timer.initResolver()
|
||||||
|
rpcLogger.preResolver(data)
|
||||||
|
|
||||||
|
const result = await resolver(data, {session})
|
||||||
|
rpcLogger.timer.resolverDuration()
|
||||||
|
rpcLogger.postResolver(result)
|
||||||
|
|
||||||
|
rpcLogger.timer.initSerialization()
|
||||||
|
const serializedResult = superjsonSerialize(result)
|
||||||
|
|
||||||
|
rpcLogger.timer.initNextJsSerialization()
|
||||||
|
const response = new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
result: serializedResult.json,
|
||||||
|
error: null,
|
||||||
|
meta: {
|
||||||
|
result: serializedResult.meta,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
session?.setSession(response)
|
||||||
|
return response
|
||||||
|
} catch (error: any) {
|
||||||
|
if (error._clearStack) {
|
||||||
|
error.stack = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
config?.onError?.(error, {session} as Ctx)
|
||||||
|
rpcLogger.error(error)
|
||||||
|
|
||||||
|
if (!error.statusCode) {
|
||||||
|
error.statusCode = 500
|
||||||
|
}
|
||||||
|
|
||||||
|
const formattedError = config?.formatError?.(error, {session} as Ctx) ?? error
|
||||||
|
const serializedError = superjsonSerialize(formattedError)
|
||||||
|
|
||||||
|
const response = new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
result: null,
|
||||||
|
error: serializedError.json,
|
||||||
|
meta: {
|
||||||
|
error: serializedError.meta,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
session?.setSession(response)
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Everything else is error
|
||||||
|
rpcLogger.warn(`${req.method} method not supported`)
|
||||||
|
return new Response(null, {status: 404})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
GET: handleRpcRequest,
|
||||||
|
POST: handleRpcRequest,
|
||||||
|
HEAD: handleRpcRequest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,12 +14,24 @@ import {getResolverConfig} from "../../parsers/parse-rpc-config"
|
|||||||
// Subset of `import type { LoaderDefinitionFunction } from 'webpack'`
|
// Subset of `import type { LoaderDefinitionFunction } from 'webpack'`
|
||||||
|
|
||||||
export async function loader(this: Loader, input: string): Promise<string> {
|
export async function loader(this: Loader, input: string): Promise<string> {
|
||||||
const compiler = this._compiler!
|
|
||||||
const id = this.resource
|
const id = this.resource
|
||||||
const root = this._compiler!.context
|
const root = this.rootContext
|
||||||
|
|
||||||
const isSSR = compiler.name === "server"
|
// Webpack has `_compiler` property. Turbopack does not.
|
||||||
if (!isSSR) {
|
const webpackCompilerName = this._compiler?.name
|
||||||
|
if (webpackCompilerName) {
|
||||||
|
const isSSR = webpackCompilerName === "server"
|
||||||
|
if (!isSSR) {
|
||||||
|
return await transformBlitzRpcResolverClient(
|
||||||
|
input,
|
||||||
|
toPosixPath(id),
|
||||||
|
toPosixPath(root),
|
||||||
|
this.query,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// Handle Turbopack / other bundlers case.
|
||||||
|
// The decision of which environment to run the loader in is decided by the loader configuration instead.
|
||||||
|
} else {
|
||||||
return await transformBlitzRpcResolverClient(
|
return await transformBlitzRpcResolverClient(
|
||||||
input,
|
input,
|
||||||
toPosixPath(id),
|
toPosixPath(id),
|
||||||
|
|||||||
@@ -13,12 +13,24 @@ import {posix} from "path"
|
|||||||
// Subset of `import type { LoaderDefinitionFunction } from 'webpack'`
|
// Subset of `import type { LoaderDefinitionFunction } from 'webpack'`
|
||||||
|
|
||||||
export async function loader(this: Loader, input: string): Promise<string> {
|
export async function loader(this: Loader, input: string): Promise<string> {
|
||||||
const compiler = this._compiler!
|
|
||||||
const id = this.resource
|
const id = this.resource
|
||||||
const root = this._compiler!.context
|
const root = this.rootContext
|
||||||
|
|
||||||
const isSSR = compiler.name === "server"
|
// Webpack has `_compiler` property. Turbopack does not.
|
||||||
if (isSSR) {
|
const webpackCompilerName = this._compiler?.name
|
||||||
|
if (webpackCompilerName) {
|
||||||
|
const isSSR = webpackCompilerName === "server"
|
||||||
|
if (isSSR) {
|
||||||
|
return await transformBlitzRpcResolverServer(
|
||||||
|
input,
|
||||||
|
toPosixPath(id),
|
||||||
|
toPosixPath(root),
|
||||||
|
this.query,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// Handle Turbopack / other bundlers case.
|
||||||
|
// The decision of which environment to run the loader in is decided by the loader configuration instead.
|
||||||
|
} else {
|
||||||
return await transformBlitzRpcResolverServer(
|
return await transformBlitzRpcResolverServer(
|
||||||
input,
|
input,
|
||||||
toPosixPath(id),
|
toPosixPath(id),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {join} from "path"
|
import {join, relative} from "path"
|
||||||
import {promises} from "fs"
|
import {promises} from "fs"
|
||||||
import {
|
import {
|
||||||
assertPosixPath,
|
assertPosixPath,
|
||||||
@@ -14,17 +14,37 @@ import {
|
|||||||
// Subset of `import type { LoaderDefinitionFunction } from 'webpack'`
|
// Subset of `import type { LoaderDefinitionFunction } from 'webpack'`
|
||||||
|
|
||||||
export async function loader(this: Loader, input: string): Promise<string> {
|
export async function loader(this: Loader, input: string): Promise<string> {
|
||||||
const compiler = this._compiler!
|
|
||||||
const id = this.resource
|
const id = this.resource
|
||||||
const root = this._compiler!.context
|
const root = this.rootContext
|
||||||
const rpcFolders = this.query.includeRPCFolders ? this.query.includeRPCFolders : []
|
const rpcFolders = this.query.includeRPCFolders ? this.query.includeRPCFolders : []
|
||||||
|
|
||||||
const isSSR = compiler.name === "server"
|
// Webpack has `_compiler` property. Turbopack does not.
|
||||||
if (isSSR) {
|
const webpackCompilerName = this._compiler?.name
|
||||||
|
if (webpackCompilerName) {
|
||||||
|
const isSSR = webpackCompilerName === "server"
|
||||||
|
if (isSSR) {
|
||||||
|
this.cacheable(false)
|
||||||
|
|
||||||
|
const resolvers = await collectResolvers(root, rpcFolders, ["ts", "js", "tsx", "jsx"])
|
||||||
|
|
||||||
|
return await transformBlitzRpcServer(
|
||||||
|
this.context,
|
||||||
|
input,
|
||||||
|
toPosixPath(id),
|
||||||
|
toPosixPath(root),
|
||||||
|
resolvers,
|
||||||
|
this.query,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// Handle Turbopack / other bundlers case.
|
||||||
|
// The decision of which environment to run the loader in is decided by the loader configuration instead.
|
||||||
|
} else {
|
||||||
this.cacheable(false)
|
this.cacheable(false)
|
||||||
|
|
||||||
const resolvers = await collectResolvers(root, rpcFolders, ["ts", "js", "tsx", "jsx"])
|
const resolvers = await collectResolvers(root, rpcFolders, ["ts", "js", "tsx", "jsx"])
|
||||||
|
|
||||||
return await transformBlitzRpcServer(
|
return await transformBlitzRpcServer(
|
||||||
|
this.context,
|
||||||
input,
|
input,
|
||||||
toPosixPath(id),
|
toPosixPath(id),
|
||||||
toPosixPath(root),
|
toPosixPath(root),
|
||||||
@@ -43,6 +63,7 @@ function slash(str: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function transformBlitzRpcServer(
|
export async function transformBlitzRpcServer(
|
||||||
|
context: string,
|
||||||
src: string,
|
src: string,
|
||||||
id: string,
|
id: string,
|
||||||
root: string,
|
root: string,
|
||||||
@@ -68,7 +89,9 @@ export async function transformBlitzRpcServer(
|
|||||||
|
|
||||||
code += `__internal_addBlitzRpcResolver('${routePath}','${slash(
|
code += `__internal_addBlitzRpcResolver('${routePath}','${slash(
|
||||||
resolverFilePath,
|
resolverFilePath,
|
||||||
)}',() => ${importStrategy}('${slash(resolverFilePath)}'));`
|
)}',() => ${importStrategy}('${slash(
|
||||||
|
relative(context, resolverFilePath).replace(/\\/g, "/"),
|
||||||
|
)}'))`
|
||||||
code += "\n"
|
code += "\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ export interface LoaderOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Loader {
|
export interface Loader {
|
||||||
_compiler?: {
|
_compiler: {
|
||||||
name: string
|
name: string
|
||||||
context: string
|
|
||||||
}
|
}
|
||||||
|
rootContext: string
|
||||||
|
context: string
|
||||||
resource: string
|
resource: string
|
||||||
cacheable: (enabled: boolean) => void
|
cacheable: (enabled: boolean) => void
|
||||||
query: LoaderOptions
|
query: LoaderOptions
|
||||||
|
|||||||
@@ -1,5 +1,141 @@
|
|||||||
# blitz
|
# blitz
|
||||||
|
|
||||||
|
## 2.1.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [2711291e9]
|
||||||
|
- Updated dependencies [56bd32b55]
|
||||||
|
- @blitzjs/generator@2.1.2
|
||||||
|
|
||||||
|
## 2.1.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 9a0ba87d1: fix: make sure blitz superjson custom error registers in rpc handler
|
||||||
|
- @blitzjs/generator@2.1.1
|
||||||
|
|
||||||
|
## 2.1.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 3b10b13e6: feat: add blitz auth support for the Web `Request` API standard
|
||||||
|
|
||||||
|
Usage using the new `withBlitzAuth` adapter in the App Router:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import {withBlitzAuth} from "app/blitz-server"
|
||||||
|
|
||||||
|
export const {POST} = withBlitzAuth({
|
||||||
|
POST: async (_request, _params, ctx) => {
|
||||||
|
const session = ctx.session
|
||||||
|
await session.$revoke()
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
userId: session.userId,
|
||||||
|
}),
|
||||||
|
{status: 200},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
feat: New Blitz RPC handler meant to with the next.js app router `route.ts` files
|
||||||
|
|
||||||
|
Usage using the new `rpcAppHandler` function
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// app/api/rpc/[[...blitz]]/route.ts
|
||||||
|
import {rpcAppHandler} from "@blitzjs/rpc"
|
||||||
|
import {withBlitzAuth} from "app/blitz-server"
|
||||||
|
|
||||||
|
// Usage with blitz auth
|
||||||
|
export const {GET, POST, HEAD} = withBlitzAuth(rpcAppHandler())
|
||||||
|
|
||||||
|
// Standalone usage
|
||||||
|
export const {GET, POST, HEAD} = rpcAppHandler()
|
||||||
|
```
|
||||||
|
|
||||||
|
chore: Update the app directory starter
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- d53da39cb: Improved parsing of default export names to handle higher-order components (HOCs) in the `parseDefaultExportName` function.
|
||||||
|
- Updated dependencies [3b10b13e6]
|
||||||
|
- @blitzjs/generator@2.1.0
|
||||||
|
|
||||||
|
## 2.0.10
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 318e9740d: feat: support next-auth version 4.24.7
|
||||||
|
- @blitzjs/generator@2.0.10
|
||||||
|
|
||||||
|
## 2.0.9
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 5a14306f7: fix export `enhancePrisma` in client
|
||||||
|
- @blitzjs/generator@2.0.9
|
||||||
|
|
||||||
|
## 2.0.8
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 5e61a1681: bug: merge existing and custom blitz turbo configs
|
||||||
|
- 77555468f: fix: add missing host while initialising the next-auth adapter
|
||||||
|
- @blitzjs/generator@2.0.8
|
||||||
|
|
||||||
|
## 2.0.7
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- ee7bf87ec: Turbopack support for Blitz
|
||||||
|
|
||||||
|
This PR includes the changes required to make the Blitz loaders work with Turbopack.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm blitz dev --turbo
|
||||||
|
```
|
||||||
|
|
||||||
|
- 178c152b2: fix: patch next.js to hide intentional throws of `DYNAMIC_SERVER_USAGE`
|
||||||
|
- @blitzjs/generator@2.0.7
|
||||||
|
|
||||||
|
## 2.0.6
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 76a2544f9: Use `SIGINT` signal instead of `SIGABRT` to stop the process, when using custom server for better compatibility with operative systems
|
||||||
|
- @blitzjs/generator@2.0.6
|
||||||
|
|
||||||
|
## 2.0.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 6f54841b7: fix: getBlitzContext() can only be used in React Server Components in Nextjs 13 or higher
|
||||||
|
- @blitzjs/generator@2.0.5
|
||||||
|
|
||||||
|
## 2.0.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- dd604c767: perf: add filter to select only non expired sessions
|
||||||
|
- 28a79040e: feat: export `BlitzServerMiddleware` from blitz-next with stronger types
|
||||||
|
- Updated dependencies [71b995003]
|
||||||
|
- @blitzjs/generator@2.0.4
|
||||||
|
|
||||||
|
## 2.0.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 2f5c8a3a0: Address missing sodium native prebuilds required to use secure-password during server rendering
|
||||||
|
- Updated dependencies [47722e045]
|
||||||
|
- Updated dependencies [595f400e9]
|
||||||
|
- @blitzjs/generator@2.0.3
|
||||||
|
|
||||||
## 2.0.2
|
## 2.0.2
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "blitz",
|
"name": "blitz",
|
||||||
"version": "2.0.2",
|
"version": "2.1.2",
|
||||||
"homepage": "https://blitzjs.com/",
|
"homepage": "https://blitzjs.com/",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
"blitz": "bin/blitz"
|
"blitz": "bin/blitz"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@blitzjs/generator": "2.0.2",
|
"@blitzjs/generator": "2.1.2",
|
||||||
"@mrleebo/prisma-ast": "0.2.6",
|
"@mrleebo/prisma-ast": "0.2.6",
|
||||||
"@types/global-agent": "2.1.1",
|
"@types/global-agent": "2.1.1",
|
||||||
"arg": "5.0.1",
|
"arg": "5.0.1",
|
||||||
@@ -80,7 +80,7 @@
|
|||||||
"watchpack": "2.1.1"
|
"watchpack": "2.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@types/cookie": "0.4.1",
|
"@types/cookie": "0.4.1",
|
||||||
"@types/cross-spawn": "6.0.2",
|
"@types/cross-spawn": "6.0.2",
|
||||||
"@types/debug": "4.1.7",
|
"@types/debug": "4.1.7",
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import {CliCommand} from "../index"
|
|||||||
import prompts from "prompts"
|
import prompts from "prompts"
|
||||||
import {bootstrap} from "global-agent"
|
import {bootstrap} from "global-agent"
|
||||||
import {baseLogger, log} from "../../logging"
|
import {baseLogger, log} from "../../logging"
|
||||||
const debug = require("debug")("blitz:cli")
|
import Debug from "debug"
|
||||||
|
const debug = Debug("blitz:cli")
|
||||||
import {join, resolve, dirname} from "path"
|
import {join, resolve, dirname} from "path"
|
||||||
import {Stream} from "stream"
|
import {Stream} from "stream"
|
||||||
import {promisify} from "util"
|
import {promisify} from "util"
|
||||||
|
|||||||
@@ -16,7 +16,14 @@ export const codegenTasks = async () => {
|
|||||||
*/
|
*/
|
||||||
const nextDir = await resolveCwd("next")
|
const nextDir = await resolveCwd("next")
|
||||||
const nextClientIndex = join(nextDir, "../..", "client", "index.js")
|
const nextClientIndex = join(nextDir, "../..", "client", "index.js")
|
||||||
|
const nextClientOnRecoverableErrorIndex = join(
|
||||||
|
nextDir,
|
||||||
|
"../..",
|
||||||
|
"client",
|
||||||
|
"on-recoverable-error.js",
|
||||||
|
)
|
||||||
const readFile = await fs.readFile(nextClientIndex)
|
const readFile = await fs.readFile(nextClientIndex)
|
||||||
|
const readOnRecoverableErrorFile = await fs.readFile(nextClientOnRecoverableErrorIndex)
|
||||||
const packageJson = await getPackageJson()
|
const packageJson = await getPackageJson()
|
||||||
const version = packageJson.dependencies.next
|
const version = packageJson.dependencies.next
|
||||||
const nextVersion = semver.clean(version, {loose: true}) || semver.valid(semver.coerce(version))
|
const nextVersion = semver.clean(version, {loose: true}) || semver.valid(semver.coerce(version))
|
||||||
@@ -48,14 +55,16 @@ export const codegenTasks = async () => {
|
|||||||
)
|
)
|
||||||
await fs.writeFile(nextClientIndex, updatedFile)
|
await fs.writeFile(nextClientIndex, updatedFile)
|
||||||
log.success("Next.js was successfully patched with a React Suspense fix")
|
log.success("Next.js was successfully patched with a React Suspense fix")
|
||||||
} else if (nextVersion && semver.satisfies(nextVersion, ">=13.3.1")) {
|
} else {
|
||||||
const updatedFile = readFile
|
const updatedFile = readOnRecoverableErrorFile.toString().replace(
|
||||||
.toString()
|
/defaultOnRecoverableError\(err\);/gm,
|
||||||
.replace(
|
` if (err.toString().includes("DYNAMIC_SERVER_USAGE") || err.toString().includes("could not finish this Suspense boundary") || err.toString().includes("Minified React error #419")) {
|
||||||
/_onrecoverableerror\.default$/gm,
|
return;
|
||||||
`(err) => (err.toString().includes("DYNAMIC_SERVER_USAGE") || err.toString().includes("could not finish this Suspense boundary") || err.toString().includes("Minified React error #419")) ? null : _onrecoverableerror.default(err)`,
|
} else {
|
||||||
)
|
defaultOnRecoverableError(err)
|
||||||
await fs.writeFile(nextClientIndex, updatedFile)
|
}`,
|
||||||
|
)
|
||||||
|
await fs.writeFile(nextClientOnRecoverableErrorIndex, updatedFile)
|
||||||
log.success("Next.js was successfully patched with a React Suspense fix")
|
log.success("Next.js was successfully patched with a React Suspense fix")
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import {readJSON} from "fs-extra"
|
|||||||
import path from "path"
|
import path from "path"
|
||||||
import pkgDir from "pkg-dir"
|
import pkgDir from "pkg-dir"
|
||||||
import resolveCwd from "resolve-cwd"
|
import resolveCwd from "resolve-cwd"
|
||||||
const debug = require("debug")("blitz:utils")
|
import Debug from "debug"
|
||||||
|
const debug = Debug("blitz:utils")
|
||||||
|
|
||||||
export async function resolveBinAsync(pkg: string, executable = pkg) {
|
export async function resolveBinAsync(pkg: string, executable = pkg) {
|
||||||
const packageDir = await pkgDir(resolveCwd(pkg))
|
const packageDir = await pkgDir(resolveCwd(pkg))
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import path from "path"
|
|||||||
import * as REPL from "repl"
|
import * as REPL from "repl"
|
||||||
import {REPLCommand, REPLServer} from "repl"
|
import {REPLCommand, REPLServer} from "repl"
|
||||||
// eslint-disable-next-line @next/next/no-assign-module-variable
|
// eslint-disable-next-line @next/next/no-assign-module-variable
|
||||||
const debug = require("debug")("blitz:repl")
|
import Debug from "debug"
|
||||||
|
const debug = Debug("blitz:repl")
|
||||||
import ProgressBar from "progress"
|
import ProgressBar from "progress"
|
||||||
import {log} from "../../logging"
|
import {log} from "../../logging"
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ import {ChildProcess} from "child_process"
|
|||||||
import {spawn} from "cross-spawn"
|
import {spawn} from "cross-spawn"
|
||||||
import detect from "detect-port"
|
import detect from "detect-port"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import {existsSync, readJSONSync} from "fs-extra"
|
import {copySync, existsSync, readJSONSync} from "fs-extra"
|
||||||
import * as esbuild from "esbuild"
|
import * as esbuild from "esbuild"
|
||||||
import pkgDir from "pkg-dir"
|
import pkgDir from "pkg-dir"
|
||||||
import type {ServerConfig} from "./config"
|
import type {ServerConfig} from "./config"
|
||||||
|
|
||||||
const debug = require("debug")("blitz:utils")
|
import Debug from "debug"
|
||||||
|
const debug = Debug("blitz:utils")
|
||||||
|
|
||||||
export function getProjectRootSync() {
|
export function getProjectRootSync() {
|
||||||
return process.cwd()
|
return process.cwd()
|
||||||
@@ -127,7 +128,7 @@ export function startCustomServer(
|
|||||||
console.log("\n")
|
console.log("\n")
|
||||||
//@ts-ignore -- incorrect TS type from node
|
//@ts-ignore -- incorrect TS type from node
|
||||||
process.exitCode = RESTART_CODE
|
process.exitCode = RESTART_CODE
|
||||||
process.kill("SIGABRT")
|
process.kill("SIGINT")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -151,22 +152,12 @@ function getSpawnEnv(config: ServerConfig) {
|
|||||||
return spawnEnv
|
return spawnEnv
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createCommandAndPort(config: ServerConfig, command: string) {
|
async function detectAvailablePort(config: ServerConfig) {
|
||||||
let spawnCommand: string[] = [command]
|
return await detect({port: config.port ? config.port : 3000})
|
||||||
let availablePort: number
|
|
||||||
|
|
||||||
availablePort = await detect({port: config.port ? config.port : 3000})
|
|
||||||
spawnCommand = spawnCommand.concat(["-p", `${availablePort}`])
|
|
||||||
|
|
||||||
if (config.hostname) {
|
|
||||||
spawnCommand = spawnCommand.concat(["-H", `${config.hostname}`])
|
|
||||||
}
|
|
||||||
|
|
||||||
const spawnEnv = getSpawnEnv(config)
|
|
||||||
|
|
||||||
return {spawnCommand, spawnEnv, availablePort}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const frameworkCommands = ["blitz", "next"]
|
||||||
|
|
||||||
export async function nextStartDev(
|
export async function nextStartDev(
|
||||||
nextBin: string,
|
nextBin: string,
|
||||||
cwd: string,
|
cwd: string,
|
||||||
@@ -174,12 +165,11 @@ export async function nextStartDev(
|
|||||||
_buildFolder: string,
|
_buildFolder: string,
|
||||||
config: ServerConfig,
|
config: ServerConfig,
|
||||||
) {
|
) {
|
||||||
const {spawnCommand, spawnEnv, availablePort} = await createCommandAndPort(config, "dev")
|
const spawnEnv = getSpawnEnv(config)
|
||||||
|
const availablePort = await detectAvailablePort(config)
|
||||||
process.env.BLITZ_DEV_SERVER_ORIGIN = `http://localhost:${availablePort}`
|
process.env.BLITZ_DEV_SERVER_ORIGIN = `http://localhost:${availablePort}`
|
||||||
|
|
||||||
debug("cwd ", cwd)
|
const spawnCommand = process.argv.slice(2).filter((arg) => !frameworkCommands.includes(arg))
|
||||||
debug("spawn ", nextBin, spawnCommand)
|
|
||||||
|
|
||||||
return new Promise<void>((res, rej) => {
|
return new Promise<void>((res, rej) => {
|
||||||
spawn(nextBin, spawnCommand, {
|
spawn(nextBin, spawnCommand, {
|
||||||
@@ -248,7 +238,8 @@ export function nextExport(nextBin: string, config: ServerConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function nextStart(nextBin: string, _buildFolder: string, config: ServerConfig) {
|
export async function nextStart(nextBin: string, _buildFolder: string, config: ServerConfig) {
|
||||||
const {spawnCommand, spawnEnv} = await createCommandAndPort(config, "start")
|
const spawnEnv = getSpawnEnv(config)
|
||||||
|
const spawnCommand = process.argv.slice(2).filter((arg) => !frameworkCommands.includes(arg))
|
||||||
|
|
||||||
return new Promise<void>((res, rej) => {
|
return new Promise<void>((res, rej) => {
|
||||||
spawn(nextBin, spawnCommand, {
|
spawn(nextBin, spawnCommand, {
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import {outputFile, readdir, readFile} from "fs-extra"
|
|||||||
import Watchpack from "watchpack"
|
import Watchpack from "watchpack"
|
||||||
import {findNodeModulesRoot} from "./find-node-modules"
|
import {findNodeModulesRoot} from "./find-node-modules"
|
||||||
|
|
||||||
const debug = require("debug")("blitz")
|
import Debug from "debug"
|
||||||
|
const debug = Debug("blitz")
|
||||||
export const CONFIG_FILE = ".blitz.config.compiled.js"
|
export const CONFIG_FILE = ".blitz.config.compiled.js"
|
||||||
export const NEXT_CONFIG_FILE = "next.config.js"
|
export const NEXT_CONFIG_FILE = "next.config.js"
|
||||||
export const PHASE_PRODUCTION_SERVER = "phase-production-server"
|
export const PHASE_PRODUCTION_SERVER = "phase-production-server"
|
||||||
@@ -503,12 +504,13 @@ const pascalCase = (value: string): string => {
|
|||||||
return val.substr(0, 1).toUpperCase() + val.substr(1)
|
return val.substr(0, 1).toUpperCase() + val.substr(1)
|
||||||
}
|
}
|
||||||
export function parseDefaultExportName(contents: string): string | null {
|
export function parseDefaultExportName(contents: string): string | null {
|
||||||
const result = contents.match(/export\s+default(?:\s+(?:const|let|class|var|function))?\s+(\w+)/)
|
const result = contents.match(/export\s+default(?:\s+(const|let|class|var|function))?\s+(\w+)(?:\(([a-zA-Z_$][a-zA-Z0-9_$]*\b).*\))?/)
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
const [,declaration,compOrHOCName,comp] = result
|
||||||
return result[1] ?? null
|
if(declaration||!comp) return compOrHOCName ?? null;
|
||||||
|
return comp ?? null
|
||||||
}
|
}
|
||||||
export async function generateManifest() {
|
export async function generateManifest() {
|
||||||
const config = await loadConfig(process.cwd())
|
const config = await loadConfig(process.cwd())
|
||||||
|
|||||||
@@ -89,7 +89,10 @@ export class PaginationArgumentError extends Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNotInUserTestEnvironment() && !globalThis._BLITZ_ERROR_CLASS_REGISTERED) {
|
let _blitzErrorClassRegistered = false
|
||||||
|
|
||||||
|
export function registerBlitzErrorClasses() {
|
||||||
|
if (_blitzErrorClassRegistered || !isNotInUserTestEnvironment()) return
|
||||||
SuperJson.registerClass(AuthenticationError, {
|
SuperJson.registerClass(AuthenticationError, {
|
||||||
identifier: "BlitzAuthenticationError",
|
identifier: "BlitzAuthenticationError",
|
||||||
allowProps: errorProps,
|
allowProps: errorProps,
|
||||||
@@ -125,5 +128,7 @@ if (isNotInUserTestEnvironment() && !globalThis._BLITZ_ERROR_CLASS_REGISTERED) {
|
|||||||
allowProps: errorProps,
|
allowProps: errorProps,
|
||||||
})
|
})
|
||||||
|
|
||||||
globalThis._BLITZ_ERROR_CLASS_REGISTERED = true
|
_blitzErrorClassRegistered = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerBlitzErrorClasses()
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
PaginationArgumentError,
|
PaginationArgumentError,
|
||||||
RedirectError,
|
RedirectError,
|
||||||
OAuthError,
|
OAuthError,
|
||||||
|
registerBlitzErrorClasses,
|
||||||
} from "./errors"
|
} from "./errors"
|
||||||
import type {EventHooks, MiddlewareHooks} from "./types"
|
import type {EventHooks, MiddlewareHooks} from "./types"
|
||||||
export {
|
export {
|
||||||
@@ -18,7 +19,9 @@ export {
|
|||||||
PaginationArgumentError,
|
PaginationArgumentError,
|
||||||
RedirectError,
|
RedirectError,
|
||||||
OAuthError,
|
OAuthError,
|
||||||
|
registerBlitzErrorClasses,
|
||||||
}
|
}
|
||||||
|
export * from "./utils/enhance-prisma"
|
||||||
|
|
||||||
export type BlitzProviderComponentType = <TProps = any>(
|
export type BlitzProviderComponentType = <TProps = any>(
|
||||||
component: ComponentType<TProps>,
|
component: ComponentType<TProps>,
|
||||||
@@ -84,6 +87,5 @@ if (typeof window !== "undefined" && process.env.NODE_ENV === "development") {
|
|||||||
|
|
||||||
export * from "./utils"
|
export * from "./utils"
|
||||||
export * from "./types"
|
export * from "./types"
|
||||||
export * from "./utils/enhance-prisma"
|
|
||||||
export * from "./utils/zod"
|
export * from "./utils/zod"
|
||||||
export {reduceBlitzClientPlugins} from "./plugin"
|
export {reduceBlitzClientPlugins} from "./plugin"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export * from "./utils/enhance-prisma"
|
|||||||
export * from "./middleware"
|
export * from "./middleware"
|
||||||
export * from "./paginate"
|
export * from "./paginate"
|
||||||
export * from "./logging"
|
export * from "./logging"
|
||||||
export {reduceBlitzServerPlugins} from "./plugin"
|
export {reduceBlitzServerPlugins, merge, pipe} from "./plugin"
|
||||||
export {findNodeModulesRoot, findNodeModulesRootSync} from "./cli/utils/find-node-modules"
|
export {findNodeModulesRoot, findNodeModulesRootSync} from "./cli/utils/find-node-modules"
|
||||||
|
|
||||||
export {startWatcher, stopWatcher} from "./cli/utils/routes-manifest"
|
export {startWatcher, stopWatcher} from "./cli/utils/routes-manifest"
|
||||||
|
|||||||
@@ -99,8 +99,8 @@ const branded = (msg: string) => {
|
|||||||
* @param {string} msg
|
* @param {string} msg
|
||||||
*/
|
*/
|
||||||
const clearLine = (msg?: string) => {
|
const clearLine = (msg?: string) => {
|
||||||
readline.clearLine(process.stdout, 0)
|
readline.clearLine(process.stdout as any, 0)
|
||||||
readline.cursorTo(process.stdout, 0)
|
readline.cursorTo(process.stdout as any, 0)
|
||||||
msg && process.stdout.write(msg)
|
msg && process.stdout.write(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,7 +173,8 @@ const box = async (mes: string, title: string) => {
|
|||||||
* If the DEBUG env var is set this will write to the console
|
* If the DEBUG env var is set this will write to the console
|
||||||
* @param str msg
|
* @param str msg
|
||||||
*/
|
*/
|
||||||
const debug = require("debug")("blitz")
|
import Debug from "debug"
|
||||||
|
const debug = Debug("blitz")
|
||||||
|
|
||||||
export const log = {
|
export const log = {
|
||||||
withBrand,
|
withBrand,
|
||||||
|
|||||||
@@ -1,5 +1,103 @@
|
|||||||
# @blitzjs/codemod
|
# @blitzjs/codemod
|
||||||
|
|
||||||
|
## 2.1.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [2711291e9]
|
||||||
|
- Updated dependencies [56bd32b55]
|
||||||
|
- @blitzjs/generator@2.1.2
|
||||||
|
- blitz@2.1.2
|
||||||
|
|
||||||
|
## 2.1.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [9a0ba87d1]
|
||||||
|
- blitz@2.1.1
|
||||||
|
- @blitzjs/generator@2.1.1
|
||||||
|
|
||||||
|
## 2.1.0
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [d53da39cb]
|
||||||
|
- Updated dependencies [3b10b13e6]
|
||||||
|
- blitz@2.1.0
|
||||||
|
- @blitzjs/generator@2.1.0
|
||||||
|
|
||||||
|
## 2.0.10
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [318e9740d]
|
||||||
|
- blitz@2.0.10
|
||||||
|
- @blitzjs/generator@2.0.10
|
||||||
|
|
||||||
|
## 2.0.9
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [5a14306f7]
|
||||||
|
- blitz@2.0.9
|
||||||
|
- @blitzjs/generator@2.0.9
|
||||||
|
|
||||||
|
## 2.0.8
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [5e61a1681]
|
||||||
|
- Updated dependencies [77555468f]
|
||||||
|
- blitz@2.0.8
|
||||||
|
- @blitzjs/generator@2.0.8
|
||||||
|
|
||||||
|
## 2.0.7
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [ee7bf87ec]
|
||||||
|
- Updated dependencies [178c152b2]
|
||||||
|
- blitz@2.0.7
|
||||||
|
- @blitzjs/generator@2.0.7
|
||||||
|
|
||||||
|
## 2.0.6
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [76a2544f9]
|
||||||
|
- blitz@2.0.6
|
||||||
|
- @blitzjs/generator@2.0.6
|
||||||
|
|
||||||
|
## 2.0.5
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [6f54841b7]
|
||||||
|
- blitz@2.0.5
|
||||||
|
- @blitzjs/generator@2.0.5
|
||||||
|
|
||||||
|
## 2.0.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- f25aac08c: Added support to codemod upgrade-legacy for projects that have their pages folder nested in a src/ folder
|
||||||
|
- Updated dependencies [dd604c767]
|
||||||
|
- Updated dependencies [71b995003]
|
||||||
|
- Updated dependencies [28a79040e]
|
||||||
|
- blitz@2.0.4
|
||||||
|
- @blitzjs/generator@2.0.4
|
||||||
|
|
||||||
|
## 2.0.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 956a739e8: codemod: provide correct path to new template paths
|
||||||
|
- Updated dependencies [47722e045]
|
||||||
|
- Updated dependencies [2f5c8a3a0]
|
||||||
|
- Updated dependencies [595f400e9]
|
||||||
|
- @blitzjs/generator@2.0.3
|
||||||
|
- blitz@2.0.3
|
||||||
|
|
||||||
## 2.0.2
|
## 2.0.2
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@blitzjs/codemod",
|
"name": "@blitzjs/codemod",
|
||||||
"version": "2.0.2",
|
"version": "2.1.2",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "unbuild",
|
"build": "unbuild",
|
||||||
"dev": "watch unbuild src --wait=0.2",
|
"dev": "watch unbuild src --wait=0.2",
|
||||||
@@ -25,9 +25,9 @@
|
|||||||
"@babel/plugin-proposal-class-properties": "7.17.12",
|
"@babel/plugin-proposal-class-properties": "7.17.12",
|
||||||
"@babel/plugin-syntax-jsx": "7.17.12",
|
"@babel/plugin-syntax-jsx": "7.17.12",
|
||||||
"@babel/plugin-syntax-typescript": "7.17.12",
|
"@babel/plugin-syntax-typescript": "7.17.12",
|
||||||
"@blitzjs/generator": "2.0.2",
|
"@blitzjs/generator": "2.1.2",
|
||||||
"arg": "5.0.1",
|
"arg": "5.0.1",
|
||||||
"blitz": "2.0.2",
|
"blitz": "2.1.2",
|
||||||
"chalk": "^4.1.0",
|
"chalk": "^4.1.0",
|
||||||
"cross-spawn": "7.0.3",
|
"cross-spawn": "7.0.3",
|
||||||
"debug": "4.3.3",
|
"debug": "4.3.3",
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/preset-env": "7.12.10",
|
"@babel/preset-env": "7.12.10",
|
||||||
"@blitzjs/config": "2.0.2",
|
"@blitzjs/config": "2.1.2",
|
||||||
"@types/jscodeshift": "0.11.2",
|
"@types/jscodeshift": "0.11.2",
|
||||||
"@types/node": "18.11.9",
|
"@types/node": "18.11.9",
|
||||||
"ast-types": "0.14.2",
|
"ast-types": "0.14.2",
|
||||||
|
|||||||
@@ -32,6 +32,12 @@ class ExpectedError extends Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const findPagesDirectory = () => {
|
||||||
|
const srcPagesDir = path.join("src", "pages")
|
||||||
|
const pagesDir = path.resolve("pages")
|
||||||
|
return fs.existsSync(srcPagesDir) ? path.resolve(srcPagesDir) : pagesDir
|
||||||
|
}
|
||||||
|
|
||||||
const isInternalBlitzMonorepoDevelopment = fs.existsSync(
|
const isInternalBlitzMonorepoDevelopment = fs.existsSync(
|
||||||
path.join(__dirname, "../../../blitz-next"),
|
path.join(__dirname, "../../../blitz-next"),
|
||||||
)
|
)
|
||||||
@@ -46,7 +52,22 @@ const upgradeLegacy = async () => {
|
|||||||
if (blitzConfigFile === "") {
|
if (blitzConfigFile === "") {
|
||||||
throw new ExpectedError("Could not identify Legacy Blitz Config file")
|
throw new ExpectedError("Could not identify Legacy Blitz Config file")
|
||||||
}
|
}
|
||||||
const appDir = path.resolve("app")
|
// Check if app directory exists in either app/ or src/app
|
||||||
|
const appDir = fs.existsSync(path.resolve("app"))
|
||||||
|
? path.resolve("app")
|
||||||
|
: fs.existsSync(path.resolve("src"))
|
||||||
|
? path.resolve(path.join("src", "app"))
|
||||||
|
: ""
|
||||||
|
try {
|
||||||
|
// Throw Error if appDir empty
|
||||||
|
if (appDir === "") {
|
||||||
|
throw new ExpectedError(
|
||||||
|
"Could not identify Legacy Blitz App directory in project (no app/ or src/ directory found)",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
let failedAt =
|
let failedAt =
|
||||||
fs.existsSync(path.resolve(".migration.json")) && fs.readJSONSync("./.migration.json").failedAt
|
fs.existsSync(path.resolve(".migration.json")) && fs.readJSONSync("./.migration.json").failedAt
|
||||||
let collectedErrors: {message: string; step: number}[] = []
|
let collectedErrors: {message: string; step: number}[] = []
|
||||||
@@ -536,10 +557,10 @@ const upgradeLegacy = async () => {
|
|||||||
isInternalBlitzMonorepoDevelopment ? "templates" : "dist/templates",
|
isInternalBlitzMonorepoDevelopment ? "templates" : "dist/templates",
|
||||||
)
|
)
|
||||||
const blitzServer = fs
|
const blitzServer = fs
|
||||||
.readFileSync(path.join(templatePath, "app", "app", "blitz-server.ts"))
|
.readFileSync(path.join(templatePath, "app", "src", "app", "blitz-server.ts"))
|
||||||
.toString()
|
.toString()
|
||||||
const blitzClient = fs
|
const blitzClient = fs
|
||||||
.readFileSync(path.join(templatePath, "app", "app", "blitz-client.ts"))
|
.readFileSync(path.join(templatePath, "app", "src", "app", "blitz-client.ts"))
|
||||||
.toString()
|
.toString()
|
||||||
|
|
||||||
const replaceTemplateValues = (input: string) => {
|
const replaceTemplateValues = (input: string) => {
|
||||||
@@ -584,7 +605,9 @@ const upgradeLegacy = async () => {
|
|||||||
j.Identifier,
|
j.Identifier,
|
||||||
(node) => node.name === "cookiePrefix",
|
(node) => node.name === "cookiePrefix",
|
||||||
)
|
)
|
||||||
cookieIdentifierBlitzClient.get().parentPath.value.value.value = cookiePrefix
|
if (cookieIdentifierBlitzClient.length) {
|
||||||
|
cookieIdentifierBlitzClient.get().parentPath.value.value.value = cookiePrefix
|
||||||
|
}
|
||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
`${appDir}/blitz-client.${isTypescript ? "ts" : "js"}`,
|
`${appDir}/blitz-client.${isTypescript ? "ts" : "js"}`,
|
||||||
@@ -676,7 +699,7 @@ const upgradeLegacy = async () => {
|
|||||||
steps.push({
|
steps.push({
|
||||||
name: "create pages/api/rpc directory and add [[...blitz]].ts wildecard API route",
|
name: "create pages/api/rpc directory and add [[...blitz]].ts wildecard API route",
|
||||||
action: async () => {
|
action: async () => {
|
||||||
const pagesDir = path.resolve("pages/api/rpc")
|
const pagesDir = path.resolve(`${findPagesDirectory()}/api/rpc`)
|
||||||
const templatePath = path.join(
|
const templatePath = path.join(
|
||||||
require.resolve("@blitzjs/generator"),
|
require.resolve("@blitzjs/generator"),
|
||||||
"..",
|
"..",
|
||||||
@@ -684,7 +707,9 @@ const upgradeLegacy = async () => {
|
|||||||
isInternalBlitzMonorepoDevelopment ? "templates" : "dist/templates",
|
isInternalBlitzMonorepoDevelopment ? "templates" : "dist/templates",
|
||||||
)
|
)
|
||||||
const rpcRoute = fs
|
const rpcRoute = fs
|
||||||
.readFileSync(path.join(templatePath, "app", "pages", "api", "rpc", "blitzrpcroute.ts"))
|
.readFileSync(
|
||||||
|
path.join(templatePath, "app", "src", "pages", "api", "rpc", "blitzrpcroute.ts"),
|
||||||
|
)
|
||||||
.toString()
|
.toString()
|
||||||
|
|
||||||
if (!fs.existsSync(pagesDir)) {
|
if (!fs.existsSync(pagesDir)) {
|
||||||
@@ -925,7 +950,7 @@ const upgradeLegacy = async () => {
|
|||||||
name: "convert useRouterQuery to useRouter",
|
name: "convert useRouterQuery to useRouter",
|
||||||
action: async () => {
|
action: async () => {
|
||||||
//First check ./pages
|
//First check ./pages
|
||||||
const pagesDir = path.resolve("pages")
|
const pagesDir = findPagesDirectory()
|
||||||
getAllFiles(pagesDir, [], [], [".ts", ".tsx", ".js", ".jsx"]).forEach((file) => {
|
getAllFiles(pagesDir, [], [], [".ts", ".tsx", ".js", ".jsx"]).forEach((file) => {
|
||||||
try {
|
try {
|
||||||
const filepath = path.resolve(pagesDir, file)
|
const filepath = path.resolve(pagesDir, file)
|
||||||
@@ -1057,7 +1082,7 @@ const upgradeLegacy = async () => {
|
|||||||
steps.push({
|
steps.push({
|
||||||
name: "wrap App component with withBlitz HOC",
|
name: "wrap App component with withBlitz HOC",
|
||||||
action: async () => {
|
action: async () => {
|
||||||
const pagesDir = path.resolve("pages")
|
const pagesDir = findPagesDirectory()
|
||||||
|
|
||||||
const program = getCollectionFromSource(
|
const program = getCollectionFromSource(
|
||||||
path.join(pagesDir, `_app.${isTypescript ? "tsx" : "jsx"}`),
|
path.join(pagesDir, `_app.${isTypescript ? "tsx" : "jsx"}`),
|
||||||
@@ -1107,7 +1132,7 @@ const upgradeLegacy = async () => {
|
|||||||
steps.push({
|
steps.push({
|
||||||
name: "update imports in the _document file",
|
name: "update imports in the _document file",
|
||||||
action: async () => {
|
action: async () => {
|
||||||
const pagesDir = path.resolve("pages")
|
const pagesDir = findPagesDirectory()
|
||||||
|
|
||||||
if (fs.existsSync(path.join(pagesDir, `_document.${isTypescript ? "tsx" : "jsx"}`))) {
|
if (fs.existsSync(path.join(pagesDir, `_document.${isTypescript ? "tsx" : "jsx"}`))) {
|
||||||
const program = getCollectionFromSource(
|
const program = getCollectionFromSource(
|
||||||
@@ -1187,7 +1212,7 @@ const upgradeLegacy = async () => {
|
|||||||
steps.push({
|
steps.push({
|
||||||
name: "wrap getServerSideProps, getStaticProps and API handlers with gSSP, gSP, and api",
|
name: "wrap getServerSideProps, getStaticProps and API handlers with gSSP, gSP, and api",
|
||||||
action: async () => {
|
action: async () => {
|
||||||
const pagesDir = path.resolve("pages")
|
const pagesDir = findPagesDirectory()
|
||||||
getAllFiles(pagesDir, [], ["api"], [".ts", ".tsx", ".js", ".jsx"]).forEach((file) => {
|
getAllFiles(pagesDir, [], ["api"], [".ts", ".tsx", ".js", ".jsx"]).forEach((file) => {
|
||||||
try {
|
try {
|
||||||
const program = getCollectionFromSource(file)
|
const program = getCollectionFromSource(file)
|
||||||
@@ -1310,7 +1335,9 @@ const upgradeLegacy = async () => {
|
|||||||
steps.push({
|
steps.push({
|
||||||
name: "check for usages of invokeWithMiddleware",
|
name: "check for usages of invokeWithMiddleware",
|
||||||
action: async () => {
|
action: async () => {
|
||||||
getAllFiles(path.resolve("pages"), [], [], [".ts", ".tsx", ".js", ".jsx"]).forEach((file) => {
|
const srcPagesDir = path.resolve(path.join("src/pages"))
|
||||||
|
const pagesDir = fs.existsSync(srcPagesDir) ? srcPagesDir : path.resolve("pages")
|
||||||
|
getAllFiles(pagesDir, [], [], [".ts", ".tsx", ".js", ".jsx"]).forEach((file) => {
|
||||||
const program = getCollectionFromSource(file)
|
const program = getCollectionFromSource(file)
|
||||||
try {
|
try {
|
||||||
const invokeWithMiddlewarePath = findCallExpression(program, "invokeWithMiddleware")
|
const invokeWithMiddlewarePath = findCallExpression(program, "invokeWithMiddleware")
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ describe("replaceBlitzPkgsVersions", () => {
|
|||||||
return {
|
return {
|
||||||
fetchDistTags: vi.fn((pkg: string) => {
|
fetchDistTags: vi.fn((pkg: string) => {
|
||||||
if (pkg === "blitz") {
|
if (pkg === "blitz") {
|
||||||
return {alpha: "1.0.0", beta: "2.0.0", danger: "3.0.0"}
|
return {alpha: "1.0.0", beta: "2.0.0", danger: "2.1.0"}
|
||||||
}
|
}
|
||||||
if (pkg === "zod") {
|
if (pkg === "zod") {
|
||||||
return {latest: "1.2.3"}
|
return {latest: "1.2.3"}
|
||||||
@@ -52,10 +52,10 @@ describe("replaceBlitzPkgsVersions", () => {
|
|||||||
it("correctly updates versions with the danger tag", async () => {
|
it("correctly updates versions with the danger tag", async () => {
|
||||||
expect(await replaceBlitzPkgsVersions(pkgJson, "danger")).toEqual({
|
expect(await replaceBlitzPkgsVersions(pkgJson, "danger")).toEqual({
|
||||||
dependencies: {
|
dependencies: {
|
||||||
blitz: "3.0.0",
|
blitz: "2.1.0",
|
||||||
"@blitzjs/rpc": "3.0.0",
|
"@blitzjs/rpc": "2.1.0",
|
||||||
"@blitzjs/auth": "3.0.0",
|
"@blitzjs/auth": "2.1.0",
|
||||||
"@blitzjs/next": "3.0.0",
|
"@blitzjs/next": "2.1.0",
|
||||||
next: "12.2.0",
|
next: "12.2.0",
|
||||||
zod: "1.2.3",
|
zod: "1.2.3",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,27 @@
|
|||||||
# @blitzjs/config
|
# @blitzjs/config
|
||||||
|
|
||||||
|
## 2.1.2
|
||||||
|
|
||||||
|
## 2.1.1
|
||||||
|
|
||||||
|
## 2.1.0
|
||||||
|
|
||||||
|
## 2.0.10
|
||||||
|
|
||||||
|
## 2.0.9
|
||||||
|
|
||||||
|
## 2.0.8
|
||||||
|
|
||||||
|
## 2.0.7
|
||||||
|
|
||||||
|
## 2.0.6
|
||||||
|
|
||||||
|
## 2.0.5
|
||||||
|
|
||||||
|
## 2.0.4
|
||||||
|
|
||||||
|
## 2.0.3
|
||||||
|
|
||||||
## 2.0.2
|
## 2.0.2
|
||||||
|
|
||||||
## 2.0.1
|
## 2.0.1
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@blitzjs/config",
|
"name": "@blitzjs/config",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2.0.2",
|
"version": "2.1.2",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "5.42.1",
|
"@typescript-eslint/eslint-plugin": "5.42.1",
|
||||||
|
|||||||
@@ -1,5 +1,83 @@
|
|||||||
# @blitzjs/generator
|
# @blitzjs/generator
|
||||||
|
|
||||||
|
## 2.1.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 2711291e9: Remove `views` property from `Session.PublicData` in `types.ts` file again
|
||||||
|
- 56bd32b55: Fix Zod schema generation for datetime fields by removing extra parentheses.
|
||||||
|
|
||||||
|
## 2.1.1
|
||||||
|
|
||||||
|
## 2.1.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 3b10b13e6: feat: add blitz auth support for the Web `Request` API standard
|
||||||
|
|
||||||
|
Usage using the new `withBlitzAuth` adapter in the App Router:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import {withBlitzAuth} from "app/blitz-server"
|
||||||
|
|
||||||
|
export const {POST} = withBlitzAuth({
|
||||||
|
POST: async (_request, _params, ctx) => {
|
||||||
|
const session = ctx.session
|
||||||
|
await session.$revoke()
|
||||||
|
|
||||||
|
return new Response(
|
||||||
|
JSON.stringify({
|
||||||
|
userId: session.userId,
|
||||||
|
}),
|
||||||
|
{status: 200},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
feat: New Blitz RPC handler meant to with the next.js app router `route.ts` files
|
||||||
|
|
||||||
|
Usage using the new `rpcAppHandler` function
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// app/api/rpc/[[...blitz]]/route.ts
|
||||||
|
import {rpcAppHandler} from "@blitzjs/rpc"
|
||||||
|
import {withBlitzAuth} from "app/blitz-server"
|
||||||
|
|
||||||
|
// Usage with blitz auth
|
||||||
|
export const {GET, POST, HEAD} = withBlitzAuth(rpcAppHandler())
|
||||||
|
|
||||||
|
// Standalone usage
|
||||||
|
export const {GET, POST, HEAD} = rpcAppHandler()
|
||||||
|
```
|
||||||
|
|
||||||
|
chore: Update the app directory starter
|
||||||
|
|
||||||
|
## 2.0.10
|
||||||
|
|
||||||
|
## 2.0.9
|
||||||
|
|
||||||
|
## 2.0.8
|
||||||
|
|
||||||
|
## 2.0.7
|
||||||
|
|
||||||
|
## 2.0.6
|
||||||
|
|
||||||
|
## 2.0.5
|
||||||
|
|
||||||
|
## 2.0.4
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 71b995003: fix: ajv dependency was not installed with blitz new
|
||||||
|
|
||||||
|
## 2.0.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 47722e045: Fix: search inside any subdirectory to inside `src|app` directories to find `blitz-server.ts` to use the `BlitzCliConfig` configurations.
|
||||||
|
- 595f400e9: fix: add missing `prettier`, `pretty-quick` and other missing dev dependencies in the new app template
|
||||||
|
|
||||||
## 2.0.2
|
## 2.0.2
|
||||||
|
|
||||||
## 2.0.1
|
## 2.0.1
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user