workspace-integrations
Version:
Webex Workspace Integrations NodeJS SDK
383 lines (382 loc) • 14.2 kB
TypeScript
/**
* Entry point for this library. Initalises your Workspace integration and returns an integration object (async),
* which you can then use for Webex APIs, including invoke commands, read status values,
* set configs, subscribe to notifications, etc.
*
* Throws an exception if unable to connect.
*/
export type connect = (options: IntegrationConfig) => Promise<Integration>;
/**
* Defines a public web hook where Webex will send notifications to you for status changes and events on devices.
*/
export interface Webhook {
/** Must be https */
targetUrl: string;
/**
* Passing 'none' will delete the web hook
*/
type: 'hmac_signature' | 'basic_authentication' | 'none';
/** This will be sent with every web hook. You can use it to verify that the web hook came from Webex. */
secret: string;
/** Username if using basic auth */
username?: string;
/** Password if using basic auth */
password?: string;
}
/**
* Error level works in an expanding way, eg 'error' will only show errors,
* 'warn' will show warnings and errors, etc.
*/
export type LogLevel = 'error' | 'warn' | 'info' | 'verbose';
export interface AppConfig {
appId: string;
appSecret: string;
accessToken: string;
activationCode: ActivationCode;
tokenExpiryTime: string;
pollUrl?: string;
}
export interface ActivationCode {
oauthUrl: string;
refreshToken: string;
webexapisBaseUrl: string;
appUrl: string;
}
export type NotificationType = 'webhook' | 'longpolling' | 'none';
/**
* Your configs for initialising your Workspace Integration.
* Must contain client id and secret, which you get when deploying the integration in Control Hub,
* as well as the JSON Web Token (activationCode) which you get when you activate it.
*/
export interface IntegrationConfig {
clientId: string;
clientSecret: string;
activationCode: ActivationCode;
/**
* How you want your integration to receive device notifications such as events
* and status updates.
*
* - webhook: Webex posts the notification to a public web server that you control
* - longpolling: Your integration using [long polling](https://javascript.info/long-polling)
* to get notifications.
* - none: you won't receive any notifications
*/
notifications: NotificationType;
/** Required if you set {@link notifications} to `webhook`. */
webhook?: Webhook;
/**
* Public URL endpoint to send signed JWT actions, such as health check, app update, deactivation etc
*/
actionsUrl?: string;
/**
* Which info to show from the SDK. Default is error only.
*/
logLevel?: LogLevel;
}
/**
* A notification sent to your integration from Webex, either when an xStatus changes or when
* an xEvent occurs. Remember that you will only receive notifications for APIs you have set
* in your manifest.
*/
export interface Notification {
appId: string;
deviceId: string;
workspaceId: string;
orgId: string;
timestamp: string;
type: 'status' | 'event' | 'healthCheck';
}
/**
* Called when a device has an event that matches the path you are listening to.
* Remember to add the path to the manifest xAPI event scope too.
*/
export type EventListener = (deviceId: string, path: string, event: DataObject, data: Notification) => void;
/**
* Called when a device has a status update that matches the path you are listening to.
* Remember to add the path to the manifest xAPI status scope too.
*
* Note: if the status path you are listening to is removed (for dynamic lists such as
* xStatus Call[...], xStatus Conference Presentation LocalInstance[...] etc),
* the value param will be set to { ghost: true } to notify this
*/
export type StatusListener = (deviceId: string, path: string, value: DataObject, data: Notification) => void;
/**
* All xAPIs are defined by a path in a tree fashion, eg:
*
* - xCommand Call Disconnect
* - xConfiguration Audio DefaultVolume
* - xStatus Audio Volume
* - xEvent UserInterface Extensions Widget Action
*
* In this SDK, the type (command, event etc) is not necessary because it's given by the context.
* You can also use . or space as path separator (`Call.Disconnect` or `Call Disconnect`).
*/
export type XapiPath = string;
/**
* The API of the Cisco collaboration devices (RoomOS).
*
* Read more on [roomos.cisco.com](https://roomos.cisco.com/doc/TechDocs/Introduction).
*
* All xAPIS are accessed with a path, for example `Call.Disconnect`, `Audio.Volume` etc. Find the
* the xAPIs that you need in the [xAPI section](https://roomos.cisco.com/xapi) and copy the path
* from the snippet section.
*
* Status, commands and events that you use needs to be specified in the manifest, but this does
* not apply for configurations (for historical reasons).
*/
export interface XAPI {
command: Command;
status: Status;
event: Event;
config: Config;
}
/**
* Invoke a command on a Cisco device. Commands are typically non-persistent actions that users do
* from the user interface, such as starting a call, changing the volume etc. Also advanced
* configurations such as saving macros and setting custom wallpaper can be commands.
*
* Some commands such as Phonebook search also returns results back to the user, this is provided
* as a promise result.
*
* @param multiline For commands that accept large blobs of content, such as wallpaper image,
* macro content, booking XML etc. *
*/
export type Command = (deviceId: string, path: XapiPath, params?: DataObject, multiline?: string) => Promise<DataObject>;
/**
* A generic dictionary object (JSON-like)
*/
export type DataObject = Record<string, any>;
/**
* Device statuses are typically states, sensor data etc that can change at any time.
* There are two ways to get status info:
* 1. Query them (`get`)
* 2. Subscribe to them (`on`). In this case you will be notified whenever a status changes.
* Note: Only a few statuses actually support notifications.
*/
export interface Status {
/**
* allowEmpty: if set to true, returns empty array if path was not found, otherwise it throws error.
* Typically useful when working with dynamic lists.
*/
get: (deviceId: string, path: XapiPath, allowEmpty?: boolean) => Promise<DataObject | number | string>;
on: (path: XapiPath, listener: StatusListener) => void;
}
/**
* Device events are typically events that occur at a singular point in time and don't last
* long, such as incoming button press on a UI extension, incoming call, system boot etc.
* Workspace integrations only support a subset of all events,
* see Control Hub > Workspace integrations for an updated list.
*/
export interface Event {
on: (path: XapiPath, listener: EventListener) => void;
}
/**
* Device configurations (xConfigs) are typically permanent settings that are set by admins,
* such as default volume, wallpapers, digital signage, network settings, security policies etc.
*
* Find and read more about them on
* [roomos.cisco.com](https://roomos.cisco.com/xapi/?search=***&Type=Configuration).
*
* Scopes required: `spark-admin:devices_read` and `spark-admin:devices_write`
*
* The module is a wrapper fot for the
* [Device Configurations API](https://developer.webex.com/docs/api/v1/device-configurations).
*
* It is not possible to subscribe to config notifications. Also, unlike device status and events,
* you do not need to add the specific configs to the manifest.
*/
export interface Config {
get: (deviceId: string, path: XapiPath) => Promise<DataObject | number | string>;
/**
* Requires the spark-admin:devices-write scope
*/
set: (deviceId: string, path: XapiPath, value: string | number) => Promise<DataObject>;
/**
* Set multiple configs on a device with a single HTTP call. Requires the
* spark-admin:devices-write scope.
*
* Configs are set as key/value pairs in an object. Remember to use apostrophes for
* the keys too, since they usually contain dots.
*
* Eg:
* ```
* const configs = { 'Audio.DefaultVolume': 60, 'SystemUnit.TimeZone': 'Africa/Abidjan' };
* await integration.xapi.config.setMany(deviceId, configs);
* ```
*/
setMany: (deviceId: string, values: DataObject) => Promise<DataObject>;
}
/**
* Provides access to all the supported Webex APIs as child objects.
* Automatically takes care of retrieving and refreshing access tokens,
* as well as long polling for notifications, when that method is used.
*/
export interface Integration {
getAppInfo(): Promise<AppInfo>;
/**
* Sets an error handler on the integration, so you are notified when something goes wrong.
* This will typically be called if the SDK is not able to refresh the access token
* eg due to network issues or if Webex is not available.
*/
onError(handler: ErrorHandler): any;
/**
* Checks the state of the integration. Checks that it's able to talk to Webex,
* implying that the access token is valid etc.
* @returns Promise containing the http response from Webex
*/
ping(): Promise<any>;
/**
* Sets an action handler, so you are notified when there are important
* action notifications such as if the integration manifest was updated.
*/
onAction(handler: ActionHandler): any;
/**
* Takes a list of events from Webex and checks if you have event listeners registered that
* match the incoming notification, and if so deliver it.
*
* @param notifications The payload (list of messages) from an incoming Webex web hook
*/
processNotifications(notifications: DataObject[]): any;
refreshToken(): void;
webexApi(partialUrl: string, method?: string, body?: any, contentType?: string): Promise<any>;
/**
* Helper function for decoding a JSON Web Token.
* Throws error if not valid.
*
* @param jwt B64-encoded JWT string, as received from Webex
*/
decodeJwt(jwt: string): DataObject;
devices: Devices;
workspaces: Workspaces;
xapi: XAPI;
}
export interface Http {
/**
*
* @param partialUrl URL without the https://webexapis.com/v1/ part
*/
get(partialUrl: string): Promise<any>;
accessToken: string;
baseUrl: string;
}
/**
* A workspace is a location that can contain zero, one or many devices,
* typically a meeting room, huddle room, or reception.
*
* Module is a wrapper for the
* [Webex Workspaces API](https://developer.webex.com/docs/api/v1/workspaces).
*/
export interface Workspaces {
/**
* Find workspaces in the org.
*
* @param filter See query parameters on [here](https://developer.webex.com/docs/api/v1/workspaces/list-workspaces)
*/
getWorkspaces(filters?: DataObject): Promise<Workspace[]>;
/**
* Get workspace details.
* Wrapper for https://developer.webex.com/docs/api/v1/workspaces/get-workspace-details for more
*/
getWorkspace(workspaceId: string): Promise<Workspace>;
}
/**
* A Workspace is typically a room. It can contain zero, one or several Cisco devices.
*/
export interface Workspace {
id: string;
orgId: string;
workspaceLocationId: string;
displayName: string;
sipAddress: string;
capacity?: number;
type: 'notSet' | 'focus' | 'huddle' | 'meetingRoom' | 'open' | 'desk' | 'other' | string;
notes?: string;
/** Whether the workspace supports hot desking or not */
hotdeskingStatus: 'on' | 'off';
devicePlatform: string;
}
/**
* A Cisco collaboration device. Must belong to one and only one workspace.
*/
export interface Device {
id: string;
displayName: string;
workspaceId: string;
workspaceLocationId: string;
placeId: string;
orgId: string;
product: string;
/**
* - roomdesk: Cisco collaboration device (Board, Room Kit, Desk etc)
* - accessory: Cisco Navigator, etc
* - webexgo: Webex Calling device
*/
type: 'roomdesk' | 'accessory' | 'webexgo' | 'unknown';
/** The person owning the device, if it's in personal mode. */
personId?: string;
tags: string[];
ip: string;
mac: string;
/** Network connectivity type (LAN, wifi, ...) */
activeInterface: string;
primarySipUrl: string;
sipUrls: string[];
errorCodes: string[];
serial: string;
software: string;
upgradeChannel: string;
connectionStatus: 'connected' | 'disconnected' | 'connected_with_issues' | string;
created: string;
firstSeen: string;
lastSeen: string;
capabilities: string[];
permissions: string[];
devicePlatform: string;
}
export interface Devices {
/**
* Find all devices, optionally matching the filter.
*
* The filter parameters are defined on
* https://developer.webex.com/docs/api/v1/devices/list-devices.
*
* Example:
* ```js
* integration.devices.getDevices({ connectionStatus: 'connected', tag: 'sales-department' })
* ```
*
* Note that this method may also return devices that are not in the location the integration
* is approved for.
*
* @param filters Object containing the key/value pairs as in the Webex Devices API
*/
getDevices(filters?: DataObject): Promise<Device[]>;
getDevice(deviceId: string): Promise<Device>;
}
export type ErrorHandler = (error: string) => any;
export type ActionHandler = (action: DataObject) => any;
/**
* Info about your integration. Contains much of the information provided by the manifest.
* In particular, use this to check which optional scopes and xAPI's the admin has accepted.
*/
export interface AppInfo {
id: string;
manifestVersion: number;
scopes: string[];
roles: string[];
xapiAccessKeys: {
commands?: string[];
statuses?: string[];
events?: string[];
};
createdAt: string;
updatedAt: string;
provisioningState: string;
publicLocationIds: string[];
features?: Array<'digital_signage' | 'persistent_web_app'>;
queue?: {
pollUrl: string;
state: string;
};
availability: string;
}