diff --git a/examples/auth/blitz.config.js b/examples/auth/blitz.config.ts similarity index 85% rename from examples/auth/blitz.config.js rename to examples/auth/blitz.config.ts index c6443b63e4..158cc2e766 100644 --- a/examples/auth/blitz.config.js +++ b/examples/auth/blitz.config.ts @@ -1,4 +1,5 @@ -const {sessionMiddleware, simpleRolesIsAuthorized} = require("blitz") +import {sessionMiddleware, simpleRolesIsAuthorized} from "blitz" +import db from "db" const withBundleAnalyzer = require("@next/bundle-analyzer")({ enabled: process.env.ANALYZE === "true", }) @@ -8,6 +9,7 @@ module.exports = withBundleAnalyzer({ sessionMiddleware({ isAuthorized: simpleRolesIsAuthorized, // sessionExpiryMinutes: 4, + getSession: (handle) => db.session.findFirst({where: {handle}}), }), ], cli: { diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 1a8b25b52c..faed6489dc 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -2,14 +2,17 @@ require("v8-compile-cache") const cacheFile = require("path").join(__dirname, ".blitzjs-cli-cache") const lazyLoad = require("@salesforce/lazy-require").default.create(cacheFile) lazyLoad.start() +import {buildConfig} from "@blitzjs/config" import {run as oclifRun} from "@oclif/command" // Load the .env environment variable so it's available for all commands require("dotenv-expand")(require("dotenv-flow").config({silent: true})) export function run() { - oclifRun() - .then(require("@oclif/command/flush")) - // @ts-ignore (TS complains about using `catch`) - .catch(require("@oclif/errors/handle")) + buildConfig().then(() => { + oclifRun() + .then(require("@oclif/command/flush")) + // @ts-ignore (TS complains about using `catch`) + .catch(require("@oclif/errors/handle")) + }) } diff --git a/packages/config/package.json b/packages/config/package.json index 4f8c174419..9cc8aa9d5e 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -25,6 +25,7 @@ }, "gitHead": "d3b9fce0bdd251c2b1890793b0aa1cd77c1c0922", "dependencies": { + "esbuild": "^0.11.12", "fs-extra": "^9.1.0", "pkg-dir": "^5.0.0" } diff --git a/packages/config/src/index.ts b/packages/config/src/index.ts index 3ace2cc80d..447bf2317b 100644 --- a/packages/config/src/index.ts +++ b/packages/config/src/index.ts @@ -1,12 +1,67 @@ +import * as esbuild from "esbuild" import {existsSync, readJSONSync} from "fs-extra" import path, {join} from "path" import pkgDir from "pkg-dir" const debug = require("debug")("blitz:config") export function getProjectRoot() { - return ( - path.dirname(path.resolve(process.cwd(), "blitz.config.js")) || pkgDir.sync() || process.cwd() - ) + return path.dirname(getConfigSrcPath()) +} + +export function getConfigSrcPath() { + const tsPath = path.resolve(path.join(process.cwd(), "blitz.config.ts")) + if (existsSync(tsPath)) { + return tsPath + } else { + const jsPath = path.resolve(path.join(process.cwd(), "blitz.config.js")) + return jsPath + } +} +export function getConfigBuildPath() { + return path.join(getProjectRoot(), ".blitz", "blitz.config.js") +} + +interface BuildConfigOptions { + watch?: boolean +} + +export async function buildConfig({watch}: BuildConfigOptions = {}) { + debug("Starting buildConfig...") + const pkg = readJSONSync(path.join(pkgDir.sync()!, "package.json")) + debug("src", getConfigSrcPath()) + debug("build", getConfigBuildPath()) + + const esbuildOptions: esbuild.BuildOptions = { + entryPoints: [getConfigSrcPath()], + outfile: getConfigBuildPath(), + format: "cjs", + bundle: true, + platform: "node", + external: [ + "blitz", + "next", + ...Object.keys(require("blitz/package").dependencies), + ...Object.keys(pkg?.dependencies ?? {}), + ...Object.keys(pkg?.devDependencies ?? {}), + ], + } + + if (watch) { + esbuildOptions.watch = { + onRebuild(error) { + if (error) { + console.error("Failed to re-build blitz config") + } else { + console.log("\n> Blitz config changed - restart for changes to take effect\n") + } + }, + } + } + + debug("Building config...") + debug("Src: ", getConfigSrcPath()) + debug("Build: ", getConfigBuildPath()) + await esbuild.build(esbuildOptions) } export interface BlitzConfig extends Record { @@ -59,13 +114,19 @@ export const getConfig = (reload?: boolean): BlitzConfig => { const projectRoot = getProjectRoot() const nextConfigPath = path.join(projectRoot, "next.config.js") - const blitzConfigPath = path.join(projectRoot, "blitz.config.js") + let blitzConfigPath + if (existsSync(path.join(projectRoot, ".blitz"))) { + blitzConfigPath = path.join(projectRoot, ".blitz", "blitz.config.js") + } else { + // projectRoot is inside .blitz/build/ + blitzConfigPath = path.join(projectRoot, "..", "blitz.config.js") + } debug("nextConfigPath: " + nextConfigPath) debug("blitzConfigPath: " + blitzConfigPath) let loadedNextConfig = {} - let loadedBlitzConfig = {} + let loadedBlitzConfig: any = {} try { // -------------------------------- // Load next.config.js if it exists diff --git a/packages/core/src/auth/auth-types.ts b/packages/core/src/auth/auth-types.ts index d3bfca3e7f..c0d5dba19a 100644 --- a/packages/core/src/auth/auth-types.ts +++ b/packages/core/src/auth/auth-types.ts @@ -22,12 +22,12 @@ export type IsAuthorizedArgs = "isAuthorized" extends keyof Session export interface SessionModel extends Record { handle: string - userId?: PublicData["userId"] - expiresAt?: Date - hashedSessionToken?: string - antiCSRFToken?: string - publicData?: string - privateData?: string + userId?: PublicData["userId"] | null + expiresAt?: Date | null + hashedSessionToken?: string | null + antiCSRFToken?: string | null + publicData?: string | null + privateData?: string | null } export type SessionConfig = { @@ -41,7 +41,7 @@ export type SessionConfig = { createSession: (session: SessionModel) => Promise updateSession: (handle: string, session: Partial) => Promise deleteSession: (handle: string) => Promise - isAuthorized: (data: {ctx: Ctx; args: any[]}) => boolean + isAuthorized: (data: {ctx: Ctx; args: any}) => boolean } export interface SessionContextBase { diff --git a/packages/core/src/server/auth/sessions.ts b/packages/core/src/server/auth/sessions.ts index 6eeaa6ea9c..919ed812b8 100644 --- a/packages/core/src/server/auth/sessions.ts +++ b/packages/core/src/server/auth/sessions.ts @@ -626,7 +626,8 @@ export async function getSessionKernel( if (req.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 = hash256(persistedSession.publicData) !== hashedPublicData + const hasPublicDataChanged = + hash256(persistedSession.publicData ?? undefined) !== hashedPublicData if (hasPublicDataChanged) { debug("PublicData has changed since the last request") } diff --git a/packages/generator/templates/app/blitz.config.js b/packages/generator/templates/app/blitz.config.ts similarity index 85% rename from packages/generator/templates/app/blitz.config.js rename to packages/generator/templates/app/blitz.config.ts index ce6217701c..646c005557 100644 --- a/packages/generator/templates/app/blitz.config.js +++ b/packages/generator/templates/app/blitz.config.ts @@ -1,4 +1,4 @@ -const { sessionMiddleware, simpleRolesIsAuthorized } = require("blitz") +import { sessionMiddleware, simpleRolesIsAuthorized } from "blitz" module.exports = { middleware: [ diff --git a/packages/installer/src/utils/paths.ts b/packages/installer/src/utils/paths.ts index a59ea4c43e..91f43ee2b8 100644 --- a/packages/installer/src/utils/paths.ts +++ b/packages/installer/src/utils/paths.ts @@ -19,7 +19,7 @@ export const paths = { return "babel.config.js" }, blitzConfig() { - return "blitz.config.js" + return `blitz.config${ext()}` }, packageJson() { return "package.json" diff --git a/packages/installer/test/utils/paths.test.ts b/packages/installer/test/utils/paths.test.ts index 76c831c518..b503351d55 100644 --- a/packages/installer/test/utils/paths.test.ts +++ b/packages/installer/test/utils/paths.test.ts @@ -12,7 +12,7 @@ describe("path utils", () => { expect(paths.app()).toBe("app/pages/_app.tsx") expect(paths.entry()).toBe("app/pages/index.tsx") // Blitz and Babel configs are always JS, we shouldn't transform this extension - expect(paths.blitzConfig()).toBe("blitz.config.js") + expect(paths.blitzConfig()).toBe("blitz.config.ts") expect(paths.babelConfig()).toBe("babel.config.js") }) diff --git a/packages/server/package.json b/packages/server/package.json index 593b828b3d..976e202c36 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -29,7 +29,7 @@ "@blitzjs/file-pipeline": "0.35.0-canary.2", "cross-spawn": "7.0.3", "detect-port": "1.3.0", - "esbuild": "0.11.12", + "esbuild": "^0.11.12", "expand-tilde": "2.0.2", "fast-glob": "3.2.5", "flush-write-stream": "2.0.0", diff --git a/packages/server/src/next-utils.ts b/packages/server/src/next-utils.ts index 906fbecc76..74a4344eb3 100644 --- a/packages/server/src/next-utils.ts +++ b/packages/server/src/next-utils.ts @@ -4,7 +4,9 @@ import {ChildProcess} from "child_process" import {spawn} from "cross-spawn" import detect from "detect-port" import * as esbuild from "esbuild" +import {readJSONSync} from "fs-extra" import path from "path" +import pkgDir from "pkg-dir" import {ServerConfig, standardBuildFolderPathRegex} from "./config" import {Manifest} from "./stages/manifest" import {resolverBuildFolderReplaceRegex, resolverFullBuildPathRegex} from "./stages/rpc" @@ -268,13 +270,21 @@ export function startCustomServer( }) } + const pkg = readJSONSync(path.join(pkgDir.sync()!, "package.json")) + const esbuildOptions: esbuild.BuildOptions = { entryPoints: [serverSrcPath], outfile: getCustomServerBuildPath(), format: "cjs", bundle: true, platform: "node", - external: ["blitz", "next", ...Object.keys(require("blitz/package").dependencies)], + external: [ + "blitz", + "next", + ...Object.keys(require("blitz/package").dependencies), + ...Object.keys(pkg.dependencies), + ...Object.keys(pkg.devDependencies), + ], } if (watch) { diff --git a/packages/server/src/stages/config/index.ts b/packages/server/src/stages/config/index.ts index 85381b76da..367a721b67 100644 --- a/packages/server/src/stages/config/index.ts +++ b/packages/server/src/stages/config/index.ts @@ -12,7 +12,9 @@ const isNowBuild = () => process.env.NOW_BUILDER || process.env.VERCEL_BUILDER export const createStageConfig: Stage = ({config, processNewFile, processNewChildFile}) => { // Preconditions const hasNextConfig = pathExistsSync(resolve(config.src, "next.config.js")) - const hasBlitzConfig = pathExistsSync(resolve(config.src, "blitz.config.js")) + const hasBlitzConfig = + pathExistsSync(resolve(config.src, "blitz.config.js")) || + pathExistsSync(resolve(config.src, "blitz.config.ts")) if (hasNextConfig && !isNowBuild()) { // TODO: Pause the stream and ask the user if they wish to have their configuration file renamed @@ -41,7 +43,7 @@ export const createStageConfig: Stage = ({config, processNewFile, processNewChil path: resolve(config.src, "next.config.js"), contents: Buffer.from(` const {withBlitz} = require('@blitzjs/core/with-blitz'); -const config = require('./blitz.config.js'); +const config = require('../blitz.config.js'); module.exports = withBlitz(config); `), }), @@ -74,7 +76,7 @@ module.exports = withBlitz(config); file.contents = Buffer.from(` const {withBlitz} = require('@blitzjs/core/with-blitz'); const vercelConfig = require('./next-vercel.config.js'); -const config = require('./blitz.config.js'); +const config = require('../blitz.config.js'); module.exports = withBlitz({...config, ...vercelConfig}); `) } diff --git a/test/integration/auth/blitz.config.js b/test/integration/auth/blitz.config.ts similarity index 85% rename from test/integration/auth/blitz.config.js rename to test/integration/auth/blitz.config.ts index d552f323f0..6bc476154e 100644 --- a/test/integration/auth/blitz.config.js +++ b/test/integration/auth/blitz.config.ts @@ -1,5 +1,5 @@ -const {sessionMiddleware, simpleRolesIsAuthorized} = require("blitz") -const db = require("./db") +import {sessionMiddleware, simpleRolesIsAuthorized} from "blitz" +import db from "./db" module.exports = { middleware: [ diff --git a/test/integration/auth/db.js b/test/integration/auth/db.ts similarity index 71% rename from test/integration/auth/db.js rename to test/integration/auth/db.ts index b197e52c59..1f79528f8c 100644 --- a/test/integration/auth/db.js +++ b/test/integration/auth/db.ts @@ -2,6 +2,14 @@ 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 @@ -10,4 +18,4 @@ db.defaults({ sessions: [], }).write() -module.exports = db +export default db diff --git a/yarn.lock b/yarn.lock index c4f7aae85d..0a3477b042 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9141,10 +9141,10 @@ es6-symbol@^3.1.1, es6-symbol@~3.1.3: d "^1.0.1" ext "^1.1.2" -esbuild@0.11.12: - version "0.11.12" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.11.12.tgz#8cbe15bcb44212624c3e77c896a835f74dc71c3c" - integrity sha512-c8cso/1RwVj+fbDvLtUgSG4ZJQ0y9Zdrl6Ot/GAjyy4pdMCHaFnDMts5gqFnWRPLajWtEnI+3hlET4R9fVoZng== +esbuild@^0.11.12: + version "0.11.16" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.11.16.tgz#435f00474fb21e70f59a545b85e4cfc7ba106485" + integrity sha512-34ZWjo4ouvM5cDe7uRoM9GFuMyEmpH9fnVYmomvS1cq9ED9d/0ZG1r+p4P2VbX7ihjv36zA2SWTmP8Zmt/EANA== escalade@^3.1.1: version "3.1.1"