@relaypro/sdk
Advanced tools
Comparing version 1.0.2 to 1.1.0
export declare const PORT: number; | ||
export declare const HEARTBEAT: number; | ||
export declare const STRICT_PATH: string; | ||
export declare const TIMEOUT = 5000; | ||
export declare const REFRESH_TIMEOUT = 45000; | ||
export declare const NOTIFICATION_TIMEOUT = 60000; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.REFRESH_TIMEOUT = exports.TIMEOUT = exports.STRICT_PATH = exports.HEARTBEAT = exports.PORT = void 0; | ||
exports.NOTIFICATION_TIMEOUT = exports.REFRESH_TIMEOUT = exports.TIMEOUT = exports.HEARTBEAT = exports.PORT = void 0; | ||
exports.PORT = process.env.PORT ? parseInt(process.env.PORT) : 8080; | ||
exports.HEARTBEAT = process.env.HEARTBEAT ? parseInt(process.env.HEARTBEAT) : 30000; | ||
exports.STRICT_PATH = process.env.STRICT_PATH ?? `1`; | ||
exports.TIMEOUT = 5000; | ||
exports.REFRESH_TIMEOUT = 45000; | ||
exports.NOTIFICATION_TIMEOUT = 60000; |
export declare enum Event { | ||
ERROR = "error", | ||
START = "start", | ||
STOP = "stop", | ||
BUTTON = "button", | ||
TIMER = "timer", | ||
NOTIFICATION = "notification", | ||
INCIDENT = "incident", | ||
PROMPT_START = "prompt_start", | ||
CALL_RINGING = "call_ringing", | ||
CALL_CONNECTED = "call_connected", | ||
@@ -12,2 +17,6 @@ CALL_DISCONNECTED = "call_disconnected", | ||
} | ||
export declare enum CallDirection { | ||
INBOUND = "inbound", | ||
OUTBOUND = "outbound" | ||
} | ||
export declare enum Button { | ||
@@ -44,2 +53,3 @@ ACTION = "action", | ||
ID = "id", | ||
TYPE = "type", | ||
ADDRESS = "address", | ||
@@ -55,2 +65,9 @@ COORDINATES = "latlong", | ||
} | ||
export declare enum DeviceType { | ||
RELAY = "relay", | ||
RELAY2 = "relay2", | ||
RELAY_APP = "relay_app", | ||
ROIP = "roip", | ||
DASH = "dash" | ||
} | ||
export declare enum Notification { | ||
@@ -62,1 +79,24 @@ BROADCAST = "broadcast", | ||
} | ||
export declare enum IncidentStatus { | ||
RESOLVED = "resolved", | ||
CANCELLED = "cancelled" | ||
} | ||
export declare enum NotificationPriority { | ||
NORMAL = "normal", | ||
HIGH = "high", | ||
CRITICAL = "critical" | ||
} | ||
export declare enum NotificationSound { | ||
DEFAULT = "default", | ||
SOS = "sos" | ||
} | ||
export declare enum TimerType { | ||
TIMEOUT = "timeout", | ||
INTERVAL = "interval" | ||
} | ||
export declare enum TimeoutType { | ||
MILLISECONDS = "ms", | ||
SECONDS = "secs", | ||
MINUTES = "mins", | ||
HOURS = "hrs" | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Notification = exports.DeviceInfoField = exports.DeviceInfoQuery = exports.Language = exports.Taps = exports.Button = exports.Event = void 0; | ||
exports.TimeoutType = exports.TimerType = exports.NotificationSound = exports.NotificationPriority = exports.IncidentStatus = exports.Notification = exports.DeviceType = exports.DeviceInfoField = exports.DeviceInfoQuery = exports.Language = exports.Taps = exports.Button = exports.CallDirection = exports.Event = void 0; | ||
var Event; | ||
(function (Event) { | ||
Event["ERROR"] = "error"; | ||
Event["START"] = "start"; | ||
Event["STOP"] = "stop"; | ||
Event["BUTTON"] = "button"; | ||
Event["TIMER"] = "timer"; | ||
Event["NOTIFICATION"] = "notification"; | ||
Event["INCIDENT"] = "incident"; | ||
Event["PROMPT_START"] = "prompt_start"; | ||
Event["CALL_RINGING"] = "call_ringing"; | ||
Event["CALL_CONNECTED"] = "call_connected"; | ||
@@ -16,2 +21,7 @@ Event["CALL_DISCONNECTED"] = "call_disconnected"; | ||
})(Event = exports.Event || (exports.Event = {})); | ||
var CallDirection; | ||
(function (CallDirection) { | ||
CallDirection["INBOUND"] = "inbound"; | ||
CallDirection["OUTBOUND"] = "outbound"; | ||
})(CallDirection = exports.CallDirection || (exports.CallDirection = {})); | ||
var Button; | ||
@@ -52,2 +62,3 @@ (function (Button) { | ||
DeviceInfoQuery["ID"] = "id"; | ||
DeviceInfoQuery["TYPE"] = "type"; | ||
DeviceInfoQuery["ADDRESS"] = "address"; | ||
@@ -64,2 +75,10 @@ DeviceInfoQuery["COORDINATES"] = "latlong"; | ||
})(DeviceInfoField = exports.DeviceInfoField || (exports.DeviceInfoField = {})); | ||
var DeviceType; | ||
(function (DeviceType) { | ||
DeviceType["RELAY"] = "relay"; | ||
DeviceType["RELAY2"] = "relay2"; | ||
DeviceType["RELAY_APP"] = "relay_app"; | ||
DeviceType["ROIP"] = "roip"; | ||
DeviceType["DASH"] = "dash"; | ||
})(DeviceType = exports.DeviceType || (exports.DeviceType = {})); | ||
var Notification; | ||
@@ -72,1 +91,29 @@ (function (Notification) { | ||
})(Notification = exports.Notification || (exports.Notification = {})); | ||
var IncidentStatus; | ||
(function (IncidentStatus) { | ||
IncidentStatus["RESOLVED"] = "resolved"; | ||
IncidentStatus["CANCELLED"] = "cancelled"; | ||
})(IncidentStatus = exports.IncidentStatus || (exports.IncidentStatus = {})); | ||
var NotificationPriority; | ||
(function (NotificationPriority) { | ||
NotificationPriority["NORMAL"] = "normal"; | ||
NotificationPriority["HIGH"] = "high"; | ||
NotificationPriority["CRITICAL"] = "critical"; | ||
})(NotificationPriority = exports.NotificationPriority || (exports.NotificationPriority = {})); | ||
var NotificationSound; | ||
(function (NotificationSound) { | ||
NotificationSound["DEFAULT"] = "default"; | ||
NotificationSound["SOS"] = "sos"; | ||
})(NotificationSound = exports.NotificationSound || (exports.NotificationSound = {})); | ||
var TimerType; | ||
(function (TimerType) { | ||
TimerType["TIMEOUT"] = "timeout"; | ||
TimerType["INTERVAL"] = "interval"; | ||
})(TimerType = exports.TimerType || (exports.TimerType = {})); | ||
var TimeoutType; | ||
(function (TimeoutType) { | ||
TimeoutType["MILLISECONDS"] = "ms"; | ||
TimeoutType["SECONDS"] = "secs"; | ||
TimeoutType["MINUTES"] = "mins"; | ||
TimeoutType["HOURS"] = "hrs"; | ||
})(TimeoutType = exports.TimeoutType || (exports.TimeoutType = {})); |
@@ -1,25 +0,31 @@ | ||
import WebSocket from 'ws'; | ||
import * as enums from './enums'; | ||
import { LedIndex, ButtonEvent, Call, ConnectedCall, DisconnectedCall, FailedCall, NotificationEvent, Options, ReceivedCall, Relay, StartedCall, Workflow } from './types'; | ||
import { BaseCall, ButtonEvent, ConnectedCall, DisconnectedCall, FailedCall, ReceivedCall, StartedCall, NotificationEvent, NotificationOptions, IncidentEvent, LocalWebSocket, Options, Relay, Workflow, LedIndex, LedEffect, LedInfo, PlaceCall, Prompt, RingingCall, RegisterRequest } from './types'; | ||
declare const Event: typeof enums.Event, Language: typeof enums.Language; | ||
export * from './enums'; | ||
interface WorkflowEvents { | ||
[Event.START]: (event: Record<string, never>) => void; | ||
[Event.BUTTON]: (event: ButtonEvent) => void; | ||
[Event.TIMER]: (event: Record<string, never>) => void; | ||
[Event.NOTIFICATION]: (event: NotificationEvent) => void; | ||
[Event.CALL_CONNECTED]: (event: ConnectedCall) => void; | ||
[Event.CALL_DISCONNECTED]: (event: DisconnectedCall) => void; | ||
[Event.CALL_FAILED]: (event: FailedCall) => void; | ||
[Event.CALL_RECEIVED]: (event: ReceivedCall) => void; | ||
[Event.CALL_START_REQUEST]: (event: StartedCall) => void; | ||
} | ||
declare type WorkflowEventHandlers = { | ||
[Event.ERROR]?: (error: Error) => Promise<void>; | ||
[Event.START]?: (event: Record<string, never>) => Promise<void>; | ||
[Event.STOP]?: (event: Record<string, never>) => Promise<void>; | ||
[Event.BUTTON]?: (event: ButtonEvent) => Promise<void>; | ||
[Event.TIMER]?: (event: Record<`name`, string>) => Promise<void>; | ||
[Event.NOTIFICATION]?: (event: NotificationEvent) => Promise<void>; | ||
[Event.INCIDENT]?: (event: IncidentEvent) => Promise<void>; | ||
[Event.PROMPT_START]?: (event: Prompt) => Promise<void>; | ||
[Event.CALL_RINGING]?: (event: RingingCall) => Promise<void>; | ||
[Event.CALL_CONNECTED]?: (event: ConnectedCall) => Promise<void>; | ||
[Event.CALL_DISCONNECTED]?: (event: DisconnectedCall) => Promise<void>; | ||
[Event.CALL_FAILED]?: (event: FailedCall) => Promise<void>; | ||
[Event.CALL_RECEIVED]?: (event: ReceivedCall) => Promise<void>; | ||
[Event.CALL_START_REQUEST]?: (event: StartedCall) => Promise<void>; | ||
}; | ||
declare const createWorkflow: (fn: Workflow) => Workflow; | ||
declare class RelayEventAdapter { | ||
private websocket; | ||
private emitter; | ||
constructor(websocket: WebSocket); | ||
on<U extends keyof WorkflowEvents>(event: U, listener: WorkflowEvents[U]): void; | ||
off<U extends keyof WorkflowEvents>(event: U, listener: WorkflowEvents[U]): void; | ||
private workQueue; | ||
private handlers; | ||
constructor(websocket: LocalWebSocket); | ||
on<U extends keyof WorkflowEventHandlers>(event: U, listener: WorkflowEventHandlers[U]): void; | ||
off<U extends keyof WorkflowEventHandlers>(event: U): void; | ||
private onClose; | ||
private onError; | ||
private onMessage; | ||
@@ -30,4 +36,9 @@ private _send; | ||
private _call; | ||
say(text: string, lang?: enums.Language): Promise<void>; | ||
play(filename: string): Promise<void>; | ||
setTimer(type: enums.TimerType, name: string, timeout: number | undefined, timeout_type: enums.TimeoutType): Promise<void>; | ||
clearTimer(name: string): Promise<void>; | ||
restartDevice(): Promise<void>; | ||
powerDownDevice(): Promise<void>; | ||
say(text: string, lang?: enums.Language): Promise<string>; | ||
play(filename: string): Promise<string>; | ||
stopPlayback(id?: string | string[]): Promise<void>; | ||
translate(text: string, from?: enums.Language, to?: enums.Language): Promise<string>; | ||
@@ -39,5 +50,6 @@ vibrate(pattern: number[]): Promise<void>; | ||
rainbow(rotations?: number): Promise<void>; | ||
rotate(): Promise<void>; | ||
flash(): Promise<void>; | ||
breathe(): Promise<void>; | ||
rotate(color?: string): Promise<void>; | ||
flash(color?: string): Promise<void>; | ||
breathe(color?: string): Promise<void>; | ||
ledAction(effect: LedEffect, args: LedInfo): Promise<void>; | ||
private _getDeviceInfo; | ||
@@ -52,12 +64,15 @@ getDeviceName(): Promise<string>; | ||
getDeviceBattery(refresh: boolean): Promise<number>; | ||
getDeviceType(): Promise<enums.DeviceType>; | ||
private setDeviceInfo; | ||
setDeviceName(name: string): Promise<void>; | ||
setDeviceChannel(channel: string): Promise<void>; | ||
setChannel(name: string, target: string[]): Promise<void>; | ||
placeCall(call: Call): Promise<void>; | ||
private _buildCallIdRequestOrThrow; | ||
answerCall(callRequest: string | Call): Promise<void>; | ||
hangupCall(callRequest: string | Call): Promise<void>; | ||
setDeviceMode(mode: `panic` | `alarm` | `none`): Promise<void>; | ||
setChannel(name: string, target: string[], { suppressTTS, disableHomeChannel }?: { | ||
suppressTTS?: boolean; | ||
disableHomeChannel?: false; | ||
}): Promise<void>; | ||
setVar(name: string, value: string): Promise<void>; | ||
set(obj: Record<string, string>, value?: string): Promise<void>; | ||
unsetVar(name: string): Promise<void>; | ||
unset(names: string | string[]): Promise<void>; | ||
getVar(name: string, defaultValue?: undefined): Promise<string>; | ||
@@ -68,5 +83,7 @@ get(names: string | string[]): Promise<string | string[]>; | ||
private _sendNotification; | ||
broadcast(text: string, target: string[]): Promise<void>; | ||
notify(text: string, target: string[]): Promise<void>; | ||
alert(name: string, text: string, target: string[]): Promise<void>; | ||
broadcast(name: string, text: string, target: string[], pushOptions?: NotificationOptions): Promise<void>; | ||
cancelBroadcast(name: string, target: string[]): Promise<void>; | ||
notify(name: string, text: string, target: string[], pushOptions?: NotificationOptions): Promise<void>; | ||
cancelNotify(name: string, target: string[]): Promise<void>; | ||
alert(name: string, text: string, target: string[], pushOptions?: NotificationOptions): Promise<void>; | ||
cancelAlert(name: string, target: string[]): Promise<void>; | ||
@@ -81,2 +98,7 @@ listen(phrases?: never[], { transcribe, alt_lang, timeout }?: { | ||
terminate(): Promise<void>; | ||
private _buildCallIdRequestOrThrow; | ||
placeCall(call: PlaceCall): Promise<void>; | ||
answerCall(callRequest: string | BaseCall): Promise<void>; | ||
hangupCall(callRequest: string | BaseCall): Promise<void>; | ||
register(request: RegisterRequest): Promise<void>; | ||
} | ||
@@ -83,0 +105,0 @@ declare const initializeRelaySdk: (options?: Options) => Relay; |
@@ -5,7 +5,7 @@ "use strict"; | ||
const tslib_1 = require("tslib"); | ||
const ws_1 = tslib_1.__importDefault(require("ws")); | ||
const events_1 = tslib_1.__importDefault(require("events")); | ||
const ws_1 = tslib_1.__importStar(require("ws")); | ||
const enums = tslib_1.__importStar(require("./enums")); | ||
const utils_1 = require("./utils"); | ||
const constants_1 = require("./constants"); | ||
const queue_1 = tslib_1.__importDefault(require("./queue")); | ||
const { Event, Language, DeviceInfoQuery, DeviceInfoField, Notification, } = enums; | ||
@@ -24,3 +24,3 @@ tslib_1.__exportStar(require("./enums"), exports); | ||
}); | ||
Object.defineProperty(this, "emitter", { | ||
Object.defineProperty(this, "workQueue", { | ||
enumerable: true, | ||
@@ -31,20 +31,47 @@ configurable: true, | ||
}); | ||
Object.defineProperty(this, "handlers", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: {} | ||
}); | ||
console.log(`creating event adapter`); | ||
this.emitter = new events_1.default.EventEmitter(); | ||
this.workQueue = new queue_1.default(); | ||
this.websocket = websocket; | ||
this.websocket.on(`close`, this.onClose.bind(this)); | ||
this.websocket.on(`error`, this.onError.bind(this)); | ||
this.websocket.on(`message`, this.onMessage.bind(this)); | ||
} | ||
on(event, listener) { | ||
this.emitter?.on(event, listener); | ||
this.off(event); | ||
this.handlers[event] = listener; | ||
} | ||
off(event, listener) { | ||
this.emitter?.off(event, listener); | ||
off(event) { | ||
const { [event]: handler, ...rest } = this.handlers; | ||
if (handler) { | ||
this.handlers = rest; | ||
} | ||
} | ||
async onClose() { | ||
onClose() { | ||
this.websocket = null; | ||
} | ||
onError(error) { | ||
this.workQueue?.enqueue(async () => { | ||
if (this.handlers?.[Event.ERROR]) { | ||
try { | ||
await this.handlers?.[Event.ERROR]?.(error); | ||
} | ||
catch (err) { | ||
console.log(`\`error\` handler failed`); | ||
console.error(err); | ||
} | ||
} | ||
else { // if no handler, log | ||
console.error(error); | ||
} | ||
}); | ||
} | ||
onMessage(msg) { | ||
const message = utils_1.safeParse(msg); | ||
if (this.emitter && message?._type && !message?._id) { // not interested in response events (marked by correlation id) | ||
if (this.workQueue && message?._type && !message?._id) { // not interested in response events (marked by correlation id) | ||
const eventNameParts = message._type.match(WORKFLOW_EVENT_REGEX); | ||
@@ -54,3 +81,11 @@ if (eventNameParts?.[1]) { | ||
const { _type, ...args } = message; | ||
this.emitter.emit(eventNameParts?.[1], args); | ||
this.workQueue?.enqueue(async () => { | ||
const event = eventNameParts?.[1]; | ||
try { | ||
await this.handlers?.[event]?.(args); | ||
} | ||
catch (err) { | ||
this.onError(err); | ||
} | ||
}); | ||
} | ||
@@ -73,4 +108,8 @@ else { | ||
return new Promise((resolve, reject) => { | ||
if (!this.websocket) { | ||
reject(`websocket-not-connected`); | ||
if (!(this.websocket?.isAlive && this.websocket?.readyState === ws_1.OPEN)) { | ||
console.error({ | ||
isAlive: this.websocket?.isAlive, | ||
readyState: this.websocket?.readyState, | ||
}); | ||
reject(new Error(`websocket-not-connected`)); | ||
return; | ||
@@ -86,3 +125,3 @@ } | ||
if (err) { | ||
reject(`failed-to-send`); | ||
reject(new Error(`failed-to-send`)); | ||
} | ||
@@ -101,3 +140,3 @@ else { | ||
this.websocket?.off?.(`message`, responseListener); | ||
reject(`failed-to-receive-response-timeout`); | ||
reject(new Error(`failed-to-receive-response-timeout`)); | ||
}, timeout); | ||
@@ -116,3 +155,3 @@ const responseListener = (msg) => { | ||
else if (_type === `wf_api_error_response`) { | ||
reject(event?.error); | ||
reject(new Error(event?.error ?? `Unknown error`)); | ||
} | ||
@@ -136,8 +175,33 @@ else { | ||
} | ||
async setTimer(type, name, timeout = 60, timeout_type) { | ||
await this._cast(`set_timer`, { type, name, timeout, timeout_type }); | ||
} | ||
async clearTimer(name) { | ||
await this._cast(`clear_timer`, { name }); | ||
} | ||
async restartDevice() { | ||
await this._cast(`device_power_off`, { restart: true }); | ||
} | ||
async powerDownDevice() { | ||
await this._cast(`device_power_off`, { restart: false }); | ||
} | ||
async say(text, lang = Language.ENGLISH) { | ||
await this._cast(`say`, { text, lang }); | ||
const { id } = (await this._call(`say`, { text, lang })); | ||
return id; | ||
} | ||
async play(filename) { | ||
await this._cast(`play`, { filename }); | ||
const { id } = (await this._call(`play`, { filename })); | ||
return id; | ||
} | ||
async stopPlayback(id) { | ||
if (Array.isArray(id)) { | ||
await this._cast(`stop_playback`, { ids: id }); | ||
} | ||
else if (typeof id === `string`) { | ||
await this._cast(`stop_playback`, { ids: [id] }); | ||
} | ||
else { | ||
await this._cast(`stop_playback`, {}); | ||
} | ||
} | ||
async translate(text, from = Language.ENGLISH, to = Language.SPANISH) { | ||
@@ -151,22 +215,25 @@ const { text: translatedText } = (await this._call(`translate`, { text, from_lang: from, to_lang: to })); | ||
async switchLedOn(led, color) { | ||
await this._cast(`set_led`, { effect: `static`, args: { colors: { [`${led}`]: color } } }); | ||
await this.ledAction(`static`, { colors: { [`${led}`]: color } }); | ||
} | ||
async switchAllLedOn(color) { | ||
await this._cast(`set_led`, { effect: `static`, args: { colors: { ring: color } } }); | ||
await this.ledAction(`static`, { colors: { ring: color } }); | ||
} | ||
async switchAllLedOff() { | ||
await this._cast(`set_led`, { effect: `off`, args: {} }); | ||
await this.ledAction(`off`, {}); | ||
} | ||
async rainbow(rotations = -1) { | ||
await this._cast(`set_led`, { effect: `rainbow`, args: { rotations } }); | ||
await this.ledAction(`rainbow`, { rotations }); | ||
} | ||
async rotate() { | ||
await this._cast(`set_led`, { effect: `rotate`, args: { rotations: -1, colors: { [`1`]: `FFFFFF` } } }); | ||
async rotate(color = `FFFFFF`) { | ||
await this.ledAction(`rotate`, { rotations: -1, colors: { [`1`]: color } }); | ||
} | ||
async flash() { | ||
await this._cast(`set_led`, { effect: `flash`, args: { count: -1, colors: { ring: `0000FF` } } }); | ||
async flash(color = `0000FF`) { | ||
await this.ledAction(`flash`, { count: -1, colors: { ring: color } }); | ||
} | ||
async breathe() { | ||
await this._cast(`set_led`, { effect: `breathe`, args: { count: -1, colors: { ring: `0000FF` } } }); | ||
async breathe(color = `0000FF`) { | ||
await this.ledAction(`breathe`, { count: -1, colors: { ring: color } }); | ||
} | ||
async ledAction(effect, args) { | ||
await this._cast(`set_led`, { effect, args }); | ||
} | ||
async _getDeviceInfo(query, refresh = false) { | ||
@@ -200,2 +267,5 @@ const response = await this._call(`get_device_info`, { query, refresh }, refresh ? constants_1.REFRESH_TIMEOUT : constants_1.TIMEOUT); | ||
} | ||
async getDeviceType() { | ||
return await this._getDeviceInfo(DeviceInfoQuery.TYPE); | ||
} | ||
async setDeviceInfo(field, value) { | ||
@@ -210,30 +280,8 @@ await this._cast(`set_device_info`, { field, value }); | ||
} | ||
async setChannel(name, target) { | ||
await this._cast(`set_channel`, { channel_name: name, target }); | ||
async setDeviceMode(mode, target) { | ||
await this._cast(`set_device_mode`, { mode, target }); | ||
} | ||
async placeCall(call) { | ||
await this._call(`call`, call); | ||
async setChannel(name, target, { suppressTTS = false, disableHomeChannel = false } = {}) { | ||
await this._cast(`set_channel`, { channel_name: name, target, suppress_tts: suppressTTS, disable_home_channel: disableHomeChannel }); | ||
} | ||
_buildCallIdRequestOrThrow(arg) { | ||
if (typeof arg === `string`) { | ||
return { call_id: arg }; | ||
} | ||
else if (typeof arg === `object`) { | ||
if (typeof arg.call_id === `string`) { | ||
return { call_id: arg.call_id }; | ||
} | ||
else { | ||
throw new Error(`missing required parameter`); | ||
} | ||
} | ||
else { | ||
throw new Error(`invalid argument type`); | ||
} | ||
} | ||
async answerCall(callRequest) { | ||
await this._call(`answer`, this._buildCallIdRequestOrThrow(callRequest)); | ||
} | ||
async hangupCall(callRequest) { | ||
await this._call(`hangup`, this._buildCallIdRequestOrThrow(callRequest)); | ||
} | ||
async setVar(name, value) { | ||
@@ -251,2 +299,13 @@ await this._cast(`set_var`, { name, value }); | ||
} | ||
async unsetVar(name) { | ||
await this._cast(`unset_var`, { name }); | ||
} | ||
async unset(names) { | ||
if (Array.isArray(names)) { | ||
Promise.all(names.map(name => this.unsetVar(name))); | ||
} | ||
else { | ||
return this.unsetVar(names); | ||
} | ||
} | ||
async getVar(name, defaultValue = undefined) { | ||
@@ -270,14 +329,20 @@ const { value } = (await this._call(`get_var`, { name }) ?? defaultValue); | ||
} | ||
async _sendNotification(type, text, target, name) { | ||
await this._cast(`notification`, { type, name, text, target }); | ||
async _sendNotification(type, text, target, name, pushOptions) { | ||
await this._cast(`notification`, { type, name, text, target, push_opts: pushOptions }, constants_1.NOTIFICATION_TIMEOUT); | ||
} | ||
async broadcast(text, target) { | ||
await this._sendNotification(Notification.BROADCAST, text, target); | ||
async broadcast(name, text, target, pushOptions) { | ||
await this._sendNotification(Notification.BROADCAST, text, target, name, pushOptions); | ||
} | ||
async notify(text, target) { | ||
await this._sendNotification(Notification.NOTIFY, text, target); | ||
async cancelBroadcast(name, target) { | ||
await this._sendNotification(Notification.CANCEL, undefined, target, name); | ||
} | ||
async alert(name, text, target) { | ||
await this._sendNotification(Notification.ALERT, text, target, name); | ||
async notify(name, text, target, pushOptions) { | ||
await this._sendNotification(Notification.NOTIFY, text, target, name, pushOptions); | ||
} | ||
async cancelNotify(name, target) { | ||
await this._sendNotification(Notification.CANCEL, undefined, target, name); | ||
} | ||
async alert(name, text, target, pushOptions) { | ||
await this._sendNotification(Notification.ALERT, text, target, name, pushOptions); | ||
} | ||
async cancelAlert(name, target) { | ||
@@ -303,4 +368,32 @@ await this._sendNotification(Notification.CANCEL, undefined, target, name); | ||
async terminate() { | ||
await this._send(`terminate`); | ||
await this._cast(`terminate`); | ||
} | ||
_buildCallIdRequestOrThrow(arg) { | ||
if (typeof arg === `string`) { | ||
return { call_id: arg }; | ||
} | ||
else if (typeof arg === `object`) { | ||
if (typeof arg.call_id === `string`) { | ||
return { call_id: arg.call_id }; | ||
} | ||
else { | ||
throw new Error(`missing required parameter`); | ||
} | ||
} | ||
else { | ||
throw new Error(`invalid argument type`); | ||
} | ||
} | ||
async placeCall(call) { | ||
await this._cast(`call`, call); | ||
} | ||
async answerCall(callRequest) { | ||
await this._cast(`answer`, this._buildCallIdRequestOrThrow(callRequest)); | ||
} | ||
async hangupCall(callRequest) { | ||
await this._cast(`hangup`, this._buildCallIdRequestOrThrow(callRequest)); | ||
} | ||
async register(request) { | ||
await this._cast(`register`, request); | ||
} | ||
} | ||
@@ -325,7 +418,9 @@ const DEFAULT_WORKFLOW = `__default_relay_workflow__`; | ||
if (request.url) { | ||
const shouldEnforceStrictPaths = (options.STRICT_PATH ?? constants_1.STRICT_PATH) === `1`; | ||
const path = request.url.slice(1); | ||
const hasDefaultWorkflow = workflows?.has(DEFAULT_WORKFLOW); | ||
const hasNamedWorkflow = workflows?.has(path); | ||
return (shouldEnforceStrictPaths ? hasNamedWorkflow : hasDefaultWorkflow) ?? false; | ||
if (path) { | ||
return !!workflows?.has(path); | ||
} | ||
else { | ||
return !!workflows?.has(DEFAULT_WORKFLOW); | ||
} | ||
} | ||
@@ -382,3 +477,3 @@ else { | ||
} | ||
else if (typeof path === `string`) { | ||
else if (typeof path === `string` && typeof workflow === `function`) { | ||
const strippedPath = path.replace(/^\/+/, ``); | ||
@@ -391,5 +486,2 @@ workflows.set(strippedPath, workflow); | ||
} | ||
else { | ||
console.error(`workflows is not initialized`); | ||
} | ||
} | ||
@@ -396,0 +488,0 @@ }; |
interface Params { | ||
max?: number; | ||
} | ||
declare type fn = { | ||
declare type work = { | ||
(): PromiseLike<void>; | ||
@@ -14,4 +14,4 @@ }; | ||
private execute; | ||
enqueue(fn: fn): void; | ||
enqueue(fn: work): void; | ||
} | ||
export {}; |
@@ -29,2 +29,3 @@ "use strict"; | ||
next() { | ||
// console.log(`${this.queue.length} : ${this.numActive} : ${this.max}`) | ||
if (this.queue.length) { | ||
@@ -42,3 +43,5 @@ if (this.numActive < this.max) { | ||
if (typeof obj?.then === `function`) { | ||
resolve(); | ||
obj.then(() => { | ||
resolve(); | ||
}); | ||
} | ||
@@ -45,0 +48,0 @@ }).finally(() => { |
@@ -5,9 +5,20 @@ /// <reference types="node" /> | ||
import WebSocket from 'ws'; | ||
import { Button, Taps } from './enums'; | ||
import { Button, CallDirection, IncidentStatus, NotificationPriority, NotificationSound, Taps } from './enums'; | ||
import { RelayEventAdapter } from './index'; | ||
export declare type LedIndex = `ring` | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | `1` | `2` | `3` | `4` | `5` | `6` | `7` | `8` | `9` | `10` | `11` | `12` | `13` | `14` | `15` | `16`; | ||
export interface Msg { | ||
export declare type LedEffect = `off` | `breathe` | `flash` | `rotate` | `rainbow` | `static`; | ||
export declare type LedInfo = { | ||
rotations?: number; | ||
count?: number; | ||
duration?: number; | ||
repeat_delay?: number; | ||
pattern_repeats?: number; | ||
colors?: { | ||
[K in LedIndex]?: string; | ||
}; | ||
}; | ||
export declare type Msg = { | ||
_id: string; | ||
_type: string; | ||
error?: unknown; | ||
error?: string; | ||
button?: string; | ||
@@ -19,11 +30,10 @@ taps?: string; | ||
notification_state?: string; | ||
} | ||
export interface Options { | ||
STRICT_PATH?: string; | ||
}; | ||
export declare type Options = { | ||
server?: http.Server | https.Server; | ||
} | ||
export interface LocalWebSocket extends WebSocket { | ||
}; | ||
export declare type LocalWebSocket = WebSocket & { | ||
connectionId: string; | ||
isAlive: boolean; | ||
} | ||
}; | ||
export interface Workflow { | ||
@@ -35,7 +45,13 @@ (relay: RelayEventAdapter): void; | ||
} | ||
export interface ButtonEvent { | ||
export declare type ButtonEvent = { | ||
button: Button; | ||
taps: Taps; | ||
} | ||
export interface NotificationState { | ||
}; | ||
export declare type NotificationOptions = { | ||
priority: NotificationPriority; | ||
title: string; | ||
body: string; | ||
sound: NotificationSound; | ||
}; | ||
export declare type NotificationState = { | ||
acknowledged: string[]; | ||
@@ -45,4 +61,4 @@ created: string[]; | ||
timed_out: string[]; | ||
} | ||
export interface NotificationEvent { | ||
}; | ||
export declare type NotificationEvent = { | ||
source: string; | ||
@@ -52,22 +68,37 @@ event: string; | ||
notification_state: NotificationState; | ||
} | ||
export interface BaseCall { | ||
}; | ||
export declare type RegisterRequest = { | ||
uri?: string; | ||
password?: string; | ||
expires?: number; | ||
}; | ||
export declare type BaseCall = { | ||
call_id: string; | ||
} | ||
export interface StartedCall extends BaseCall { | ||
}; | ||
export declare type StartedCall = BaseCall & { | ||
device_id: string; | ||
device_name: string; | ||
} | ||
export interface ReceivedCall extends StartedCall { | ||
direction: string; | ||
} | ||
export interface ConnectedCall extends ReceivedCall { | ||
}; | ||
export declare type PlaceCall = Partial<Omit<StartedCall, `call_id`>>; | ||
export declare type ReceivedCall = StartedCall & { | ||
start_time_epoch: number; | ||
direction: CallDirection; | ||
}; | ||
export declare type RingingCall = ReceivedCall; | ||
export declare type ConnectedCall = ReceivedCall & { | ||
connect_time_epoch: number; | ||
} | ||
export interface DisconnectedCall extends ConnectedCall { | ||
}; | ||
export declare type DisconnectedCall = ConnectedCall & { | ||
reason: string; | ||
end_time_epoch: number; | ||
} | ||
}; | ||
export declare type FailedCall = DisconnectedCall; | ||
export declare type Call = StartedCall | ReceivedCall | ConnectedCall | DisconnectedCall | FailedCall; | ||
export declare type IncidentEvent = { | ||
type: IncidentStatus; | ||
incident_id: string; | ||
reason: string; | ||
}; | ||
export declare type Prompt = { | ||
id: string; | ||
}; |
{ | ||
"name": "@relaypro/sdk", | ||
"version": "1.0.2", | ||
"version": "1.1.0", | ||
"description": "Workflow SDK Relay on Node.js", | ||
@@ -19,7 +19,9 @@ "license": "MIT", | ||
"scripts": { | ||
"test": "mocha --exit test/*", | ||
"test": "nyc mocha --exit test/*", | ||
"release": "np", | ||
"build": "del-cli dist && tsc", | ||
"build:check": "tsc --noEmit", | ||
"prepare": "npm run build" | ||
"prepare": "npm run build", | ||
"concat-doc": "mkdir -p concat-docs && npx concat-md --toc --decrease-title-levels --dir-name-as-title docs > concat-docs/relay-js.md", | ||
"doc-sync": "node ./scripts/doc-sync.mjs" | ||
}, | ||
@@ -30,25 +32,31 @@ "files": [ | ||
"dependencies": { | ||
"tslib": "2.1.0", | ||
"ws": "7.4.3" | ||
"tslib": "2.2.0", | ||
"ws": "7.4.6" | ||
}, | ||
"devDependencies": { | ||
"@types/chai": "4.2.15", | ||
"@types/mocha": "8.2.1", | ||
"@types/node": "14.14.22", | ||
"@types/ws": "7.4.0", | ||
"@typescript-eslint/eslint-plugin": "4.15.2", | ||
"@typescript-eslint/parser": "4.15.2", | ||
"chai": "4.3.0", | ||
"@types/chai": "4.2.18", | ||
"@types/mocha": "8.2.2", | ||
"@types/node": "15.6.1", | ||
"@types/ws": "7.4.4", | ||
"@typescript-eslint/eslint-plugin": "4.26.0", | ||
"@typescript-eslint/parser": "4.26.0", | ||
"chai": "4.3.4", | ||
"chai-as-promised": "7.1.1", | ||
"concat-md": "0.3.5", | ||
"del-cli": "3.0.1", | ||
"eslint": "7.20.0", | ||
"eslint-config-standard": "16.0.2", | ||
"eslint": "7.27.0", | ||
"eslint-config-standard": "16.0.3", | ||
"eslint-plugin-eslint-comments": "3.2.0", | ||
"eslint-plugin-import": "2.22.1", | ||
"eslint-plugin-mocha": "8.0.0", | ||
"eslint-plugin-import": "2.23.4", | ||
"eslint-plugin-mocha": "9.0.0", | ||
"eslint-plugin-node": "11.1.0", | ||
"eslint-plugin-promise": "4.3.1", | ||
"mocha": "8.3.0", | ||
"np": "7.4.0", | ||
"ts-node": "9.1.1", | ||
"typescript": "4.1.3" | ||
"eslint-plugin-promise": "5.1.0", | ||
"got": "11.8.2", | ||
"mocha": "8.4.0", | ||
"np": "7.5.0", | ||
"nyc": "15.1.0", | ||
"ts-node": "10.0.0", | ||
"typedoc": "0.20.36", | ||
"typedoc-plugin-markdown": "3.9.0", | ||
"typescript": "4.3.2" | ||
}, | ||
@@ -58,3 +66,6 @@ "types": "dist/index.d.ts", | ||
"access": "public" | ||
}, | ||
"sdk": { | ||
"commitHash": "4af2916d3c2babe59f0e879c1dcfcfcb6eb827c3" | ||
} | ||
} |
@@ -0,1 +1,3 @@ | ||
@relaypro/sdk / [Exports](modules.md) | ||
# relay-js | ||
@@ -8,3 +10,3 @@ | ||
```bash | ||
npm install @relaypro/sdk | ||
npm install @relaypro/sdk | ||
``` | ||
@@ -14,4 +16,6 @@ | ||
The following code snippet demonstrates a very simple "Hello World" workflow. However, it does show some of the power that is available through the Relay SDK. | ||
```javascript | ||
import relay from 'relay-js' | ||
import { relay, Event } from '@relaypro/sdk' | ||
@@ -21,5 +25,9 @@ const app = relay() | ||
app.workflow(`helloworld`, workflow => { | ||
workflow.on(`start`, async () => { | ||
workflow.say(`This is a default workflow`) | ||
workflow.terminate() | ||
workflow.on(Event.START, async () => { | ||
const greeting = await relay.get(`greeting`) | ||
const name = await relay.getDeviceName() | ||
await relay.say(`What is your name ?`) | ||
const user = await relay.listen() | ||
await relay.say(`Hello ${user}! ${greeting} ${name}`) | ||
await relay.terminate() | ||
}) | ||
@@ -29,6 +37,40 @@ }) | ||
Features demonstrated here: | ||
* When the workflow is triggered, the `start` event is emitted and the registered start callback | ||
function is called. | ||
* A configuration variable `greeting` is retrieved as is the triggering device's name. | ||
* The workflow then uses text-to-speech to prompt the user for their name. | ||
* The workflow awaits for a response from the device user. | ||
* The workflow then again uses text-to-speech to reply with a dynamic message. | ||
* Finally, the workflow is terminated and the device is returned to its original state. | ||
In this sample, a workflow callback function is registered with the name `helloworld`. This value | ||
of `helloworld` is used to map a WebSocket connection at the path `ws://yourhost:port/helloworld` | ||
to the registered workflow callback function. | ||
It is also possible to register a "default" workflow at path `/` by providing the workflow callback | ||
function as the first parameter: | ||
```javascript | ||
app.workflow(wf => { | ||
wf.on(Event.START, async () => { | ||
// handle start event | ||
}) | ||
}) | ||
``` | ||
## API | ||
The Relay JS SDK covers a broad set of use cases. Explore the various actions that can be performed | ||
in workflow event callbacks: | ||
* [Relay](classes/relayeventadapter.md) | ||
## Workflow Registration | ||
To register your workflow on a Relay device see https://api-docs.relaypro.com/docs/register-workflows | ||
More thorough documentation on how toregister your workflow on a Relay device | ||
can be found at https://api-docs.relaypro.com/docs/register-workflows | ||
In order to configure | ||
@@ -41,3 +83,4 @@ ## Development | ||
npm install | ||
npm test | ||
npm run build | ||
npm run test | ||
``` | ||
@@ -44,0 +87,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
45646
16
999
85
25
+ Addedtslib@2.2.0(transitive)
+ Addedws@7.4.6(transitive)
- Removedtslib@2.1.0(transitive)
- Removedws@7.4.3(transitive)
Updatedtslib@2.2.0
Updatedws@7.4.6