1
0
mirror of https://github.com/microsoft/TypeScript-Node-Starter.git synced 2025-11-08 12:07:34 +00:00

Fix #305 Update packages to latest (#317)

thx to @samal-rasmussen!
This commit is contained in:
Sámal Rasmussen
2021-02-08 18:37:56 +00:00
committed by GitHub
parent db005fa89b
commit 5381d62a10
8 changed files with 5196 additions and 4356 deletions

View File

@@ -287,24 +287,24 @@ You'll notice that npm scripts can call each other which makes it easy to compos
Below is a list of all the scripts this template has available:
| Npm Script | Description |
| Npm Script | Description |
| ------------------------- | ------------------------------------------------------------------------------------------------- |
| `start` | Does the same as 'npm run serve'. Can be invoked with `npm start` |
| `build` | Full build. Runs ALL build tasks (`build-sass`, `build-ts`, `lint`, `copy-static-assets`) |
| `serve` | Runs node on `dist/server.js` which is the apps entry point |
| `watch-node` | Runs node with nodemon so the process restarts if it crashes. Used in the main watch task |
| `watch` | Runs all watch tasks (TypeScript, Sass, Node). Use this if you're not touching static assets. |
| `test` | Runs tests using Jest test runner |
| `watch-test` | Runs tests in watch mode |
| `build-ts` | Compiles all source `.ts` files to `.js` files in the `dist` folder |
| `watch-ts` | Same as `build-ts` but continuously watches `.ts` files and re-compiles when needed |
| `build-sass` | Compiles all `.scss` files to `.css` files |
| `watch-sass` | Same as `build-sass` but continuously watches `.scss` files and re-compiles when needed |
| `lint` | Runs ESLint on project files |
| `build-sass` | Compiles all `.scss` files to `.css` files |
| `build-ts` | Compiles all source `.ts` files to `.js` files in the `dist` folder |
| `build` | Full build. Runs ALL build tasks (`build-sass`, `build-ts`, `lint`, `copy-static-assets`) |
| `copy-static-assets` | Calls script that copies JS libs, fonts, and images to dist directory |
| `debug` | Performs a full build and then serves the app in watch mode |
| `serve-debug` | Runs the app with the --inspect flag |
| `watch-debug` | The same as `watch` but includes the --inspect flag so you can attach a debugger |
| `lint` | Runs ESLint on project files |
| `serve-debug` | Runs the app with the --inspect flag |
| `serve` | Runs node on `dist/server.js` which is the apps entry point |
| `start` | Does the same as 'npm run serve'. Can be invoked with `npm start` |
| `test` | Runs tests using Jest test runner |
| `watch-debug` | The same as `watch` but includes the --inspect flag so you can attach a debugger |
| `watch-node` | Runs node with nodemon so the process restarts if it crashes. Used in the main watch task |
| `watch-sass` | Same as `build-sass` but continuously watches `.scss` files and re-compiles when needed |
| `watch-test` | Runs tests in watch mode |
| `watch-ts` | Same as `build-ts` but continuously watches `.ts` files and re-compiles when needed |
| `watch` | Runs all watch tasks (TypeScript, Sass, Node). Use this if you're not touching static assets. |
## Type Definition (`.d.ts`) Files
TypeScript uses `.d.ts` files to provide types for JavaScript libraries that were not written in TypeScript.
@@ -596,7 +596,7 @@ In that file you'll find two sections:
| chai | Testing utility library that makes it easier to write tests |
| concurrently | Utility that manages multiple concurrent tasks. Used with npm scripts |
| jest | Testing library for JavaScript. |
| node-sass | Allows to compile .scss files to .css |
| sass | Allows to compile .scss files to .css |
| nodemon | Utility that automatically restarts node process when it crashes |
| supertest | HTTP assertion library. |
| ts-jest | A preprocessor with sourcemap support to help use TypeScript with Jest.|

9246
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,90 +9,88 @@
"author": "Bowden Kelly",
"license": "MIT",
"scripts": {
"build": "npm run build-sass && npm run build-ts && npm run lint && npm run copy-static-assets",
"build-sass": "node-sass src/public/css/main.scss dist/public/css/main.css",
"build-sass": "sass src/public/css/main.scss dist/public/css/main.css",
"build-ts": "tsc",
"build": "npm run build-sass && npm run build-ts && npm run lint && npm run copy-static-assets",
"copy-static-assets": "ts-node copyStaticAssets.ts",
"debug": "npm run build && npm run watch-debug",
"lint": "tsc --noEmit && eslint \"**/*.{js,ts}\" --quiet --fix",
"serve": "node dist/server.js",
"serve-debug": "nodemon --inspect dist/server.js",
"serve": "node dist/server.js",
"start": "npm run serve",
"test": "jest --forceExit --coverage --verbose",
"watch": "concurrently -k -p \"[{name}]\" -n \"Sass,TypeScript,Node\" -c \"yellow.bold,cyan.bold,green.bold\" \"npm run watch-sass\" \"npm run watch-ts\" \"npm run watch-node\"",
"watch-debug": "concurrently -k -p \"[{name}]\" -n \"Sass,TypeScript,Node\" -c \"yellow.bold,cyan.bold,green.bold\" \"npm run watch-sass\" \"npm run watch-ts\" \"npm run serve-debug\"",
"watch-node": "nodemon dist/server.js",
"watch-sass": "node-sass -w src/public/css/main.scss dist/public/css/main.css",
"watch-sass": "sass --watch src/public/css/main.scss dist/public/css/main.css",
"watch-test": "npm run test -- --watchAll",
"watch-ts": "tsc -w"
"watch-ts": "tsc -w",
"watch": "concurrently -k -p \"[{name}]\" -n \"Sass,TypeScript,Node\" -c \"yellow.bold,cyan.bold,green.bold\" \"npm run watch-sass\" \"npm run watch-ts\" \"npm run watch-node\""
},
"dependencies": {
"async": "^3.1.0",
"bcrypt-nodejs": "^0.0.3",
"bluebird": "^3.5.5",
"body-parser": "^1.19.0",
"compression": "^1.7.4",
"connect-mongo": "^3.0.0",
"dotenv": "^8.2.0",
"errorhandler": "^1.5.1",
"express": "^4.17.1",
"@types/mongodb": "3.6.5",
"async": "3.2.0",
"bcrypt-nodejs": "0.0.3",
"bluebird": "3.7.2",
"body-parser": "1.19.0",
"compression": "1.7.4",
"connect-mongo": "jdesboeufs/connect-mongo#527f9b6cd3d95d9bcd765c9ef9f2b5705611f9f5",
"dotenv": "8.2.0",
"errorhandler": "1.5.1",
"express": "4.17.1",
"express-flash": "0.0.2",
"express-session": "^1.16.2",
"express-validator": "^6.2.0",
"fbgraph": "^1.4.4",
"lodash": "^4.17.19",
"lusca": "^1.6.1",
"mongoose": "^5.7.5",
"nodemailer": "^6.3.0",
"passport": "^0.4.0",
"passport-facebook": "^3.0.0",
"passport-local": "^1.0.0",
"pug": "^2.0.4",
"winston": "^3.2.1"
"express-session": "1.17.1",
"express-validator": "6.9.2",
"fbgraph": "1.4.4",
"lodash": "4.17.20",
"lusca": "1.6.1",
"mongoose": "5.11.15",
"nodemailer": "6.4.17",
"passport": "0.4.1",
"passport-facebook": "3.0.0",
"passport-local": "1.0.0",
"pug": "3.0.0",
"winston": "3.3.3"
},
"devDependencies": {
"@types/async": "^3.0.2",
"@types/bcrypt-nodejs": "^0.0.30",
"@types/bluebird": "^3.5.27",
"@types/body-parser": "^1.17.1",
"@types/chai": "^4.2.3",
"@types/compression": "^1.0.1",
"@types/concurrently": "^4.1.0",
"@types/connect-mongo": "^3.0.0",
"@types/errorhandler": "^0.0.32",
"@types/eslint": "^6.1.1",
"@types/express": "^4.17.1",
"@types/express-flash": "0.0.1",
"@types/express-session": "^1.15.14",
"@types/jest": "^24.0.23",
"@types/jquery": "^3.3.31",
"@types/lodash": "^4.14.141",
"@types/lusca": "^1.6.1",
"@types/mongoose": "^5.5.18",
"@types/node": "^12.7.8",
"@types/node-sass": "^4.11.0",
"@types/nodemailer": "^6.2.1",
"@types/passport": "^1.0.1",
"@types/passport-facebook": "^2.1.9",
"@types/passport-local": "^1.0.33",
"@types/pug": "^2.0.4",
"@types/request": "^2.48.3",
"@types/request-promise": "^4.1.44",
"@types/shelljs": "^0.8.5",
"@types/supertest": "^2.0.8",
"@types/winston": "^2.4.4",
"@typescript-eslint/eslint-plugin": "^2.3.1",
"@typescript-eslint/parser": "^2.3.1",
"chai": "^4.2.0",
"concurrently": "^5.3.0",
"eslint": "^6.4.0",
"jest": "^24.9.0",
"node-sass": "^4.14.1",
"nodemon": "^1.19.2",
"shelljs": "^0.8.3",
"supertest": "^4.0.2",
"ts-jest": "^24.1.0",
"ts-node": "^8.4.1",
"typescript": "^3.6.3"
"@types/async": "3.2.5",
"@types/bcrypt-nodejs": "0.0.31",
"@types/bluebird": "3.5.33",
"@types/body-parser": "1.19.0",
"@types/chai": "4.2.14",
"@types/compression": "1.7.0",
"@types/concurrently": "5.2.1",
"@types/errorhandler": "1.5.0",
"@types/eslint": "7.2.6",
"@types/express": "4.17.11",
"@types/express-flash": "0.0.2",
"@types/express-session": "1.17.3",
"@types/jest": "26.0.20",
"@types/jquery": "3.5.5",
"@types/lodash": "4.14.168",
"@types/lusca": "1.6.2",
"@types/node": "14.14.25",
"@types/nodemailer": "6.4.0",
"@types/passport": "1.0.5",
"@types/passport-facebook": "2.1.10",
"@types/passport-local": "1.0.33",
"@types/pug": "2.0.4",
"@types/request": "2.48.5",
"@types/request-promise": "4.1.47",
"@types/shelljs": "0.8.8",
"@types/supertest": "2.0.10",
"@types/winston": "2.4.4",
"@typescript-eslint/eslint-plugin": "4.14.2",
"@typescript-eslint/parser": "4.14.2",
"chai": "4.3.0",
"concurrently": "5.3.0",
"eslint": "7.19.0",
"jest": "26.6.3",
"nodemon": "2.0.7",
"sass": "1.32.6",
"shelljs": "0.8.4",
"supertest": "6.1.3",
"ts-jest": "26.5.0",
"ts-node": "9.1.1",
"typescript": "4.1.3"
}
}
}

View File

@@ -19,7 +19,6 @@ import * as userController from "./controllers/user";
import * as apiController from "./controllers/api";
import * as contactController from "./controllers/contact";
// API keys and Passport configuration
import * as passportConfig from "./config/passport";

View File

@@ -6,17 +6,18 @@ import _ from "lodash";
// import { User, UserType } from '../models/User';
import { User, UserDocument } from "../models/User";
import { Request, Response, NextFunction } from "express";
import { NativeError } from "mongoose";
const LocalStrategy = passportLocal.Strategy;
const FacebookStrategy = passportFacebook.Strategy;
passport.serializeUser<any, any>((user, done) => {
done(undefined, user.id);
passport.serializeUser<any, any>((req, user, done) => {
done(undefined, user);
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
User.findById(id, (err: NativeError, user: UserDocument) => {
done(err, user.id);
});
});
@@ -25,7 +26,7 @@ passport.deserializeUser((id, done) => {
* Sign in using Email and Password.
*/
passport.use(new LocalStrategy({ usernameField: "email" }, (email, password, done) => {
User.findOne({ email: email.toLowerCase() }, (err, user: any) => {
User.findOne({ email: email.toLowerCase() }, (err: NativeError, user: UserDocument) => {
if (err) { return done(err); }
if (!user) {
return done(undefined, false, { message: `Email ${email} not found.` });
@@ -68,13 +69,13 @@ passport.use(new FacebookStrategy({
passReqToCallback: true
}, (req: any, accessToken, refreshToken, profile, done) => {
if (req.user) {
User.findOne({ facebook: profile.id }, (err, existingUser) => {
User.findOne({ facebook: profile.id }, (err: NativeError, existingUser: UserDocument) => {
if (err) { return done(err); }
if (existingUser) {
req.flash("errors", { msg: "There is already a Facebook account that belongs to you. Sign in with that account or delete it, then link it with your current account." });
done(err);
} else {
User.findById(req.user.id, (err, user: any) => {
User.findById(req.user.id, (err: NativeError, user: UserDocument) => {
if (err) { return done(err); }
user.facebook = profile.id;
user.tokens.push({ kind: "facebook", accessToken });
@@ -89,12 +90,12 @@ passport.use(new FacebookStrategy({
}
});
} else {
User.findOne({ facebook: profile.id }, (err, existingUser) => {
User.findOne({ facebook: profile.id }, (err: NativeError, existingUser: UserDocument) => {
if (err) { return done(err); }
if (existingUser) {
return done(undefined, existingUser);
}
User.findOne({ email: profile._json.email }, (err, existingEmailUser) => {
User.findOne({ email: profile._json.email }, (err: NativeError, existingEmailUser: UserDocument) => {
if (err) { return done(err); }
if (existingEmailUser) {
req.flash("errors", { msg: "There is already an account using this email address. Sign in to that account and link it with Facebook manually from Account Settings." });

View File

@@ -8,17 +8,18 @@ import { IVerifyOptions } from "passport-local";
import { WriteError } from "mongodb";
import { check, sanitize, validationResult } from "express-validator";
import "../config/passport";
import { CallbackError, NativeError } from "mongoose";
/**
* Login page.
* @route GET /login
*/
export const getLogin = (req: Request, res: Response) => {
export const getLogin = (req: Request, res: Response): void => {
if (req.user) {
return res.redirect("/");
}
res.render("account/login", {
title: "Login"
title: "Login",
});
};
@@ -26,10 +27,9 @@ export const getLogin = (req: Request, res: Response) => {
* Sign in using email and password.
* @route POST /login
*/
export const postLogin = async (req: Request, res: Response, next: NextFunction) => {
export const postLogin = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
await check("email", "Email is not valid").isEmail().run(req);
await check("password", "Password cannot be blank").isLength({min: 1}).run(req);
// eslint-disable-next-line @typescript-eslint/camelcase
await sanitize("email").normalizeEmail({ gmail_remove_dots: false }).run(req);
const errors = validationResult(req);
@@ -57,7 +57,7 @@ export const postLogin = async (req: Request, res: Response, next: NextFunction)
* Log out.
* @route GET /logout
*/
export const logout = (req: Request, res: Response) => {
export const logout = (req: Request, res: Response): void => {
req.logout();
res.redirect("/");
};
@@ -66,7 +66,7 @@ export const logout = (req: Request, res: Response) => {
* Signup page.
* @route GET /signup
*/
export const getSignup = (req: Request, res: Response) => {
export const getSignup = (req: Request, res: Response): void => {
if (req.user) {
return res.redirect("/");
}
@@ -79,11 +79,10 @@ export const getSignup = (req: Request, res: Response) => {
* Create a new local account.
* @route POST /signup
*/
export const postSignup = async (req: Request, res: Response, next: NextFunction) => {
export const postSignup = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
await check("email", "Email is not valid").isEmail().run(req);
await check("password", "Password must be at least 4 characters long").isLength({ min: 4 }).run(req);
await check("confirmPassword", "Passwords do not match").equals(req.body.password).run(req);
// eslint-disable-next-line @typescript-eslint/camelcase
await sanitize("email").normalizeEmail({ gmail_remove_dots: false }).run(req);
const errors = validationResult(req);
@@ -98,7 +97,7 @@ export const postSignup = async (req: Request, res: Response, next: NextFunction
password: req.body.password
});
User.findOne({ email: req.body.email }, (err, existingUser) => {
User.findOne({ email: req.body.email }, (err: NativeError, existingUser: UserDocument) => {
if (err) { return next(err); }
if (existingUser) {
req.flash("errors", { msg: "Account with that email address already exists." });
@@ -120,7 +119,7 @@ export const postSignup = async (req: Request, res: Response, next: NextFunction
* Profile page.
* @route GET /account
*/
export const getAccount = (req: Request, res: Response) => {
export const getAccount = (req: Request, res: Response): void => {
res.render("account/profile", {
title: "Account Management"
});
@@ -130,9 +129,8 @@ export const getAccount = (req: Request, res: Response) => {
* Update profile information.
* @route POST /account/profile
*/
export const postUpdateProfile = async (req: Request, res: Response, next: NextFunction) => {
export const postUpdateProfile = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
await check("email", "Please enter a valid email address.").isEmail().run(req);
// eslint-disable-next-line @typescript-eslint/camelcase
await sanitize("email").normalizeEmail({ gmail_remove_dots: false }).run(req);
const errors = validationResult(req);
@@ -143,14 +141,14 @@ export const postUpdateProfile = async (req: Request, res: Response, next: NextF
}
const user = req.user as UserDocument;
User.findById(user.id, (err, user: UserDocument) => {
User.findById(user.id, (err: NativeError, user: UserDocument) => {
if (err) { return next(err); }
user.email = req.body.email || "";
user.profile.name = req.body.name || "";
user.profile.gender = req.body.gender || "";
user.profile.location = req.body.location || "";
user.profile.website = req.body.website || "";
user.save((err: WriteError) => {
user.save((err: WriteError & CallbackError) => {
if (err) {
if (err.code === 11000) {
req.flash("errors", { msg: "The email address you have entered is already associated with an account." });
@@ -168,7 +166,7 @@ export const postUpdateProfile = async (req: Request, res: Response, next: NextF
* Update current password.
* @route POST /account/password
*/
export const postUpdatePassword = async (req: Request, res: Response, next: NextFunction) => {
export const postUpdatePassword = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
await check("password", "Password must be at least 4 characters long").isLength({ min: 4 }).run(req);
await check("confirmPassword", "Passwords do not match").equals(req.body.password).run(req);
@@ -180,10 +178,10 @@ export const postUpdatePassword = async (req: Request, res: Response, next: Next
}
const user = req.user as UserDocument;
User.findById(user.id, (err, user: UserDocument) => {
User.findById(user.id, (err: NativeError, user: UserDocument) => {
if (err) { return next(err); }
user.password = req.body.password;
user.save((err: WriteError) => {
user.save((err: WriteError & CallbackError) => {
if (err) { return next(err); }
req.flash("success", { msg: "Password has been changed." });
res.redirect("/account");
@@ -195,7 +193,7 @@ export const postUpdatePassword = async (req: Request, res: Response, next: Next
* Delete user account.
* @route POST /account/delete
*/
export const postDeleteAccount = (req: Request, res: Response, next: NextFunction) => {
export const postDeleteAccount = (req: Request, res: Response, next: NextFunction): void => {
const user = req.user as UserDocument;
User.remove({ _id: user.id }, (err) => {
if (err) { return next(err); }
@@ -209,10 +207,10 @@ export const postDeleteAccount = (req: Request, res: Response, next: NextFunctio
* Unlink OAuth provider.
* @route GET /account/unlink/:provider
*/
export const getOauthUnlink = (req: Request, res: Response, next: NextFunction) => {
export const getOauthUnlink = (req: Request, res: Response, next: NextFunction): void => {
const provider = req.params.provider;
const user = req.user as UserDocument;
User.findById(user.id, (err, user: any) => {
User.findById(user.id, (err: NativeError, user: any) => {
if (err) { return next(err); }
user[provider] = undefined;
user.tokens = user.tokens.filter((token: AuthToken) => token.kind !== provider);
@@ -228,7 +226,7 @@ export const getOauthUnlink = (req: Request, res: Response, next: NextFunction)
* Reset Password page.
* @route GET /reset/:token
*/
export const getReset = (req: Request, res: Response, next: NextFunction) => {
export const getReset = (req: Request, res: Response, next: NextFunction): void => {
if (req.isAuthenticated()) {
return res.redirect("/");
}
@@ -251,7 +249,7 @@ export const getReset = (req: Request, res: Response, next: NextFunction) => {
* Process the reset password request.
* @route POST /reset/:token
*/
export const postReset = async (req: Request, res: Response, next: NextFunction) => {
export const postReset = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
await check("password", "Password must be at least 4 characters long.").isLength({ min: 4 }).run(req);
await check("confirm", "Passwords must match.").equals(req.body.password).run(req);
@@ -263,7 +261,7 @@ export const postReset = async (req: Request, res: Response, next: NextFunction)
}
async.waterfall([
function resetPassword(done: Function) {
function resetPassword(done: (err: any, user: UserDocument) => void) {
User
.findOne({ passwordResetToken: req.params.token })
.where("passwordResetExpires").gt(Date.now())
@@ -284,7 +282,7 @@ export const postReset = async (req: Request, res: Response, next: NextFunction)
});
});
},
function sendResetPasswordEmail(user: UserDocument, done: Function) {
function sendResetPasswordEmail(user: UserDocument, done: (err: Error) => void) {
const transporter = nodemailer.createTransport({
service: "SendGrid",
auth: {
@@ -313,7 +311,7 @@ export const postReset = async (req: Request, res: Response, next: NextFunction)
* Forgot Password page.
* @route GET /forgot
*/
export const getForgot = (req: Request, res: Response) => {
export const getForgot = (req: Request, res: Response): void => {
if (req.isAuthenticated()) {
return res.redirect("/");
}
@@ -326,9 +324,8 @@ export const getForgot = (req: Request, res: Response) => {
* Create a random token, then the send user an email with a reset link.
* @route POST /forgot
*/
export const postForgot = async (req: Request, res: Response, next: NextFunction) => {
export const postForgot = async (req: Request, res: Response, next: NextFunction): Promise<void> => {
await check("email", "Please enter a valid email address.").isEmail().run(req);
// eslint-disable-next-line @typescript-eslint/camelcase
await sanitize("email").normalizeEmail({ gmail_remove_dots: false }).run(req);
const errors = validationResult(req);
@@ -339,14 +336,14 @@ export const postForgot = async (req: Request, res: Response, next: NextFunction
}
async.waterfall([
function createRandomToken(done: Function) {
function createRandomToken(done: (err: Error, token: string) => void) {
crypto.randomBytes(16, (err, buf) => {
const token = buf.toString("hex");
done(err, token);
});
},
function setRandomToken(token: AuthToken, done: Function) {
User.findOne({ email: req.body.email }, (err, user: any) => {
function setRandomToken(token: AuthToken, done: (err: NativeError | WriteError, token?: AuthToken, user?: UserDocument) => void) {
User.findOne({ email: req.body.email }, (err: NativeError, user: any) => {
if (err) { return done(err); }
if (!user) {
req.flash("errors", { msg: "Account with that email address does not exist." });
@@ -359,7 +356,7 @@ export const postForgot = async (req: Request, res: Response, next: NextFunction
});
});
},
function sendForgotPasswordEmail(token: AuthToken, user: UserDocument, done: Function) {
function sendForgotPasswordEmail(token: AuthToken, user: UserDocument, done: (err: Error) => void) {
const transporter = nodemailer.createTransport({
service: "SendGrid",
auth: {

View File

@@ -23,32 +23,35 @@ export type UserDocument = mongoose.Document & {
gravatar: (size: number) => string;
};
type comparePasswordFunction = (candidatePassword: string, cb: (err: any, isMatch: any) => {}) => void;
type comparePasswordFunction = (candidatePassword: string, cb: (err: any, isMatch: any) => void) => void;
export interface AuthToken {
accessToken: string;
kind: string;
}
const userSchema = new mongoose.Schema({
email: { type: String, unique: true },
password: String,
passwordResetToken: String,
passwordResetExpires: Date,
facebook: String,
twitter: String,
google: String,
tokens: Array,
profile: {
name: String,
gender: String,
location: String,
website: String,
picture: String
}
}, { timestamps: true });
const userSchema = new mongoose.Schema<UserDocument>(
{
email: { type: String, unique: true },
password: String,
passwordResetToken: String,
passwordResetExpires: Date,
facebook: String,
twitter: String,
google: String,
tokens: Array,
profile: {
name: String,
gender: String,
location: String,
website: String,
picture: String
}
},
{ timestamps: true },
);
/**
* Password hash middleware.

12
src/types/express-session-types.d.ts vendored Normal file
View File

@@ -0,0 +1,12 @@
/**
* Naming this file express-session.d.ts causes imports from "express-session"
* to reference this file and not the node_modules package.
*/
import session from "express-session-types";
declare module "express-session" {
export interface SessionData {
returnTo: string;
}
}