@koloseum/utils 0.2.0 → 0.2.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.
package/dist/utils.d.ts CHANGED
@@ -34,7 +34,7 @@ export declare const Utility: {
34
34
  /**
35
35
  * Calls a Supabase Edge function.
36
36
  * @param {boolean} browser - Whether the function is being called in the browser
37
- * @param {SupabaseClient} supabase - The Supabase client
37
+ * @param {SupabaseClient<Database>} supabase - The Supabase client
38
38
  * @param {string} path - The path to the Edge function
39
39
  * @param {FunctionInvokeOptions} [options] - The options to use for the function invocation; defaults to `{ method: "GET" }`
40
40
  * @returns The response from the Edge function
@@ -124,6 +124,30 @@ export declare const Utility: {
124
124
  * @param {PronounsCheckboxes} checkboxes - The pronouns checkboxes
125
125
  */
126
126
  handlePronounsCheckboxClick: (e: MouseEvent, checkboxes: PronounsCheckboxes) => void;
127
+ /**
128
+ * Checks if a user is authorised to access a microservice.
129
+ * @param {SupabaseClient<Database>} supabase - The Supabase client.
130
+ * @param {UserWithCustomMetadata} user - The user to check.
131
+ * @param {Object} options - The options for the function.
132
+ * @param {MicroserviceGroup} options.microserviceGroup - The microservice group.
133
+ * @param {Microservice<MicroserviceGroup> | string} options.microservice - The microservice.
134
+ * @param {string} options.playersUrl - The URL to the Players microservice.
135
+ * @param {(role: string) => string} options.requestedPermission - A function that returns the requested permission for a given role.
136
+ * @returns {Promise<{ isAuthorised?: boolean; redirect?: { code: number; url: string }; error?: CustomError }>} The result of the function.
137
+ */
138
+ isUserAuthorised: (supabase: SupabaseClient<Database>, user: UserWithCustomMetadata, options: {
139
+ microserviceGroup: MicroserviceGroup;
140
+ microservice: Microservice<MicroserviceGroup> | string;
141
+ playersUrl: string;
142
+ requestedPermission: (role: string) => string;
143
+ }) => Promise<{
144
+ isAuthorised?: boolean;
145
+ redirect?: {
146
+ code: number;
147
+ url: string;
148
+ };
149
+ error?: CustomError;
150
+ }>;
127
151
  /**
128
152
  * 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:
129
153
  * - `name`: The name of the microservice.
package/dist/utils.js CHANGED
@@ -88,7 +88,7 @@ export const Utility = {
88
88
  /**
89
89
  * Calls a Supabase Edge function.
90
90
  * @param {boolean} browser - Whether the function is being called in the browser
91
- * @param {SupabaseClient} supabase - The Supabase client
91
+ * @param {SupabaseClient<Database>} supabase - The Supabase client
92
92
  * @param {string} path - The path to the Edge function
93
93
  * @param {FunctionInvokeOptions} [options] - The options to use for the function invocation; defaults to `{ method: "GET" }`
94
94
  * @returns The response from the Edge function
@@ -581,6 +581,105 @@ export const Utility = {
581
581
  }
582
582
  }
583
583
  },
584
+ /**
585
+ * Checks if a user is authorised to access a microservice.
586
+ * @param {SupabaseClient<Database>} supabase - The Supabase client.
587
+ * @param {UserWithCustomMetadata} user - The user to check.
588
+ * @param {Object} options - The options for the function.
589
+ * @param {MicroserviceGroup} options.microserviceGroup - The microservice group.
590
+ * @param {Microservice<MicroserviceGroup> | string} options.microservice - The microservice.
591
+ * @param {string} options.playersUrl - The URL to the Players microservice.
592
+ * @param {(role: string) => string} options.requestedPermission - A function that returns the requested permission for a given role.
593
+ * @returns {Promise<{ isAuthorised?: boolean; redirect?: { code: number; url: string }; error?: CustomError }>} The result of the function.
594
+ */
595
+ isUserAuthorised: async (supabase, user, options) => {
596
+ // Destructure options
597
+ const { microserviceGroup, microservice, playersUrl } = options;
598
+ // Return true if microservice group is public
599
+ if (microserviceGroup === "public")
600
+ return { isAuthorised: true };
601
+ // Get user's roles and the role prefix
602
+ const roles = [];
603
+ const rolePrefix = microserviceGroup === "backroom" ? "backroom" : microserviceGroup.slice(0, -1);
604
+ for (const role of user.app_metadata.roles) {
605
+ if (role === "player")
606
+ continue;
607
+ if (role.startsWith(`${rolePrefix}_`))
608
+ roles.push(role.replace(`${rolePrefix}_`, ""));
609
+ }
610
+ // Redirect to Players microservices if user does not have any roles for the microservice group
611
+ if (roles.length === 0)
612
+ return { redirect: { code: 307, url: playersUrl } };
613
+ // Destructure role
614
+ const [role] = roles;
615
+ let isAuthorised = false;
616
+ // Grant access if superuser or account microservice
617
+ const isSuperuser = (microserviceGroup === "backroom" || microserviceGroup === "lounges") && role === "superuser";
618
+ if (isSuperuser || microservice === "account")
619
+ isAuthorised = true;
620
+ // Evaluate access
621
+ else if (microserviceGroup !== "players") {
622
+ // Get user's role and requested app permission
623
+ const requestedPermission = options.requestedPermission(role);
624
+ // Check if user has the requested permission
625
+ const { data, error: isAuthorisedError } = await supabase
626
+ .schema("compliance")
627
+ .rpc("authorise", { requested_permission: requestedPermission });
628
+ if (isAuthorisedError)
629
+ return Utility.parsePostgrestError(isAuthorisedError);
630
+ // Grant access if user has the requested permission
631
+ isAuthorised = data;
632
+ }
633
+ // Validate SuprSend subscriber
634
+ let personData;
635
+ if (user.app_metadata.person_data) {
636
+ const { first_name: firstName, last_name: lastName, pseudonym } = user.app_metadata.person_data;
637
+ personData = { firstName, lastName, phone: user.phone, pseudonym };
638
+ }
639
+ const { code, error: validationError } = await Utility.callEdgeFunction(false, supabase, `suprsend/validate-subscriber?user-id=${user.id}`, { method: "POST", body: personData });
640
+ if (validationError)
641
+ return { error: Utility.customError(code, validationError) };
642
+ // Initialise user metadata if not already done
643
+ if (!user.user_metadata.backroom) {
644
+ // Update user metadata in database
645
+ const { error: updateError } = await supabase.auth.updateUser({
646
+ data: { backroom: { welcome_notification_sent: false } }
647
+ });
648
+ if (updateError)
649
+ return { error: Utility.customError(updateError.status ?? 500, updateError.message) };
650
+ // Update user object in memory
651
+ user.user_metadata.backroom = { welcome_notification_sent: false };
652
+ }
653
+ // Send welcome notification if user is new
654
+ if (!user.user_metadata.backroom.welcome_notification_sent) {
655
+ // Define workflow body
656
+ const workflowBody = {
657
+ name: "welcome-to-backroom",
658
+ template: "welcome-to-backroom",
659
+ notification_category: "system",
660
+ users: [
661
+ {
662
+ distinct_id: user.id,
663
+ $skip_create: true
664
+ }
665
+ ]
666
+ };
667
+ // Trigger workflow
668
+ const { code, error: workflowError } = await Utility.callEdgeFunction(false, supabase, `suprsend/trigger-workflow?user-id=${user.id}`, { method: "POST", body: workflowBody });
669
+ if (workflowError)
670
+ return { error: Utility.customError(code, workflowError) };
671
+ // Update user metadata in database
672
+ const { error: updateError } = await supabase.auth.updateUser({
673
+ data: { backroom: { welcome_notification_sent: true } }
674
+ });
675
+ if (updateError)
676
+ return { error: Utility.customError(updateError.status ?? 500, updateError.message) };
677
+ // Update user object in memory
678
+ user.user_metadata.backroom.welcome_notification_sent = true;
679
+ }
680
+ // Return result
681
+ return { isAuthorised };
682
+ },
584
683
  /**
585
684
  * 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:
586
685
  * - `name`: The name of the microservice.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koloseum/utils",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "author": "Koloseum Technologies Limited",
5
5
  "type": "module",
6
6
  "description": "Utility logic for use across Koloseum web apps (TypeScript)",
@@ -36,7 +36,7 @@
36
36
  "validator": "^13.15.15"
37
37
  },
38
38
  "devDependencies": {
39
- "@koloseum/types": "^0.2.0",
39
+ "@koloseum/types": "^0.2.1",
40
40
  "@playwright/test": "^1.53.1",
41
41
  "@suprsend/web-components": "^0.2.1",
42
42
  "@types/sanitize-html": "^2.16.0",