text: import Constants from 'expo-constants';
  import { Platform, UnavailabilityError } from 'expo-modules-core';
  import invariant from 'invariant';
  import qs from 'qs';
  import { useEffect, useState } from 'react';
  import URL from 'url-parse';
  import NativeLinking from './ExpoLinking';
  import { hasCustomScheme, resolveScheme } from './Schemes';
  function validateURL(url) {
      invariant(typeof url === 'string', 'Invalid URL: should be a string. Was: ' + url);
      invariant(url, 'Invalid URL: cannot be empty');
  }
  function getHostUri() {
      if (Constants.manifest?.hostUri) {
          return Constants.manifest.hostUri;
      }
      else if (Constants.manifest2?.extra?.expoClient?.hostUri) {
          return Constants.manifest2.extra.expoClient.hostUri;
      }
      else if (!hasCustomScheme()) {
          // we're probably not using up-to-date xdl, so just fake it for now
          // we have to remove the /--/ on the end since this will be inserted again later
          return removeScheme(Constants.linkingUri).replace(/\/--($|\/.*$)/, '');
      }
      else {
          return null;
      }
  }
  function isExpoHosted() {
      const hostUri = getHostUri();
      return !!(hostUri &&
          (/^(.*\.)?(expo\.io|exp\.host|exp\.direct|expo\.test)(:.*)?(\/.*)?$/.test(hostUri) ||
              Constants.manifest?.developer));
  }
  function removeScheme(url) {
      return url.replace(/^[a-zA-Z0-9+.-]+:\/\//, '');
  }
  function removePort(url) {
      return url.replace(/(?=([a-zA-Z0-9+.-]+:\/\/)?[^/]):\d+/, '');
  }
  function removeLeadingSlash(url) {
      return url.replace(/^\//, '');
  }
  function removeTrailingSlashAndQueryString(url) {
      return url.replace(/\/?\?.*$/, '');
  }
  function ensureLeadingSlash(input, shouldAppend) {
      const hasSlash = input.endsWith('/');
      if (hasSlash && !shouldAppend) {
          return input.substring(0, input.length - 1);
      }
      else if (!hasSlash && shouldAppend) {
          return `${input}/`;
      }
      return input;
  }
  function ensureTrailingSlash(input, shouldAppend) {
      const hasSlash = input.startsWith('/');
      if (hasSlash && !shouldAppend) {
          return input.substring(1);
      }
      else if (!hasSlash && shouldAppend) {
          return `/${input}`;
      }
      return input;
  }
  /**
   * Create a URL that works for the environment the app is currently running in.
   * The scheme in bare and standalone must be defined in the app.json under `expo.scheme`.
   *
   * **Examples**
   *
   * - Bare: empty string
   * - Standalone, Custom: `yourscheme:///path`
   * - Web (dev): `https://localhost:19006/path`
   * - Web (prod): `https://myapp.com/path`
   * - Expo Client (dev): `exp://128.0.0.1:19000/--/path`
   * - Expo Client (prod): `exp://exp.host/@yourname/your-app/--/path`
   *
   * @param path addition path components to append to the base URL.
   * @param queryParams An object of parameters that will be converted into a query string.
   */
  export function makeUrl(path = '', queryParams, scheme) {
      return createURL(path, { queryParams, scheme, isTripleSlashed: true });
  }
  /**
   * Create a URL that works for the environment the app is currently running in.
   * The scheme in bare and standalone must be defined in the Expo config (app.config.js or app.json) under `expo.scheme`.
   *
   * **Examples**
   *
   * - Bare: `<scheme>://path` -- uses provided scheme or scheme from Expo config `scheme`.
   * - Standalone, Custom: `yourscheme://path`
   * - Web (dev): `https://localhost:19006/path`
   * - Web (prod): `https://myapp.com/path`
   * - Expo Client (dev): `exp://128.0.0.1:19000/--/path`
   * - Expo Client (prod): `exp://exp.host/@yourname/your-app/--/path`
   *
   * @param path addition path components to append to the base URL.
   * @param scheme URI protocol `<scheme>://` that must be built into your native app.
   * @param queryParams An object of parameters that will be converted into a query string.
   */
  export function createURL(path, { scheme, queryParams = {}, isTripleSlashed = false } = {}) {
      if (Platform.OS === 'web') {
          if (!Platform.isDOMAvailable)
              return '';
          const origin = ensureLeadingSlash(window.location.origin, false);
          let queryString = qs.stringify(queryParams);
          if (queryString) {
              queryString = `?${queryString}`;
          }
          let outputPath = path;
          if (outputPath)
              outputPath = ensureTrailingSlash(path, true);
          return encodeURI(`${origin}${outputPath}${queryString}`);
      }
      const resolvedScheme = resolveScheme({ scheme });
      let hostUri = getHostUri() || '';
      if (hasCustomScheme() && isExpoHosted()) {
          hostUri = '';
      }
      if (path) {
          if (isExpoHosted() && hostUri) {
              path = `/--/${removeLeadingSlash(path)}`;
          }
          if (isTripleSlashed && !path.startsWith('/')) {
              path = `/${path}`;
          }
      }
      else {
          path = '';
      }
      // merge user-provided query params with any that were already in the hostUri
      // e.g. release-channel
      let queryString = '';
      const queryStringMatchResult = hostUri.match(/(.*)\?(.+)/);
      if (queryStringMatchResult) {
          hostUri = queryStringMatchResult[1];
          queryString = queryStringMatchResult[2];
          let paramsFromHostUri = {};
          try {
              const parsedParams = qs.parse(queryString);
              if (typeof parsedParams === 'object') {
                  paramsFromHostUri = parsedParams;
              }
          }
          catch (e) { }
          queryParams = {
              ...queryParams,
              ...paramsFromHostUri,
          };
      }
      queryString = qs.stringify(queryParams);
      if (queryString) {
          queryString = `?${queryString}`;
      }
      hostUri = ensureTrailingSlash(hostUri, !isTripleSlashed);
      return encodeURI(`${resolvedScheme}:${isTripleSlashed ? '/' : ''}/${hostUri}${path}${queryString}`);
  }
  /**
   * Returns the components and query parameters for a given URL.
   *
   * @param url Input URL to parse
   */
  export function parse(url) {
      validateURL(url);
      const parsed = URL(url, /* parseQueryString */ true);
      for (const param in parsed.query) {
          parsed.query[param] = decodeURIComponent(parsed.query[param]);
      }
      const queryParams = parsed.query;
      const hostUri = getHostUri() || '';
      const hostUriStripped = removePort(removeTrailingSlashAndQueryString(hostUri));
      let path = parsed.pathname || null;
      let hostname = parsed.hostname || null;
      let scheme = parsed.protocol || null;
      if (scheme) {
          // Remove colon at end
          scheme = scheme.substring(0, scheme.length - 1);
      }
      if (path) {
          path = removeLeadingSlash(path);
          let expoPrefix = null;
          if (hostUriStripped) {
              const parts = hostUriStripped.split('/');
              expoPrefix = parts
                  .slice(1)
                  .concat(['--/'])
                  .join('/');
          }
          if (isExpoHosted() && !hasCustomScheme() && expoPrefix && path.startsWith(expoPrefix)) {
              path = path.substring(expoPrefix.length);
              hostname = null;
          }
          else if (path.indexOf('+') > -1) {
              path = path.substring(path.indexOf('+') + 1);
          }
      }
      return {
          hostname,
          path,
          queryParams,
          scheme,
      };
  }
  /**
   * Add a handler to Linking changes by listening to the `url` event type
   * and providing the handler
   *
   * See https://reactnative.dev/docs/linking.html#addeventlistener
   */
  export function addEventListener(type, handler) {
      NativeLinking.addEventListener(type, handler);
  }
  /**
   * Remove a handler by passing the `url` event type and the handler.
   *
   * See https://reactnative.dev/docs/linking.html#removeeventlistener
   */
  export function removeEventListener(type, handler) {
      NativeLinking.removeEventListener(type, handler);
  }
  /**
   * **Native:** Parses the link that opened the app. If no link opened the app, all the fields will be \`null\`.
   * **Web:** Parses the current window URL.
   */
  export async function parseInitialURLAsync() {
      const initialUrl = await NativeLinking.getInitialURL();
      if (!initialUrl) {
          return {
              scheme: null,
              hostname: null,
              path: null,
              queryParams: null,
          };
      }
      return parse(initialUrl);
  }
  /**
   * Launch an Android intent with optional extras
   *
   * @platform android
   */
  export async function sendIntent(action, extras) {
      if (Platform.OS === 'android') {
          return await NativeLinking.sendIntent(action, extras);
      }
      throw new UnavailabilityError('Linking', 'sendIntent');
  }
  /**
   * Attempt to open the system settings for an the app.
   *
   * @platform ios
   */
  export async function openSettings() {
      if (Platform.OS === 'web') {
          throw new UnavailabilityError('Linking', 'openSettings');
      }
      if (NativeLinking.openSettings) {
          return await NativeLinking.openSettings();
      }
      await openURL('app-settings:');
  }
  /**
   * If the app launch was triggered by an app link,
   * it will give the link url, otherwise it will give `null`
   */
  export async function getInitialURL() {
      return (await NativeLinking.getInitialURL()) ?? null;
  }
  /**
   * Try to open the given `url` with any of the installed apps.
   */
  export async function openURL(url) {
      validateURL(url);
      return await NativeLinking.openURL(url);
  }
  /**
   * Determine whether or not an installed app can handle a given URL.
   * On web this always returns true because there is no API for detecting what URLs can be opened.
   */
  export async function canOpenURL(url) {
      validateURL(url);
      return await NativeLinking.canOpenURL(url);
  }
  /**
   * Returns the initial URL followed by any subsequent changes to the URL.
   */
  export function useURL() {
      const [url, setLink] = useState(null);
      function onChange(event) {
          setLink(event.url);
      }
      useEffect(() => {
          getInitialURL().then(url => setLink(url));
          addEventListener('url', onChange);
          return () => removeEventListener('url', onChange);
      }, []);
      return url;
  }
  /**
   * Returns the initial URL followed by any subsequent changes to the URL.
   * @deprecated Use `useURL` instead.
   */
  export function useUrl() {
      console.warn(`Linking.useUrl has been deprecated in favor of Linking.useURL. This API will be removed in SDK 44.`);
      return useURL();
  }
  export * from './Linking.types';
  //# sourceMappingURL=Linking.js.map