Introduction

1. ZetaPush Celtia

ZetaPush accelerates the creation of connected applications by providing turnkey services. The developer consumes the services needed to run his application using development kits ready to be integrated into his front end code.

ZetaPush Celtia represents a major version of ZetaPush with a major change: the developer can write business code in languages such as JavaScript and TypeScript.

The developer will focus on his business code and ZetaPush will make his life easier by providing him with all the common components such as user management, data storage, etc.

In addition, ZetaPush hosts business code and front-end code.

2. Sections

Quick Start

Tutorials

Guides

Developer Manual

Reference

If you want to start using ZetaPush quickly

If you want to learn how to use ZetaPush Celtia main features, you can begin here

If you want to go into some topics in depth

If you want to cover completely each topic

If you want to search for a particular piece of information

3. Terms and concepts

Word Definition

ZetaPush Account

A developer account on the ZetaPush platform to create and manage applications.

Credentials

A Login/Password pair of the developer ZetaPush account.

Cloud function

A single operation that has a name, well-defined behavior, that can accept parameters and can produce an output.

This is equivalent to a function in any language except that it is run remotely.

Cloud service

Several Cloud functions that are grouped together to cover a coherent set of features. You can consider this as a class (custom cloud service) with methods (cloud functions).

ZetaPush already provides ready-to-use cloud services. For example we have: Chat, Groups, Messaging…​

In this documentation, we mention Cloud Services as a shortcut of ZetaPush Cloud Services.

Custom Cloud Service

A set of features similar to ZetaPush Cloud Services but developed by you. The usage of your custom cloud services is exactly the same as ZetaPush cloud services.

Front

Web pages developed by you (HTML / CSS / JS).

Worker

A set of Custom cloud services that you have developed to mutualize your business logic.

Organization

A group of ZetaPush accounts. Each organization may have several managers and several developers. Each person uses his own credentials to interact with ZetaPush but actions are shared among the organization.

Application

A logical container designed to perform a group of coordinated tasks or activities for the benefit of the user.

An application may have a front part and a worker.

An application has at least one environment.

Environment

Your application may be deployed and executed in separate zones called Environments. Each environment is a particular zone that you can organize as you wish. For example, you can have prod, pre-prod, dev environments for the same application.

CLI

Command Line Interface: utility scripts that are usable in a terminal to run your code or deploy your application, for example.

Console

The main website used to manage your ZetaPush account and applications, read the documentation, monitor your applications…​

Quick Start

4. System requirements

To create an application with ZetaPush you only need the Node.js ecosystem:

  • Node.js version 8.11.2 (LTS) or higher

  • npm version 5.x or higher

Node.js is used to:

  • create custom cloud services

  • locally run custom cloud services

  • deploy your application on ZetaPush

Install Node.js and npm

Go to Node.js Downloads and follow the installation instructions.

You also need to install additional tools for Node.js:

Additional tools

Windows

You must install development tools on Windows (Visual Studio Build Tools and Python). Fortunately, there is a npm tool that helps you to install all required dependencies. You must run this command line using PowerShell as Administrator:

npm install --global --production windows-build-tools

Be patient! It may take a while.

Debian/Ubuntu

Install build tools:

sudo apt-get install -y build-essential

Enterprise Linux and Fedora

Install build tools:

sudo yum install gcc-c++ make
# or: sudo yum groupinstall 'Development Tools'

-

5. Create your first application

5.1. From the command line

Generate application
$ npm init @zetapush first-hello-world (1)
1 first-hello-world is the name of the folder that will be created with all the generated files

You will be prompted for a developer login and a developer password in order to create a new account.

The developer login and the developer password will be stored in the .zetarc file. By default, the .gitignore file is configured to not deploy this file.

Using npm lower than 6

npm provides npm init command since version 6.

You can either upgrade your npm version or use npx utility.

npm 5-

Upgrade npm

➊ - Upgrade npm
$ npm install -g npm@latest
➋ - Use npm init
$ npm init @zetapush first-hello-world

Use npx to launch the script

Launch with npx
$ npx @zetapush/create first-hello-world

-

See ZetaPush account management to learn how to manage your account and your applications.

5.2. Generated project

result
Figure 1. Result of first-hello-world project

The project first-hello-world generated by the CLI is available on Github. This sample is also available using different front frameworks:

5.2.1. What it does ?

The generated project is really simple. It is just a web page that uses some JavaScript to call a cloud function named hello when button is clicked. The cloud function is a custom cloud function that simply returns a message with the current date. The result is retrieved by the JavaScript code and displayed in the browser console (using console.log).

5.2.2. Structure of generated project

The files of the generated project are structured as followed:

Generated tree structure
{appName}
├── .zetarc
├── .gitignore
├── front
│   ├── index.css
│   ├── index.html
│   ├── index.js
│   └── logo.png
├── worker
│   └── index.ts
├── package.json
├── README.md
└── tsconfig.json
Table 1. Definition of generated files
File / Folder Definition

.zetarc

Contains the developer’s credentials. Useful to deploy or run your code. The content is auto generated if the file is empty.

.gitignore

Standard file used by Git to prevent commiting some files. It is preconfigured to prevent publication of your developer credentials (on GitHub for example).

package.json

Standard file for NPM to handle a module. It contains the dependencies, the name of your application, the entry point of your custom cloud services (main property) and many useful other informations for your application.

README.md

Gives you some information about how to use your application.

front/

By convention, the front end code of your application is in this folder. You can change it by editing package.json.

worker/

By convention, the back end code of your application is in this folder. You can change it by editing package.json.

6. Run locally your first project

6.1. What is run ?

Run is used in development phase. You run your code locally on your development machine. You can then iterate on your code to provide new features quickly or even debug your code.

6.2. From your terminal

Go into the generated folder (first-hello-world):

$ cd first-hello-world

Then run the following command:

Start application (front and custom cloud services)
$ npm run start -- --serve-front

npm run start is a script alias defined in the package.json file. The command that is executed under the hood is:

$ zeta run --serve-front

This command launches both a local web server on localhost:3000 and the custom cloud services. You can open a web browser on localhost:3000 and open the browser console.

You can click on the button and see the result of the custom cloud service call in the browser console.

6.3. How it works

run locally
Figure 2. Exchanges between web page and custom cloud services

Clicking on the button triggers a call to the ZetaPush cloud. ZetaPush routes the call to the local Node.js (the Node.js has been registered automatically by the CLI)
The custom cloud service does its job and provides a response. ZetaPush routes the response to the connected web page

There are 3 parts that are working together:

  1. The web page that initiates a connection to the ZetaPush cloud

  2. The ZetaPush cloud

  3. The worker that provides the custom cloud function implementation

Firstly, the web page is loaded in the browser and a JavaScript code automatically connects the ZetaPush client to the ZetaPush cloud.

The connection is requested with client.connect() in first-hello-world/front/index.html.

The connection between ZetaPush client and the ZetaPush cloud is established and is bi-directional. Any message sent by ZetaPush client will go through this opened connection. The ZetaPush cloud can also send messages to the ZetaPush client through this opened connection.

Then, when the user clicks on the button, a message is sent to the ZetaPush cloud in order to execute some code. The ZetaPush cloud routes the message to the worker to call the custom cloud function.

The button is defined in first-hello-world/front/index.html

The action of the button is done in first-hello-world/front/index.js and it calls api.hello().

The custom cloud function is simply a JavaScript or TypeScript function. This function is called and it generates a result that is returned to ZetaPush cloud. ZetaPush cloud routes the response message to the ZetaPush client to send the result.

The code of the cloud function is available in first-hello-world/worker/index.ts

Finally, the ZetaPush client receives the result and the JavaScript code of the web page displays it in the browser console (using console.log).

The result is handled in first-hello-world/front/index.js.

Even if you run locally, the cloud functions defined by your worker are available on the Internet through ZetaPush cloud.

7. Push your first project in the Cloud

7.1. What is push ?

Push is used to make your code "public". It will publish your web page(s) and also upload the code of your worker on ZetaPush cloud. You can push when you think that your code is ready to be used by your end-users.

7.2. From your terminal

Deploy application (front and custom cloud services)
$ npm run deploy

npm run deploy is a script alias defined in the package.json file. The command that is executed under the hood is:

$ zeta push

This command uploads your code (front and worker) to the ZetaPush cloud. ZetaPush then handles the deployment by publishing your front and your custom cloud services.

The CLI displays the URL to access the published web page.

7.3. How it works

run in cloud
Figure 3. Exchanges between web page and custom cloud services

Clicking on the button triggers a call to the ZetaPush cloud which in turn routes directly the call to the hosted Node.js
The custom cloud service does its job and provides a response that ZetaPush routes back to the hosted web page

Now, the web page (front) and the custom cloud functions (defined in a worker) are hosted directly on ZetaPush cloud. The behavior remains the same as when code is executed local machine:

  • There are still the same 3 parts working together (web page, ZetaPush cloud and custom cloud function)

  • There is still a connection established by the client from the web page

  • There is still a message sent by the client to ZetaPush cloud that is routed to call the custom cloud function

  • There is still a message sent by the ZetaPush cloud that is routed to the client with the result of the custom cloud function

8. What’s next

You have created a new application, executed it locally and then published it.

Now, you are ready to code your own application:

Developer manual

9. Requirements

If you already prepared your environment, you can skip this section.

9.1. System requirements

To create an application with ZetaPush you only need the Node.js ecosystem:

  • Node.js version 8.11.2 (LTS) or higher

  • npm version 5.x or higher

Node.js is used to:

  • create custom cloud services

  • locally run custom cloud services

  • deploy your application on ZetaPush

Install Node.js and npm

Go to Node.js Downloads and follow the installation instructions.

You also need to install additional tools for Node.js:

Additional tools

Windows

You must install development tools on Windows (Visual Studio Build Tools and Python). Fortunately, there is a npm tool that helps you to install all required dependencies. You must run this command line using PowerShell as Administrator:

npm install --global --production windows-build-tools

Be patient! It may take a while.

Debian/Ubuntu

Install build tools:

sudo apt-get install -y build-essential

Enterprise Linux and Fedora

Install build tools:

sudo yum install gcc-c++ make
# or: sudo yum groupinstall 'Development Tools'

-

9.2. Using CLI

Once your have your application ready (see Quick start if you don’t have created an application) you can:

  • Run the backend code (Worker) locally

  • Deploy your application

To do this we provide a CLI (Command Line Interface) to help you focus on your code and not spend time on writing commands or scripts.

The CLI module is declared in the package.json of the project so it is installed by npm when you create your project (see how to create an application using npm if you haven’t created a project).

When the project is created, we configure the package.json with a scripts section to make aliases that work directly with npm.

9.2.1. Use npm script aliases to run the CLI

$ npm run <alias>

If you want to run your worker locally using script alias, you can execute:

$ npm run start

The start alias calls zeta run under the hood.

The start alias is used because it is the standard alias to use in development. We follow npm conventions so a user that is used to npm know which command to execute to start is project locally.

If you want to deploy your application using script alias, you can execute:

$ npm run deploy

The start alias calls zeta push under the hood.

9.2.2. Use CLI directly

With the CLI, you can run your worker with:

Run worker
1
$ zeta run

Or deploy your application with:

Deploy the application
1
$ zeta push

There are 3 ways to use directly zeta commands provided by the CLI:

  • Set an environment variable that points to your local node_modules/.bin (recommended)

  • Use npx tool

  • Install CLI as global (not recommended)

In order to be able to run zeta commands directly, you need to update your PATH.

Update environement variables

Debian/Ubuntu/MacOSX

You need to add it to your shell config file ~/.zshrc, ~/.profile or ~/.bashrc.

$ export PATH=./node_modules/.bin:$PATH

Note that this will not automatically update your path for the remainder of the session. To do this, you should run:

$ source ~/.zshrc
$ source ~/.profile
$ source ~/.bashrc

Windows 10 and Windows 8

  • In Search, search for and then select: System (Control Panel)

  • Click the Advanced system settings link.

  • Click Environment Variables. In the section System Variables, find the PATH environment variable and select it. Click Edit. If the PATH environment variable does not exist, click New.

  • In the Edit System Variable (or New System Variable) window, specify the value of the PATH environment variable. Click OK. Close all remaining windows by clicking OK.

  • Reopen Command prompt window, and run zeta command.

Windows 7

  • From the desktop, right click the Computer icon.

  • Choose Properties from the context menu.

  • Click the Advanced system settings link.

  • Click Environment Variables. In the section System Variables, find the PATH environment variable and select it. Click Edit. If the PATH environment variable does not exist, click New.

  • In the Edit System Variable (or New System Variable) window, specify the value of the PATH environment variable. Click OK. Close all remaining windows by clicking OK.

  • Reopen Command prompt window, and run zeta command.

Windows Vista

  • From the desktop, right click the My Computer icon.

  • Choose Properties from the context menu.

  • Click the Advanced tab (Advanced system settings link in Vista).

  • Click Environment Variables. In the section System Variables, find the PATH environment variable and select it. Click Edit. If the PATH environment variable does not exist, click New.

  • In the Edit System Variable (or New System Variable) window, specify the value of the PATH environment variable. Click OK. Close all remaining windows by clicking OK.

  • Reopen Command prompt window, and run zeta command.

Windows XP

  • Select Start, select Control Panel. double click System, and select the Advanced tab.

  • Click Environment Variables. In the section System Variables, find the PATH environment variable and select it. Click Edit. If the PATH environment variable does not exist, click New.

  • In the Edit System Variable (or New System Variable) window, specify the value of the PATH environment variable. Click OK. Close all remaining windows by clicking OK.

  • Reopen Command prompt window, and run zeta command.

-

9.2.2.2. Use npx tool

npx is shipped with npm standard install

$ npx zeta <command>

10. ZetaPush concepts

In order to be able to use ZetaPush, you need a ZetaPush account. Your account is used when you develop to run your project locally or to deploy it on ZetaPush cloud.

The code you produce is bound to an application.

An account belongs to an organization. An organization is useful to work in team. You can have several applications for your organization. You can manage access rights on applications according to members of your team.

As usual in development, you may need to run your application in different contexts (dev, continuous integration, prod…​). Each application may have several environments. You can also manage access rights on environments according to members of your team.

For now, environments are not fully supported but this feature will be available soon.

10.1. Create your account

Currently, the only way to get a ZetaPush account is by contacting us. The aim is to understand your needs and to advise you even if you just want to test it:

Your account will be created soon after the first contact and an application that fits your needs will be available. Then you are ready to start working with ZetaPush.

Soon we will open access to everyone for free trial. Account creation will be available through our CLI tool, from the main site and the web console.

11. Develop your front with ZetaPush

You may want to quickly provide a web application by just focusing on the visible part and the user experience instead of wasting time on technical concerns.

ZetaPush provides built-in cloud services to increase your productivity:

Table 2. List of ZetaPush cloud services
Cloud service Description

Standard User Workflow

The StandardUserWorkflow corresponds to the most common inscription process on the Internet. It handles:

  • Inscription of your end-users into your application: the user fills some information and StandardUserWorkflow sends an email (or SMS or anything else) to the user in order to confirm its account. Once the user has confirmed its account, he can authenticate himself and he is ready to use your application.

  • Authentication of your end-users

  • Lost password of your end-users: the user ask for resetting its password. StandardUserWorkflow sends an email (or SMS or anything else) to the user. The user clicks the link in the email to choose another password. Once confirmed, its account is updated with the new password.

  • Profile edition: your end-users can update their information

User management

This section describes several services that provide basic user management functions:

  • Simple: cloud functions to create a user, change credentials of a user, update a user or delete a user.

  • Weak: cloud functions to control and release of weakly authenticated user sessions.

  • Userdir: cloud functions to retrieve and search users created by Simple.

  • Groups: cloud functions to handle group of users.

This APIs are available if StandardUserWorkflow doesn’t fit your needs or you want to go further. Under the hood, StandardUserWorkflow use these services.

Data management

This section describes several services that provide basic data management functions:

  • Gda: NoSQL database that can store values, objects and arrays as document in columns.

  • Stack: Store values, objects and arrays in a stack. Each item is pushed in the stack and can be accessed later.

  • Search: Search engine to make full text searches.

File management

This section describes several services that provide basic file management functions:

  • Zpfs_hdfs: Store files on a file system.

  • Template: Define a template and then evaluate it with an execution context.

Communication

It is possible to interact with your end-users using these services:

  • Messaging: Send messages to a particular user (or a group of users). This is the service you use for a chat.

  • Notif: Send notifications to your end-users mobile phone (Android, iOS or Windows Phone).

  • Sendmail: Send emails to your end-users.

  • Sms_ovh: Send SMS to your end-users.

Utilities

This section provides some utility tools:

  • Cron: Schedule a task to be executed periodically.

  • Logs: Log some information. Logs will be available on ZetaPush cloud.

  • Trigger: Listen to some event that is triggered by ZetaPush cloud and react to that event.

ZetaPush cloud services need to be "created" before being able to use them. This way, you can choose which services are part of your application instead of having them all.

Currently, using a front to interact with ZetaPush cloud services directly is not really possible due to this "creation" phase. For security reasons, service creation and configuration can’t be done via a client.

When the web console will be fully ready, ZetaPush cloud services "creation" will be available through the web console.

Hopefully, you can use a worker to declare the use of a ZetaPush cloud service and even configure it. The "creation" process is automatically handled by the worker.

See the next section to know how to develop custom cloud services and use ZetaPush cloud services.

12. Develop your business logic

Even if ZetaPush provides ready to use cloud services, we know that any application needs some specific behaviors. Instead of limiting your possibilities, we provide a way to help you develop quickly your own business logic.

12.1. What is a custom cloud service

A custom cloud service combines many cloud functions like the cloud services exposed by ZetaPush. The only difference is that you create the cloud functions. Generally, you will want to put the business logic of your application in the custom cloud services.

12.1.1. Architecture

You develop cloud services that are contained in a concept named worker. In your code it is materialized by a folder named worker. The worker is the ZetaPush handler that starts your code (your custom cloud services).

Your application is composed of a logic part (the worker) and a UI part (the front).

There are two ways of running an application (worker and front):

  • You develop on your machine and iterate to provide features. Your application runs locally and interacts with ZetaPush Cloud.

  • Once you are ready to make the developed features available to your end-users, you publish your application. Your application runs directly in ZetaPush Cloud.

12.1.1.1. Run on your machine
custom cloud service dev
Figure 4. Custom Cloud Service in development phase

Both front and worker are running locally. The front interacts with custom cloud services contained in the worker through ZetaPush Cloud. As ZetaPush Cloud provides bidirectional connection, the custom cloud services can also interact with the front through ZetaPush Cloud too.

A custom cloud service can interact with built-in cloud services provided by ZetaPush.

When you start using ZetaPush, you only develop locally so from your point of vue, your front seems to directly interact with your custom cloud services.

In fact, all messages go through the Internet and ZetaPush Cloud. It means that a published front can interact with a worker that is running locally and vice versa.

12.1.1.2. Run in cloud
custom cloud service prod
Figure 5. Custom Cloud Service in production phase

Once published, everything runs in the ZetaPush Cloud. However the behavior is the same. Every interaction between the front and custom cloud services goes through the ZetaPush Cloud.

The only main difference is that ZetaPush Cloud manages the hosting, the scalability and the high availability for you.

12.2. Develop a custom cloud services

12.2.1. Define a custom cloud service

As a reminder worker is the ZetaPush container that will handle your code that defines custom cloud services. By convention, the code of your custom cloud services is placed in files under worker directory:

Tree structure convention
hello-world
├── .zetarc
├── .gitignore
├── front
│   ├── ...
│   └── ...
├── worker
│   ├── file1.ts
│   ├── file2.ts
│   ├── ...
│   ├── fileN.ts
│   └── index.ts
├── package.json
├── README.md
└── tsconfig.json
Change directory structure

Translated into code, a custom cloud service is just a class and its methods are the cloud functions. The code is written in any ts file defined in worker directory. For small application like a "hello world", write your code directly in index.ts file. So the most basic example of a custom cloud service is below:

Basic custom cloud service
1
2
3
4
5
6
7
8
class HelloWorldAsCustomCloudService {     (1)

    constructor() {}                       (2)

    helloWorld() {                         (3)
        return "Hello World";
    }
}
1 A custom cloud service is encapsulated in a JavaScript/TypeScript class. HelloWorldAsCustomCloudService is your first custom cloud service.
2 A class can define a constructor. We will see later why it is important
3 helloWorld is your first custom cloud function
A cloud function is always asynchronous (with the async keyword or not)
Change entry point

By default, the code above is directly written in index.ts file. This is done in order to follow NodeJS conventions. Indeed, index.ts is the usually the file that imports all other files.

You can write code of your custom cloud services in any other file named as you want. You will see later how to indicate to ZetaPush worker how to find your files if you don’t want to follow convention.

12.2.1.1. Define a cloud function

Each cloud function in a custom cloud service is a standard JavaScript/TypeScript method. For example, if you want a cloud function that receives two parameters you write:

A more realistic cloud function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class HelloWorldAsCustomCloudService {                            (1)
    constructor() {}

    helloWorld() {
        return "Hello World";
    }

    saySomething(message: string, times: number) {                (2)
        let fullMessage = '';
        for(let i=0 ; i<times ; i++) {                            (3)
            fullMessage += `${message}\n`
        }
        return fullMessage                                        (4)
    }
}
1 The custom cloud service definition as seen before
2 Declaration of a cloud function named saySomething. This cloud function accepts two parameters. As TypeScript is the recommended way, each parameter is typed.
3 Just for an example, the business logic consists in looping a number of times and concatenating the message. You can obviously write any code you want here.
4 The custom cloud function simply returns the contactenated string.
Why typing ?

Typing is optional but recommended to have a well defined API. Thanks to typing, ZetaPush is able to generate more accurate documentation based on your code and also generate mobile/web/IoT SDKs from your code with the right types so it makes developing your clients easier (for example, auto-completion can be used).

Tips about cloud functions

A custom cloud service can have as many custom cloud functions as you want.

A custom cloud function can have as many parameters as you want. Parameters can be anything: string, number, boolean, array or object. You can code your function as you always do.

A custom cloud function can return anything including a Promise. You can also write your code using async/await syntax.

Define several custom cloud services

Obviously when your application grows, you need to split your custom cloud service into several classes in order to make your API more understandable and more maintainable.

You have now a custom cloud service that provides two cloud functions. But until it is exposed, it can’t be called from outside of the worker.

The next section describes how you can expose your custom cloud service.

12.2.2. Expose a custom cloud service

When you define a custom cloud service that you want to expose to the client, you need to declare it. There are 2 cases:

  • Only one custom cloud service exposed

  • Many custom cloud services exposed

In this section we only address one custom cloud service exposed.

How to expose several custom cloud services

You can also learn how to expose several custom cloud services in the advanced sections.

We follow npm conventions to indicate the entry point of your worker. Indeed, the package.json defines a property named main. We use this property to indicate which file is the main file that declares the exposed custom cloud service. By default, the main file is named index.ts and this file is placed in worker directory. So the main property is by default worker/index.ts.

custom cloud service entry point

Now that your custom cloud service is marked as the entry point, it can be exposed by ZetaPush. However you still have a little change to make on your code:

A more realistic cloud function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export default class HelloWorldAsCustomCloudService {                    (1) (2)
    constructor() {}

    helloWorld() {
        return "Hello World";
    }

    saySomething(message: string, times: number) {
        let fullMessage = '';
        for(let i=0 ; i<times ; i++) {
            fullMessage += `${message}\n`
        }
        return fullMessage
    }
}
1 export: this is required by TypeScript. In fact, declaring a class in a file makes it private. It means that if you have another .ts file and you want to import HelloWorldAsCustomCloudService declaration, it won’t be possible without export keyword. This is for code encapsulation.
2 default: TypeScript provides this keyword. When exposing only one custom cloud service, default tells the worker that there is only one class (only one custom cloud service defined in the index.ts). So the worker can directly analyze it and instantiate it.
How to expose several custom cloud services

As seen above, you can also learn how to expose several custom cloud services in the advanced sections.

Now your custom cloud service can be loaded by the ZetaPush worker and your custom cloud service is automatically exposed. It means that now a client can call the cloud functions defined in your custom cloud service.

The next section shows how to call a cloud function from a web page using pure JavaScript.

12.2.3. Use a custom cloud service in your front

In this chapter we will see how to consume our cloud functions from a web page. At the end of this example, we will have one button to call helloWorld cloud function and one section with a message, a number of repetitions and a button to call saySomething cloud function.

Mobile applications

Here we show how to create a web page that consumes our custom cloud service.

You can also create a mobile application for Android, iOS and Windows Phone as well as code for a device. You can use any language you want for the client part.

By default we target web because it is currently the most used technology (even to build some mobile applications using hybrid technologies).

As a reminder, here is the code of custom cloud service named HelloWorldAsCustomCloudService:

worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
export default class HelloWorldAsCustomCloudService {
    constructor() {}

    helloWorld() {
        return "Hello World";
    }

    saySomething(message: string, times: number) {
        let fullMessage = '';
        for(let i=0 ; i<times ; i++) {
            fullMessage += `${message}\n`
        }
        return fullMessage
    }
}
12.2.3.1. Prepare your front for using ZetaPush client

By convention the directory structure of a ZetaPush application is defined below. You place the code of your web page in the front directory:

Tree structure convention
hello-world
├── .zetarc
├── .gitignore
├── front
│   ├── ...
│   ├── index.js
│   └── index.html
├── worker
│   ├── ...
│   ├── ...
│   └── index.ts
├── package.json
├── README.md
└── tsconfig.json
Other front files

For this example, we only need an HTML page and a JavaScript file. Needless to say that you can have CSS files, images and anything you want too.

Moreover, you are not limited to write pure JavaScript code. You can also use any framework you want:

For the example, we create an HTML page with a button to display the HelloWorld message in the page each time the button is clicked:

front/index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Celtia</title>
</head>

<body>
    <button onclick="hello()">hello</button>                    (1)
    <ul id="result-container"></ul>                             (2)

    <script src="https://unpkg.com/@zetapush/client"></script>  (2)
    <script src="./index.js"></script>                          (3)
</body>

</html>
1 We call hello() function that is defined later in index.js
2 Define a node that will display received messages
3 We include the client module provided by ZetaPush
4 We include a JavaScript file to distinguish HTML code from JavaScript code. All could be written in the HTML

Then, in order to interact with ZetaPush cloud, we need to create a client instance and to connect to the cloud:

front/index.js
1
2
3
4
5
6
7
8
9
10
11
// Create new ZetaPush Client
const client = new ZetaPushClient.WeakClient();     (1)
// Create a proxy to invoked worker methods
const api = client.createProxyTaskService();        (2)
// Handle connection
client.connect()                                    (3)
  .then(() => {                                     (4)
    console.debug('onConnectionEstablished');
    [...document.querySelectorAll('button')].forEach((node) =>
      node.removeAttribute('disabled'));
  });
1 Use ZetaPushClient factory to instantiate a client. In this example, we ask for an anonymous connection (it means that actions are not bound to a particular user of your application)
2 Custom cloud service provides some functions that can be called from a client. For example, the custom cloud service exposes helloWorld and saySomething cloud functions. Instead of having to write the signature of these functions in the client too, we simply use a JavaScript Proxy. Therefore, you can directly interact with your custom cloud service without writing any pass-through code on the client side.
3 The client is ready, now connects it to the ZetaPush cloud.
4 Once the connection is established, the Promise is resolved and you can write some code in then callback.
Available client types

ZetaPushClient provides several factories to get instances of a client according to what you want to do. Here we are using a WeakClient instance but there are other client types.

12.2.3.2. Call hello cloud function

Our client is ready and now we want to call cloud function named helloWorld, we add the following code:

front/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Create new ZetaPush Client
const client = new ZetaPushClient.WeakClient();
// Create a proxy to invoked worker methods
const api = client.createProxyTaskService();
// Handle connection
client.connect()
  .then(() => {
    console.debug('onConnectionEstablished');
    [...document.querySelectorAll('button')].forEach((node) =>
      node.removeAttribute('disabled'));
  });
// Handle DOM events
async function hello() {                                                                                (1)
  const messageFromCloudFunction = await api.helloWorld();                                        (2)
  document.getElementById('result-container').innerHTML += `<li>${messageFromCloudFunction}</li>` (3)
}
1 Each time a user clicks on the button defined in the HTML, this method is called.
2 Calls the helloWorld cloud function and store the result in a variable.
3 Add a new list item in the HTML page

Before running this sample, we improve our front in order to also understand how to call a cloud function that has parameters.

12.2.3.3. Call saySomething cloud function

We add two inputs to be able to send values to the saySomething cloud function. The first input is a text to repeat. The second input is the number of times to repeat the message. Here is the updated code:

front/index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Celtia</title>
</head>

<body>
    <button onclick="hello()">hello</button>
    <div style="border: 1px solid #ccc">
      Message: <input type="text" id="message-input" />             (1)
      Repeat: <input type="text" value="1" id="repeat-input" />     (2)
      <button onclick="saySeveralTimes()">say something</button>    (3)
    </div>
    <ul id="result-container"></ul>

    <script src="https://unpkg.com/@zetapush/client"></script>
    <script src="./index.js"></script>
</body>

</html>
1 The first input to enter a message
2 The second input to enter the number of times to repeat the message
3 A new button to call saySeveralTimes() function defined in index.js
front/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Create new ZetaPush Client
const client = new ZetaPushClient.WeakClient();
// Create a proxy to invoked worker methods
const api = client.createProxyTaskService();
// Handle connection
client.connect()
  .then(() => {
    console.debug('onConnectionEstablished');
    [...document.querySelectorAll('button')].forEach((node) =>
      node.removeAttribute('disabled'));
  });
// Handle DOM events
async function hello() {
  const messageFromCloudFunction = await api.helloWorld();
  document.getElementById('result-container').innerHTML += `<li>${messageFromCloudFunction}</li>`
}
async function saySeveralTimes() {                                                      (1)
  const message = document.getElementById('message-input').value;                 (2)
  const repeat = document.getElementById('repeat-input').value;                   (3)
  const messages = await api.saySomething(message, parseInt(repeat));             (4)
  document.getElementById('result-container').innerHTML += `<li>${messages}</li>` (5)
}
1 Each time a user clicks on the button 'say something' defined in the HTML, this method is called.
2 Reads the value of the input for getting the message.
3 Reads the value of the input for getting the number of times to display the message.
4 Calls saySomething cloud function with parameters. Note that as second parameter is a number, we have to convert the string from the input to a number using parseInt.
5 Add a new list item in the HTML page containing the repeated messages

Now everything is ready to run our application.

When you call a cloud function from the client, the result is always a Promise even if the custom cloud function is synchronous because everything goes through the network.

12.2.4. Run application

You have now defined a custom cloud service with one or several cloud function(s). You have also exposed your custom cloud service. So it is ready to be called from a client. Your client is also ready to call the custom cloud service.

The next step is to start the project (both front and worker) using the ZetaPush CLI on your computer.

Npm script aliases

Npm provides a handy feature to run scripts provided by dependencies without needing to change your computer settings or install the tool. ZetaPush defines npm script aliases to run the ZetaPush CLI through npm.

To start your worker and you front using the ZetaPush CLI through npm, you simply run:

Start application (front and custom cloud services)
$ npm run start -- --serve-front

npm run start is a script alias defined in the package.json file. The command that is executed under the hood is:

$ zeta run --serve-front
Run only the worker

It is also possible to run only your worker.

Automatic injection of ZetaPush information in your front

If you look closely to the code we have written, there is no information about your application at all in this sample code (the appName defined in .zetarc is neither in HTML nor in JavaScript). However, in order to interact with your application through the ZetaPush cloud, you need to provide the appName.

The ZetaPush CLI automatically injects the appName from .zetarc.

When you run your project locally, the local HTTP server that exposes the HTML page is lightly modified to include the appName. This information is then automatically read by the ZetaPush client.

When your project is run in the cloud, the same principle is applied.

This way, you just use .zetarc file for your credentials and appName and avoid having to write them twice. This also avoids conflicts when you work in team if you want different ZetaPush appName per developer.

Now when we click the "hello" button, "Hello World" is displayed on the page.

call zetapush cloud service
Figure 6. How it works ?

When you start your project locally, the first thing that happens is that your worker connects himself automatically to the ZetaPush cloud [1][2].

Then when you open your web browser, the connection from the client is established between the web page and the ZetaPush cloud [3][4].

When you click on the button, a message is sent through the opened connection in order to tell ZetaPush cloud to execute some remote code [5]. ZetaPush cloud routes the message to your worker [6] (that is running on your machine here). The worker receives the message and calls the hello cloud function [7].

The cloud function generates a result [8]. The worker picks this result and transform it to a message [9]. This message is then sent to the ZetaPush cloud [10]. The ZetaPush cloud routes the response message to the calling client [11]. The client receives the message and the response is parsed [12] and available in your JavaScript.

You can also try to enter a message and a number of repetitions and hit the "say something" button.

The behavior is exactly the same. This time a message is sent to call the cloud function with also the parameters.

Serialization/deserailization between client and custom cloud service

When you call a cloud function from the client, under the hood, the values are serialized in JSON. This is understandable because everything goes through the network.

On the worker side, everything is deserialized by the worker and your custom cloud service receives the values as they were written in the front side.

12.2.5. Compose cloud services

You can compose cloud services either by using built-in cloud services provided by ZetaPush or by using another of your custom cloud services.

12.2.5.1. Dependency injection

Dependency injection is a powerful software technique that is totally managed by the worker.

You don’t need to manage the creation of neither built-in cloud services nor your custom cloud services. You just indicate in your code that you need a dependency and ZetaPush instantiates it for you. The instantiated dependency is then injected everywhere the dependency is needed.

The dependency injection of ZetaPush uses Angular injection-js library.

To mark a custom cloud service injectable (meaning that can be automatically created by ZetaPush and then injected everywhere the dependency is aksed), you need to import the package @zetapush/core in order to use Injectable decorator.

Install @zetapush/core using npm
1
$ npm install --save @zetapush/core

Once the npm package is installed, you can import Injectable decorator and place it on your custom cloud service:

Use @Injectable on a custom cloud service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Injectable } from '@zetapush/core';            (1)

@Injectable()                                           (2)
export default class HelloWorldAsCustomCloudService {
  constructor() {}

  helloWorld() {
      return "Hello World";
  }

  saySomething(message: string, times: number) {
      let fullMessage = '';
      for(let i=0 ; i<times ; i++) {
          fullMessage += `${message}\n`
      }
      return fullMessage
  }
}
1 Import the ZetaPush module that contains core features for custom cloud services such as injectable
2 Mark you custom cloud service candidate for dependency injection

Here we just indicate that this custom cloud service can have dependencies that will be automatically injected and also that this custom cloud service can be injected anywhere it is needed.

In the next sections, we will see in concrete terms how to use it to reuse either a built-in cloud service or one of your custom cloud services.

12.2.5.2. Use built-in cloud service

ZetaPush built-in cloud services are available in @zetapush/platform-legacy module. Add this module to your package.json by running the following command:

Install @zetapush/platform-legacy using npm
1
$ npm install --save @zetapush/platform-legacy
List of cloud services provided by ZetaPush

As a reminder, here is the list of built-in cloud services

In the following example, we will use the Stack cloud service provided by ZetaPush. In our use-case, we want to put some data associated with the current timestamp and be able to list all stored data.

To do this, the Stack service already provides some methods:

  • push({ stack: string, data: object });

  • list({ stack: string });

MyStorageService
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import { Injectable } from '@zetapush/core';
import { Stack } from '@zetapush/platform-legacy';  (1)

@Injectable()
export default class MyStorageService {
  private stackName = 'stack-example';

  constructor(private stack: Stack) {}              (2)

  /**
   *  Store data with associated timestamp
   */
  storeWithTimestamp(value: any) {
    return this.stack.push({                        (3)
      stack: this.stackName,
      data: {
        value,
        timestamp: Date.now()
      }
    });
  }

  /**
   * List all stored data
   */
  getAllData() {
    return this.stack.list({                        (4)
      stack: this.stackName
    });
  }
}
1 We import the Stack service so that TypeScript knows it
2 We ask ZetaPush to inject a dependency of type Stack (stack is an instance of Stack). Here we use the shorthand syntax for declaring a constructor parameter as well as a property. So the property this.stack is defined and is initialized with stack parameter.
3 Calls the Stack service to store data (method push)
4 Calls the Stack service to list data (method list)

The example defines a custom cloud service named MyStorageService that provides two cloud functions:

  • storeWithTimestamp that receives a value from a client and calls the Stack service to store received value (value parameter) as well as the current timestamp (using Date.now())

  • getAllData that has no parameters and calls Stack service to get all previsouly stored pairs of <value, timestamp>.

The most important part to understand is in the constructor. As described before, the example uses dependency injection. You simply tell ZetaPush that you need a dependency of type Stack. You don’t create it in your custom cloud service because it is not the responsibility of your custom cloud service to create the Stack service. Instead, you let ZetaPush handle the creation. Thanks to @Injectable decorator, ZetaPush detects that you have a custom cloud services with needed dependencies. ZetaPush understands that you need a Stack instance so it instantiates it before instantiating your custom cloud service. Then ZetaPush instantiates your custom cloud service by providing, as the first argument of your constructor here, the instance of Stack.

This behavior avoids you to have complex code to instantiate built-in cloud services. Moreover, if you have several custom cloud services that are using the Stack service, thanks to dependency injection, there will be only one instance shared between your custom cloud services.

12.2.5.3. Use another custom cloud service

In this example, we will have 2 custom cloud services:

  • Calendar: Utils function to return the current date

  • HelloWorldService: Basic example using Calendar cloud function

The first custom cloud service (Calendar) is defined in the file worker/calendar.js.

worker/calendar.ts
1
2
3
4
5
export class Calendar {
  getNow() { (1)
    return new Date().toLocalDateString('fr-FR');
  }
}
1 The only cloud function of the Calendar service

Then, we have the HelloWorldWithDateService that use our Calendar service. It is defined in the file worker/index.ts.

worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { Injectable } from '@zetapush/core';
import { Calendar } from './calendar';        (1)

@Injectable()
export default class HelloWorldWithDateService {
  constructor(                                (2)
    private calendar: Calendar
  ) {}
  /**
   * Return 'Hello World' with current date
   */
  helloWorldWithDate() {
    return `Hello world at ${this.calendar.getNow()}`;
 }
}
1 We import the Calendar service from the worker/calendar.ts file
2 calendar is an instance of Calendar and this.calendar is initialized with calendar value

As for built-in cloud services, dependency injection works for your custom cloud services. Here it was an example

Private custom cloud service

In this example, we still have only one custom cloud service exposed.

One HelloWorldWithDateService is exposed and delegates some work to Calendar. Calendar is not exposed and can’t be directly called from a client. So it can be considered as a private custom cloud service.

Sometimes you may want to expose several custom cloud services.

Shared module of custom cloud services

As you can see, a custom cloud service is no more than just a standard class with methods written in TypeScript. If you want to develop reusable custom cloud services that could be used in different applications, you can do it easily by following standards. Actually, you can just create a npm module and import it like we do with @zetapush/core or @zetapush/platform-legacy.

You can also import any existing library that is available in the community.

13. Deploy/publish your application

Once you have developed your application and tested it, you may want to deploy it on the ZetaPush cloud.

13.1. What will be deployed ?

In the deployment with ZetaPush, you have 2 parts:

  • Hosting and scalability of the worker (custom cloud services)

  • Hosting of the front end

13.1.1. Worker

When you deploy the worker (custom cloud services) of your application, we take care of the hosting of your code. In addition, we manage the scability of your application.

13.1.2. Front end

For the front end part, we host your application and return you an unique URL to access to your application. We also link your front end logic with the differents services you need (custom cloud services or cloud services provided by ZetaPush).

13.2. Deploy both front and custom cloud services on the ZetaPush Cloud

The deployment is very easy, to do this you only need to launch this command in your application directory:

Deploy the application
$ npm run deploy

npm run deploy is a script alias defined in the package.json file. The command that is executed under the hood is:

$ zeta push

The command will read the .zetarc file. If there is no developerLogin and developerPassword properties or if the ZetaPush account is not validated, you will not be able to push your application.

About the appName property, if it is empty, the CLI will deploy your code on a new application.

When you deploy your application (Front + Worker), the CLI returns you an unique URL to use it.

13.3. Deploy your front on the ZetaPush Cloud

If you want to only deploy the front part of your application on the ZetaPush platform, you can launch:

Deploy the worker
$ npm run deploy -- --front

npm run deploy is a script alias defined in the package.json file. The command that is executed under the hood is:

$ zeta push --front

In this case your worker is not deployed at all.

13.4. Deploy your custom cloud services on the ZetaPush Cloud

The Worker is the back end of your application. Generally you put your business logic inside it.

If you want to deploy your worker only on the ZetaPush platform, you can launch:

Deploy the worker
$ npm run deploy -- --worker

npm run deploy is a script alias defined in the package.json file. The command that is executed under the hood is:

$ zeta push --worker

In this case you only deploy your back end code, so no URL will be returned.

14. User management in your application

15. Store data in your application

16. Secure your application

Tutorials

In this tutorial, you will create an application with ZetaPush, from the initialization to the deployment. You will learn to:

  • Add business logic with ZetaPush

  • Use cloud services provided by ZetaPush

  • Run your code locally

  • Deploy your application

17. Use case

You will create a realtime chat application, but it will be particular: This will be an Avengers Chat !

At the beginning, the user of the chat can choose an Avenger. Each character has many skills and they can use them on the chat to attack the others Avengers.

Table 3. List of skills by Avenger
Avenger Skill

Captain America

Shoot of shield / Cure

Falcon

Archery / Super vision

Iron Man

Flight / Missile launcher

Hulk

Punch / Regeneration

Thor

Hammer hit / Lightning strike

Spider Man

Shoot of cobweb / Jump with cobweb

Wolverine

Scratch / Regeneration

You will create this application in few steps:

We recommend to use TypeScript so in this tutorial all of your code will be in this language.

17.1. Initialize your application

In the first step, you need to create your application. To do this you can run:

1
npm init @zetapush myApp

This command will ask you your developer login and password.

This command will create you an account on the ZetaPush platform and will create your first application in the myApp directory. An email will be sent to confirm your account.

To use your application, you need to validate your account. To do this, click on the link in the received email

In this tutorial, we are focusing on the ZetaPush development. So, to begin, get all resources and add them to your application (css, assets, …​):

1
2
3
4
$ cd myApp/front/
$ rm -r ./*
$ curl -X GET 'http://github-download-subfolder.zpush.io/?owner=zetapush&repository=zetapush-tutorials&path=avengersChat/front' --output front.zip
$ unzip front.zip && rm front.zip
If you are using Windows, you can download the file with all resources and unzip it in the front directory. Link: http://github-download-subfolder.zpush.io/?owner=zetapush&repository=zetapush-tutorials&path=avengersChat/front

So you already have the style and the frontend logic in the folders assets and utils. You can browse these files to understand this code.

In this tutorial, you need to:

  1. Create the business logic with a custom cloud service

  2. Implement the interaction with the custom cloud service (front side)

  3. Deploy your application

17.2. Create your business logic

Now, you will create the business logic of your application. To do this, you will use a custom cloud service.

A custom cloud service is a class where you develop a business logic. You can create several custom cloud services inside one application. Each custom cloud service can use the cloud services provided by ZetaPush.

In your existing application you already have a custom cloud service on the file worker/index.ts (The entry point of the service is defined in the package.json with the property main).

To use your custom cloud services you need to export them. To do this, the property main in your package.json define the path of the file where you export all of your custom cloud services.

You can delete the content of the file worker/index.ts and fill it with the following content step by step.

17.2.1. Import cloud services and define constants

First, you need to import the cloud services provided by ZetaPush, used in this application:

  • Stack (Save data in a stack)

  • Messaging (Send and receive messages)

  • Groups (Manage group of users)

You also need to import Injectable that is useful for the dependencies injection.

Imports and constants
1
2
3
4
5
import { Injectable } from '@zetapush/core';
import { Stack, Messaging, Groups } from '@zetapush/platform-legacy';

const CONVERSATION_ID = 'avengersChat';
const CHANNEL_MESSAGING = 'avengersChannel'; (1)
1 Channel on which the users send and listen to the messages

17.2.2. Create the class with its constructor

A custom cloud service is a class, so you need to create it.

Class and constructor
1
2
3
4
5
6
7
8
9
10
11
12
@Injectable() (1)
export default class AvengersApi {
  /**
   * Constructor of our API
   */
  constructor(
    private stack: Stack,
    private messaging: Messaging,
    private groups: Groups
  ) {
  }
}
1 We expose our custom cloud service with only one annotation
The dependencies injection of ZetaPush use injection-js.

17.2.3. Create the chat

To create our chat, we use the Groups cloud service provided by ZetaPush. The created group includes all users of the conversation. So we add a method to our class to create this conversation.

Create conversation
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * Create the conversation of the chat, if doesn't already exists
 */
async createConversation() {
  const { exists } = await this.groups.exists({
    group: CONVERSATION_ID
  });
  if (!exists) {
    await this.groups.createGroup({
      group: CONVERSATION_ID
    });
  }
}

17.2.4. Add user to the conversation

When an user comes to the chat, we need to add it to the conversation. So we create a method in our class to add the current user to the conversation.

1
2
3
4
5
6
7
8
9
/**
* Add the current user to the conversation
*/
addMeToConversation(parameters: any, context: any) { (1)
  return this.groups.addUser({
    group: CONVERSATION_ID,
      user: context.owner (2)
  });
}
1 Each custom cloud function takes only one (client-provided) parameter. The second is the context, injected by the SDK
2 We get the caller (owner) of the cloud function from the context.

17.2.5. Send a message

No we want to send a message on our chat. To do this, we need to follow 3 steps:

  1. Get all users in the conversation

  2. Send the message of all users in the conversation

  3. Store the message in a stack

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* Send a message on the chat
* @param {Object} message
*/
async sendMessage(message = {}) {
  // Get all users inside the conversation
  const group = await this.groups.groupUsers({
    group: CONVERSATION_ID
  });
  const users = group.users || [];

  // Send the message to each user in the conversation
  this.messaging.send({
    target: users,
    channel: CHANNEL_MESSAGING,
    data: { message }
  });

  // Store the message in a stack
  await this.stack.push({
    stack: CONVERSATION_ID,
    data: message
  });

  return group;
}
There is no specific method to launch an attack, to do this, we only send a specific message throught sendMessage.

17.2.6. Get all messages

To complete our business logic, we need to have an other method in our class to get all messages (when we enter the chat).

1
2
3
4
5
6
7
8
9
/**
* Get all messages in the conversation
*/
async getMessages() {
  const { result } = await this.stack.list({
    stack: CONVERSATION_ID
  });
  return result;
}

Now your custom cloud service is ready with this following content:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import { Injectable } from '@zetapush/core';
import { Stack, Messaging, Groups } from "@zetapush/platform-legacy";

const CONVERSATION_ID = "avengersChat";
const CHANNEL_MESSAGING = "avengersChannel";

@Injectable()
export default class AvengersApi {
  /**
   * Constructor of our API
   */
  constructor(
    private stack: Stack,
    private messaging: Messaging,
    private groups: Groups
  ) {}

  /**
   * Create the conversation of the chat, if doesn't already exists
   */
  async createConversation() {
    const { exists } = await this.groups.exists({
      group: CONVERSATION_ID
    });
    if (!exists) {
      await this.groups.createGroup({
        group: CONVERSATION_ID
      });
    }
  }

  /**
   * Add the current user in the conversation
   */
  addMeToConversation(parameters: any, context: any) {
    return this.groups.addUser({
      group: CONVERSATION_ID,
      user: context.owner
    });
  }

  /**
   * Send a message on the chat
   * @param {Object} message
   */
  async sendMessage(message = {}) {
    // Get all users inside the conversation
    const group = await this.groups.groupUsers({
      group: CONVERSATION_ID
    });
    const users = group.users || [];

    // Send the message to each user in the conversation
    this.messaging.send({
      target: users,
      channel: CHANNEL_MESSAGING,
      data: { message }
    });

    // Store the message in a stack
    await this.stack.push({
      stack: CONVERSATION_ID,
      data: message
    });

    return group;
  }

  /**
   * Get all messages in the conversation
   */
  async getMessages() {
    const { result } = await this.stack.list({
      stack: CONVERSATION_ID
    });
    return result;
  }
}

17.3. Use your custom cloud services

Once we have our custom cloud service, we need to create the frontend of our application.

17.3.1. Launch the worker locally

When we work on the frontend part, we often want to test our interaction with the backend logic. With ZetaPush, you can launch your worker locally to test this interaction. To do this you need to use the CLI and run: zeta run. But in this project, the CLI is imported and a script is created with npm, so you just need to launch:

Run worker locally
// In the root of the application
$ npm run start -- --serve-front
If you want to install the ZetaPush CLI you can run npm install -g @zetapush/cli.

Then you have access to your application on http://localhost:3000.

17.3.2. Interaction with worker

Now you just need to add the interaction with the custom cloud service. To do this, fill the file front/index.js:

Interaction with worker
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import AvengersController from './utils/controller.js'; (1)

// Create the ZetaPush Client
const client = new ZetaPushClient.WeakClient();
/**
 * Create service to listen incoming messages
 */
const service = client.createService({
  Type: ZetaPushPlatform.Messaging,
  listener: {
    // Listen incoming messages from the channel 'avengersChannel'
    avengersChannel: ({ data }) => controller.onAvengersMessage(data), (2)
  },
});

const controller = new AvengersController(client);

(async function main() {
  // Expose to template
  window.$controller = controller;
  // Connect to ZetaPush
  await client.connect();
  // Notify client connected
  controller.onConnectionEstablished();
})();
1 Import the frontend logic (in the controller)
2 Cloud service provided by ZetaPush to listen to incoming messages

17.4. Deploy your application

Your application is working but only locally. To deploy your application you just need to launch zeta push. In this application you already have a npm script so you can run:

Deploy the application
$ npm run deploy

This command deploys all in once (Front and Worker). It will return you an unique URL to access to your application.

Enjoy ! Your Avengers Chat is working and deployed !

Guides

FAQ

  1. Do I have to develop custom cloud services ?

    No. Developing custom cloud services is not required. You can use cloud services that are already provided by ZetaPush. You may need to develop custom cloud services in different situations:

    • You have several devices so you want to mutualize your business code

    • ZetaPush services are not fully compatible with your business needs

Reference

18. Available cloud services

18.1. Standard User Workflow

18.1.1. Presentation

In a software application, we (almost) always need to manage users. The Standard User Workflow helps you to do this, in the most common use case. Currently, it only handles the registration of a user. In the following versions, this cloud service will help you to:

  • Log in a user

  • Log out a user

  • Manage a forgotten password

  • Manage permissions of users

  • etc…​

At this moment, the connection and the disconnection of a user is done through the ZetaPush SDK (We will see below how to do this).

For us, the most common use case is when a user can create an account using a login and a password and needs to confirm his account via a link in an email.

Sign up:

standarduserworkflow signup
1 The user creates his account using a login, a password and an email. When the user submits the form, the account is created on the ZetaPush platform. In order to ensure that the user is not a bot, the account has to be confirmed before the user is authorized to login.
2 An email is sent to the user in order to confirm its account. The email contains the confirmation link. He needs to confirm his account before connection.
3 When the user clicks on the lonk in the email, he is authorized to login.

Log in:

standarduserworkflow login
1 When the user account is confirmed, he can log in the application using the his login and his password.
If the user tries to log into the application before he confirmed his account, an error will be returned to explain that the account needs to be confirmed via the link in the confirmation email.

18.1.2. Quick start

In this part we will explain how to use the Standard User Workflow in the default behavior, i.e. using the default implementations of each parts of the workflow (For example, the default implementation to send the confirmation email use the Mailjet API).

To use the Standard User Workflow, you just need 4 steps :

  • Create a ZetaPush application as usual

  • Import and use the Standard User Workflow in your worker

  • Configure some properties

  • Develop your front by calling the Standard User Workflow API

18.1.2.1. Create a ZetaPush application as usual

In this Quickstart, we begin with a generated application using the CLI. So you can run:

$ npm init @zetapush myApp

We import the library @zetapush/user-management that provides the Standard User Workflow using NPM:

$ npm install --save @zetapush/user-management
18.1.2.2. Import and use the Standard User Workflow in your worker

Your worker contains just this code :

worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
import { Module } from '@zetapush/core';
import { StandardUserManagementModule, StandardUserWorkflow, ConfirmationUrlHttpHandler } from '@zetapush/user-management';

@Module({ (1)
  imports: [StandardUserManagementModule], (2)
  expose: {
    user: StandardUserWorkflow, (3)
    http: ConfirmationUrlHttpHandler (4)
  }
})
export default class Api {}
1 As usual, the worker code exports a class (maned Api here). As we import another module (@zetapush/user-management) we need to use @module annotation.
2 First you need to export a class (named Api here) that is a module (configured with the @Module() annotation). You import the StandardUserManagementModule to use it into your application.
3 The @zetapush/user-management library/cloud service provides the StandardUserWorkflow class. The front needs to call methods of the StandardUserWorkflow class that’s why StandardUserWorkflow class is exposed. In this example, the StandardUserWorflow methods are exposed in user namespace.
4 We also expose ConfirmationUrlHttpHandler to instanciate a web server in your worker that will listen the account confirmation event (When the user clicks on the link in the email).

That all for the worker !

18.1.2.3. Configure some properties

Some configuration properties are required (like Mailjet API keys for example) to make the whole workflow work. To configure those properties, you need to create a file named application.json at the root of your application:

application.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
  "email": {
    "from": "celtia@zetapush.com" (1)
  },
  "registration": {
    "confirmation": {
      "base-url": "http://localhost:2999", (2)
      "email": {
        "subject": "Please confirm your account registration"
      },
      "success-url": "http://localhost:3000#login", (3)
      "failure-url": "http://localhost:3000#confirmation-failed" (4)
    }
  },
  "mailjet": {  (5)
    "apikey-public": "",
    "apikey-private": ""
  }
}
1 We configure the email sender
2 the base-url property is necessary to run the application in local. This property will soon be optional.
3 Link of your application where the user will be redirected when he confirms his account.
4 Link of your application where the user will be redirected when the confirmation failed.
5 Your Mailjet properties.
18.1.2.4. Develop your front by calling the Standard User Workflow API

Finally, we just need to call the cloud functions to create a user account, log in and log out from the client part. You can replace the front/index.js file by the following content :

front/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// Create the ZetaPush API
const client = new ZetaPushClient.SmartClient();
const userApi = client.createProxyTaskService({ (1)
  namespace: 'user'
});

// The user is hard-coded because we only show the front -> worker interaction
const user = {
  login: 'test',
  password: 'password',
  email: 'test-zetapush@yopmail.com'
};

async function signUpUser() { (2)
  // First connection as anonymous user to allow us to create a user
  await client.connect();

  // Creation of the user account
  try {
    await userApi.signup({
      credentials: {
        login: user.login,
        password: user.password
      },
      profile: {
        email: user.email
      }
    });
    console.log('User account created');
  } catch (err) {
    console.error('Failed to create user account : ', err);
  }
}

/**
 * Connection of a user
 */
async function connectUser() { (3)
  await client.setCredentials({ login: user.login, password: user.password });
  client
    .connect()
    .then(() => {
      console.log('User connected');
    })
    .catch(err => {
      console.error('Failed to connect user : ', err);
    });
}

/**
 * Disconnection of a user
 */
async function disconnectUser() { (4)
  await client.disconnect();
  console.log('User disconnected');
}
1 We created a ZetaPush client and his API to call our cloud functions (We use the namespace 'user' to call the Standard User Workflow).
2 Function to create an account of the ZetaPush platform for this application.
3 Function to connect a user.
4 Function to disconnect a user.

Here is a very basic HTML page to see the result in the console :

front/index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Standard User Workflow</title>
</head>

<body>
  <button onclick="signUpUser()">Sign up</button>
  <button onclick="connectUser()">Connect</button>

  <script src="https://unpkg.com/@zetapush/client"></script>
  <script src="./index.js"></script>
</body>

</html>

Run the following command to run your application in local and serve the front part :

Run the application
$ npm run start -- --serve-front
For a more real-world sample with a complete UI (signup form and login form) you can go to GitHub ZetaPush Examples.

19. Legacy cloud services

19.1. User Management

19.1.1. Simple

End-user API for the simple local authentication

These API verbs allow end-users to manage their account(s).

19.1.1.1. createUser

Creates a new account in this 'simple' authentication realm. Returns a map of account fields, including a field named <i>zetapushKey</i> containing the global user key of the user (value of the <b>__userKey</b> pseudo-constant when this new account will be used)

createUser(parameters: BasicAuthenticatedUser): Promise<-object>.adoc#,Map<String,Object>>
1
const response = await this.simple.createUser(parameters);
19.1.1.2. credentials

Returns the list of account credentials in this service for the asking user. Might return an empty list.

credentials(parameters: ImpersonatedTraceableRequest): Promise<AllCredentials>
1
const response = await this.simple.credentials(parameters);
19.1.1.3. updateKey

Updates an existing account primary key (login, NOT <b>__userKey</b>) in this 'simple' authentication realm. The updated account MUST belong to the user making the call. The configured login field MUST be given, as a user (identified by his zetapush userKey) might possess several accounts. Returns a map of account fields

updateKey(parameters: UserLoginchange): Promise<-object>.adoc#,Map<String,Object>>
1
const response = await this.simple.updateKey(parameters);
19.1.1.4. updateUser

Updates an existing account in this 'simple' authentication realm. The updated account MUST belong to the user making the call. The configured login field MUST be given, as a user (identified by his zetapush userKey) might possess several accounts. Returns a map of account fields

updateUser(parameters: BasicAuthenticatedUser): Promise<-object>.adoc#,Map<String,Object>>
1
const response = await this.simple.updateUser(parameters);
19.1.1.5. deleteUser

Deletes an existing account in this 'simple' authentication realm.

deleteUser(parameters: ExistenceCheck): Promise<ExistenceCheck>
1
const response = await this.simple.deleteUser(parameters);
19.1.1.6. checkUser

Checks whether the given account already exists in this 'simple' authentication realm. This verb returns all the information about the user, including non public fields.

checkUser(parameters: ExistenceCheck): Promise<-object>.adoc#,Map<String,Object>>
1
const response = await this.simple.checkUser(parameters);
19.1.1.7. requestReset

Requests a password reset for the given unique account key. The account key must exist and must be given, as it cannot obviously be deduced from the currently logged in user. The returned token needs to be sent to the intended recipient only. The typical use case is to define a macro that requests a reset, generates a email template and emails the user. The macro can then be safely called by a weakly authenticated user. Requesting a reset does not invalidate the password. Requesting a reset again invalidates previous reset requests (only the last token is usable)

requestReset(parameters: ResetRequest): Promise<ResetInfo>
1
const response = await this.simple.requestReset(parameters);
19.1.1.8. changePassword

Changes a user password for this authentication realm. The user can be either explicit, implicit (one of the current user’s accounts) or deduced from the token. You should provide at least one of 'key' and 'token'. If you do not, the server will try and find any key for the current user. The change is effective immediately. However, already logged in users might stay connected. The password and token fields are always null in the output.

changePassword(parameters: ChangePasswordRequest): Promise<ChangePasswordRequest>
1
const response = await this.simple.changePassword(parameters);
19.1.1.9. checkPassword
checkPassword(parameters: CheckPasswordRequest): Promise<CheckPasswordResult>
1
const response = await this.simple.checkPassword(parameters);
19.1.1.10. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Simple, BasicAuthenticatedUser } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private simple: Simple (2)
  ) {}
  async doStuff(parameters: BasicAuthenticatedUser) {
    const response = await this.simple.createUser(parameters); (3)
    return response;
  }
}
1 Import Simple from platform
2 Declare injected service
3 Call injected service

19.1.2. Weak

User API for weak devices control

User API for control and release of weakly authenticated user sessions.

19.1.2.1. control

Takes control of a weak user session, identified by the given public token. The public token has been previously made available by the controlled device, for example by displaying a QRCode. Upon control notification, the client SDK of the controlled session is expected to re-handshake.

control(parameters: UserControlRequest): Promise<UserControlStatus>
1
const response = await this.weak.control(parameters);
19.1.2.2. release

Releases control of a weak user session, identified by the given public token. The weak user session must have been previously controlled by a call to 'control'.

release(parameters: UserControlRequest): Promise<UserControlStatus>
1
const response = await this.weak.release(parameters);
19.1.2.3. provision

Provisions an arbitrary number of accounts. The maximum number of accounts that you can create in one single call is configured per server.

provision(parameters: ProvisioningRequest): Promise<ProvisioningResult>
1
const response = await this.weak.provision(parameters);
19.1.2.4. getToken

Returns your current session’s private token. The token field may be null, if you did not log in with this authentication. The token can be used to log in as the same weak user another time.

getToken(parameters: undefined): Promise<UserToken>
1
const response = await this.weak.getToken(parameters);
19.1.2.5. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Weak, UserControlRequest } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private weak: Weak (2)
  ) {}
  async doStuff(parameters: UserControlRequest) {
    const response = await this.weak.control(parameters); (3)
    return response;
  }
}
1 Import Weak from platform
2 Declare injected service
3 Call injected service

19.1.3. Userdir

User API for user information

19.1.3.1. userInfo
userInfo(parameters: UserInfoRequest): Promise<UserInfoResponse>
1
const response = await this.userdir.userInfo(parameters);
search(parameters: UserSearchRequest): Promise<UserSearchResponse>
1
const response = await this.userdir.search(parameters);
19.1.3.3. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Userdir, UserInfoRequest } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private userdir: Userdir (2)
  ) {}
  async doStuff(parameters: UserInfoRequest) {
    const response = await this.userdir.userInfo(parameters); (3)
    return response;
  }
}
1 Import Userdir from platform
2 Declare injected service
3 Call injected service

19.1.4. Groups

User API for groups and rights.

Groups are stored per user. This means that two users can own a group with the same identifier. A couple (owner, group) is needed to uniquely identify a group inside a group management service. The triplet (deploymentId, owner, group) is actually needed to fully qualify a group outside of the scope of this service.

19.1.4.1. grant

The granting API does not do any check when storing permissions. In particular when granting rights on a verb and resource of another API, the existence of said verb and resource is not checked.

grant(parameters: Grant): Promise<Grant>
1
const response = await this.groups.grant(parameters);
19.1.4.2. createGroup

Creates a group owned by the current user. Group creation may fail if the group already exists.

createGroup(parameters: GroupInfo): Promise<GroupInfo>
1
const response = await this.groups.createGroup(parameters);
19.1.4.3. listOwnedGroups

Returns the whole list of groups owned by the current user

listOwnedGroups(parameters: TraceablePaginatedImpersonatedRequest): Promise<OwnedGroups>
1
const response = await this.groups.listOwnedGroups(parameters);
19.1.4.4. listDetailedOwnedGroups

Returns the whole list of groups owned by the current user, with their members

listDetailedOwnedGroups(parameters: TraceablePaginatedImpersonatedRequest): Promise<OwnedGroupsWithDetails>
1
const response = await this.groups.listDetailedOwnedGroups(parameters);
19.1.4.5. myGroups

Returns the whole list of groups the current user is part of. Groups may be owned by anyone, including the current user.

myGroups(parameters: ImpersonatedRequest): Promise<GroupInfo[]>
1
const response = await this.groups.myGroups(parameters);
19.1.4.6. listJoinedGroups

Returns the whole list of groups the current user is part of. Groups may be owned by anyone, including the current user.

listJoinedGroups(parameters: TraceablePaginatedImpersonatedRequest): Promise<JoinedGroups>
1
const response = await this.groups.listJoinedGroups(parameters);
19.1.4.7. delGroup

Removes the given group owned by the current user or the given owner. Also removes all grants to that group.

delGroup(parameters: GroupRelated): Promise<GroupRelated>
1
const response = await this.groups.delGroup(parameters);
19.1.4.8. addMe

Adds me (the caller) to a group. This verb exists so that group owners may grant the right to join their groups without granting the right to add other users to those groups. The 'user' field is implicitly set to the current user’s key.

addMe(parameters: UserGroup): Promise<UserGroup>
1
const response = await this.groups.addMe(parameters);
19.1.4.9. memberOf

Tests whether I (the caller) am a member of the given group. This verb exists so that users can determine if they are part of a group without being granted particular rights. The 'user' field is implicitly set to the current user’s key.

memberOf(parameters: UserMembership): Promise<UserGroupMembership>
1
const response = await this.groups.memberOf(parameters);
19.1.4.10. addUsers

Users are processed in the given order In case of failure in the middle of a user list, this verb may have succeeded to add the first users, but will not continue processing the end of the list.

addUsers(parameters: GroupUsers): Promise<void>
1
const response = await this.groups.addUsers(parameters);
19.1.4.11. delUsers
delUsers(parameters: GroupUsers): Promise<void>
1
const response = await this.groups.delUsers(parameters);
19.1.4.12. mgrant

Grant several rights at once.

mgrant(parameters: Grants): Promise<Grants>
1
const response = await this.groups.mgrant(parameters);
19.1.4.13. mrevoke
mrevoke(parameters: Grants): Promise<Grants>
1
const response = await this.groups.mrevoke(parameters);
19.1.4.14. listGrants

This API lists explicitly configured rights. Effective rights include configured rights, implicit rights and inherited rights.

listGrants(parameters: GroupRelated): Promise<GrantList>
1
const response = await this.groups.listGrants(parameters);
19.1.4.15. listGroupGrants

This API lists explicitly configured rights. Effective rights include configured rights, implicit rights and inherited rights.

listGroupGrants(parameters: GroupRelatedAndPaged): Promise<PagedGrantList>
1
const response = await this.groups.listGroupGrants(parameters);
19.1.4.16. listPresences

Returns the list of members of the given groups, along with their actual and current presence on the zetapush server. The current implementation does not include information about the particular devices users are connected with. If a user is connected twice with two different devices, two identical entries will be returned.

listPresences(parameters: GroupRelated): Promise<GroupPresence>
1
const response = await this.groups.listPresences(parameters);
19.1.4.17. listGroupPresences

Returns the list of members of the given groups, along with their actual and current presence on the zetapush server. The current implementation does not include information about the particular devices users are connected with. If a user is connected twice with two different devices, two identical entries will be returned.

listGroupPresences(parameters: GroupRelatedAndPaged): Promise<PagedGroupPresence>
1
const response = await this.groups.listGroupPresences(parameters);
19.1.4.18. addUser

Adds the given user to the given group. Addition may fail if the given group does not already exist.

addUser(parameters: UserGroup): Promise<UserGroup>
1
const response = await this.groups.addUser(parameters);
19.1.4.19. delUser
delUser(parameters: UserGroup): Promise<UserGroup>
1
const response = await this.groups.delUser(parameters);
19.1.4.20. groupUsers

Returns the whole list of users configured inside the given group.

groupUsers(parameters: GroupRelated): Promise<GroupUsers>
1
const response = await this.groups.groupUsers(parameters);
19.1.4.21. revoke
revoke(parameters: Grant): Promise<Grant>
1
const response = await this.groups.revoke(parameters);
19.1.4.22. allGroups

Returns the whole list of groups owned by the current user, with their members

allGroups(parameters: ImpersonatedRequest): Promise<GroupUsers[]>
1
const response = await this.groups.allGroups(parameters);
19.1.4.23. groups

Returns the whole list of groups owned by the current user

groups(parameters: ImpersonatedRequest): Promise<GroupInfo[]>
1
const response = await this.groups.groups(parameters);
19.1.4.24. check

This API checks if the given user has the proper authorizations to perform the given action on the owner’s resource. If you give the same value for 'user' and 'owner', the check always passes.

check(parameters: GrantCheckRequest): Promise<GrantCheckResult>
1
const response = await this.groups.check(parameters);
19.1.4.25. exists

Returns whether a group exists or not.

exists(parameters: GroupRelated): Promise<GroupExistence>
1
const response = await this.groups.exists(parameters);
19.1.4.26. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Groups, Grant } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private groups: Groups (2)
  ) {}
  async doStuff(parameters: Grant) {
    const response = await this.groups.grant(parameters); (3)
    return response;
  }
}
1 Import Groups from platform
2 Declare injected service
3 Call injected service

19.2. Data Management

19.2.1. Gda

GDA User API

User API for Generic Data Access. The data are stored on a per-user basis. Users can put, get, list their data.

19.2.1.1. puts

Creates or replaces the (maybe partial) contents of a collection of rows. This method only creates or replaces cells for non-null input values.

puts(parameters: GdaPuts): Promise<GdaPutsResult>
1
const response = await this.gda.puts(parameters);
19.2.1.2. inc

Increments a cell 64-bit signed integer value and returns the result in the data field. The increment is atomic : if you concurrently increment 10 times a value by 1, the final result will be the initial value plus 10. The actual individual resulting values seen by the 10 concurrent callers may vary discontinuously, with duplicates : at least one of them will see the final (+10) result.

inc(parameters: GdaPut): Promise<GdaPut>
1
const response = await this.gda.inc(parameters);
19.2.1.3. removeRow

Removes all columns of the given row from the given table.

removeRow(parameters: GdaRowRequest): Promise<GdaRowRequest>
1
const response = await this.gda.removeRow(parameters);
19.2.1.4. removeColumn

Removes all cells of the given column of the given row from the given table.

removeColumn(parameters: GdaColumnRequest): Promise<GdaColumnRequest>
1
const response = await this.gda.removeColumn(parameters);
19.2.1.5. removeCell

Removes only one cell of the given column of the given row from the given table.

removeCell(parameters: GdaCellRequest): Promise<GdaCellRequest>
1
const response = await this.gda.removeCell(parameters);
19.2.1.6. mget

Returns full data rows, in the order they were asked.

mget(parameters: GdaMultiGetRequest): Promise<GdaMultiGetResult>
1
const response = await this.gda.mget(parameters);
19.2.1.7. getCells

Returns a precise list of cells from a column in a data row.

getCells(parameters: GdaCellsRequest): Promise<GdaCellsResult>
1
const response = await this.gda.getCells(parameters);
19.2.1.8. get

Returns a full data row.

get(parameters: GdaGet): Promise<GdaGetResult>
1
const response = await this.gda.get(parameters);
19.2.1.9. put

Creates or replaces the contents of a particular cell.

put(parameters: GdaPut): Promise<GdaPut>
1
const response = await this.gda.put(parameters);
19.2.1.10. list

Returns a paginated list of rows from the given table.

list(parameters: GdaList): Promise<GdaListResult>
1
const response = await this.gda.list(parameters);
19.2.1.11. removeRange

Removes the specified columns of the given range of rows from the given table.

removeRange(parameters: GdaRemoveRange): Promise<GdaRemoveRange>
1
const response = await this.gda.removeRange(parameters);
19.2.1.12. filter

Similar to range, but rows can be filtered out according to a developer-supplied predicate. A range consists of consecutive rows from the start key (inclusive) to the stop key (exclusive). You can specify partial keys for the start and stop fields.

filter(parameters: GdaFilterRequest): Promise<GdaFilterResult>
1
const response = await this.gda.filter(parameters);
19.2.1.13. range

Returns a paginated range of rows from the given table. A range consists of consecutive rows from the start key (inclusive) to the stop key (exclusive). You can specify partial keys for the start and stop fields.

range(parameters: GdaRange): Promise<GdaRangeResult>
1
const response = await this.gda.range(parameters);
19.2.1.14. reduce

Returns a computed single reduced result from a range of rows from the given table. A range consists of consecutive rows from the start key (inclusive) to the stop key (exclusive). You can specify partial keys for the start and stop fields.

reduce(parameters: GdaReduceRequest): Promise<GdaReduceResult>
1
const response = await this.gda.reduce(parameters);
19.2.1.15. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Gda, GdaPuts } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private gda: Gda (2)
  ) {}
  async doStuff(parameters: GdaPuts) {
    const response = await this.gda.puts(parameters); (3)
    return response;
  }
}
1 Import Gda from platform
2 Declare injected service
3 Call injected service

19.2.2. Stack

Data stack user API

Data is stored on a per user basis. However, notifications can be sent to a configurable set of listeners. Stack names are arbitrary and do not need to be explicitly initialized.

19.2.2.1. purge

Removes all items from the given stack.

purge(parameters: StackRequest): Promise<StackRequest>
1
const response = await this.stack.purge(parameters);
19.2.2.2. getListeners

Returns the whole list of listeners for the given stack.

getListeners(parameters: StackRequest): Promise<StackListeners>
1
const response = await this.stack.getListeners(parameters);
19.2.2.3. setListeners

Sets the listeners for the given stack.

setListeners(parameters: StackListeners): Promise<StackListeners>
1
const response = await this.stack.setListeners(parameters);
19.2.2.4. remove

Removes the item with the given guid from the given stack.

remove(parameters: StackItemRemove): Promise<StackItemRemove>
1
const response = await this.stack.remove(parameters);
19.2.2.5. update

Updates an existing item of the given stack. The item MUST exist prior to the call.

update(parameters: StackItemAdd): Promise<StackItemAdd>
1
const response = await this.stack.update(parameters);
19.2.2.6. push

Pushes an item onto the given stack. The stack does not need to be created.

push(parameters: StackItemAdd): Promise<StackItemAdd>
1
const response = await this.stack.push(parameters);
19.2.2.7. list

Returns a paginated list of contents for the given stack. Content is sorted according to the statically configured order.

list(parameters: StackListRequest): Promise<StackListResponse>
1
const response = await this.stack.list(parameters);
19.2.2.8. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Stack, StackRequest } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private stack: Stack (2)
  ) {}
  async doStuff(parameters: StackRequest) {
    const response = await this.stack.purge(parameters); (3)
    return response;
  }
}
1 Import Stack from platform
2 Declare injected service
3 Call injected service

19.2.3. Search

ElasticSearch Service

This API is a very thin wrapper around ElasticSearch’s API.

19.2.3.1. index

Inserts or updates a document into the elasticsearch engine.

index(parameters: SearchData): Promise<void>
1
const response = await this.search.index(parameters);
19.2.3.2. get

Retrieves a document from the elasticsearch engine by id.

get(parameters: SearchDocumentId): Promise<SearchData>
1
const response = await this.search.get(parameters);
19.2.3.3. delete

Deletes a document from the elasticsearch engine by id.

delete(parameters: SearchDocumentId): Promise<void>
1
const response = await this.search.delete(parameters);
19.2.3.4. search
search(parameters: SearchRequest): Promise<SearchResults>
1
const response = await this.search.search(parameters);
19.2.3.5. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Search, SearchData } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private search: Search (2)
  ) {}
  async doStuff(parameters: SearchData) {
    const response = await this.search.index(parameters); (3)
    return response;
  }
}
1 Import Search from platform
2 Declare injected service
3 Call injected service

19.3. File Management

19.3.1. Zpfs_hdfs

User API for local file management

User API for file content manipulation User API for virtual file management and http file upload This API contains all the verbs needed to browse, upload and remove files. Files are stored on a per-user basis: each user has his or her own whole virtual filesystem. Uploading a file is a 3-step process : request an upload URL, upload via HTTP, notify this service of completion.

19.3.1.1. readToken

Requests a token. This token can be used to retrieve a compressed folder via HTTP.

readToken(parameters: ZpfsRequest): Promise<ZpfsToken>
1
const response = await this.zpfs_hdfs.readToken(parameters);
19.3.1.2. create

Creates a file, writes content and closes the file as a single operation. Calling this verb is functionnally equivalent to successively calling 'newUploadUrl', posting the content and calling 'newFile'

create(parameters: FileCreationRequest): Promise<ListingEntryInfo>
1
const response = await this.zpfs_hdfs.create(parameters);
19.3.1.3. open

Opens a file for reading.

open(parameters: ZpfsRequest): Promise<ZpfsFileHandler>
1
const response = await this.zpfs_hdfs.open(parameters);

Links a file or folder to another location. May fail if the target location is not empty.

link(parameters: CreatedFile): Promise<CreatedFile>
1
const response = await this.zpfs_hdfs.link(parameters);
19.3.1.5. stat

Returns information about a single file. The entry field will be null if the path does not exist

stat(parameters: FileStatRequest): Promise<FileStatResult>
1
const response = await this.zpfs_hdfs.stat(parameters);
19.3.1.6. cp

Copies a file or folder (recursively) to a new location. May fail if the target location is not empty.

cp(parameters: CreatedFile): Promise<CreatedFile>
1
const response = await this.zpfs_hdfs.cp(parameters);
19.3.1.7. ls

Returns a paginated list of the folder’s content.

ls(parameters: FolderListingRequest): Promise<FolderListing>
1
const response = await this.zpfs_hdfs.ls(parameters);
19.3.1.8. mv

Moves a file or folder (recursively) to a new location. May fail if the target location is not empty.

mv(parameters: CreatedFile): Promise<CreatedFile>
1
const response = await this.zpfs_hdfs.mv(parameters);
19.3.1.9. snapshot

Creates a new folder and then copies the given files inside

snapshot(parameters: SnapshotCreationRequest): Promise<CreatedFile>
1
const response = await this.zpfs_hdfs.snapshot(parameters);
19.3.1.10. du

Returns an recursively aggregated number of used bytes, starting at the given path.

du(parameters: ZpfsRequest): Promise<ZpfsDiskUsage>
1
const response = await this.zpfs_hdfs.du(parameters);
19.3.1.11. rm

Removes a file or folder (recursively).

rm(parameters: FileRemoval): Promise<FileRemoval>
1
const response = await this.zpfs_hdfs.rm(parameters);
19.3.1.12. freeUploadUrl
freeUploadUrl(parameters: FileUploadRequest): Promise<FileUploadLocation>
1
const response = await this.zpfs_hdfs.freeUploadUrl(parameters);
19.3.1.13. newUploadUrl

Requests an HTTP upload URL. The URL contains temporary credentials (typically valid for a few minutes) and is meant for immediate use.

newUploadUrl(parameters: FileUploadRequest): Promise<FileUploadLocation>
1
const response = await this.zpfs_hdfs.newUploadUrl(parameters);
19.3.1.14. updateMeta
updateMeta(parameters: FileMetaUpdate): Promise<ListingEntryInfo>
1
const response = await this.zpfs_hdfs.updateMeta(parameters);
19.3.1.15. newFile

The client application calls this verb to notify that it’s done uploading to the cloud. Calling that verb MAY trigger additional events such as thumbnail/metadata creation.

newFile(parameters: FileUploadComplete): Promise<ListingEntryInfo>
1
const response = await this.zpfs_hdfs.newFile(parameters);
19.3.1.16. mkdir

Creates a new folder. May fail if the target location is not empty.

mkdir(parameters: FolderCreationRequest): Promise<CreatedFile>
1
const response = await this.zpfs_hdfs.mkdir(parameters);
19.3.1.17. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Zpfs_hdfs, ZpfsRequest } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private zpfs_hdfs: Zpfs_hdfs (2)
  ) {}
  async doStuff(parameters: ZpfsRequest) {
    const response = await this.zpfs_hdfs.readToken(parameters); (3)
    return response;
  }
}
1 Import Zpfs_hdfs from platform
2 Declare injected service
3 Call injected service

19.3.2. Template

User API for templates

Users use this API to evaluate pre-configured templates.

19.3.2.1. evaluate

Evaluates the given template and returns the result as a string. Templates are parsed the first time they are evaluated. Evaluation may fail early due to a parsing error.

evaluate(parameters: TemplateRequest): Promise<TemplateResult>
1
const response = await this.template.evaluate(parameters);
19.3.2.2. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Template, TemplateRequest } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private template: Template (2)
  ) {}
  async doStuff(parameters: TemplateRequest) {
    const response = await this.template.evaluate(parameters); (3)
    return response;
  }
}
1 Import Template from platform
2 Declare injected service
3 Call injected service

19.4. Communication

19.4.1. Messaging

Messaging service

Simple and flexible user-to-user or user-to-group messaging service.

19.4.1.1. send

Sends the given message to the specified target on the given (optional) channel. The administratively given default channel name is used when none is provided in the message itself.

send(parameters: Message): Promise<void>
1
const response = await this.messaging.send(parameters);
19.4.1.2. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Messaging, Message } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private messaging: Messaging (2)
  ) {}
  async doStuff(parameters: Message) {
    const response = await this.messaging.send(parameters); (3)
    return response;
  }
}
1 Import Messaging from platform
2 Declare injected service
3 Call injected service

19.4.2. Notif

Notification User API

User API for notifications. For notifications to work properly, it is imperative that the resource name of a device remain constant over time.

19.4.2.1. send

Sends a native push notification to the target.

send(parameters: NotificationMessage): Promise<NotificationSendStatus>
1
const response = await this.notif.send(parameters);
19.4.2.2. unregister

Unregisters the device for the current user and resource. This verb does not need any parameters.

unregister(parameters: undefined): Promise<void>
1
const response = await this.notif.unregister(parameters);
19.4.2.3. register

Registers the device for the current user and resource. This service maintains a mapping of userkey/resource to device registration IDs. You MUST NOT re-use the same resource name from one device to another if you want to target specific devices with 'send'. Only one registration can be active for a given userKey/resource pair in a notification service. Device registration can be <b>neither impersonated nor called indirectly</b> (from a scheduled job).

register(parameters: NotifiableDeviceRegistration): Promise<void>
1
const response = await this.notif.register(parameters);
19.4.2.4. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Notif, NotificationMessage } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private notif: Notif (2)
  ) {}
  async doStuff(parameters: NotificationMessage) {
    const response = await this.notif.send(parameters); (3)
    return response;
  }
}
1 Import Notif from platform
2 Declare injected service
3 Call injected service

19.4.3. Sendmail

Mail service user API

This service is statically configured with an outgoing SMTP server. Users call the API here to actually send emails.

19.4.3.1. send

Sends an email with the given body to the intended recipients.

send(parameters: Email): Promise<void>
1
const response = await this.sendmail.send(parameters);
19.4.3.2. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Sendmail, Email } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private sendmail: Sendmail (2)
  ) {}
  async doStuff(parameters: Email) {
    const response = await this.sendmail.send(parameters); (3)
    return response;
  }
}
1 Import Sendmail from platform
2 Declare injected service
3 Call injected service

19.4.4. Sms_ovh

SMS service

User API for SMS.

19.4.4.1. send

Sends the given message to the given recipients.

send(parameters: SmsMessage): Promise<void>
1
const response = await this.sms_ovh.send(parameters);
19.4.4.2. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Sms_ovh, SmsMessage } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private sms_ovh: Sms_ovh (2)
  ) {}
  async doStuff(parameters: SmsMessage) {
    const response = await this.sms_ovh.send(parameters); (3)
    return response;
  }
}
1 Import Sms_ovh from platform
2 Declare injected service
3 Call injected service

19.5. Utilities Management

19.5.1. Cron

User API for the Scheduler

User endpoints for scheduling : users can schedule, list and delete tasks. Tasks are stored on a per-user basis: a task will run with the priviledges of the user who stored it. Tasks are run on the server and thus can call api verbs marked as server-only.

19.5.1.1. schedule

Schedules a task for later execution. Tasks are executed asynchronously with the identity of the calling user. Tasks will be executed at a fixed moment in time in the future, or repeatedly, with minute precision. If a task already exists with the same cronName (a cronName is unique for a given user), this new task completely replaces it. A task can be scheduled with a cron-like syntax for repetitive or one-shot execution. Wildcards are not allowed for minutes and hours. When scheduling for one-shot execution, the time must be at least two minutes into the future.

schedule(parameters: CronTaskRequest): Promise<CronTaskRequest>
1
const response = await this.cron.schedule(parameters);
19.5.1.2. setTimeout

Schedules a task for later execution. Tasks are executed asynchronously with the identity of the calling user. Tasks will be executed with second precision in the near future (120 seconds delay max).

setTimeout(parameters: TimerRequest): Promise<TimerResult>
1
const response = await this.cron.setTimeout(parameters);
19.5.1.3. unschedule

Removes a previously scheduled task. Does absolutely nothing if asked to remove a non-existent task.

unschedule(parameters: CronTaskDeletion): Promise<CronTaskDeletion>
1
const response = await this.cron.unschedule(parameters);
19.5.1.4. list

Returns a paginated list of the asking user’s tasks.

list(parameters: CronTaskListRequest): Promise<CronPlanning>
1
const response = await this.cron.list(parameters);
19.5.1.5. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Cron, CronTaskRequest } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private cron: Cron (2)
  ) {}
  async doStuff(parameters: CronTaskRequest) {
    const response = await this.cron.schedule(parameters); (3)
    return response;
  }
}
1 Import Cron from platform
2 Declare injected service
3 Call injected service

19.5.2. Logs

Log API

User API for logging.

19.5.2.1. log

Adds some server generated data and stores the entry into the sink defined by configuration.

log(parameters: LogRequest): Promise<void>
1
const response = await this.logs.log(parameters);
19.5.2.2. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Logs, LogRequest } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private logs: Logs (2)
  ) {}
  async doStuff(parameters: LogRequest) {
    const response = await this.logs.log(parameters); (3)
    return response;
  }
}
1 Import Logs from platform
2 Declare injected service
3 Call injected service

19.5.3. Trigger

Trigger service

Register listeners and trigger events.

19.5.3.1. trigger

Triggers an event. All listeners previously registered for that event will be called, in no particular order.

trigger(parameters: EventTrigger): Promise<void>
1
const response = await this.trigger.trigger(parameters);
19.5.3.2. How to use it ?
worker/index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
import { Injectable } from '@zetapush/core';
import { Trigger, EventTrigger } from '@zetapush/platform-legacy'; (1)

@Injectable()
export default class Api {
  constructor(
    private trigger: Trigger (2)
  ) {}
  async doStuff(parameters: EventTrigger) {
    const response = await this.trigger.trigger(parameters); (3)
    return response;
  }
}
1 Import Trigger from platform
2 Declare injected service
3 Call injected service

20. Command Line Interface

20.1. Initialize an application

The command to initialize an application with the CLI is:

$ npm init @zetapush myApp (1)
1 myApp is the name of the generated directory

This command can take the following parameters:

  • --developer-login

This login is the email used by the developer when logging in to the ZetaPush console. It does not concern the applications developed by the developer. It is only used to identify the developer account.

  • --developer-password

Like the property --developer-login, this password is only used for the ZetaPush developer account. It does not concern the applications developed by the developer.

  • --app-name

A developer can develop many applications. Hence the need to identify each of them. The appName property is the unique name of an application on a ZetaPush developer account.

  • --platform-url

By default, the developer uses the production environment of ZetaPush to develop and deploy its applications. In most cases, the developer doesn’t need to set this property. This property if useful when another (on premise, or dedicated) ZetaPush platform is to be used.

  • --env-name

An application created by a developer can have many environments. The default environment is prod but you can create your own (dev, preprod, …​). An environment is one stage in the development of the application.

  • --javascript

This option allow developer to bootstrap project with a pure JavaScript stack. Default strategy is TypeScript.

20.1.1. Create a new project and/or account

20.1.1.1. Initialization workflows

With or without account

Don’t have ZetaPush account

init without account
Figure 7. I want to create an account

➊ You launch npm init @zetapush myApp without parameters
➋ You type your email and a password to create your ZetaPush account
➌ The application is created in the myApp folder
➍ The .zetarc file looks like:

1
2
3
4
5
{
    "developerLogin": "user@gmail.com",
    "developerPassword": "password",
    "appName": "nameOfAppAutoGenerated"
}
You need to confirm your ZetaPush account by clicking in the link in the email to run or deploy your application.

Have an account and an app

init with account and app
Figure 8. I want to use an existing application

➊ I launch npm init @zetapush myApp with the --developer-login, --developer-password and --appName parameters
➋ The application is created in the myApp folder
➌ The .zetarc file looks like:

1
2
3
4
5
{
    "developerLogin": "user@gmail.com",
    "developerPassword": "password",
    "appName": "nameOfAppAutoGenerated"
}

Have an account and want new app

init with account without app
Figure 9. I want to create a new application

➊ I launch npm init @zetapush myApp with the --developer-login and --developer-password parameters
➋ The application is created in the myApp folder
➌ The .zetarc file looks like:

1
2
3
4
5
{
    "developerLogin": "user@gmail.com",
    "developerPassword": "password",
    "appName": ""
}
If the appName property in the .zetarc is empty or missing, ZetaPush deploys or executes the code in a new application.

-

20.1.1.2. Create a new account and a new application
Generate application
$ npm init @zetapush hello-world (1)
1 hello-world is the name of the folder that will be created with all the generated files

You will be prompted for a developer login and a developer password in order to create a new account.

The developer login and the developer password will be stored in the .zetarc file. By default, the .gitignore file is configured to not deploy this file.

Using npm lower than 6

npm provides npm init command since version 6.

You can either upgrade your npm version or use npx utility.

npm 5-

Upgrade npm

➊ - Upgrade npm
$ npm install -g npm@latest
➋ - Use npm init
$ npm init @zetapush hello-world

Use npx to launch the script

Launch with npx
$ npx @zetapush/create hello-world

-

20.1.1.3. Use existing account and application
Generate application
$ npm init @zetapush hello-world (1)
           --developer-login <your email address> (2)
           --app-name <your application name> (3)
1 hello-world is the name of the folder that will be created with all the generated files
2 <your email address> is the email you used when you registered on ZetaPush
3 <your application name> is the application name registered on ZetaPush

You will be prompted for a password in order to log in to ZetaPush.

Using npm lower than 6

npm provides npm init command since version 6.

You can either upgrade your npm version or use npx utility.

npm 5-

Upgrade npm

➊ - Upgrade npm
$ npm install -g npm@latest
➋ - Use npm init
$ npm init @zetapush hello-world

Use npx to launch the script

Launch with npx
$ npx @zetapush/create hello-world

-

20.1.1.4. Add an application to my account
Generate application
$ npm init @zetapush hello-world (1)
           --developer-login <your email address> (2)
1 hello-world is the name of the folder that will be created with all the generated files
2 <your email address> is the email you used when you registered on ZetaPush

You will be prompted for a password in order to log in to ZetaPush.

Using npm lower than 6

npm provides npm init command since version 6.

You can either upgrade your npm version or use npx utility.

npm 5-

Upgrade npm

➊ - Upgrade npm
$ npm install -g npm@latest
➋ - Use npm init
$ npm init @zetapush hello-world

Use npx to launch the script

Launch with npx
$ npx @zetapush/create hello-world

-

20.2. Run project locally

20.2.1. Run front and custom cloud services

Start application (front and custom cloud services)
$ npm run start -- --serve-front

npm run start is a script alias defined in the package.json file. The command that is executed under the hood is:

$ zeta run --serve-front

20.2.2. Run only custom cloud services

Start custom cloud services locally
$ npm run start

npm run start is a script alias defined in the package.json file. The command that is executed under the hood is:

$ zeta run

20.3. Deploy project on the ZetaPush Cloud

20.3.1. Deploy front and custom cloud services

Deploy application (front and custom cloud services)
$ npm run deploy

npm run deploy is a script alias defined in the package.json file. The command that is executed under the hood is:

$ zeta push

20.3.2. Deploy only custom cloud services

Deploy the worker
$ npm run deploy -- --worker

npm run deploy is a script alias defined in the package.json file. The command that is executed under the hood is:

$ zeta push --worker

20.3.3. Deploy only front

Deploy the worker
$ npm run deploy -- --front

npm run deploy is a script alias defined in the package.json file. The command that is executed under the hood is:

$ zeta push --front

21. Configuration

ZetaPush provides many variables to configure your applications. There are 2 types: the account configuration variables and the application configuration variables.

21.1. Account configuration

To use ZetaPush Celtia, you need to have an account and an optional application. You specify this properties in the .zetarc file. Here is the list of them:

Table 4. Account variables
Name of the property Definition environment variable Name in the .zetarc CLI parameter

Developer login

This login is the email used by the developer when logging in to the ZetaPush console. It does not concern the applications developed by the developer. It is only used to identify the developer account.

ZP_DEVELOPER_LOGIN

developerLogin

--developer-login <login>

Developer password

Like the property --developer-login, this password is only used for the ZetaPush developer account. It does not concern the applications developed by the developer.

ZP_DEVELOPER_PASSWORD

developerLogin

--developer-password <password>

Application name

A developer can develop many applications. Hence the need to identify each of them. The appName property is the unique name of an application on a ZetaPush developer account.

ZP_APP_NAME

appName

--app-name <name>

Environment name

An application created by a developer can have many environments. The default environment is prod but you can create your own (dev, preprod, …​). An environment is one stage in the development of the application.

ZP_ENV_NAME

envName

--env-name <env>

Platform URL

By default, the developer uses the production environment of ZetaPush to develop and deploy its applications. In most cases, the developer doesn’t need to set this property. This property if useful when another (on premise, or dedicated) ZetaPush platform is to be used.

ZP_PLATFORM_URL

platformUrl

--platform-url <platform>

21.2. Application configuration

You can configure your applications with several variables. Here is the list of them:

Table 5. Application variables
Name of the property Definition package.json CLI parameter Default value

Front code

In an application, you need to define where you put your front end part of your application. ZetaPush uses this property to host and expose it.

1
2
3
"zetapush": {
    "front": "./path/of/front"
}

--front <path>

./front/

Worker code

When you create your business logic in custom cloud services, ZetaPush need to know his location to deploy it.

1
2
3
"zetapush": {
    "worker": "./path/of/worker"
}

--worker <path>

./worker/

Worker entry point

To use your custom cloud services from the front part you need to export them. So the exportation of services need to be in only one file.

"main": "./path/of/entry"

None

./worker/index.ts

21.3. Configuration override

You can put many properties in several locations (environment variables, CLI…​). ZetaPush includes and overrides this properties in a specific order:

21.3.1. Account properties

override account properties

So if you use the same property in several locations, the environment variable is overwritten by the .zetarc value and this last value is overwritten by the CLI parameter.

21.3.2. Application properties

override application properties

So if you use the same property in several locations, the default value is overwritten by the package.json value and this last value is overwritten by the CLI parameter.

21.4. User Management

Unresolved directive in reference.adoc - include::/var/lib/jenkins/workspace/Github_documentation_master-IOSGDW42Y6L7PFABZDVKWIMQ7U5ZFS2WPFP2G4YQ6QQOVPTQ7Y4A/src/docs/asciidoc/common/cloud-services/user-management.adoc[leveloffset=+2]