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.
The runtime provides two frameworks.
The ZIP file contains your own app code along with manifests, needed to configure the runtime.
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": [
...
]
}
}
The init array of database may contain the following items:
{
"cmd": "column",
"name": string,
"type": string
}
{
"cmd": "statement",
"name": string,
"mode": string,
"query": string,
"args": object,
"monitor": string (optionally),
"return": string (optionally)
}
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:{
"cmd": "item",
"name": string,
"type": string,
"default": value,
"password": bool,
"min": value,
"max": value,
"options": array[string]
}
{
"cmd": "mode",
"name": string,
"read": bool,
"write": bool
}
The init array of dbfiles contains the following objects:
{
"cmd": "start",
"name": string,
"folder": string
}
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": {}
},
}
}
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"
}
}
}
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"
]
}
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
}
]
}
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.
The following AppWebsocket messages can be used by the app to communicate with the app service.
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>
...
}
}
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.
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>
...
}
}
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>
...
}
As final message for the command "SqlExecResult" is sent.
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
}
When the monitored SQL statements are executed a notification is sent
{
"mt": "SqlUpdate",
"src": string (see AppWebsocket protocol)
"statement": string,
"id": ulong64,
"obj": object
}
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)
}
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
}
For some operations, as file upload or download, HTTP operations are implemented
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>
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.
The relative URL in the DbFilesList results can be directly used to retrieve the files.
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:
The library for service-side scripts is described in separate articles in the SDK Reference.