summaryrefslogtreecommitdiff
path: root/shared/utils/src/platform.ts
diff options
context:
space:
mode:
Diffstat (limited to 'shared/utils/src/platform.ts')
-rw-r--r--shared/utils/src/platform.ts249
1 files changed, 249 insertions, 0 deletions
diff --git a/shared/utils/src/platform.ts b/shared/utils/src/platform.ts
new file mode 100644
index 0000000..15644e5
--- /dev/null
+++ b/shared/utils/src/platform.ts
@@ -0,0 +1,249 @@
+import {
+ parseUserAgent,
+ flagsExtension,
+ compareExtension,
+} from '@amp/runtime-detect';
+import { launchClient, type LaunchCallback } from './launch/launch-client';
+
+type NavigatorLike = {
+ userAgent: string;
+ maxTouchPoints?: number;
+};
+
+/**
+ * Detect a Platform descriptor from the browsers user agent.
+ */
+function detectDescriptor(options?: {
+ window?: Window;
+ navigator?: NavigatorLike;
+}) {
+ const defaultNavigator: NavigatorLike =
+ typeof options?.window?.navigator !== 'undefined'
+ ? options.window.navigator
+ : {
+ userAgent: '',
+ maxTouchPoints: 0,
+ };
+
+ return parseUserAgent(options?.navigator ?? defaultNavigator, {
+ extensions: [flagsExtension, compareExtension],
+ });
+}
+
+export type PlatformDescriptor = ReturnType<typeof detectDescriptor>;
+
+export class Platform {
+ static detect(
+ this: typeof Platform,
+ options?: { window?: Window; navigator?: NavigatorLike },
+ ) {
+ const window = options?.window ?? globalThis?.window;
+ return new this({
+ window: window,
+ descriptor: detectDescriptor({
+ window: window,
+ navigator: options?.navigator,
+ }),
+ });
+ }
+
+ /**
+ * Descriptor from detecting platform data.
+ */
+ readonly descriptor: PlatformDescriptor;
+
+ /**
+ * Navigator value used to create the platform descriptor.
+ */
+ readonly navigator: NavigatorLike;
+
+ /**
+ * Reference to the platform Window object. This might be `undefined` in some
+ * environments.
+ */
+ readonly window: Window | undefined;
+
+ /**
+ * User Agent string the platform descriptor was parsed from.
+ */
+ readonly ua: string;
+
+ /**
+ * Browser descriptor for the Platform.
+ */
+ readonly browser: PlatformDescriptor['browser'];
+
+ /**
+ * Browser Engine descriptor for the Platform.
+ */
+ readonly engine: PlatformDescriptor['engine'];
+
+ /**
+ * Operating System descriptor for the Platform.
+ */
+ readonly os: PlatformDescriptor['os'];
+
+ constructor(config: {
+ descriptor: PlatformDescriptor;
+ window?: Window;
+ navigator?: NavigatorLike;
+ }) {
+ const { descriptor } = config;
+ this.descriptor = descriptor;
+ this.navigator = config.navigator ?? descriptor.navigator;
+ this.window = config.window;
+
+ this.ua = descriptor.ua;
+ this.browser = descriptor.browser;
+ this.engine = descriptor.engine;
+ this.os = descriptor.os;
+ }
+
+ /**
+ * Check if Apple native applications can be opened on the Platform.
+ */
+ canOpenNative(): boolean {
+ return this.ismacOS() || this.isiOS();
+ }
+
+ /**
+ * Check if the Platform is running a mobile browser.
+ */
+ isMobile(): boolean {
+ return this.browser.isMobile;
+ }
+
+ /**
+ * Check if the Platform registers as running the Android operating system.
+ */
+ isAndroid(): boolean {
+ return this.os.isAndroid;
+ }
+
+ /**
+ * Check if the Platform registers as running the iOS operating system.
+ */
+ isiOS(): boolean {
+ return this.os.isIOS;
+ }
+
+ /**
+ * Check if the Platform registers as running the iPadOS operating system.
+ */
+ isiPadOS(): boolean {
+ return this.os.isIPadOS;
+ }
+
+ /**
+ * Check if the Platform registers as running the macOS operating system.
+ */
+ ismacOS(): boolean {
+ return this.os.isMacOS;
+ }
+
+ /**
+ * Check if the Platform registers as running the Windows operating system.
+ */
+ isWindows(): boolean {
+ return this.os.isWindows;
+ }
+
+ /**
+ * Check if the Platform registers as running a Linux operating system.
+ */
+ isLinux(): boolean {
+ return this.os.isLinux;
+ }
+
+ /**
+ * Check if the Platform is running the Apple Safari browser.
+ */
+ isSafari(): boolean {
+ return this.browser.isSafari;
+ }
+
+ /**
+ * Check if the Platform is running the Google Chrome browser.
+ */
+ isChrome(): boolean {
+ return this.browser.isChrome;
+ }
+
+ /**
+ * Check if the Platform is running the Mozilla Firefox browser.
+ */
+ isFirefox(): boolean {
+ return this.browser.isFirefox;
+ }
+
+ /**
+ * Check if the Platform is running the Microsoft Edge browser.
+ */
+ isEdge(): boolean {
+ return this.browser.isEdge;
+ }
+
+ /**
+ * Get name for the Platform browser.
+ * @deprecated Use `platform.browser.name` directly
+ */
+ clientName(): string {
+ return this.browser.name[0].toUpperCase() + this.browser.name.slice(1);
+ }
+
+ /**
+ * Get the Platform browser major version number.
+ * @deprecated Use `platform.browser.major` directly
+ */
+ majorVersion(): number {
+ return this.browser.major ?? 0;
+ }
+
+ /**
+ * Get the Platform browser minor version number.
+ * @deprecated Use `platform.browser.minor` directly
+ */
+ minorVersion(): number {
+ return this.browser.minor ?? 0;
+ }
+
+ /**
+ * Get the name for the Platform operating system.
+ * @deprecated Use `platform.os.name` directly
+ */
+ osName(): string {
+ return this.os.name;
+ }
+
+ /**
+ * Attempt to launch a native client for the given web URL.
+ *
+ * The callback is called with a report if the attempt was successful.
+ *
+ * @example
+ * ```javascript
+ * platform.launchClient(
+ * 'https://music.apple.com/browse',
+ * function ({ link, success }) {
+ * if (success) {
+ * console.log(`Opened client with ${link}`);
+ * } else {
+ * console.log(`Failed to open client with ${link}`);
+ * }
+ * }
+ * );
+ * ```
+ */
+ launchClient(url: string, callback?: LaunchCallback): void {
+ launchClient(url, this, callback);
+ }
+
+ /**
+ * Check if the platform has full support for playing encrypted HLS content.
+ */
+ hasEncryptedPlaybackSupport(): boolean {
+ return !this.os.isIOS || this.os.gte('17.5');
+ }
+}
+
+export const platform = Platform.detect();