├── .editorconfig
├── .gitignore
├── .prettierignore
├── .travis.yml
├── changelog.md
├── license
├── package-lock.json
├── package.json
├── readme.md
├── src
├── encryption.spec.ts
├── encryption.ts
├── hash.spec.ts
├── hash.ts
├── index.spec.ts
├── index.ts
├── random.spec.ts
├── random.ts
├── utils.spec.ts
└── utils.ts
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_size = 4
6 | indent_style = tab
7 | insert_final_newline = true
8 | trim_trailing_whitespace = true
9 |
10 | [*.md]
11 | trim_trailing_whitespace = false
12 |
13 | [*.yml]
14 | indent_size = 2
15 | indent_style = space
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | npm-debug.log
4 | dist
5 | coverage
6 | .nyc_output
7 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | dist
2 | coverage
3 | node_modules
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | sudo: false
3 | node_js:
4 | - 13
5 | - 12
6 | - 11
7 | - 10
8 | - 9
9 | - 8
10 | - 7
11 | - 6
12 | after_success:
13 | - npm run coveralls
14 |
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | # Crypto Extra Changelog
2 |
3 | ## v1.0
4 |
5 | - Removed manual type checking in favor of Typescript
6 | - Renamed `generateKey` to `randomKey`
7 |
8 | ## v0.4
9 |
10 | - BREAKING: Removed both Bcrypt methods (https://github.com/jsonmaur/node-crypto-extra/issues/1)
11 | - Bug fixes
12 |
13 | ## v0.3
14 |
15 | - Removed [npmjs.org/bcryptjs]() package in favor of [npmjs.org/bcrypt](), which relies on `node-gyp` for faster results.
16 | - Removed `.checksum` and `.checksumSync`. Use [this package](https://github.com/dshaw/checksum) instead.
17 | - Renamed `.bcrypt` to `.bcryptHash` to be more consistent.
18 | - Removed `.bcryptSync` and `.bcryptCompareSync` in favor of promised versions.
19 | - Added `length` option to `.generateKey`.
20 |
21 | #### Removed Deprecations
22 |
23 | - `.decrypt` that was used before encryption IV was implemented.
24 | - Old version of `.random`.
25 | - Specifying `options.length` on `.randomString`.
26 | - Old consolidated version of `.bcrypt` that was hash and compare in one.
27 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2019 Jason Maurer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "crypto-extra",
3 | "version": "1.0.1",
4 | "description": "Convenience methods for the crypto module",
5 | "author": "Jason Maurer",
6 | "license": "MIT",
7 | "homepage": "https://github.com/jsonmaur/node-crypto-extra#readme",
8 | "repository": {
9 | "type": "git",
10 | "url": "git+https://github.com/jsonmaur/node-crypto-extra.git"
11 | },
12 | "engines": {
13 | "node": ">=6"
14 | },
15 | "keywords": [
16 | "crypto",
17 | "cryptography",
18 | "hash",
19 | "encrypt",
20 | "decrypt",
21 | "encryption",
22 | "decryption",
23 | "sha1",
24 | "md5",
25 | "aes256",
26 | "random",
27 | "hex",
28 | "cipher",
29 | "extra"
30 | ],
31 | "files": [
32 | "dist/",
33 | "license",
34 | "readme.md"
35 | ],
36 | "main": "dist/index.js",
37 | "scripts": {
38 | "clean": "rm -rf dist coverage",
39 | "format": "prettier --write './**/*.{ts,json,yml,md}'",
40 | "format:check": "prettier --check './**/*.{ts,json,yml,md}'",
41 | "test": "npm run format:check && jest --coverage",
42 | "coveralls": "cat coverage/lcov.info | coveralls",
43 | "prebuild": "npm run clean",
44 | "build": "tsc",
45 | "prepare": "npm run build"
46 | },
47 | "devDependencies": {
48 | "@types/jest": "24.0.19",
49 | "@types/node": "12.11.5",
50 | "coveralls": "3.0.7",
51 | "jest": "24.9.0",
52 | "prettier": "1.18.2",
53 | "ts-jest": "24.1.0",
54 | "typescript": "3.6.4"
55 | },
56 | "prettier": {
57 | "semi": false,
58 | "useTabs": true,
59 | "trailingComma": "all",
60 | "arrowParens": "always",
61 | "printWidth": 100
62 | },
63 | "jest": {
64 | "testEnvironment": "node",
65 | "transform": {
66 | "\\.ts$": "ts-jest"
67 | },
68 | "collectCoverageFrom": [
69 | "src/**/*.ts"
70 | ],
71 | "coverageReporters": [
72 | "lcov",
73 | "text"
74 | ]
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Crypto-Extra for Node.js
2 |
3 | [](https://travis-ci.org/jsonmaur/node-crypto-extra)
4 | [](https://coveralls.io/github/jsonmaur/node-crypto-extra?branch=master)
5 |
6 | Adds convenience methods to the native Node.js [crypto module](https://nodejs.org/api/crypto.html). It is a drop in replacement, and extends the original module functionality.
7 |
8 | - [Getting Started](#getting-started)
9 | - [API](#api)
10 | - [encrypt](#api-encrypt)
11 | - [decrypt](#api-decrypt)
12 | - [hash](#api-hash)
13 | - [randomKey](#api-random-key)
14 | - [randomString](#api-random-string)
15 | - [randomNumber](#api-random-number)
16 | - [native crypto methods](https://nodejs.org/api/crypto.html)
17 |
18 | ## Why?
19 |
20 | The native `crypto` module can be a pain to work with, and requires a lot of boilerplate to do things such as randomizing and encryption. This abstracts all of that.
21 |
22 |
23 |
24 | ## Getting Started
25 |
26 | ```bash
27 | $ npm install crypto-extra --save
28 | ```
29 |
30 | To use in your project, simply require into your project as you would the `crypto` module.
31 |
32 | ```javascript
33 | const crypto = require("crypto-extra")
34 |
35 | crypto.randomString()
36 | //= L0e84MUt0n
37 |
38 | crypto.hash("hello")
39 | //= 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
40 | ```
41 |
42 |
43 |
44 | ## API
45 |
46 |
47 |
48 | ### .encrypt (value, secretKey)
49 |
50 | Encrypts a value with a secret key using AES-256-CTR.
51 |
52 | - **value** - The value you want to encrypt. Everything (except objects) is converted to a string before encryption for consistency. Objects are stringified using `JSON.stringify`.
53 |
54 | > Type: `any`
55 |
56 | - **secretKey** - The key used in the encryption. If not supplied, the lib will fallback to the environment variable `ENCRYPTION_KEY`.
57 |
58 | > Type: `string`
59 | > Default: `process.env.ENCRYPTION_KEY`
60 |
61 |
62 |
63 | ### .decrypt (value, secretKey)
64 |
65 | Decrypts a value using AES-256-CTR.
66 |
67 | - **value** - The encrypted value you want to decrypt. Will automatically parse objects that were encrypted.
68 |
69 | > Type: `string`
70 |
71 | - **secretKey** - The key used in the encryption. If not supplied, the lib will fallback to the environment variable `ENCRYPTION_KEY`.
72 |
73 | > Type: `string`
74 | > Default: `process.env.ENCRYPTION_KEY`
75 |
76 |
77 |
78 | ### .hash (value, options)
79 |
80 | Hashes a string with the provided algorithm.
81 |
82 | - **value** - The value you want to hash. Any non-string value is converted to a string before hashing for consistency.
83 |
84 | > Type: `string`
85 |
86 | - **options**
87 |
88 | - **rounds** - The number of rounds to use when hashing.
89 |
90 | > Type: `integer`
91 | > Default: `1`
92 |
93 | - **salt** - A string to be appended to the value before it is hashed.
94 |
95 | > Type: `string`
96 |
97 | - **algorithm** - The hashing algorithm to use.
98 |
99 | > Type: `string`
100 | > Default: `SHA256`
101 |
102 |
103 |
104 | ### .randomKey (length)
105 |
106 | Generates a random 256-bit key that can be used as an encryption key.
107 |
108 | - **length** - The length of the key you want to generate. **Must be an even number.**
109 |
110 | > Type: `number`
111 | > Default: `32`
112 |
113 |
114 |
115 | ### .randomString (length, charset)
116 |
117 | Returns a random string of a defined length.
118 |
119 | - **length** - Length of the random string. Must be above 0.
120 |
121 | > Type: `integer`
122 | > Default: `10`
123 |
124 | - **charset** - The character set to take from.
125 |
126 | > Type: `string`
127 | > Default: `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`
128 |
129 |
130 |
131 | ### .randomNumber (options)
132 |
133 | Returns a random string within a defined range.
134 |
135 | - **options**
136 |
137 | - **min** - Minimum number of range. Must be a positive integer.
138 |
139 | > Type: `integer`
140 | > Default: `0`
141 |
142 | - **max** - Maximum number of range. This cannot be higher than `9007199254740991` due to Javascript integer limits (http://mzl.la/1A1nVyU). If you need a number higher than this, consider using [randomString](#api-random-string) with the charset `0123456789` instead.
143 |
144 | > Type: `integer`
145 | > Default: `9007199254740991`
146 |
147 | ## License
148 |
149 | [MIT](license) © [Jason Maurer](https://maur.co)
150 |
--------------------------------------------------------------------------------
/src/encryption.spec.ts:
--------------------------------------------------------------------------------
1 | import * as encryption from "./encryption"
2 |
3 | const SECRET_KEY = "asdfasdfasdfasdfasdfasdfasdfasdf"
4 |
5 | test("encrypt()", async () => {
6 | expect(encryption.decrypt(encryption.encrypt("hey", SECRET_KEY), SECRET_KEY)).toBe("hey")
7 | expect(encryption.encrypt("hey", SECRET_KEY)).toBeTruthy()
8 | expect(encryption.encrypt(100, SECRET_KEY)).toBeTruthy()
9 | expect(encryption.encrypt({ hello: "hey" }, SECRET_KEY)).toBeTruthy()
10 | expect(encryption.encrypt(true, SECRET_KEY)).toBeTruthy()
11 | expect(encryption.encrypt("hey", "hello")).toBeTruthy()
12 | expect(() => encryption.encrypt("hey", "")).toThrow(Error)
13 | expect(() => encryption.encrypt("hey")).toThrow(Error)
14 | })
15 |
16 | test("decrypt()", async () => {
17 | const encryptedStr =
18 | "ae8f31$9aef670513191e77b51d3948bc0ea539$33a8b27803725fd7e8c5641548b43b545a876767219e9badc280be8e3aff8bba"
19 | const encryptedObj =
20 | "55bc46634486927655e1c9e7a514ae$f5ba32e5cc42e78f5a07bcfe0645f668$d9a20b941a6ffdb64526055d388a1411e8227afd978dcec7f7aa110085a218b8"
21 | const encryptedObjTampered =
22 | "55bc46634486927655e1c9e7a514ae$f5ba32e5cc42e78f5a07bcfe0645f668$d9a20b941a6ffdb64526055d388a1411e8227afd978dcec7f7aa110085a218b9"
23 |
24 | expect(encryption.decrypt(encryptedStr, SECRET_KEY)).toBe("hey")
25 | expect(encryption.decrypt(encryptedObj, SECRET_KEY)).toEqual({ hello: "hey" })
26 | expect(() => encryption.decrypt("hi$")).toThrow(Error)
27 | expect(() => encryption.decrypt("hey$", "short-secret-key")).toThrow(Error)
28 | expect(() => encryption.decrypt(encryptedObjTampered, SECRET_KEY)).toThrow(Error)
29 | })
30 |
--------------------------------------------------------------------------------
/src/encryption.ts:
--------------------------------------------------------------------------------
1 | import crypto from "crypto"
2 | import { stringify } from "./utils"
3 |
4 | const ALGORITHM = "aes-256-ctr"
5 | const HMAC_ALGORITHM = "sha256"
6 |
7 | /**
8 | * Gets the encryption key from the environment,
9 | * and hash with SHA256 (ensures length). Falls back
10 | * to the environment variable if no key is specified.
11 | */
12 | function getEncryptionKey(key?: string): Buffer {
13 | const encryptionKey = key || process.env.ENCRYPTION_KEY
14 |
15 | if (!encryptionKey) {
16 | throw new Error("No encryption key was found")
17 | }
18 |
19 | const cryptoKey = crypto
20 | .createHash("sha256")
21 | .update(encryptionKey)
22 | .digest()
23 |
24 | return cryptoKey
25 | }
26 |
27 | /**
28 | * Ensures the encrypted payload has not been tampered with.
29 | */
30 | function constantTimeCompare(val1: string, val2: string): boolean {
31 | if (val1.length !== val2.length) {
32 | return false
33 | }
34 |
35 | let sentinel = 0
36 | for (let i = 0, len = val1.length; i < len; i++) {
37 | sentinel |= val1.charCodeAt(i) ^ val2.charCodeAt(i)
38 | }
39 |
40 | return sentinel === 0
41 | }
42 |
43 | /**
44 | * Encrypts a value using ciphers.
45 | */
46 | export function encrypt(value: any, key?: string): string {
47 | const iv = Buffer.from(crypto.randomBytes(16))
48 | const encryptionKey = Buffer.from(getEncryptionKey(key))
49 | const cipher = crypto.createCipheriv(ALGORITHM, encryptionKey, iv)
50 |
51 | cipher.setEncoding("hex")
52 | cipher.write(stringify(value))
53 | cipher.end()
54 |
55 | const cipherText = cipher.read()
56 | const hmac = crypto.createHmac(HMAC_ALGORITHM, encryptionKey)
57 |
58 | hmac.update(cipherText)
59 | hmac.update(iv.toString("hex"))
60 |
61 | return `${cipherText}$${iv.toString("hex")}$${hmac.digest("hex")}`
62 | }
63 |
64 | /**
65 | * Decrypts a value using ciphers.
66 | */
67 | export function decrypt(value: string, key?: string): any {
68 | const cipher = value.split("$")
69 | const iv = Buffer.from(cipher[1], "hex")
70 | const encryptionKey = Buffer.from(getEncryptionKey(key))
71 | const hmac = crypto.createHmac(HMAC_ALGORITHM, encryptionKey)
72 |
73 | hmac.update(cipher[0])
74 | hmac.update(iv.toString("hex"))
75 |
76 | if (!constantTimeCompare(hmac.digest("hex"), cipher[2])) {
77 | throw new Error("Encrypted payload has been tampered with")
78 | }
79 |
80 | const decipher = crypto.createDecipheriv(ALGORITHM, encryptionKey, iv)
81 | const decryptedText = decipher.update(cipher[0], "hex")
82 | const final = `${decryptedText}${decipher.final()}`
83 |
84 | try {
85 | return JSON.parse(final)
86 | } catch (err) {
87 | return final
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/hash.spec.ts:
--------------------------------------------------------------------------------
1 | import * as hash from "./hash"
2 |
3 | test("hash()", async () => {
4 | expect(hash.hash("testing")).toBe(
5 | "cf80cd8aed482d5d1527d7dc72fceff84e6326592848447d2dc0b0e87dfc9a90",
6 | )
7 | expect(hash.hash("testing", { algorithm: "md5" })).toBe("ae2b1fca515949e5d54fb22b8ed95575")
8 | expect(hash.hash("testing", { salt: "yo-this-is-a-salt" })).toBe(
9 | "bd3df90288d99583d1c93f00ec00d92c97c3aff241b1beffb819dbd15f68d9f6",
10 | )
11 | expect(hash.hash({ test: "hi" })).toBe(
12 | "aa6d68a0aab2f834d2bc353d734907e0e0d562e1beaf99432bd665c96f5b4d7b",
13 | )
14 | expect(hash.hash("testing", { rounds: 100 })).toBe(
15 | "2c66de00e03581e03866d7b62a31a7d5776419f498f479a877270294c2600321",
16 | )
17 | })
18 |
--------------------------------------------------------------------------------
/src/hash.ts:
--------------------------------------------------------------------------------
1 | import crypto from "crypto"
2 | import { stringify } from "./utils"
3 |
4 | type HashOptions = {
5 | algorithm?: string
6 | rounds?: number
7 | salt?: string
8 | }
9 |
10 | /**
11 | * Gets the hash a value.
12 | */
13 | export function hash(value: any, options: HashOptions = {}): string {
14 | const parsedValue = stringify(value)
15 | const algorithm = options.algorithm || "sha256"
16 | const rounds = options.rounds || 1
17 |
18 | let hash = `${parsedValue}${options.salt || ""}`
19 | for (let i = 0; i < rounds; i++) {
20 | hash = crypto
21 | .createHash(algorithm)
22 | .update(hash)
23 | .digest("hex")
24 | }
25 |
26 | return hash
27 | }
28 |
--------------------------------------------------------------------------------
/src/index.spec.ts:
--------------------------------------------------------------------------------
1 | import crypto from "./"
2 |
3 | test("exports", async () => {
4 | expect(crypto.createHmac).toBeTruthy()
5 | expect(crypto.randomString).toBeTruthy()
6 | })
7 |
8 | test("deprecated", async () => {
9 | expect(crypto.generateKey()).toBeTruthy()
10 | })
11 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import crypto from "crypto"
2 | import * as hash from "./hash"
3 | import * as encryption from "./encryption"
4 | import * as random from "./random"
5 |
6 | function deprecationNotice(msg: string) {
7 | console.log(`crypto-extra: ${msg}`)
8 | }
9 |
10 | export = Object.assign(crypto, {
11 | hash: hash.hash,
12 | encrypt: encryption.encrypt,
13 | decrypt: encryption.decrypt,
14 | randomString: random.randomString,
15 | randomNumber: random.randomNumber,
16 | randomKey: random.randomKey,
17 |
18 | /* deprecated methods */
19 | generateKey: (...args: any) => {
20 | deprecationNotice("`generateKey` has been renamed to `randomKey`")
21 | return random.randomKey(...args)
22 | },
23 | })
24 |
--------------------------------------------------------------------------------
/src/random.spec.ts:
--------------------------------------------------------------------------------
1 | import * as random from "./random"
2 |
3 | test("randomString()", async () => {
4 | expect(random.randomString()).toBeTruthy()
5 | expect(random.randomString()).toHaveLength(10)
6 | expect(random.randomString(20)).toHaveLength(20)
7 | expect(() => random.randomString(0)).toThrow(Error)
8 | expect(() => random.randomString(-5)).toThrow(Error)
9 | })
10 |
11 | test("randomNumber()", async () => {
12 | expect(random.randomNumber()).toBeGreaterThan(0)
13 | expect(() => random.randomNumber({ max: Number.MAX_SAFE_INTEGER + 1 })).toThrow(Error)
14 | expect(() => random.randomNumber({ min: -1 })).toThrow(Error)
15 | expect(() => random.randomNumber({ max: -1 })).toThrow(Error)
16 |
17 | const min = 100
18 | const max = 150
19 | for (let i = 0; i < 10000; i++) {
20 | const num = random.randomNumber({ min, max })
21 | expect(num >= min).toBe(true)
22 | expect(num <= max).toBe(true)
23 | }
24 | })
25 |
26 | test("randomKey()", async () => {
27 | expect(random.randomKey()).toHaveLength(64)
28 | expect(random.randomKey(10)).toHaveLength(10)
29 | expect(random.randomKey(152)).toHaveLength(152)
30 | expect(() => random.randomKey(65)).toThrow(TypeError)
31 | expect(() => random.randomKey(0)).toThrow(TypeError)
32 | })
33 |
--------------------------------------------------------------------------------
/src/random.ts:
--------------------------------------------------------------------------------
1 | import { randomBytes } from "crypto"
2 |
3 | type RandomNumberOptions = {
4 | min?: number
5 | max?: number
6 | }
7 |
8 | /**
9 | * Creates a random string.
10 | */
11 | export function randomString(size?: number, charset?: string): string {
12 | if (size !== undefined && size <= 0) {
13 | throw new Error("Random size must be a number above 0!")
14 | }
15 |
16 | const bytes = randomBytes(size || 10)
17 | const chars = charset || "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
18 |
19 | let value = ""
20 | for (let i = 0, len = bytes.length; i < len; i++) {
21 | value += chars[bytes.readUInt8(i) % chars.length]
22 | }
23 |
24 | return value
25 | }
26 |
27 | /**
28 | * Generates a random number.
29 | */
30 | export function randomNumber(options: RandomNumberOptions = {}): number {
31 | const integerLimit = Number.MAX_SAFE_INTEGER
32 |
33 | options.min = options.min || 0
34 | options.max = options.max || integerLimit
35 |
36 | if (
37 | options.min < 0 ||
38 | options.min > integerLimit - 1 ||
39 | options.max < 1 ||
40 | options.max > integerLimit
41 | ) {
42 | throw new Error(`Limits must be between 0 and ${integerLimit}`)
43 | }
44 |
45 | const hex = randomBytes(16).toString("hex")
46 | const integer = parseInt(hex, 16)
47 | const random = integer / 0xffffffffffffffffffffffffffffffff
48 |
49 | return Math.floor(random * (options.max - options.min + 1) + options.min)
50 | }
51 |
52 | /**
53 | * Generates a secure 256-bit key.
54 | */
55 | export function randomKey(length: number = 64): string {
56 | if (length < 2 || length % 2 !== 0) {
57 | throw new TypeError("Length must be an even number above 0")
58 | }
59 |
60 | return randomBytes(length / 2).toString("hex")
61 | }
62 |
--------------------------------------------------------------------------------
/src/utils.spec.ts:
--------------------------------------------------------------------------------
1 | import * as utils from "./utils"
2 |
3 | test("stringify()", async () => {
4 | expect(utils.stringify(1)).toBe("1")
5 | expect(utils.stringify({ hey: "hi" })).toBe('{"hey":"hi"}')
6 | })
7 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Turns a value into a string. Uses JSON.stringify
3 | * if the value is an object.
4 | */
5 | export function stringify(value: any): string {
6 | return typeof value === "object" ? JSON.stringify(value) : String(value)
7 | }
8 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": ["src/**/*.ts"],
3 | "exclude": ["node_modules", "**/*.spec.ts"],
4 | "compilerOptions": {
5 | "outDir": "dist",
6 | "module": "commonjs",
7 | "declaration": true,
8 | "strict": true,
9 | "esModuleInterop": true,
10 | "noEmitOnError": true,
11 | "listEmittedFiles": true,
12 | "removeComments": true,
13 | "noUnusedLocals": true,
14 | "forceConsistentCasingInFileNames": true
15 | }
16 | }
17 |
--------------------------------------------------------------------------------