@onurege3467/zerohelper 7.1.0 → 8.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/README.md +762 -0
- package/database/IDatabase.js +18 -0
- package/database/cacheWrapper.js +526 -62
- package/database/index.js +9 -2
- package/database/json.js +59 -0
- package/database/migration.js +227 -0
- package/database/mongodb.js +45 -0
- package/database/mysql.js +61 -0
- package/database/pg.js +64 -0
- package/database/redis.js +342 -0
- package/database/sqlite.js +69 -0
- package/functions/index.js +267 -0
- package/package.json +11 -7
- package/.snapshots/config.json +0 -151
- package/.snapshots/readme.md +0 -11
- package/.snapshots/sponsors.md +0 -44
- package/1.json +0 -15
- package/readme.md +0 -418
- package/test.js +0 -261
- package/test_mysqlonly.js +0 -144
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
// redis.js - Redis Database Adapter (v4.x Uyumlu)
|
|
2
|
+
const { createClient } = require('redis');
|
|
3
|
+
|
|
4
|
+
class RedisDatabase {
|
|
5
|
+
constructor(config = {}) {
|
|
6
|
+
this.config = {
|
|
7
|
+
host: config.host || '127.0.0.1',
|
|
8
|
+
port: config.port || 6379,
|
|
9
|
+
password: config.password,
|
|
10
|
+
db: config.db || 0,
|
|
11
|
+
connectTimeout: config.connectTimeout || 5000,
|
|
12
|
+
commandTimeout: config.commandTimeout || 5000,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
this.keyPrefix = config.keyPrefix || 'app:';
|
|
16
|
+
this.client = null;
|
|
17
|
+
this.isConnecting = false; // Eşzamanlı bağlantı girişimlerini önlemek için
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async connect() {
|
|
21
|
+
if (this.client && this.client.isReady) {
|
|
22
|
+
return this.client;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Eğer zaten bağlantı girişimi yapılıyorsa, bekle
|
|
26
|
+
if (this.isConnecting) {
|
|
27
|
+
while (this.isConnecting) {
|
|
28
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
29
|
+
}
|
|
30
|
+
return this.client;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
this.isConnecting = true;
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
this.client = createClient({
|
|
37
|
+
socket: {
|
|
38
|
+
host: this.config.host,
|
|
39
|
+
port: this.config.port,
|
|
40
|
+
connectTimeout: this.config.connectTimeout,
|
|
41
|
+
},
|
|
42
|
+
password: this.config.password,
|
|
43
|
+
database: this.config.db,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
this.client.on('error', (err) => {
|
|
47
|
+
console.error('Redis Error:', err.message);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
//this.client.on('connect', () => console.log('Redis Connected'));
|
|
51
|
+
//this.client.on('ready', () => console.log('Redis Ready'));
|
|
52
|
+
this.client.on('end', () => {
|
|
53
|
+
console.log('Redis Connection Ended');
|
|
54
|
+
this.client = null;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Timeout ile bağlantı kontrolü
|
|
58
|
+
await Promise.race([
|
|
59
|
+
this.client.connect(),
|
|
60
|
+
new Promise((_, reject) =>
|
|
61
|
+
setTimeout(() => reject(new Error('Redis connection timeout')), this.config.connectTimeout)
|
|
62
|
+
),
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
console.log('Redis bağlantısı başarılı');
|
|
66
|
+
} catch (err) {
|
|
67
|
+
this.client = null;
|
|
68
|
+
throw new Error(`Redis bağlantısı başarısız: ${err.message}`);
|
|
69
|
+
} finally {
|
|
70
|
+
this.isConnecting = false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return this.client;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
_getKey(table, id) {
|
|
77
|
+
return `${this.keyPrefix}${table}:${id}`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
_getTableKey(table) {
|
|
81
|
+
return `${this.keyPrefix}${table}:*`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async select(table, where = {}) {
|
|
85
|
+
try {
|
|
86
|
+
const client = await this.connect();
|
|
87
|
+
const pattern = this._getTableKey(table);
|
|
88
|
+
const keys = await client.keys(pattern);
|
|
89
|
+
|
|
90
|
+
if (!keys.length) return [];
|
|
91
|
+
|
|
92
|
+
const values = await client.mGet(keys);
|
|
93
|
+
return values
|
|
94
|
+
.map(v => {
|
|
95
|
+
try {
|
|
96
|
+
return v ? JSON.parse(v) : null;
|
|
97
|
+
} catch (parseErr) {
|
|
98
|
+
console.error('JSON parse error:', parseErr);
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
.filter(Boolean)
|
|
103
|
+
.filter(item => Object.entries(where).every(([k, val]) => item[k] === val));
|
|
104
|
+
} catch (err) {
|
|
105
|
+
console.error('Select error:', err);
|
|
106
|
+
throw err;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
async selectOne(table, where = {}) {
|
|
111
|
+
const results = await this.select(table, where);
|
|
112
|
+
return results.length ? results[0] : null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async insert(table, data) {
|
|
116
|
+
try {
|
|
117
|
+
const client = await this.connect();
|
|
118
|
+
const insertData = { ...data };
|
|
119
|
+
|
|
120
|
+
if (!insertData.id) {
|
|
121
|
+
insertData.id = Date.now().toString() + Math.random().toString(36).slice(2, 9);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const key = this._getKey(table, insertData.id);
|
|
125
|
+
await client.set(key, JSON.stringify(insertData));
|
|
126
|
+
return insertData;
|
|
127
|
+
} catch (err) {
|
|
128
|
+
console.error('Insert error:', err);
|
|
129
|
+
throw err;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async update(table, data, where) {
|
|
134
|
+
try {
|
|
135
|
+
const existing = await this.select(table, where);
|
|
136
|
+
if (!existing.length) return [];
|
|
137
|
+
|
|
138
|
+
const client = await this.connect();
|
|
139
|
+
const updated = [];
|
|
140
|
+
|
|
141
|
+
for (const item of existing) {
|
|
142
|
+
const merged = { ...item, ...data };
|
|
143
|
+
await client.set(this._getKey(table, item.id), JSON.stringify(merged));
|
|
144
|
+
updated.push(merged);
|
|
145
|
+
}
|
|
146
|
+
return updated;
|
|
147
|
+
} catch (err) {
|
|
148
|
+
console.error('Update error:', err);
|
|
149
|
+
throw err;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async updateOne(table, data, where) {
|
|
154
|
+
const results = await this.update(table, data, where);
|
|
155
|
+
return results.length ? results[0] : null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async set(table, data, where) {
|
|
159
|
+
try {
|
|
160
|
+
const existing = await this.selectOne(table, where);
|
|
161
|
+
if (existing) {
|
|
162
|
+
return await this.updateOne(table, data, where);
|
|
163
|
+
} else {
|
|
164
|
+
return await this.insert(table, { ...data, ...where });
|
|
165
|
+
}
|
|
166
|
+
} catch (err) {
|
|
167
|
+
console.error('Set error:', err);
|
|
168
|
+
throw err;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async delete(table, where) {
|
|
173
|
+
try {
|
|
174
|
+
const existing = await this.select(table, where);
|
|
175
|
+
if (!existing.length) return [];
|
|
176
|
+
|
|
177
|
+
const client = await this.connect();
|
|
178
|
+
const keys = existing.map(item => this._getKey(table, item.id));
|
|
179
|
+
await client.del(keys);
|
|
180
|
+
return existing;
|
|
181
|
+
} catch (err) {
|
|
182
|
+
console.error('Delete error:', err);
|
|
183
|
+
throw err;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async deleteOne(table, where) {
|
|
188
|
+
const results = await this.delete(table, where);
|
|
189
|
+
return results.length ? results[0] : null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async bulkInsert(table, dataArray) {
|
|
193
|
+
if (!Array.isArray(dataArray) || !dataArray.length) {
|
|
194
|
+
return [];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
const results = [];
|
|
199
|
+
for (const data of dataArray) {
|
|
200
|
+
results.push(await this.insert(table, data));
|
|
201
|
+
}
|
|
202
|
+
return results;
|
|
203
|
+
} catch (err) {
|
|
204
|
+
console.error('Bulk insert error:', err);
|
|
205
|
+
throw err;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async ensureTable(table) {
|
|
210
|
+
// Redis'te tablo kavramı yoktur, her zaman true döner
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async close() {
|
|
215
|
+
if (this.client) {
|
|
216
|
+
try {
|
|
217
|
+
await this.client.quit();
|
|
218
|
+
} catch (err) {
|
|
219
|
+
console.error('Redis close error:', err);
|
|
220
|
+
} finally {
|
|
221
|
+
this.client = null;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async ping() {
|
|
227
|
+
try {
|
|
228
|
+
const client = await this.connect();
|
|
229
|
+
return await client.ping();
|
|
230
|
+
} catch (err) {
|
|
231
|
+
console.error('Ping error:', err);
|
|
232
|
+
throw err;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async flushTable(table) {
|
|
237
|
+
try {
|
|
238
|
+
const client = await this.connect();
|
|
239
|
+
const pattern = this._getTableKey(table);
|
|
240
|
+
const keys = await client.keys(pattern);
|
|
241
|
+
|
|
242
|
+
if (keys.length > 0) {
|
|
243
|
+
await client.del(keys);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return keys.length;
|
|
247
|
+
} catch (err) {
|
|
248
|
+
console.error('Flush table error:', err);
|
|
249
|
+
throw err;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Yardımcı metodlar
|
|
254
|
+
async getStats(table) {
|
|
255
|
+
try {
|
|
256
|
+
const client = await this.connect();
|
|
257
|
+
const pattern = this._getTableKey(table);
|
|
258
|
+
const keys = await client.keys(pattern);
|
|
259
|
+
return {
|
|
260
|
+
table,
|
|
261
|
+
keyCount: keys.length,
|
|
262
|
+
pattern
|
|
263
|
+
};
|
|
264
|
+
} catch (err) {
|
|
265
|
+
console.error('Get stats error:', err);
|
|
266
|
+
throw err;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async exists(table, where) {
|
|
271
|
+
const result = await this.selectOne(table, where);
|
|
272
|
+
return result !== null;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Numerik alanları artırır (increment).
|
|
277
|
+
* Redis için hash field'ları üzerinde HINCRBY kullanır.
|
|
278
|
+
* @param {string} table - Verinin güncelleneceği tablo adı.
|
|
279
|
+
* @param {object} increments - Artırılacak alanlar ve miktarları.
|
|
280
|
+
* @param {object} where - Güncelleme koşulları.
|
|
281
|
+
* @returns {Promise<number>} Etkilenen kayıt sayısı.
|
|
282
|
+
*/
|
|
283
|
+
async increment(table, increments, where = {}) {
|
|
284
|
+
try {
|
|
285
|
+
const client = await this.connect();
|
|
286
|
+
|
|
287
|
+
// Önce mevcut kayıtları bul
|
|
288
|
+
const existingRecords = await this.select(table, where);
|
|
289
|
+
let affectedCount = 0;
|
|
290
|
+
|
|
291
|
+
for (const record of existingRecords) {
|
|
292
|
+
const key = this._getRecordKey(table, record._id);
|
|
293
|
+
|
|
294
|
+
// Her increment field için HINCRBY kullan
|
|
295
|
+
for (const [field, value] of Object.entries(increments)) {
|
|
296
|
+
await client.hIncrBy(key, field, value);
|
|
297
|
+
}
|
|
298
|
+
affectedCount++;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return affectedCount;
|
|
302
|
+
} catch (err) {
|
|
303
|
+
console.error('Increment error:', err);
|
|
304
|
+
throw err;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Numerik alanları azaltır (decrement).
|
|
310
|
+
* Redis için hash field'ları üzerinde HINCRBY ile negatif değer kullanır.
|
|
311
|
+
* @param {string} table - Verinin güncelleneceği tablo adı.
|
|
312
|
+
* @param {object} decrements - Azaltılacak alanlar ve miktarları.
|
|
313
|
+
* @param {object} where - Güncelleme koşulları.
|
|
314
|
+
* @returns {Promise<number>} Etkilenen kayıt sayısı.
|
|
315
|
+
*/
|
|
316
|
+
async decrement(table, decrements, where = {}) {
|
|
317
|
+
try {
|
|
318
|
+
const client = await this.connect();
|
|
319
|
+
|
|
320
|
+
// Önce mevcut kayıtları bul
|
|
321
|
+
const existingRecords = await this.select(table, where);
|
|
322
|
+
let affectedCount = 0;
|
|
323
|
+
|
|
324
|
+
for (const record of existingRecords) {
|
|
325
|
+
const key = this._getRecordKey(table, record._id);
|
|
326
|
+
|
|
327
|
+
// Her decrement field için HINCRBY ile negatif değer kullan
|
|
328
|
+
for (const [field, value] of Object.entries(decrements)) {
|
|
329
|
+
await client.hIncrBy(key, field, -value);
|
|
330
|
+
}
|
|
331
|
+
affectedCount++;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return affectedCount;
|
|
335
|
+
} catch (err) {
|
|
336
|
+
console.error('Decrement error:', err);
|
|
337
|
+
throw err;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
module.exports = RedisDatabase;
|
package/database/sqlite.js
CHANGED
|
@@ -466,6 +466,75 @@ class SQLiteDatabase extends IDatabase{
|
|
|
466
466
|
});
|
|
467
467
|
}
|
|
468
468
|
|
|
469
|
+
/**
|
|
470
|
+
* WHERE clause oluşturur
|
|
471
|
+
* @param {object} where - WHERE koşulları
|
|
472
|
+
* @returns {object} - whereClause string ve values array
|
|
473
|
+
*/
|
|
474
|
+
buildWhereClause(where = {}) {
|
|
475
|
+
const conditions = Object.keys(where);
|
|
476
|
+
if (conditions.length === 0) {
|
|
477
|
+
return { whereClause: '', values: [] };
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
const whereClause = ' WHERE ' + conditions.map(key => `${key} = ?`).join(' AND ');
|
|
481
|
+
const values = Object.values(where);
|
|
482
|
+
|
|
483
|
+
return { whereClause, values };
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Numerik alanları artırır (increment).
|
|
488
|
+
* @param {string} table - Verinin güncelleneceği tablo adı.
|
|
489
|
+
* @param {object} increments - Artırılacak alanlar ve miktarları.
|
|
490
|
+
* @param {object} where - Güncelleme koşulları.
|
|
491
|
+
* @returns {Promise<number>} Etkilenen kayıt sayısı.
|
|
492
|
+
*/
|
|
493
|
+
async increment(table, increments, where = {}) {
|
|
494
|
+
const incrementClauses = Object.keys(increments).map(field =>
|
|
495
|
+
`${field} = ${field} + ?`
|
|
496
|
+
).join(', ');
|
|
497
|
+
|
|
498
|
+
const incrementValues = Object.values(increments);
|
|
499
|
+
const { whereClause, values: whereValues } = this.buildWhereClause(where);
|
|
500
|
+
|
|
501
|
+
const sql = `UPDATE ${table} SET ${incrementClauses}${whereClause}`;
|
|
502
|
+
const allValues = [...incrementValues, ...whereValues];
|
|
503
|
+
|
|
504
|
+
return new Promise((resolve, reject) => {
|
|
505
|
+
this.db.run(sql, allValues, function(err) {
|
|
506
|
+
if (err) reject(err);
|
|
507
|
+
else resolve(this.changes);
|
|
508
|
+
});
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Numerik alanları azaltır (decrement).
|
|
514
|
+
* @param {string} table - Verinin güncelleneceği tablo adı.
|
|
515
|
+
* @param {object} decrements - Azaltılacak alanlar ve miktarları.
|
|
516
|
+
* @param {object} where - Güncelleme koşulları.
|
|
517
|
+
* @returns {Promise<number>} Etkilenen kayıt sayısı.
|
|
518
|
+
*/
|
|
519
|
+
async decrement(table, decrements, where = {}) {
|
|
520
|
+
const decrementClauses = Object.keys(decrements).map(field =>
|
|
521
|
+
`${field} = ${field} - ?`
|
|
522
|
+
).join(', ');
|
|
523
|
+
|
|
524
|
+
const decrementValues = Object.values(decrements);
|
|
525
|
+
const { whereClause, values: whereValues } = this.buildWhereClause(where);
|
|
526
|
+
|
|
527
|
+
const sql = `UPDATE ${table} SET ${decrementClauses}${whereClause}`;
|
|
528
|
+
const allValues = [...decrementValues, ...whereValues];
|
|
529
|
+
|
|
530
|
+
return new Promise((resolve, reject) => {
|
|
531
|
+
this.db.run(sql, allValues, function(err) {
|
|
532
|
+
if (err) reject(err);
|
|
533
|
+
else resolve(this.changes);
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
|
|
469
538
|
/**
|
|
470
539
|
* Veritabanı bağlantısını kapatır.
|
|
471
540
|
*/
|
package/functions/index.js
CHANGED
|
@@ -372,6 +372,256 @@ function generateSlug(text) {
|
|
|
372
372
|
function wordCount(text) {
|
|
373
373
|
return text.trim().split(/\s+/).length;
|
|
374
374
|
}
|
|
375
|
+
|
|
376
|
+
// Validasyon İşlemleri
|
|
377
|
+
function isEmail(email) {
|
|
378
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
379
|
+
return emailRegex.test(email);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function isPhone(phone) {
|
|
383
|
+
const phoneRegex = /^[\+]?[1-9][\d]{0,15}$/;
|
|
384
|
+
return phoneRegex.test(phone.replace(/[\s\-\(\)]/g, ''));
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function isURL(url) {
|
|
388
|
+
try {
|
|
389
|
+
new URL(url);
|
|
390
|
+
return true;
|
|
391
|
+
} catch {
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function sanitizeHTML(html) {
|
|
397
|
+
return html
|
|
398
|
+
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
|
|
399
|
+
.replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi, '')
|
|
400
|
+
.replace(/javascript:/gi, '')
|
|
401
|
+
.replace(/on\w+\s*=/gi, '');
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function validateCreditCard(cardNumber) {
|
|
405
|
+
// Luhn algoritması
|
|
406
|
+
const cleanNumber = cardNumber.replace(/\D/g, '');
|
|
407
|
+
if (cleanNumber.length < 13 || cleanNumber.length > 19) return false;
|
|
408
|
+
|
|
409
|
+
let sum = 0;
|
|
410
|
+
let isEven = false;
|
|
411
|
+
|
|
412
|
+
for (let i = cleanNumber.length - 1; i >= 0; i--) {
|
|
413
|
+
let digit = parseInt(cleanNumber[i]);
|
|
414
|
+
|
|
415
|
+
if (isEven) {
|
|
416
|
+
digit *= 2;
|
|
417
|
+
if (digit > 9) digit -= 9;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
sum += digit;
|
|
421
|
+
isEven = !isEven;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return sum % 10 === 0;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function validateSchema(data, schema) {
|
|
428
|
+
const errors = [];
|
|
429
|
+
|
|
430
|
+
for (const [key, rules] of Object.entries(schema)) {
|
|
431
|
+
const value = data[key];
|
|
432
|
+
|
|
433
|
+
if (rules.required && (value === undefined || value === null || value === '')) {
|
|
434
|
+
errors.push(`${key} alanı zorunludur`);
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (value !== undefined && value !== null) {
|
|
439
|
+
if (rules.type && typeof value !== rules.type) {
|
|
440
|
+
errors.push(`${key} alanı ${rules.type} tipinde olmalıdır`);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (rules.minLength && value.length < rules.minLength) {
|
|
444
|
+
errors.push(`${key} en az ${rules.minLength} karakter olmalıdır`);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (rules.maxLength && value.length > rules.maxLength) {
|
|
448
|
+
errors.push(`${key} en fazla ${rules.maxLength} karakter olmalıdır`);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (rules.pattern && !rules.pattern.test(value)) {
|
|
452
|
+
errors.push(`${key} geçerli formatta değil`);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (rules.min && value < rules.min) {
|
|
456
|
+
errors.push(`${key} en az ${rules.min} olmalıdır`);
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
if (rules.max && value > rules.max) {
|
|
460
|
+
errors.push(`${key} en fazla ${rules.max} olmalıdır`);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
return {
|
|
466
|
+
isValid: errors.length === 0,
|
|
467
|
+
errors
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function sanitizeInput(input, options = {}) {
|
|
472
|
+
if (typeof input !== 'string') return input;
|
|
473
|
+
|
|
474
|
+
let sanitized = input;
|
|
475
|
+
|
|
476
|
+
if (options.trim !== false) {
|
|
477
|
+
sanitized = sanitized.trim();
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (options.removeHTML) {
|
|
481
|
+
sanitized = sanitizeHTML(sanitized);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
if (options.escape) {
|
|
485
|
+
sanitized = sanitized
|
|
486
|
+
.replace(/&/g, '&')
|
|
487
|
+
.replace(/</g, '<')
|
|
488
|
+
.replace(/>/g, '>')
|
|
489
|
+
.replace(/"/g, '"')
|
|
490
|
+
.replace(/'/g, ''');
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return sanitized;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Logger İşlemleri
|
|
497
|
+
class Logger {
|
|
498
|
+
constructor(options = {}) {
|
|
499
|
+
this.level = options.level || 'info';
|
|
500
|
+
this.enableColors = options.enableColors !== false;
|
|
501
|
+
this.enableTimestamp = options.enableTimestamp !== false;
|
|
502
|
+
this.logFile = options.logFile || null;
|
|
503
|
+
this.levels = {
|
|
504
|
+
error: 0,
|
|
505
|
+
warn: 1,
|
|
506
|
+
info: 2,
|
|
507
|
+
debug: 3
|
|
508
|
+
};
|
|
509
|
+
this.colors = {
|
|
510
|
+
error: '\x1b[31m', // Red
|
|
511
|
+
warn: '\x1b[33m', // Yellow
|
|
512
|
+
info: '\x1b[36m', // Cyan
|
|
513
|
+
debug: '\x1b[35m', // Magenta
|
|
514
|
+
reset: '\x1b[0m'
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
shouldLog(level) {
|
|
519
|
+
return this.levels[level] <= this.levels[this.level];
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
formatMessage(level, message, data) {
|
|
523
|
+
let formatted = '';
|
|
524
|
+
|
|
525
|
+
if (this.enableTimestamp) {
|
|
526
|
+
formatted += `[${new Date().toISOString()}] `;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (this.enableColors) {
|
|
530
|
+
formatted += `${this.colors[level]}[${level.toUpperCase()}]${this.colors.reset} `;
|
|
531
|
+
} else {
|
|
532
|
+
formatted += `[${level.toUpperCase()}] `;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
formatted += message;
|
|
536
|
+
|
|
537
|
+
if (data !== undefined) {
|
|
538
|
+
formatted += ' ' + (typeof data === 'object' ? JSON.stringify(data, null, 2) : data);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
return formatted;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
writeToFile(message) {
|
|
545
|
+
if (this.logFile) {
|
|
546
|
+
const fs = require('fs');
|
|
547
|
+
const timestamp = new Date().toISOString();
|
|
548
|
+
const logEntry = `${timestamp} ${message}\n`;
|
|
549
|
+
|
|
550
|
+
try {
|
|
551
|
+
fs.appendFileSync(this.logFile, logEntry);
|
|
552
|
+
} catch (error) {
|
|
553
|
+
console.error('Log dosyasına yazılamadı:', error.message);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
log(level, message, data) {
|
|
559
|
+
if (!this.shouldLog(level)) return;
|
|
560
|
+
|
|
561
|
+
const formatted = this.formatMessage(level, message, data);
|
|
562
|
+
|
|
563
|
+
if (level === 'error') {
|
|
564
|
+
console.error(formatted);
|
|
565
|
+
} else if (level === 'warn') {
|
|
566
|
+
console.warn(formatted);
|
|
567
|
+
} else {
|
|
568
|
+
console.log(formatted);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
this.writeToFile(formatted);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
error(message, data) {
|
|
575
|
+
this.log('error', message, data);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
warn(message, data) {
|
|
579
|
+
this.log('warn', message, data);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
info(message, data) {
|
|
583
|
+
this.log('info', message, data);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
debug(message, data) {
|
|
587
|
+
this.log('debug', message, data);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
setLevel(level) {
|
|
591
|
+
if (this.levels.hasOwnProperty(level)) {
|
|
592
|
+
this.level = level;
|
|
593
|
+
} else {
|
|
594
|
+
throw new Error(`Geçersiz log seviyesi: ${level}`);
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
getLevel() {
|
|
599
|
+
return this.level;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function createLogger(options = {}) {
|
|
604
|
+
return new Logger(options);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Varsayılan logger instance
|
|
608
|
+
const defaultLogger = new Logger();
|
|
609
|
+
|
|
610
|
+
function logInfo(message, data) {
|
|
611
|
+
defaultLogger.info(message, data);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
function logError(message, data) {
|
|
615
|
+
defaultLogger.error(message, data);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
function logWarn(message, data) {
|
|
619
|
+
defaultLogger.warn(message, data);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
function logDebug(message, data) {
|
|
623
|
+
defaultLogger.debug(message, data);
|
|
624
|
+
}
|
|
375
625
|
// Exportlar
|
|
376
626
|
module.exports = {
|
|
377
627
|
http: {
|
|
@@ -435,4 +685,21 @@ module.exports = {
|
|
|
435
685
|
combination,
|
|
436
686
|
permutation,
|
|
437
687
|
},
|
|
688
|
+
validation: {
|
|
689
|
+
isEmail,
|
|
690
|
+
isPhone,
|
|
691
|
+
isURL,
|
|
692
|
+
sanitizeHTML,
|
|
693
|
+
validateCreditCard,
|
|
694
|
+
validateSchema,
|
|
695
|
+
sanitizeInput,
|
|
696
|
+
},
|
|
697
|
+
logger: {
|
|
698
|
+
createLogger,
|
|
699
|
+
Logger,
|
|
700
|
+
info: logInfo,
|
|
701
|
+
error: logError,
|
|
702
|
+
warn: logWarn,
|
|
703
|
+
debug: logDebug,
|
|
704
|
+
},
|
|
438
705
|
};
|