Skip to content

Commit

Permalink
fix broken vercel deployments (patch) (#2479)
Browse files Browse the repository at this point in the history
  • Loading branch information
flybayer committed Jun 11, 2021
1 parent f20d7cf commit 503ec19
Show file tree
Hide file tree
Showing 17 changed files with 352 additions and 1 deletion.
6 changes: 5 additions & 1 deletion packages/core/src/server/auth/sessions.ts
Expand Up @@ -5,6 +5,7 @@ import {getProjectRoot} from "@blitzjs/config"
import {log} from "@blitzjs/display"
import {fromBase64, toBase64} from "b64-lite"
import cookie from "cookie"
import fs from "fs"
import {IncomingMessage, ServerResponse} from "http"
import {sign as jwtSign, verify as jwtVerify} from "jsonwebtoken"
import {getCookieParser} from "next/dist/next-server/server/api-utils"
Expand Down Expand Up @@ -52,7 +53,10 @@ process.nextTick(getConfig)

const getDb = () => {
const projectRoot = getProjectRoot()
const path = join(projectRoot, ".next/server/blitz-db.js")
let path = join(projectRoot, ".next/server/blitz-db.js")
if (!fs.existsSync(path)) {
path = join(projectRoot, ".next/serverless/blitz-db.js")
}
// eslint-disable-next-line no-eval -- block webpack from following this module path
return eval("require")(path).default
}
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/server/index.ts
Expand Up @@ -29,6 +29,7 @@ export const fixNodeFileTrace = () => {
path.resolve("next.config.js")
path.resolve(".blitz/blitz.config.js")
path.resolve(".next/server/blitz-db.js")
path.resolve(".next/serverless/blitz-db.js")
}
export const withFixNodeFileTrace = (fn: Function) => {
fixNodeFileTrace()
Expand Down
6 changes: 6 additions & 0 deletions test/integration/auth-serverless/app/mutations/login.ts
@@ -0,0 +1,6 @@
import {Ctx} from "blitz"

export default async function login(_: any, ctx: Ctx) {
await ctx.session.$create({userId: 1, role: "user"})
return true
}
6 changes: 6 additions & 0 deletions test/integration/auth-serverless/app/mutations/logout.ts
@@ -0,0 +1,6 @@
import {Ctx} from "blitz"

export default async function logout(_: any, ctx: Ctx) {
await ctx.session.$revoke()
return true
}
@@ -0,0 +1,8 @@
import {Ctx} from "blitz"
import delay from "delay"

export default async function getAuthenticatedBasic(_: any, ctx: Ctx) {
await delay(10)
ctx.session.$authorize()
return "authenticated-basic-result"
}
@@ -0,0 +1,7 @@
import {Ctx} from "blitz"
import delay from "delay"

export default async function getNoauthBasic(_: any, ctx: Ctx) {
await delay(10)
return "noauth-basic-result"
}
4 changes: 4 additions & 0 deletions test/integration/auth-serverless/babel.config.js
@@ -0,0 +1,4 @@
module.exports = {
presets: ["blitz/babel"],
plugins: [],
}
21 changes: 21 additions & 0 deletions test/integration/auth-serverless/blitz.config.ts
@@ -0,0 +1,21 @@
import {BlitzConfig, sessionMiddleware, simpleRolesIsAuthorized} from "blitz"
import db from "./db"

const config: BlitzConfig = {
target: "experimental-serverless-trace",
middleware: [
sessionMiddleware({
isAuthorized: simpleRolesIsAuthorized,
getSession: (handle) => db.get("sessions").find({handle}).value(),
getSessions: (userId) => db.get("sessions").filter({userId}).value(),
createSession: (session) => {
return db.get("sessions").push(session).write()
},
updateSession: async (handle, session) => {
return db.get("sessions").find({handle}).assign(session).write()
},
deleteSession: (handle) => db.get("sessions").remove({handle}).write(),
}),
],
}
module.exports = config
21 changes: 21 additions & 0 deletions test/integration/auth-serverless/db.ts
@@ -0,0 +1,21 @@
const low = require("lowdb")
const FileSync = require("lowdb/adapters/FileSync")
// const Memory = require("lowdb/adapters/Memory")

declare global {
namespace NodeJS {
interface Global {
db: any
}
}
}

let db = global.db || low(new FileSync("db.json"))
global.db = db

db.defaults({
users: [{id: 1}],
sessions: [],
}).write()

export default db
27 changes: 27 additions & 0 deletions test/integration/auth-serverless/pages/_app.tsx
@@ -0,0 +1,27 @@
import {AppProps, ErrorFallbackProps, useQueryErrorResetBoundary} from "blitz"
import {useRouter} from "next/router"
import {ErrorBoundary} from "react-error-boundary"
import {ReactQueryDevtools} from "react-query/devtools"

if (typeof window !== "undefined") {
;(window as any).DEBUG_BLITZ = 1
}

export default function App({Component, pageProps}: AppProps) {
const router = useRouter()

return (
<ErrorBoundary
FallbackComponent={RootErrorFallback}
resetKeys={[router.asPath]}
onReset={useQueryErrorResetBoundary().reset}
>
<Component {...pageProps} />
<ReactQueryDevtools />
</ErrorBoundary>
)
}

function RootErrorFallback({error}: ErrorFallbackProps) {
return <div id="error">{error.name}</div>
}
23 changes: 23 additions & 0 deletions test/integration/auth-serverless/pages/_document.tsx
@@ -0,0 +1,23 @@
import {BlitzScript, Document, DocumentHead, Html, Main} from "blitz"

class MyDocument extends Document {
// Only uncomment if you need to customize this behaviour
// static async getInitialProps(ctx: DocumentContext) {
// const initialProps = await Document.getInitialProps(ctx)
// return {...initialProps}
// }

render() {
return (
<Html lang="en">
<DocumentHead />
<body>
<Main />
<BlitzScript />
</body>
</Html>
)
}
}

export default MyDocument
34 changes: 34 additions & 0 deletions test/integration/auth-serverless/pages/authenticated-query.tsx
@@ -0,0 +1,34 @@
import logout from "app/mutations/logout"
import getAuthenticatedBasic from "app/queries/getAuthenticatedBasic"
import {useMutation, useQuery} from "blitz"
import {Suspense} from "react"

function Content() {
const [result] = useQuery(getAuthenticatedBasic, undefined)
const [logoutMutation] = useMutation(logout)
return (
<div>
<div id="content">{result}</div>
<button
id="logout"
onClick={async () => {
await logoutMutation()
}}
>
logout
</button>
</div>
)
}

function Page() {
return (
<div id="page">
<Suspense fallback={"Loading..."}>
<Content />
</Suspense>
</div>
)
}

export default Page
52 changes: 52 additions & 0 deletions test/integration/auth-serverless/pages/login.tsx
@@ -0,0 +1,52 @@
import login from "app/mutations/login"
import logout from "app/mutations/logout"
import {useMutation, useSession} from "blitz"
import {useState} from "react"

function Content() {
const [error, setError] = useState(null)
const session = useSession({suspense: false})
const [loginMutation] = useMutation(login)
const [logoutMutation] = useMutation(logout)

if (error) return <div id="error">{error}</div>

return (
<div>
<div id="content">{session.userId ? "logged-in" : "logged-out"}</div>
{session.userId ? (
<button
id="logout"
onClick={async () => {
try {
await logoutMutation()
} catch (error) {
setError(error)
}
}}
>
logout
</button>
) : (
<button
id="login"
onClick={async () => {
await loginMutation()
}}
>
login
</button>
)}
</div>
)
}

function Page() {
return (
<div id="page">
<Content />
</div>
)
}

export default Page
20 changes: 20 additions & 0 deletions test/integration/auth-serverless/pages/noauth-query.tsx
@@ -0,0 +1,20 @@
import getNoauthBasic from "app/queries/getNoauthBasic"
import {useQuery} from "blitz"
import {Suspense} from "react"

function Content() {
const [result] = useQuery(getNoauthBasic, undefined)
return <div id="content">{result}</div>
}

function Page() {
return (
<div id="page">
<Suspense fallback={"Loading..."}>
<Content />
</Suspense>
</div>
)
}

export default Page
78 changes: 78 additions & 0 deletions test/integration/auth-serverless/test/index.test.ts
@@ -0,0 +1,78 @@
/* eslint-env jest */
import fs from "fs-extra"
import {
blitzBuild,
blitzExport,
findPort,
killApp,
launchApp,
renderViaHTTP,
waitFor,
} from "lib/blitz-test-utils"
import webdriver from "lib/next-webdriver"
import {join} from "path"
import rimraf from "rimraf"

const context: any = {}
jest.setTimeout(1000 * 60 * 5)

describe("Auth", () => {
beforeAll(async () => {
rimraf.sync(join(__dirname, "../db.json"))

context.appPort = await findPort()
context.server = await launchApp(join(__dirname, "../"), context.appPort, {
env: {__NEXT_TEST_WITH_DEVTOOL: 1},
})

const prerender = [
"/login",
"/noauth-query",
"/authenticated-query",
"/api/queries/getNoauthBasic",
"/api/queries/getAuthenticatedBasic",
"/api/mutations/login",
"/api/mutations/logout",
]
await Promise.all(prerender.map((route) => renderViaHTTP(context.appPort, route)))
})
afterAll(() => killApp(context.server))

describe("unauthenticated", () => {
it("should render result for open query", async () => {
const browser = await webdriver(context.appPort, "/noauth-query")
let text = await browser.elementByCss("#page").text()
await browser.waitForElementByCss("#content")
text = await browser.elementByCss("#content").text()
expect(text).toMatch(/noauth-basic-result/)
if (browser) await browser.close()
})

it("should render error for protected query", async () => {
const browser = await webdriver(context.appPort, "/authenticated-query")
await browser.waitForElementByCss("#error")
let text = await browser.elementByCss("#error").text()
expect(text).toMatch(/AuthenticationError/)
if (browser) await browser.close()
})
})

describe("authenticated", () => {
it("should login and out successfully", async () => {
const browser = await webdriver(context.appPort, "/login")
await browser.waitForElementByCss("#content")
let text = await browser.elementByCss("#content").text()
expect(text).toMatch(/logged-out/)
await browser.elementByCss("#login").click()
await waitFor(100)
text = await browser.elementByCss("#content").text()
expect(text).toMatch(/logged-in/)
await browser.elementByCss("#logout").click()
await waitFor(100)
text = await browser.elementByCss("#content").text()
expect(text).toMatch(/logged-out/)

if (browser) await browser.close()
})
})
})
25 changes: 25 additions & 0 deletions test/integration/auth-serverless/tsconfig.json
@@ -0,0 +1,25 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"baseUrl": "./",
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"tsBuildInfoFile": ".tsbuildinfo",
"paths": {
"lib/*": ["../../lib/*"]
}
},
"exclude": ["node_modules"],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
}
14 changes: 14 additions & 0 deletions test/integration/auth-serverless/types.ts
@@ -0,0 +1,14 @@
import {DefaultCtx, SessionContext, SimpleRolesIsAuthorized} from "blitz"

declare module "blitz" {
export interface Ctx extends DefaultCtx {
session: SessionContext
}
export interface Session {
isAuthorized: SimpleRolesIsAuthorized<"user">
PublicData: {
userId: number
role: "user"
}
}
}

0 comments on commit 503ec19

Please sign in to comment.