@koloseum/utils 0.2.26 → 0.2.28

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
@@ -1,5 +1,5 @@
1
1
  import type { Database } from "@koloseum/types/database";
2
- import type { CustomError, Microservice, MicroserviceGroup, MicroserviceObject, UserWithCustomMetadata } from "@koloseum/types/general";
2
+ import type { BrowserInfo, CustomError, Microservice, MicroserviceGroup, MicroserviceObject, UserWithCustomMetadata } from "@koloseum/types/general";
3
3
  import type { BranchAddressObject, County, IdentityType, PronounsCheckboxes, PronounsItem, Sex, SocialMediaPlatform } from "@koloseum/types/public-auth";
4
4
  import type { Page } from "@sveltejs/kit";
5
5
  import type { SupabaseClient, FunctionInvokeOptions, PostgrestError } from "@supabase/supabase-js";
@@ -261,7 +261,7 @@ export declare const Utility: {
261
261
  */
262
262
  sanitiseHtml: (input: string) => string;
263
263
  /**
264
- * Sends a welcome notification to a user.
264
+ * Sends a welcome notification to a new user.
265
265
  * @param {SupabaseClient<Database>} supabase - The Supabase client
266
266
  * @param {UserWithCustomMetadata} user - The user to send the notification to
267
267
  * @param {MicroserviceGroup} microserviceGroup - The microservice group the user belongs to
@@ -339,3 +339,56 @@ export declare const Cache: {
339
339
  */
340
340
  setData: <T>(valkey: any, cachePrefix: string, key: string, data: T, ttl?: number) => Promise<void>;
341
341
  };
342
+ export declare const Browser: {
343
+ /**
344
+ * Checks if a specific feature is supported by the browser.
345
+ * @param feature - The feature to check
346
+ * @param browserName - The name of the browser
347
+ * @param browserVersion - The version of the browser
348
+ * @returns `true` if the feature is supported, `false` otherwise
349
+ */
350
+ checkFeatureSupport: (feature: string, browserName: string, browserVersion: number) => boolean;
351
+ /**
352
+ * Gets detailed browser information for debugging.
353
+ */
354
+ getDetailedInfo: () => {
355
+ browser: string;
356
+ os: string;
357
+ platform: string;
358
+ engine: string;
359
+ userAgent: string;
360
+ };
361
+ /**
362
+ * Gets comprehensive browser information using Bowser.
363
+ */
364
+ getInfo: () => BrowserInfo;
365
+ /**
366
+ * Gets specific browser recommendations based on the detected browser.
367
+ */
368
+ getRecommendations: () => {
369
+ title: string;
370
+ message: string;
371
+ recommendations: string[];
372
+ critical: boolean;
373
+ };
374
+ /**
375
+ * Checks if the current browser is compatible with the application.
376
+ */
377
+ isBrowserCompatible: () => boolean;
378
+ /**
379
+ * Checks if the browser is Internet Explorer.
380
+ */
381
+ isInternetExplorer: () => boolean;
382
+ /**
383
+ * Checks if the browser is iOS Safari.
384
+ */
385
+ isIOSSafari: () => boolean;
386
+ /**
387
+ * Checks if the browser is a legacy version that needs updating.
388
+ */
389
+ isLegacyBrowser: () => boolean;
390
+ /**
391
+ * Checks if the browser is an old version of Safari.
392
+ */
393
+ isOldSafari: () => boolean;
394
+ };
package/dist/utils.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { v4 as uuidv4 } from "uuid";
2
2
  import { error as svelteError } from "@sveltejs/kit";
3
3
  import { FunctionsFetchError, FunctionsHttpError, FunctionsRelayError } from "@supabase/supabase-js";
4
+ import Bowser from "bowser";
4
5
  import validator from "validator";
5
6
  /* HELPERS */
6
7
  const parsePgInterval = (await import("postgres-interval")).default;
@@ -867,19 +868,23 @@ export const Utility = {
867
868
  // Assign result of authorisation check
868
869
  isAuthorised = data;
869
870
  }
870
- // Validate SuprSend subscriber
871
- let personData;
872
- if (user.app_metadata.person_data) {
873
- const { first_name: firstName, last_name: lastName, pseudonym } = user.app_metadata.person_data;
874
- personData = { firstName, lastName, phone: user.phone, pseudonym };
871
+ // If user has completed Player registration
872
+ if (roles.includes("player")) {
873
+ // Prepare person data
874
+ let personData = {};
875
+ if (user.app_metadata.person_data) {
876
+ const { first_name: firstName, last_name: lastName, pseudonym } = user.app_metadata.person_data;
877
+ personData = { firstName, lastName, phone: user.phone, pseudonym };
878
+ }
879
+ // Validate SuprSend subscriber
880
+ const { code, error: validationError } = await Utility.callEdgeFunction(false, supabase, `suprsend/validate-subscriber?user-id=${user.id}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: personData });
881
+ if (validationError)
882
+ return { error: Utility.customError(code, validationError) };
883
+ // Send welcome notification if not already sent
884
+ const { error: welcomeError } = await Utility.sendWelcomeNotification(supabase, user, microserviceGroup);
885
+ if (welcomeError)
886
+ return { error: welcomeError };
875
887
  }
876
- const { code, error: validationError } = await Utility.callEdgeFunction(false, supabase, `suprsend/validate-subscriber?user-id=${user.id}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: personData });
877
- if (validationError)
878
- return { error: Utility.customError(code, validationError) };
879
- // Send welcome notification if needed
880
- const { error: welcomeError } = await Utility.sendWelcomeNotification(supabase, user, microserviceGroup);
881
- if (welcomeError)
882
- return { error: welcomeError };
883
888
  // Return result
884
889
  return { isAuthorised };
885
890
  },
@@ -1476,7 +1481,7 @@ export const Utility = {
1476
1481
  */
1477
1482
  sanitiseHtml: (input) => typeof input !== "string" ? "" : sanitize(input, { allowedTags: [], allowedAttributes: {} }),
1478
1483
  /**
1479
- * Sends a welcome notification to a user.
1484
+ * Sends a welcome notification to a new user.
1480
1485
  * @param {SupabaseClient<Database>} supabase - The Supabase client
1481
1486
  * @param {UserWithCustomMetadata} user - The user to send the notification to
1482
1487
  * @param {MicroserviceGroup} microserviceGroup - The microservice group the user belongs to
@@ -1729,3 +1734,286 @@ export const Cache = {
1729
1734
  }
1730
1735
  }
1731
1736
  };
1737
+ /* BROWSER COMPATIBILITY FUNCTIONS */
1738
+ export const Browser = {
1739
+ /**
1740
+ * Checks if a specific feature is supported by the browser.
1741
+ * @param feature - The feature to check
1742
+ * @param browserName - The name of the browser
1743
+ * @param browserVersion - The version of the browser
1744
+ * @returns `true` if the feature is supported, `false` otherwise
1745
+ */
1746
+ checkFeatureSupport: (feature, browserName, browserVersion) => {
1747
+ // Feature support matrix based on browser versions
1748
+ const featureSupport = {
1749
+ optionalChaining: {
1750
+ Chrome: 80,
1751
+ Firefox: 74,
1752
+ Safari: 13.4,
1753
+ Edge: 80,
1754
+ Opera: 80
1755
+ },
1756
+ nullishCoalescing: {
1757
+ Chrome: 80,
1758
+ Firefox: 72,
1759
+ Safari: 13.4,
1760
+ Edge: 80,
1761
+ Opera: 80
1762
+ },
1763
+ fetch: {
1764
+ Chrome: 42,
1765
+ Firefox: 39,
1766
+ Safari: 10.1,
1767
+ Edge: 14,
1768
+ Opera: 29
1769
+ },
1770
+ es6Modules: {
1771
+ Chrome: 61,
1772
+ Firefox: 60,
1773
+ Safari: 10.1,
1774
+ Edge: 16,
1775
+ Opera: 48
1776
+ },
1777
+ asyncAwait: {
1778
+ Chrome: 55,
1779
+ Firefox: 52,
1780
+ Safari: 10.1,
1781
+ Edge: 14,
1782
+ Opera: 42
1783
+ }
1784
+ };
1785
+ const featureMatrix = featureSupport[feature];
1786
+ if (!featureMatrix)
1787
+ return true; // Unknown feature, assume supported
1788
+ const minVersion = featureMatrix[browserName];
1789
+ if (!minVersion)
1790
+ return true; // Unknown browser, assume supported
1791
+ return browserVersion >= minVersion;
1792
+ },
1793
+ /**
1794
+ * Gets detailed browser information for debugging.
1795
+ */
1796
+ getDetailedInfo: () => {
1797
+ if (typeof window === "undefined") {
1798
+ return {
1799
+ browser: "Server-side rendering",
1800
+ os: "Unknown",
1801
+ platform: "Unknown",
1802
+ engine: "Unknown",
1803
+ userAgent: "Unknown"
1804
+ };
1805
+ }
1806
+ const browser = Bowser.getParser(window.navigator.userAgent);
1807
+ return {
1808
+ browser: `${browser.getBrowserName()} ${browser.getBrowserVersion()}`,
1809
+ os: `${browser.getOSName()} ${browser.getOSVersion()}`,
1810
+ platform: browser.getPlatformType(),
1811
+ engine: browser.getEngineName(),
1812
+ userAgent: window.navigator.userAgent
1813
+ };
1814
+ },
1815
+ /**
1816
+ * Gets comprehensive browser information using Bowser.
1817
+ */
1818
+ getInfo: () => {
1819
+ if (typeof window === "undefined") {
1820
+ return {
1821
+ name: "server",
1822
+ version: 0,
1823
+ isOldSafari: false,
1824
+ isIOS: false,
1825
+ supportsOptionalChaining: true,
1826
+ supportsNullishCoalescing: true,
1827
+ supportsFetch: true
1828
+ };
1829
+ }
1830
+ const browser = Bowser.getParser(window.navigator.userAgent);
1831
+ const browserName = browser.getBrowserName();
1832
+ const browserVersion = parseFloat(browser.getBrowserVersion() || "0");
1833
+ const osName = browser.getOSName();
1834
+ const isIOS = osName === "iOS";
1835
+ const isSafari = browserName === "Safari";
1836
+ const isOldSafari = isSafari && browserVersion < 13.4;
1837
+ return {
1838
+ name: browserName,
1839
+ version: browserVersion,
1840
+ isOldSafari,
1841
+ isIOS,
1842
+ supportsOptionalChaining: Browser.checkFeatureSupport("optionalChaining", browserName, browserVersion),
1843
+ supportsNullishCoalescing: Browser.checkFeatureSupport("nullishCoalescing", browserName, browserVersion),
1844
+ supportsFetch: Browser.checkFeatureSupport("fetch", browserName, browserVersion)
1845
+ };
1846
+ },
1847
+ /**
1848
+ * Gets specific browser recommendations based on the detected browser.
1849
+ */
1850
+ getRecommendations: () => {
1851
+ if (typeof window === "undefined")
1852
+ return {
1853
+ title: "Browser compatibility issue",
1854
+ message: "Browser detection is not available on theserver.",
1855
+ recommendations: [],
1856
+ critical: false
1857
+ };
1858
+ const browser = Bowser.getParser(window.navigator.userAgent);
1859
+ const browserName = browser.getBrowserName();
1860
+ const browserVersion = browser.getBrowserVersion();
1861
+ // Internet Explorer
1862
+ if (browserName === "Internet Explorer") {
1863
+ return {
1864
+ title: "Unsupported browser",
1865
+ message: "Internet Explorer is not supported. Please use a modern browser.",
1866
+ recommendations: [
1867
+ "Download and install Microsoft Edge",
1868
+ "Use an alternative such as Chrome or Firefox (or Safari on Mac)"
1869
+ ],
1870
+ critical: true
1871
+ };
1872
+ }
1873
+ // Apple Safari
1874
+ if (browserName === "Safari" && parseFloat(browserVersion || "0") < 13.4) {
1875
+ return {
1876
+ title: "Browser compatibility issue",
1877
+ message: `You're using Safari ${browserVersion || "Unknown"}, which doesn't support modern web features.`,
1878
+ recommendations: [
1879
+ "Update to Safari 13.4 or later",
1880
+ "Use Chrome or Firefox as an alternative",
1881
+ "Update your iOS device to the latest version"
1882
+ ],
1883
+ critical: true
1884
+ };
1885
+ }
1886
+ // Google Chrome
1887
+ if (browserName === "Chrome" && parseFloat(browserVersion || "0") < 80) {
1888
+ return {
1889
+ title: "Outdated browser",
1890
+ message: `You're using Chrome ${browserVersion || "Unknown"}, which may not support all features.`,
1891
+ recommendations: ["Update Chrome to version 80 or later", "Enable automatic updates in Chrome settings"],
1892
+ critical: false
1893
+ };
1894
+ }
1895
+ // Mozilla Firefox
1896
+ if (browserName === "Firefox" && parseFloat(browserVersion || "0") < 80) {
1897
+ return {
1898
+ title: "Outdated browser",
1899
+ message: `You're using Firefox ${browserVersion || "Unknown"}, which may not support all features.`,
1900
+ recommendations: ["Update Firefox to version 80 or later", "Enable automatic updates in Firefox settings"],
1901
+ critical: false
1902
+ };
1903
+ }
1904
+ // Microsoft Edge
1905
+ if (browserName === "Edge" && parseFloat(browserVersion || "0") < 80) {
1906
+ return {
1907
+ title: "Outdated browser",
1908
+ message: `You're using Edge ${browserVersion || "Unknown"}, which may not support all features.`,
1909
+ recommendations: ["Update Edge to version 80 or later", "Enable automatic updates in Edge settings"],
1910
+ critical: false
1911
+ };
1912
+ }
1913
+ // For unknown or very old browsers
1914
+ if (browserName === "Unknown" || parseFloat(browserVersion || "0") < 50) {
1915
+ return {
1916
+ title: "Unrecognised browser",
1917
+ message: "Your browser may not be fully supported. For the best experience, please use a modern browser.",
1918
+ recommendations: ["Use Chrome, Firefox or Edge (latest version)", "Use Safari 13.4+ (on Mac/iOS)"],
1919
+ critical: true
1920
+ };
1921
+ }
1922
+ // Default for modern browsers
1923
+ return {
1924
+ title: "Browser compatibility issue",
1925
+ message: "Your browser may not fully support this application.",
1926
+ recommendations: [
1927
+ "Update your browser to the latest version",
1928
+ "Clear your browser cache and cookies",
1929
+ "Disable browser extensions temporarily",
1930
+ "Try a different modern browser"
1931
+ ],
1932
+ critical: false
1933
+ };
1934
+ },
1935
+ /**
1936
+ * Checks if the current browser is compatible with the application.
1937
+ */
1938
+ isBrowserCompatible: () => {
1939
+ if (typeof window === "undefined")
1940
+ return true;
1941
+ const browser = Bowser.getParser(window.navigator.userAgent);
1942
+ const browserName = browser.getBrowserName();
1943
+ const browserVersion = parseFloat(browser.getBrowserVersion() || "0");
1944
+ // Define minimum supported versions
1945
+ const minVersions = {
1946
+ "Internet Explorer": 0, // Not supported at all
1947
+ Safari: 13.4,
1948
+ Chrome: 80,
1949
+ Firefox: 80,
1950
+ Edge: 80,
1951
+ Opera: 80
1952
+ };
1953
+ // Internet Explorer is never compatible
1954
+ if (browserName === "Internet Explorer") {
1955
+ return false;
1956
+ }
1957
+ // Check if browser version meets minimum requirements
1958
+ const minVersion = minVersions[browserName];
1959
+ if (minVersion && browserVersion < minVersion) {
1960
+ return false;
1961
+ }
1962
+ // Check for critical modern features
1963
+ return (Browser.checkFeatureSupport("optionalChaining", browserName, browserVersion) &&
1964
+ Browser.checkFeatureSupport("nullishCoalescing", browserName, browserVersion) &&
1965
+ Browser.checkFeatureSupport("fetch", browserName, browserVersion) &&
1966
+ Browser.checkFeatureSupport("es6Modules", browserName, browserVersion) &&
1967
+ Browser.checkFeatureSupport("asyncAwait", browserName, browserVersion));
1968
+ },
1969
+ /**
1970
+ * Checks if the browser is Internet Explorer.
1971
+ */
1972
+ isInternetExplorer: () => {
1973
+ if (typeof window === "undefined")
1974
+ return false;
1975
+ const browser = Bowser.getParser(window.navigator.userAgent);
1976
+ return browser.getBrowserName() === "Internet Explorer";
1977
+ },
1978
+ /**
1979
+ * Checks if the browser is iOS Safari.
1980
+ */
1981
+ isIOSSafari: () => {
1982
+ if (typeof window === "undefined")
1983
+ return false;
1984
+ const browser = Bowser.getParser(window.navigator.userAgent);
1985
+ return browser.getOSName() === "iOS" && browser.getBrowserName() === "Safari";
1986
+ },
1987
+ /**
1988
+ * Checks if the browser is a legacy version that needs updating.
1989
+ */
1990
+ isLegacyBrowser: () => {
1991
+ if (typeof window === "undefined")
1992
+ return false;
1993
+ const browser = Bowser.getParser(window.navigator.userAgent);
1994
+ const browserName = browser.getBrowserName();
1995
+ const browserVersion = parseFloat(browser.getBrowserVersion() || "0");
1996
+ // Legacy browser thresholds
1997
+ const legacyThresholds = {
1998
+ "Internet Explorer": 0, // All versions are legacy
1999
+ Safari: 13.4,
2000
+ Chrome: 80,
2001
+ Firefox: 80,
2002
+ Edge: 80,
2003
+ Opera: 80
2004
+ };
2005
+ const threshold = legacyThresholds[browserName];
2006
+ return threshold ? browserVersion < threshold : false;
2007
+ },
2008
+ /**
2009
+ * Checks if the browser is an old version of Safari.
2010
+ */
2011
+ isOldSafari: () => {
2012
+ if (typeof window === "undefined")
2013
+ return false;
2014
+ const browser = Bowser.getParser(window.navigator.userAgent);
2015
+ const browserName = browser.getBrowserName();
2016
+ const browserVersion = parseFloat(browser.getBrowserVersion() || "0");
2017
+ return browserName === "Safari" && browserVersion < 13.4;
2018
+ }
2019
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@koloseum/utils",
3
- "version": "0.2.26",
3
+ "version": "0.2.28",
4
4
  "author": "Koloseum Technologies Limited",
5
5
  "type": "module",
6
6
  "description": "Utility logic for use across Koloseum web apps (TypeScript)",
@@ -31,6 +31,7 @@
31
31
  "dependencies": {
32
32
  "@supabase/supabase-js": "^2.57.4",
33
33
  "@sveltejs/kit": "^2.41.0",
34
+ "bowser": "^2.12.1",
34
35
  "kenya-administrative-divisions": "^0.0.18",
35
36
  "postgres-interval": "^4.0.2",
36
37
  "sanitize-html": "^2.17.0",
@@ -38,7 +39,7 @@
38
39
  "validator": "^13.15.15"
39
40
  },
40
41
  "devDependencies": {
41
- "@koloseum/types": "^0.2.8",
42
+ "@koloseum/types": "^0.2.10",
42
43
  "@playwright/test": "^1.55.0",
43
44
  "@suprsend/web-components": "^0.4.0",
44
45
  "@types/sanitize-html": "^2.16.0",