@yognky/premium-security 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/LICENSE +21 -0
- package/README.md +8 -0
- package/dist/defenses/advanced.d.ts +2 -0
- package/dist/defenses/advanced.js +7 -0
- package/dist/defenses/advenced.d.ts +2 -0
- package/dist/defenses/advenced.js +48 -0
- package/dist/defenses/bruteforce.d.ts +2 -0
- package/dist/defenses/bruteforce.js +43 -0
- package/dist/defenses/curlBot.d.ts +2 -0
- package/dist/defenses/curlBot.js +31 -0
- package/dist/defenses/ddos.d.ts +2 -0
- package/dist/defenses/ddos.js +42 -0
- package/dist/defenses/headers.d.ts +2 -0
- package/dist/defenses/headers.js +25 -0
- package/dist/defenses/malware.d.ts +2 -0
- package/dist/defenses/malware.js +34 -0
- package/dist/defenses/rateLimit.d.ts +2 -0
- package/dist/defenses/rateLimit.js +31 -0
- package/dist/defenses/spoofing.d.ts +2 -0
- package/dist/defenses/spoofing.js +7 -0
- package/dist/defenses/sqlInjection.d.ts +2 -0
- package/dist/defenses/sqlInjection.js +40 -0
- package/dist/defenses/timingAttack.d.ts +2 -0
- package/dist/defenses/timingAttack.js +7 -0
- package/dist/defenses/whitelist.d.ts +2 -0
- package/dist/defenses/whitelist.js +22 -0
- package/dist/defenses/xss.d.ts +2 -0
- package/dist/defenses/xss.js +45 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +98 -0
- package/dist/type/index.d.ts +41 -0
- package/dist/type/index.js +2 -0
- package/dist/types/index.d.ts +27 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/banner.d.ts +3 -0
- package/dist/utils/banner.js +71 -0
- package/dist/utils/helpers.d.ts +11 -0
- package/dist/utils/helpers.js +74 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/logger.d.ts +44 -0
- package/dist/utils/logger.js +148 -0
- package/docs/API.md +35 -0
- package/docs/EXAMPLE.md +45 -0
- package/docs/INSTALLATTION.md +6 -0
- package/examples/advenced-server.js +59 -0
- package/examples/basic-server.js +33 -0
- package/examples/simple-express.js +21 -0
- package/examples/with-express.ts +33 -0
- package/gitignore +48 -0
- package/nodemon.json +11 -0
- package/npmignore +36 -0
- package/package.json +27 -0
- package/src/defenses/advanced.ts +6 -0
- package/src/defenses/advenced.ts +54 -0
- package/src/defenses/bruteforce.ts +47 -0
- package/src/defenses/curlBot.ts +33 -0
- package/src/defenses/ddos.ts +46 -0
- package/src/defenses/headers.ts +27 -0
- package/src/defenses/malware.ts +35 -0
- package/src/defenses/rateLimit.ts +34 -0
- package/src/defenses/spoofing.ts +5 -0
- package/src/defenses/sqlInjection.ts +41 -0
- package/src/defenses/timingAttack.ts +5 -0
- package/src/defenses/whitelist.ts +23 -0
- package/src/defenses/xss.ts +46 -0
- package/src/index.ts +125 -0
- package/src/type/index.ts +48 -0
- package/src/types/index.ts +32 -0
- package/src/utils/banner.ts +73 -0
- package/src/utils/helpers +237 -0
- package/src/utils/helpers.ts +77 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/logger.ts +174 -0
- package/test/bruteforce.test.ts +34 -0
- package/test/ddos.test.ts +30 -0
- package/test/integration.test.ts +44 -0
- package/test/sql.test.ts +39 -0
- package/test/xss.test.ts +39 -0
- package/test-module.js +23 -0
- package/tsconfig.build.json +17 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
export enum LogLevel {
|
|
5
|
+
INFO = 'INFO',
|
|
6
|
+
WARNING = 'WARNING',
|
|
7
|
+
ERROR = 'ERROR',
|
|
8
|
+
ATTACK = 'ATTACK',
|
|
9
|
+
DEBUG = 'DEBUG'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface LogEntry {
|
|
13
|
+
timestamp: string;
|
|
14
|
+
level: LogLevel;
|
|
15
|
+
message: string;
|
|
16
|
+
ip?: string;
|
|
17
|
+
attackType?: string;
|
|
18
|
+
details?: any;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
class Logger {
|
|
22
|
+
private logFile: string;
|
|
23
|
+
private enableFileLogging: boolean;
|
|
24
|
+
private enableConsoleLogging: boolean;
|
|
25
|
+
private logBuffer: LogEntry[] = [];
|
|
26
|
+
private bufferSize: number = 100;
|
|
27
|
+
|
|
28
|
+
constructor() {
|
|
29
|
+
this.logFile = path.join(process.cwd(), 'yongky-security.log');
|
|
30
|
+
this.enableFileLogging = true;
|
|
31
|
+
this.enableConsoleLogging = true;
|
|
32
|
+
this.initLogFile();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private initLogFile() {
|
|
36
|
+
if (!fs.existsSync(this.logFile)) {
|
|
37
|
+
fs.writeFileSync(this.logFile, `# YOGNKY SECURITY LOG\n# Started at: ${new Date().toISOString()}\n\n`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private formatLogEntry(entry: LogEntry): string {
|
|
42
|
+
return `[${entry.timestamp}] [${entry.level}] ${entry.message}${entry.ip ? ` | IP: ${entry.ip}` : ''}${entry.attackType ? ` | Attack: ${entry.attackType}` : ''}`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private async writeToFile(entry: LogEntry) {
|
|
46
|
+
if (!this.enableFileLogging) return;
|
|
47
|
+
|
|
48
|
+
this.logBuffer.push(entry);
|
|
49
|
+
if (this.logBuffer.length >= this.bufferSize) {
|
|
50
|
+
await this.flushLogs();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private async flushLogs() {
|
|
55
|
+
const logsToWrite = this.logBuffer.splice(0, this.bufferSize);
|
|
56
|
+
const logText = logsToWrite.map(entry => this.formatLogEntry(entry)).join('\n') + '\n';
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
fs.appendFileSync(this.logFile, logText);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
console.error('Failed to write log:', error);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
public log(level: LogLevel, message: string, metadata?: any) {
|
|
66
|
+
const entry: LogEntry = {
|
|
67
|
+
timestamp: new Date().toISOString(),
|
|
68
|
+
level,
|
|
69
|
+
message,
|
|
70
|
+
...metadata
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
if (this.enableConsoleLogging) {
|
|
74
|
+
const colors = {
|
|
75
|
+
[LogLevel.INFO]: '\x1b[36m', // Cyan
|
|
76
|
+
[LogLevel.WARNING]: '\x1b[33m', // Yellow
|
|
77
|
+
[LogLevel.ERROR]: '\x1b[31m', // Red
|
|
78
|
+
[LogLevel.ATTACK]: '\x1b[35m', // Magenta
|
|
79
|
+
[LogLevel.DEBUG]: '\x1b[32m' // Green
|
|
80
|
+
};
|
|
81
|
+
const reset = '\x1b[0m';
|
|
82
|
+
console.log(`${colors[level]}${this.formatLogEntry(entry)}${reset}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
this.writeToFile(entry);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public info(message: string, metadata?: any) {
|
|
89
|
+
this.log(LogLevel.INFO, message, metadata);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public warning(message: string, metadata?: any) {
|
|
93
|
+
this.log(LogLevel.WARNING, message, metadata);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public error(message: string, metadata?: any) {
|
|
97
|
+
this.log(LogLevel.ERROR, message, metadata);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public attack(attackType: string, ip: string, details?: any) {
|
|
101
|
+
this.log(LogLevel.ATTACK, `${attackType} detected`, {
|
|
102
|
+
ip,
|
|
103
|
+
attackType,
|
|
104
|
+
details
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public debug(message: string, metadata?: any) {
|
|
109
|
+
if (process.env.NODE_ENV === 'development') {
|
|
110
|
+
this.log(LogLevel.DEBUG, message, metadata);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public async getLogs(level?: LogLevel, limit: number = 100): Promise<LogEntry[]> {
|
|
115
|
+
try {
|
|
116
|
+
const content = fs.readFileSync(this.logFile, 'utf-8');
|
|
117
|
+
const lines = content.split('\n').filter(line => line.trim());
|
|
118
|
+
const logs: LogEntry[] = [];
|
|
119
|
+
|
|
120
|
+
for (const line of lines) {
|
|
121
|
+
if (line.startsWith('#')) continue;
|
|
122
|
+
|
|
123
|
+
const match = line.match(/\[(.*?)\] \[(.*?)\] (.*?)(?: \| IP: (.*?))?(?: \| Attack: (.*?))?/);
|
|
124
|
+
if (match) {
|
|
125
|
+
const [, timestamp, level, message, ip, attackType] = match;
|
|
126
|
+
if (!level || (level && (!level || level === level))) {
|
|
127
|
+
logs.push({ timestamp, level: level as LogLevel, message, ip, attackType });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return logs.slice(-limit);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
this.error('Failed to read logs', error);
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
public async clearLogs() {
|
|
140
|
+
try {
|
|
141
|
+
fs.writeFileSync(this.logFile, `# YOGNKY SECURITY LOG\n# Cleared at: ${new Date().toISOString()}\n\n`);
|
|
142
|
+
this.logBuffer = [];
|
|
143
|
+
this.info('Logs cleared successfully');
|
|
144
|
+
} catch (error) {
|
|
145
|
+
this.error('Failed to clear logs', error);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public async getStatistics() {
|
|
150
|
+
const logs = await this.getLogs();
|
|
151
|
+
const stats = {
|
|
152
|
+
totalAttacks: logs.filter(log => log.level === LogLevel.ATTACK).length,
|
|
153
|
+
totalErrors: logs.filter(log => log.level === LogLevel.ERROR).length,
|
|
154
|
+
topAttackTypes: {} as Record<string, number>,
|
|
155
|
+
topIPs: {} as Record<string, number>,
|
|
156
|
+
timeline: {} as Record<string, number>
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
for (const log of logs) {
|
|
160
|
+
if (log.attackType) {
|
|
161
|
+
stats.topAttackTypes[log.attackType] = (stats.topAttackTypes[log.attackType] || 0) + 1;
|
|
162
|
+
}
|
|
163
|
+
if (log.ip) {
|
|
164
|
+
stats.topIPs[log.ip] = (stats.topIPs[log.ip] || 0) + 1;
|
|
165
|
+
}
|
|
166
|
+
const date = log.timestamp.split('T')[0];
|
|
167
|
+
stats.timeline[date] = (stats.timeline[date] || 0) + 1;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return stats;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export const logger = new Logger();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import request from 'supertest';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import { bruteforceProtection } from '../src/defenses/bruteforce';
|
|
4
|
+
|
|
5
|
+
describe('Anti Brute Force', () => {
|
|
6
|
+
let app: express.Application;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
app = express();
|
|
10
|
+
app.use(express.json());
|
|
11
|
+
app.use(bruteforceProtection);
|
|
12
|
+
app.post('/login', (req, res) => res.json({ message: 'OK' }));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('should allow first 4 attempts', async () => {
|
|
16
|
+
for (let i = 0; i < 4; i++) {
|
|
17
|
+
const response = await request(app)
|
|
18
|
+
.post('/login')
|
|
19
|
+
.send({ username: 'admin', password: 'wrong' });
|
|
20
|
+
expect(response.status).toBe(200);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('should block after 5 attempts', async () => {
|
|
25
|
+
for (let i = 0; i < 5; i++) {
|
|
26
|
+
await request(app).post('/login').send({ username: 'admin', password: 'wrong' });
|
|
27
|
+
}
|
|
28
|
+
const response = await request(app)
|
|
29
|
+
.post('/login')
|
|
30
|
+
.send({ username: 'admin', password: 'wrong' });
|
|
31
|
+
expect(response.status).toBe(429);
|
|
32
|
+
expect(response.body.error).toContain('Brute Force');
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import request from 'supertest';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import { ddosProtection } from '../src/defenses/ddos';
|
|
4
|
+
|
|
5
|
+
describe('Anti DDoS Protection', () => {
|
|
6
|
+
let app: express.Application;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
app = express();
|
|
10
|
+
app.use(ddosProtection({ maxPerMinute: 5, blockDuration: 10 }));
|
|
11
|
+
app.get('/', (req, res) => res.json({ message: 'OK' }));
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('should allow requests under limit', async () => {
|
|
15
|
+
for (let i = 0; i < 5; i++) {
|
|
16
|
+
const response = await request(app).get('/');
|
|
17
|
+
expect(response.status).toBe(200);
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('should block requests over limit', async () => {
|
|
22
|
+
for (let i = 0; i < 6; i++) {
|
|
23
|
+
const response = await request(app).get('/');
|
|
24
|
+
if (i >= 5) {
|
|
25
|
+
expect(response.status).toBe(429);
|
|
26
|
+
expect(response.body.error).toContain('DDoS');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import request from 'supertest';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import ModulesEz from '../src/index';
|
|
4
|
+
|
|
5
|
+
describe('YONGKY SECURITY - Integration Tests', () => {
|
|
6
|
+
let app: express.Application;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
app = express();
|
|
10
|
+
app.use(express.json());
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test('should load all defenses', () => {
|
|
14
|
+
ModulesEz({
|
|
15
|
+
anti_ddos: true,
|
|
16
|
+
anti_sql: true,
|
|
17
|
+
anti_xss: true,
|
|
18
|
+
anti_curl: true,
|
|
19
|
+
anti_header: true,
|
|
20
|
+
anti_bruteforce: true,
|
|
21
|
+
anti_rateLimit: true,
|
|
22
|
+
anti_malware: true
|
|
23
|
+
})(app);
|
|
24
|
+
|
|
25
|
+
expect(app._router.stack.length).toBeGreaterThan(5);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('should block SQL injection', async () => {
|
|
29
|
+
ModulesEz({ anti_sql: true })(app);
|
|
30
|
+
app.get('/test', (req, res) => res.json({ ok: true }));
|
|
31
|
+
|
|
32
|
+
const response = await request(app)
|
|
33
|
+
.get('/test?name=john\' OR \'1\'=\'1');
|
|
34
|
+
expect(response.status).toBe(403);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test('should respect whitelist', async () => {
|
|
38
|
+
ModulesEz({ anti_pengunjung: '127.0.0.1' })(app);
|
|
39
|
+
app.get('/test', (req, res) => res.json({ ok: true }));
|
|
40
|
+
|
|
41
|
+
const response = await request(app).get('/test');
|
|
42
|
+
expect(response.status).toBe(200);
|
|
43
|
+
});
|
|
44
|
+
});
|
package/test/sql.test.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import request from 'supertest';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import { sqlInjectionProtection } from '../src/defenses/sqlInjection';
|
|
4
|
+
|
|
5
|
+
describe('Anti SQL Injection', () => {
|
|
6
|
+
let app: express.Application;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
app = express();
|
|
10
|
+
app.use(express.json());
|
|
11
|
+
app.use(sqlInjectionProtection);
|
|
12
|
+
app.get('/test', (req, res) => res.json({ message: 'OK' }));
|
|
13
|
+
app.post('/test', (req, res) => res.json({ message: 'OK' }));
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('should allow normal requests', async () => {
|
|
17
|
+
const response = await request(app).get('/test?name=john');
|
|
18
|
+
expect(response.status).toBe(200);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('should block SQL injection in query', async () => {
|
|
22
|
+
const response = await request(app).get('/test?name=john\' OR \'1\'=\'1');
|
|
23
|
+
expect(response.status).toBe(403);
|
|
24
|
+
expect(response.body.error).toContain('SQL Injection');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('should block SQL injection in body', async () => {
|
|
28
|
+
const response = await request(app)
|
|
29
|
+
.post('/test')
|
|
30
|
+
.send({ name: "admin' --", password: "anything" });
|
|
31
|
+
expect(response.status).toBe(403);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('should block UNION injection', async () => {
|
|
35
|
+
const response = await request(app)
|
|
36
|
+
.get('/test?id=1 UNION SELECT * FROM users');
|
|
37
|
+
expect(response.status).toBe(403);
|
|
38
|
+
});
|
|
39
|
+
});
|
package/test/xss.test.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import request from 'supertest';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import { xssProtection } from '../src/defenses/xss';
|
|
4
|
+
|
|
5
|
+
describe('Anti XSS Protection', () => {
|
|
6
|
+
let app: express.Application;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
app = express();
|
|
10
|
+
app.use(express.json());
|
|
11
|
+
app.use(xssProtection);
|
|
12
|
+
app.get('/test', (req, res) => res.json({ message: 'OK' }));
|
|
13
|
+
app.post('/test', (req, res) => res.json({ message: 'OK' }));
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('should allow normal input', async () => {
|
|
17
|
+
const response = await request(app).get('/test?name=john');
|
|
18
|
+
expect(response.status).toBe(200);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('should block script tag', async () => {
|
|
22
|
+
const response = await request(app)
|
|
23
|
+
.get('/test?name=<script>alert("xss")</script>');
|
|
24
|
+
expect(response.status).toBe(403);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('should block javascript protocol', async () => {
|
|
28
|
+
const response = await request(app)
|
|
29
|
+
.get('/test?url=javascript:alert(1)');
|
|
30
|
+
expect(response.status).toBe(403);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('should block onerror event', async () => {
|
|
34
|
+
const response = await request(app)
|
|
35
|
+
.post('/test')
|
|
36
|
+
.send({ comment: '<img src=x onerror=alert(1)>' });
|
|
37
|
+
expect(response.status).toBe(403);
|
|
38
|
+
});
|
|
39
|
+
});
|
package/test-module.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const app = express();
|
|
3
|
+
const yognky = require('./dist/index.js').default;
|
|
4
|
+
|
|
5
|
+
console.log('Module loaded:', typeof yognky);
|
|
6
|
+
|
|
7
|
+
yognky({
|
|
8
|
+
anti_ddos: { maxPerMinute: 5, blockDuration: 10 }
|
|
9
|
+
})(app);
|
|
10
|
+
|
|
11
|
+
app.get('/', (req, res) => res.json({ ok: true }));
|
|
12
|
+
|
|
13
|
+
app.listen(3001, () => {
|
|
14
|
+
console.log('Test server di port 3001');
|
|
15
|
+
console.log('Kirim 10 request:');
|
|
16
|
+
|
|
17
|
+
setTimeout(() => {
|
|
18
|
+
for (let i = 1; i <= 10; i++) {
|
|
19
|
+
fetch('http://localhost:3001/')
|
|
20
|
+
.then(res => console.log(`Request ${i}: ${res.status}`));
|
|
21
|
+
}
|
|
22
|
+
}, 1000);
|
|
23
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"sourceMap": false,
|
|
5
|
+
"declarationMap": false,
|
|
6
|
+
"removeComments": true,
|
|
7
|
+
"noEmitOnError": true
|
|
8
|
+
},
|
|
9
|
+
"exclude": [
|
|
10
|
+
"node_modules",
|
|
11
|
+
"dist",
|
|
12
|
+
"tests",
|
|
13
|
+
"examples",
|
|
14
|
+
"**/*.test.ts",
|
|
15
|
+
"**/*.spec.ts"
|
|
16
|
+
]
|
|
17
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"lib": ["ES2020", "DOM"],
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": false,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": false,
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"declarationMap": true,
|
|
14
|
+
"sourceMap": true,
|
|
15
|
+
"moduleResolution": "node",
|
|
16
|
+
"resolveJsonModule": true,
|
|
17
|
+
"allowSyntheticDefaultImports": true,
|
|
18
|
+
"noImplicitAny": false,
|
|
19
|
+
"noUnusedLocals": false,
|
|
20
|
+
"noUnusedParameters": false,
|
|
21
|
+
"removeComments": false,
|
|
22
|
+
"preserveConstEnums": true
|
|
23
|
+
},
|
|
24
|
+
"include": ["src/**/*"],
|
|
25
|
+
"exclude": ["node_modules", "dist", "tests", "examples"]
|
|
26
|
+
}
|