@koloseum/utils 0.2.15 → 0.2.16

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 CHANGED
@@ -250,6 +250,16 @@ export declare const Utility: {
250
250
  * @returns A sanitised string, or an empty string if the input is invalid
251
251
  */
252
252
  sanitiseHtml: (input: string) => string;
253
+ /**
254
+ * Sends a welcome notification to a user.
255
+ * @param {SupabaseClient<Database>} supabase - The Supabase client
256
+ * @param {UserWithCustomMetadata} user - The user to send the notification to
257
+ * @param {MicroserviceGroup} microserviceGroup - The microservice group the user belongs to
258
+ * @returns An object with an `error` if any has occurred
259
+ */
260
+ sendWelcomeNotification: (supabase: SupabaseClient<Database>, user: UserWithCustomMetadata, microserviceGroup: MicroserviceGroup) => Promise<{
261
+ error?: CustomError;
262
+ }>;
253
263
  /**
254
264
  * A regular expression for social media handles, without a leading slash or @ character.
255
265
  *
package/dist/utils.js CHANGED
@@ -703,6 +703,9 @@ export const Utility = {
703
703
  // Return true if microservice group is public
704
704
  if (microserviceGroup === "public")
705
705
  return { isAuthorised: true };
706
+ // Validate user metadata and app metadata
707
+ if (!user.user_metadata || !user.app_metadata)
708
+ return { error: Utility.customError(400, "User metadata is required.") };
706
709
  // Get user's roles and the role prefix
707
710
  const roles = [];
708
711
  const rolePrefix = microserviceGroup === "backroom" ? "backroom" : microserviceGroup.slice(0, -1);
@@ -748,43 +751,9 @@ export const Utility = {
748
751
  if (validationError)
749
752
  return { error: Utility.customError(code, validationError) };
750
753
  // Send welcome notification if needed
751
- if (!user.user_metadata.backroom || !user.user_metadata.backroom.welcome_notification_sent) {
752
- // Initialise backroom metadata if it doesn't exist
753
- if (!user.user_metadata.backroom) {
754
- // Update user metadata in database
755
- const { error: updateError } = await supabase.auth.updateUser({
756
- data: { backroom: { welcome_notification_sent: false } }
757
- });
758
- if (updateError)
759
- return { error: Utility.customError(updateError.status ?? 500, updateError.message) };
760
- // Update user object in memory
761
- user.user_metadata.backroom = { welcome_notification_sent: false };
762
- }
763
- // Define SuprSend workflow body
764
- const workflowBody = {
765
- name: "welcome-to-backroom",
766
- template: "welcome-to-backroom",
767
- notification_category: "system",
768
- users: [
769
- {
770
- distinct_id: user.id,
771
- $skip_create: true
772
- }
773
- ]
774
- };
775
- // Send welcome notification
776
- const { code, error: workflowError } = await Utility.callEdgeFunction(false, supabase, `suprsend/trigger-workflow?user-id=${user.id}`, { method: "POST", body: workflowBody });
777
- if (workflowError)
778
- return { error: Utility.customError(code, workflowError) };
779
- // Update user metadata in database
780
- const { error: updateError } = await supabase.auth.updateUser({
781
- data: { backroom: { welcome_notification_sent: true } }
782
- });
783
- if (updateError)
784
- return { error: Utility.customError(updateError.status ?? 500, updateError.message) };
785
- // Update user object in memory
786
- user.user_metadata.backroom.welcome_notification_sent = true;
787
- }
754
+ const { error: welcomeError } = await Utility.sendWelcomeNotification(supabase, user, microserviceGroup);
755
+ if (welcomeError)
756
+ return { error: welcomeError };
788
757
  // Return result
789
758
  return { isAuthorised };
790
759
  },
@@ -1357,6 +1326,67 @@ export const Utility = {
1357
1326
  * @returns A sanitised string, or an empty string if the input is invalid
1358
1327
  */
1359
1328
  sanitiseHtml: (input) => typeof input !== "string" ? "" : sanitize(input, { allowedTags: [], allowedAttributes: {} }),
1329
+ /**
1330
+ * Sends a welcome notification to a user.
1331
+ * @param {SupabaseClient<Database>} supabase - The Supabase client
1332
+ * @param {UserWithCustomMetadata} user - The user to send the notification to
1333
+ * @param {MicroserviceGroup} microserviceGroup - The microservice group the user belongs to
1334
+ * @returns An object with an `error` if any has occurred
1335
+ */
1336
+ sendWelcomeNotification: async (supabase, user, microserviceGroup) => {
1337
+ // Backroom
1338
+ if (microserviceGroup === "backroom" && !user.user_metadata.backroom?.welcome_notification_sent) {
1339
+ // Use atomic update with timestamp to prevent race conditions
1340
+ const currentTime = new Date().toISOString();
1341
+ const { data: updatedUser, error: updateError } = await supabase.auth.updateUser({
1342
+ data: {
1343
+ backroom: {
1344
+ ...user.user_metadata.backroom,
1345
+ welcome_notification_sent: true,
1346
+ welcome_notification_timestamp: currentTime
1347
+ }
1348
+ }
1349
+ });
1350
+ if (updateError)
1351
+ return { error: Utility.customError(updateError.status ?? 500, updateError.message) };
1352
+ // Only send notification if flag was successfully updated
1353
+ const updatedBackroom = updatedUser.user?.user_metadata?.backroom;
1354
+ if (updatedBackroom?.welcome_notification_sent === true &&
1355
+ updatedBackroom?.welcome_notification_timestamp === currentTime) {
1356
+ // Define SuprSend workflow body
1357
+ const workflowBody = {
1358
+ name: "welcome-to-backroom",
1359
+ template: "welcome-to-backroom",
1360
+ notification_category: "system",
1361
+ users: [
1362
+ {
1363
+ distinct_id: user.id,
1364
+ $skip_create: true
1365
+ }
1366
+ ]
1367
+ };
1368
+ // Send welcome notification
1369
+ const { code, error: workflowError } = await Utility.callEdgeFunction(false, supabase, `suprsend/trigger-workflow?user-id=${user.id}`, { method: "POST", body: workflowBody });
1370
+ // If notification fails, revert the flag and return error
1371
+ if (workflowError) {
1372
+ await supabase.auth.updateUser({
1373
+ data: {
1374
+ backroom: {
1375
+ ...user.user_metadata.backroom,
1376
+ welcome_notification_sent: false,
1377
+ welcome_notification_timestamp: undefined
1378
+ }
1379
+ }
1380
+ });
1381
+ return { error: Utility.customError(code, workflowError) };
1382
+ }
1383
+ // Update user object in memory
1384
+ user.user_metadata.backroom = updatedBackroom;
1385
+ }
1386
+ }
1387
+ // Return empty object
1388
+ return {};
1389
+ },
1360
1390
  /**
1361
1391
  * A regular expression for social media handles, without a leading slash or @ character.
1362
1392
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koloseum/utils",
3
- "version": "0.2.15",
3
+ "version": "0.2.16",
4
4
  "author": "Koloseum Technologies Limited",
5
5
  "type": "module",
6
6
  "description": "Utility logic for use across Koloseum web apps (TypeScript)",
@@ -38,7 +38,7 @@
38
38
  "validator": "^13.15.15"
39
39
  },
40
40
  "devDependencies": {
41
- "@koloseum/types": "^0.2.4",
41
+ "@koloseum/types": "^0.2.5",
42
42
  "@playwright/test": "^1.53.1",
43
43
  "@suprsend/web-components": "^0.2.1",
44
44
  "@types/sanitize-html": "^2.16.0",