Compare commits
17 Commits
@blitzjs/r
...
blitz@2.1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a096f2cd80 | ||
|
|
ded16b325b | ||
|
|
4494662d6d | ||
|
|
9a0ba87d15 | ||
|
|
c80ce51d36 | ||
|
|
b505933a16 | ||
|
|
d53da39cbf | ||
|
|
e1055f7366 | ||
|
|
3b10b13e6b | ||
|
|
25601754a4 | ||
|
|
e0cfa328ec | ||
|
|
f02469aac8 | ||
|
|
2f3c552ac3 | ||
|
|
721461a7b9 | ||
|
|
3193bdea48 | ||
|
|
318e9740d6 | ||
|
|
0df368308b |
@@ -4065,6 +4065,25 @@
|
||||
"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"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
24
.github/workflows/main.yml
vendored
24
.github/workflows/main.yml
vendored
@@ -17,13 +17,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: pnpm/action-setup@v2.2.4
|
||||
- uses: pnpm/action-setup@v4.0.0
|
||||
with:
|
||||
version: 8.6.5
|
||||
version: 8.6.6
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 20
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
@@ -38,13 +38,13 @@ jobs:
|
||||
name: Build
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: pnpm/action-setup@v2.2.4
|
||||
- uses: pnpm/action-setup@v4.0.0
|
||||
with:
|
||||
version: 8.6.5
|
||||
version: 8.6.6
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 20
|
||||
cache: "pnpm"
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- name: Build
|
||||
@@ -68,14 +68,14 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PNPM
|
||||
uses: pnpm/action-setup@v2.2.4
|
||||
uses: pnpm/action-setup@v4.0.0
|
||||
with:
|
||||
version: 8.6.5
|
||||
version: 8.6.6
|
||||
|
||||
- name: Setup node@16
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 20
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install dependencies
|
||||
@@ -129,15 +129,15 @@ jobs:
|
||||
|
||||
- name: Setup PNPM
|
||||
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:
|
||||
version: 8.6.5
|
||||
version: 8.6.6
|
||||
|
||||
- name: Setup node@18
|
||||
if: matrix.folder != 'next-13-app-dir' || matrix.os != 'windows-latest'
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 20
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install dependencies
|
||||
|
||||
17
.github/workflows/pr-release.yml
vendored
17
.github/workflows/pr-release.yml
vendored
@@ -22,16 +22,19 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: resolve pr refs
|
||||
id: refs
|
||||
uses: eficode/resolve-pr-refs@main
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Fetch PR information
|
||||
id: pr_info
|
||||
env:
|
||||
GH_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@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
ref: ${{ steps.pr_info.outputs.head_sha }}
|
||||
|
||||
- name: Setup PNPM
|
||||
uses: pnpm/action-setup@646cdf48217256a3d0b80361c5a50727664284f2
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
16.13.2
|
||||
@@ -6,7 +6,7 @@
|
||||
<img alt="" src="https://img.shields.io/badge/Join%20our%20community-6700EB.svg?style=for-the-badge&labelColor=000000&logoWidth=20&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAQ9SURBVHgB7d3dVdtAEIbhcSpICUoH0IEogQqSVBBSAU4FSSpIOoAORAfQgSghHXzZ1U/YcMD4R9rZmf2ec3y448LyiNf27iLiGIAmPLrweC9Un3DhrzG6EarLNP09nlwJ1SOZ/lQr5N80/S/p2QMVCBf5N17XCfm1Y/rBHqjAG9PPHvBsz+mf9WAP+HLA9M/YA14cOP2payH7jpj+VCtk1wnTP+vj7xCy6cTpn7EHLMLp059iD1iD8eveJbVCNsSLheX1YA/YgOWnf8YeKB3Wmf7Ud6Fy4f/FHmtpxbl3YlC4MJ/Cj0bWdwPnPbARg+L0S54XQHS32WwuxClzd4CM0z9rPfeAuTtA5ulPXYQ7wZ04Y+oOoDD9KZc9YOoOoDj9s4dwFzgXR6w1wIPoOvPWA9buAHEJ173o3gWiy3AnuBUHLEbgmYwvAk1/wuM8vAgexThzbwPDkx7/DHwVXfFOxP2GmsKd4Ab6zPeAyU8CI7AHFmH2BRCBPXAyk18GzUrqAXCTiR4ssyj0VFw/oCU8+e+RZ33AWz6KMaYbIIWxB+JSLs1bsbkeMN0AqakHvoku9oA2sAfqBvbAQdw0QArsgb25aYBUQT3QgT2gB+yBuqGcHij2UCqXDZACe2Anlw2QYg/QAOyBuoE98CL3DZDCuK4/rh/Q7oGL6U+TOvcNkJoijN8X1C48+T+g75eQDrAH/qmqAVJgDwyqaoAUe4AGYA/UDZX3QLUNkEIZPRCd5+6BahsgVUgPROwBTSijB7jpVAvGHriHvmw9wAZ4BpX1ABvgmakHtPcbRuwBTWAPULgAV9D/jKDY9YRvwvgEaurD44uQHvAol7qBW7WKluVtIHiUS7GyvA0s6CiXDnxrpQfsgbqBS7GKk/2jYHCrVlGyfxTMrVo0ALdq1Q3sgSKofh0M9oA61a+D2QM0AHugbmAPqClmSRjK2apVVQ8UsySsoK1aHdgDesCtWnUDeyCrIpeFg1u3sylyWTi3btMA7IG6gT2wuuK3hoE9sKrit4YVslWLPaAN7IG6ocKt2zmY2h4O9sDiTG0PZw/QANy6XTewBxZj9ogYVHy025LMHhEz9cBn0We6B0yfERReBLfhx0/R1YQHPx/QBPbA0VwcEwf2wNFcHBPHHjiem3MC2QPHcXdSaJjA+KfgTPQ8hhfjBzHC40mhlzJ+Xq9lK4a4PCs43AVaGTed5mZq+iOXZwWHi3AnOj2wFWNcnxYe7gTxLtBKHuamP/J+Wnh8a5irB7ZC5Yk9gPX1QuXC+usHWqGyhYvUYR0a7zboUOFCNVhnk0krZAOW7wFOvzXhom2xnEbIHizTA1wEYhWW6YFGyC6c1gOcfg9wfA80Qj7g8B7g9HuCww+haIR8wf49wOn3Cvv9k8tGyC/s7gFOv3fY3QONkH+v9MBWqB7PeqDn9FcIT//kcitUn6kHOu/T/xfWzlQy3dEHhwAAAABJRU5ErkJggg==">
|
||||
</a>
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
||||
<a aria-label="All Contributors" href="#contributors-"><img alt="" src="https://img.shields.io/badge/all_contributors-428-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-430-17BB8A.svg?style=for-the-badge&labelColor=000000"></a>
|
||||
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
||||
<a aria-label="License" href="https://github.com/blitz-js/blitz/blob/main/LICENSE">
|
||||
<img alt="" src="https://img.shields.io/npm/l/blitz.svg?style=for-the-badge&labelColor=000000&color=blue">
|
||||
@@ -79,6 +79,9 @@ Your financial contributions help ensure Blitz continues to be developed and mai
|
||||
</a></td>
|
||||
<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"/>
|
||||
</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>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -754,6 +757,8 @@ Thanks to these wonderful people ([emoji key](https://allcontributors.org/docs/e
|
||||
</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>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
@@ -1,5 +1,39 @@
|
||||
# next-blitz-auth
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "next-blitz-auth",
|
||||
"version": "0.1.10",
|
||||
"version": "0.1.13",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"blitz:dev": "next dev",
|
||||
@@ -12,17 +12,17 @@
|
||||
"schema": "prisma/schema.prisma"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/auth": "2.0.9",
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/next": "2.0.9",
|
||||
"@blitzjs/rpc": "2.0.9",
|
||||
"@blitzjs/auth": "2.1.1",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@blitzjs/next": "2.1.1",
|
||||
"@blitzjs/rpc": "2.1.1",
|
||||
"@hookform/error-message": "2.0.0",
|
||||
"@hookform/resolvers": "2.9.10",
|
||||
"@prisma/client": "^4.5.0",
|
||||
"@tanstack/react-query": "4.0.10",
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"flatted": "3.2.7",
|
||||
"next": "canary",
|
||||
"next": "14.3.0-canary.28",
|
||||
"prisma": "^4.5.0",
|
||||
"react": "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 {RpcServerPlugin} from "@blitzjs/rpc"
|
||||
|
||||
const {api, getBlitzContext, useAuthenticatedBlitzContext, invoke} = setupBlitzServer({
|
||||
plugins: [
|
||||
AuthServerPlugin({
|
||||
cookiePrefix: "web-cookie-prefix",
|
||||
storage: PrismaStorage(db),
|
||||
isAuthorized: simpleRolesIsAuthorized,
|
||||
}),
|
||||
RpcServerPlugin({
|
||||
logging: {
|
||||
disablelevel: "debug",
|
||||
},
|
||||
onInvokeError(error) {
|
||||
console.log("onInvokeError", error)
|
||||
},
|
||||
}),
|
||||
],
|
||||
logger: BlitzLogger({}),
|
||||
})
|
||||
const {api, getBlitzContext, useAuthenticatedBlitzContext, invoke, withBlitzAuth} =
|
||||
setupBlitzServer({
|
||||
plugins: [
|
||||
AuthServerPlugin({
|
||||
cookiePrefix: "web-cookie-prefix",
|
||||
storage: PrismaStorage(db),
|
||||
isAuthorized: simpleRolesIsAuthorized,
|
||||
}),
|
||||
RpcServerPlugin({
|
||||
logging: {
|
||||
disablelevel: "debug",
|
||||
},
|
||||
onInvokeError(error) {
|
||||
console.log("onInvokeError", error)
|
||||
},
|
||||
}),
|
||||
],
|
||||
logger: BlitzLogger({}),
|
||||
})
|
||||
|
||||
export {api, getBlitzContext, useAuthenticatedBlitzContext, invoke}
|
||||
export {api, getBlitzContext, useAuthenticatedBlitzContext, invoke, withBlitzAuth}
|
||||
|
||||
export const cliConfig: BlitzCliConfig = {
|
||||
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 = {
|
||||
httpMethod: "GET",
|
||||
httpMethod: "POST",
|
||||
}
|
||||
|
||||
@@ -23,15 +23,15 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/auth": "2.0.9",
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/next": "2.0.9",
|
||||
"@blitzjs/rpc": "2.0.9",
|
||||
"@blitzjs/auth": "2.1.1",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@blitzjs/next": "2.1.1",
|
||||
"@blitzjs/rpc": "2.1.1",
|
||||
"@hookform/error-message": "2.0.0",
|
||||
"@hookform/resolvers": "2.9.10",
|
||||
"@prisma/client": "4.6.1",
|
||||
"blitz": "2.0.9",
|
||||
"next": "canary",
|
||||
"blitz": "2.1.1",
|
||||
"next": "14.3.0-canary.28",
|
||||
"openid-client": "5.2.1",
|
||||
"prisma": "4.6.1",
|
||||
"react": "18.2.0",
|
||||
|
||||
@@ -24,16 +24,16 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/auth": "2.0.9",
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/next": "2.0.9",
|
||||
"@blitzjs/rpc": "2.0.9",
|
||||
"@blitzjs/auth": "2.1.1",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@blitzjs/next": "2.1.1",
|
||||
"@blitzjs/rpc": "2.1.1",
|
||||
"@hookform/error-message": "2.0.0",
|
||||
"@hookform/resolvers": "2.9.10",
|
||||
"@prisma/client": "4.6.1",
|
||||
"blitz": "2.0.9",
|
||||
"next": "canary",
|
||||
"next-auth": "4.18.7",
|
||||
"blitz": "2.1.1",
|
||||
"next": "14.3.0-canary.28",
|
||||
"next-auth": "4.24.7",
|
||||
"prisma": "4.6.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
|
||||
@@ -11,15 +11,11 @@ const LoginPage: BlitzPage = () => {
|
||||
<LoginForm
|
||||
onSuccess={(_user) => {
|
||||
const next = router.query.next ? decodeURIComponent(router.query.next as string) : "/"
|
||||
// return router.push(next)
|
||||
return router.push(next)
|
||||
}}
|
||||
/>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
LoginPage.authenticate = {
|
||||
redirectTo: "/",
|
||||
}
|
||||
|
||||
export default LoginPage
|
||||
@@ -16,17 +16,17 @@
|
||||
"schema": "./db/schema.prisma"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/auth": "2.0.9",
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/next": "2.0.9",
|
||||
"@blitzjs/rpc": "2.0.9",
|
||||
"@blitzjs/auth": "2.1.1",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@blitzjs/next": "2.1.1",
|
||||
"@blitzjs/rpc": "2.1.1",
|
||||
"@prisma/client": "4.6.1",
|
||||
"@types/jest": "29.2.2",
|
||||
"@types/passport-twitter": "1.0.37",
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"jest": "29.3.0",
|
||||
"jest-environment-jsdom": "29.3.0",
|
||||
"next": "canary",
|
||||
"next": "14.3.0-canary.28",
|
||||
"passport-mock-strategy": "2.0.0",
|
||||
"passport-twitter": "1.0.4",
|
||||
"prisma": "4.6.1",
|
||||
|
||||
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"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/auth": "2.0.9",
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/next": "2.0.9",
|
||||
"@blitzjs/rpc": "2.0.9",
|
||||
"@blitzjs/auth": "2.1.1",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@blitzjs/next": "2.1.1",
|
||||
"@blitzjs/rpc": "2.1.1",
|
||||
"@hookform/error-message": "2.0.0",
|
||||
"@hookform/resolvers": "2.9.10",
|
||||
"@prisma/client": "4.6.1",
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"delay": "5.0.0",
|
||||
"next": "canary",
|
||||
"next": "14.3.0-canary.28",
|
||||
"prisma": "4.6.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
"prisma:studio": "prisma studio"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/auth": "2.0.9",
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/next": "2.0.9",
|
||||
"@blitzjs/auth": "2.1.1",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@blitzjs/next": "2.1.1",
|
||||
"@prisma/client": "4.6.1",
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"lowdb": "3.0.0",
|
||||
"next": "canary",
|
||||
"next": "14.3.0-canary.28",
|
||||
"prisma": "4.6.1",
|
||||
"react": "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) => {
|
||||
const blitzContext = ctx
|
||||
|
||||
const user = await authenticateUser(req.query.email as string, req.query.password as string)
|
||||
|
||||
await blitzContext.session.$create({
|
||||
await ctx.session.$create({
|
||||
userId: user.id,
|
||||
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})
|
||||
})
|
||||
|
||||
@@ -16,19 +16,19 @@
|
||||
"schema": "db/schema.prisma"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/auth": "2.0.9",
|
||||
"@blitzjs/next": "2.0.9",
|
||||
"@blitzjs/rpc": "2.0.9",
|
||||
"@blitzjs/auth": "2.1.1",
|
||||
"@blitzjs/next": "2.1.1",
|
||||
"@blitzjs/rpc": "2.1.1",
|
||||
"@prisma/client": "4.6.1",
|
||||
"blitz": "2.0.9",
|
||||
"lowdb": "3.0.0",
|
||||
"next": "canary",
|
||||
"blitz": "2.1.1",
|
||||
"lowdb": "2.1.0",
|
||||
"next": "14.3.0-canary.28",
|
||||
"prisma": "4.6.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@next/bundle-analyzer": "12.0.8",
|
||||
"@types/express": "4.17.13",
|
||||
"@types/fs-extra": "9.0.13",
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/next": "2.0.9",
|
||||
"@blitzjs/rpc": "2.0.9",
|
||||
"blitz": "2.0.9",
|
||||
"next": "canary",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@blitzjs/next": "2.1.1",
|
||||
"@blitzjs/rpc": "2.1.1",
|
||||
"blitz": "2.1.1",
|
||||
"next": "14.3.0-canary.28",
|
||||
"react": "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,6 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
/// <reference types="next/navigation-types/compat/navigation" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
"prisma:studio": "prisma studio"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/auth": "2.0.9",
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/next": "2.0.9",
|
||||
"@blitzjs/rpc": "2.0.9",
|
||||
"@blitzjs/auth": "2.1.1",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@blitzjs/next": "2.1.1",
|
||||
"@blitzjs/rpc": "2.1.1",
|
||||
"@prisma/client": "4.6.1",
|
||||
"blitz": "2.0.9",
|
||||
"lowdb": "3.0.0",
|
||||
"next": "canary",
|
||||
"blitz": "2.1.1",
|
||||
"lowdb": "2.1.0",
|
||||
"next": "14.3.0-canary.28",
|
||||
"prisma": "4.6.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
@@ -45,6 +45,6 @@
|
||||
"node-fetch": "3.2.3",
|
||||
"playwright": "1.28.0",
|
||||
"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 {simpleRolesIsAuthorized} from "@blitzjs/auth"
|
||||
import {BlitzLogger} from "blitz"
|
||||
import {RpcServerPlugin} from "@blitzjs/rpc"
|
||||
|
||||
const {api, getBlitzContext} = setupBlitzServer({
|
||||
export const {api, getBlitzContext, withBlitzAuth} = setupBlitzServer({
|
||||
plugins: [
|
||||
AuthServerPlugin({
|
||||
cookiePrefix: "auth-tests-cookie-prefix",
|
||||
storage: PrismaStorage(db),
|
||||
isAuthorized: simpleRolesIsAuthorized,
|
||||
}),
|
||||
RpcServerPlugin({}),
|
||||
],
|
||||
logger: BlitzLogger({}),
|
||||
})
|
||||
|
||||
export {api, getBlitzContext}
|
||||
|
||||
@@ -57,7 +57,7 @@ const runTests = (mode?: string) => {
|
||||
"should render result for open query",
|
||||
async () => {
|
||||
const res = await fetch(`http://localhost:${appPort}/api/noauth`, {
|
||||
method: "GET",
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/json; charset=utf-8"},
|
||||
})
|
||||
expect(res.status).toBe(200)
|
||||
@@ -67,7 +67,7 @@ const runTests = (mode?: string) => {
|
||||
|
||||
it("sets correct cookie", async () => {
|
||||
const res = await fetch(`http://localhost:${appPort}/api/noauth`, {
|
||||
method: "GET",
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/json; charset=utf-8"},
|
||||
})
|
||||
const cookieHeader = res.headers.get("Set-Cookie")
|
||||
@@ -94,6 +94,8 @@ const runTests = (mode?: string) => {
|
||||
async () => {
|
||||
const browser = await webdriver(appPort, "/react-query")
|
||||
|
||||
await browser.refresh()
|
||||
|
||||
browser.waitForElementByCss("#button", 0)
|
||||
await browser.elementByCss("#button").click()
|
||||
|
||||
@@ -133,7 +135,7 @@ const runTests = (mode?: string) => {
|
||||
|
||||
it("does not require CSRF header on HEAD requests", async () => {
|
||||
const res = await fetch(`http://localhost:${appPort}/api/noauth`, {
|
||||
method: "GET",
|
||||
method: "POST",
|
||||
headers: {"Content-Type": "application/json; charset=utf-8"},
|
||||
})
|
||||
const cookieHeader = res.headers.get("Set-Cookie")
|
||||
|
||||
@@ -16,19 +16,19 @@
|
||||
"prisma:studio": "prisma studio"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/auth": "2.0.9",
|
||||
"@blitzjs/next": "2.0.9",
|
||||
"@blitzjs/rpc": "2.0.9",
|
||||
"@blitzjs/auth": "2.1.1",
|
||||
"@blitzjs/next": "2.1.1",
|
||||
"@blitzjs/rpc": "2.1.1",
|
||||
"@prisma/client": "4.6.1",
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"lowdb": "3.0.0",
|
||||
"next": "canary",
|
||||
"next": "14.3.0-canary.28",
|
||||
"prisma": "4.6.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@next/bundle-analyzer": "12.0.8",
|
||||
"@types/express": "4.17.13",
|
||||
"@types/fs-extra": "9.0.13",
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
"clean": "rm -rf .turbo && rm -rf node_modules"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/auth": "2.0.9",
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/next": "2.0.9",
|
||||
"@blitzjs/rpc": "2.0.9",
|
||||
"@blitzjs/auth": "2.1.1",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@blitzjs/next": "2.1.1",
|
||||
"@blitzjs/rpc": "2.1.1",
|
||||
"@prisma/client": "4.6.1",
|
||||
"@tanstack/react-query": "4.0.10",
|
||||
"blitz": "2.0.9",
|
||||
"next": "canary",
|
||||
"blitz": "2.1.1",
|
||||
"next": "14.3.0-canary.28",
|
||||
"prisma": "4.6.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
|
||||
@@ -16,18 +16,18 @@
|
||||
"schema": "db/schema.prisma"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/next": "2.0.9",
|
||||
"@blitzjs/rpc": "2.0.9",
|
||||
"@blitzjs/next": "2.1.1",
|
||||
"@blitzjs/rpc": "2.1.1",
|
||||
"@prisma/client": "4.6.1",
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"lowdb": "3.0.0",
|
||||
"next": "canary",
|
||||
"next": "14.3.0-canary.28",
|
||||
"prisma": "4.6.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@next/bundle-analyzer": "12.0.8",
|
||||
"@types/express": "4.17.13",
|
||||
"@types/fs-extra": "9.0.13",
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/next": "2.0.9",
|
||||
"@blitzjs/rpc": "2.0.9",
|
||||
"blitz": "2.0.9",
|
||||
"next": "canary",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@blitzjs/next": "2.1.1",
|
||||
"@blitzjs/rpc": "2.1.1",
|
||||
"blitz": "2.1.1",
|
||||
"next": "14.3.0-canary.28",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
},
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/next": "2.0.9",
|
||||
"@blitzjs/rpc": "2.0.9",
|
||||
"blitz": "2.0.9",
|
||||
"next": "canary",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@blitzjs/next": "2.1.1",
|
||||
"@blitzjs/rpc": "2.1.1",
|
||||
"blitz": "2.1.1",
|
||||
"next": "14.3.0-canary.28",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
},
|
||||
|
||||
@@ -16,19 +16,19 @@
|
||||
"schema": "db/schema.prisma"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/auth": "2.0.9",
|
||||
"@blitzjs/next": "2.0.9",
|
||||
"@blitzjs/rpc": "2.0.9",
|
||||
"@blitzjs/auth": "2.1.1",
|
||||
"@blitzjs/next": "2.1.1",
|
||||
"@blitzjs/rpc": "2.1.1",
|
||||
"@prisma/client": "4.6.1",
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"lowdb": "3.0.0",
|
||||
"next": "canary",
|
||||
"next": "14.3.0-canary.28",
|
||||
"prisma": "4.6.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@next/bundle-analyzer": "12.0.8",
|
||||
"@types/express": "4.17.13",
|
||||
"@types/fs-extra": "9.0.13",
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@blitzjs/config": "workspace:2.0.9",
|
||||
"@blitzjs/next": "workspace:2.0.9",
|
||||
"@blitzjs/rpc": "workspace:2.0.9",
|
||||
"@blitzjs/config": "workspace:2.1.1",
|
||||
"@blitzjs/next": "workspace:2.1.1",
|
||||
"@blitzjs/rpc": "workspace:2.1.1",
|
||||
"@tanstack/react-query": "4.13.0",
|
||||
"@testing-library/react": "13.4.0",
|
||||
"@types/express": "4.17.13",
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
"husky": "8.0.2",
|
||||
"jsdom": "^19.0.0",
|
||||
"lint-staged": "13.0.3",
|
||||
"next": "canary",
|
||||
"next": "14.3.0-canary.28",
|
||||
"only-allow": "1.1.0",
|
||||
"prettier": "^2.7.1",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-prisma": "4.4.0",
|
||||
"pretty-quick": "3.1.3",
|
||||
"turbo": "1.10.9",
|
||||
@@ -47,10 +47,11 @@
|
||||
},
|
||||
"pnpm": {
|
||||
"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"
|
||||
"@types/mime": "3.0.4",
|
||||
"next": "14.3.0-canary.28"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,70 @@
|
||||
# @blitzjs/auth
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@blitzjs/auth",
|
||||
"version": "2.0.9",
|
||||
"version": "2.1.1",
|
||||
"homepage": "https://blitzjs.com/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -50,7 +50,7 @@
|
||||
"url": "0.11.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"next": "*",
|
||||
"next-auth": "*",
|
||||
"secure-password": "4.0.0"
|
||||
@@ -67,7 +67,7 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@testing-library/react": "13.4.0",
|
||||
"@testing-library/react-hooks": "8.0.1",
|
||||
"@types/cookie": "0.4.1",
|
||||
@@ -75,9 +75,9 @@
|
||||
"@types/jsonwebtoken": "8.5.8",
|
||||
"@types/react": "18.0.25",
|
||||
"@types/react-dom": "17.0.14",
|
||||
"blitz": "2.0.9",
|
||||
"next": "canary",
|
||||
"next-auth": "4.18.7",
|
||||
"blitz": "2.1.1",
|
||||
"next": "14.3.0-canary.28",
|
||||
"next-auth": "4.24.7",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"secure-password": "4.0.0",
|
||||
|
||||
@@ -107,13 +107,8 @@ export function NextAuthAdapter<P extends Provider[]>(
|
||||
providerId = providerId.split("?")[0]
|
||||
}
|
||||
const {options, cookies} = await init({
|
||||
// @ts-ignore
|
||||
url: new URL(
|
||||
internalRequest.url,
|
||||
process.env.APP_ORIGIN || process.env.BLITZ_DEV_SERVER_ORIGIN,
|
||||
),
|
||||
authOptions: config as unknown as AuthOptions,
|
||||
host: internalRequest.url.host,
|
||||
origin: internalRequest.origin,
|
||||
action,
|
||||
providerId,
|
||||
callbackUrl: req.body?.callbackUrl ?? (req.query?.callbackUrl as string),
|
||||
|
||||
@@ -74,16 +74,28 @@ export async function toInternalRequest(req: Request): Promise<
|
||||
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 {
|
||||
url,
|
||||
action,
|
||||
providerId,
|
||||
method: req.method ?? "GET",
|
||||
headers: Object.fromEntries(req.headers),
|
||||
headers,
|
||||
body: req.body ? await readJSONBody(req.body) : undefined,
|
||||
cookies: parseCookie(req.headers.get("cookie") ?? "") ?? {},
|
||||
error: url.searchParams.get("error") ?? undefined,
|
||||
query: Object.fromEntries(url.searchParams),
|
||||
origin: detectOrigin(
|
||||
headers["x-forwarded-host"] ?? headers.host,
|
||||
headers["x-forwarded-proto"],
|
||||
),
|
||||
}
|
||||
} catch (error) {
|
||||
return error as Error
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {RequestMiddleware, Ctx, createServerPlugin} 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 {getBlitzContext, getSession, useAuthenticatedBlitzContext} from "./auth-sessions"
|
||||
|
||||
@@ -130,11 +130,28 @@ export const AuthServerPlugin = createServerPlugin((options: AuthPluginOptions)
|
||||
if (!globalThis.__BLITZ_GET_RSC_CONTEXT) {
|
||||
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 {
|
||||
requestMiddlewares: [authPluginSessionMiddleware()],
|
||||
exports: () => ({
|
||||
getBlitzContext,
|
||||
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 cookie, {parse} from "cookie"
|
||||
import {IncomingMessage, ServerResponse} from "http"
|
||||
import {sign as jwtSign, verify as jwtVerify} from "jsonwebtoken"
|
||||
import jsonwebtoken from "jsonwebtoken"
|
||||
import {
|
||||
assert,
|
||||
isPast,
|
||||
@@ -13,9 +12,9 @@ import {
|
||||
AuthorizationError,
|
||||
CSRFTokenMismatchError,
|
||||
log,
|
||||
AuthenticatedCtx,
|
||||
baseLogger,
|
||||
chalk,
|
||||
AuthenticatedCtx,
|
||||
} from "blitz"
|
||||
import {
|
||||
EmptyPublicData,
|
||||
@@ -39,12 +38,69 @@ import {
|
||||
AuthenticatedSessionContext,
|
||||
} from "../shared"
|
||||
import {generateToken, hash256} from "./auth-utils"
|
||||
import {Socket} from "net"
|
||||
import {UrlObject} from "url"
|
||||
import {formatWithValidation} from "../shared/url-utils"
|
||||
|
||||
export function isLocalhost(req: IncomingMessage): boolean {
|
||||
let {host} = req.headers
|
||||
import type {UrlObject} from "url"
|
||||
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
|
||||
if (host) {
|
||||
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> {
|
||||
({ctx, args}: {ctx: any; args: [roleOrRoles?: RoleType | RoleType[]]}): boolean
|
||||
@@ -131,14 +188,6 @@ type 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(
|
||||
res: ServerResponse & {[key: string]: any},
|
||||
): asserts res is ServerResponse & {blitzCtx: Ctx} {
|
||||
@@ -147,58 +196,112 @@ 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(
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
appDir = false,
|
||||
isRsc: boolean,
|
||||
): Promise<SessionContext>
|
||||
export async function getSession(
|
||||
req: IncomingMessage | Request,
|
||||
res?: ServerResponse,
|
||||
isRsc?: boolean,
|
||||
): Promise<SessionContext> {
|
||||
ensureApiRequest(req)
|
||||
ensureMiddlewareResponse(res)
|
||||
|
||||
debug("cookiePrefix", globalThis.__BLITZ_SESSION_COOKIE_PREFIX)
|
||||
|
||||
if (res.blitzCtx.session) {
|
||||
debug("Returning existing session")
|
||||
return res.blitzCtx.session
|
||||
const headers = convertRequestToHeader(req)
|
||||
if (res) {
|
||||
ensureMiddlewareResponse(res)
|
||||
debug("cookiePrefix", globalThis.__BLITZ_SESSION_COOKIE_PREFIX)
|
||||
if (res.blitzCtx.session) {
|
||||
debug("Returning existing session")
|
||||
return res.blitzCtx.session
|
||||
}
|
||||
}
|
||||
|
||||
let sessionKernel = await getSessionKernel(req, res)
|
||||
const method = req.method
|
||||
let sessionKernel = await getSessionKernel({headers, method})
|
||||
|
||||
if (sessionKernel) {
|
||||
debug("Got existing session", sessionKernel)
|
||||
}
|
||||
|
||||
if (!sessionKernel) {
|
||||
debug("No session found, creating anonymous session")
|
||||
sessionKernel = await createAnonymousSession(req, res)
|
||||
sessionKernel = await createAnonymousSession({headers})
|
||||
}
|
||||
|
||||
const sessionContext = makeProxyToPublicData(
|
||||
new SessionContextClass(req, res, sessionKernel, appDir),
|
||||
new SessionContextClass(headers, sessionKernel, !!isRsc, res),
|
||||
)
|
||||
debug("New session context")
|
||||
res.blitzCtx.session = sessionContext
|
||||
if (res) {
|
||||
;(res as any).blitzCtx = {
|
||||
session: sessionContext,
|
||||
}
|
||||
sessionContext.setSession(res)
|
||||
}
|
||||
return sessionContext
|
||||
}
|
||||
|
||||
interface RouteUrlObject extends Pick<UrlObject, "pathname" | "query" | "href"> {
|
||||
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 req = new IncomingMessage(new Socket()) as IncomingMessage & {
|
||||
cookies: {[key: string]: string}
|
||||
}
|
||||
req.headers = Object.fromEntries(headers())
|
||||
const reqHeader = Object.fromEntries(headers())
|
||||
const csrfToken = cookies().get(COOKIE_CSRF_TOKEN())
|
||||
if (csrfToken) {
|
||||
req.headers[HEADER_CSRF] = csrfToken.value
|
||||
reqHeader[HEADER_CSRF] = csrfToken.value
|
||||
}
|
||||
req.cookies = Object.fromEntries(
|
||||
cookies()
|
||||
.getAll()
|
||||
.map((c: {name: string; value: string}) => [c.name, c.value]),
|
||||
const session = await getSession(
|
||||
{
|
||||
headers: new Headers(reqHeader),
|
||||
method: "POST",
|
||||
} as Request,
|
||||
null as never,
|
||||
true,
|
||||
)
|
||||
const res = new ServerResponse(req)
|
||||
const session = await getSession(req, res, true)
|
||||
const ctx: Ctx = {
|
||||
session,
|
||||
}
|
||||
@@ -206,17 +309,13 @@ export async function getBlitzContext(): Promise<Ctx> {
|
||||
} catch (e) {
|
||||
if ((e as NodeJS.ErrnoException).code === "MODULE_NOT_FOUND") {
|
||||
throw new Error(
|
||||
"Usage of `useAuthenticatedBlitzContext` is supported only in next.js 13.0.0 and above. Please upgrade your next.js version.",
|
||||
"Usage of `getBlitzContext` is supported only in next.js 13.0.0 and above. Please upgrade your next.js version.",
|
||||
)
|
||||
}
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
interface RouteUrlObject extends Pick<UrlObject, "pathname" | "query" | "href"> {
|
||||
pathname: string
|
||||
}
|
||||
|
||||
export async function useAuthenticatedBlitzContext({
|
||||
redirectTo,
|
||||
redirectAuthenticatedTo,
|
||||
@@ -291,18 +390,6 @@ export async function useAuthenticatedBlitzContext({
|
||||
}
|
||||
}
|
||||
|
||||
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 message = `Method ${method} is not yet supported in React Server Components`
|
||||
const _box = await log.box(message, log.chalk.hex("8a3df0").bold("Blitz Auth"))
|
||||
@@ -310,21 +397,27 @@ const NotSupportedMessage = async (method: string) => {
|
||||
}
|
||||
|
||||
export class SessionContextClass implements SessionContext {
|
||||
private _req: IncomingMessage & {cookies: {[key: string]: string}}
|
||||
private _res: ServerResponse & {blitzCtx: Ctx}
|
||||
private _headers: Headers
|
||||
private _kernel: SessionKernel
|
||||
private _appDir: boolean
|
||||
private _isRsc: boolean
|
||||
private _response?: ServerResponse
|
||||
|
||||
constructor(
|
||||
req: IncomingMessage & {cookies: {[key: string]: string}},
|
||||
res: ServerResponse & {blitzCtx: Ctx},
|
||||
kernel: SessionKernel,
|
||||
appDir: boolean,
|
||||
) {
|
||||
this._req = req
|
||||
this._res = res
|
||||
private static headersToIncludeInResponse = [
|
||||
HEADER_CSRF,
|
||||
HEADER_CSRF_ERROR,
|
||||
HEADER_PUBLIC_DATA_TOKEN,
|
||||
HEADER_SESSION_CREATED,
|
||||
]
|
||||
|
||||
constructor(headers: Headers, kernel: SessionKernel, isRsc: boolean, response?: ServerResponse) {
|
||||
this._headers = headers
|
||||
this._kernel = kernel
|
||||
this._appDir = appDir
|
||||
this._isRsc = isRsc
|
||||
this._response = response
|
||||
}
|
||||
|
||||
$antiCSRFToken() {
|
||||
return this._kernel.antiCSRFToken
|
||||
}
|
||||
|
||||
get $handle() {
|
||||
@@ -352,38 +445,69 @@ export class SessionContextClass implements SessionContext {
|
||||
$isAuthorized(...args: IsAuthorizedArgs) {
|
||||
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 {
|
||||
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>) {
|
||||
if (this._appDir) {
|
||||
if (this._isRsc) {
|
||||
void NotSupportedMessage("$create")
|
||||
return
|
||||
}
|
||||
this._kernel = await createNewSession({
|
||||
req: this._req,
|
||||
res: this._res,
|
||||
headers: this._headers,
|
||||
publicData,
|
||||
privateData,
|
||||
jwtPayload: this._kernel.jwtPayload,
|
||||
anonymous: false,
|
||||
})
|
||||
|
||||
if (this._response) this.setSession(this._response)
|
||||
}
|
||||
|
||||
async $revoke() {
|
||||
if (this._appDir) {
|
||||
if (this._isRsc) {
|
||||
void NotSupportedMessage("$revoke")
|
||||
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() {
|
||||
if (this._appDir) {
|
||||
if (this._isRsc) {
|
||||
void NotSupportedMessage("$revokeAll")
|
||||
return
|
||||
}
|
||||
@@ -395,25 +519,28 @@ export class SessionContextClass implements SessionContext {
|
||||
}
|
||||
|
||||
async $setPublicData(data: Record<any, any>) {
|
||||
if (this._appDir) {
|
||||
if (this._isRsc) {
|
||||
void NotSupportedMessage("$setPublicData")
|
||||
return
|
||||
}
|
||||
if (this.userId) {
|
||||
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() {
|
||||
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")
|
||||
return Promise.resolve()
|
||||
}
|
||||
return setPrivateData(this._kernel, data)
|
||||
await setPrivateData(this._kernel, data)
|
||||
if (this._response) this.setSession(this._response)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,7 +632,7 @@ const JWT_ANONYMOUS_SUBJECT = "anonymous"
|
||||
const JWT_ALGORITHM = "HS256"
|
||||
|
||||
const createAnonymousSessionToken = (payload: AnonymousSessionPayload) => {
|
||||
return jwtSign({[JWT_NAMESPACE]: payload}, getSessionSecretKey() || "", {
|
||||
return jsonwebtoken.sign({[JWT_NAMESPACE]: payload}, getSessionSecretKey() || "", {
|
||||
algorithm: JWT_ALGORITHM,
|
||||
issuer: JWT_ISSUER,
|
||||
audience: JWT_AUDIENCE,
|
||||
@@ -519,7 +646,7 @@ const parseAnonymousSessionToken = (token: string) => {
|
||||
const secret = getSessionSecretKey()
|
||||
|
||||
try {
|
||||
const fullPayload = jwtVerify(token, secret!, {
|
||||
const fullPayload = jsonwebtoken.verify(token, secret!, {
|
||||
algorithms: [JWT_ALGORITHM],
|
||||
issuer: JWT_ISSUER,
|
||||
audience: JWT_AUDIENCE,
|
||||
@@ -536,126 +663,127 @@ const parseAnonymousSessionToken = (token: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const setCookie = (res: ServerResponse, cookieStr: string) => {
|
||||
const getCookieName = (c: string) => c.split("=", 2)[0]
|
||||
const appendCookie = () => append(res, "Set-Cookie", cookieStr)
|
||||
|
||||
const cookiesHeader = res.getHeader("Set-Cookie")
|
||||
const cookieName = getCookieName(cookieStr)
|
||||
|
||||
if (typeof cookiesHeader !== "string" && !Array.isArray(cookiesHeader)) {
|
||||
appendCookie()
|
||||
return
|
||||
const cookieOptions = (headers: Headers, expires: Date, httpOnly: boolean) => {
|
||||
return {
|
||||
path: "/",
|
||||
secure:
|
||||
global.sessionConfig.secureCookies &&
|
||||
!isLocalhost({
|
||||
headers,
|
||||
} as Request),
|
||||
sameSite: global.sessionConfig.sameSite,
|
||||
domain: global.sessionConfig.domain,
|
||||
expires: new Date(expires),
|
||||
httpOnly,
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof cookiesHeader === "string") {
|
||||
if (cookieName === getCookieName(cookiesHeader)) {
|
||||
res.setHeader("Set-Cookie", cookieStr)
|
||||
function replaceOrAppendValueInSetCookieHeader(
|
||||
headers: Headers,
|
||||
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 {
|
||||
appendCookie()
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < cookiesHeader.length; i++) {
|
||||
if (cookieName === getCookieName(cookiesHeader[i] || "")) {
|
||||
cookiesHeader[i] = cookieStr
|
||||
res.setHeader("Set-Cookie", cookiesHeader)
|
||||
return
|
||||
if (i === cookiesAsArray.length - 1) {
|
||||
cookiesAsArray.push(newValue)
|
||||
return cookiesAsArray.join(", ")
|
||||
}
|
||||
}
|
||||
appendCookie()
|
||||
}
|
||||
return cookiesAsArray.filter(Boolean).join(", ")
|
||||
}
|
||||
|
||||
const setHeader = (res: ServerResponse, name: string, value: string) => {
|
||||
res.setHeader(name, value)
|
||||
if ("_blitz" in res) {
|
||||
;(res as any)._blitz[name] = value
|
||||
}
|
||||
}
|
||||
|
||||
const setSessionCookie = (res: ServerResponse, sessionToken: string, expiresAt: Date) => {
|
||||
setCookie(
|
||||
res,
|
||||
cookie.serialize(COOKIE_SESSION_TOKEN(), sessionToken, {
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: global.sessionConfig.secureCookies,
|
||||
sameSite: global.sessionConfig.sameSite,
|
||||
domain: global.sessionConfig.domain,
|
||||
expires: expiresAt,
|
||||
}),
|
||||
const setSessionCookie = (headers: Headers, sessionToken: string, expiresAt: Date) => {
|
||||
const sessionCookie = cookie.serialize(
|
||||
COOKIE_SESSION_TOKEN(),
|
||||
sessionToken,
|
||||
cookieOptions(headers, expiresAt, true),
|
||||
)
|
||||
}
|
||||
|
||||
const setAnonymousSessionCookie = (res: ServerResponse, token: string, expiresAt: Date) => {
|
||||
setCookie(
|
||||
res,
|
||||
cookie.serialize(COOKIE_ANONYMOUS_SESSION_TOKEN(), token, {
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: global.sessionConfig.secureCookies,
|
||||
sameSite: global.sessionConfig.sameSite,
|
||||
domain: global.sessionConfig.domain,
|
||||
expires: expiresAt,
|
||||
}),
|
||||
const newCookies = replaceOrAppendValueInSetCookieHeader(
|
||||
headers,
|
||||
COOKIE_SESSION_TOKEN(),
|
||||
sessionCookie,
|
||||
)
|
||||
headers.set("Set-Cookie", newCookies)
|
||||
}
|
||||
|
||||
const setCSRFCookie = (
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
antiCSRFToken: string,
|
||||
expiresAt: Date,
|
||||
) => {
|
||||
const setAnonymousSessionCookie = (headers: Headers, token: string, expiresAt: Date) => {
|
||||
const anonCookie = cookie.serialize(
|
||||
COOKIE_ANONYMOUS_SESSION_TOKEN(),
|
||||
token,
|
||||
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)
|
||||
assert(antiCSRFToken !== undefined, "Internal error: antiCSRFToken is being set to undefined")
|
||||
setCookie(
|
||||
res,
|
||||
cookie.serialize(COOKIE_CSRF_TOKEN(), antiCSRFToken, {
|
||||
path: "/",
|
||||
secure: global.sessionConfig.secureCookies && !isLocalhost(req),
|
||||
sameSite: global.sessionConfig.sameSite,
|
||||
domain: global.sessionConfig.domain,
|
||||
expires: expiresAt,
|
||||
}),
|
||||
const csrfCookie = cookie.serialize(
|
||||
COOKIE_CSRF_TOKEN(),
|
||||
antiCSRFToken,
|
||||
cookieOptions(headers, expiresAt, false),
|
||||
)
|
||||
|
||||
const newCookies = replaceOrAppendValueInSetCookieHeader(headers, COOKIE_CSRF_TOKEN(), csrfCookie)
|
||||
headers.set("Set-Cookie", newCookies)
|
||||
}
|
||||
|
||||
const setPublicDataCookie = (
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
publicDataToken: string,
|
||||
expiresAt: Date,
|
||||
) => {
|
||||
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 setPublicDataCookie = (headers: Headers, publicDataToken: string, expiresAt: Date) => {
|
||||
headers.set(HEADER_PUBLIC_DATA_TOKEN, "updated")
|
||||
const publicDataCookie = cookie.serialize(
|
||||
COOKIE_PUBLIC_DATA_TOKEN(),
|
||||
publicDataToken,
|
||||
cookieOptions(headers, expiresAt, false),
|
||||
)
|
||||
const newCookies = replaceOrAppendValueInSetCookieHeader(
|
||||
headers,
|
||||
COOKIE_PUBLIC_DATA_TOKEN(),
|
||||
publicDataCookie,
|
||||
)
|
||||
headers.set("Set-Cookie", newCookies)
|
||||
}
|
||||
|
||||
// --------------------------------
|
||||
// Get Session
|
||||
// --------------------------------
|
||||
async function getSessionKernel(
|
||||
req: IncomingMessage & {cookies: {[key: string]: string}},
|
||||
res: ServerResponse,
|
||||
): Promise<SessionKernel | null> {
|
||||
const anonymousSessionToken = req.cookies[COOKIE_ANONYMOUS_SESSION_TOKEN()]
|
||||
const sessionToken = req.cookies[COOKIE_SESSION_TOKEN()] // for essential method
|
||||
const idRefreshToken = req.cookies[COOKIE_REFRESH_TOKEN()] // for advanced method
|
||||
async function getSessionKernel({
|
||||
headers,
|
||||
method,
|
||||
}: {
|
||||
headers: Headers
|
||||
method: string | undefined
|
||||
}): 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 =
|
||||
req.method !== "GET" &&
|
||||
req.method !== "OPTIONS" &&
|
||||
req.method !== "HEAD" &&
|
||||
method !== "GET" &&
|
||||
method !== "OPTIONS" &&
|
||||
method !== "HEAD" &&
|
||||
!process.env.DANGEROUSLY_DISABLE_CSRF_PROTECTION
|
||||
const antiCSRFToken = req.headers[HEADER_CSRF] as string | undefined
|
||||
|
||||
if (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()
|
||||
}
|
||||
|
||||
@@ -710,7 +838,7 @@ async function getSessionKernel(
|
||||
* But only renew with non-GET requests because a GET request could be from a
|
||||
* browser level navigation
|
||||
*/
|
||||
if (req.method !== "GET") {
|
||||
if (method !== "GET") {
|
||||
// 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
|
||||
const hasPublicDataChanged =
|
||||
@@ -733,8 +861,7 @@ async function getSessionKernel(
|
||||
|
||||
if (hasPublicDataChanged || hasQuarterExpiryTimePassed) {
|
||||
await refreshSession(
|
||||
req,
|
||||
res,
|
||||
headers,
|
||||
{
|
||||
handle,
|
||||
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()
|
||||
}
|
||||
|
||||
@@ -795,16 +922,14 @@ async function getSessionKernel(
|
||||
// Create Session
|
||||
// --------------------------------
|
||||
interface CreateNewAnonSession {
|
||||
req: IncomingMessage
|
||||
res: ServerResponse
|
||||
headers: Headers
|
||||
publicData: EmptyPublicData
|
||||
privateData?: Record<any, any>
|
||||
anonymous: true
|
||||
jwtPayload?: JwtPayload
|
||||
}
|
||||
interface CreateNewAuthedSession {
|
||||
req: IncomingMessage
|
||||
res: ServerResponse
|
||||
headers: Headers
|
||||
publicData: PublicData
|
||||
privateData?: Record<any, any>
|
||||
anonymous: false
|
||||
@@ -814,7 +939,6 @@ interface CreateNewAuthedSession {
|
||||
async function createNewSession(
|
||||
args: CreateNewAnonSession | CreateNewAuthedSession,
|
||||
): Promise<SessionKernel> {
|
||||
const {req, res} = args
|
||||
assert(args.publicData.userId !== undefined, "You must provide publicData.userId")
|
||||
|
||||
const antiCSRFToken = createAntiCSRFToken()
|
||||
@@ -835,12 +959,12 @@ async function createNewSession(
|
||||
new Date(),
|
||||
global.sessionConfig.anonSessionExpiryMinutes as number,
|
||||
)
|
||||
setAnonymousSessionCookie(res, anonymousSessionToken, expiresAt)
|
||||
setCSRFCookie(req, res, antiCSRFToken, expiresAt)
|
||||
setPublicDataCookie(req, res, publicDataToken, expiresAt)
|
||||
setAnonymousSessionCookie(args.headers, anonymousSessionToken, expiresAt)
|
||||
setCSRFCookie(args.headers, antiCSRFToken, expiresAt)
|
||||
setPublicDataCookie(args.headers, publicDataToken, expiresAt)
|
||||
// Clear the essential session cookie in case it was previously set
|
||||
setSessionCookie(res, "", new Date(0))
|
||||
setHeader(res, HEADER_SESSION_CREATED, "true")
|
||||
setSessionCookie(args.headers, "", new Date(0))
|
||||
args.headers.set(HEADER_SESSION_CREATED, "true")
|
||||
|
||||
return {
|
||||
handle,
|
||||
@@ -891,12 +1015,13 @@ async function createNewSession(
|
||||
privateData: JSON.stringify(newPrivateData),
|
||||
})
|
||||
|
||||
setSessionCookie(res, sessionToken, expiresAt)
|
||||
setCSRFCookie(req, res, antiCSRFToken, expiresAt)
|
||||
setPublicDataCookie(req, res, publicDataToken, expiresAt)
|
||||
setSessionCookie(args.headers, sessionToken, expiresAt)
|
||||
debug("Session created", {handle, publicData: newPublicData, expiresAt})
|
||||
setCSRFCookie(args.headers, antiCSRFToken, expiresAt)
|
||||
setPublicDataCookie(args.headers, publicDataToken, expiresAt)
|
||||
// Clear the anonymous session cookie in case it was previously set
|
||||
setAnonymousSessionCookie(res, "", new Date(0))
|
||||
setHeader(res, HEADER_SESSION_CREATED, "true")
|
||||
setAnonymousSessionCookie(args.headers, "", new Date(0))
|
||||
args.headers.set(HEADER_SESSION_CREATED, "true")
|
||||
|
||||
return {
|
||||
handle,
|
||||
@@ -914,10 +1039,9 @@ async function createNewSession(
|
||||
}
|
||||
}
|
||||
|
||||
async function createAnonymousSession(req: IncomingMessage, res: ServerResponse) {
|
||||
async function createAnonymousSession({headers}: {headers: Headers}) {
|
||||
return await createNewSession({
|
||||
req,
|
||||
res,
|
||||
headers,
|
||||
publicData: {userId: null},
|
||||
anonymous: true,
|
||||
})
|
||||
@@ -928,8 +1052,7 @@ async function createAnonymousSession(req: IncomingMessage, res: ServerResponse)
|
||||
// --------------------------------
|
||||
|
||||
async function refreshSession(
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
headers: Headers,
|
||||
sessionKernel: SessionKernel,
|
||||
{publicDataChanged}: {publicDataChanged: boolean},
|
||||
) {
|
||||
@@ -943,8 +1066,8 @@ async function refreshSession(
|
||||
const publicDataToken = createPublicDataToken(sessionKernel.publicData)
|
||||
|
||||
const expiresAt = addYears(new Date(), 30)
|
||||
setAnonymousSessionCookie(res, anonymousSessionToken, expiresAt)
|
||||
setPublicDataCookie(req, res, publicDataToken, expiresAt)
|
||||
setAnonymousSessionCookie(headers, anonymousSessionToken, expiresAt)
|
||||
setPublicDataCookie(headers, publicDataToken, expiresAt)
|
||||
} else if (global.sessionConfig.method === "essential" && "sessionToken" in sessionKernel) {
|
||||
const expiresAt = addMinutes(new Date(), global.sessionConfig.sessionExpiryMinutes as number)
|
||||
|
||||
@@ -952,7 +1075,7 @@ async function refreshSession(
|
||||
if (publicDataChanged) {
|
||||
debug("Public data has changed")
|
||||
const publicDataToken = createPublicDataToken(sessionKernel.publicData)
|
||||
setPublicDataCookie(req, res, publicDataToken, expiresAt)
|
||||
setPublicDataCookie(headers, publicDataToken, expiresAt)
|
||||
await global.sessionConfig.updateSession(sessionKernel.handle, {
|
||||
expiresAt,
|
||||
publicData: JSON.stringify(sessionKernel.publicData),
|
||||
@@ -994,12 +1117,7 @@ async function syncPubicDataFieldsForUserIfNeeded(
|
||||
}
|
||||
}
|
||||
|
||||
async function revokeSession(
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
handle: string,
|
||||
anonymous: boolean = false,
|
||||
) {
|
||||
async function revokeSession(headers: Headers, handle: string, anonymous: boolean = false) {
|
||||
debug("Revoking session", handle)
|
||||
if (!anonymous) {
|
||||
try {
|
||||
@@ -1012,7 +1130,9 @@ async function revokeSession(
|
||||
// This fixes race condition where all client side queries get refreshed
|
||||
// in parallel and each creates a new anon session
|
||||
// https://github.com/blitz-js/blitz/issues/2746
|
||||
return createAnonymousSession(req, res)
|
||||
return createAnonymousSession({
|
||||
headers,
|
||||
})
|
||||
}
|
||||
|
||||
async function revokeAllSessionsForUser(userId: PublicData["userId"]) {
|
||||
@@ -1078,8 +1198,7 @@ async function setPrivateData(sessionKernel: SessionKernel, data: Record<any, an
|
||||
}
|
||||
|
||||
async function setPublicData(
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
headers: Headers,
|
||||
sessionKernel: SessionKernel,
|
||||
data: Record<any, any>,
|
||||
) {
|
||||
@@ -1091,7 +1210,7 @@ async function setPublicData(
|
||||
...data,
|
||||
} as PublicData
|
||||
|
||||
await refreshSession(req, res, {...sessionKernel, publicData}, {publicDataChanged: true})
|
||||
await refreshSession(headers, {...sessionKernel, publicData}, {publicDataChanged: true})
|
||||
return publicData
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,6 @@ export {
|
||||
getSession,
|
||||
isLocalhost,
|
||||
setPublicDataForUser,
|
||||
setCookie,
|
||||
simpleRolesIsAuthorized,
|
||||
getBlitzContext,
|
||||
} from "./auth-sessions"
|
||||
export type {AnonymousSessionPayload, SimpleRolesIsAuthorized} from "./auth-sessions"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//@ts-nocheck
|
||||
import {Ctx} from "blitz"
|
||||
import type {Ctx} from "blitz"
|
||||
import type {ServerResponse} from "http"
|
||||
|
||||
export interface Session {
|
||||
// isAuthorize can be injected here
|
||||
@@ -66,6 +67,12 @@ export interface SessionContextBase {
|
||||
$getPrivateData: () => Promise<Record<any, any>>
|
||||
$setPrivateData: (data: Record<any, any>) => 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
|
||||
|
||||
@@ -1,5 +1,72 @@
|
||||
# @blitzjs/next
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@blitzjs/next",
|
||||
"version": "2.0.9",
|
||||
"version": "2.1.1",
|
||||
"homepage": "https://blitzjs.com/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -29,7 +29,7 @@
|
||||
"eslint.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"@blitzjs/rpc": "2.0.9",
|
||||
"@blitzjs/rpc": "2.1.1",
|
||||
"@types/hoist-non-react-statics": "3.3.1",
|
||||
"copy-webpack-plugin": "11.0.0",
|
||||
"debug": "4.3.3",
|
||||
@@ -39,13 +39,13 @@
|
||||
"supports-color": "8.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"next": "*",
|
||||
"react": "*",
|
||||
"tslog": "4.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@testing-library/dom": "8.13.0",
|
||||
"@testing-library/jest-dom": "5.16.3",
|
||||
"@testing-library/react": "13.4.0",
|
||||
@@ -56,10 +56,10 @@
|
||||
"@types/react": "18.0.25",
|
||||
"@types/react-dom": "17.0.14",
|
||||
"@types/testing-library__react-hooks": "4.0.0",
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"cross-spawn": "7.0.3",
|
||||
"find-up": "4.1.0",
|
||||
"next": "canary",
|
||||
"next": "14.3.0-canary.28",
|
||||
"next-router-mock": "0.9.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
|
||||
@@ -243,6 +243,7 @@ export interface BlitzConfig extends NextConfig {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function withBlitz(nextConfig: BlitzConfig = {}): NextConfig {
|
||||
if (
|
||||
process.env.NODE_ENV !== "production" &&
|
||||
|
||||
@@ -1,5 +1,70 @@
|
||||
# @blitzjs/rpc
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@blitzjs/rpc",
|
||||
"version": "2.0.9",
|
||||
"version": "2.1.1",
|
||||
"homepage": "https://blitzjs.com/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -37,19 +37,19 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@tanstack/query-core": "4.24.4",
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"next": "*",
|
||||
"react": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blitzjs/auth": "2.0.9",
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/auth": "2.1.1",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@tanstack/query-core": "4.24.4",
|
||||
"@types/debug": "4.1.7",
|
||||
"@types/react": "18.0.25",
|
||||
"@types/react-dom": "17.0.14",
|
||||
"blitz": "2.0.9",
|
||||
"next": "canary",
|
||||
"blitz": "2.1.1",
|
||||
"next": "14.3.0-canary.28",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"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 {resolve} from "path"
|
||||
import {deserialize, parse, serialize as superjsonSerialize} from "superjson"
|
||||
@@ -172,6 +172,12 @@ export function installTurboConfig() {
|
||||
as: "*.ts",
|
||||
},
|
||||
},
|
||||
"**/*...blitz*/route.{jsx,tsx,js,ts}": {
|
||||
default: {
|
||||
loaders: [{loader: loaderServer, options: {}}],
|
||||
as: "*.ts",
|
||||
},
|
||||
},
|
||||
"**/{queries,mutations}/**": {
|
||||
browser: {
|
||||
loaders: [
|
||||
@@ -227,12 +233,13 @@ async function getResolverMap(): Promise<ResolverFiles | null | undefined> {
|
||||
}
|
||||
|
||||
interface RpcConfig {
|
||||
onError?: (error: Error, ctx: Ctx) => void
|
||||
formatError?: (error: Error, ctx: Ctx) => Error
|
||||
onError?: (error: Error, ctx?: Ctx) => void
|
||||
formatError?: (error: Error, ctx?: Ctx) => Error
|
||||
logging?: RpcLoggerOptions
|
||||
}
|
||||
|
||||
export function rpcHandler(config: RpcConfig) {
|
||||
export function rpcHandler(config?: RpcConfig) {
|
||||
registerBlitzErrorClasses()
|
||||
return async function handleRpcRequest(req: NextApiRequest, res: NextApiResponse, ctx: Ctx) {
|
||||
const resolverMap = await getResolverMap()
|
||||
assert(resolverMap, "No query or mutation resolvers found")
|
||||
@@ -244,7 +251,7 @@ export function rpcHandler(config: RpcConfig) {
|
||||
const relativeRoutePath = (req.query.blitz as string[])?.join("/")
|
||||
const routePath = "/" + relativeRoutePath
|
||||
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
|
||||
if (!loadableResolver) {
|
||||
@@ -303,6 +310,7 @@ export function rpcHandler(config: RpcConfig) {
|
||||
|
||||
rpcLogger.timer.initNextJsSerialization()
|
||||
;(res as any).blitzResult = result
|
||||
ctx?.session?.setSession(res)
|
||||
res.json({
|
||||
result: serializedResult.json,
|
||||
error: null,
|
||||
@@ -322,16 +330,18 @@ export function rpcHandler(config: RpcConfig) {
|
||||
error.stack = ""
|
||||
}
|
||||
|
||||
config.onError?.(error, ctx)
|
||||
config?.onError?.(error, ctx)
|
||||
rpcLogger.error(error)
|
||||
|
||||
if (!error.statusCode) {
|
||||
error.statusCode = 500
|
||||
}
|
||||
|
||||
const formattedError = config.formatError?.(error, ctx) ?? error
|
||||
const formattedError = config?.formatError?.(error, ctx) ?? error
|
||||
const serializedError = superjsonSerialize(formattedError)
|
||||
|
||||
ctx?.session?.setSession(res)
|
||||
|
||||
res.json({
|
||||
result: null,
|
||||
error: serializedError.json,
|
||||
@@ -349,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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,69 @@
|
||||
# blitz
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "blitz",
|
||||
"version": "2.0.9",
|
||||
"version": "2.1.1",
|
||||
"homepage": "https://blitzjs.com/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -30,7 +30,7 @@
|
||||
"blitz": "bin/blitz"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blitzjs/generator": "2.0.9",
|
||||
"@blitzjs/generator": "2.1.1",
|
||||
"@mrleebo/prisma-ast": "0.2.6",
|
||||
"@types/global-agent": "2.1.1",
|
||||
"arg": "5.0.1",
|
||||
@@ -80,7 +80,7 @@
|
||||
"watchpack": "2.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@types/cookie": "0.4.1",
|
||||
"@types/cross-spawn": "6.0.2",
|
||||
"@types/debug": "4.1.7",
|
||||
|
||||
@@ -3,7 +3,8 @@ import {CliCommand} from "../index"
|
||||
import prompts from "prompts"
|
||||
import {bootstrap} from "global-agent"
|
||||
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 {Stream} from "stream"
|
||||
import {promisify} from "util"
|
||||
|
||||
@@ -4,7 +4,8 @@ import {readJSON} from "fs-extra"
|
||||
import path from "path"
|
||||
import pkgDir from "pkg-dir"
|
||||
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) {
|
||||
const packageDir = await pkgDir(resolveCwd(pkg))
|
||||
|
||||
@@ -5,7 +5,8 @@ import path from "path"
|
||||
import * as REPL from "repl"
|
||||
import {REPLCommand, REPLServer} from "repl"
|
||||
// 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 {log} from "../../logging"
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ import * as esbuild from "esbuild"
|
||||
import pkgDir from "pkg-dir"
|
||||
import type {ServerConfig} from "./config"
|
||||
|
||||
const debug = require("debug")("blitz:utils")
|
||||
import Debug from "debug"
|
||||
const debug = Debug("blitz:utils")
|
||||
|
||||
export function getProjectRootSync() {
|
||||
return process.cwd()
|
||||
|
||||
@@ -5,7 +5,8 @@ import {outputFile, readdir, readFile} from "fs-extra"
|
||||
import Watchpack from "watchpack"
|
||||
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 NEXT_CONFIG_FILE = "next.config.js"
|
||||
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)
|
||||
}
|
||||
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) {
|
||||
return null
|
||||
}
|
||||
|
||||
return result[1] ?? null
|
||||
const [,declaration,compOrHOCName,comp] = result
|
||||
if(declaration||!comp) return compOrHOCName ?? null;
|
||||
return comp ?? null
|
||||
}
|
||||
export async function generateManifest() {
|
||||
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, {
|
||||
identifier: "BlitzAuthenticationError",
|
||||
allowProps: errorProps,
|
||||
@@ -125,5 +128,7 @@ if (isNotInUserTestEnvironment() && !globalThis._BLITZ_ERROR_CLASS_REGISTERED) {
|
||||
allowProps: errorProps,
|
||||
})
|
||||
|
||||
globalThis._BLITZ_ERROR_CLASS_REGISTERED = true
|
||||
_blitzErrorClassRegistered = true
|
||||
}
|
||||
|
||||
registerBlitzErrorClasses()
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
PaginationArgumentError,
|
||||
RedirectError,
|
||||
OAuthError,
|
||||
registerBlitzErrorClasses,
|
||||
} from "./errors"
|
||||
import type {EventHooks, MiddlewareHooks} from "./types"
|
||||
export {
|
||||
@@ -18,6 +19,7 @@ export {
|
||||
PaginationArgumentError,
|
||||
RedirectError,
|
||||
OAuthError,
|
||||
registerBlitzErrorClasses,
|
||||
}
|
||||
export * from "./utils/enhance-prisma"
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ export * from "./utils/enhance-prisma"
|
||||
export * from "./middleware"
|
||||
export * from "./paginate"
|
||||
export * from "./logging"
|
||||
export {reduceBlitzServerPlugins} from "./plugin"
|
||||
export {reduceBlitzServerPlugins, merge, pipe} from "./plugin"
|
||||
export {findNodeModulesRoot, findNodeModulesRootSync} from "./cli/utils/find-node-modules"
|
||||
|
||||
export {startWatcher, stopWatcher} from "./cli/utils/routes-manifest"
|
||||
|
||||
@@ -99,8 +99,8 @@ const branded = (msg: string) => {
|
||||
* @param {string} msg
|
||||
*/
|
||||
const clearLine = (msg?: string) => {
|
||||
readline.clearLine(process.stdout, 0)
|
||||
readline.cursorTo(process.stdout, 0)
|
||||
readline.clearLine(process.stdout as any, 0)
|
||||
readline.cursorTo(process.stdout as any, 0)
|
||||
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
|
||||
* @param str msg
|
||||
*/
|
||||
const debug = require("debug")("blitz")
|
||||
import Debug from "debug"
|
||||
const debug = Debug("blitz")
|
||||
|
||||
export const log = {
|
||||
withBrand,
|
||||
|
||||
@@ -1,5 +1,30 @@
|
||||
# @blitzjs/codemod
|
||||
|
||||
## 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@blitzjs/codemod",
|
||||
"version": "2.0.9",
|
||||
"version": "2.1.1",
|
||||
"scripts": {
|
||||
"build": "unbuild",
|
||||
"dev": "watch unbuild src --wait=0.2",
|
||||
@@ -25,9 +25,9 @@
|
||||
"@babel/plugin-proposal-class-properties": "7.17.12",
|
||||
"@babel/plugin-syntax-jsx": "7.17.12",
|
||||
"@babel/plugin-syntax-typescript": "7.17.12",
|
||||
"@blitzjs/generator": "2.0.9",
|
||||
"@blitzjs/generator": "2.1.1",
|
||||
"arg": "5.0.1",
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"chalk": "^4.1.0",
|
||||
"cross-spawn": "7.0.3",
|
||||
"debug": "4.3.3",
|
||||
@@ -38,7 +38,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "7.12.10",
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@types/jscodeshift": "0.11.2",
|
||||
"@types/node": "18.11.9",
|
||||
"ast-types": "0.14.2",
|
||||
|
||||
@@ -10,7 +10,7 @@ describe("replaceBlitzPkgsVersions", () => {
|
||||
return {
|
||||
fetchDistTags: vi.fn((pkg: string) => {
|
||||
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") {
|
||||
return {latest: "1.2.3"}
|
||||
@@ -52,10 +52,10 @@ describe("replaceBlitzPkgsVersions", () => {
|
||||
it("correctly updates versions with the danger tag", async () => {
|
||||
expect(await replaceBlitzPkgsVersions(pkgJson, "danger")).toEqual({
|
||||
dependencies: {
|
||||
blitz: "3.0.0",
|
||||
"@blitzjs/rpc": "3.0.0",
|
||||
"@blitzjs/auth": "3.0.0",
|
||||
"@blitzjs/next": "3.0.0",
|
||||
blitz: "2.1.0",
|
||||
"@blitzjs/rpc": "2.1.0",
|
||||
"@blitzjs/auth": "2.1.0",
|
||||
"@blitzjs/next": "2.1.0",
|
||||
next: "12.2.0",
|
||||
zod: "1.2.3",
|
||||
},
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# @blitzjs/config
|
||||
|
||||
## 2.1.1
|
||||
|
||||
## 2.1.0
|
||||
|
||||
## 2.0.10
|
||||
|
||||
## 2.0.9
|
||||
|
||||
## 2.0.8
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@blitzjs/config",
|
||||
"private": true,
|
||||
"version": "2.0.9",
|
||||
"version": "2.1.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "5.42.1",
|
||||
|
||||
@@ -1,5 +1,53 @@
|
||||
# @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
|
||||
|
||||
## 2.0.10
|
||||
|
||||
## 2.0.9
|
||||
|
||||
## 2.0.8
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@blitzjs/generator",
|
||||
"version": "2.0.9",
|
||||
"version": "2.1.1",
|
||||
"homepage": "https://blitzjs.com/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -54,7 +54,7 @@
|
||||
"zod": "3.20.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@juanm04/cpx": "2.0.1",
|
||||
"@types/babel__core": "7.1.19",
|
||||
"@types/diff": "5.0.2",
|
||||
|
||||
@@ -68,11 +68,15 @@ export class AppGenerator extends Generator<AppGeneratorOptions> {
|
||||
this.destinationPath("package.json"),
|
||||
)
|
||||
|
||||
const rpcEndpointPath = `src/pages/api/rpc/blitzrpcroute.${this.options.useTs ? "ts" : "js"}`
|
||||
const rpcEndpointPath = `src/app/api/rpc/blitzrpcroute/route.${
|
||||
this.options.useTs ? "ts" : "js"
|
||||
}`
|
||||
if (this.fs.exists(rpcEndpointPath)) {
|
||||
this.fs.move(
|
||||
this.destinationPath(rpcEndpointPath),
|
||||
this.destinationPath(`src/pages/api/rpc/[[...blitz]].${this.options.useTs ? "ts" : "js"}`),
|
||||
this.destinationPath(
|
||||
`src/app/api/rpc/[[...blitz]]/route.${this.options.useTs ? "ts" : "js"}`,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# https://EditorConfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 2
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
@@ -0,0 +1,4 @@
|
||||
import {rpcAppHandler} from "@blitzjs/rpc"
|
||||
import {withBlitzAuth} from "src/app/blitz-server"
|
||||
|
||||
export const {GET, HEAD, POST} = withBlitzAuth(rpcAppHandler())
|
||||
@@ -5,7 +5,7 @@ import {BlitzLogger} from "blitz"
|
||||
import {RpcServerPlugin} from "@blitzjs/rpc"
|
||||
import {authConfig} from "./blitz-auth-config"
|
||||
|
||||
const {api, getBlitzContext, useAuthenticatedBlitzContext, invoke} = setupBlitzServer({
|
||||
const {api, getBlitzContext, useAuthenticatedBlitzContext, invoke,withBlitzAuth} = setupBlitzServer({
|
||||
plugins: [
|
||||
AuthServerPlugin({
|
||||
...authConfig,
|
||||
@@ -17,4 +17,4 @@ const {api, getBlitzContext, useAuthenticatedBlitzContext, invoke} = setupBlitzS
|
||||
logger: BlitzLogger({}),
|
||||
})
|
||||
|
||||
export {api, getBlitzContext, useAuthenticatedBlitzContext, invoke}
|
||||
export {api, getBlitzContext, useAuthenticatedBlitzContext, invoke,withBlitzAuth}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
// Note: This stays in the /pages folder for the time being
|
||||
|
||||
import { rpcHandler } from "@blitzjs/rpc"
|
||||
import { api } from "src/app/blitz-server"
|
||||
|
||||
export default api(rpcHandler({ onError: (error, ctx) => console.log(error) }))
|
||||
@@ -25,7 +25,7 @@
|
||||
"@typescript-eslint/parser": "5.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@blitzjs/config": "2.0.9",
|
||||
"@blitzjs/config": "2.1.1",
|
||||
"@types/react": "18.0.25",
|
||||
"@types/react-dom": "17.0.14",
|
||||
"react": "18.2.0",
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
diff --git a/package.json b/package.json
|
||||
index 42c10484d14e2b029157acf9a08087e8133b20d2..c5a6acce9dd9c8f24271be0b8ae19df680ea0f7b 100644
|
||||
--- a/package.json
|
||||
+++ b/package.json
|
||||
@@ -34,7 +34,10 @@
|
||||
"./next": "./next/index.js",
|
||||
"./middleware": "./middleware.js",
|
||||
"./client/_utils": "./client/_utils.js",
|
||||
- "./providers/*": "./providers/*.js"
|
||||
+ "./providers/*": "./providers/*.js",
|
||||
+ "./core/init": "./core/init.js",
|
||||
+ "./core/lib/oauth/authorization-url": "./core/lib/oauth/authorization-url.js",
|
||||
+ "./core/lib/oauth/callback": "./core/lib/oauth/callback.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "pnpm clean && pnpm build:js && pnpm build:css",
|
||||
23
patches/next-auth@4.24.7.patch
Normal file
23
patches/next-auth@4.24.7.patch
Normal file
@@ -0,0 +1,23 @@
|
||||
diff --git a/package.json b/package.json
|
||||
index c89e03c41a03de738cfb0ad090a63c2e99dadc7b..a5f38083c24732651c427c2b2d17cbcb23495473 100644
|
||||
--- a/package.json
|
||||
+++ b/package.json
|
||||
@@ -57,6 +57,18 @@
|
||||
"./providers/*": {
|
||||
"types": "./providers/*.d.ts",
|
||||
"default": "./providers/*.js"
|
||||
+ },
|
||||
+ "./core/init": {
|
||||
+ "types": "./core/init.d.ts",
|
||||
+ "default": "./core/init.js"
|
||||
+ },
|
||||
+ "./core/lib/oauth/authorization-url": {
|
||||
+ "types": "./core/lib/oauth/authorization-url.d.ts",
|
||||
+ "default": "./core/lib/oauth/authorization-url.js"
|
||||
+ },
|
||||
+ "./core/lib/oauth/callback": {
|
||||
+ "types": "./core/lib/oauth/callback.d.ts",
|
||||
+ "default": "./core/lib/oauth/callback.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
2412
pnpm-lock.yaml
generated
2412
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"jscodeshift": "0.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"jscodeshift": "0.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"jscodeshift": "0.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"jscodeshift": "0.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"jscodeshift": "0.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"blitz": "2.0.9"
|
||||
"blitz": "2.1.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"blitz": "2.0.9"
|
||||
"blitz": "2.1.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"jscodeshift": "0.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"jscodeshift": "0.13.0",
|
||||
"uuid": "^8.3.1"
|
||||
},
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"jscodeshift": "0.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"jscodeshift": "0.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"blitz": "2.0.9",
|
||||
"blitz": "2.1.1",
|
||||
"jscodeshift": "0.13.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -23,6 +23,6 @@
|
||||
},
|
||||
"homepage": "https://github.com/blitz-js/blitz#readme",
|
||||
"dependencies": {
|
||||
"blitz": "2.0.9"
|
||||
"blitz": "2.1.1"
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user