@koloseum/utils 0.2.28 → 0.3.1

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,131 @@
1
+ import type { IdentityType, PronounsItem, Sex, SocialMediaPlatform, SocialMediaPlatformObject } from "@koloseum/types/public-auth";
2
+ import type { MobilePhoneLocale } from "validator";
3
+ export declare const Transform: {
4
+ /**
5
+ * Capitalises a given word.
6
+ * @param {string} word - The word to be capitalised
7
+ * @returns The capitalised word
8
+ */
9
+ capitalise: (word: string) => string;
10
+ /**
11
+ * Cleans a URL by removing the protocol and trailing slashes.
12
+ * @param {string} url - The URL to clean
13
+ * @returns {string} The cleaned URL
14
+ */
15
+ cleanUrl: (url: string) => string;
16
+ /**
17
+ * Formats a date in the format DD/MM/YYYY (by default) or YYYY-MM-DD (for client).
18
+ * @param {string} date - Date to be formatted
19
+ * @param {boolean} forClient - Specify whether the data is for displaying on the client; defaults to `false`
20
+ * @returns The formatted date string, or `null` if invalid input or in case of an error
21
+ */
22
+ formatDate: (date: string, forClient?: boolean) => string | null;
23
+ /**
24
+ * Formats a social media platform for display.
25
+ * @param {SocialMediaPlatform} platform - The social media platform to be formatted
26
+ * @returns The formatted social media platform string
27
+ */
28
+ formatSocialMediaPlatform: (platform: SocialMediaPlatform) => string;
29
+ /**
30
+ * Returns an age in years given a birth date.
31
+ * @param {Date | string | number | null} dateOfBirth - The date of birth
32
+ * @returns The age in years, or `NaN` if the input is invalid
33
+ */
34
+ getAge: (dateOfBirth: Date | string | number | null) => number;
35
+ /**
36
+ * Formats a date as a locale-specific string.
37
+ * @param {Date | string | number | null} date - Date to be formatted
38
+ * @param {boolean} withTime - Specify whether the date should include time; defaults to `false`
39
+ * @param {string} timeZone - The time zone to use for formatting; defaults to `Africa/Nairobi`
40
+ * @returns The formatted date string, or an empty string if invalid input
41
+ */
42
+ getDateString: (date: Date | string | number | null, withTime?: boolean, timeZone?: string) => string;
43
+ /**
44
+ * Formats an identity type for display.
45
+ * @param {IdentityType} identityType - The identity type to be formatted
46
+ * @returns The formatted identity type string
47
+ */
48
+ getIdentityTypeString: (identityType: IdentityType) => string;
49
+ /**
50
+ * Formats a date to an ISO string in Kenyan time, i.e. `Africa/Nairobi` (UTC+3).
51
+ * @param {Date | string | number | null} date - The date to format
52
+ * @returns {string} The formatted date in ISO string format, or an empty string if invalid input
53
+ */
54
+ getKenyanISOString: (date: Date | string | number | null) => string;
55
+ /**
56
+ * Returns a pronoun given pronouns and a type.
57
+ * @param {PronounsItem | null} pronouns - The pronouns to be formatted
58
+ * @param {"subject" | "object" | "possessive" | "reflexive"} type - The type of pronoun to be returned
59
+ * @param {Sex} sex - The user's sex; defaults to `undefined`
60
+ * @returns The formatted pronoun, or `null` if the input is invalid
61
+ */
62
+ getPronoun: (pronouns: PronounsItem | null, type: "subject" | "object" | "possessive" | "reflexive", sex?: Sex) => string | null;
63
+ /**
64
+ * Paginates an array.
65
+ * @template T - The type of array items; defaults to `any`
66
+ * @param {T[]} array - The array to paginate
67
+ * @param {number} page - The page number
68
+ * @param {number} pageSize - The number of items per page; defaults to 10
69
+ * @returns {Object} The paginated array and total number of pages
70
+ */
71
+ paginateArray: <T = any>(array: T[], page: number, pageSize?: number) => {
72
+ paginatedItems: T[];
73
+ totalPages: number;
74
+ };
75
+ /**
76
+ * Sanitises any potential HTML injected into user input.
77
+ * @param {string} input - The input to be sanitised
78
+ * @returns A sanitised string, or an empty string if the input is invalid
79
+ */
80
+ sanitiseHtml: (input: string) => string;
81
+ };
82
+ export declare const Validate: {
83
+ /**
84
+ * A regular expression for E.164 phone numbers.
85
+ *
86
+ * - Source: https://www.twilio.com/docs/glossary/what-e164
87
+ */
88
+ e164Regex: RegExp;
89
+ /**
90
+ * The minimum birth date (from today's date) for a user who is a minor, i.e. `YYYY-MM-DD`
91
+ */
92
+ minimumMinorBirthDate: string;
93
+ /**
94
+ * A regular expression for user passwords to match during authentication. It covers the following rules:
95
+ * - at least 8 characters long
96
+ * - at least one digit
97
+ * - at least one lowercase letter
98
+ * - at least one uppercase letter
99
+ * - at least one symbol
100
+ */
101
+ passwordRegex: RegExp;
102
+ /**
103
+ * Returns a regular expression for a Koloseum platform ID.
104
+ * @param {string} type - The type of platform ID to return
105
+ * @returns A regular expression for the platform ID, or `null` if the type is invalid
106
+ */
107
+ platformIdRegex: (type: "lounge" | "loungeBranch" | "player") => RegExp | null;
108
+ /**
109
+ * A regular expression for social media handles, without a leading slash or @ character.
110
+ *
111
+ * - Source: https://stackoverflow.com/a/74579651
112
+ */
113
+ socialMediaHandleRegex: RegExp;
114
+ /**
115
+ * An array of values representing social media platforms recognised in the database.
116
+ */
117
+ socialMediaPlatforms: SocialMediaPlatformObject[];
118
+ /**
119
+ * Validates an E.164 phone number.
120
+ * @param {string} phoneNumber - The phone number to be validated
121
+ * @param {"any" | MobilePhoneLocale | MobilePhoneLocale[]} [locale="any"] - The locale(s) to validate the phone number against
122
+ * @returns `true` if the phone number is valid; `false` otherwise
123
+ */
124
+ validateE164: (phoneNumber: string, locale?: "any" | MobilePhoneLocale | MobilePhoneLocale[]) => boolean;
125
+ /**
126
+ * Validates a social media handle.
127
+ * @param {string} handle - The social media handle to be validated
128
+ * @returns `true` if the handle is valid; `false` otherwise
129
+ */
130
+ validateSocialMediaHandle: (handle: string) => boolean;
131
+ };
@@ -0,0 +1,383 @@
1
+ import validator from "validator";
2
+ /* HELPERS */
3
+ const sanitize = (await import("sanitize-html")).default;
4
+ const { isMobilePhone, isURL } = validator;
5
+ /* DATA TRANSFORMATION HELPERS */
6
+ export const Transform = {
7
+ /**
8
+ * Capitalises a given word.
9
+ * @param {string} word - The word to be capitalised
10
+ * @returns The capitalised word
11
+ */
12
+ capitalise: (word) => word.charAt(0).toUpperCase() +
13
+ word
14
+ .slice(1)
15
+ .split("")
16
+ .map((c) => c.toLowerCase())
17
+ .join(""),
18
+ /**
19
+ * Cleans a URL by removing the protocol and trailing slashes.
20
+ * @param {string} url - The URL to clean
21
+ * @returns {string} The cleaned URL
22
+ */
23
+ cleanUrl: (url) => url.replace(/^https?:\/\//, "").replace(/\/+$/, ""),
24
+ /**
25
+ * Formats a date in the format DD/MM/YYYY (by default) or YYYY-MM-DD (for client).
26
+ * @param {string} date - Date to be formatted
27
+ * @param {boolean} forClient - Specify whether the data is for displaying on the client; defaults to `false`
28
+ * @returns The formatted date string, or `null` if invalid input or in case of an error
29
+ */
30
+ formatDate: (date, forClient = false) => {
31
+ // Return null if no date is provided
32
+ if (date === "" || typeof date !== "string")
33
+ return null;
34
+ // Handle input
35
+ try {
36
+ // Parse date string
37
+ const parsedDate = Date.parse(date);
38
+ // Return null if date string is not parseable
39
+ if (isNaN(parsedDate))
40
+ return null;
41
+ // Use the Intl.DateTimeFormat with explicit options to ensure correct formatting
42
+ const formattedDate = new Intl.DateTimeFormat(forClient ? "fr-CA" : "en-KE", {
43
+ day: "2-digit",
44
+ month: "2-digit",
45
+ year: "numeric",
46
+ timeZone: "Africa/Nairobi"
47
+ }).format(parsedDate);
48
+ // Return formatted date string
49
+ return formattedDate;
50
+ }
51
+ catch (error) {
52
+ console.error(error);
53
+ return null;
54
+ }
55
+ },
56
+ /**
57
+ * Formats a social media platform for display.
58
+ * @param {SocialMediaPlatform} platform - The social media platform to be formatted
59
+ * @returns The formatted social media platform string
60
+ */
61
+ formatSocialMediaPlatform: (platform) => {
62
+ const platforms = Validate.socialMediaPlatforms.map(({ value }) => value);
63
+ if (!platforms.includes(platform))
64
+ return "";
65
+ if (platform === "tiktok")
66
+ return "TikTok";
67
+ if (platform === "twitter")
68
+ return "X (formerly Twitter)";
69
+ if (platform === "youtube")
70
+ return "YouTube";
71
+ return Transform.capitalise(platform);
72
+ },
73
+ /**
74
+ * Returns an age in years given a birth date.
75
+ * @param {Date | string | number | null} dateOfBirth - The date of birth
76
+ * @returns The age in years, or `NaN` if the input is invalid
77
+ */
78
+ getAge: (dateOfBirth) => {
79
+ // Return NaN if no date is provided
80
+ if (!dateOfBirth)
81
+ return NaN;
82
+ // Validate and process date of birth
83
+ let birthDate;
84
+ if (dateOfBirth instanceof Date) {
85
+ if (isNaN(dateOfBirth.getTime()))
86
+ return NaN;
87
+ birthDate = dateOfBirth;
88
+ }
89
+ else if (typeof dateOfBirth === "string") {
90
+ if (dateOfBirth === "" || isNaN(Date.parse(dateOfBirth)))
91
+ return NaN;
92
+ // Format date of birth if it's a string
93
+ const formattedDate = Transform.formatDate(dateOfBirth, true);
94
+ if (!formattedDate)
95
+ return NaN;
96
+ birthDate = new Date(formattedDate);
97
+ }
98
+ else if (typeof dateOfBirth === "number") {
99
+ if (isNaN(dateOfBirth))
100
+ return NaN;
101
+ birthDate = new Date(dateOfBirth);
102
+ }
103
+ else {
104
+ return NaN;
105
+ }
106
+ // Validate the final date object
107
+ if (isNaN(birthDate.getTime()))
108
+ return NaN;
109
+ // Calculate age
110
+ const currentDate = new Date();
111
+ const monthDiff = currentDate.getMonth() - birthDate.getMonth();
112
+ let age = currentDate.getFullYear() - birthDate.getFullYear();
113
+ // Return age
114
+ return monthDiff < 0 || (monthDiff === 0 && currentDate.getDate() < birthDate.getDate()) ? --age : age;
115
+ },
116
+ /**
117
+ * Formats a date as a locale-specific string.
118
+ * @param {Date | string | number | null} date - Date to be formatted
119
+ * @param {boolean} withTime - Specify whether the date should include time; defaults to `false`
120
+ * @param {string} timeZone - The time zone to use for formatting; defaults to `Africa/Nairobi`
121
+ * @returns The formatted date string, or an empty string if invalid input
122
+ */
123
+ getDateString: (date, withTime = false, timeZone = "Africa/Nairobi") => {
124
+ // Return empty string if no date is provided
125
+ if (!date)
126
+ return "";
127
+ // Validate date to format
128
+ let dateToFormat;
129
+ if (date instanceof Date) {
130
+ if (isNaN(date.getTime()))
131
+ return "";
132
+ dateToFormat = date;
133
+ }
134
+ else if (typeof date === "string" || typeof date === "number") {
135
+ if (typeof date === "string" && (date === "" || isNaN(Date.parse(date))))
136
+ return "";
137
+ if (typeof date === "number" && isNaN(date))
138
+ return "";
139
+ dateToFormat = new Date(date);
140
+ }
141
+ else
142
+ return "";
143
+ // Validate the final date object
144
+ if (isNaN(dateToFormat.getTime()))
145
+ return "";
146
+ // Format date
147
+ return dateToFormat.toLocaleString("en-KE", {
148
+ timeZone,
149
+ year: "numeric",
150
+ month: "long",
151
+ day: "numeric",
152
+ hour: withTime ? "numeric" : undefined,
153
+ minute: withTime ? "2-digit" : undefined,
154
+ hour12: withTime ? true : undefined
155
+ });
156
+ },
157
+ /**
158
+ * Formats an identity type for display.
159
+ * @param {IdentityType} identityType - The identity type to be formatted
160
+ * @returns The formatted identity type string
161
+ */
162
+ getIdentityTypeString: (identityType) => {
163
+ if (identityType === "national")
164
+ return "National ID";
165
+ if (identityType === "alien")
166
+ return "Alien ID";
167
+ if (identityType === "passport")
168
+ return "Passport";
169
+ if (identityType === "driver_licence")
170
+ return "Driver's licence";
171
+ return "";
172
+ },
173
+ /**
174
+ * Formats a date to an ISO string in Kenyan time, i.e. `Africa/Nairobi` (UTC+3).
175
+ * @param {Date | string | number | null} date - The date to format
176
+ * @returns {string} The formatted date in ISO string format, or an empty string if invalid input
177
+ */
178
+ getKenyanISOString: (date) => {
179
+ // Return empty string if no date is provided or input is invalid
180
+ if (!date || (typeof date !== "string" && typeof date !== "number" && !(date instanceof Date)))
181
+ return "";
182
+ // Get locale string to format
183
+ const dateObj = date instanceof Date ? date : new Date(date);
184
+ const localeString = dateObj.toLocaleString("sv-SE", {
185
+ timeZone: "Africa/Nairobi"
186
+ });
187
+ // Return formatted string
188
+ return localeString.replace(" ", "T") + "+03:00";
189
+ },
190
+ /**
191
+ * Returns a pronoun given pronouns and a type.
192
+ * @param {PronounsItem | null} pronouns - The pronouns to be formatted
193
+ * @param {"subject" | "object" | "possessive" | "reflexive"} type - The type of pronoun to be returned
194
+ * @param {Sex} sex - The user's sex; defaults to `undefined`
195
+ * @returns The formatted pronoun, or `null` if the input is invalid
196
+ */
197
+ getPronoun: (pronouns, type, sex) => {
198
+ // Get pronoun from pronouns item
199
+ if (pronouns) {
200
+ // Return subject pronoun
201
+ if (type === "subject") {
202
+ if (pronouns === "he/him/his/himself")
203
+ return "he";
204
+ if (pronouns === "she/her/hers/herself")
205
+ return "she";
206
+ if (pronouns === "they/them/their/themself")
207
+ return "they";
208
+ if (pronouns === "name_only")
209
+ return "";
210
+ }
211
+ // Return object pronoun
212
+ else if (type === "object") {
213
+ if (pronouns === "he/him/his/himself")
214
+ return "him";
215
+ if (pronouns === "she/her/hers/herself")
216
+ return "her";
217
+ if (pronouns === "they/them/their/themself")
218
+ return "them";
219
+ if (pronouns === "name_only")
220
+ return "";
221
+ }
222
+ // Return possessive pronoun
223
+ else if (type === "possessive") {
224
+ if (pronouns === "he/him/his/himself")
225
+ return "his";
226
+ if (pronouns === "she/her/hers/herself")
227
+ return "her";
228
+ if (pronouns === "they/them/their/themself")
229
+ return "their";
230
+ if (pronouns === "name_only")
231
+ return "";
232
+ }
233
+ // Return reflexive pronoun
234
+ else if (type === "reflexive") {
235
+ if (pronouns === "he/him/his/himself")
236
+ return "himself";
237
+ if (pronouns === "she/her/hers/herself")
238
+ return "herself";
239
+ if (pronouns === "they/them/their/themself")
240
+ return "themself";
241
+ if (pronouns === "name_only")
242
+ return "";
243
+ }
244
+ }
245
+ // Assume pronoun for sex if no pronouns are provided
246
+ else if (sex) {
247
+ // Return subject pronoun
248
+ if (type === "subject") {
249
+ if (sex === "male" || sex === "intersex_man")
250
+ return "he";
251
+ if (sex === "female" || sex === "intersex_woman")
252
+ return "she";
253
+ return "they";
254
+ }
255
+ // Return object pronoun
256
+ else if (type === "object") {
257
+ if (sex === "male" || sex === "intersex_man")
258
+ return "him";
259
+ if (sex === "female" || sex === "intersex_woman")
260
+ return "her";
261
+ return "them";
262
+ }
263
+ // Return possessive pronoun
264
+ else if (type === "possessive") {
265
+ if (sex === "male" || sex === "intersex_man")
266
+ return "his";
267
+ if (sex === "female" || sex === "intersex_woman")
268
+ return "her";
269
+ return "their";
270
+ }
271
+ // Return reflexive pronoun
272
+ else if (type === "reflexive") {
273
+ if (sex === "male" || sex === "intersex_man")
274
+ return "himself";
275
+ if (sex === "female" || sex === "intersex_woman")
276
+ return "herself";
277
+ return "themself";
278
+ }
279
+ }
280
+ // Return null
281
+ return null;
282
+ },
283
+ /**
284
+ * Paginates an array.
285
+ * @template T - The type of array items; defaults to `any`
286
+ * @param {T[]} array - The array to paginate
287
+ * @param {number} page - The page number
288
+ * @param {number} pageSize - The number of items per page; defaults to 10
289
+ * @returns {Object} The paginated array and total number of pages
290
+ */
291
+ paginateArray: (array, page, pageSize = 10) => {
292
+ // Define variables
293
+ const startIndex = (page - 1) * pageSize;
294
+ const endIndex = startIndex + pageSize;
295
+ const totalPages = Math.ceil(array.length / pageSize);
296
+ // Paginate items
297
+ const paginatedItems = array.slice(startIndex, endIndex);
298
+ // Return data
299
+ return { paginatedItems, totalPages };
300
+ },
301
+ /**
302
+ * Sanitises any potential HTML injected into user input.
303
+ * @param {string} input - The input to be sanitised
304
+ * @returns A sanitised string, or an empty string if the input is invalid
305
+ */
306
+ sanitiseHtml: (input) => typeof input !== "string" ? "" : sanitize(input, { allowedTags: [], allowedAttributes: {} })
307
+ };
308
+ /* DATA VALIDATION HELPERS */
309
+ export const Validate = {
310
+ /**
311
+ * A regular expression for E.164 phone numbers.
312
+ *
313
+ * - Source: https://www.twilio.com/docs/glossary/what-e164
314
+ */
315
+ e164Regex: /^\+?[1-9]\d{1,14}$/,
316
+ /**
317
+ * The minimum birth date (from today's date) for a user who is a minor, i.e. `YYYY-MM-DD`
318
+ */
319
+ minimumMinorBirthDate: (() => {
320
+ const today = new Date();
321
+ const tomorrow = new Date();
322
+ tomorrow.setUTCDate(today.getDate() + 1);
323
+ const tomorrow18YearsAgo = tomorrow.getFullYear() - 18;
324
+ tomorrow.setFullYear(tomorrow18YearsAgo);
325
+ return tomorrow.toISOString().split("T")[0];
326
+ })(),
327
+ /**
328
+ * A regular expression for user passwords to match during authentication. It covers the following rules:
329
+ * - at least 8 characters long
330
+ * - at least one digit
331
+ * - at least one lowercase letter
332
+ * - at least one uppercase letter
333
+ * - at least one symbol
334
+ */
335
+ passwordRegex: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()\-_+=|{}\[\]:;'<>,.?/~]).{8,}$/,
336
+ /**
337
+ * Returns a regular expression for a Koloseum platform ID.
338
+ * @param {string} type - The type of platform ID to return
339
+ * @returns A regular expression for the platform ID, or `null` if the type is invalid
340
+ */
341
+ platformIdRegex: (type) => {
342
+ if (type === "lounge")
343
+ return /^KL\d{7}$/;
344
+ if (type === "loungeBranch")
345
+ return /^KLB\d{7}$/;
346
+ if (type === "player")
347
+ return /^KP\d{7}$/;
348
+ return null;
349
+ },
350
+ /**
351
+ * A regular expression for social media handles, without a leading slash or @ character.
352
+ *
353
+ * - Source: https://stackoverflow.com/a/74579651
354
+ */
355
+ socialMediaHandleRegex: /^([A-Za-z0-9_.]{3,25})$/gm,
356
+ /**
357
+ * An array of values representing social media platforms recognised in the database.
358
+ */
359
+ socialMediaPlatforms: [
360
+ { value: "facebook", linkPrefix: "https://www.facebook.com/" },
361
+ { value: "instagram", linkPrefix: "https://www.instagram.com/" },
362
+ { value: "kick", linkPrefix: "https://kick.com/" },
363
+ { value: "tiktok", linkPrefix: "https://www.tiktok.com/@" },
364
+ { value: "twitch", linkPrefix: "https://www.twitch.tv/" },
365
+ { value: "twitter", linkPrefix: "https://x.com/" },
366
+ { value: "youtube", linkPrefix: "https://www.youtube.com/@" }
367
+ ],
368
+ /**
369
+ * Validates an E.164 phone number.
370
+ * @param {string} phoneNumber - The phone number to be validated
371
+ * @param {"any" | MobilePhoneLocale | MobilePhoneLocale[]} [locale="any"] - The locale(s) to validate the phone number against
372
+ * @returns `true` if the phone number is valid; `false` otherwise
373
+ */
374
+ validateE164: (phoneNumber, locale = "en-KE") => isMobilePhone(phoneNumber, locale) && Boolean(phoneNumber.match(Validate.e164Regex)),
375
+ /**
376
+ * Validates a social media handle.
377
+ * @param {string} handle - The social media handle to be validated
378
+ * @returns `true` if the handle is valid; `false` otherwise
379
+ */
380
+ validateSocialMediaHandle: (handle) => !isURL(handle, { require_protocol: false }) &&
381
+ !handle.startsWith("@") &&
382
+ Boolean(handle.match(Validate.socialMediaHandleRegex))
383
+ };
@@ -0,0 +1,58 @@
1
+ export declare const Status: {
2
+ /**
3
+ * A generic error message.
4
+ */
5
+ ERROR: string;
6
+ /**
7
+ * A generic loading message.
8
+ */
9
+ LOADING: string;
10
+ /**
11
+ * A generic password reset request message.
12
+ */
13
+ PASSWORD_RESET_REQUESTED: string;
14
+ /**
15
+ * A generic password reset confirmation message.
16
+ */
17
+ PASSWORD_RESET_COMPLETED: string;
18
+ };
19
+ export declare const Cache: {
20
+ /**
21
+ * Delete cached data from Valkey.
22
+ * @param valkey - The Valkey client instance
23
+ * @param cachePrefix - The cache prefix
24
+ * @param key - The cache key
25
+ */
26
+ deleteData: (valkey: any, cachePrefix: string, key: string) => Promise<void>;
27
+ /**
28
+ * Generate cache key with consistent formatting
29
+ * @param prefix - The key prefix
30
+ * @param params - Additional parameters to include in the key
31
+ * @returns The formatted cache key
32
+ */
33
+ generateDataKey: (prefix: string, ...params: (string | number)[]) => string;
34
+ /**
35
+ * Get cached data from Valkey.
36
+ * @param valkey - The Valkey client instance
37
+ * @param cachePrefix - The cache prefix
38
+ * @param key - The cache key
39
+ * @returns The cached data, or `null` if not found
40
+ */
41
+ getData: <T>(valkey: any, cachePrefix: string, key: string) => Promise<T | null>;
42
+ /**
43
+ * Invalidate cache by pattern
44
+ * @param valkey - The Valkey client instance
45
+ * @param cachePrefix - The cache prefix
46
+ * @param pattern - The pattern to match keys against (e.g., "app-config*")
47
+ */
48
+ invalidateDataByPattern: (valkey: any, cachePrefix: string, pattern: string) => Promise<void>;
49
+ /**
50
+ * Set data in Valkey cache.
51
+ * @param valkey - The Valkey client instance
52
+ * @param cachePrefix - The cache prefix
53
+ * @param key - The cache key
54
+ * @param data - The data to cache
55
+ * @param ttl - The time to live in seconds; defaults to 1 hour
56
+ */
57
+ setData: <T>(valkey: any, cachePrefix: string, key: string, data: T, ttl?: number) => Promise<void>;
58
+ };
@@ -0,0 +1,92 @@
1
+ /* STATUS MESSAGES */
2
+ export const Status = {
3
+ /**
4
+ * A generic error message.
5
+ */
6
+ ERROR: "An unexpected error occurred. Kindly try again.",
7
+ /**
8
+ * A generic loading message.
9
+ */
10
+ LOADING: "Please wait…",
11
+ /**
12
+ * A generic password reset request message.
13
+ */
14
+ PASSWORD_RESET_REQUESTED: "If the provided email address is registered, you will receive a password reset link shortly.",
15
+ /**
16
+ * A generic password reset confirmation message.
17
+ */
18
+ PASSWORD_RESET_COMPLETED: "Your password has been reset successfully. You can now log in with your new password."
19
+ };
20
+ /* CACHE HELPERS */
21
+ export const Cache = {
22
+ /**
23
+ * Delete cached data from Valkey.
24
+ * @param valkey - The Valkey client instance
25
+ * @param cachePrefix - The cache prefix
26
+ * @param key - The cache key
27
+ */
28
+ deleteData: async (valkey, cachePrefix, key) => {
29
+ try {
30
+ await valkey.del(`${cachePrefix}${key}`);
31
+ }
32
+ catch (error) {
33
+ console.error("Cache delete error:", error);
34
+ }
35
+ },
36
+ /**
37
+ * Generate cache key with consistent formatting
38
+ * @param prefix - The key prefix
39
+ * @param params - Additional parameters to include in the key
40
+ * @returns The formatted cache key
41
+ */
42
+ generateDataKey: (prefix, ...params) => `${prefix}:${params.join(":")}`,
43
+ /**
44
+ * Get cached data from Valkey.
45
+ * @param valkey - The Valkey client instance
46
+ * @param cachePrefix - The cache prefix
47
+ * @param key - The cache key
48
+ * @returns The cached data, or `null` if not found
49
+ */
50
+ getData: async (valkey, cachePrefix, key) => {
51
+ try {
52
+ const cached = await valkey.get(`${cachePrefix}${key}`);
53
+ return cached ? JSON.parse(cached) : null;
54
+ }
55
+ catch (error) {
56
+ console.error("Cache get error:", error);
57
+ return null;
58
+ }
59
+ },
60
+ /**
61
+ * Invalidate cache by pattern
62
+ * @param valkey - The Valkey client instance
63
+ * @param cachePrefix - The cache prefix
64
+ * @param pattern - The pattern to match keys against (e.g., "app-config*")
65
+ */
66
+ invalidateDataByPattern: async (valkey, cachePrefix, pattern) => {
67
+ try {
68
+ const keys = await valkey.keys(`${cachePrefix}${pattern}`);
69
+ if (keys.length > 0)
70
+ await valkey.del(...keys);
71
+ }
72
+ catch (error) {
73
+ console.error("Cache pattern invalidation error:", error);
74
+ }
75
+ },
76
+ /**
77
+ * Set data in Valkey cache.
78
+ * @param valkey - The Valkey client instance
79
+ * @param cachePrefix - The cache prefix
80
+ * @param key - The cache key
81
+ * @param data - The data to cache
82
+ * @param ttl - The time to live in seconds; defaults to 1 hour
83
+ */
84
+ setData: async (valkey, cachePrefix, key, data, ttl = 3600) => {
85
+ try {
86
+ await valkey.setex(`${cachePrefix}${key}`, ttl, JSON.stringify(data));
87
+ }
88
+ catch (error) {
89
+ console.error("Cache set error:", error);
90
+ }
91
+ }
92
+ };