@onurege3467/zerohelper 9.0.0 → 9.2.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.
Files changed (45) hide show
  1. package/README.md +152 -254
  2. package/dist/bin/zero.d.ts +2 -0
  3. package/dist/bin/zero.js +141 -0
  4. package/dist/database/IDatabase.d.ts +25 -31
  5. package/dist/database/IDatabase.js +38 -0
  6. package/dist/database/cacheWrapper.d.ts +5 -2
  7. package/dist/database/cacheWrapper.js +36 -50
  8. package/dist/database/index.d.ts +3 -2
  9. package/dist/database/index.js +13 -9
  10. package/dist/database/json.d.ts +4 -4
  11. package/dist/database/json.js +85 -87
  12. package/dist/database/mongodb.d.ts +12 -12
  13. package/dist/database/mongodb.js +49 -82
  14. package/dist/database/mysql.d.ts +7 -9
  15. package/dist/database/mysql.js +149 -270
  16. package/dist/database/pg.d.ts +12 -14
  17. package/dist/database/pg.js +113 -222
  18. package/dist/database/redis.d.ts +5 -3
  19. package/dist/database/redis.js +81 -107
  20. package/dist/database/seeder.d.ts +20 -0
  21. package/dist/database/seeder.js +37 -0
  22. package/dist/database/sqlite.d.ts +12 -15
  23. package/dist/database/sqlite.js +108 -223
  24. package/dist/database/telemetry.d.ts +35 -0
  25. package/dist/database/telemetry.js +41 -0
  26. package/dist/database/toon.d.ts +32 -0
  27. package/dist/database/toon.js +209 -0
  28. package/dist/database/types.d.ts +28 -34
  29. package/dist/database/zpack.d.ts +10 -4
  30. package/dist/database/zpack.js +151 -71
  31. package/dist/functions/index.d.ts +16 -0
  32. package/dist/functions/index.js +49 -3
  33. package/dist/functions/security.d.ts +15 -0
  34. package/dist/functions/security.js +46 -0
  35. package/dist/functions/toon.d.ts +7 -0
  36. package/dist/functions/toon.js +118 -0
  37. package/dist/functions/worker.d.ts +5 -0
  38. package/dist/functions/worker.js +35 -0
  39. package/dist/test_v91_advanced.d.ts +1 -0
  40. package/dist/test_v91_advanced.js +48 -0
  41. package/dist/test_v91_basics.d.ts +1 -0
  42. package/dist/test_v91_basics.js +54 -0
  43. package/dist/test_v91_performance.d.ts +1 -0
  44. package/dist/test_v91_performance.js +54 -0
  45. package/package.json +16 -3
@@ -7,6 +7,7 @@ exports.ZPackAdapter = exports.ZPackDatabase = void 0;
7
7
  const IDatabase_1 = require("./IDatabase");
8
8
  const fs_1 = __importDefault(require("fs"));
9
9
  const fsp = fs_1.default.promises;
10
+ const zlib_1 = __importDefault(require("zlib"));
10
11
  class ZPackDatabase {
11
12
  constructor(filePath, options = {}) {
12
13
  this.fd = null;
@@ -22,6 +23,7 @@ class ZPackDatabase {
22
23
  throw new Error("ZPackDatabase: 'filePath' zorunludur.");
23
24
  this.filePath = filePath;
24
25
  this._autoFlush = options.autoFlush === true;
26
+ this._compression = options.compression === true;
25
27
  }
26
28
  async open() {
27
29
  if (this.fd)
@@ -56,6 +58,26 @@ class ZPackDatabase {
56
58
  await this.fd.close();
57
59
  this._closed = true;
58
60
  }
61
+ async vacuum() {
62
+ this._ensureOpen();
63
+ return this._enqueue(async () => {
64
+ const tempPath = this.filePath + ".tmp";
65
+ const tempDb = new ZPackDatabase(tempPath, { autoFlush: false, compression: this._compression });
66
+ await tempDb.open();
67
+ for (const docId of this.index.keys()) {
68
+ const doc = await this.get(docId);
69
+ if (doc)
70
+ await tempDb.insert(doc, docId);
71
+ }
72
+ await tempDb.close();
73
+ await this.fd.close();
74
+ await fsp.rename(tempPath, this.filePath);
75
+ this.fd = null;
76
+ this.index.clear();
77
+ this.deleted.clear();
78
+ await this.open();
79
+ });
80
+ }
59
81
  async insert(document, docId) {
60
82
  this._ensureOpen();
61
83
  const payload = this._encodeDocument(document, docId);
@@ -111,7 +133,7 @@ class ZPackDatabase {
111
133
  }
112
134
  else {
113
135
  this.index.set(meta.docId, cur);
114
- this.deleted.delete(meta.docId);
136
+ this.deleted.add(meta.docId); // Bugfix: added to deleted, should be removed
115
137
  if (meta.docId >= this._nextId)
116
138
  this._nextId = meta.docId + 1;
117
139
  }
@@ -126,8 +148,6 @@ class ZPackDatabase {
126
148
  });
127
149
  }
128
150
  async delete(docId) {
129
- if (!Number.isInteger(docId) || docId <= 0)
130
- throw new Error("delete: 'docId' pozitif bir tamsayı olmalıdır.");
131
151
  const tomb = this._encodeTombstone(docId);
132
152
  await this._enqueue(async () => {
133
153
  const writeOffset = this.fileSize;
@@ -146,21 +166,16 @@ class ZPackDatabase {
146
166
  if (offset === undefined)
147
167
  return null;
148
168
  const header = Buffer.alloc(6);
149
- if (offset + BigInt(header.length) > this._contentEnd)
150
- return null;
151
169
  const { bytesRead: hread } = await this.fd.read(header, 0, header.length, offset);
152
170
  if (hread !== header.length)
153
171
  return null;
154
172
  const docLength = header.readUInt16LE(0);
155
173
  const totalSize = 2 + docLength;
156
- if (docLength < 4 || offset + BigInt(totalSize) > this._contentEnd)
157
- return null;
158
174
  const buf = Buffer.alloc(totalSize);
159
175
  const { bytesRead } = await this.fd.read(buf, 0, totalSize, offset);
160
176
  if (bytesRead !== totalSize)
161
177
  return null;
162
- const parsed = this._decodeDocument(buf);
163
- return parsed.fieldCount === 0 ? null : parsed.document;
178
+ return this._decodeDocument(buf).document;
164
179
  }
165
180
  keys() { return Array.from(this.index.keys()); }
166
181
  _ensureOpen() {
@@ -200,6 +215,15 @@ class ZPackDatabase {
200
215
  }
201
216
  _encodeDocument(document, docId) {
202
217
  let id = docId ?? this._nextId++;
218
+ if (this._compression) {
219
+ const dataStr = JSON.stringify(document);
220
+ const compressed = zlib_1.default.deflateSync(dataStr);
221
+ const buf = Buffer.alloc(6 + compressed.length);
222
+ buf.writeUInt16LE(4 + compressed.length, 0);
223
+ buf.writeUInt32LE(id, 2);
224
+ compressed.copy(buf, 6);
225
+ return buf;
226
+ }
203
227
  const fieldBuffers = [];
204
228
  for (const [key, value] of Object.entries(document)) {
205
229
  const keyBuf = Buffer.from(String(key), "utf8");
@@ -222,46 +246,35 @@ class ZPackDatabase {
222
246
  }
223
247
  return buf;
224
248
  }
225
- _encodeTombstone(docId) {
226
- const buf = Buffer.alloc(6);
227
- buf.writeUInt16LE(4, 0);
228
- buf.writeUInt32LE(docId, 2);
229
- return buf;
230
- }
231
- _peekDocMeta(encodedBuf) {
232
- const payloadSize = encodedBuf.readUInt16LE(0);
233
- const docId = encodedBuf.readUInt32LE(2);
234
- const fieldBytes = payloadSize - 4;
235
- let p = 6, consumed = 0, fields = 0;
236
- while (consumed < fieldBytes) {
237
- const klen = encodedBuf.readUInt8(p);
238
- p += 1 + klen;
239
- consumed += 1 + klen;
240
- if (consumed >= fieldBytes)
241
- break;
242
- const vlen = encodedBuf.readUInt8(p);
243
- p += 1 + vlen;
244
- consumed += 1 + vlen;
245
- fields += 1;
246
- }
247
- return { docId, fieldCount: fields };
248
- }
249
249
  _decodeDocument(buf) {
250
250
  const payloadSize = buf.readUInt16LE(0);
251
251
  const docId = buf.readUInt32LE(2);
252
+ if (this._compression && payloadSize > 4) {
253
+ try {
254
+ const decompressed = zlib_1.default.inflateSync(buf.subarray(6));
255
+ return { docId, fieldCount: 1, document: JSON.parse(decompressed.toString()) };
256
+ }
257
+ catch (e) { }
258
+ }
252
259
  let p = 6;
253
260
  const end = 2 + payloadSize;
254
261
  const obj = {};
255
262
  let fields = 0;
256
263
  while (p < end) {
264
+ if (p + 1 > end)
265
+ break;
257
266
  const klen = buf.readUInt8(p);
258
267
  p += 1;
268
+ if (p + klen > end)
269
+ break;
259
270
  const key = buf.toString("utf8", p, p + klen);
260
271
  p += klen;
261
- if (p >= end)
272
+ if (p + 1 > end)
262
273
  break;
263
274
  const vlen = buf.readUInt8(p);
264
275
  p += 1;
276
+ if (p + vlen > end)
277
+ break;
265
278
  const val = buf.toString("utf8", p, p + vlen);
266
279
  p += vlen;
267
280
  obj[key] = val;
@@ -269,6 +282,17 @@ class ZPackDatabase {
269
282
  }
270
283
  return { docId, fieldCount: fields, document: obj };
271
284
  }
285
+ _encodeTombstone(docId) {
286
+ const buf = Buffer.alloc(6);
287
+ buf.writeUInt16LE(4, 0);
288
+ buf.writeUInt32LE(docId, 2);
289
+ return buf;
290
+ }
291
+ _peekDocMeta(encodedBuf) {
292
+ const payloadSize = encodedBuf.readUInt16LE(0);
293
+ const docId = encodedBuf.readUInt32LE(2);
294
+ return { docId, fieldCount: payloadSize > 4 ? 1 : 0 };
295
+ }
272
296
  async _tryLoadIndexFromFooter() {
273
297
  if (this.fileSize < 13n)
274
298
  return false;
@@ -326,7 +350,13 @@ class ZPackAdapter extends IDatabase_1.IDatabase {
326
350
  this.keyIndex = new Map();
327
351
  this.rowCache = new Map();
328
352
  this.secondary = new Map();
329
- this.db = new ZPackDatabase(config.filePath, { autoFlush: !!config.autoFlush });
353
+ this.indexedFields = new Map();
354
+ this.db = new ZPackDatabase(config.path, { autoFlush: !!config.autoFlush, compression: !!config.cache });
355
+ if (config.indexFields) {
356
+ for (const [table, fields] of Object.entries(config.indexFields)) {
357
+ this.indexedFields.set(table, new Set(fields));
358
+ }
359
+ }
330
360
  this.initPromise = this._init();
331
361
  }
332
362
  async _init() {
@@ -336,19 +366,14 @@ class ZPackAdapter extends IDatabase_1.IDatabase {
336
366
  if (!doc || !doc.t || !Number.isFinite(Number(doc._id)))
337
367
  continue;
338
368
  const table = String(doc.t), idNum = Number(doc._id);
339
- if (!this.keyIndex.has(table)) {
340
- this.keyIndex.set(table, new Map());
341
- this.tableMaxId.set(table, 0);
342
- this.rowCache.set(table, new Map());
343
- this.secondary.set(table, new Map());
344
- }
369
+ await this.ensureTable(table);
345
370
  this.keyIndex.get(table).set(idNum, physicalDocId);
346
371
  if (idNum > (this.tableMaxId.get(table) || 0))
347
372
  this.tableMaxId.set(table, idNum);
373
+ this._updateSecondaryIndex(table, idNum, doc);
348
374
  }
349
375
  }
350
376
  async ensureTable(table) {
351
- await this.initPromise;
352
377
  if (!this.tableMaxId.has(table)) {
353
378
  this.tableMaxId.set(table, 0);
354
379
  this.keyIndex.set(table, new Map());
@@ -356,6 +381,25 @@ class ZPackAdapter extends IDatabase_1.IDatabase {
356
381
  this.secondary.set(table, new Map());
357
382
  }
358
383
  }
384
+ _updateSecondaryIndex(table, logicalId, data, oldData = null) {
385
+ const fields = this.indexedFields.get(table);
386
+ if (!fields)
387
+ return;
388
+ const tableIndex = this.secondary.get(table);
389
+ for (const field of fields) {
390
+ if (!tableIndex.has(field))
391
+ tableIndex.set(field, new Map());
392
+ const fieldMap = tableIndex.get(field);
393
+ if (oldData && oldData[field] !== undefined)
394
+ fieldMap.get(String(oldData[field]))?.delete(logicalId);
395
+ if (data[field] !== undefined) {
396
+ const newVal = String(data[field]);
397
+ if (!fieldMap.has(newVal))
398
+ fieldMap.set(newVal, new Set());
399
+ fieldMap.get(newVal).add(logicalId);
400
+ }
401
+ }
402
+ }
359
403
  _coerce(table, data, id) {
360
404
  const out = { t: table, _id: String(id) };
361
405
  for (const [k, v] of Object.entries(data || {})) {
@@ -370,7 +414,30 @@ class ZPackAdapter extends IDatabase_1.IDatabase {
370
414
  return Object.entries(where).every(([k, v]) => String(row[k]) === String(v));
371
415
  }
372
416
  async select(table, where = null) {
417
+ const start = Date.now();
418
+ await this.initPromise;
373
419
  await this.ensureTable(table);
420
+ if (where && Object.keys(where).length === 1) {
421
+ const [field, value] = Object.entries(where)[0];
422
+ const index = this.secondary.get(table)?.get(field);
423
+ if (index) {
424
+ const matches = index.get(String(value));
425
+ if (matches) {
426
+ const results = [];
427
+ for (const logicalId of matches) {
428
+ const physicalId = this.keyIndex.get(table).get(logicalId);
429
+ if (physicalId !== undefined) {
430
+ const doc = await this.db.get(physicalId);
431
+ if (doc)
432
+ results.push(doc);
433
+ }
434
+ }
435
+ this.recordMetric('select', table, Date.now() - start);
436
+ return results;
437
+ }
438
+ return [];
439
+ }
440
+ }
374
441
  const results = [];
375
442
  for (const [logicalId, physicalId] of this.keyIndex.get(table).entries()) {
376
443
  let row = this.rowCache.get(table).get(logicalId);
@@ -378,15 +445,13 @@ class ZPackAdapter extends IDatabase_1.IDatabase {
378
445
  const doc = await this.db.get(physicalId);
379
446
  if (!doc)
380
447
  continue;
381
- row = { _id: Number(doc._id) };
382
- for (const [k, v] of Object.entries(doc))
383
- if (k !== 't' && k !== '_id')
384
- row[k] = v;
448
+ row = doc;
385
449
  this.rowCache.get(table).set(logicalId, row);
386
450
  }
387
451
  if (this._matches(row, where))
388
452
  results.push({ ...row });
389
453
  }
454
+ this.recordMetric('select', table, Date.now() - start);
390
455
  return results;
391
456
  }
392
457
  async selectOne(table, where = null) {
@@ -394,68 +459,83 @@ class ZPackAdapter extends IDatabase_1.IDatabase {
394
459
  return res[0] || null;
395
460
  }
396
461
  async insert(table, data) {
462
+ const start = Date.now();
463
+ await this.initPromise;
397
464
  await this.ensureTable(table);
465
+ await this.runHooks('beforeInsert', table, data);
398
466
  const nextId = (this.tableMaxId.get(table) || 0) + 1;
399
467
  const record = this._coerce(table, data, nextId);
400
468
  const physicalId = await this.db.insert(record);
401
469
  this.tableMaxId.set(table, nextId);
402
470
  this.keyIndex.get(table).set(nextId, physicalId);
403
- const row = { _id: nextId, ...data };
404
- this.rowCache.get(table).set(nextId, row);
471
+ const fullRow = { _id: nextId, ...data };
472
+ this.rowCache.get(table).set(nextId, fullRow);
473
+ this._updateSecondaryIndex(table, nextId, fullRow);
474
+ await this.runHooks('afterInsert', table, fullRow);
475
+ this.recordMetric('insert', table, Date.now() - start);
405
476
  return nextId;
406
477
  }
407
478
  async update(table, data, where) {
479
+ const start = Date.now();
408
480
  const rows = await this.select(table, where);
409
481
  for (const row of rows) {
482
+ const logicalId = row._id;
483
+ await this.runHooks('beforeUpdate', table, { old: row, new: data });
410
484
  const merged = { ...row, ...data };
411
- const record = this._coerce(table, merged, row._id);
485
+ const record = this._coerce(table, merged, logicalId);
412
486
  const physicalId = await this.db.insert(record);
413
- this.keyIndex.get(table).set(row._id, physicalId);
414
- this.rowCache.get(table).set(row._id, merged);
487
+ this.keyIndex.get(table).set(logicalId, physicalId);
488
+ this.rowCache.get(table).set(logicalId, merged);
489
+ this._updateSecondaryIndex(table, logicalId, merged, row);
490
+ await this.runHooks('afterUpdate', table, merged);
415
491
  }
492
+ this.recordMetric('update', table, Date.now() - start);
416
493
  return rows.length;
417
494
  }
418
- async set(table, data, where) {
419
- const existing = await this.selectOne(table, where);
420
- return existing ? this.update(table, data, where) : this.insert(table, { ...where, ...data });
421
- }
422
495
  async delete(table, where) {
496
+ const start = Date.now();
423
497
  const rows = await this.select(table, where);
424
498
  for (const row of rows) {
425
- const physicalId = this.keyIndex.get(table).get(row._id);
499
+ const logicalId = row._id;
500
+ await this.runHooks('beforeDelete', table, row);
501
+ const physicalId = this.keyIndex.get(table).get(logicalId);
426
502
  if (physicalId !== undefined) {
427
503
  await this.db.delete(physicalId);
428
- this.keyIndex.get(table).delete(row._id);
429
- this.rowCache.get(table).delete(row._id);
504
+ this.keyIndex.get(table).delete(logicalId);
505
+ this.rowCache.get(table).delete(logicalId);
506
+ this._updateSecondaryIndex(table, logicalId, {}, row);
430
507
  }
508
+ await this.runHooks('afterDelete', table, row);
431
509
  }
510
+ this.recordMetric('delete', table, Date.now() - start);
432
511
  return rows.length;
433
512
  }
513
+ async set(table, data, where) {
514
+ const ex = await this.selectOne(table, where);
515
+ return ex ? this.update(table, data, where) : this.insert(table, { ...where, ...data });
516
+ }
434
517
  async bulkInsert(table, dataArray) {
435
- for (const data of dataArray)
436
- await this.insert(table, data);
518
+ for (const d of dataArray)
519
+ await this.insert(table, d);
437
520
  return dataArray.length;
438
521
  }
439
- async increment(table, increments, where = {}) {
522
+ async increment(table, incs, where = {}) {
440
523
  const rows = await this.select(table, where);
441
524
  for (const row of rows) {
442
525
  const updated = { ...row };
443
- for (const [f, v] of Object.entries(increments))
526
+ for (const [f, v] of Object.entries(incs))
444
527
  updated[f] = (Number(updated[f]) || 0) + v;
445
528
  await this.update(table, updated, { _id: row._id });
446
529
  }
447
530
  return rows.length;
448
531
  }
449
- async decrement(table, decrements, where = {}) {
450
- const rows = await this.select(table, where);
451
- for (const row of rows) {
452
- const updated = { ...row };
453
- for (const [f, v] of Object.entries(decrements))
454
- updated[f] = (Number(updated[f]) || 0) - v;
455
- await this.update(table, updated, { _id: row._id });
456
- }
457
- return rows.length;
532
+ async decrement(table, decs, where = {}) {
533
+ const incs = {};
534
+ for (const k in decs)
535
+ incs[k] = -decs[k];
536
+ return this.increment(table, incs, where);
458
537
  }
538
+ async vacuum() { await this.db.vacuum(); }
459
539
  async close() { await this.db.close(); }
460
540
  }
461
541
  exports.ZPackAdapter = ZPackAdapter;
@@ -1,3 +1,5 @@
1
+ import * as security from './security';
2
+ import * as toon from './toon';
1
3
  export declare function makeUniqueId(): string;
2
4
  export declare function randomArray<T>(arr: T[]): T;
3
5
  export declare function randomText(length?: number): string;
@@ -181,3 +183,17 @@ export declare const logger_module: {
181
183
  warn: typeof logWarn;
182
184
  debug: typeof logDebug;
183
185
  };
186
+ export declare const security_module: {
187
+ checkRateLimit(key: string, options: security.RateLimiterOptions): Promise<{
188
+ allowed: boolean;
189
+ remaining: number;
190
+ reset: number;
191
+ }>;
192
+ };
193
+ export declare const worker_module: {
194
+ runAsyncTask<T>(taskFn: string, data: any): Promise<T>;
195
+ };
196
+ export declare const toon_module: {
197
+ stringify: typeof toon.stringify;
198
+ parse: typeof toon.parse;
199
+ };
@@ -1,9 +1,42 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
5
38
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.logger_module = exports.validation_module = exports.math_module = exports.crypto_module = exports.object_module = exports.array_module = exports.string_module = exports.random_module = exports.date_module = exports.http_module = exports.Logger = void 0;
39
+ exports.toon_module = exports.worker_module = exports.security_module = exports.logger_module = exports.validation_module = exports.math_module = exports.crypto_module = exports.object_module = exports.array_module = exports.string_module = exports.random_module = exports.date_module = exports.http_module = exports.Logger = void 0;
7
40
  exports.makeUniqueId = makeUniqueId;
8
41
  exports.randomArray = randomArray;
9
42
  exports.randomText = randomText;
@@ -68,6 +101,9 @@ const bcrypt_1 = __importDefault(require("bcrypt"));
68
101
  const https_1 = __importDefault(require("https"));
69
102
  const http_1 = __importDefault(require("http"));
70
103
  const url_1 = require("url");
104
+ const security = __importStar(require("./security"));
105
+ const worker = __importStar(require("./worker"));
106
+ const toon = __importStar(require("./toon"));
71
107
  // Random İşlemler
72
108
  function makeUniqueId() {
73
109
  return Date.now().toString(36) + Math.random().toString(36).substr(2);
@@ -373,8 +409,8 @@ function isEmail(email) {
373
409
  return emailRegex.test(email);
374
410
  }
375
411
  function isPhone(phone) {
376
- const phoneRegex = /^[\+]?[1-9][\d]{0,15}$/;
377
- return phoneRegex.test(phone.replace(/[\s\-\(\)]/g, ''));
412
+ const phoneRegex = /^[\\+]?[1-9][\\d]{0,15}$/;
413
+ return phoneRegex.test(phone.replace(/[\\s\-\(\)]/g, ''));
378
414
  }
379
415
  function isURL(url) {
380
416
  try {
@@ -634,3 +670,13 @@ exports.logger_module = {
634
670
  warn: logWarn,
635
671
  debug: logDebug,
636
672
  };
673
+ exports.security_module = {
674
+ ...security
675
+ };
676
+ exports.worker_module = {
677
+ ...worker
678
+ };
679
+ exports.toon_module = {
680
+ stringify: toon.stringify,
681
+ parse: toon.parse
682
+ };
@@ -0,0 +1,15 @@
1
+ export interface RateLimiterOptions {
2
+ limit: number;
3
+ window: number;
4
+ storage?: 'memory' | 'redis';
5
+ redisClient?: any;
6
+ }
7
+ /**
8
+ * Advanced Rate Limiter for API protection.
9
+ * Returns true if allowed, false if rate limited.
10
+ */
11
+ export declare function checkRateLimit(key: string, options: RateLimiterOptions): Promise<{
12
+ allowed: boolean;
13
+ remaining: number;
14
+ reset: number;
15
+ }>;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkRateLimit = checkRateLimit;
4
+ const localStore = new Map();
5
+ /**
6
+ * Advanced Rate Limiter for API protection.
7
+ * Returns true if allowed, false if rate limited.
8
+ */
9
+ async function checkRateLimit(key, options) {
10
+ const { limit, window, storage = 'memory', redisClient } = options;
11
+ const now = Date.now();
12
+ if (storage === 'redis' && redisClient) {
13
+ const redisKey = `rate_limit:${key}`;
14
+ const multi = redisClient.multi();
15
+ multi.incr(redisKey);
16
+ multi.ttl(redisKey);
17
+ const [count, ttl] = await multi.exec();
18
+ if (count === 1) {
19
+ await redisClient.expire(redisKey, window);
20
+ }
21
+ const isAllowed = count <= limit;
22
+ return {
23
+ allowed: isAllowed,
24
+ remaining: Math.max(0, limit - Number(count)),
25
+ reset: ttl > 0 ? now + (ttl * 1000) : now + (window * 1000)
26
+ };
27
+ }
28
+ else {
29
+ // Memory Storage
30
+ let data = localStore.get(key);
31
+ if (!data || now > data.resetTime) {
32
+ data = {
33
+ count: 0,
34
+ resetTime: now + (window * 1000)
35
+ };
36
+ }
37
+ data.count++;
38
+ localStore.set(key, data);
39
+ const isAllowed = data.count <= limit;
40
+ return {
41
+ allowed: isAllowed,
42
+ remaining: Math.max(0, limit - data.count),
43
+ reset: data.resetTime
44
+ };
45
+ }
46
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * TOON (Token-Oriented Object Notation) Support for ZeroHelper
3
+ * Optimized for LLM token efficiency and now supports Native Storage.
4
+ * API matches standard JSON object (stringify/parse).
5
+ */
6
+ export declare function stringify(data: any, indent?: number): string;
7
+ export declare function parse(toonStr: string): any;
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ /**
3
+ * TOON (Token-Oriented Object Notation) Support for ZeroHelper
4
+ * Optimized for LLM token efficiency and now supports Native Storage.
5
+ * API matches standard JSON object (stringify/parse).
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.stringify = stringify;
9
+ exports.parse = parse;
10
+ function stringify(data, indent = 0) {
11
+ const space = ' '.repeat(indent);
12
+ if (data === null)
13
+ return 'null';
14
+ if (typeof data === 'boolean' || typeof data === 'number')
15
+ return String(data);
16
+ if (typeof data === 'string') {
17
+ const hasSpecial = new RegExp('[\,\n:]').test(data);
18
+ if (hasSpecial)
19
+ return '"' + data.replace(/"/g, '\\"') + '"';
20
+ return data;
21
+ }
22
+ if (Array.isArray(data)) {
23
+ if (data.length === 0)
24
+ return '[]';
25
+ const first = data[0];
26
+ if (typeof first === 'object' && first !== null && !Array.isArray(first)) {
27
+ const keys = Object.keys(first);
28
+ const isUniform = data.every(item => item && typeof item === 'object' &&
29
+ Object.keys(item).length === keys.length &&
30
+ Object.keys(item).every(k => keys.includes(k)));
31
+ if (isUniform && data.length > 1) {
32
+ const header = '[' + data.length + ']{' + keys.join(',') + '}:';
33
+ const rows = data.map(item => {
34
+ const rowValues = keys.map(k => {
35
+ const val = item[k];
36
+ if (val === null)
37
+ return 'null';
38
+ const valStr = String(val);
39
+ const hasSpecialRow = new RegExp('[\,\n:]').test(valStr);
40
+ return (typeof val === 'string' && hasSpecialRow) ? '"' + valStr + '"' : valStr;
41
+ }).join(',');
42
+ return space + ' ' + rowValues;
43
+ });
44
+ return header + '\n' + rows.join('\n');
45
+ }
46
+ }
47
+ return '[' + data.length + ']: ' + data.map(v => stringify(v)).join(',');
48
+ }
49
+ if (typeof data === 'object') {
50
+ const entries = Object.entries(data);
51
+ if (entries.length === 0)
52
+ return '{}';
53
+ return entries.map(([key, value]) => {
54
+ const valStr = stringify(value, indent + 2);
55
+ const isComplex = typeof value === 'object' && value !== null && !Array.isArray(value);
56
+ const separator = isComplex ? '\n' : ' ';
57
+ return space + key + ':' + separator + valStr;
58
+ }).join('\n');
59
+ }
60
+ return '';
61
+ }
62
+ function parse(toonStr) {
63
+ if (!toonStr || toonStr.trim() === '')
64
+ return {};
65
+ const lines = toonStr.split('\n').filter(l => l.trim() !== '');
66
+ const result = {};
67
+ let i = 0;
68
+ while (i < lines.length) {
69
+ const line = lines[i].trim();
70
+ const tabularMatch = line.match(/^(\w+)\[(\d+)\]\{(.*)\}:$/);
71
+ if (tabularMatch) {
72
+ const tableName = tabularMatch[1];
73
+ const rowCount = parseInt(tabularMatch[2]);
74
+ const fields = tabularMatch[3].split(',');
75
+ const rows = [];
76
+ for (let j = 0; j < rowCount; j++) {
77
+ i++;
78
+ if (!lines[i])
79
+ break;
80
+ const values = lines[i].trim().split(',').map(v => {
81
+ const trimmed = v.trim();
82
+ if (trimmed === 'true')
83
+ return true;
84
+ if (trimmed === 'false')
85
+ return false;
86
+ if (trimmed === 'null')
87
+ return null;
88
+ if (!isNaN(Number(trimmed)) && trimmed !== '')
89
+ return Number(trimmed);
90
+ return trimmed.replace(/^"|"$/g, '');
91
+ });
92
+ const row = {};
93
+ fields.forEach((f, idx) => row[f] = values[idx]);
94
+ rows.push(row);
95
+ }
96
+ result[tableName] = rows;
97
+ }
98
+ else {
99
+ const kvMatch = line.match(/^(\w+):\s*(.*)$/);
100
+ if (kvMatch) {
101
+ const key = kvMatch[1];
102
+ const value = kvMatch[2];
103
+ let parsedVal = value.trim();
104
+ if (parsedVal === 'true')
105
+ parsedVal = true;
106
+ else if (parsedVal === 'false')
107
+ parsedVal = false;
108
+ else if (parsedVal === 'null')
109
+ parsedVal = null;
110
+ else if (!isNaN(Number(parsedVal)) && parsedVal !== '')
111
+ parsedVal = Number(parsedVal);
112
+ result[key] = parsedVal;
113
+ }
114
+ }
115
+ i++;
116
+ }
117
+ return result;
118
+ }