@koloseum/utils 0.1.16 → 0.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.
- package/dist/utils.d.ts +53 -43
- package/dist/utils.js +432 -80
- package/package.json +14 -13
package/dist/utils.d.ts
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import type { Database } from "@koloseum/types/database";
|
|
2
|
-
import type { CustomError, Microservice, MicroserviceGroup, MicroserviceObject } from "@koloseum/types/general";
|
|
3
|
-
import type { PronounsCheckboxes, SocialMediaPlatform } from "@koloseum/types/public-auth";
|
|
2
|
+
import type { CustomError, Microservice, MicroserviceGroup, MicroserviceObject, UserWithCustomMetadata } from "@koloseum/types/general";
|
|
3
|
+
import type { IdentityType, PronounsCheckboxes, PronounsItem, Sex, SocialMediaPlatform } from "@koloseum/types/public-auth";
|
|
4
4
|
import type { Page } from "@sveltejs/kit";
|
|
5
|
-
import type { SupabaseClient, PostgrestError } from "@supabase/supabase-js";
|
|
6
|
-
import type { suprsend } from "@suprsend/node-sdk";
|
|
5
|
+
import type { SupabaseClient, FunctionInvokeOptions, PostgrestError } from "@supabase/supabase-js";
|
|
7
6
|
import type { IOptions } from "@suprsend/web-components/dist/types/interface.d.ts";
|
|
8
7
|
import type { MobilePhoneLocale } from "validator";
|
|
8
|
+
export declare const Data: {
|
|
9
|
+
/**
|
|
10
|
+
* A generic authenticated user.
|
|
11
|
+
* @param {string} id - The user ID; defaults to a random UUID
|
|
12
|
+
* @param {Date} date - The date and time; defaults to the current date and time
|
|
13
|
+
* @param {string} phone - The phone number; defaults to a generic Kenyan phone number
|
|
14
|
+
* @param {string} identityId - A default identity ID; defaults to a random UUID
|
|
15
|
+
* @returns A generic authenticated user.
|
|
16
|
+
*/
|
|
17
|
+
authenticatedUser: (id?: string, date?: Date, phone?: string, identityId?: string) => UserWithCustomMetadata;
|
|
18
|
+
};
|
|
9
19
|
export declare const Status: {
|
|
10
20
|
/**
|
|
11
21
|
* A generic error message.
|
|
@@ -26,10 +36,10 @@ export declare const Utility: {
|
|
|
26
36
|
* @param {boolean} browser - Whether the function is being called in the browser
|
|
27
37
|
* @param {SupabaseClient} supabase - The Supabase client
|
|
28
38
|
* @param {string} path - The path to the Edge function
|
|
29
|
-
* @param {
|
|
39
|
+
* @param {FunctionInvokeOptions} [options] - The options to use for the function invocation; defaults to `{ method: "GET" }`
|
|
30
40
|
* @returns The response from the Edge function
|
|
31
41
|
*/
|
|
32
|
-
callEdgeFunction: (browser: boolean, supabase: SupabaseClient<Database>, path: string,
|
|
42
|
+
callEdgeFunction: (browser: boolean, supabase: SupabaseClient<Database>, path: string, options?: FunctionInvokeOptions) => Promise<{
|
|
33
43
|
code: number;
|
|
34
44
|
data?: any;
|
|
35
45
|
error?: string;
|
|
@@ -41,6 +51,12 @@ export declare const Utility: {
|
|
|
41
51
|
* @returns The capitalised word
|
|
42
52
|
*/
|
|
43
53
|
capitalise: (word: string) => string;
|
|
54
|
+
/**
|
|
55
|
+
* Cleans a URL by removing the protocol and trailing slashes.
|
|
56
|
+
* @param {string} url - The URL to clean
|
|
57
|
+
* @returns {string} The cleaned URL
|
|
58
|
+
*/
|
|
59
|
+
cleanUrl: (url: string) => string;
|
|
44
60
|
/**
|
|
45
61
|
* Returns a custom error object.
|
|
46
62
|
* @param {number} code - The error code; defaults to `500` if not provided or invalid
|
|
@@ -74,30 +90,40 @@ export declare const Utility: {
|
|
|
74
90
|
*/
|
|
75
91
|
getAge: (dateOfBirth: string) => number;
|
|
76
92
|
/**
|
|
77
|
-
*
|
|
93
|
+
* Formats a date as a locale-specific string.
|
|
94
|
+
* @param {Date | string} date - Date to be formatted
|
|
95
|
+
* @param {boolean} withTime - Specify whether the date should include time; defaults to `false`
|
|
96
|
+
* @param {string} timeZone - The time zone to use for formatting; defaults to `Africa/Nairobi`
|
|
97
|
+
* @returns The formatted date string, or `null` if invalid input
|
|
98
|
+
*/
|
|
99
|
+
getDateString: (date: Date | string | null, withTime?: boolean, timeZone?: string) => string | null;
|
|
100
|
+
/**
|
|
101
|
+
* Formats an identity type for display.
|
|
102
|
+
* @param {IdentityType} identityType - The identity type to be formatted
|
|
103
|
+
* @returns The formatted identity type string
|
|
104
|
+
*/
|
|
105
|
+
getIdentityTypeString: (identityType: IdentityType) => string;
|
|
106
|
+
/**
|
|
107
|
+
* Returns a pronoun given pronouns and a type.
|
|
108
|
+
* @param {PronounsItem | null} pronouns - The pronouns to be formatted
|
|
109
|
+
* @param {"subject" | "object" | "possessive" | "reflexive"} type - The type of pronoun to be returned
|
|
110
|
+
* @param {Sex} sex - The user's sex; defaults to `undefined`
|
|
111
|
+
* @returns The formatted pronoun, or `null` if the input is invalid
|
|
112
|
+
*/
|
|
113
|
+
getPronoun: (pronouns: PronounsItem | null, type: "subject" | "object" | "possessive" | "reflexive", sex?: Sex) => string | null;
|
|
114
|
+
/**
|
|
115
|
+
* Generate a SuprSend notification inbox configuration object for a user.
|
|
78
116
|
* @param {string} userId - The user ID to generate the configuration for.
|
|
79
117
|
* @param {string} publicApiKey - The public API key to use for SuprSend.
|
|
80
|
-
* @returns The SuprSend configuration object.
|
|
118
|
+
* @returns The SuprSend notification inbox configuration object.
|
|
81
119
|
*/
|
|
82
|
-
|
|
120
|
+
getSuprSendInboxConfig: (userId: string, publicApiKey: string) => IOptions;
|
|
83
121
|
/**
|
|
84
122
|
* Handles the click event for pronouns checkboxes.
|
|
85
123
|
* @param {MouseEvent} e - The click event
|
|
86
124
|
* @param {PronounsCheckboxes} checkboxes - The pronouns checkboxes
|
|
87
125
|
*/
|
|
88
126
|
handlePronounsCheckboxClick: (e: MouseEvent, checkboxes: PronounsCheckboxes) => void;
|
|
89
|
-
/**
|
|
90
|
-
* A regular expression for Koloseum Lounge Branch IDs. It covers the following rules:
|
|
91
|
-
* - 9 characters long
|
|
92
|
-
* - begins with "KLB" followed by 7 digits
|
|
93
|
-
*/
|
|
94
|
-
loungeBranchIdRegex: RegExp;
|
|
95
|
-
/**
|
|
96
|
-
* A regular expression for Koloseum Lounge IDs. It covers the following rules:
|
|
97
|
-
* - 9 characters long
|
|
98
|
-
* - begins with "KL" followed by 7 digits
|
|
99
|
-
*/
|
|
100
|
-
loungeIdRegex: RegExp;
|
|
101
127
|
/**
|
|
102
128
|
* A reference of microservices available on the platform, represented as an object with each user group (i.e. `public`, `players`, `lounges`, and `backroom`) having its own array of microservices. Each microservice in a list is an object with the following properties:
|
|
103
129
|
* - `name`: The name of the microservice.
|
|
@@ -119,13 +145,13 @@ export declare const Utility: {
|
|
|
119
145
|
* @param base - The base path of the application; defaults to an empty string.
|
|
120
146
|
* @returns `true` if the page is active, `false` otherwise.
|
|
121
147
|
*/
|
|
122
|
-
pageIsActive: (page: Page, slug: string, microservice?: Microservice<MicroserviceGroup>, base?: string) => boolean;
|
|
148
|
+
pageIsActive: (page: Page, slug: string | undefined, microservice?: Microservice<MicroserviceGroup>, base?: string) => boolean;
|
|
123
149
|
/**
|
|
124
150
|
* Parses a `CustomError` object within a page/layout server load function and returns an error to be thrown.
|
|
125
151
|
* @param {CustomError} error - The error object
|
|
126
152
|
* @returns A new `Error` object if the error is unexpected, or a Svelte error otherwise
|
|
127
153
|
*/
|
|
128
|
-
parseLoadError: (error: CustomError) => Error;
|
|
154
|
+
parseLoadError: (error: CustomError) => Error | never;
|
|
129
155
|
/**
|
|
130
156
|
* Parses a `PostgrestError` object and returns a custom error object if any has occurred.
|
|
131
157
|
* @param {PostgrestError | null} postgrestError - The `PostgrestError` object, or `null` if no error occurred
|
|
@@ -144,11 +170,11 @@ export declare const Utility: {
|
|
|
144
170
|
*/
|
|
145
171
|
passwordRegex: RegExp;
|
|
146
172
|
/**
|
|
147
|
-
*
|
|
148
|
-
* -
|
|
149
|
-
*
|
|
173
|
+
* Returns a regular expression for a Koloseum platform ID.
|
|
174
|
+
* @param {string} type - The type of platform ID to return
|
|
175
|
+
* @returns A regular expression for the platform ID, or `null` if the type is invalid
|
|
150
176
|
*/
|
|
151
|
-
|
|
177
|
+
platformIdRegex: (type: "lounge" | "loungeBranch" | "player") => RegExp | null;
|
|
152
178
|
/**
|
|
153
179
|
* Sanitises any potential HTML injected into user input.
|
|
154
180
|
* @param {string} input - The input to be sanitised
|
|
@@ -174,20 +200,4 @@ export declare const Utility: {
|
|
|
174
200
|
* @returns `true` if the handle is valid; `false` otherwise
|
|
175
201
|
*/
|
|
176
202
|
validateSocialMediaHandle: (handle: string) => boolean;
|
|
177
|
-
/**
|
|
178
|
-
* Validates a SuprSend subscriber. If the subscriber does not exist, it will be created with the provided person data.
|
|
179
|
-
* @param {suprsend.Suprsend} suprSend - The SuprSend instance.
|
|
180
|
-
* @param {string} userId - The user ID.
|
|
181
|
-
* @param {Object} personData - The person data; required if the subscriber does not exist.
|
|
182
|
-
* @returns {Promise<{ error?: CustomError; success?: true }>} A promise that resolves to an object with an error if the subscriber validation fails, or indicating success otherwise.
|
|
183
|
-
*/
|
|
184
|
-
validateSuprSendSubscriber: (suprSend: suprsend.Suprsend, userId: string, personData?: {
|
|
185
|
-
firstName: string;
|
|
186
|
-
lastName: string;
|
|
187
|
-
phone: string;
|
|
188
|
-
pseudonym?: string;
|
|
189
|
-
}) => Promise<{
|
|
190
|
-
error?: CustomError;
|
|
191
|
-
success?: true;
|
|
192
|
-
}>;
|
|
193
203
|
};
|
package/dist/utils.js
CHANGED
|
@@ -1,9 +1,73 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from "uuid";
|
|
1
2
|
import { error as svelteError } from "@sveltejs/kit";
|
|
2
3
|
import { FunctionsFetchError, FunctionsHttpError, FunctionsRelayError } from "@supabase/supabase-js";
|
|
3
4
|
import sanitize from "sanitize-html";
|
|
4
5
|
import validator from "validator";
|
|
5
6
|
/* Helper functions */
|
|
6
7
|
const { isMobilePhone, isURL } = validator;
|
|
8
|
+
/* Dummy data */
|
|
9
|
+
export const Data = {
|
|
10
|
+
/**
|
|
11
|
+
* A generic authenticated user.
|
|
12
|
+
* @param {string} id - The user ID; defaults to a random UUID
|
|
13
|
+
* @param {Date} date - The date and time; defaults to the current date and time
|
|
14
|
+
* @param {string} phone - The phone number; defaults to a generic Kenyan phone number
|
|
15
|
+
* @param {string} identityId - A default identity ID; defaults to a random UUID
|
|
16
|
+
* @returns A generic authenticated user.
|
|
17
|
+
*/
|
|
18
|
+
authenticatedUser: (id = uuidv4(), date = new Date(), phone = "254111222333", identityId = uuidv4()) => {
|
|
19
|
+
// Convert date to ISO string
|
|
20
|
+
const time = date.toISOString();
|
|
21
|
+
// User data
|
|
22
|
+
return {
|
|
23
|
+
id,
|
|
24
|
+
aud: "authenticated",
|
|
25
|
+
role: "authenticated",
|
|
26
|
+
email: "",
|
|
27
|
+
phone,
|
|
28
|
+
phone_confirmed_at: time,
|
|
29
|
+
confirmation_sent_at: time,
|
|
30
|
+
confirmed_at: time,
|
|
31
|
+
last_sign_in_at: time,
|
|
32
|
+
app_metadata: {
|
|
33
|
+
person_data: { first_name: "John", last_name: "Test", pseudonym: "JDtest" },
|
|
34
|
+
provider: "phone",
|
|
35
|
+
providers: ["phone"],
|
|
36
|
+
roles: ["player", "backroom_superuser"]
|
|
37
|
+
},
|
|
38
|
+
user_metadata: {
|
|
39
|
+
email_verified: false,
|
|
40
|
+
phone_verified: false,
|
|
41
|
+
sub: id,
|
|
42
|
+
backroom: {
|
|
43
|
+
welcome_notification_sent: true
|
|
44
|
+
},
|
|
45
|
+
players: {
|
|
46
|
+
welcome_notification_sent: true
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
identities: [
|
|
50
|
+
{
|
|
51
|
+
identity_id: identityId,
|
|
52
|
+
id,
|
|
53
|
+
user_id: id,
|
|
54
|
+
identity_data: {
|
|
55
|
+
email_verified: false,
|
|
56
|
+
phone_verified: false,
|
|
57
|
+
sub: id
|
|
58
|
+
},
|
|
59
|
+
provider: "phone",
|
|
60
|
+
last_sign_in_at: time,
|
|
61
|
+
created_at: time,
|
|
62
|
+
updated_at: time
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
created_at: time,
|
|
66
|
+
updated_at: time,
|
|
67
|
+
is_anonymous: false
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
};
|
|
7
71
|
/* Status messages */
|
|
8
72
|
export const Status = {
|
|
9
73
|
/**
|
|
@@ -26,31 +90,25 @@ export const Utility = {
|
|
|
26
90
|
* @param {boolean} browser - Whether the function is being called in the browser
|
|
27
91
|
* @param {SupabaseClient} supabase - The Supabase client
|
|
28
92
|
* @param {string} path - The path to the Edge function
|
|
29
|
-
* @param {
|
|
93
|
+
* @param {FunctionInvokeOptions} [options] - The options to use for the function invocation; defaults to `{ method: "GET" }`
|
|
30
94
|
* @returns The response from the Edge function
|
|
31
95
|
*/
|
|
32
|
-
callEdgeFunction: async (browser, supabase, path,
|
|
96
|
+
callEdgeFunction: async (browser, supabase, path, options = { method: "GET" }) => {
|
|
33
97
|
try {
|
|
34
|
-
// Set up headers with safe origin handling for SSR
|
|
35
|
-
const headers = {
|
|
36
|
-
"Content-Type": "application/json",
|
|
37
|
-
Accept: "application/json"
|
|
38
|
-
};
|
|
39
98
|
// Only add Origin header in browser environment
|
|
40
99
|
if (browser)
|
|
41
|
-
headers
|
|
100
|
+
options.headers = { ...options.headers, Origin: window.location.origin };
|
|
42
101
|
// Fetch response with additional options for better cross-origin handling
|
|
43
|
-
const { data, error } = await supabase.functions.invoke(path,
|
|
44
|
-
method,
|
|
45
|
-
headers
|
|
46
|
-
});
|
|
102
|
+
const { data, error } = await supabase.functions.invoke(path, options);
|
|
47
103
|
// Handle different error types
|
|
48
104
|
if (error) {
|
|
49
105
|
// Define context
|
|
50
106
|
const context = {};
|
|
51
107
|
// Define error code and message
|
|
52
108
|
const code = Number(error.context.status) || 500;
|
|
53
|
-
let message =
|
|
109
|
+
let message = error.context.statusText === "Internal Server Error"
|
|
110
|
+
? Status.ERROR
|
|
111
|
+
: error.context.statusText || Status.ERROR;
|
|
54
112
|
// Handle HTTP errors
|
|
55
113
|
if (error instanceof FunctionsHttpError) {
|
|
56
114
|
// Get error data
|
|
@@ -74,8 +132,8 @@ export const Utility = {
|
|
|
74
132
|
if (path.includes("verify-id") && data.attemptId)
|
|
75
133
|
context.attemptId = data.attemptId;
|
|
76
134
|
}
|
|
77
|
-
catch
|
|
78
|
-
|
|
135
|
+
catch {
|
|
136
|
+
return { code: 500, error: Status.ERROR };
|
|
79
137
|
}
|
|
80
138
|
}
|
|
81
139
|
// Handle relay and fetch errors
|
|
@@ -87,7 +145,7 @@ export const Utility = {
|
|
|
87
145
|
// Return response
|
|
88
146
|
return { code: 200, data };
|
|
89
147
|
}
|
|
90
|
-
catch
|
|
148
|
+
catch {
|
|
91
149
|
return { code: 500, error: Status.ERROR };
|
|
92
150
|
}
|
|
93
151
|
},
|
|
@@ -102,6 +160,12 @@ export const Utility = {
|
|
|
102
160
|
.split("")
|
|
103
161
|
.map((c) => c.toLowerCase())
|
|
104
162
|
.join(""),
|
|
163
|
+
/**
|
|
164
|
+
* Cleans a URL by removing the protocol and trailing slashes.
|
|
165
|
+
* @param {string} url - The URL to clean
|
|
166
|
+
* @returns {string} The cleaned URL
|
|
167
|
+
*/
|
|
168
|
+
cleanUrl: (url) => url.replace(/^https?:\/\//, "").replace(/\/+$/, ""),
|
|
105
169
|
/**
|
|
106
170
|
* Returns a custom error object.
|
|
107
171
|
* @param {number} code - The error code; defaults to `500` if not provided or invalid
|
|
@@ -143,7 +207,7 @@ export const Utility = {
|
|
|
143
207
|
return formattedDate;
|
|
144
208
|
}
|
|
145
209
|
catch (error) {
|
|
146
|
-
console.
|
|
210
|
+
console.error(error);
|
|
147
211
|
return null;
|
|
148
212
|
}
|
|
149
213
|
},
|
|
@@ -180,12 +244,157 @@ export const Utility = {
|
|
|
180
244
|
return monthDiff < 0 || (monthDiff === 0 && currentDate.getDate() < birthDate.getDate()) ? --age : age;
|
|
181
245
|
},
|
|
182
246
|
/**
|
|
183
|
-
*
|
|
247
|
+
* Formats a date as a locale-specific string.
|
|
248
|
+
* @param {Date | string} date - Date to be formatted
|
|
249
|
+
* @param {boolean} withTime - Specify whether the date should include time; defaults to `false`
|
|
250
|
+
* @param {string} timeZone - The time zone to use for formatting; defaults to `Africa/Nairobi`
|
|
251
|
+
* @returns The formatted date string, or `null` if invalid input
|
|
252
|
+
*/
|
|
253
|
+
getDateString: (date, withTime = false, timeZone = "Africa/Nairobi") => {
|
|
254
|
+
// Return null if no date is provided
|
|
255
|
+
if (!date)
|
|
256
|
+
return null;
|
|
257
|
+
// Validate date to format
|
|
258
|
+
let dateToFormat;
|
|
259
|
+
if (typeof date === "string") {
|
|
260
|
+
if (date === "" || isNaN(Date.parse(date)))
|
|
261
|
+
return null;
|
|
262
|
+
dateToFormat = new Date(date);
|
|
263
|
+
}
|
|
264
|
+
else if (date instanceof Date) {
|
|
265
|
+
if (isNaN(date.getTime()))
|
|
266
|
+
return null;
|
|
267
|
+
dateToFormat = date;
|
|
268
|
+
}
|
|
269
|
+
else
|
|
270
|
+
return null;
|
|
271
|
+
// Format date
|
|
272
|
+
return dateToFormat.toLocaleString("en-KE", {
|
|
273
|
+
timeZone,
|
|
274
|
+
year: "numeric",
|
|
275
|
+
month: "long",
|
|
276
|
+
day: "numeric",
|
|
277
|
+
hour: withTime ? "numeric" : undefined,
|
|
278
|
+
minute: withTime ? "2-digit" : undefined,
|
|
279
|
+
hour12: withTime ? true : undefined
|
|
280
|
+
});
|
|
281
|
+
},
|
|
282
|
+
/**
|
|
283
|
+
* Formats an identity type for display.
|
|
284
|
+
* @param {IdentityType} identityType - The identity type to be formatted
|
|
285
|
+
* @returns The formatted identity type string
|
|
286
|
+
*/
|
|
287
|
+
getIdentityTypeString: (identityType) => {
|
|
288
|
+
if (identityType === "national")
|
|
289
|
+
return "National ID";
|
|
290
|
+
if (identityType === "alien")
|
|
291
|
+
return "Alien ID";
|
|
292
|
+
if (identityType === "passport")
|
|
293
|
+
return "Passport";
|
|
294
|
+
if (identityType === "driver_licence")
|
|
295
|
+
return "Driver's licence";
|
|
296
|
+
return "";
|
|
297
|
+
},
|
|
298
|
+
/**
|
|
299
|
+
* Returns a pronoun given pronouns and a type.
|
|
300
|
+
* @param {PronounsItem | null} pronouns - The pronouns to be formatted
|
|
301
|
+
* @param {"subject" | "object" | "possessive" | "reflexive"} type - The type of pronoun to be returned
|
|
302
|
+
* @param {Sex} sex - The user's sex; defaults to `undefined`
|
|
303
|
+
* @returns The formatted pronoun, or `null` if the input is invalid
|
|
304
|
+
*/
|
|
305
|
+
getPronoun: (pronouns, type, sex) => {
|
|
306
|
+
// Get pronoun from pronouns item
|
|
307
|
+
if (pronouns) {
|
|
308
|
+
// Return subject pronoun
|
|
309
|
+
if (type === "subject") {
|
|
310
|
+
if (pronouns === "he/him/his/himself")
|
|
311
|
+
return "he";
|
|
312
|
+
if (pronouns === "she/her/hers/herself")
|
|
313
|
+
return "she";
|
|
314
|
+
if (pronouns === "they/them/their/themself")
|
|
315
|
+
return "they";
|
|
316
|
+
if (pronouns === "name_only")
|
|
317
|
+
return "";
|
|
318
|
+
}
|
|
319
|
+
// Return object pronoun
|
|
320
|
+
else if (type === "object") {
|
|
321
|
+
if (pronouns === "he/him/his/himself")
|
|
322
|
+
return "him";
|
|
323
|
+
if (pronouns === "she/her/hers/herself")
|
|
324
|
+
return "her";
|
|
325
|
+
if (pronouns === "they/them/their/themself")
|
|
326
|
+
return "them";
|
|
327
|
+
if (pronouns === "name_only")
|
|
328
|
+
return "";
|
|
329
|
+
}
|
|
330
|
+
// Return possessive pronoun
|
|
331
|
+
else if (type === "possessive") {
|
|
332
|
+
if (pronouns === "he/him/his/himself")
|
|
333
|
+
return "his";
|
|
334
|
+
if (pronouns === "she/her/hers/herself")
|
|
335
|
+
return "her";
|
|
336
|
+
if (pronouns === "they/them/their/themself")
|
|
337
|
+
return "their";
|
|
338
|
+
if (pronouns === "name_only")
|
|
339
|
+
return "";
|
|
340
|
+
}
|
|
341
|
+
// Return reflexive pronoun
|
|
342
|
+
else if (type === "reflexive") {
|
|
343
|
+
if (pronouns === "he/him/his/himself")
|
|
344
|
+
return "himself";
|
|
345
|
+
if (pronouns === "she/her/hers/herself")
|
|
346
|
+
return "herself";
|
|
347
|
+
if (pronouns === "they/them/their/themself")
|
|
348
|
+
return "themself";
|
|
349
|
+
if (pronouns === "name_only")
|
|
350
|
+
return "";
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
// Assume pronoun for sex if no pronouns are provided
|
|
354
|
+
else if (sex) {
|
|
355
|
+
// Return subject pronoun
|
|
356
|
+
if (type === "subject") {
|
|
357
|
+
if (sex === "male" || sex === "intersex_man")
|
|
358
|
+
return "he";
|
|
359
|
+
if (sex === "female" || sex === "intersex_woman")
|
|
360
|
+
return "she";
|
|
361
|
+
return "they";
|
|
362
|
+
}
|
|
363
|
+
// Return object pronoun
|
|
364
|
+
else if (type === "object") {
|
|
365
|
+
if (sex === "male" || sex === "intersex_man")
|
|
366
|
+
return "him";
|
|
367
|
+
if (sex === "female" || sex === "intersex_woman")
|
|
368
|
+
return "her";
|
|
369
|
+
return "them";
|
|
370
|
+
}
|
|
371
|
+
// Return possessive pronoun
|
|
372
|
+
else if (type === "possessive") {
|
|
373
|
+
if (sex === "male" || sex === "intersex_man")
|
|
374
|
+
return "his";
|
|
375
|
+
if (sex === "female" || sex === "intersex_woman")
|
|
376
|
+
return "her";
|
|
377
|
+
return "their";
|
|
378
|
+
}
|
|
379
|
+
// Return reflexive pronoun
|
|
380
|
+
else if (type === "reflexive") {
|
|
381
|
+
if (sex === "male" || sex === "intersex_man")
|
|
382
|
+
return "himself";
|
|
383
|
+
if (sex === "female" || sex === "intersex_woman")
|
|
384
|
+
return "herself";
|
|
385
|
+
return "themself";
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
// Return null
|
|
389
|
+
return null;
|
|
390
|
+
},
|
|
391
|
+
/**
|
|
392
|
+
* Generate a SuprSend notification inbox configuration object for a user.
|
|
184
393
|
* @param {string} userId - The user ID to generate the configuration for.
|
|
185
394
|
* @param {string} publicApiKey - The public API key to use for SuprSend.
|
|
186
|
-
* @returns The SuprSend configuration object.
|
|
395
|
+
* @returns The SuprSend notification inbox configuration object.
|
|
187
396
|
*/
|
|
188
|
-
|
|
397
|
+
getSuprSendInboxConfig: (userId, publicApiKey) => ({
|
|
189
398
|
distinctId: userId,
|
|
190
399
|
publicApiKey,
|
|
191
400
|
inbox: {
|
|
@@ -372,18 +581,6 @@ export const Utility = {
|
|
|
372
581
|
}
|
|
373
582
|
}
|
|
374
583
|
},
|
|
375
|
-
/**
|
|
376
|
-
* A regular expression for Koloseum Lounge Branch IDs. It covers the following rules:
|
|
377
|
-
* - 9 characters long
|
|
378
|
-
* - begins with "KLB" followed by 7 digits
|
|
379
|
-
*/
|
|
380
|
-
loungeBranchIdRegex: /^KLB\d{7}$/,
|
|
381
|
-
/**
|
|
382
|
-
* A regular expression for Koloseum Lounge IDs. It covers the following rules:
|
|
383
|
-
* - 9 characters long
|
|
384
|
-
* - begins with "KL" followed by 7 digits
|
|
385
|
-
*/
|
|
386
|
-
loungeIdRegex: /^KL\d{7}$/,
|
|
387
584
|
/**
|
|
388
585
|
* A reference of microservices available on the platform, represented as an object with each user group (i.e. `public`, `players`, `lounges`, and `backroom`) having its own array of microservices. Each microservice in a list is an object with the following properties:
|
|
389
586
|
* - `name`: The name of the microservice.
|
|
@@ -401,13 +598,186 @@ export const Utility = {
|
|
|
401
598
|
features: [
|
|
402
599
|
{
|
|
403
600
|
name: "Players",
|
|
404
|
-
description: "
|
|
405
|
-
slug: "players"
|
|
601
|
+
description: "Search, review, and manage Player data.",
|
|
602
|
+
slug: "players",
|
|
603
|
+
tabs: [
|
|
604
|
+
{
|
|
605
|
+
name: "Profile",
|
|
606
|
+
description: "Review basic Player data.",
|
|
607
|
+
root: true
|
|
608
|
+
},
|
|
609
|
+
{
|
|
610
|
+
name: "Documents",
|
|
611
|
+
description: "Review Player documents.",
|
|
612
|
+
slug: "documents"
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
name: "Data updates",
|
|
616
|
+
description: "Review Player data updates.",
|
|
617
|
+
slug: "data-updates",
|
|
618
|
+
tabs: [
|
|
619
|
+
{
|
|
620
|
+
name: "Requests",
|
|
621
|
+
description: "Review Player data update requests.",
|
|
622
|
+
root: true
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
name: "History",
|
|
626
|
+
description: "Review Player data update history.",
|
|
627
|
+
slug: "history"
|
|
628
|
+
}
|
|
629
|
+
]
|
|
630
|
+
},
|
|
631
|
+
{
|
|
632
|
+
name: "Credits",
|
|
633
|
+
description: "Review Koloseum Credits data for the Player.",
|
|
634
|
+
slug: "credits",
|
|
635
|
+
tabs: [
|
|
636
|
+
{
|
|
637
|
+
name: "Transactions",
|
|
638
|
+
description: "Review Player transactions with Koloseum Credits.",
|
|
639
|
+
root: true
|
|
640
|
+
},
|
|
641
|
+
{
|
|
642
|
+
name: "Transfers",
|
|
643
|
+
description: "Review Player transfers with Koloseum Credits.",
|
|
644
|
+
slug: "transfers"
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
name: "Subscriptions",
|
|
648
|
+
description: "Review Player subscriptions with Koloseum Credits.",
|
|
649
|
+
slug: "subscriptions"
|
|
650
|
+
}
|
|
651
|
+
]
|
|
652
|
+
},
|
|
653
|
+
{
|
|
654
|
+
name: "Misconduct",
|
|
655
|
+
description: "Review Player reports and sanctions.",
|
|
656
|
+
slug: "misconduct",
|
|
657
|
+
tabs: [
|
|
658
|
+
{
|
|
659
|
+
name: "Reports",
|
|
660
|
+
description: "Review Player reports.",
|
|
661
|
+
root: true
|
|
662
|
+
},
|
|
663
|
+
{
|
|
664
|
+
name: "Sanctions",
|
|
665
|
+
description: "Review Player sanctions.",
|
|
666
|
+
slug: "sanctions"
|
|
667
|
+
}
|
|
668
|
+
]
|
|
669
|
+
},
|
|
670
|
+
{
|
|
671
|
+
name: "Points / KXP",
|
|
672
|
+
description: "Review Koloseum Experience Points (KXP) transactions for the Player.",
|
|
673
|
+
slug: "points"
|
|
674
|
+
}
|
|
675
|
+
]
|
|
406
676
|
},
|
|
407
677
|
{
|
|
408
678
|
name: "Lounges",
|
|
409
|
-
description: "
|
|
410
|
-
slug: "lounges"
|
|
679
|
+
description: "Search, review, and manage Lounge data.",
|
|
680
|
+
slug: "lounges",
|
|
681
|
+
tabs: [
|
|
682
|
+
{
|
|
683
|
+
name: "Profile",
|
|
684
|
+
description: "Review basic Lounge data.",
|
|
685
|
+
root: true
|
|
686
|
+
},
|
|
687
|
+
{
|
|
688
|
+
name: "Documents",
|
|
689
|
+
description: "Review Lounge documents.",
|
|
690
|
+
slug: "documents"
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
name: "Staff",
|
|
694
|
+
description: "Search, review, and manage Lounge staff data.",
|
|
695
|
+
slug: "staff"
|
|
696
|
+
},
|
|
697
|
+
{
|
|
698
|
+
name: "Branches",
|
|
699
|
+
description: "Review Lounge branches.",
|
|
700
|
+
slug: "branches",
|
|
701
|
+
tabs: [
|
|
702
|
+
{
|
|
703
|
+
name: "Profile",
|
|
704
|
+
description: "Review basic Lounge branch data.",
|
|
705
|
+
root: true
|
|
706
|
+
},
|
|
707
|
+
{
|
|
708
|
+
name: "Amenities",
|
|
709
|
+
description: "Review Lounge branch amenities.",
|
|
710
|
+
slug: "amenities"
|
|
711
|
+
},
|
|
712
|
+
{
|
|
713
|
+
name: "Staff",
|
|
714
|
+
description: "Search, review, and manage Lounge branchstaff data.",
|
|
715
|
+
slug: "staff"
|
|
716
|
+
}
|
|
717
|
+
]
|
|
718
|
+
},
|
|
719
|
+
{
|
|
720
|
+
name: "Data updates",
|
|
721
|
+
description: "Review Lounge data updates.",
|
|
722
|
+
slug: "data-updates",
|
|
723
|
+
tabs: [
|
|
724
|
+
{
|
|
725
|
+
name: "Requests",
|
|
726
|
+
description: "Review Lounge data update requests.",
|
|
727
|
+
root: true
|
|
728
|
+
},
|
|
729
|
+
{
|
|
730
|
+
name: "History",
|
|
731
|
+
description: "Review Lounge data update history.",
|
|
732
|
+
slug: "history"
|
|
733
|
+
}
|
|
734
|
+
]
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
name: "Credits",
|
|
738
|
+
description: "Review Koloseum Credits data for the Lounge.",
|
|
739
|
+
slug: "credits",
|
|
740
|
+
tabs: [
|
|
741
|
+
{
|
|
742
|
+
name: "Transactions",
|
|
743
|
+
description: "Review Lounge transactions with Koloseum Credits.",
|
|
744
|
+
root: true
|
|
745
|
+
},
|
|
746
|
+
{
|
|
747
|
+
name: "Transfers",
|
|
748
|
+
description: "Review Lounge transfers with Koloseum Credits.",
|
|
749
|
+
slug: "transfers"
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
name: "Subscriptions",
|
|
753
|
+
description: "Review Lounge subscriptions with Koloseum Credits.",
|
|
754
|
+
slug: "subscriptions"
|
|
755
|
+
}
|
|
756
|
+
]
|
|
757
|
+
},
|
|
758
|
+
{
|
|
759
|
+
name: "Misconduct",
|
|
760
|
+
description: "Review Lounge reports and sanctions.",
|
|
761
|
+
slug: "misconduct",
|
|
762
|
+
tabs: [
|
|
763
|
+
{
|
|
764
|
+
name: "Reports",
|
|
765
|
+
description: "Review Lounge reports.",
|
|
766
|
+
root: true
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
name: "Sanctions",
|
|
770
|
+
description: "Review Lounge sanctions.",
|
|
771
|
+
slug: "sanctions"
|
|
772
|
+
}
|
|
773
|
+
]
|
|
774
|
+
},
|
|
775
|
+
{
|
|
776
|
+
name: "Points / KXP",
|
|
777
|
+
description: "Review Koloseum Experience Points (KXP) transactions for the Lounge.",
|
|
778
|
+
slug: "points"
|
|
779
|
+
}
|
|
780
|
+
]
|
|
411
781
|
}
|
|
412
782
|
],
|
|
413
783
|
roles: [
|
|
@@ -584,7 +954,19 @@ export const Utility = {
|
|
|
584
954
|
* @param base - The base path of the application; defaults to an empty string.
|
|
585
955
|
* @returns `true` if the page is active, `false` otherwise.
|
|
586
956
|
*/
|
|
587
|
-
pageIsActive: (page, slug, microservice, base = "") =>
|
|
957
|
+
pageIsActive: (page, slug, microservice, base = "") => {
|
|
958
|
+
// Return true if microservice is provided and matches slug
|
|
959
|
+
if (microservice)
|
|
960
|
+
return slug === microservice;
|
|
961
|
+
// Remove trailing slash from base for consistency
|
|
962
|
+
const cleanBase = base.replace(/\/$/, "");
|
|
963
|
+
// Match exactly the base path if slug is falsy (i.e. root microservice feature)
|
|
964
|
+
if (!slug)
|
|
965
|
+
return page.url.pathname === cleanBase || page.url.pathname === `${cleanBase}/`;
|
|
966
|
+
// Match exact or subpath otherwise
|
|
967
|
+
const target = `${cleanBase}/${slug}`;
|
|
968
|
+
return page.url.pathname === target || page.url.pathname.startsWith(`${target}/`);
|
|
969
|
+
},
|
|
588
970
|
/**
|
|
589
971
|
* Parses a `CustomError` object within a page/layout server load function and returns an error to be thrown.
|
|
590
972
|
* @param {CustomError} error - The error object
|
|
@@ -659,11 +1041,19 @@ export const Utility = {
|
|
|
659
1041
|
*/
|
|
660
1042
|
passwordRegex: /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()-_+=|{}[\]:;'<>,.?/~]).{8,}$/,
|
|
661
1043
|
/**
|
|
662
|
-
*
|
|
663
|
-
* -
|
|
664
|
-
*
|
|
1044
|
+
* Returns a regular expression for a Koloseum platform ID.
|
|
1045
|
+
* @param {string} type - The type of platform ID to return
|
|
1046
|
+
* @returns A regular expression for the platform ID, or `null` if the type is invalid
|
|
665
1047
|
*/
|
|
666
|
-
|
|
1048
|
+
platformIdRegex: (type) => {
|
|
1049
|
+
if (type === "lounge")
|
|
1050
|
+
return /^KL\d{7}$/;
|
|
1051
|
+
if (type === "loungeBranch")
|
|
1052
|
+
return /^KLB\d{7}$/;
|
|
1053
|
+
if (type === "player")
|
|
1054
|
+
return /^KP\d{7}$/;
|
|
1055
|
+
return null;
|
|
1056
|
+
},
|
|
667
1057
|
/**
|
|
668
1058
|
* Sanitises any potential HTML injected into user input.
|
|
669
1059
|
* @param {string} input - The input to be sanitised
|
|
@@ -690,43 +1080,5 @@ export const Utility = {
|
|
|
690
1080
|
*/
|
|
691
1081
|
validateSocialMediaHandle: (handle) => !isURL(handle, { require_protocol: false }) &&
|
|
692
1082
|
!handle.startsWith("@") &&
|
|
693
|
-
Boolean(handle.match(Utility.socialMediaHandleRegex))
|
|
694
|
-
/**
|
|
695
|
-
* Validates a SuprSend subscriber. If the subscriber does not exist, it will be created with the provided person data.
|
|
696
|
-
* @param {suprsend.Suprsend} suprSend - The SuprSend instance.
|
|
697
|
-
* @param {string} userId - The user ID.
|
|
698
|
-
* @param {Object} personData - The person data; required if the subscriber does not exist.
|
|
699
|
-
* @returns {Promise<{ error?: CustomError; success?: true }>} A promise that resolves to an object with an error if the subscriber validation fails, or indicating success otherwise.
|
|
700
|
-
*/
|
|
701
|
-
validateSuprSendSubscriber: async (suprSend, userId, personData) => {
|
|
702
|
-
// Check if subscriber exists
|
|
703
|
-
try {
|
|
704
|
-
await suprSend.users.get(userId);
|
|
705
|
-
}
|
|
706
|
-
catch (_err) {
|
|
707
|
-
// If person data is not provided, return an error
|
|
708
|
-
if (!personData)
|
|
709
|
-
return { error: Utility.customError(400, "Person data is required to create a SuprSend subscriber.") };
|
|
710
|
-
// Destructure person data
|
|
711
|
-
const { firstName, lastName, phone, pseudonym } = personData;
|
|
712
|
-
// Create subscriber
|
|
713
|
-
const subscriber = suprSend.user.get_instance(userId);
|
|
714
|
-
if (!subscriber)
|
|
715
|
-
return { error: Utility.customError(500, Status.ERROR) };
|
|
716
|
-
// Set subscriber details
|
|
717
|
-
subscriber.set_preferred_language("en");
|
|
718
|
-
subscriber.set_timezone("Africa/Nairobi");
|
|
719
|
-
subscriber.set("firstName", firstName);
|
|
720
|
-
subscriber.set("lastName", lastName);
|
|
721
|
-
subscriber.set("phone", `+${phone}`);
|
|
722
|
-
if (pseudonym)
|
|
723
|
-
subscriber.set("pseudonym", pseudonym);
|
|
724
|
-
// Save subscriber
|
|
725
|
-
const response = await subscriber.save();
|
|
726
|
-
if (!response.success)
|
|
727
|
-
return { error: Utility.customError(500, Status.ERROR) };
|
|
728
|
-
}
|
|
729
|
-
// Return success
|
|
730
|
-
return { success: true };
|
|
731
|
-
}
|
|
1083
|
+
Boolean(handle.match(Utility.socialMediaHandleRegex))
|
|
732
1084
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koloseum/utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"author": "Koloseum Technologies Limited",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Utility logic for use across Koloseum web apps (TypeScript)",
|
|
@@ -29,20 +29,21 @@
|
|
|
29
29
|
"test": "vitest --run"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@supabase/supabase-js": "^2.
|
|
33
|
-
"@sveltejs/kit": "^2.
|
|
34
|
-
"sanitize-html": "^2.
|
|
35
|
-
"
|
|
32
|
+
"@supabase/supabase-js": "^2.50.1",
|
|
33
|
+
"@sveltejs/kit": "^2.22.0",
|
|
34
|
+
"sanitize-html": "^2.17.0",
|
|
35
|
+
"uuid": "^11.1.0",
|
|
36
|
+
"validator": "^13.15.15"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
|
-
"@koloseum/types": "^0.
|
|
39
|
-
"@playwright/test": "^1.
|
|
40
|
-
"@suprsend/node-sdk": "^1.13.0",
|
|
39
|
+
"@koloseum/types": "^0.2.0",
|
|
40
|
+
"@playwright/test": "^1.53.1",
|
|
41
41
|
"@suprsend/web-components": "^0.2.1",
|
|
42
|
-
"@types/sanitize-html": "^2.
|
|
43
|
-
"@types/
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
42
|
+
"@types/sanitize-html": "^2.16.0",
|
|
43
|
+
"@types/uuid": "^10.0.0",
|
|
44
|
+
"@types/validator": "^13.15.2",
|
|
45
|
+
"prettier": "^3.6.0",
|
|
46
|
+
"typescript": "^5.8.3",
|
|
47
|
+
"vitest": "^3.2.4"
|
|
47
48
|
}
|
|
48
49
|
}
|