JavaScript Runtime

The JavaScript Runtime allows to write apps for the innovaphone App Platform using JavaScript only.

It comes as a generic app binary provided by innovaphone that is part of the SDK. All the app specific files are put into a "httpfiles.zip" archive. To run the app on the App Platform, the ZIP archive is installed together with the generic app binary.

Overview
Included frameworks
httpfiles.zip
Development using the JavaScript Runtime
config.json
database
config
dbfiles
apis
serviceApis
javascript
plugins.json
Modes
Client-side framework
AppWebsocket messages
SqlInsert
SqlExec
SqlMonitor
DbFilesList
HTTP operations
HTTP POST to dbfiles
HTTP GET to dbfiles
Service-side framework
Initialization
Library

Overview

Included frameworks

The runtime provides two frameworks.

Both frameworks can be used independently. You can use the both or just one of them, depending on what you need for your app.

httpfiles.zip

The ZIP file contains your own app code along with manifests, needed to configure the runtime.

Development using the JavaScript Runtime

There are two alternative options for developing apps using the JavaScript Runtime.

Using the Visual Studio plugin (recommended)

Installation App creation Deployment to your test setup

Manual

Installation App creation Deployment to your test setup

config.json

The config.json contains objects for each area which can be configured.

If some initialization has to be done in an area, the object contains an array name "init", which contains a list objects for the commands, which are to be executed, when the App instance is started. Each of the objects contain a property "cmd", which identifies the type of command and a property "name", so that the result of the command can be referenced.

{
    "database": {
        "init": [
            ...
        ]
    },
    "config": {
        "init": [
            ...
        ]
    },
    "dbfiles": {
        "init": [
            ...
        ]
    },
    "apis": {
        ...
    },
    "serviceApis": {
        ...
    },
    "javascript": {
        "eval": [
            ...
        ]
    }
}

database

The init array of database may contain the following items:

table
Defines a database table. The property "name" is used as a name for the table. It also contains another array "init", with a list of command, for example to add columns to the table
The init object column has the following content:
{
    "cmd": "column",
    "name": string,
    "type": string
}

name
The name of the database column
type
The SQL type definition of the column (Example: "BIGSERIAL PRIMARY KEY NOT NULL")
statement
The statement object has the following content:
{
    "cmd": "statement",
    "name": string,
    "mode": string,
    "query": string,
    "args": object,
    "monitor": string (optionally),
    "return": string (optionally)
}

name
Used to invoke this statement with an AppWebsocket message. The name together with the mode must be unique.
mode
The mode in which this statement is executed. Several statements with the same name can be configured for different modes. Depending on the current mode the statement with matching name and mode is used. If node mode is configured, it is the default which is used if no mode matches directly.
query
Defines the SQL statement, with placeholders for the arguments (%s for strings, %u for unsigned integers, %i for signed integers, %llu for unsigned 64 bit integers, %lli for signed 64bit integers and %b for boolean values).
args
Contains a property for each argument in the order of the appearance of the respective placeholder in the query. The name of these properties are used as name for the properties holding the value of the argument in the AppWebsocket message to invoke the statement
If the name of an args property start with '@', it identifies a variable. There are some predefined variables: @domain - domain of logged in user, @sip - sip URI of logged in user, @dn - display name of logged in user, @guid - GUID of logged in user, @random-guid - generated GUID that can be used in the request as a unique identifier for a new entry in the database. Other variables may be defined dynamically by the return value of an SQL INSERT statement.
The value of the property is an object, which contains a string property type defining the type of the argument. For the type the values "string", "int", "unsigned", "long", "ulong64", "bool" are available.
monitor
An optional identifier which can be used to monitor this statement. The AppWebsocket message "SqlMonitor" can be used to monitor a statement with this property set
return
Identifies a variable into which the return value of an INSERT statement may be stored

config

The config array is used to define config items that can be used from the different config libraries:

The configuration of access rights is done using modes. The init array of config may contain the following items:

item
Defines a config item.
The init object column has the following content:
{
    "cmd": "item",
    "name": string,
    "type": string,
    "default": value,
    "password": bool,
    "min": value,
    "max": value,
    "options": array[string]
}

name
The name of the config item.
type
"CHOICE", "BOOL", "INT", "DWORD", "LONG64", "ULONG64", or "STRING"
default
The default value.
password (type "STRING" only)
Tells if the config item represents a password.
min (types "INT", "DWORD", "LONG64", "ULONG64" only)
The minimum value of the config item.
max (types "INT", "DWORD", "LONG64", "ULONG64" only)
The maximum value of the config item.
options (type "CHOICE" only)
An array of strings with the possible values of the choice.
mode
Defines in which modes the defined config items should be accessible. If not defined, no AppWebsocket connections will have access to the config items.
{
    "cmd": "mode",
    "name": string,
    "read": bool,
    "write": bool
}

name
The name of the mode. E.g. "owner.admin", "owner" or "pbx-manager".
read
true, if read access should be granted.
write
true, if write access should be granted.

dbfiles

The init array of dbfiles contains the following objects:

start
Starts the dbfiles instance. The object has the following content:
{
    "cmd": "start",
    "name": string,
    "folder": string
}

name
The name of the dbfiles instance
folder
An SQL type, which references another database row, which is used as a folder for the files. Example: "BIGINT REFERENCES reports(id) ON DELETE CASCADE"

apis

The apis object contains an object property for each API the App publishes. These properties have the following structure:

"<htm filename of the app>": {
    "<name of the API>": {
        "info": object,
    }
    "presence": bool,
    "hidden": bool
}

With the htm filename, it is selected on which connection from a PBX App object this information is announced. The standard format for API descriptions is used. With the property "presence" the App Service indicates that it will receive presence subscription calls for badge counts. Set it to "true" if the app receives the presence subscription within the app service. If the presence subscription should not be done to the app service but to a distinct SIP URI, it can be specified as a string. The property "hidden" can be used to hide the app from myApps UI.

The following example shows two API definitions for both Apps provided by an App Service. The first definition is for the App "manufacturer-appname", which should provide a com.innovaphone.phoneinfo API. Additionally, the App "manufacturer-appname" should be hidden from the client UI and should be able to handle presence subscriptions. The second App "manufacturer-appname-admin" will publish an own API "com.manufacturer.someapi" which can provide any custom functionality to other apps:

"apis": {
    "manufacturer-appname": {
        "com.innovaphone.phoneinfo": {
            "info": {}
        },
        "presence": true,
        "hidden": true
    },
    "manufacturer-appname-admin": {
        "com.manufacturer.someapi": {
            "info": {}
        },
    }
}

serviceApis

The serviceApis object contains an object property for each API the App Service publishes. These properties have the following structure:

"<htm filename of the app>": {
    "<name of the API>": {
        "<title of the API>": string
    }
}


With the htm filename, it is selected on which connection from a PBX App object this information is announced. The standard format for API descriptions is used.

Example of an API definition:

"serviceApis": {
    "acme-provisioning-service": {
        "com.innovaphone.provisioning": {
            "title": "ACME"
        }
    }
}


javascript

The JavaScript object specifies the JavaScript files that shall be executed in the JavaScript Environment on the service-side, when the app instance is started. The structure is like follows:

"javascript": {
    "eval": [ string ]
}

Example:

"javascript": {
    "eval": [ 
        "service1.js",
        "service2.js",
        "service3.js"
    ]
}

You can also use an asterisk as a wildcard at the end of an entry, in order to execute all JS files in a subtree of the httpfiles.zip.

Example:

"javascript": {
    "eval": [ 
        "subfolder/*",
        "service1.js"
    ]
}

plugins.json

The plugins.json contains an array of objects "plugins", with the configuration information for each plugin.

{
    "plugins": [
        {
            "js": String,
            "icon": String,
            "lang": String,
            "domains":  Bool
        }
    ]
}

js
The JavaScript file containing the Plugin JavaScript code. An extension of ".js", will be added automatically to the name configured here.
icon
The filename of the .png file, for the App Icon. This filename must be given, including the .png filename extension.
lang
The JavaScript language file, which contains an object for all the localized texts. An extension of ".js", will be added automatically to the name configured here.
domains
If set to true, this App Service can be used by multiple domains. The domains must be registered at the AP Manager. If the domain is registered and an AP object is configured in the PBX, the plugin is displayed in the PBX Manager.

Modes

Modes are used to define user access rights on the server side. They can be used to define which SQL statements may be executed and how config items can be accessed by a given user.

There is one mode that is automatically set by the App Service, if the connected user is from the App Instance domain and is authenticated with the App Instance password: "owner". This mode can be used to define different database operations for the users of the domain that provides this service and for other users. There is a defined mode called "pbx-manager" that can be used for WebSocket connections coming from the PBX Manager Plugin.

More modes maybe defined by the local PBX administrator, by adding these with '~' to the name of the App Object. This way for example a local administrator can assign different users different Apps providing different services.

The modes are concatenated using '.' as separator. For example in case of a user logging in from the domain owning the service, with an app object name ending on "~admin" a mode of "owner.admin" will result.

Client-side framework

AppWebsocket messages

The following AppWebsocket messages can be used by the app to communicate with the app service.

SqlInsert

Execute a prepared statement as Insert request, which means a return value may be used:

{
    "mt": "SqlInsert",
    "src": string (see AppWebsocket protocol)
    "statement": string,
    "args": {
        "<arg-name1>":<arg-value1>
        "<arg-name2>":<arg-value2>
        ...
    }
}

statement
Name of the prepared statement
args
The arguments with names as defined in the statement.

As a response a "SqlInsertResult" message is sent, which contains a property "id" if the request was successful. The table should contain a row named "id" as primary key for this to work.

SqlExec

Execute a prepared statement as Insert request, which means a return value may be used:

{
    "mt": "SqlExec",
    "src": string (see AppWebsocket protocol)
    "statement": string,
    "args": {
        "<arg-name1>":<arg-value1>
        "<arg-name2>":<arg-value2>
        ...
    }
}

statement
Name of the prepared statement
args
The arguments with names as defined in the statement.

As response a SqlRow message for each returned row is sent:

{
    "mt": "SqlRow",
    "src": string (see AppWebsocket protocol)
    "statement": string,
    "<row-name1>":<value1>
    "<row-name2>":<value2>
    ...
}

statement
The prepared statement name
<row-name>
Property for each returned row value. For this to work row names should not use "mt", "statement" nor "src".

As final message for the command "SqlExecResult" is sent.

SqlMonitor

The "SqlMonitor" message is used to start monitoring of SQL commands which are marked as "monitor". Whenever such an SQL command is invoked by any user, a message is sent to the monitoring App containing the values of the SQL command.

{
    "mt": "SqlMonitor",
    "src": string (see AppWebsocket protocol)
    "name": string
}

src
Needed in this case to associate the notifications to the monitor.
name
Identifies the SQL statements ("monitor property")

When the monitored SQL statements are executed a notification is sent

{
    "mt": "SqlUpdate",
    "src": string (see AppWebsocket protocol)
    "statement": string,
    "id": ulong64,
    "obj": object
}

src
Identifies the monitor
statement
The executed SQL statement
id
The returned id in case of an SqlInsert request
obj
An object with a property for each value

DbFilesList

Read the list of files stored in the addressed dbfiles instance in the identified folder, sorted by id of the file. A folder may be any row in another database table as configured in config.json.

{
    "mt": "DbFilesList",
    "src": string (see AppWebsocket protocol)
    "name": string,
    "folder": number,
    "limit": number (optional)
}

name
The name of the dbfiles instance, as configured in config.json.
folder
The id of the database table row as configured in config.json.
limit
Number of items delivered in one DbFilesListResult message. Default value is 50.

A single DbFilesListResult message is sent as response, which contains the list of files. Max. number of entries in one message is 50. The property "more" from the DbFilesListResult message can be used to request next batch of entries. If "more" property is missing, no further entries are left.

{
    "mt": "DbFilesListResult",
    "src": string (see AppWebsocket protocol)
    "files": [
        {
            id: number,
            url: string,
            name: string,
            size: number,
            created: number,
            modified: number
        }
    ],
    "more": number
}

id
The database table id of the file. This is used to delete a file.
url
relative URL which can be used for HTTP GET to retrieve the file.
name
Display name of the file. This is not necessarily unique.
size
The size of the file in bytes.
created
The creation timestamp of the file, given as a Unix timestamp in milliseconds.
modified
The last modified timestamp of the file, given as a Unix timestamp in milliseconds.
more
The id of last file delivered. Can be used with sendScrMore function of the AppWebsocket connection.

HTTP operations

For some operations, as file upload or download, HTTP operations are implemented

HTTP POST to dbfiles

With HTTP POST new files may be added to a dbfiles folder or existing files maybe deleted. From the App code a relative URL can be used

?dbfiles=<dbfiles-name>&folder=<folder>&name=<name>&del=<del-id>&key=<key>

dbfiles-name
Name of the dbfiles instance as configured in config.json.
folder
Id of the folder. Should not be 0.
name
Display name of the file.
del-id
Id of file, which shall be deleted.
key
The session key. It is used to authenticate the request. In JavaScript the session key is calculated as SHA256 hash from the AppWebsocket key with a preceding "generic-dbfiles:" seed.
sessionKey = innovaphone.crypto.sha256("generic-dbfiles:" + app.key());

The HTTP response to the POST request contains a JSON payload with result and file id: {"ok": true, "id": 1}. The JSON object can be accessed via json() method of the Fetch API.

ok
Boolean true if file was stored in the dbfiles instance.
id
Id of the created file.

HTTP GET to dbfiles

The relative URL in the DbFilesList results can be directly used to retrieve the files.

Service-side framework

Initialization

In the javascript object of the config.json you can specify which JS files from your ZIP shall be executed in the app service.

When your app service starts the following happens:

Note: The JS files declared as service files and the manifests (config.json, plugins.json) are not accessible using HTTP.

Library

The library for service-side scripts is described in separate articles in the SDK Reference.