@koloseum/utils 0.1.3 → 0.1.4
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/dist/utils.d.ts +139 -0
- package/dist/utils.js +250 -0
- package/package.json +7 -4
- package/src/utils.test.ts +22 -22
- package/src/utils.ts +2 -33
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type { Database } from "@koloseum/types/database";
|
|
2
|
+
import type { CustomError, SocialMediaPlatform } from "@koloseum/types/public/auth";
|
|
3
|
+
import type { PostgrestError, SupabaseClient } from "@supabase/supabase-js";
|
|
4
|
+
import type { MobilePhoneLocale } from "validator";
|
|
5
|
+
export declare const Status: {
|
|
6
|
+
/**
|
|
7
|
+
* A generic error message.
|
|
8
|
+
*/
|
|
9
|
+
ERROR: string;
|
|
10
|
+
/**
|
|
11
|
+
* A generic loading message.
|
|
12
|
+
*/
|
|
13
|
+
LOADING: string;
|
|
14
|
+
/**
|
|
15
|
+
* A generic password reset request message.
|
|
16
|
+
*/
|
|
17
|
+
PASSWORD_RESET_REQUESTED: string;
|
|
18
|
+
};
|
|
19
|
+
export declare const Utility: {
|
|
20
|
+
/**
|
|
21
|
+
* Calls an Edge function.
|
|
22
|
+
* @param {SupabaseClient} supabase - The Supabase client
|
|
23
|
+
* @param {string} path - The path to the Edge function
|
|
24
|
+
* @param {"GET" | "POST"} [method="GET"] - The HTTP method to use
|
|
25
|
+
* @returns The response from the Edge function
|
|
26
|
+
*/
|
|
27
|
+
callEdgeFunction: (supabase: SupabaseClient<Database>, path: string, method?: "GET" | "POST") => Promise<{
|
|
28
|
+
data?: any;
|
|
29
|
+
error?: string;
|
|
30
|
+
}>;
|
|
31
|
+
/**
|
|
32
|
+
* Capitalises a given word.
|
|
33
|
+
* @param {string} word - The word to be capitalised
|
|
34
|
+
* @returns The capitalised word
|
|
35
|
+
*/
|
|
36
|
+
capitalise: (word: string) => string;
|
|
37
|
+
/**
|
|
38
|
+
* Returns a custom error object.
|
|
39
|
+
* @param {number} code - The error code; defaults to `500` if not provided or invalid
|
|
40
|
+
* @param {string} message - The error message
|
|
41
|
+
* @returns An object with the error `code` and `message`
|
|
42
|
+
*/
|
|
43
|
+
customError: (code: number | undefined, message: string) => CustomError;
|
|
44
|
+
/**
|
|
45
|
+
* A regular expression for E.164 phone numbers.
|
|
46
|
+
*
|
|
47
|
+
* - Source: https://www.twilio.com/docs/glossary/what-e164
|
|
48
|
+
*/
|
|
49
|
+
e164Regex: RegExp;
|
|
50
|
+
/**
|
|
51
|
+
* Formats a date in the format DD/MM/YYYY (by default) or YYYY-MM-DD (for client).
|
|
52
|
+
* @param {string} date - Date to be formatted
|
|
53
|
+
* @param {boolean} forClient - Specify whether the data is for displaying on the client; defaults to `false`
|
|
54
|
+
* @returns The formatted date string, or `null` if invalid input or in case of an error
|
|
55
|
+
*/
|
|
56
|
+
formatDate: (date: string, forClient?: boolean) => string | null;
|
|
57
|
+
/**
|
|
58
|
+
* Formats a social media platform for display.
|
|
59
|
+
* @param {SocialMediaPlatform} platform - The social media platform to be formatted
|
|
60
|
+
* @returns The formatted social media platform string
|
|
61
|
+
*/
|
|
62
|
+
formatSocialMediaPlatform: (platform: SocialMediaPlatform) => string;
|
|
63
|
+
/**
|
|
64
|
+
* Returns an age in years given a birth date.
|
|
65
|
+
* @param {string} dateOfBirth - The date of birth as a string, e.g. `DD-MM-YYYY`
|
|
66
|
+
* @returns The age in years, or `NaN` if the input is invalid
|
|
67
|
+
*/
|
|
68
|
+
getAge: (dateOfBirth: string) => number;
|
|
69
|
+
/**
|
|
70
|
+
* A regular expression for Koloseum Lounge Branch IDs. It covers the following rules:
|
|
71
|
+
* - 9 characters long
|
|
72
|
+
* - begins with "KLB" followed by 7 digits
|
|
73
|
+
*/
|
|
74
|
+
loungeBranchIdRegex: RegExp;
|
|
75
|
+
/**
|
|
76
|
+
* A regular expression for Koloseum Lounge IDs. It covers the following rules:
|
|
77
|
+
* - 9 characters long
|
|
78
|
+
* - begins with "KL" followed by 7 digits
|
|
79
|
+
*/
|
|
80
|
+
loungeIdRegex: RegExp;
|
|
81
|
+
/**
|
|
82
|
+
* The minimum birth date (from today's date) for a user who is a minor, i.e. `YYYY-MM-DD`
|
|
83
|
+
*/
|
|
84
|
+
minimumMinorBirthDate: string;
|
|
85
|
+
/**
|
|
86
|
+
* Parses a `CustomError` object within a page/layout server load function and returns an error to be thrown.
|
|
87
|
+
* @param {CustomError} error - The error object
|
|
88
|
+
* @returns A new `Error` object if the error is unexpected, or a Svelte error otherwise
|
|
89
|
+
*/
|
|
90
|
+
parseLoadError: (error: CustomError) => Error;
|
|
91
|
+
/**
|
|
92
|
+
* Parses a `PostgrestError` object and returns a custom error object if any has occurred.
|
|
93
|
+
* @param {PostgrestError | null} postgrestError - The `PostgrestError` object, or `null` if no error occurred
|
|
94
|
+
* @returns An object with an `error` if any has occurred
|
|
95
|
+
*/
|
|
96
|
+
parsePostgrestError: (postgrestError: PostgrestError | null) => {
|
|
97
|
+
error?: CustomError;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* A regular expression for user passwords to match during authentication. It covers the following rules:
|
|
101
|
+
* - at least 8 characters long
|
|
102
|
+
* - at least one digit
|
|
103
|
+
* - at least one lowercase letter
|
|
104
|
+
* - at least one uppercase letter
|
|
105
|
+
* - at least one symbol
|
|
106
|
+
*/
|
|
107
|
+
passwordRegex: RegExp;
|
|
108
|
+
/**
|
|
109
|
+
* A regular expression for Koloseum Player IDs. It covers the following rules:
|
|
110
|
+
* - 9 characters long
|
|
111
|
+
* - begins with "KP" followed by 7 digits
|
|
112
|
+
*/
|
|
113
|
+
playerIdRegex: RegExp;
|
|
114
|
+
/**
|
|
115
|
+
* Sanitises any potential HTML injected into user input.
|
|
116
|
+
* @param {string} input - The input to be sanitised
|
|
117
|
+
* @returns A sanitised string, or an empty string if the input is invalid
|
|
118
|
+
*/
|
|
119
|
+
sanitiseHtml: (input: string) => string;
|
|
120
|
+
/**
|
|
121
|
+
* A regular expression for social media handles, without a leading slash or @ character.
|
|
122
|
+
*
|
|
123
|
+
* - Source: https://stackoverflow.com/a/74579651
|
|
124
|
+
*/
|
|
125
|
+
socialMediaHandleRegex: RegExp;
|
|
126
|
+
/**
|
|
127
|
+
* Validates an E.164 phone number.
|
|
128
|
+
* @param {string} phoneNumber - The phone number to be validated
|
|
129
|
+
* @param {"any" | MobilePhoneLocale | MobilePhoneLocale[]} [locale="any"] - The locale(s) to validate the phone number against
|
|
130
|
+
* @returns `true` if the phone number is valid; `false` otherwise
|
|
131
|
+
*/
|
|
132
|
+
validateE164: (phoneNumber: string, locale?: "any" | MobilePhoneLocale | MobilePhoneLocale[]) => boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Validates a social media handle.
|
|
135
|
+
* @param {string} handle - The social media handle to be validated
|
|
136
|
+
* @returns `true` if the handle is valid; `false` otherwise
|
|
137
|
+
*/
|
|
138
|
+
validateSocialMediaHandle: (handle: string) => boolean;
|
|
139
|
+
};
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { FunctionsFetchError, FunctionsHttpError, FunctionsRelayError } from "@supabase/supabase-js";
|
|
2
|
+
import { error as svelteError } from "@sveltejs/kit";
|
|
3
|
+
import parser from "any-date-parser";
|
|
4
|
+
import sanitize from "sanitize-html";
|
|
5
|
+
import validator from "validator";
|
|
6
|
+
/* Helper functions */
|
|
7
|
+
const { isMobilePhone, isURL } = validator;
|
|
8
|
+
/* Status messages */
|
|
9
|
+
export const Status = {
|
|
10
|
+
/**
|
|
11
|
+
* A generic error message.
|
|
12
|
+
*/
|
|
13
|
+
ERROR: "An unexpected error occurred. Kindly try again.",
|
|
14
|
+
/**
|
|
15
|
+
* A generic loading message.
|
|
16
|
+
*/
|
|
17
|
+
LOADING: "Please wait…",
|
|
18
|
+
/**
|
|
19
|
+
* A generic password reset request message.
|
|
20
|
+
*/
|
|
21
|
+
PASSWORD_RESET_REQUESTED: "If the provided email address is registered, you will receive a password reset link shortly.",
|
|
22
|
+
};
|
|
23
|
+
/* Utility functions */
|
|
24
|
+
export const Utility = {
|
|
25
|
+
/**
|
|
26
|
+
* Calls an Edge function.
|
|
27
|
+
* @param {SupabaseClient} supabase - The Supabase client
|
|
28
|
+
* @param {string} path - The path to the Edge function
|
|
29
|
+
* @param {"GET" | "POST"} [method="GET"] - The HTTP method to use
|
|
30
|
+
* @returns The response from the Edge function
|
|
31
|
+
*/
|
|
32
|
+
callEdgeFunction: async (supabase, path, method = "GET") => {
|
|
33
|
+
// Fetch response
|
|
34
|
+
const { data, error } = await supabase.functions.invoke(path, { method });
|
|
35
|
+
// Return error if any
|
|
36
|
+
if (error instanceof FunctionsHttpError)
|
|
37
|
+
return { error: await error.context.json() };
|
|
38
|
+
else if (error instanceof FunctionsRelayError)
|
|
39
|
+
return { error: error.message };
|
|
40
|
+
else if (error instanceof FunctionsFetchError)
|
|
41
|
+
return { error: error.message };
|
|
42
|
+
// Return response
|
|
43
|
+
return { data };
|
|
44
|
+
},
|
|
45
|
+
/**
|
|
46
|
+
* Capitalises a given word.
|
|
47
|
+
* @param {string} word - The word to be capitalised
|
|
48
|
+
* @returns The capitalised word
|
|
49
|
+
*/
|
|
50
|
+
capitalise: (word) => word.charAt(0).toUpperCase() +
|
|
51
|
+
word
|
|
52
|
+
.slice(1)
|
|
53
|
+
.split("")
|
|
54
|
+
.map((c) => c.toLowerCase())
|
|
55
|
+
.join(""),
|
|
56
|
+
/**
|
|
57
|
+
* Returns a custom error object.
|
|
58
|
+
* @param {number} code - The error code; defaults to `500` if not provided or invalid
|
|
59
|
+
* @param {string} message - The error message
|
|
60
|
+
* @returns An object with the error `code` and `message`
|
|
61
|
+
*/
|
|
62
|
+
customError: (code, message) => (!code || code < 400 || code > 599 ? { code: 500, message: Status.ERROR } : { code, message }),
|
|
63
|
+
/**
|
|
64
|
+
* A regular expression for E.164 phone numbers.
|
|
65
|
+
*
|
|
66
|
+
* - Source: https://www.twilio.com/docs/glossary/what-e164
|
|
67
|
+
*/
|
|
68
|
+
e164Regex: /^\+?[1-9]\d{1,14}$/,
|
|
69
|
+
/**
|
|
70
|
+
* Formats a date in the format DD/MM/YYYY (by default) or YYYY-MM-DD (for client).
|
|
71
|
+
* @param {string} date - Date to be formatted
|
|
72
|
+
* @param {boolean} forClient - Specify whether the data is for displaying on the client; defaults to `false`
|
|
73
|
+
* @returns The formatted date string, or `null` if invalid input or in case of an error
|
|
74
|
+
*/
|
|
75
|
+
formatDate: (date, forClient = false) => {
|
|
76
|
+
if (date === "")
|
|
77
|
+
return null;
|
|
78
|
+
try {
|
|
79
|
+
const formattedDate = new Intl.DateTimeFormat(forClient ? "fr-CA" : "en-KE", {
|
|
80
|
+
day: "2-digit",
|
|
81
|
+
month: "2-digit",
|
|
82
|
+
year: "numeric",
|
|
83
|
+
// @ts-ignore: .fromString method exists but is not typed in `any-date-parser` package
|
|
84
|
+
}).format(parser.fromString(date));
|
|
85
|
+
return formattedDate;
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
/**
|
|
92
|
+
* Formats a social media platform for display.
|
|
93
|
+
* @param {SocialMediaPlatform} platform - The social media platform to be formatted
|
|
94
|
+
* @returns The formatted social media platform string
|
|
95
|
+
*/
|
|
96
|
+
formatSocialMediaPlatform: (platform) => {
|
|
97
|
+
const platforms = ["facebook", "instagram", "kick", "tiktok", "twitch", "twitter", "youtube"];
|
|
98
|
+
if (!platforms.includes(platform))
|
|
99
|
+
return "";
|
|
100
|
+
if (platform === "tiktok")
|
|
101
|
+
return "TikTok";
|
|
102
|
+
if (platform === "twitter")
|
|
103
|
+
return "X (formerly Twitter)";
|
|
104
|
+
if (platform === "youtube")
|
|
105
|
+
return "YouTube";
|
|
106
|
+
return Utility.capitalise(platform);
|
|
107
|
+
},
|
|
108
|
+
/**
|
|
109
|
+
* Returns an age in years given a birth date.
|
|
110
|
+
* @param {string} dateOfBirth - The date of birth as a string, e.g. `DD-MM-YYYY`
|
|
111
|
+
* @returns The age in years, or `NaN` if the input is invalid
|
|
112
|
+
*/
|
|
113
|
+
getAge: (dateOfBirth) => {
|
|
114
|
+
if (dateOfBirth === "" || typeof dateOfBirth !== "string")
|
|
115
|
+
return NaN;
|
|
116
|
+
dateOfBirth = Utility.formatDate(dateOfBirth, true);
|
|
117
|
+
const birthDate = new Date(dateOfBirth);
|
|
118
|
+
const currentDate = new Date();
|
|
119
|
+
let age = currentDate.getFullYear() - birthDate.getFullYear();
|
|
120
|
+
const monthDiff = currentDate.getMonth() - birthDate.getMonth();
|
|
121
|
+
return monthDiff < 0 || (monthDiff === 0 && currentDate.getDate() < birthDate.getDate()) ? --age : age;
|
|
122
|
+
},
|
|
123
|
+
/**
|
|
124
|
+
* A regular expression for Koloseum Lounge Branch IDs. It covers the following rules:
|
|
125
|
+
* - 9 characters long
|
|
126
|
+
* - begins with "KLB" followed by 7 digits
|
|
127
|
+
*/
|
|
128
|
+
loungeBranchIdRegex: /^KLB\d{7}$/,
|
|
129
|
+
/**
|
|
130
|
+
* A regular expression for Koloseum Lounge IDs. It covers the following rules:
|
|
131
|
+
* - 9 characters long
|
|
132
|
+
* - begins with "KL" followed by 7 digits
|
|
133
|
+
*/
|
|
134
|
+
loungeIdRegex: /^KL\d{7}$/,
|
|
135
|
+
/**
|
|
136
|
+
* The minimum birth date (from today's date) for a user who is a minor, i.e. `YYYY-MM-DD`
|
|
137
|
+
*/
|
|
138
|
+
minimumMinorBirthDate: (() => {
|
|
139
|
+
const today = new Date();
|
|
140
|
+
const tomorrow = new Date();
|
|
141
|
+
tomorrow.setUTCDate(today.getDate() + 1);
|
|
142
|
+
const tomorrow18YearsAgo = tomorrow.getFullYear() - 18;
|
|
143
|
+
tomorrow.setFullYear(tomorrow18YearsAgo);
|
|
144
|
+
return tomorrow.toISOString().split("T")[0];
|
|
145
|
+
})(),
|
|
146
|
+
/**
|
|
147
|
+
* Parses a `CustomError` object within a page/layout server load function and returns an error to be thrown.
|
|
148
|
+
* @param {CustomError} error - The error object
|
|
149
|
+
* @returns A new `Error` object if the error is unexpected, or a Svelte error otherwise
|
|
150
|
+
*/
|
|
151
|
+
parseLoadError: (error) => (error.code === 500 ? new Error(error.message) : svelteError(error.code, { message: error.message })),
|
|
152
|
+
/**
|
|
153
|
+
* Parses a `PostgrestError` object and returns a custom error object if any has occurred.
|
|
154
|
+
* @param {PostgrestError | null} postgrestError - The `PostgrestError` object, or `null` if no error occurred
|
|
155
|
+
* @returns An object with an `error` if any has occurred
|
|
156
|
+
*/
|
|
157
|
+
parsePostgrestError: (postgrestError) => {
|
|
158
|
+
// Return undefined if no error occurred
|
|
159
|
+
let error;
|
|
160
|
+
if (!postgrestError)
|
|
161
|
+
return { error };
|
|
162
|
+
// Return custom error if hint is a number between 400 and 599
|
|
163
|
+
const customErrorCode = Number(postgrestError.hint);
|
|
164
|
+
if (!isNaN(customErrorCode) && customErrorCode >= 400 && customErrorCode <= 599) {
|
|
165
|
+
error = Utility.customError(customErrorCode, postgrestError.message);
|
|
166
|
+
return { error };
|
|
167
|
+
}
|
|
168
|
+
// Map Postgrest error codes to custom error codes
|
|
169
|
+
const errorMap = [
|
|
170
|
+
{ code: "08", status: 503 },
|
|
171
|
+
{ code: "09", status: 500 },
|
|
172
|
+
{ code: "0L", status: 403 },
|
|
173
|
+
{ code: "0P", status: 403 },
|
|
174
|
+
{ code: "23503", status: 409 },
|
|
175
|
+
{ code: "23505", status: 409 },
|
|
176
|
+
{ code: "25006", status: 405 },
|
|
177
|
+
{ code: "25", status: 500 },
|
|
178
|
+
{ code: "28", status: 403 },
|
|
179
|
+
{ code: "2D", status: 500 },
|
|
180
|
+
{ code: "38", status: 500 },
|
|
181
|
+
{ code: "39", status: 500 },
|
|
182
|
+
{ code: "3B", status: 500 },
|
|
183
|
+
{ code: "40", status: 500 },
|
|
184
|
+
{ code: "53400", status: 500 },
|
|
185
|
+
{ code: "53", status: 503 },
|
|
186
|
+
{ code: "54", status: 500 },
|
|
187
|
+
{ code: "55", status: 500 },
|
|
188
|
+
{ code: "57", status: 500 },
|
|
189
|
+
{ code: "58", status: 500 },
|
|
190
|
+
{ code: "F0", status: 500 },
|
|
191
|
+
{ code: "HV", status: 500 },
|
|
192
|
+
{ code: "P0001", status: 400 },
|
|
193
|
+
{ code: "P0", status: 500 },
|
|
194
|
+
{ code: "XX", status: 500 },
|
|
195
|
+
{ code: "42883", status: 404 },
|
|
196
|
+
{ code: "42P01", status: 404 },
|
|
197
|
+
{ code: "42P17", status: 500 },
|
|
198
|
+
{ code: "42501", status: 403 },
|
|
199
|
+
];
|
|
200
|
+
// Return custom error if Postgrest error code is found
|
|
201
|
+
for (const { code, status } of errorMap)
|
|
202
|
+
if (postgrestError.code === code || postgrestError.code.startsWith(code)) {
|
|
203
|
+
error = Utility.customError(status, Status.ERROR);
|
|
204
|
+
return { error };
|
|
205
|
+
}
|
|
206
|
+
// Return generic error
|
|
207
|
+
error = Utility.customError(500, Status.ERROR);
|
|
208
|
+
return { error };
|
|
209
|
+
},
|
|
210
|
+
/**
|
|
211
|
+
* A regular expression for user passwords to match during authentication. It covers the following rules:
|
|
212
|
+
* - at least 8 characters long
|
|
213
|
+
* - at least one digit
|
|
214
|
+
* - at least one lowercase letter
|
|
215
|
+
* - at least one uppercase letter
|
|
216
|
+
* - at least one symbol
|
|
217
|
+
*/
|
|
218
|
+
passwordRegex: /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()-_+=|{}[\]:;'<>,.?/~]).{8,}$/,
|
|
219
|
+
/**
|
|
220
|
+
* A regular expression for Koloseum Player IDs. It covers the following rules:
|
|
221
|
+
* - 9 characters long
|
|
222
|
+
* - begins with "KP" followed by 7 digits
|
|
223
|
+
*/
|
|
224
|
+
playerIdRegex: /^KP\d{7}$/,
|
|
225
|
+
/**
|
|
226
|
+
* Sanitises any potential HTML injected into user input.
|
|
227
|
+
* @param {string} input - The input to be sanitised
|
|
228
|
+
* @returns A sanitised string, or an empty string if the input is invalid
|
|
229
|
+
*/
|
|
230
|
+
sanitiseHtml: (input) => (typeof input !== "string" ? "" : sanitize(input, { allowedTags: [], allowedAttributes: {} })),
|
|
231
|
+
/**
|
|
232
|
+
* A regular expression for social media handles, without a leading slash or @ character.
|
|
233
|
+
*
|
|
234
|
+
* - Source: https://stackoverflow.com/a/74579651
|
|
235
|
+
*/
|
|
236
|
+
socialMediaHandleRegex: /^([A-Za-z0-9_.]{3,25})$/gm,
|
|
237
|
+
/**
|
|
238
|
+
* Validates an E.164 phone number.
|
|
239
|
+
* @param {string} phoneNumber - The phone number to be validated
|
|
240
|
+
* @param {"any" | MobilePhoneLocale | MobilePhoneLocale[]} [locale="any"] - The locale(s) to validate the phone number against
|
|
241
|
+
* @returns `true` if the phone number is valid; `false` otherwise
|
|
242
|
+
*/
|
|
243
|
+
validateE164: (phoneNumber, locale = "en-KE") => isMobilePhone(phoneNumber, locale) && Boolean(phoneNumber.match(Utility.e164Regex)),
|
|
244
|
+
/**
|
|
245
|
+
* Validates a social media handle.
|
|
246
|
+
* @param {string} handle - The social media handle to be validated
|
|
247
|
+
* @returns `true` if the handle is valid; `false` otherwise
|
|
248
|
+
*/
|
|
249
|
+
validateSocialMediaHandle: (handle) => !isURL(handle, { require_protocol: false }) && !handle.startsWith("@") && Boolean(handle.match(Utility.socialMediaHandleRegex)),
|
|
250
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koloseum/utils",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"author": "Koloseum Technologies Limited",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"description": "Utility logic for use across Koloseum web apps (TypeScript)",
|
|
6
7
|
"keywords": [
|
|
7
8
|
"Koloseum"
|
|
@@ -14,14 +15,16 @@
|
|
|
14
15
|
"type": "git",
|
|
15
16
|
"url": "git+https://github.com/koloseum-technologies/npm-utils.git"
|
|
16
17
|
},
|
|
17
|
-
"main": "./
|
|
18
|
+
"main": "./dist/utils.js",
|
|
18
19
|
"exports": {
|
|
19
|
-
"./src": "./
|
|
20
|
+
"./src": "./dist/utils.js"
|
|
20
21
|
},
|
|
21
22
|
"files": [
|
|
22
|
-
"./src/**/*.ts"
|
|
23
|
+
"./src/**/*.ts",
|
|
24
|
+
"./dist/**/*"
|
|
23
25
|
],
|
|
24
26
|
"scripts": {
|
|
27
|
+
"build": "npx tsc",
|
|
25
28
|
"test": "vitest --run"
|
|
26
29
|
},
|
|
27
30
|
"dependencies": {
|
package/src/utils.test.ts
CHANGED
|
@@ -28,7 +28,7 @@ describe("Utility helper", () => {
|
|
|
28
28
|
parsePostgrestError,
|
|
29
29
|
sanitiseHtml,
|
|
30
30
|
validateE164,
|
|
31
|
-
validateSocialMediaHandle
|
|
31
|
+
validateSocialMediaHandle,
|
|
32
32
|
} = Utility;
|
|
33
33
|
|
|
34
34
|
// Test each helper
|
|
@@ -99,65 +99,65 @@ describe("Utility helper", () => {
|
|
|
99
99
|
expect(parsePostgrestError(null)).toEqual({ error: undefined });
|
|
100
100
|
expect(
|
|
101
101
|
parsePostgrestError({
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
code: "42501",
|
|
103
|
+
name: "insufficient_privilege",
|
|
104
104
|
message: 'Insufficient privileges: permission denied for relation "restricted_table"',
|
|
105
105
|
details: 'User does not have the necessary permissions to access the relation "restricted_table".',
|
|
106
|
-
hint: ""
|
|
106
|
+
hint: "",
|
|
107
107
|
})
|
|
108
108
|
).toEqual({ error: { code: 403, message: Status.ERROR } });
|
|
109
109
|
expect(
|
|
110
110
|
parsePostgrestError({
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
code: "42883",
|
|
112
|
+
name: "undefined_function",
|
|
113
113
|
message: "Undefined function: function non_existent_function() does not exist",
|
|
114
114
|
details: "Function non_existent_function() does not exist.",
|
|
115
|
-
hint: "No function matches the given name and argument types. You might need to add explicit type casts."
|
|
115
|
+
hint: "No function matches the given name and argument types. You might need to add explicit type casts.",
|
|
116
116
|
})
|
|
117
117
|
).toEqual({ error: { code: 404, message: Status.ERROR } });
|
|
118
118
|
expect(
|
|
119
119
|
parsePostgrestError({
|
|
120
|
-
|
|
121
|
-
|
|
120
|
+
code: "25006",
|
|
121
|
+
name: "read_only_sql_transaction",
|
|
122
122
|
message: "Read only SQL transaction: cannot execute INSERT in a read-only transaction",
|
|
123
123
|
details: "Cannot execute INSERT in a read-only transaction.",
|
|
124
|
-
hint: ""
|
|
124
|
+
hint: "",
|
|
125
125
|
})
|
|
126
126
|
).toEqual({ error: { code: 405, message: Status.ERROR } });
|
|
127
127
|
expect(
|
|
128
128
|
parsePostgrestError({
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
code: "23505",
|
|
130
|
+
name: "unique_violation",
|
|
131
131
|
message: 'Uniqueness violation: duplicate key value violates unique constraint "users_username_key"',
|
|
132
132
|
details: "Key (username)=(john_doe) already exists.",
|
|
133
|
-
hint: ""
|
|
133
|
+
hint: "",
|
|
134
134
|
})
|
|
135
135
|
).toEqual({ error: { code: 409, message: Status.ERROR } });
|
|
136
136
|
expect(
|
|
137
137
|
parsePostgrestError({
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
code: "53400",
|
|
139
|
+
name: "configuration_file_error",
|
|
140
140
|
message: "invalid page header in block 0 of relation base/12345/67890",
|
|
141
141
|
details: "The page header is corrupted. This may indicate hardware or file system issues.",
|
|
142
|
-
hint: ""
|
|
142
|
+
hint: "",
|
|
143
143
|
})
|
|
144
144
|
).toEqual({ error: { code: 500, message: Status.ERROR } });
|
|
145
145
|
expect(
|
|
146
146
|
parsePostgrestError({
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
code: "08003",
|
|
148
|
+
name: "connection_does_not_exist",
|
|
149
149
|
message: "connection does not exist",
|
|
150
150
|
details: "The connection to the database was lost or never established.",
|
|
151
|
-
hint: ""
|
|
151
|
+
hint: "",
|
|
152
152
|
})
|
|
153
153
|
).toEqual({ error: { code: 503, message: Status.ERROR } });
|
|
154
154
|
expect(
|
|
155
155
|
parsePostgrestError({
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
code: "P0001",
|
|
157
|
+
name: "raise_exception",
|
|
158
158
|
message: "I'm a teapot!",
|
|
159
159
|
details: "Pretty simple",
|
|
160
|
-
hint: "418"
|
|
160
|
+
hint: "418",
|
|
161
161
|
})
|
|
162
162
|
).toEqual({ error: { code: 418, message: "I'm a teapot!" } });
|
|
163
163
|
});
|
package/src/utils.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import type { Database } from "@koloseum/types/database";
|
|
2
2
|
import type { CustomError, SocialMediaPlatform } from "@koloseum/types/public/auth";
|
|
3
3
|
|
|
4
|
-
import type { Page, Locator } from "@playwright/test";
|
|
5
4
|
import type { PostgrestError, SupabaseClient } from "@supabase/supabase-js";
|
|
6
5
|
import type { MobilePhoneLocale } from "validator";
|
|
7
6
|
|
|
8
|
-
import { expect } from "@playwright/test";
|
|
9
7
|
import { FunctionsFetchError, FunctionsHttpError, FunctionsRelayError } from "@supabase/supabase-js";
|
|
10
8
|
import { error as svelteError } from "@sveltejs/kit";
|
|
11
9
|
|
|
@@ -91,8 +89,8 @@ export const Utility = {
|
|
|
91
89
|
day: "2-digit",
|
|
92
90
|
month: "2-digit",
|
|
93
91
|
year: "numeric",
|
|
94
|
-
|
|
95
|
-
}).format(parser.fromString(date));
|
|
92
|
+
// @ts-ignore: .fromString method exists but is not typed in `any-date-parser` package
|
|
93
|
+
}).format(parser.fromString(date));
|
|
96
94
|
|
|
97
95
|
return formattedDate;
|
|
98
96
|
} catch (error) {
|
|
@@ -264,32 +262,3 @@ export const Utility = {
|
|
|
264
262
|
*/
|
|
265
263
|
validateSocialMediaHandle: (handle: string) => !isURL(handle, { require_protocol: false }) && !handle.startsWith("@") && Boolean(handle.match(Utility.socialMediaHandleRegex)),
|
|
266
264
|
};
|
|
267
|
-
|
|
268
|
-
/* Testing functions */
|
|
269
|
-
export const Testing = {
|
|
270
|
-
/**
|
|
271
|
-
* Asserts the absence of a field on the page.
|
|
272
|
-
* @param {Locator[]} fields - The fields to check for absence
|
|
273
|
-
* @returns A promise that resolves when the check is complete
|
|
274
|
-
*/
|
|
275
|
-
assertFieldAbsence: async (...fields: Locator[]) => {
|
|
276
|
-
for (const field of fields) await expect(field).not.toBeVisible();
|
|
277
|
-
},
|
|
278
|
-
/**
|
|
279
|
-
* Clicks a locator and waits for a response.
|
|
280
|
-
* @param {Page} page - The page on which to click the locator
|
|
281
|
-
* @param {Locator} locator - The locator to click
|
|
282
|
-
* @param {string} endpoint - The endpoint to wait for
|
|
283
|
-
* @returns A promise that resolves when the click and response are complete
|
|
284
|
-
*/
|
|
285
|
-
clickAndWait: async (page: Page, locator: Locator, endpoint: string) => {
|
|
286
|
-
// Ensure the locator is visible
|
|
287
|
-
await expect(locator).toBeVisible();
|
|
288
|
-
|
|
289
|
-
// Click with force option to ensure the click happens
|
|
290
|
-
await locator.click({ force: true });
|
|
291
|
-
|
|
292
|
-
// Wait for the API response
|
|
293
|
-
await page.waitForResponse(endpoint);
|
|
294
|
-
},
|
|
295
|
-
};
|