Newer
Older
import { knownUSPVersions } from "./util";
export type CommandType =
| "GET"
| "SET"
| "ADD"
| "DELETE"
| "OPERATE"
| "NOTIFY"
| "GET_SUPPORTED_DM"
| "GET_INSTANCES"
| "GET_SUPPORTED_PROTO";
export type SetCommandOptions = {
/**
* Prints raw set response message
*/
raw?: boolean;
};
Marin Karamihalev
committed
export type GetCommandGeneralOptions = {
/**
* Defaults to 2 (Only applies to usp version 1.2 )
*/
Marin Karamihalev
committed
};
export type GetCommandOptions = {
raw?: boolean;
Marin Karamihalev
committed
* All results will be nestled into { result: <result>, __query__: <full path> } (defaults to false)
* @deprecated Use getNested instead
Marin Karamihalev
committed
} & 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>[];
Marin Karamihalev
committed
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 }[];
};
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>;
};
};
}[];
};
};
};
};
export type SetRawResponse = {
header: {
msgId: string;
msgType: "SET_RESP";
};
body: {
response: {
setResp: {
updatedObjResults: {
requestedPath: string;
operStatus: {
operSuccess: {
updatedInstResults: [
{
affectedPath: string;
updatedParams: Record<string, string>;
}
];
};
};
}[];
};
};
};
};
Marin Karamihalev
committed
export type GetNestedReturn =
| UspProperty
| UspPropertyList
| UspObject
| UspObjectList;
export type GetCommand = (
paths: string | string[],
options?: GetCommandOptions
) => Promise<GetReturn>;
Marin Karamihalev
committed
export type GetNestedCommand = (<T = GetNestedReturn>(
path: string,
options?: GetNestedCommandOptions
) => Promise<T>) &
(<T = GetNestedReturn>(
paths: string[],
options?: GetNestedCommandOptions
) => Promise<T[]>);
value:
| (JSValue | JSValue[] | InputRecord)
| (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 = ((
Marin Karamihalev
committed
path: string | string[],
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 = (
path: string | string[],
allowPartial?: boolean
Marin Karamihalev
committed
) => Promise<string[]>;
export type OperateSubscribeOptions = {
/**
* Skip response from calling operate, defaults to true
*/
Marin Karamihalev
committed
skipOperateResponse?: boolean;
};
export type OperateFn = {
Marin Karamihalev
committed
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,
Marin Karamihalev
committed
input?: Record<string, 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
Marin Karamihalev
committed
| GetNestedCommand
| SetCommand
| AddCommand
| DelCommand
| OperateRecipe
| SubscribeRecipe
| SupportedDMCommand
| InstancesCommand
| SupportedProtoCommand;
export type PbRequestCommand =
| PbRequestCommandGet
| PbRequestCommandSet
| PbRequestCommandAdd
| PbRequestCommandDel
| PbRequestCommandOperate
| PbRequestCommandSupport
| PbRequestCommandInstance
export interface SuportedCommandOpts {
firstLevelOnly?: boolean;
returnCommands?: boolean;
returnEvents?: boolean;
returnParams?: boolean;
export type InputRecord = {
[k: string]:
| {
required: boolean;
value: any;
}
| string
| number
| boolean;
} & { allowPartial?: boolean };
export type PbRequestCommandNotifyResp = {
notifyResp: {
subscriptionId: string;
};
};
export type PbRequestCommandNotify = {
notify: {
subscriptionId: string;
sendResp: boolean;
[key: string]: unknown;
};
};
export type PbRequestCommandSupportProto = {
getSupportedProtocol: {
controllerSupportedProtocolVersions: string;
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
};
};
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;
paramSettings: {
lookup: SetLookupUpdateParamSetting;
param: string;
value: any;
required: boolean;
}[];
}[];
};
};
Marin Karamihalev
committed
export type AddLookupCreateObject = "Add.CreateObject";
export type AddLookupCreateParamSetting = "Add.CreateParamSetting";
export type PbRequestCommandAdd = {
add: {
allowPartial: boolean;
createObjs: {
Marin Karamihalev
committed
lookup: AddLookupCreateObject;
objPath: string;
paramSettings: {
param: string;
value: any;
required: boolean;
Marin Karamihalev
committed
lookup: AddLookupCreateParamSetting;
}[];
}[];
};
};
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;
Marin Karamihalev
committed
/** Options that allow extending command funcitonality */
export type Options = {
/** Timeout command after given number of milliseconds (throws an error for handling with catch) */
/** 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
committed
};
export interface USP {
Marin Karamihalev
committed
* @param path Location of value (e.g. "Device.DeviceInfo." or an array of multiple paths)
* @param options Get options (not required)
* 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
get: GetCommand;
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;
* Set value at path
* @param path Location of value (e.g. "Device.DeviceInfo.")
* @param value Value to assign
* @returns Object that respresents executed change
* ```
* await usp.set("Device.WiFi.Radio.1.", { Name: "radio-1" })
* 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" }]
)
set: SetCommand;
/**
* 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
* const [ping, cleanPing] = await usp.operate("Device.IP.Diagnostics.IPPing()")
* const results = await ping({ Host: "iopsys.eu" })
* await cleanPing()
Marin Karamihalev
committed
* // 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)
operate: OperateRecipe;
* 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
committed
* @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
committed
* await usp.add("Device.NAT.PortMapping.", { Description: "cpe-1" })
* await usp.add("Device.NAT.PortMapping.", { Description: "cpe-1", allowPartial: true })
Marin Karamihalev
committed
* 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" }]
);
add: AddCommand;
* 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
committed
* @returns String array of affected paths
* ```
* await usp.del("Device.NAT.PortMapping.1.")
* await usp.del("Device.NAT.PortMapping.1.", true)
del: DelCommand;
* 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;
/**
* @param versions Controller supported protocol versions
supportedProto: SupportedProtoCommand;
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
* 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
committed
/**
* 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;
Marin Karamihalev
committed
/**
* 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 {
Marin Karamihalev
committed
id?: string;
notif: NotifType;
reference: string | string[];
export type SubscriptionCallback = (
msg: Response,
fullMsg?: Record<string, any>
) => void;
export interface OperateOptions {
Marin Karamihalev
committed
sendResponse?: boolean;
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;
Marin Karamihalev
committed
fromId?: string;
toId?: string;
idEndpoint?: string;
publishEndpoint?: string;
subscribeEndpoint?: string;
ca?: CertType | Object[];
key?: CertType;
cert?: CertType;
/**
* Close connection if disconnected
*/
closeOnDisconnect?: boolean;
/**
* 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;
};
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 = {
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;
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;