ayiin 2.0.48 → 2.0.50

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.
@@ -0,0 +1,16 @@
1
+ declare class Async {
2
+ /**
3
+ * Sleep for a given number of milliseconds
4
+ * @param {number} ms - milliseconds to sleep
5
+ * @returns {Promise<void>}
6
+ */
7
+ sleep: (ms: number) => Promise<void>;
8
+ /**
9
+ * Retry a function with a given number of retries
10
+ * @param {function} fn - function to retry
11
+ * @param {number} retries - number of retries
12
+ * @returns {Promise<T>}
13
+ */
14
+ retry: <T>(fn: () => Promise<T>, retries?: number) => Promise<T>;
15
+ }
16
+ export default Async;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class Async {
4
+ /**
5
+ * Sleep for a given number of milliseconds
6
+ * @param {number} ms - milliseconds to sleep
7
+ * @returns {Promise<void>}
8
+ */
9
+ sleep = (ms) => {
10
+ return new Promise((resolve) => setTimeout(resolve, ms));
11
+ };
12
+ /**
13
+ * Retry a function with a given number of retries
14
+ * @param {function} fn - function to retry
15
+ * @param {number} retries - number of retries
16
+ * @returns {Promise<T>}
17
+ */
18
+ retry = async (fn, retries = 3) => {
19
+ let error;
20
+ for (let i = 0; i < retries; i++) {
21
+ try {
22
+ return await fn();
23
+ }
24
+ catch (err) {
25
+ error = err;
26
+ }
27
+ }
28
+ throw error;
29
+ };
30
+ }
31
+ exports.default = Async;
@@ -0,0 +1,12 @@
1
+ declare class Currency {
2
+ /**
3
+ * Format money ke string sesuai locale
4
+ * @memberof Random
5
+ * @param {number | string} amount - jumlah uang
6
+ * @param {Intl.LocalesArgument} locales - default "id-ID"
7
+ * @param {Intl.NumberFormatOptions} options - default currency IDR
8
+ * @returns {string} string
9
+ */
10
+ formatMoney: (amount: number | string, locales?: Intl.LocalesArgument, options?: Intl.NumberFormatOptions) => string;
11
+ }
12
+ export default Currency;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class Currency {
4
+ /**
5
+ * Format money ke string sesuai locale
6
+ * @memberof Random
7
+ * @param {number | string} amount - jumlah uang
8
+ * @param {Intl.LocalesArgument} locales - default "id-ID"
9
+ * @param {Intl.NumberFormatOptions} options - default currency IDR
10
+ * @returns {string} string
11
+ */
12
+ formatMoney = (amount, locales = "id-ID", options = {
13
+ style: "currency",
14
+ currency: "IDR",
15
+ minimumFractionDigits: 0,
16
+ }) => {
17
+ return new Intl.NumberFormat(locales, options).format(Number(amount));
18
+ };
19
+ }
20
+ exports.default = Currency;
@@ -0,0 +1,42 @@
1
+ import { DurationInput } from "../types";
2
+ declare class Dates {
3
+ /**
4
+ * Format tanggal ke string sesuai locale
5
+ * @param {Date} date
6
+ * @param {Intl.LocalesArgument} locales - default "id-ID"
7
+ * @returns {string} string
8
+ */
9
+ formatDate: (date: Date, locales?: Intl.LocalesArgument) => string;
10
+ /**
11
+ * Hitung waktu relatif (misalnya "5 menit lalu")
12
+ * @param {Date} date
13
+ * @returns {string} string
14
+ */
15
+ timeAgo: (date: Date) => string;
16
+ /**
17
+ * Tambahkan menit ke tanggal
18
+ * @param {Date} date
19
+ * @param {number} minutes - menit untuk ditambahkan
20
+ * @returns {Date} tanggal baru
21
+ */
22
+ addMinutes: (date: Date, minutes: number) => Date;
23
+ /**
24
+ * Cek apakah tanggal telah berakhir
25
+ * @param {Date} date
26
+ * @returns {boolean} true jika tanggal telah berakhir, false jika belum
27
+ */
28
+ isExpired: (date: Date) => boolean;
29
+ /**
30
+ * Konversi waktu ke milidetik
31
+ * @param {DurationInput} duration
32
+ * @returns {number} milidetik
33
+ */
34
+ toMilliseconds: ({ hours, minutes, seconds, }: DurationInput) => number;
35
+ /**
36
+ * Format waktu sisa ke string
37
+ * @param {number} ms - milisekund
38
+ * @returns {string} string
39
+ */
40
+ formatRemainingTime: (ms: number) => string;
41
+ }
42
+ export default Dates;
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class Dates {
4
+ /**
5
+ * Format tanggal ke string sesuai locale
6
+ * @param {Date} date
7
+ * @param {Intl.LocalesArgument} locales - default "id-ID"
8
+ * @returns {string} string
9
+ */
10
+ formatDate = (date, locales = "id-ID") => new Intl.DateTimeFormat(locales, {
11
+ year: "numeric",
12
+ month: "long",
13
+ day: "numeric",
14
+ hour: "2-digit",
15
+ minute: "2-digit",
16
+ }).format(date);
17
+ /**
18
+ * Hitung waktu relatif (misalnya "5 menit lalu")
19
+ * @param {Date} date
20
+ * @returns {string} string
21
+ */
22
+ timeAgo = (date) => {
23
+ const diff = Date.now() - date.getTime();
24
+ const seconds = Math.floor(diff / 1000);
25
+ if (seconds < 60)
26
+ return `${seconds} detik lalu`;
27
+ const minutes = Math.floor(seconds / 60);
28
+ if (minutes < 60)
29
+ return `${minutes} menit lalu`;
30
+ const hours = Math.floor(minutes / 60);
31
+ if (hours < 24)
32
+ return `${hours} jam lalu`;
33
+ const days = Math.floor(hours / 24);
34
+ return `${days} hari lalu`;
35
+ };
36
+ /**
37
+ * Tambahkan menit ke tanggal
38
+ * @param {Date} date
39
+ * @param {number} minutes - menit untuk ditambahkan
40
+ * @returns {Date} tanggal baru
41
+ */
42
+ addMinutes = (date, minutes) => {
43
+ return new Date(date.getTime() + minutes * 60_000);
44
+ };
45
+ /**
46
+ * Cek apakah tanggal telah berakhir
47
+ * @param {Date} date
48
+ * @returns {boolean} true jika tanggal telah berakhir, false jika belum
49
+ */
50
+ isExpired = (date) => {
51
+ return date.getTime() < Date.now();
52
+ };
53
+ /**
54
+ * Konversi waktu ke milidetik
55
+ * @param {DurationInput} duration
56
+ * @returns {number} milidetik
57
+ */
58
+ toMilliseconds = ({ hours = 0, minutes = 0, seconds = 0, }) => {
59
+ return (hours * 3600 + minutes * 60 + seconds) * 1000;
60
+ };
61
+ /**
62
+ * Format waktu sisa ke string
63
+ * @param {number} ms - milisekund
64
+ * @returns {string} string
65
+ */
66
+ formatRemainingTime = (ms) => {
67
+ if (ms <= 0)
68
+ return "0 detik";
69
+ const totalSeconds = Math.floor(ms / 1000);
70
+ const minutes = Math.floor(totalSeconds / 60);
71
+ const seconds = totalSeconds % 60;
72
+ if (minutes > 0) {
73
+ return `${minutes} menit ${seconds} detik lagi`;
74
+ }
75
+ return `${seconds} detik lagi`;
76
+ };
77
+ }
78
+ exports.default = Dates;
@@ -0,0 +1,15 @@
1
+ declare class Files {
2
+ /**
3
+ * Pastikan direktori ada
4
+ * @param {string} path - path direktori
5
+ * @returns {Promise<void>}
6
+ */
7
+ ensureDir: (path: string) => Promise<void>;
8
+ /**
9
+ * Baca file JSON
10
+ * @param {string} path - path file
11
+ * @returns {Promise<T>} data JSON
12
+ */
13
+ readJSON: <T>(path: string) => Promise<T>;
14
+ }
15
+ export default Files;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const promises_1 = __importDefault(require("fs/promises"));
7
+ class Files {
8
+ /**
9
+ * Pastikan direktori ada
10
+ * @param {string} path - path direktori
11
+ * @returns {Promise<void>}
12
+ */
13
+ ensureDir = async (path) => {
14
+ await promises_1.default.mkdir(path, { recursive: true });
15
+ };
16
+ /**
17
+ * Baca file JSON
18
+ * @param {string} path - path file
19
+ * @returns {Promise<T>} data JSON
20
+ */
21
+ readJSON = async (path) => {
22
+ const data = await promises_1.default.readFile(path, "utf-8");
23
+ return JSON.parse(data);
24
+ };
25
+ }
26
+ exports.default = Files;
@@ -1,9 +1,16 @@
1
+ import Async from "./async";
1
2
  import Crypt from "./crypt";
2
- import { Limiter } from "./limiter";
3
+ import Currency from "./currency";
4
+ import Dates from "./dates";
5
+ import Files from "./files";
6
+ import Limiter from "./limiter";
7
+ import Objects from "./objects";
8
+ import Random from "./random";
3
9
  import ResponseApi from "./response";
4
- import Tools from "./tools";
10
+ import Strings from "./strings";
11
+ import Validation from "./validation";
5
12
  declare class Methods {
6
13
  }
7
- interface Methods extends Crypt, Tools, ResponseApi, Limiter {
14
+ interface Methods extends Async, Crypt, Currency, Dates, Files, Limiter, Objects, Random, ResponseApi, Strings, Validation {
8
15
  }
9
16
  export default Methods;
@@ -3,15 +3,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ const async_1 = __importDefault(require("./async"));
6
7
  const crypt_1 = __importDefault(require("./crypt"));
7
- const limiter_1 = require("./limiter");
8
+ const currency_1 = __importDefault(require("./currency"));
9
+ const dates_1 = __importDefault(require("./dates"));
10
+ const files_1 = __importDefault(require("./files"));
11
+ const limiter_1 = __importDefault(require("./limiter"));
12
+ const objects_1 = __importDefault(require("./objects"));
13
+ const random_1 = __importDefault(require("./random"));
8
14
  const response_1 = __importDefault(require("./response"));
9
- const tools_1 = __importDefault(require("./tools"));
15
+ const strings_1 = __importDefault(require("./strings"));
16
+ const validation_1 = __importDefault(require("./validation"));
10
17
  class Methods {
11
18
  }
12
19
  // copy instance properties
13
- Object.assign(Methods.prototype, new tools_1.default());
20
+ Object.assign(Methods.prototype, new async_1.default());
14
21
  Object.assign(Methods.prototype, new crypt_1.default());
22
+ Object.assign(Methods.prototype, new currency_1.default());
23
+ Object.assign(Methods.prototype, new dates_1.default());
24
+ Object.assign(Methods.prototype, new files_1.default());
25
+ Object.assign(Methods.prototype, new limiter_1.default());
26
+ Object.assign(Methods.prototype, new objects_1.default());
27
+ Object.assign(Methods.prototype, new random_1.default());
15
28
  Object.assign(Methods.prototype, new response_1.default());
16
- Object.assign(Methods.prototype, new limiter_1.Limiter());
29
+ Object.assign(Methods.prototype, new strings_1.default());
30
+ Object.assign(Methods.prototype, new validation_1.default());
17
31
  exports.default = Methods;
@@ -1,6 +1,7 @@
1
1
  import { RequestHandler } from "express";
2
2
  import { RateLimiterOptions } from "../types";
3
- import Tools from "./tools";
4
- export declare class Limiter extends Tools {
3
+ import Dates from "./dates";
4
+ declare class Limiter extends Dates {
5
5
  createRateLimit: (options: RateLimiterOptions) => RequestHandler;
6
6
  }
7
+ export default Limiter;
@@ -3,8 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Limiter = void 0;
7
- const tools_1 = __importDefault(require("./tools"));
6
+ const dates_1 = __importDefault(require("./dates"));
8
7
  // 🔹 MemoryStore default
9
8
  class MemoryStore {
10
9
  store = new Map();
@@ -45,7 +44,7 @@ class MemoryStore {
45
44
  }
46
45
  }
47
46
  // 🔹 Class Limiter
48
- class Limiter extends tools_1.default {
47
+ class Limiter extends dates_1.default {
49
48
  createRateLimit = (options) => {
50
49
  const store = options.store ?? new MemoryStore();
51
50
  if (options.refreshOnStart) {
@@ -81,7 +80,9 @@ class Limiter extends tools_1.default {
81
80
  })
82
81
  : (options.messageFormat ??
83
82
  `[FloodWait] - Silakan coba lagi dalam ${this.formatRemainingTime(remainingMs)}.`);
84
- return res.status(429).json({ success: false, error: msg });
83
+ return res
84
+ .status(429)
85
+ .json({ success: false, error: msg, ms: remainingMs });
85
86
  }
86
87
  }
87
88
  // ambil level sekarang
@@ -136,10 +137,12 @@ class Limiter extends tools_1.default {
136
137
  })
137
138
  : (options.messageFormat ??
138
139
  `[FloodWait] - Terlalu banyak permintaan. Silakan coba lagi dalam ${this.formatRemainingTime(floodwaitMs)}.`);
139
- return res.status(429).json({ success: false, error: msg });
140
+ return res
141
+ .status(429)
142
+ .json({ success: false, error: msg, ms: floodwaitMs });
140
143
  }
141
144
  next();
142
145
  };
143
146
  };
144
147
  }
145
- exports.Limiter = Limiter;
148
+ exports.default = Limiter;
@@ -0,0 +1,15 @@
1
+ declare class Objects {
2
+ /**
3
+ * Deep clone objectek
4
+ * @param {T} obj
5
+ * @returns {T
6
+ */
7
+ deepClone: <T>(obj: T) => T;
8
+ /**
9
+ * Cek apakah objectek kosong
10
+ * @param {object} obj
11
+ * @returns {boolean} true jika objectek kosong, false jika tidak
12
+ */
13
+ isEmptyObject: (obj: object) => boolean;
14
+ }
15
+ export default Objects;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class Objects {
4
+ /**
5
+ * Deep clone objectek
6
+ * @param {T} obj
7
+ * @returns {T
8
+ */
9
+ deepClone = (obj) => {
10
+ return JSON.parse(JSON.stringify(obj));
11
+ };
12
+ /**
13
+ * Cek apakah objectek kosong
14
+ * @param {object} obj
15
+ * @returns {boolean} true jika objectek kosong, false jika tidak
16
+ */
17
+ isEmptyObject = (obj) => {
18
+ return Object.keys(obj).length === 0;
19
+ };
20
+ }
21
+ exports.default = Objects;
@@ -0,0 +1,22 @@
1
+ declare class Random {
2
+ /**
3
+ * Generate UUID v4 sederhana
4
+ * @returns {string}
5
+ */
6
+ randomUuid: () => string;
7
+ /**
8
+ * Pick a random from array
9
+ * @param {T[]} array
10
+ * @memberof Random
11
+ * @returns {T} item acak dari array
12
+ */
13
+ randomItem: <T>(array: T[]) => T | undefined;
14
+ /**
15
+ * Ambil beberapa item acak unik dari array
16
+ * @param {T[]} array
17
+ * @param {number} count - jumlah item
18
+ * @returns {T[]} array item acak unik dari array
19
+ */
20
+ randomMany: <T>(array: T[], count: number | string) => T[];
21
+ }
22
+ export default Random;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class Random {
4
+ /**
5
+ * Generate UUID v4 sederhana
6
+ * @returns {string}
7
+ */
8
+ randomUuid = () => {
9
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
10
+ const r = (Math.random() * 16) | 0;
11
+ const v = c === "x" ? r : (r & 0x3) | 0x8;
12
+ return v.toString(16);
13
+ });
14
+ };
15
+ /**
16
+ * Pick a random from array
17
+ * @param {T[]} array
18
+ * @memberof Random
19
+ * @returns {T} item acak dari array
20
+ */
21
+ randomItem = (array) => {
22
+ return array[Math.floor(Math.random() * array.length)];
23
+ };
24
+ /**
25
+ * Ambil beberapa item acak unik dari array
26
+ * @param {T[]} array
27
+ * @param {number} count - jumlah item
28
+ * @returns {T[]} array item acak unik dari array
29
+ */
30
+ randomMany = (array, count) => {
31
+ const copy = [...array];
32
+ for (let i = copy.length - 1; i > 0; i--) {
33
+ const j = Math.floor(Math.random() * (i + 1));
34
+ [copy[i], copy[j]] = [copy[j], copy[i]];
35
+ }
36
+ return copy.slice(0, Number(count));
37
+ };
38
+ }
39
+ exports.default = Random;
@@ -0,0 +1,27 @@
1
+ declare class Strings {
2
+ /**
3
+ * Generate unique ID dengan pilihan tipe
4
+ * @param {"number"|"string"|"mixed"} type - tipe ID (angka, string, atau campuran)
5
+ * @param {number} length - panjang ID (default 8)
6
+ * @returns {string} ID unik acak
7
+ */
8
+ uniqueId: ({ type, length, prefix, }: {
9
+ type?: "number" | "string" | "mixed";
10
+ length?: number | string;
11
+ prefix?: string;
12
+ }) => string;
13
+ /**
14
+ * Convert string menjadi camelCase
15
+ * @param {string} input - string yang akan diubah
16
+ * @returns {string} camelCase string
17
+ */
18
+ toCamelCase: (input: string) => string;
19
+ /**
20
+ * Capitalize string (huruf pertama jadi kapital)
21
+ * @param {string} input - string yang akan diubah
22
+ * @returns {string} string dengan huruf pertama kapital
23
+ */
24
+ capitalize: (input: string) => string;
25
+ slugify: (str: string) => string;
26
+ }
27
+ export default Strings;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class Strings {
4
+ /**
5
+ * Generate unique ID dengan pilihan tipe
6
+ * @param {"number"|"string"|"mixed"} type - tipe ID (angka, string, atau campuran)
7
+ * @param {number} length - panjang ID (default 8)
8
+ * @returns {string} ID unik acak
9
+ */
10
+ uniqueId = ({ type = "mixed", length = 8, prefix, }) => {
11
+ let chars;
12
+ switch (type) {
13
+ case "number":
14
+ chars = "0123456789";
15
+ break;
16
+ case "string":
17
+ chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
18
+ break;
19
+ default:
20
+ chars =
21
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
22
+ }
23
+ let id = "";
24
+ for (let i = 0; i < Number(length); i++) {
25
+ id += chars[Math.floor(Math.random() * chars.length)];
26
+ }
27
+ return prefix ? prefix + id : id;
28
+ };
29
+ /**
30
+ * Convert string menjadi camelCase
31
+ * @param {string} input - string yang akan diubah
32
+ * @returns {string} camelCase string
33
+ */
34
+ toCamelCase = (input) => {
35
+ return input
36
+ .toLowerCase()
37
+ .replace(/[-_\s]+(.)?/g, (_, chr) => (chr ? chr.toUpperCase() : ""));
38
+ };
39
+ /**
40
+ * Capitalize string (huruf pertama jadi kapital)
41
+ * @param {string} input - string yang akan diubah
42
+ * @returns {string} string dengan huruf pertama kapital
43
+ */
44
+ capitalize = (input) => {
45
+ if (!input)
46
+ return "";
47
+ return input.charAt(0).toUpperCase() + input.slice(1);
48
+ };
49
+ slugify = (str) => {
50
+ return str
51
+ .toLowerCase()
52
+ .replace(/\s+/g, "-")
53
+ .replace(/[^\w-]+/g, "");
54
+ };
55
+ }
56
+ exports.default = Strings;
@@ -0,0 +1,16 @@
1
+ declare class Validation {
2
+ /**
3
+ * Validasi apakah string adalah email
4
+ * @param {string} str
5
+ * @returns {boolean} true jika string adalah email, false jika bukan
6
+ */
7
+ isEmail: (str: string) => boolean;
8
+ /**
9
+ * Validasi apakah string adalah URL
10
+ * @param {string} str
11
+ * @returns {boolean} true jika string adalah URL, false jika bukan
12
+ */
13
+ isUrl: (str: string) => boolean;
14
+ isUUID: (str: string) => boolean;
15
+ }
16
+ export default Validation;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class Validation {
4
+ /**
5
+ * Validasi apakah string adalah email
6
+ * @param {string} str
7
+ * @returns {boolean} true jika string adalah email, false jika bukan
8
+ */
9
+ isEmail = (str) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str);
10
+ /**
11
+ * Validasi apakah string adalah URL
12
+ * @param {string} str
13
+ * @returns {boolean} true jika string adalah URL, false jika bukan
14
+ */
15
+ isUrl = (str) => {
16
+ try {
17
+ new URL(str);
18
+ return true;
19
+ }
20
+ catch {
21
+ return false;
22
+ }
23
+ };
24
+ isUUID = (str) => {
25
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str);
26
+ };
27
+ }
28
+ exports.default = Validation;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ayiin",
3
- "version": "2.0.48",
3
+ "version": "2.0.50",
4
4
  "author": {
5
5
  "name": "AyiinXd",
6
6
  "url": "https://github.com/AyiinXd"
@@ -1,87 +0,0 @@
1
- import { DurationInput } from "../types";
2
- declare class Tools {
3
- /**
4
- * Format money ke string sesuai locale
5
- * @memberof Tools
6
- * @param {number | string} amount - jumlah uang
7
- * @param {Intl.LocalesArgument} locales - default "id-ID"
8
- * @param {Intl.NumberFormatOptions} options - default currency IDR
9
- * @returns {string} string
10
- */
11
- formatMoney: (amount: number | string, locales?: Intl.LocalesArgument, options?: Intl.NumberFormatOptions) => string;
12
- /**
13
- * Generate unique ID dengan pilihan tipe
14
- * @param {"number"|"string"|"mixed"} type - tipe ID (angka, string, atau campuran)
15
- * @param {number} length - panjang ID (default 8)
16
- * @returns {string} ID unik acak
17
- */
18
- uniqueId: ({ type, length, prefix, }: {
19
- type?: "number" | "string" | "mixed";
20
- length?: number | string;
21
- prefix?: string;
22
- }) => string;
23
- /**
24
- * Generate UUID v4 sederhana
25
- * @returns {string}
26
- */
27
- randomUuid: () => string;
28
- /**
29
- * Pick a random from array
30
- * @param {T[]} array
31
- * @memberof Tools
32
- * @returns {T} item acak dari array
33
- */
34
- randomItem: <T>(array: T[]) => T | undefined;
35
- /**
36
- * Ambil beberapa item acak unik dari array
37
- * @param {T[]} array
38
- * @param {number} count - jumlah item
39
- * @returns {T[]} array item acak unik dari array
40
- */
41
- randomMany: <T>(array: T[], count: number | string) => T[];
42
- /**
43
- * Validasi apakah string adalah email
44
- * @param {string} str
45
- * @returns {boolean} true jika string adalah email, false jika bukan
46
- */
47
- isEmail: (str: string) => boolean;
48
- /**
49
- * Validasi apakah string adalah URL
50
- * @param {string} str
51
- * @returns {boolean} true jika string adalah URL, false jika bukan
52
- */
53
- isUrl: (str: string) => boolean;
54
- /**
55
- * Format tanggal ke string sesuai locale
56
- * @param {Date} date
57
- * @param {Intl.LocalesArgument} locales - default "id-ID"
58
- * @returns {string} string
59
- */
60
- formatDate: (date: Date, locales?: Intl.LocalesArgument) => string;
61
- /**
62
- * Hitung waktu relatif (misalnya "5 menit lalu")
63
- * @param {Date} date
64
- * @returns {string} string
65
- */
66
- timeAgo: (date: Date) => string;
67
- /**
68
- * Convert string menjadi camelCase
69
- * @param {string} input - string yang akan diubah
70
- * @returns {string} camelCase string
71
- */
72
- toCamelCase: (input: string) => string;
73
- /**
74
- * Capitalize string (huruf pertama jadi kapital)
75
- * @param {string} input - string yang akan diubah
76
- * @returns {string} string dengan huruf pertama kapital
77
- */
78
- capitalize: (input: string) => string;
79
- slugify: (str: string) => string;
80
- deepClone: <T>(obj: T) => T;
81
- isEmptyObject: (obj: object) => boolean;
82
- sleep: (ms: number) => Promise<void>;
83
- retry: <T>(fn: () => Promise<T>, retries?: number) => Promise<T>;
84
- toMilliseconds: ({ hours, minutes, seconds, }: DurationInput) => number;
85
- formatRemainingTime: (ms: number) => string;
86
- }
87
- export default Tools;
@@ -1,192 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- class Tools {
4
- /**
5
- * Format money ke string sesuai locale
6
- * @memberof Tools
7
- * @param {number | string} amount - jumlah uang
8
- * @param {Intl.LocalesArgument} locales - default "id-ID"
9
- * @param {Intl.NumberFormatOptions} options - default currency IDR
10
- * @returns {string} string
11
- */
12
- formatMoney = (amount, locales = "id-ID", options = {
13
- style: "currency",
14
- currency: "IDR",
15
- minimumFractionDigits: 0,
16
- }) => {
17
- return new Intl.NumberFormat(locales, options).format(Number(amount));
18
- };
19
- /**
20
- * Generate unique ID dengan pilihan tipe
21
- * @param {"number"|"string"|"mixed"} type - tipe ID (angka, string, atau campuran)
22
- * @param {number} length - panjang ID (default 8)
23
- * @returns {string} ID unik acak
24
- */
25
- uniqueId = ({ type = "mixed", length = 8, prefix, }) => {
26
- let chars;
27
- switch (type) {
28
- case "number":
29
- chars = "0123456789";
30
- break;
31
- case "string":
32
- chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
33
- break;
34
- default:
35
- chars =
36
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
37
- }
38
- let id = "";
39
- for (let i = 0; i < Number(length); i++) {
40
- id += chars[Math.floor(Math.random() * chars.length)];
41
- }
42
- return prefix ? prefix + id : id;
43
- };
44
- /**
45
- * Generate UUID v4 sederhana
46
- * @returns {string}
47
- */
48
- randomUuid = () => {
49
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
50
- const r = (Math.random() * 16) | 0;
51
- const v = c === "x" ? r : (r & 0x3) | 0x8;
52
- return v.toString(16);
53
- });
54
- };
55
- /**
56
- * Pick a random from array
57
- * @param {T[]} array
58
- * @memberof Tools
59
- * @returns {T} item acak dari array
60
- */
61
- randomItem = (array) => {
62
- return array[Math.floor(Math.random() * array.length)];
63
- };
64
- /**
65
- * Ambil beberapa item acak unik dari array
66
- * @param {T[]} array
67
- * @param {number} count - jumlah item
68
- * @returns {T[]} array item acak unik dari array
69
- */
70
- randomMany = (array, count) => {
71
- const copy = [...array];
72
- for (let i = copy.length - 1; i > 0; i--) {
73
- const j = Math.floor(Math.random() * (i + 1));
74
- [copy[i], copy[j]] = [copy[j], copy[i]];
75
- }
76
- return copy.slice(0, Number(count));
77
- };
78
- /**
79
- * Validasi apakah string adalah email
80
- * @param {string} str
81
- * @returns {boolean} true jika string adalah email, false jika bukan
82
- */
83
- isEmail = (str) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str);
84
- /**
85
- * Validasi apakah string adalah URL
86
- * @param {string} str
87
- * @returns {boolean} true jika string adalah URL, false jika bukan
88
- */
89
- isUrl = (str) => {
90
- try {
91
- new URL(str);
92
- return true;
93
- }
94
- catch {
95
- return false;
96
- }
97
- };
98
- /**
99
- * Format tanggal ke string sesuai locale
100
- * @param {Date} date
101
- * @param {Intl.LocalesArgument} locales - default "id-ID"
102
- * @returns {string} string
103
- */
104
- formatDate = (date, locales = "id-ID") => new Intl.DateTimeFormat(locales, {
105
- year: "numeric",
106
- month: "long",
107
- day: "numeric",
108
- hour: "2-digit",
109
- minute: "2-digit",
110
- }).format(date);
111
- /**
112
- * Hitung waktu relatif (misalnya "5 menit lalu")
113
- * @param {Date} date
114
- * @returns {string} string
115
- */
116
- timeAgo = (date) => {
117
- const diff = Date.now() - date.getTime();
118
- const seconds = Math.floor(diff / 1000);
119
- if (seconds < 60)
120
- return `${seconds} detik lalu`;
121
- const minutes = Math.floor(seconds / 60);
122
- if (minutes < 60)
123
- return `${minutes} menit lalu`;
124
- const hours = Math.floor(minutes / 60);
125
- if (hours < 24)
126
- return `${hours} jam lalu`;
127
- const days = Math.floor(hours / 24);
128
- return `${days} hari lalu`;
129
- };
130
- /**
131
- * Convert string menjadi camelCase
132
- * @param {string} input - string yang akan diubah
133
- * @returns {string} camelCase string
134
- */
135
- toCamelCase = (input) => {
136
- return input
137
- .toLowerCase()
138
- .replace(/[-_\s]+(.)?/g, (_, chr) => (chr ? chr.toUpperCase() : ""));
139
- };
140
- /**
141
- * Capitalize string (huruf pertama jadi kapital)
142
- * @param {string} input - string yang akan diubah
143
- * @returns {string} string dengan huruf pertama kapital
144
- */
145
- capitalize = (input) => {
146
- if (!input)
147
- return "";
148
- return input.charAt(0).toUpperCase() + input.slice(1);
149
- };
150
- slugify = (str) => {
151
- return str
152
- .toLowerCase()
153
- .replace(/\s+/g, "-")
154
- .replace(/[^\w-]+/g, "");
155
- };
156
- deepClone = (obj) => {
157
- return JSON.parse(JSON.stringify(obj));
158
- };
159
- isEmptyObject = (obj) => {
160
- return Object.keys(obj).length === 0;
161
- };
162
- sleep = (ms) => {
163
- return new Promise((resolve) => setTimeout(resolve, ms));
164
- };
165
- retry = async (fn, retries = 3) => {
166
- let error;
167
- for (let i = 0; i < retries; i++) {
168
- try {
169
- return await fn();
170
- }
171
- catch (err) {
172
- error = err;
173
- }
174
- }
175
- throw error;
176
- };
177
- toMilliseconds = ({ hours = 0, minutes = 0, seconds = 0, }) => {
178
- return (hours * 3600 + minutes * 60 + seconds) * 1000;
179
- };
180
- formatRemainingTime = (ms) => {
181
- if (ms <= 0)
182
- return "0 detik";
183
- const totalSeconds = Math.floor(ms / 1000);
184
- const minutes = Math.floor(totalSeconds / 60);
185
- const seconds = totalSeconds % 60;
186
- if (minutes > 0) {
187
- return `${minutes} menit ${seconds} detik lagi`;
188
- }
189
- return `${seconds} detik lagi`;
190
- };
191
- }
192
- exports.default = Tools;