@relaypro/sdk
Advanced tools
Comparing version 1.1.0 to 1.2.0
export declare const PORT: number; | ||
export declare const HEARTBEAT: number; | ||
export declare const TIMEOUT = 5000; | ||
export declare const EVENT_TIMEOUT = 32000; | ||
export declare const REFRESH_TIMEOUT = 45000; | ||
export declare const NOTIFICATION_TIMEOUT = 60000; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.NOTIFICATION_TIMEOUT = exports.REFRESH_TIMEOUT = exports.TIMEOUT = exports.HEARTBEAT = exports.PORT = void 0; | ||
exports.NOTIFICATION_TIMEOUT = exports.REFRESH_TIMEOUT = exports.EVENT_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.TIMEOUT = 5000; | ||
exports.EVENT_TIMEOUT = 32000; | ||
exports.REFRESH_TIMEOUT = 45000; | ||
exports.NOTIFICATION_TIMEOUT = 60000; |
@@ -10,2 +10,3 @@ export declare enum Event { | ||
PROMPT_START = "prompt_start", | ||
PROMPT_STOP = "prompt_stop", | ||
CALL_RINGING = "call_ringing", | ||
@@ -58,3 +59,4 @@ CALL_CONNECTED = "call_connected", | ||
INDOOR_LOCATION = "indoor_location", | ||
LOCATION = "location" | ||
LOCATION = "location", | ||
USERNAME = "username" | ||
} | ||
@@ -61,0 +63,0 @@ export declare enum DeviceInfoField { |
@@ -14,2 +14,3 @@ "use strict"; | ||
Event["PROMPT_START"] = "prompt_start"; | ||
Event["PROMPT_STOP"] = "prompt_stop"; | ||
Event["CALL_RINGING"] = "call_ringing"; | ||
@@ -68,2 +69,3 @@ Event["CALL_CONNECTED"] = "call_connected"; | ||
DeviceInfoQuery["LOCATION"] = "location"; | ||
DeviceInfoQuery["USERNAME"] = "username"; | ||
})(DeviceInfoQuery = exports.DeviceInfoQuery || (exports.DeviceInfoQuery = {})); | ||
@@ -70,0 +72,0 @@ var DeviceInfoField; |
import * as enums from './enums'; | ||
import { BaseCall, ButtonEvent, ConnectedCall, DisconnectedCall, FailedCall, ReceivedCall, StartedCall, NotificationEvent, NotificationOptions, IncidentEvent, LocalWebSocket, Options, Relay, Workflow, LedIndex, LedEffect, LedInfo, PlaceCall, Prompt, RingingCall, RegisterRequest } from './types'; | ||
import { BaseCall, ButtonEvent, ConnectedCall, DisconnectedCall, FailedCall, ReceivedCall, StartedCall, NotificationEvent, NotificationOptions, IncidentEvent, LocalWebSocket, Options, Relay, Workflow, LedIndex, LedEffect, LedInfo, PlaceCall, Prompt, RingingCall, RegisterRequest, StopEvent, Mapper, AnyPrimitive } from './types'; | ||
declare const Event: typeof enums.Event, Language: typeof enums.Language; | ||
@@ -8,3 +8,3 @@ export * from './enums'; | ||
[Event.START]?: (event: Record<string, never>) => Promise<void>; | ||
[Event.STOP]?: (event: Record<string, never>) => Promise<void>; | ||
[Event.STOP]?: (event: StopEvent) => Promise<void>; | ||
[Event.BUTTON]?: (event: ButtonEvent) => Promise<void>; | ||
@@ -15,2 +15,3 @@ [Event.TIMER]?: (event: Record<`name`, string>) => Promise<void>; | ||
[Event.PROMPT_START]?: (event: Prompt) => Promise<void>; | ||
[Event.PROMPT_STOP]?: (event: Prompt) => Promise<void>; | ||
[Event.CALL_RINGING]?: (event: RingingCall) => Promise<void>; | ||
@@ -28,2 +29,3 @@ [Event.CALL_CONNECTED]?: (event: ConnectedCall) => Promise<void>; | ||
private handlers; | ||
private defaultLogParameters; | ||
constructor(websocket: LocalWebSocket); | ||
@@ -37,2 +39,4 @@ on<U extends keyof WorkflowEventHandlers>(event: U, listener: WorkflowEventHandlers[U]): void; | ||
private _sendReceive; | ||
private _waitForEventCondition; | ||
_waitForEventAndOverride<U extends keyof WorkflowEventHandlers>(eventName: U): Promise<void>; | ||
private _cast; | ||
@@ -45,3 +49,5 @@ private _call; | ||
say(text: string, lang?: enums.Language): Promise<string>; | ||
sayAndWait(text: string, lang?: enums.Language): Promise<string>; | ||
play(filename: string): Promise<string>; | ||
playAndWait(filename: string): Promise<string>; | ||
stopPlayback(id?: string | string[]): Promise<void>; | ||
@@ -68,2 +74,4 @@ translate(text: string, from?: enums.Language, to?: enums.Language): Promise<string>; | ||
getDeviceType(): Promise<enums.DeviceType>; | ||
getUserProfile(): Promise<string>; | ||
setUserProfile(username: string, force?: boolean): Promise<void>; | ||
private setDeviceInfo; | ||
@@ -77,2 +85,6 @@ setDeviceName(name: string): Promise<void>; | ||
}): Promise<void>; | ||
setHomeChannelState(target: string[], enabled: boolean): Promise<void>; | ||
getGroupMembers(groupName: string): Promise<string[]>; | ||
setDefaultLogParameters(params: Record<string, string | number | boolean>): Promise<void>; | ||
logEvent(event: string, parameters: Record<string, Record<string, string | number | boolean>>): Promise<void>; | ||
setVar(name: string, value: string): Promise<void>; | ||
@@ -82,4 +94,8 @@ set(obj: Record<string, string>, value?: string): Promise<void>; | ||
unset(names: string | string[]): Promise<void>; | ||
getVar(name: string, defaultValue?: undefined): Promise<string>; | ||
get(names: string | string[]): Promise<string | string[]>; | ||
getVar(name: string, defaultValue?: undefined): Promise<string | undefined>; | ||
getMappedVar<Type>(name: string, mapper: Mapper<Type>, defaultValue?: undefined): Promise<Type | undefined>; | ||
getNumberVar(name: string, defaultValue?: undefined): Promise<number | undefined>; | ||
getArrayVar(name: string, defaultValue?: undefined): Promise<string[] | undefined>; | ||
getNumberArrayVar(name: string, defaultValue?: undefined): Promise<number[] | undefined>; | ||
get(names: string | string[], mappers: [Mapper<AnyPrimitive>]): Promise<AnyPrimitive | AnyPrimitive[]>; | ||
startTimer(timeout?: number): Promise<void>; | ||
@@ -107,2 +123,4 @@ stopTimer(): Promise<void>; | ||
register(request: RegisterRequest): Promise<void>; | ||
getUnreadInboxSize(): Promise<number>; | ||
playUnreadInboxMessages(): Promise<void>; | ||
} | ||
@@ -109,0 +127,0 @@ declare const initializeRelaySdk: (options?: Options) => Relay; |
@@ -15,2 +15,3 @@ "use strict"; | ||
const WORKFLOW_EVENT_REGEX = /^wf_api_(\w+)_event$/; | ||
const all = () => true; | ||
class RelayEventAdapter { | ||
@@ -36,2 +37,8 @@ constructor(websocket) { | ||
}); | ||
Object.defineProperty(this, "defaultLogParameters", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: {} | ||
}); | ||
console.log(`creating event adapter`); | ||
@@ -95,11 +102,2 @@ this.workQueue = new queue_1.default(); | ||
} | ||
/* | ||
private async stop(): Promise<void> { | ||
console.log(`stopping event adapter`) | ||
if (this.websocket) { | ||
console.log(`terminating event adapter websocket`) | ||
this.websocket.terminate() | ||
} | ||
} | ||
*/ | ||
async _send(type, payload = {}, id) { | ||
@@ -134,6 +132,23 @@ return new Promise((resolve, reject) => { | ||
await this._send(type, payload, id); | ||
const event = await this._waitForEventCondition((event) => { | ||
return ([`wf_api_${type}_response`, `wf_api_error_response`].includes(event._type)) && id === event._id; | ||
}, timeout); | ||
const { _id, _type, error, ...params } = event; | ||
console.log(`processing event ${_id} of type ${_type}`); | ||
if (_type === `wf_api_${type}_response`) { | ||
return Object.keys(params).length > 0 ? params : undefined; | ||
} | ||
else if (_type === `wf_api_error_response`) { | ||
throw new Error(error ?? `Unknown error`); | ||
} | ||
else { | ||
console.error(`Unknown response`, event); | ||
throw new Error(`Unknown response`); | ||
} | ||
} | ||
async _waitForEventCondition(filter = all, timeout = constants_1.EVENT_TIMEOUT) { | ||
return new Promise((resolve, reject) => { | ||
const timeoutHandle = setTimeout(() => { | ||
this.websocket?.off?.(`message`, responseListener); | ||
reject(new Error(`failed-to-receive-response-timeout`)); | ||
reject(new Error(`failed-to-receive-event-timeout`)); | ||
}, timeout); | ||
@@ -144,16 +159,6 @@ const responseListener = (msg) => { | ||
if (event) { | ||
const { _id, _type, ...params } = event; | ||
if (_id === id) { // interested here in response events (marked by correlation id) | ||
if (filter(event)) { | ||
// stop listening as soon as we have a correlated response | ||
this.websocket?.off(`message`, responseListener); | ||
if (_type === `wf_api_${type}_response`) { | ||
resolve(Object.keys(params).length > 0 ? params : undefined); | ||
} | ||
else if (_type === `wf_api_error_response`) { | ||
reject(new Error(event?.error ?? `Unknown error`)); | ||
} | ||
else { | ||
console.log(`Unknown response`, event); | ||
reject(new Error(`Unknown response`)); | ||
} | ||
resolve(event); | ||
} | ||
@@ -166,2 +171,14 @@ } | ||
} | ||
async _waitForEventAndOverride(eventName) { | ||
const eventHandler = this.handlers[eventName]; | ||
try { | ||
delete this.handlers[eventName]; | ||
await this._waitForEventCondition(event => event._type === `wf_api_${eventName}_event`); | ||
} | ||
finally { | ||
if (eventHandler !== undefined) { | ||
this.handlers[eventName] = eventHandler; | ||
} | ||
} | ||
} | ||
async _cast(type, payload = {}, timeout = constants_1.TIMEOUT) { | ||
@@ -189,2 +206,7 @@ await this._sendReceive(type, payload, timeout); | ||
} | ||
async sayAndWait(text, lang = Language.ENGLISH) { | ||
const id = await this.say(text, lang); | ||
await this._waitForEventAndOverride(Event.PROMPT_STOP); | ||
return id; | ||
} | ||
async play(filename) { | ||
@@ -194,2 +216,7 @@ const { id } = (await this._call(`play`, { filename })); | ||
} | ||
async playAndWait(filename) { | ||
const id = await this.play(filename); | ||
await this._waitForEventAndOverride(Event.PROMPT_STOP); | ||
return id; | ||
} | ||
async stopPlayback(id) { | ||
@@ -268,2 +295,8 @@ if (Array.isArray(id)) { | ||
} | ||
async getUserProfile() { | ||
return await this._getDeviceInfo(DeviceInfoQuery.USERNAME); | ||
} | ||
async setUserProfile(username, force = false) { | ||
await this._cast(`set_user_profile`, { username, force }); | ||
} | ||
async setDeviceInfo(field, value) { | ||
@@ -284,4 +317,35 @@ await this._cast(`set_device_info`, { field, value }); | ||
} | ||
async setHomeChannelState(target, enabled) { | ||
await this._cast(`set_home_channel_state`, { target, enabled }); | ||
} | ||
async getGroupMembers(groupName) { | ||
const { device_names } = await this._call(`list_group_members`, { group_name: groupName }); | ||
return device_names; | ||
} | ||
async setDefaultLogParameters(params) { | ||
this.defaultLogParameters = params; | ||
} | ||
async logEvent(event, parameters) { | ||
await this._cast(`log_message`, { | ||
name: event, | ||
content_type: `application/vnd.relay.event.parameters+json`, | ||
message: JSON.stringify({ | ||
...this.defaultLogParameters, | ||
...parameters, | ||
}) | ||
}); | ||
} | ||
// async logUserEvent(event: string, target: string, parameters: Record<string, Record<string, string|number|boolean>>): Promise<void> { | ||
// await this._cast(`log_message`, { | ||
// name: event, | ||
// content_type: `application/vnd.relay.event.parameters+json`, | ||
// target, | ||
// message: JSON.stringify({ | ||
// ...this.defaultLogParameters, | ||
// ...parameters, | ||
// }) | ||
// }) | ||
// } | ||
async setVar(name, value) { | ||
await this._cast(`set_var`, { name, value }); | ||
await this._cast(`set_var`, { name, value: utils_1.toString(value) }); | ||
} | ||
@@ -309,8 +373,39 @@ async set(obj, value) { | ||
async getVar(name, defaultValue = undefined) { | ||
const { value } = (await this._call(`get_var`, { name }) ?? defaultValue); | ||
return value; | ||
const result = await this._call(`get_var`, { name }); | ||
if (result === undefined) { | ||
return defaultValue; | ||
} | ||
else { | ||
return result.value; | ||
} | ||
} | ||
async get(names) { | ||
async getMappedVar(name, mapper, defaultValue = undefined) { | ||
const value = await this.getVar(name, defaultValue); | ||
if (value === undefined) { | ||
return value; | ||
} | ||
return mapper(value); | ||
} | ||
async getNumberVar(name, defaultValue = undefined) { | ||
return await this.getMappedVar(name, Number, defaultValue); | ||
} | ||
async getArrayVar(name, defaultValue = undefined) { | ||
return await this.getMappedVar(name, utils_1.arrayMapper, defaultValue); | ||
} | ||
async getNumberArrayVar(name, defaultValue = undefined) { | ||
return await this.getMappedVar(name, utils_1.numberArrayMapper, defaultValue); | ||
} | ||
async get(names, mappers) { | ||
if (Array.isArray(names)) { | ||
return Promise.all(names.map(name => this.getVar(name))); | ||
if (Array.isArray(mappers) && names.length !== mappers.length) { | ||
throw new Error(`"get(names, mappers) array length are not equal`); | ||
} | ||
return Promise.all(names.map(async (name, index) => { | ||
const value = await this.getVar(name); | ||
if (value === undefined) { | ||
return value; | ||
} | ||
const mapper = mappers?.[index] || String; | ||
return mapper(value); | ||
})); | ||
} | ||
@@ -395,2 +490,9 @@ else { | ||
} | ||
async getUnreadInboxSize() { | ||
const { count } = await this._call(`inbox_count`); | ||
return utils_1.filterInt(count); | ||
} | ||
async playUnreadInboxMessages() { | ||
await this._cast(`play_inbox_messages`); | ||
} | ||
} | ||
@@ -413,3 +515,2 @@ const DEFAULT_WORKFLOW = `__default_relay_workflow__`; | ||
server.shouldHandle = (request) => { | ||
console.info(`WebSocket request =>`, request.url); | ||
if (request.url) { | ||
@@ -464,3 +565,3 @@ const path = request.url.slice(1); | ||
_websocket.isAlive = false; | ||
websocket.ping(utils_1.noop); | ||
websocket.ping(); | ||
}); | ||
@@ -467,0 +568,0 @@ }, constants_1.HEARTBEAT); |
@@ -7,2 +7,4 @@ /// <reference types="node" /> | ||
import { RelayEventAdapter } from './index'; | ||
export declare type AnyPrimitive = undefined | symbol | string | boolean | number | [string | boolean | number]; | ||
export declare type Mapper<Type> = (value: string) => Type; | ||
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`; | ||
@@ -44,2 +46,5 @@ export declare type LedEffect = `off` | `breathe` | `flash` | `rotate` | `rainbow` | `static`; | ||
} | ||
export declare type StopEvent = { | ||
reason: `error` | `normal` | string; | ||
}; | ||
export declare type ButtonEvent = { | ||
@@ -46,0 +51,0 @@ button: Button; |
@@ -1,4 +0,10 @@ | ||
import { Msg } from './types'; | ||
import { AnyPrimitive, Msg } from './types'; | ||
export declare const safeParse: (msg: string) => undefined | Msg; | ||
export declare const noop: () => void; | ||
export declare const makeId: () => string; | ||
export declare const filterInt: (value: string) => number; | ||
export declare const arrayMapper: (value: string) => string[]; | ||
export declare const numberArrayMapper: (value: string) => number[]; | ||
export declare const booleanMapper: (value: string) => boolean; | ||
export declare const toString: (value: AnyPrimitive) => string; | ||
export declare const isPlainObject: <Value>(value: unknown) => value is Record<string | number | symbol, Value>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.makeId = exports.noop = exports.safeParse = void 0; | ||
exports.isPlainObject = exports.toString = exports.booleanMapper = exports.numberArrayMapper = exports.arrayMapper = exports.filterInt = exports.makeId = exports.noop = exports.safeParse = void 0; | ||
const crypto_1 = require("crypto"); | ||
@@ -20,1 +20,47 @@ const safeParse = (msg) => { | ||
// export const promiseTry = (func: Function) => new Promise((resolve) => resolve(func())) | ||
const filterInt = (value) => { | ||
if (/^[-+]?(\d+|Infinity)$/.test(value)) { | ||
return Number(value); | ||
} | ||
else { | ||
return NaN; | ||
} | ||
}; | ||
exports.filterInt = filterInt; | ||
const arrayMapper = (value) => value.split(`,`); | ||
exports.arrayMapper = arrayMapper; | ||
const numberArrayMapper = (value) => exports.arrayMapper(value).map(Number); | ||
exports.numberArrayMapper = numberArrayMapper; | ||
const booleanMapper = (value) => value === `true`; | ||
exports.booleanMapper = booleanMapper; | ||
const toString = (value) => { | ||
return value == null ? `` : baseToString(value); | ||
}; | ||
exports.toString = toString; | ||
const baseToString = (value) => { | ||
if (typeof value == `string`) { | ||
return value; | ||
} | ||
if (Array.isArray(value)) { | ||
return value.map(baseToString) + ``; | ||
} | ||
if (typeof value == `symbol`) { | ||
return value.toString(); | ||
} | ||
if (exports.isPlainObject(value)) { | ||
return JSON.stringify(value); | ||
} | ||
const result = (value + ``); | ||
if (typeof value == `number`) { | ||
return (result == `0` && (1 / value) == -Infinity) ? `-0` : result; | ||
} | ||
return result; | ||
}; | ||
const isPlainObject = (value) => { | ||
if (Object.prototype.toString.call(value) !== `[object Object]`) { | ||
return false; | ||
} | ||
const proto = Object.getPrototypeOf(value); | ||
return proto === null || proto === Object.prototype; | ||
}; | ||
exports.isPlainObject = isPlainObject; |
{ | ||
"name": "@relaypro/sdk", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "Workflow SDK Relay on Node.js", | ||
@@ -22,2 +22,3 @@ "license": "MIT", | ||
"build": "del-cli dist && tsc", | ||
"build:test": "npm run build && npm run test", | ||
"build:check": "tsc --noEmit", | ||
@@ -32,17 +33,16 @@ "prepare": "npm run build", | ||
"dependencies": { | ||
"tslib": "2.2.0", | ||
"ws": "7.4.6" | ||
"tslib": "2.3.0", | ||
"ws": "7.5.3" | ||
}, | ||
"devDependencies": { | ||
"@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", | ||
"@types/chai": "4.2.21", | ||
"@types/mocha": "8.2.3", | ||
"@types/node": "16.3.3", | ||
"@types/ws": "7.4.7", | ||
"@typescript-eslint/eslint-plugin": "4.28.4", | ||
"@typescript-eslint/parser": "4.28.4", | ||
"chai": "4.3.4", | ||
"chai-as-promised": "7.1.1", | ||
"concat-md": "0.3.5", | ||
"del-cli": "3.0.1", | ||
"eslint": "7.27.0", | ||
"del-cli": "4.0.1", | ||
"eslint": "7.31.0", | ||
"eslint-config-standard": "16.0.3", | ||
@@ -55,9 +55,9 @@ "eslint-plugin-eslint-comments": "3.2.0", | ||
"got": "11.8.2", | ||
"mocha": "8.4.0", | ||
"mocha": "9.0.2", | ||
"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" | ||
"ts-node": "10.1.0", | ||
"typedoc": "0.21.4", | ||
"typedoc-plugin-markdown": "3.10.3", | ||
"typescript": "4.3.5" | ||
}, | ||
@@ -69,4 +69,4 @@ "types": "dist/index.d.ts", | ||
"sdk": { | ||
"commitHash": "4af2916d3c2babe59f0e879c1dcfcfcb6eb827c3" | ||
"commitHash": "27706c820e0e9356bf773a92028f3054a6aff970" | ||
} | ||
} |
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
53193
24
1181
+ Addedtslib@2.3.0(transitive)
+ Addedws@7.5.3(transitive)
- Removedtslib@2.2.0(transitive)
- Removedws@7.4.6(transitive)
Updatedtslib@2.3.0
Updatedws@7.5.3