Skip to content
Snippets Groups Projects
types.ts 20.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • import { knownUSPVersions } from "./util";
    
    
    export type CommandType =
      | "GET"
      | "SET"
      | "ADD"
      | "DELETE"
      | "OPERATE"
      | "NOTIFY"
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
      | "NOTIFY_RESP"
    
      | "GET_SUPPORTED_DM"
      | "GET_INSTANCES"
      | "GET_SUPPORTED_PROTO";
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
    export type SetCommandOptions = {
      /**
       * Prints raw set response message
       */
      raw?: boolean;
    };
    
    
      /**
       * Defaults to 2 (Only applies to usp version 1.2 )
       */
    
      max_depth?: number;
    
       * All results will be nestled into { result: <result>, __query__: <full path> } (defaults to false)
       * @deprecated Use getNested instead
    
       */
      retainPath?: boolean;
    
    } & GetCommandGeneralOptions;
    
    export type GetNestedCommandOptions = {} & GetCommandGeneralOptions;
    
    type ReturnValue =
      | string
      | { __query__: string; [key: string]: ReturnValue | ReturnValue[] }
      | { __query__: string; [key: string]: ReturnValue | ReturnValue[] }[];
    
    export type GetReturn = string | Record<string, any> | Record<string, any>[];
    
    
    export type UspProperty = {
      __query__: string;
      result: string;
    };
    
    export type UspPropertyList = {
      __query__: string;
      result: { __query__: string; result: string }[];
    };
    
    export type UspObject = {
      __query__: string;
      result: { __query__: string; [key: string]: ReturnValue };
    };
    
    export type UspObjectList = {
      __query__: string;
      result: { __query__: string; [key: string]: ReturnValue }[];
    };
    
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
    export type SetResponse = {
      affectedPath: string;
      updatedParams: Record<string, string>;
    }[];
    
    
    export type AddResponse = string[];
    
    export type AddRawResponse = {
      header: {
        msgId: string;
        msgType: "ADD_RESP";
      };
      body: {
        response: {
          addResp: {
            createdObjResults: {
              requestedPath: string;
              operStatus: {
                operSuccess: {
                  instantiatedPath: string;
                  uniqueKeys: Record<string, string>;
                };
              };
            }[];
          };
        };
      };
    };
    
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
    export type SetRawResponse = {
      header: {
        msgId: string;
        msgType: "SET_RESP";
      };
      body: {
        response: {
          setResp: {
            updatedObjResults: {
              requestedPath: string;
              operStatus: {
                operSuccess: {
                  updatedInstResults: [
                    {
                      affectedPath: string;
                      updatedParams: Record<string, string>;
                    }
                  ];
                };
              };
            }[];
          };
        };
      };
    };
    
    
    export type GetNestedReturn =
      | UspProperty
      | UspPropertyList
      | UspObject
      | UspObjectList;
    
    
    export type GetCommand = (
      paths: string | string[],
      options?: GetCommandOptions
    ) => Promise<GetReturn>;
    
    export type GetNestedCommand = (<T = GetNestedReturn>(
      path: string,
      options?: GetNestedCommandOptions
    ) => Promise<T>) &
      (<T = GetNestedReturn>(
        paths: string[],
        options?: GetNestedCommandOptions
      ) => Promise<T[]>);
    
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
    export type SetCommand = ((
    
      path: string | string[],
    
      value:
        | (JSValue | JSValue[] | InputRecord)
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
        | (JSValue | JSValue[] | InputRecord)[],
      options?: { raw?: false } & SetCommandOptions
    ) => Promise<SetResponse>) &
      ((
        path: string | string[],
        value:
          | (JSValue | JSValue[] | InputRecord)
          | (JSValue | JSValue[] | InputRecord)[],
        options: { raw: true } & SetCommandOptions
      ) => Promise<SetRawResponse>);
    
    export type AddCommand = ((
    
      value:
        | (JSValue | JSValue[] | InputRecord)
        | (JSValue | JSValue[] | InputRecord)[]
        | null
        | undefined,
      options?: { raw?: false }
    ) => Promise<AddResponse>) &
      ((
        path: string | string[],
        value:
          | (JSValue | JSValue[] | InputRecord)
          | (JSValue | JSValue[] | InputRecord)[]
          | null
          | undefined,
        options: { raw: true }
      ) => Promise<AddRawResponse>);
    
    export type DelCommand = (
    
    
    export type OperateSubscribeOptions = {
      /**
       * Skip response from calling operate, defaults to true
       */
    
      subscribe: (
        cb: (msg: any) => void,
        opts?: OperateSubscribeOptions
      ) => {
    
        trigger: (input?: Record<string, any>) => Promise<any>;
      };
      (input?: Record<string, string>): Promise<any>;
    };
    
    export type OperateClearFn = () => Promise<void>;
    export type OperateRecipe = (
      path: string,
      opts?: OperateOptions
    ) => Promise<[OperateFn, OperateClearFn]>;
    
    export type OperateCommand = (
      path: string,
      id: string,
    
      resp: boolean,
    
    ) => Promise<any>;
    
    export type SupportedDMCommand = (
      paths: string | string[],
      opts?: SuportedCommandOpts
    ) => Promise<Record<string, any>>;
    export type InstancesCommand = (
      paths: string | string[],
    
      opts?: { firstLevelOnly?: boolean }
    
    ) => Promise<Record<string, any>>;
    
    export type SupportedProtoCommand = (version?: USPVersion) => Promise<string[]>;
    
    export type SubscribeRecipe = (
      opts: SubscriptionOptions,
      callback: SubscriptionCallback
    ) => Promise<PromiseClearFn>;
    
    export type PromiseClearFn = () => Promise<void>;
    
    export type Command =
      | GetCommand
    
      | SetCommand
      | AddCommand
      | DelCommand
    
      | OperateCommand
    
      | OperateRecipe
      | SubscribeRecipe
      | SupportedDMCommand
      | InstancesCommand
      | SupportedProtoCommand;
    
    export type PbRequestCommand =
      | PbRequestCommandGet
      | PbRequestCommandSet
      | PbRequestCommandAdd
      | PbRequestCommandDel
      | PbRequestCommandOperate
      | PbRequestCommandSupport
      | PbRequestCommandInstance
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
      | PbRequestCommandSupportProto
    
      | PbRequestCommandNotify
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
      | PbRequestCommandNotifyResp;
    
    
    export interface SuportedCommandOpts {
      firstLevelOnly?: boolean;
      returnCommands?: boolean;
      returnEvents?: boolean;
      returnParams?: boolean;
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
    }
    
    
    export type InputRecord = {
      [k: string]:
        | {
            required: boolean;
            value: any;
          }
        | string
        | number
        | boolean;
    } & { allowPartial?: boolean };
    
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
    export type PbRequestCommandNotifyResp = {
      notifyResp: {
        subscriptionId: string;
      };
    };
    
    
    export type PbRequestCommandNotify = {
      notify: {
        subscriptionId: string;
        sendResp: boolean;
        [key: string]: unknown;
      };
    };
    
    
    export type PbRequestCommandSupportProto = {
      getSupportedProtocol: {
    
        controllerSupportedProtocolVersions: string;
    
      };
    };
    
    export type PbRequestCommandInstance = {
      getInstances: {
        objPaths: string[];
        firstLevelOnly: boolean;
      };
    };
    
    export type PbRequestCommandSupport = {
      getSupportedDm: {
        objPaths: string[];
        firstLevelOnly: boolean;
        returnCommands: boolean;
        returnEvents: boolean;
        returnParams: boolean;
      };
    };
    
    export type PbRequestCommandOperate = {
      operate: {
        command: string;
        commandKey: string;
        sendResp: boolean;
        inputArgs: Record<string, any>;
      };
    };
    
    export type PbRequestCommandDel = {
      delete: {
        allowPartial: boolean;
        objPaths: string[];
      };
    };
    
    export type PbRequestCommandGet = {
      get: {
        paramPaths: string[];
      };
    };
    
    
    export type SetLookupUpdateObject = "Set.UpdateObject";
    export type SetLookupUpdateParamSetting = "Set.UpdateParamSetting";
    
    
    export type PbRequestCommandSet = {
      set: {
        allowPartial: boolean;
        updateObjs: {
          objPath: string;
    
          lookup: SetLookupUpdateObject;
    
            lookup: SetLookupUpdateParamSetting;
    
            param: string;
            value: any;
            required: boolean;
          }[];
        }[];
      };
    };
    
    
    export type AddLookupCreateObject = "Add.CreateObject";
    export type AddLookupCreateParamSetting = "Add.CreateParamSetting";
    
    
    export type PbRequestCommandAdd = {
      add: {
        allowPartial: boolean;
        createObjs: {
    
          objPath: string;
          paramSettings: {
            param: string;
            value: any;
            required: boolean;
    
          }[];
        }[];
      };
    };
    
    export type Recipe = ResolveRecipe;
    export type ResolveRecipe = (
      msg: GetReturn,
      level?: number
    ) => Promise<GetReturn>;
    
    
    export type PreCallCallback = (name: string, args: any[]) => void;
    export type PostCallCallback = (name: string, args: any[], result: any) => void;
    
    /** Options that allow extending command funcitonality */
    export type Options = {
      /** Timeout command after given number of milliseconds (throws an error for handling with catch) */
    
      timeout?: number;
    
      /** Call function before command */
      preCall?: PreCallCallback;
      /** Call after before command */
      postCall?: PostCallCallback;
    
      get?: {
        /**
         * Set the retainPath option to all get calls
         */
        retainPath?: boolean;
      };
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
    /** Device API */
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * Get value at path
    
       * @param path Location of value (e.g. "Device.DeviceInfo." or an array of multiple paths)
       * @param options Get options (not required)
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * ```
       * await usp.get("Device.WiFi.Radio.1.")
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * await usp.get(["Device.WiFi.Radio.1.", "Device.WiFi.Radio.2."])
    
       *
       * await usp.get("Device.WiFi.Radio.1.", { raw: true }) // skips parsing, produces raw results
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * ```
       */
    
      /**
       * Get value at path, returns  values with their full path stored in "__query__" key
       * @param path Location of value (e.g. "Device.DeviceInfo." or an array of multiple paths)
       * @param options Get options (not required)
       * ```
       * await usp.getNested("Device.WiFi.Radio.1.")
       *
       * await usp.getNested(["Device.WiFi.Radio.1.", "Device.WiFi.Radio.2."])
       *
       * await usp.getNested("Device.WiFi.Radio.1.", { max_depth: 4 })
       * // providing return type
       * await usp.getNested<UspProperty>("Device.WiFi.Radio.1.Alias")
       *
       * await usp.getNested<UspPropertyList>("Device.WiFi.Radio.*.Alias")
       *
       * await usp.getNested<UspObject>("Device.WiFi.Radio.1.")
       *
       * await usp.getNested<UspObjectList>("Device.WiFi.Radio.*.")
       *
       * await usp.getNested<UspProperty>(["Device.WiFi.Radio.1.Alias", "Device.WiFi.Radio.2.Alias"])
       * ```
       */
      getNested: GetNestedCommand;
    
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * Set value at path
       * @param path Location of value (e.g. "Device.DeviceInfo.")
       * @param value Value to assign
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * @returns Object that respresents executed change
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * ```
       * await usp.set("Device.WiFi.Radio.1.", { Name: "radio-1" })
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * await usp.set("Device.WiFi.Radio.1.Name", "radio-1")
    
       * // or
       * await usp.set(
          ["Device.NAT.PortMapping.1.", "Device.NAT.PortMapping.2."],
          [{ Description: "cat-1" }, { Description: "cat-2" }]
        )
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * ```
       */
    
      /**
       * Create a command
       * @param path Full path of command (e.g. "Device.IP.Diagnostics.IPPing()")
       * @param opts Subscription options (not required)
       * @returns Function that executes command
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * ```
    
       * const [ping, cleanPing] = await usp.operate("Device.IP.Diagnostics.IPPing()")
       * const results = await ping({ Host: "iopsys.eu" })
       * await cleanPing()
    
       * // sync command example, no need to get cleanup function as there is nothing to clean up with sync commands
       * const [op] = await device.operate("Device.WiFi.Reset()", { isAsync: false })
       * await op().then(log).catch(log)
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * ```
       */
    
       * Directly call operate without creating a subscription (avoid using unless certain subscription exists),
       * useful for calling sync operate commands for which either output is expected in response or
       * no output is expected
    
       * @param path Full path of command (e.g. "Device.IP.Diagnostics.IPPing()")
       * @param id Full id of subscription (can be found in Device.LocalAgent.Subscription.)
    
       * @param resp to get the response of operate command, useful when response has output
    
       * @param input Optional arguments for command
       * @returns Command results
       * ```
    
       * await usp._operate("Device.Reboot()", 'msg-1', false)
       * await usp._operate("Device.LocalAgent.ControllerTrust.RequestChallenge()", 'msg-2', true, {ChallengeRef: "Device.LocalAgent.ControllerTrust.Challenge.1"})
    
       * ```
       */
      _operate: OperateCommand;
    
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * Add object to path
    
       * @param path Path to add to (e.g. "Device.NAT.PortMapping." or ["Device.NAT.PortMapping."] for multiple)
       * @param values Optional object to add (if skipped will use default values), allows using arrays for multiple objects
       * @returns Full path(s) of new object(s)
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * ```
       * await usp.add("Device.NAT.PortMapping.")
    
       * await usp.add("Device.NAT.PortMapping.", { Description: "cpe-1" })
    
       * await usp.add("Device.NAT.PortMapping.", { Description: "cpe-1", allowPartial: true })
    
       * await usp.add("Device.NAT.PortMapping.", { Description: { value: "cpe-1", required: false }, allowPartial: true })
       * await usp.add(
          ["Device.NAT.PortMapping.", "Device.NAT.PortMapping."],
          [{ Description: "cpe-1" }, { Description: "cpe-2" }]
        );
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * ```
       */
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * Delete object at path
       * @param path Full path to delete (e.g. "Device.NAT.PortMapping.1.")
    
       * @param allowPartial [Optional] Allow partial (defaults to false)
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * ```
       * await usp.del("Device.NAT.PortMapping.1.")
    
       * await usp.del("Device.NAT.PortMapping.1.", true)
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * ```
       */
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * Resolve references in message
       * @param msg Message with reference in it
       * @param level Optional level of nesting to resolve to (avoid using high numbers)
       * ```
       * await usp.get("Device.WiFi.Radio.1.").then(device.resolve)
       * ```
       */
    
      resolve: ResolveRecipe;
    
      /**
       * Get Supported DM
       * @param paths Path(s)
       * @param opts [Optional] Response options
       * ```
       * await usp.supportedDM("Device.WiFi.")
       * ```
       */
      supportedDM: SupportedDMCommand;
    
      /**
    
       * Get Supported Protocols
    
       * @param versions Controller supported protocol versions
    
       * await usp.supportedProto()
    
       * await usp.supportedProto("1.0")
    
      supportedProto: SupportedProtoCommand;
    
       * Get instances
       * @param paths Path(s)
       * @param firstLevelOnly [Optional] Return only first level
       * ```
       * await usp.instances("Device.WiFi.")
       * ```
       */
      instances: SupportedDMCommand;
    
      /**
       * Subscribe to event
       * @param options Subscription options
       * @param callback Callback on relevant message
       * @returns Returns function to clear subscription
       * ```
       * const clearSub = await usp.subscribe({ id: '1234', notif: 'ObjectCreation', reference: 'Device.NAT.PortMapping.' }, console.log)
       * ```
       */
      subscribe: SubscribeRecipe;
    
      /**
       * Add handler for messages
       * @param ident Message identifier (identifies by id, can be a string or regexp)
       * @param callback Callback on relevant message
       * @returns Returns function to clear handler
       * ```
       * const clear = usp.on("error", () => console.log('An error!'))
       * ```
       */
      on: OnFn;
    
      /**
       * Disconnect from device
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
       * ```
       * await usp.disconnect()
       * ```
       */
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
      disconnect: () => Promise<void>;
    
    
      /**
       * Add general options to commands, extending their functionality
       * @param opts Options
       * @returns Entire USP API
       * ```
       * await usp.options({ timeout: 1000 }).get("Device.DeviceInfo.SerialNumber")
       * ```
       */
      options: (opts: Options) => USP;
    
      /**
       * Gets current usp version (used by usp-js library for parsing incoming messages)
       * @returns USP Version
       * ```
       * usp.getUspVersion()
       * ```
       */
      getUSPVersion: () => USPVersion;
      /**
       * Sets current usp version (only applies to version used by the library, not the version used by the agent, mostly for testing purposes)
       * To set the version used by the agent use the supportedProto function
       * @returns USP Version
       * ```
       * usp.setUspVersion("1.1")
       * ```
       */
      setUSPVersion: (version: USPVersion) => void;
    
    /**
     * Connect to device
     * @param opts - Connection options
     * @param events - Optional event handlers
     * @returns A set of functions for interacting with the device
     */
    
    export type Connect = (
      options: ConnectionOptions,
      events?: ConnectionEvents
    ) => Promise<USP>;
    
    
    type NotifType =
      | "Event"
      | "ValueChange"
      | "ObjectCreation"
      | "ObjectDeletion"
      | "OperationComplete"
      | "OnBoardRequest";
    
    export interface SubscriptionOptions {
    
      retry?: boolean;
    
      reference: string | string[];
    
    export type SubscriptionCallback = (
      msg: Response,
      fullMsg?: Record<string, any>
    ) => void;
    
    export interface OperateOptions {
    
      ID?: string;
      Persistent?: boolean;
    
      isAsync?: boolean;
    
      commandKey?: string;
    
    export interface PbRequestHeader {
      msgId: string;
      msgType: CommandType;
      lookup: "Header";
    
    export interface PbRequestBody {
      lookup: "Body";
      request: {
        lookup: "Request";
      } & PbRequestCommand;
    
    export interface PbRequestMessage {
      header: PbRequestHeader;
      body: PbRequestBody;
      lookup: "Msg";
    
    export type URLConnectionOptions = {
      url: string;
    } & OtherConnectionOptions;
    
    export type HostConnectionOptions = {
      host: string;
      port: number;
      protocol: "wss" | "ws" | "mqtt" | "mqtts" | "tcp" | "ssl" | "wx" | "wxs";
    
    } & OtherConnectionOptions;
    
    export type CertType = string | string[] | Buffer | Buffer[];
    
    export type USPVersion = typeof knownUSPVersions[number];
    
    export interface OtherConnectionOptions {
      username: string;
      password: string;
    
      fromId?: string;
      toId?: string;
      idEndpoint?: string;
    
      publishEndpoint?: string;
      subscribeEndpoint?: string;
    
      version?: USPVersion;
    
      ca?: CertType | Object[];
      key?: CertType;
      cert?: CertType;
    
      /**
       * Close connection if disconnected
       */
    
      /**
       * Number of times to attempt reconnecting before closing connection
       */
    
      reconnectsBeforeClosing?: number;
    
      /**
       * Timeout in milliseconds for connection
       */
    
      connectTimeout?: number;
    
      /**
       * Use latest available usp version (defaults to true)
       */
      useLatestUSPVersion?: boolean;
    
    export type ConnectionOptions = URLConnectionOptions | HostConnectionOptions;
    
    export type Response = string | Record<string, any>;
    
    export type CommandOptions = GetCommandOptions;
    
    
    export type DecodeOptions = {
      raw?: boolean;
    
      retainPath?: boolean;
    
    };
    
    export type DecodeFn = (
      msg: Record<string, any>,
      decodeOptions?: DecodeOptions
    ) => DecodeResponse | [any];
    
    export type DecodeResponse =
      | [any]
      | [any, ResponseID | null, null | Response]
      | [any, ResponseID | null, null | Response, CommandType];
    
    export type EncodeArgs = {
    
      rootMsg: any;
      rootRecord: any;
    
      header: any;
      options: Record<string, string>;
      args: Record<string, any>;
    };
    
    export type OnIdent = string | RegExp;
    
    
    export type CallbackOptions = {
      sendResp: boolean
    }
    
    export type OnCallback = (
      msg: Response,
      fullMsg?: Record<string, any>,
      opts?: CallbackOptions
    ) => void;
    
    
    export type EncodeFn = (args: Record<string, any>) => PbRequestMessage;
    export type CallArgs = Record<string, any>;
    export type ClearFn = () => void;
    
    export type OnFn = (ident: OnIdent, callback: OnCallback) => ClearFn;
    
    export type MakeFn = (call: CallFn, on: OnFn) => Command;
    export type MakeRecipeFn = (call: CallFn) => Recipe;
    export type CommandTrigger = {
      decode: string | ((msg: Record<string, string>) => boolean);
      encode: string;
    };
    export type CommandObject = {
      encode: EncodeFn;
      decode: DecodeFn;
    };
    
    export interface ConnectionEvents {
      onError?: (err: string) => void;
    
      onOffline?: () => void;
      onReconnect?: () => void;
      onClose?: () => void;
    
    export interface RecipeObject {
      name: string;
      make: MakeFn;
    
    Marin Karamihalev's avatar
    Marin Karamihalev committed
    }
    
    export type CallOptions = {
      responseMsgType?: CommandType;
    };
    
    
    export type ResponseID = "ignore" | "error" | string;
    export type JSValue = string | number | boolean;
    
    export type CallFn = (
      cmd: CommandType,
      args: Record<string, any>,
      callOpts?: CallOptions
    ) => Promise<any>;
    
    
    export type ConnectionClient = {
      on: (key: string, responseFn: (topic: string, data: any) => void) => void;
      subscribe: (to: string) => void;
      unsubscribe: (from: string) => void;
      publish: (endpoint: string, msg: any) => void;
      end: () => void;
    };
    
    
    export type ConnectClientFn = (
      options: ConnectionOptions
    ) => Promise<ConnectionClient>;
    
    
    export type DecodeIDFn = (data: any) => string;
    
    export type Proto = {
    
      rootRecord: any;
      rootMsg: any;
    
    export type LoadProtobufFn = (version: USPVersion) => Promise<Proto>;
    
    export type BuildConnectionFn = (connectConfig: {
      connectClient: ConnectClientFn;
      decodeID: DecodeIDFn;
      loadProtobuf: LoadProtobufFn;
    }) => Connect;