From 17fa8939a229ff3dccf90fc585f09e9eccec32bf Mon Sep 17 00:00:00 2001 From: andrzej Date: Tue, 28 May 2024 22:22:41 +0200 Subject: [PATCH] implement tutorial steps --- auth/auth.mts | 63 +++++++++++++++++++++++++++++++++++ db.mts | 21 ++++++++++++ dist/auth/auth.mjs | 57 +++++++++++++++++++++++++++++++ dist/db.mjs | 15 +++++++++ dist/index.mjs | 23 +++++++++++++ dist/model/model.js | 43 ++++++++++++++++++++++++ dist/model/model.mjs | 37 ++++++++++++++++++++ dist/routes/routes.js | 46 +++++++++++++++++++++++++ dist/routes/routes.mjs | 54 ++++++++++++++++++++++++++++++ dist/routes/secure-routes.js | 15 +++++++++ dist/routes/secure-routes.mjs | 10 ++++++ index.mts | 29 ++++++++++++++++ index.ts | 1 - model/model.mts | 41 +++++++++++++++++++++++ package.json | 9 +++++ routes/routes.mts | 52 +++++++++++++++++++++++++++++ routes/secure-routes.mts | 15 +++++++++ tsconfig.json | 24 +++++-------- 18 files changed, 538 insertions(+), 17 deletions(-) create mode 100644 auth/auth.mts create mode 100644 db.mts create mode 100644 dist/auth/auth.mjs create mode 100644 dist/db.mjs create mode 100644 dist/index.mjs create mode 100644 dist/model/model.js create mode 100644 dist/model/model.mjs create mode 100644 dist/routes/routes.js create mode 100644 dist/routes/routes.mjs create mode 100644 dist/routes/secure-routes.js create mode 100644 dist/routes/secure-routes.mjs create mode 100644 index.mts delete mode 100644 index.ts create mode 100644 model/model.mts create mode 100644 routes/routes.mts create mode 100644 routes/secure-routes.mts diff --git a/auth/auth.mts b/auth/auth.mts new file mode 100644 index 0000000..963aa8d --- /dev/null +++ b/auth/auth.mts @@ -0,0 +1,63 @@ +import passport from 'passport' +import { Strategy as localStrategy } from 'passport-local' +import { User, UserModel } from '../model/model.mjs' +import { Strategy as JWTstrategy, ExtractJwt } from 'passport-jwt' + +passport.use('signup', new localStrategy( + { + usernameField: 'email', + passwordField: 'password' + }, + async (email, password, done) => { + try { + const user = await UserModel.create({ email, password }) + return done(null, user) + } catch (err) { + done(err) + } + })) + +passport.use( + new localStrategy( + { + usernameField: "email", + passwordField: "password", + session: false + }, + async (email, password, done) => { + try { + const user: User = await UserModel.findOne({ email }) + console.log(`user: ${user}`) + if (!user) { + return done(null, false, { message: "user not found" }) + } + + const validate: boolean = await user.isValidPassword(password) + + if (!validate) { + return done(null, false, { message: "wrong password" }) + } + + return done(null, false, { message: "logged in successfully" }) + } catch (error) { + return done(error) + } + } + ) +) + +passport.use( + new JWTstrategy( + { + secretOrKey: "TOP_SECRET", + jwtFromRequest: ExtractJwt.fromUrlQueryParameter('secret_token') + }, + async (token, done) => { + try { + return done(null, token.user) + } catch (error) { + done(error) + } + } + ) +) diff --git a/db.mts b/db.mts new file mode 100644 index 0000000..481a1bf --- /dev/null +++ b/db.mts @@ -0,0 +1,21 @@ +import knex from "knex"; + +export const db = knex({ + client: 'sqlite3', + connection: { + filename: "./submissions" + }, + useNullAsDefault: true +}) + +export const testDb = knex({ + client: 'sqlite3', + connection: { + filename: "./test.db" + }, + useNullAsDefault: true +}) + + + + diff --git a/dist/auth/auth.mjs b/dist/auth/auth.mjs new file mode 100644 index 0000000..1e851de --- /dev/null +++ b/dist/auth/auth.mjs @@ -0,0 +1,57 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import passport from 'passport'; +import { Strategy as localStrategy } from 'passport-local'; +import { UserModel } from '../model/model.mjs'; +import { Strategy as JWTstrategy, ExtractJwt } from 'passport-jwt'; +passport.use('signup', new localStrategy({ + usernameField: 'email', + passwordField: 'password' +}, (email, password, done) => __awaiter(void 0, void 0, void 0, function* () { + try { + const user = yield UserModel.create({ email, password }); + return done(null, user); + } + catch (err) { + done(err); + } +}))); +passport.use(new localStrategy({ + usernameField: "email", + passwordField: "password", + session: false +}, (email, password, done) => __awaiter(void 0, void 0, void 0, function* () { + try { + const user = yield UserModel.findOne({ email }); + console.log(`user: ${user}`); + if (!user) { + return done(null, false, { message: "user not found" }); + } + const validate = yield user.isValidPassword(password); + if (!validate) { + return done(null, false, { message: "wrong password" }); + } + return done(null, false, { message: "logged in successfully" }); + } + catch (error) { + return done(error); + } +}))); +passport.use(new JWTstrategy({ + secretOrKey: "TOP_SECRET", + jwtFromRequest: ExtractJwt.fromUrlQueryParameter('secret_token') +}, (token, done) => __awaiter(void 0, void 0, void 0, function* () { + try { + return done(null, token.user); + } + catch (error) { + done(error); + } +}))); diff --git a/dist/db.mjs b/dist/db.mjs new file mode 100644 index 0000000..18bca12 --- /dev/null +++ b/dist/db.mjs @@ -0,0 +1,15 @@ +import knex from "knex"; +export const db = knex({ + client: 'sqlite3', + connection: { + filename: "./submissions" + }, + useNullAsDefault: true +}); +export const testDb = knex({ + client: 'sqlite3', + connection: { + filename: "./test.db" + }, + useNullAsDefault: true +}); diff --git a/dist/index.mjs b/dist/index.mjs new file mode 100644 index 0000000..f556717 --- /dev/null +++ b/dist/index.mjs @@ -0,0 +1,23 @@ +import express from "express"; +import mongoose from "mongoose"; +import passport from "passport"; +import bodyParser from "body-parser"; +import { default as routes } from "./routes/routes.mjs"; +import { default as secureRoute } from "./routes/secure-routes.mjs"; +import "./auth/auth.mjs"; +mongoose.connect("mongodb://127.0.0.1:27017/passport-jwt", {}); +mongoose.connection.on('error', error => console.log(error)); +mongoose.Promise = global.Promise; +const app = express(); +app.use(passport.initialize()); +app.use(bodyParser.urlencoded({ extended: false })); +app.use("/", routes); +app.use('/user', passport.authenticate('jwt', { session: false }), secureRoute); +// Handle errors. +app.use(function (err, req, res) { + res.status(err.status || 500); + res.json({ error: err }); +}); +app.listen(3000, () => { + console.log('Server started.'); +}); diff --git a/dist/model/model.js b/dist/model/model.js new file mode 100644 index 0000000..45ef611 --- /dev/null +++ b/dist/model/model.js @@ -0,0 +1,43 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.UserModel = void 0; +const mongoose_1 = __importDefault(require("mongoose")); +const bcrypt_1 = __importDefault(require("bcrypt")); +const Schema = mongoose_1.default.Schema; +const UserSchema = new Schema({ + email: { + type: String, + required: true, + unique: true + }, + password: { + type: String, + required: true + } +}); +UserSchema.pre("save", function (next) { + return __awaiter(this, void 0, void 0, function* () { + const hash = yield bcrypt_1.default.hash(this.password, 10); + this.password = hash; + next(); + }); +}); +UserSchema.methods.isValidPassword = function (password) { + return __awaiter(this, void 0, void 0, function* () { + const compare = yield bcrypt_1.default.compare(password, this.password); + return compare; + }); +}; +exports.UserModel = mongoose_1.default.model("user", UserSchema); diff --git a/dist/model/model.mjs b/dist/model/model.mjs new file mode 100644 index 0000000..b8a3b84 --- /dev/null +++ b/dist/model/model.mjs @@ -0,0 +1,37 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import mongoose from "mongoose"; +import bcrypt from "bcrypt"; +const Schema = mongoose.Schema; +const UserSchema = new Schema({ + email: { + type: String, + required: true, + unique: true + }, + password: { + type: String, + required: true + } +}); +UserSchema.pre("save", function (next) { + return __awaiter(this, void 0, void 0, function* () { + const hash = yield bcrypt.hash(this.password, 10); + this.password = hash; + next(); + }); +}); +UserSchema.methods.isValidPassword = function (password) { + return __awaiter(this, void 0, void 0, function* () { + const compare = yield bcrypt.compare(password, this.password); + return compare; + }); +}; +export const UserModel = mongoose.model("user", UserSchema); diff --git a/dist/routes/routes.js b/dist/routes/routes.js new file mode 100644 index 0000000..855fb49 --- /dev/null +++ b/dist/routes/routes.js @@ -0,0 +1,46 @@ +"use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = __importDefault(require("express")); +const passport_1 = __importDefault(require("passport")); +const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); +const jwt = jsonwebtoken_1.default; +const router = express_1.default.Router(); +router.post("/signup", passport_1.default.authenticate("signup", { session: false }), (req, res) => __awaiter(void 0, void 0, void 0, function* () { + res.json({ + message: "signup successful", + user: req.user + }); +})); +router.post("/login", (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { + passport_1.default.authenticate("login", (err, user) => __awaiter(void 0, void 0, void 0, function* () { + try { + if (err || !user) { + const error = new Error("uhoh! an error occurred"); + return next(error); + } + req.login(user, { session: false }, (error) => __awaiter(void 0, void 0, void 0, function* () { + if (error) + return next(error); + const body = { _id: user._id, email: user.email }; + const token = jwt.sign({ user: body }, "TOP_SECRET"); + return res.json({ token }); + })); + } + catch (error) { + return next(error); + } + })); +})); +exports.default = router; diff --git a/dist/routes/routes.mjs b/dist/routes/routes.mjs new file mode 100644 index 0000000..ae052b5 --- /dev/null +++ b/dist/routes/routes.mjs @@ -0,0 +1,54 @@ +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +import express from "express"; +import passport from "passport"; +const router = express.Router(); +router.post("/signup", passport.authenticate("signup", { session: false }), (req, res, next) => __awaiter(void 0, void 0, void 0, function* () { + res.json({ + message: "signup successful", + user: req.user + }); +})); +router.post("/login", passport.authenticate('local'), function (req, res) { + console.log("BOOM!"); +}); +// router.post( +// '/login', +// async (req, res, next) => { +// passport.authenticate( +// 'login', +// async (err, user, info) => { +// try { +// if (err || !user) { +// const error = new Error('An error occurred.'); +// +// return next(error); +// } +// +// req.login( +// user, +// { session: false }, +// async (error) => { +// if (error) return next(error); +// +// const body = { _id: user._id, email: user.email }; +// const token = jwt.sign({ user: body }, 'TOP_SECRET'); +// +// return res.json({ token }); +// } +// ); +// } catch (error) { +// return next(error); +// } +// } +// )(req, res, next); +// } +// ); +export default router; diff --git a/dist/routes/secure-routes.js b/dist/routes/secure-routes.js new file mode 100644 index 0000000..710643e --- /dev/null +++ b/dist/routes/secure-routes.js @@ -0,0 +1,15 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const express_1 = __importDefault(require("express")); +const router = express_1.default.Router(); +router.get('/profile', (req, res, next) => { + res.json({ + message: "you made it to the secure route", + user: req.user, + token: req.query.secret_token, + }); +}); +exports.default = router; diff --git a/dist/routes/secure-routes.mjs b/dist/routes/secure-routes.mjs new file mode 100644 index 0000000..9c4e402 --- /dev/null +++ b/dist/routes/secure-routes.mjs @@ -0,0 +1,10 @@ +import express from "express"; +const router = express.Router(); +router.get('/profile', (req, res, next) => { + res.json({ + message: "you made it to the secure route", + user: req.user, + token: req.query.secret_token, + }); +}); +export default router; diff --git a/index.mts b/index.mts new file mode 100644 index 0000000..2e7f89b --- /dev/null +++ b/index.mts @@ -0,0 +1,29 @@ +import express from "express" +import mongoose from "mongoose" +import passport from "passport" +import bodyParser from "body-parser" + +import { UserModel } from "./model/model.mjs" +import { default as routes } from "./routes/routes.mjs" +import { default as secureRoute } from "./routes/secure-routes.mjs" +import "./auth/auth.mjs" +mongoose.connect("mongodb://127.0.0.1:27017/passport-jwt", {}); +mongoose.connection.on('error', error => console.log(error)); +mongoose.Promise = global.Promise; + +const app = express() +app.use(passport.initialize()) + +app.use(bodyParser.urlencoded({ extended: false })) +app.use("/", routes) +app.use('/user', passport.authenticate('jwt', { session: false }), secureRoute); + +// Handle errors. +app.use(function(err: any, req, res: any) { + res.status(err.status || 500); + res.json({ error: err }); +}); + +app.listen(3000, () => { + console.log('Server started.') +}); diff --git a/index.ts b/index.ts deleted file mode 100644 index 8b13789..0000000 --- a/index.ts +++ /dev/null @@ -1 +0,0 @@ - diff --git a/model/model.mts b/model/model.mts new file mode 100644 index 0000000..5856ae1 --- /dev/null +++ b/model/model.mts @@ -0,0 +1,41 @@ +import mongoose from "mongoose"; +import bcrypt from "bcrypt" + +const Schema = mongoose.Schema + +const UserSchema = new Schema({ + email: { + type: String, + required: true, + unique: true + }, + password: { + type: String, + required: true + } +}) + +UserSchema.pre( + "save", + async function(next) { + const hash = await bcrypt.hash(this.password, 10) + this.password = hash; + next(); + } +) + +UserSchema.methods.isValidPassword = async function(password: string) { + const compare = await bcrypt.compare(password, this.password) + return compare +} + +export interface User { + email: string; + password: string; + isValidPassword: (password: string) => Promise +} + +export const UserModel = mongoose.model("user", UserSchema) + + + diff --git a/package.json b/package.json index de40bea..d355175 100644 --- a/package.json +++ b/package.json @@ -3,12 +3,20 @@ "version": "1.0.0", "description": "backend for the subman literary submission manager", "main": "index.ts", + "type": "module", "scripts": { "test": "test" }, "author": "Andrzej Stepien", "license": "MIT", "devDependencies": { + "@types/bcrypt": "^5.0.2", + "@types/express": "^4.17.21", + "@types/jsonwebtoken": "^9.0.6", + "@types/mongoose": "^5.11.97", + "@types/passport": "^1.0.16", + "@types/passport-jwt": "^4.0.1", + "@types/passport-local": "^1.0.38", "typescript": "^5.4.5" }, "dependencies": { @@ -17,6 +25,7 @@ "express": "^4.19.2", "jsonwebtoken": "^9.0.2", "knex": "^3.1.0", + "mongoose": "^8.4.0", "passport": "^0.7.0", "passport-jwt": "^4.0.1", "passport-local": "^1.0.0" diff --git a/routes/routes.mts b/routes/routes.mts new file mode 100644 index 0000000..96ce729 --- /dev/null +++ b/routes/routes.mts @@ -0,0 +1,52 @@ +import express from "express" +import passport from "passport" +import jwt from 'jsonwebtoken'; + +const router = express.Router() + +router.post("/signup", + passport.authenticate("signup", { session: false }), + async (req, res, next) => { + res.json({ + message: "signup successful", + user: req.user + }) + }) +router.post("/login", passport.authenticate('local'), + function(req, res) { + console.log("BOOM!") + }) +// router.post( +// '/login', +// async (req, res, next) => { +// passport.authenticate( +// 'login', +// async (err, user, info) => { +// try { +// if (err || !user) { +// const error = new Error('An error occurred.'); +// +// return next(error); +// } +// +// req.login( +// user, +// { session: false }, +// async (error) => { +// if (error) return next(error); +// +// const body = { _id: user._id, email: user.email }; +// const token = jwt.sign({ user: body }, 'TOP_SECRET'); +// +// return res.json({ token }); +// } +// ); +// } catch (error) { +// return next(error); +// } +// } +// )(req, res, next); +// } +// ); + +export default router diff --git a/routes/secure-routes.mts b/routes/secure-routes.mts new file mode 100644 index 0000000..e224c7b --- /dev/null +++ b/routes/secure-routes.mts @@ -0,0 +1,15 @@ +import express from "express" +const router = express.Router() + +router.get( + '/profile', + (req, res, next) => { + res.json({ + message: "you made it to the secure route", + user: req.user, + token: req.query.secret_token, + }) + } +) + +export default router diff --git a/tsconfig.json b/tsconfig.json index e075f97..76aa295 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,6 @@ { "compilerOptions": { /* Visit https://aka.ms/tsconfig to read more about this file */ - /* Projects */ // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ @@ -9,9 +8,8 @@ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ @@ -23,9 +21,8 @@ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ + "module": "nodenext", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ @@ -42,12 +39,10 @@ // "resolveJsonModule": true, /* Enable importing .json files. */ // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - /* JavaScript Support */ // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - /* Emit */ // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ // "declarationMap": true, /* Create sourcemaps for d.ts files. */ @@ -55,7 +50,7 @@ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ + "outDir": "./dist", /* Specify an output folder for all emitted files. */ // "removeComments": true, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ @@ -72,17 +67,15 @@ // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ - + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ + "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ @@ -101,9 +94,8 @@ // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ } }