text: /** @flow */
  
  import Config from './components/config';
  import Crypto from './components/cryptography/index';
  import SubscriptionManager from './components/subscription_manager';
  import TelemetryManager from './components/telemetry_manager';
  import NotificationsPayload from './components/push_payload';
  import ListenerManager from './components/listener_manager';
  import TokenManager from './components/token_manager';
  
  import endpointCreator from './components/endpoint';
  
  import { deprecated } from './utils';
  
  import * as addChannelsChannelGroupConfig from './endpoints/channel_groups/add_channels';
  import * as removeChannelsChannelGroupConfig from './endpoints/channel_groups/remove_channels';
  import * as deleteChannelGroupConfig from './endpoints/channel_groups/delete_group';
  import * as listChannelGroupsConfig from './endpoints/channel_groups/list_groups';
  import * as listChannelsInChannelGroupConfig from './endpoints/channel_groups/list_channels';
  
  import * as addPushChannelsConfig from './endpoints/push/add_push_channels';
  import * as removePushChannelsConfig from './endpoints/push/remove_push_channels';
  import * as listPushChannelsConfig from './endpoints/push/list_push_channels';
  import * as removeDevicePushConfig from './endpoints/push/remove_device';
  
  import * as presenceLeaveEndpointConfig from './endpoints/presence/leave';
  import * as presenceWhereNowEndpointConfig from './endpoints/presence/where_now';
  import * as presenceHeartbeatEndpointConfig from './endpoints/presence/heartbeat';
  import * as presenceGetStateConfig from './endpoints/presence/get_state';
  import * as presenceSetStateConfig from './endpoints/presence/set_state';
  import * as presenceHereNowConfig from './endpoints/presence/here_now';
  
  // Actions API
  
  import * as addMessageActionEndpointConfig from './endpoints/actions/add_message_action';
  import * as removeMessageActionEndpointConfig from './endpoints/actions/remove_message_action';
  import * as getMessageActionEndpointConfig from './endpoints/actions/get_message_actions';
  
  // File Upload API v1
  
  import { IFile, FileClass } from '../file';
  
  import * as fileUploadTypes from './endpoints/file_upload/types';
  
  import listFilesEndpointConfig from './endpoints/file_upload/list_files';
  import generateUploadUrlEndpointConfig from './endpoints/file_upload/generate_upload_url';
  import publishFileEndpointConfig from './endpoints/file_upload/publish_file';
  import sendFileFunction from './endpoints/file_upload/send_file';
  import getFileUrlFunction from './endpoints/file_upload/get_file_url';
  import downloadFileEndpointConfig from './endpoints/file_upload/download_file';
  import deleteFileEndpointConfig from './endpoints/file_upload/delete_file';
  
  // Object API v2
  import getAllUUIDMetadataEndpointConfig, {
    type GetAllUUIDMetadataParams,
    type GetAllUUIDMetadataResult,
  } from './endpoints/objects/uuid/get_all';
  
  import getUUIDMetadataEndpointConfig, {
    type GetUUIDMetadataParams,
    type GetUUIDMetadataResult,
  } from './endpoints/objects/uuid/get';
  
  import setUUIDMetadataEndpointConfig, {
    type SetUUIDMetadataParams,
    type SetUUIDMetadataResult,
  } from './endpoints/objects/uuid/set';
  
  import removeUUIDMetadataEndpointConfig, {
    type RemoveUUIDMetadataParams,
    type RemoveUUIDMetadataResult,
  } from './endpoints/objects/uuid/remove';
  
  import getAllChannelMetadataEndpointConfig, {
    type GetAllChannelMetadataParams,
    type GetAllChannelMetadataResult,
  } from './endpoints/objects/channel/get_all';
  
  import getChannelMetadataEndpointConfig, {
    type GetChannelMetadataParams,
    type GetChannelMetadataResult,
  } from './endpoints/objects/channel/get';
  
  import setChannelMetadataEndpointConfig, {
    type SetChannelMetadataParams,
    type SetChannelMetadataResult,
  } from './endpoints/objects/channel/set';
  
  import removeChannelMetadataEndpointConfig, {
    type RemoveChannelMetadataParams,
    type RemoveChannelMetadataResult,
  } from './endpoints/objects/channel/remove';
  
  import getMembersV2EndpointConfig, {
    type GetMembersParams,
    type GetMembersResult,
  } from './endpoints/objects/member/get';
  
  import setMembersV2EndpointConfig, {
    type UpsertMembersParams,
    type RemoveMembersParams,
    type SetMembersResult,
  } from './endpoints/objects/member/set';
  
  import getMembershipsV2EndpointConfig, {
    type GetMembershipsParams,
    type GetMembershipsResult,
  } from './endpoints/objects/membership/get';
  
  import setMembershipsV2EndpointConfig, {
    type UpsertMembershipsParams,
    type RemoveMembershipsParams,
    type SetMembershipsResult,
  } from './endpoints/objects/membership/set';
  
  // Objects API
  
  import * as createUserEndpointConfig from './endpoints/users/create_user';
  import * as updateUserEndpointConfig from './endpoints/users/update_user';
  import * as deleteUserEndpointConfig from './endpoints/users/delete_user';
  import * as getUserEndpointConfig from './endpoints/users/get_user';
  import * as getUsersEndpointConfig from './endpoints/users/get_users';
  import * as createSpaceEndpointConfig from './endpoints/spaces/create_space';
  import * as updateSpaceEndpointConfig from './endpoints/spaces/update_space';
  import * as deleteSpaceEndpointConfig from './endpoints/spaces/delete_space';
  import * as getSpacesEndpointConfig from './endpoints/spaces/get_spaces';
  import * as getSpaceEndpointConfig from './endpoints/spaces/get_space';
  import * as getMembersEndpointConfig from './endpoints/memberships/get_members';
  import * as addMembersEndpointConfig from './endpoints/memberships/add_members';
  import * as updateMembersEndpointConfig from './endpoints/memberships/update_members';
  import * as removeMembersEndpointConfig from './endpoints/memberships/remove_members';
  import * as getMembershipsEndpointConfig from './endpoints/memberships/get_memberships';
  import * as updateMembershipsEndpointConfig from './endpoints/memberships/update_memberships';
  import * as joinSpacesEndpointConfig from './endpoints/memberships/join_spaces';
  import * as leaveSpacesEndpointConfig from './endpoints/memberships/leave_spaces';
  
  import * as auditEndpointConfig from './endpoints/access_manager/audit';
  import * as grantEndpointConfig from './endpoints/access_manager/grant';
  import * as grantTokenEndpointConfig from './endpoints/access_manager/grant_token';
  
  import * as publishEndpointConfig from './endpoints/publish';
  import * as signalEndpointConfig from './endpoints/signal';
  import * as historyEndpointConfig from './endpoints/history/get_history';
  import * as deleteMessagesEndpointConfig from './endpoints/history/delete_messages';
  import * as messageCountsEndpointConfig from './endpoints/history/message_counts';
  import * as fetchMessagesEndpointConfig from './endpoints/fetch_messages';
  import * as timeEndpointConfig from './endpoints/time';
  import * as subscribeEndpointConfig from './endpoints/subscribe';
  
  import OPERATIONS from './constants/operations';
  import CATEGORIES from './constants/categories';
  
  import { InternalSetupStruct } from './flow_interfaces';
  import uuidGenerator from './components/uuid';
  
  type CallbackStatus = {|
    error: boolean,
    operation: string,
    statusCode: number,
  |};
  
  export default class {
    _config: Config;
    _telemetryManager: TelemetryManager;
    _listenerManager: ListenerManager;
    _tokenManager: TokenManager;
  
    // tell flow about the mounted endpoint
    time: Function;
    publish: Function;
    fire: Function;
  
    history: Function;
    deleteMessages: Function;
    messageCounts: Function;
    fetchMessages: Function;
  
    //
    channelGroups: Object;
    //
    push: Object;
    //
    hereNow: Function;
    whereNow: Function;
    getState: Function;
    setState: Function;
    //
    grant: Function;
    grantToken: Function;
    audit: Function;
    //
    subscribe: Function;
    signal: Function;
    presence: Function;
    unsubscribe: Function;
    unsubscribeAll: Function;
  
    // Actions API
    addMessageAction: Function;
    removeMessageAction: Function;
    getMessageActions: Function;
  
    // File Upload API v1
  
    File: FileClass;
    encryptFile: (key: string, file: IFile) => Promise<IFile>;
    decryptFile: (key: string, file: IFile) => Promise<IFile>;
  
    listFiles: (
      parameters: fileUploadTypes.ListFilesParams,
      callback?: (status: CallbackStatus, result: fileUploadTypes.ListFilesResult) => void
    ) => Promise<fileUploadTypes.ListFilesResult>;
    sendFile: (
      parameters: fileUploadTypes.SendFileParams,
      callback?: (status: CallbackStatus, result: fileUploadTypes.SendFileResult) => void
    ) => Promise<fileUploadTypes.SendFileResult>;
    downloadFile: (
      parameters: fileUploadTypes.DownloadFileParams,
      callback?: (status: CallbackStatus, result: fileUploadTypes.DownloadFileResult) => void
    ) => Promise<fileUploadTypes.DownloadFileResult>;
    getFileUrl: (parameters: fileUploadTypes.GetFileUrlParams) => fileUploadTypes.GetFileUrlResult;
    deleteFile: (
      parameters: fileUploadTypes.DeleteFileParams,
      callback?: (status: CallbackStatus, result: fileUploadTypes.DeleteFileResult) => void
    ) => Promise<fileUploadTypes.DeleteFileResult>;
    publishFile: (
      parameters: fileUploadTypes.PublishFileParams,
      callback?: (status: CallbackStatus, result: fileUploadTypes.PublishFileResult) => void
    ) => Promise<fileUploadTypes.PublishFileResult>;
  
    // Objects API v2
  
    objects: {
      getAllUUIDMetadata: (
        parameters?: GetAllUUIDMetadataParams,
        cb?: (status: CallbackStatus, result: GetAllUUIDMetadataResult) => void
      ) => Promise<GetAllUUIDMetadataResult>,
      getUUIDMetadata: (
        parameters?: GetUUIDMetadataParams,
        cb?: (status: CallbackStatus, result: GetUUIDMetadataResult) => void
      ) => Promise<GetUUIDMetadataResult>,
      setUUIDMetadata: (
        parameters: SetUUIDMetadataParams,
        cb?: (status: CallbackStatus, result: SetUUIDMetadataResult) => void
      ) => Promise<SetUUIDMetadataResult>,
      removeUUIDMetadata: (
        parameters?: RemoveUUIDMetadataParams,
        cb?: (status: CallbackStatus, result: RemoveUUIDMetadataResult) => void
      ) => Promise<RemoveUUIDMetadataResult>,
  
      getAllChannelMetadata: (
        parameters?: GetAllChannelMetadataParams,
        cb?: (status: CallbackStatus, result: GetAllChannelMetadataResult) => void
      ) => Promise<GetAllChannelMetadataResult>,
      getChannelMetadata: (
        parameters: GetChannelMetadataParams,
        cb?: (status: CallbackStatus, result: GetChannelMetadataResult) => void
      ) => Promise<GetChannelMetadataResult>,
      setChannelMetadata: (
        parameters: SetChannelMetadataParams,
        cb?: (status: CallbackStatus, result: SetChannelMetadataResult) => void
      ) => Promise<SetChannelMetadataResult>,
      removeChannelMetadata: (
        parameters: RemoveChannelMetadataParams,
        cb?: (status: CallbackStatus, result: RemoveChannelMetadataResult) => void
      ) => Promise<RemoveChannelMetadataResult>,
  
      getMemberships: (
        parameters: GetMembershipsParams,
        cb?: (status: CallbackStatus, result: GetMembershipsResult) => void
      ) => Promise<GetMembershipsResult>,
      setMemberships: (
        parameters: $Diff<UpsertMembershipsParams, {| type: string |}>,
        cb?: (status: CallbackStatus, result: SetMembershipsResult) => void
      ) => Promise<SetMembershipsResult>,
      removeMemberships: (
        parameters: $Diff<RemoveMembershipsParams, {| type: string |}>,
        cb?: (status: CallbackStatus, result: SetMembershipsResult) => void
      ) => Promise<SetMembershipsResult>,
  
      getChannelMembers: (
        parameters: GetMembersParams,
        cb?: (status: CallbackStatus, result: GetMembersResult) => void
      ) => Promise<GetMembersResult>,
      setChannelMembers: (
        parameters: $Diff<UpsertMembersParams, {| type: string |}>,
        cb?: (status: CallbackStatus, result: SetMembersResult) => void
      ) => Promise<SetMembersResult>,
      removeChannelMembers: (
        parameters: $Diff<RemoveMembersParams, {| type: string |}>,
        cb?: (status: CallbackStatus, result: SetMembersResult) => void
      ) => Promise<SetMembersResult>,
    };
  
    // Objects API
  
    createUser: Function;
    updateUser: Function;
    deleteUser: Function;
    getUser: Function;
    getUsers: Function;
    createSpace: Function;
    updateSpace: Function;
    deleteSpace: Function;
    getSpaces: Function;
    getSpace: Function;
    getMembers: Function;
    addMembers: Function;
    updateMembers: Function;
    removeMembers: Function;
    getMemberships: Function;
    joinSpaces: Function;
    updateMemberships: Function;
    leaveSpaces: Function;
  
    disconnect: Function;
    reconnect: Function;
  
    destroy: Function;
    stop: Function;
  
    getSubscribedChannels: Function;
    getSubscribedChannelGroups: Function;
  
    addListener: Function;
    removeListener: Function;
    removeAllListeners: Function;
  
    parseToken: Function;
    setToken: Function;
    setTokens: Function;
    getToken: Function;
    getTokens: Function;
    clearTokens: Function;
  
    getAuthKey: Function;
    setAuthKey: Function;
  
    setCipherKey: Function;
    setUUID: Function;
    getUUID: Function;
  
    getFilterExpression: Function;
    setFilterExpression: Function;
  
    setHeartbeatInterval: Function;
  
    setProxy: Function;
  
    encrypt: Function;
    decrypt: Function;
  
    //
  
    constructor(setup: InternalSetupStruct) {
      let { db, networking, cbor } = setup;
  
      const config = (this._config = new Config({ setup, db }));
      const crypto = new Crypto({ config }); // LEGACY
  
      const cryptography = setup.cryptography;
  
      networking.init(config);
  
      const tokenManager = (this._tokenManager = new TokenManager(config, cbor));
      const telemetryManager = (this._telemetryManager = new TelemetryManager({
        maximumSamplesCount: 60000,
      }));
  
      let modules = {
        config,
        networking,
        crypto,
        cryptography,
        tokenManager,
        telemetryManager,
        PubNubFile: setup.PubNubFile,
      };
  
      this.File = setup.PubNubFile;
  
      this.encryptFile = (key, file) => cryptography.encryptFile(key, file, this.File);
      this.decryptFile = (key, file) => cryptography.decryptFile(key, file, this.File);
  
      const timeEndpoint = endpointCreator.bind(this, modules, timeEndpointConfig);
      const leaveEndpoint = endpointCreator.bind(this, modules, presenceLeaveEndpointConfig);
      const heartbeatEndpoint = endpointCreator.bind(this, modules, presenceHeartbeatEndpointConfig);
      const setStateEndpoint = endpointCreator.bind(this, modules, presenceSetStateConfig);
      const subscribeEndpoint = endpointCreator.bind(this, modules, subscribeEndpointConfig);
  
      // managers
      const listenerManager = (this._listenerManager = new ListenerManager());
  
      const subscriptionManager = new SubscriptionManager({
        timeEndpoint,
        leaveEndpoint,
        heartbeatEndpoint,
        setStateEndpoint,
        subscribeEndpoint,
        crypto: modules.crypto,
        config: modules.config,
        listenerManager,
        getFileUrl: (params) => getFileUrlFunction(modules, params),
      });
  
      this.addListener = listenerManager.addListener.bind(listenerManager);
      this.removeListener = listenerManager.removeListener.bind(listenerManager);
      this.removeAllListeners = listenerManager.removeAllListeners.bind(listenerManager);
  
      this.parseToken = tokenManager.parseToken.bind(tokenManager);
      this.setToken = tokenManager.setToken.bind(tokenManager);
      this.setTokens = tokenManager.setTokens.bind(tokenManager);
      this.getToken = tokenManager.getToken.bind(tokenManager);
      this.getTokens = tokenManager.getTokens.bind(tokenManager);
      this.clearTokens = tokenManager.clearTokens.bind(tokenManager);
  
      /* channel groups */
      this.channelGroups = {
        listGroups: endpointCreator.bind(this, modules, listChannelGroupsConfig),
        listChannels: endpointCreator.bind(this, modules, listChannelsInChannelGroupConfig),
        addChannels: endpointCreator.bind(this, modules, addChannelsChannelGroupConfig),
        removeChannels: endpointCreator.bind(this, modules, removeChannelsChannelGroupConfig),
        deleteGroup: endpointCreator.bind(this, modules, deleteChannelGroupConfig),
      };
      /* push */
      this.push = {
        addChannels: endpointCreator.bind(this, modules, addPushChannelsConfig),
        removeChannels: endpointCreator.bind(this, modules, removePushChannelsConfig),
        deleteDevice: endpointCreator.bind(this, modules, removeDevicePushConfig),
        listChannels: endpointCreator.bind(this, modules, listPushChannelsConfig),
      };
      /* presence */
      this.hereNow = endpointCreator.bind(this, modules, presenceHereNowConfig);
      this.whereNow = endpointCreator.bind(this, modules, presenceWhereNowEndpointConfig);
      this.getState = endpointCreator.bind(this, modules, presenceGetStateConfig);
      this.setState = subscriptionManager.adaptStateChange.bind(subscriptionManager);
      /* PAM */
      this.grant = endpointCreator.bind(this, modules, grantEndpointConfig);
      this.grantToken = endpointCreator.bind(this, modules, grantTokenEndpointConfig);
      this.audit = endpointCreator.bind(this, modules, auditEndpointConfig);
      //
      this.publish = endpointCreator.bind(this, modules, publishEndpointConfig);
  
      this.fire = (args, callback) => {
        args.replicate = false;
        args.storeInHistory = false;
        return this.publish(args, callback);
      };
  
      this.signal = endpointCreator.bind(this, modules, signalEndpointConfig);
  
      this.history = endpointCreator.bind(this, modules, historyEndpointConfig);
      this.deleteMessages = endpointCreator.bind(this, modules, deleteMessagesEndpointConfig);
      this.messageCounts = endpointCreator.bind(this, modules, messageCountsEndpointConfig);
      this.fetchMessages = endpointCreator.bind(this, modules, fetchMessagesEndpointConfig);
  
      // Actions API
  
      this.addMessageAction = endpointCreator.bind(this, modules, addMessageActionEndpointConfig);
  
      this.removeMessageAction = endpointCreator.bind(this, modules, removeMessageActionEndpointConfig);
  
      this.getMessageActions = endpointCreator.bind(this, modules, getMessageActionEndpointConfig);
  
      // File Upload API v1
  
      this.listFiles = endpointCreator.bind(this, modules, listFilesEndpointConfig);
  
      const generateUploadUrl = endpointCreator.bind(this, modules, generateUploadUrlEndpointConfig);
      this.publishFile = endpointCreator.bind(this, modules, publishFileEndpointConfig);
  
      this.sendFile = sendFileFunction({
        generateUploadUrl,
        publishFile: this.publishFile,
        modules,
      });
  
      this.getFileUrl = (params) => getFileUrlFunction(modules, params);
  
      this.downloadFile = endpointCreator.bind(this, modules, downloadFileEndpointConfig);
  
      this.deleteFile = endpointCreator.bind(this, modules, deleteFileEndpointConfig);
  
      // Objects API v2
  
      this.objects = {
        getAllUUIDMetadata: endpointCreator.bind(this, modules, getAllUUIDMetadataEndpointConfig),
        getUUIDMetadata: endpointCreator.bind(this, modules, getUUIDMetadataEndpointConfig),
        setUUIDMetadata: endpointCreator.bind(this, modules, setUUIDMetadataEndpointConfig),
        removeUUIDMetadata: endpointCreator.bind(this, modules, removeUUIDMetadataEndpointConfig),
  
        getAllChannelMetadata: endpointCreator.bind(this, modules, getAllChannelMetadataEndpointConfig),
        getChannelMetadata: endpointCreator.bind(this, modules, getChannelMetadataEndpointConfig),
        setChannelMetadata: endpointCreator.bind(this, modules, setChannelMetadataEndpointConfig),
        removeChannelMetadata: endpointCreator.bind(this, modules, removeChannelMetadataEndpointConfig),
  
        getChannelMembers: endpointCreator.bind(this, modules, getMembersV2EndpointConfig),
        setChannelMembers: (parameters: $Diff<UpsertMembersParams, {| type: string |}>, ...rest) =>
          endpointCreator.call(
            this,
            modules,
            setMembersV2EndpointConfig,
            {
              type: 'set',
              ...parameters,
            },
            ...rest
          ),
        removeChannelMembers: (parameters: $Diff<RemoveMembersParams, {| type: string |}>, ...rest) =>
          endpointCreator.call(
            this,
            modules,
            setMembersV2EndpointConfig,
            {
              type: 'delete',
              ...parameters,
            },
            ...rest
          ),
  
        getMemberships: endpointCreator.bind(this, modules, getMembershipsV2EndpointConfig),
        setMemberships: (parameters: $Diff<UpsertMembershipsParams, {| type: string |}>, ...rest) =>
          endpointCreator.call(
            this,
            modules,
            setMembershipsV2EndpointConfig,
            {
              type: 'set',
              ...parameters,
            },
            ...rest
          ),
        removeMemberships: (parameters: $Diff<RemoveMembershipsParams, {| type: string |}>, ...rest) =>
          endpointCreator.call(
            this,
            modules,
            setMembershipsV2EndpointConfig,
            {
              type: 'delete',
              ...parameters,
            },
            ...rest
          ),
      };
  
      // Objects API
  
      this.createUser = deprecated(endpointCreator.bind(this, modules, createUserEndpointConfig));
  
      this.updateUser = deprecated(endpointCreator.bind(this, modules, updateUserEndpointConfig));
  
      this.deleteUser = deprecated(endpointCreator.bind(this, modules, deleteUserEndpointConfig));
  
      this.getUser = deprecated(endpointCreator.bind(this, modules, getUserEndpointConfig));
  
      this.getUsers = deprecated(endpointCreator.bind(this, modules, getUsersEndpointConfig));
  
      this.createSpace = deprecated(endpointCreator.bind(this, modules, createSpaceEndpointConfig));
  
      this.updateSpace = deprecated(endpointCreator.bind(this, modules, updateSpaceEndpointConfig));
  
      this.deleteSpace = deprecated(endpointCreator.bind(this, modules, deleteSpaceEndpointConfig));
  
      this.getSpaces = deprecated(endpointCreator.bind(this, modules, getSpacesEndpointConfig));
  
      this.getSpace = deprecated(endpointCreator.bind(this, modules, getSpaceEndpointConfig));
  
      this.addMembers = deprecated(endpointCreator.bind(this, modules, addMembersEndpointConfig));
  
      this.updateMembers = deprecated(endpointCreator.bind(this, modules, updateMembersEndpointConfig));
  
      this.removeMembers = deprecated(endpointCreator.bind(this, modules, removeMembersEndpointConfig));
  
      this.getMembers = deprecated(endpointCreator.bind(this, modules, getMembersEndpointConfig));
  
      this.getMemberships = deprecated(endpointCreator.bind(this, modules, getMembershipsEndpointConfig));
  
      this.joinSpaces = deprecated(endpointCreator.bind(this, modules, joinSpacesEndpointConfig));
  
      this.updateMemberships = deprecated(endpointCreator.bind(this, modules, updateMembershipsEndpointConfig));
  
      this.leaveSpaces = deprecated(endpointCreator.bind(this, modules, leaveSpacesEndpointConfig));
  
      this.time = timeEndpoint;
  
      // subscription related methods
      this.subscribe = subscriptionManager.adaptSubscribeChange.bind(subscriptionManager);
      this.presence = subscriptionManager.adaptPresenceChange.bind(subscriptionManager);
      this.unsubscribe = subscriptionManager.adaptUnsubscribeChange.bind(subscriptionManager);
      this.disconnect = subscriptionManager.disconnect.bind(subscriptionManager);
      this.reconnect = subscriptionManager.reconnect.bind(subscriptionManager);
  
      this.destroy = (isOffline: boolean) => {
        subscriptionManager.unsubscribeAll(isOffline);
        subscriptionManager.disconnect();
      };
  
      // --- deprecated  ------------------
      this.stop = this.destroy; // --------
      // --- deprecated  ------------------
  
      this.unsubscribeAll = subscriptionManager.unsubscribeAll.bind(subscriptionManager);
  
      this.getSubscribedChannels = subscriptionManager.getSubscribedChannels.bind(subscriptionManager);
      this.getSubscribedChannelGroups = subscriptionManager.getSubscribedChannelGroups.bind(subscriptionManager);
  
      // mount crypto
      this.encrypt = crypto.encrypt.bind(crypto);
      this.decrypt = crypto.decrypt.bind(crypto);
  
      /* config */
      this.getAuthKey = modules.config.getAuthKey.bind(modules.config);
      this.setAuthKey = modules.config.setAuthKey.bind(modules.config);
      this.setCipherKey = modules.config.setCipherKey.bind(modules.config);
      this.getUUID = modules.config.getUUID.bind(modules.config);
      this.setUUID = modules.config.setUUID.bind(modules.config);
      this.getFilterExpression = modules.config.getFilterExpression.bind(modules.config);
      this.setFilterExpression = modules.config.setFilterExpression.bind(modules.config);
  
      this.setHeartbeatInterval = modules.config.setHeartbeatInterval.bind(modules.config);
  
      if (networking.hasModule('proxy')) {
        this.setProxy = (proxy) => {
          modules.config.setProxy(proxy);
          this.reconnect();
        };
      }
    }
  
    getVersion(): string {
      return this._config.getVersion();
    }
  
    _addPnsdkSuffix(name: string, suffix: string) {
      this._config._addPnsdkSuffix(name, suffix);
    }
  
    // network hooks to indicate network changes
    networkDownDetected() {
      this._listenerManager.announceNetworkDown();
  
      if (this._config.restore) {
        this.disconnect();
      } else {
        this.destroy(true);
      }
    }
  
    networkUpDetected() {
      this._listenerManager.announceNetworkUp();
      this.reconnect();
    }
  
    static notificationPayload(title: ?string, body: ?string): NotificationsPayload {
      return new NotificationsPayload(title, body);
    }
  
    static generateUUID(): string {
      return uuidGenerator.createUUID();
    }
  
    static OPERATIONS = OPERATIONS;
    static CATEGORIES = CATEGORIES;
  }
  