> ##### Genserve is a server generator to help manage non-blocking servers.
>
> ######  _You can control spawned servers via command lines or within your code._
> 
> ######  _It can be used with a CI system, in a development environment, in production, etc._

<br/>

---

<br/>

<!-- TOC -->
  * [1. Installation](#1-installation)
    * [Windows](#windows)
    * [Linux](#linux)
  * [2. Usage](#2-usage)
    * [In a Terminal](#in-a-terminal)
    * [In a script](#in-a-script)
      * [For CommonJs](#for-commonjs)
      * [For ESM](#for-esm)
  * [3. Notes](#3-notes)
  * [4. Quick start](#4-quick-start)
    * [Start a server](#start-a-server)
    * [Display the server status](#display-the-server-status)
    * [Restart the server using port 5000 and serving a different directory](#restart-the-server-using-port-5000-and-serving-a-different-directory)
    * [Stop the server](#stop-the-server)
    * [Stop all registered servers](#stop-all-registered-servers)
  * [5. Overview](#5-overview)
          * [Launch a server in the background and run some tests (using that server) in the same terminal](#launch-a-server-in-the-background-and-run-some-tests-using-that-server-in-the-same-terminal)
  * [6. Commands](#6-commands)
    * [backup](#backup)
    * [build](#build)
          * [sophia.default.json](#sophiadefaultjson)
    * [clone](#clone)
          * [Example](#example)
    * [create](#create)
          * [Example](#example-1)
    * [delete](#delete)
    * [deploy](#deploy)
    * [description](#description)
    * [edit](#edit)
          * [To edit server settings](#to-edit-server-settings)
    * [enable](#enable)
          * [Example](#example-2)
      * [Activatable Options](#activatable-options)
    * [erase](#erase)
    * [exec](#exec)
    * [flush](#flush)
    * [get](#get)
    * [info](#info)
    * [investigate](#investigate)
    * [list](#list)
    * [load](#load)
    * [lock](#lock)
    * [log](#log)
    * [pack](#pack)
          * [Create](#create-)
    * [path](#path)
          * [Show path to a server settings file:](#show-path-to-a-server-settings-file)
    * [ping](#ping)
    * [project](#project)
          * [Example](#example-3)
    * [protect](#protect)
    * [pull](#pull)
    * [push](#push)
    * [remove](#remove)
    * [rename](#rename)
    * [reset](#reset)
    * [restart](#restart)
    * [restore](#restore)
    * [save](#save)
    * [scan](#scan)
      * [examples](#examples)
    * [search](#search)
      * [examples](#examples-1)
    * [set](#set)
    * [show](#show)
    * [Shutdown](#shutdown)
    * [start](#start)
          * [Example](#example-4)
      * [Start from a config file](#start-from-a-config-file)
          * [Example](#example-5)
          * [Now, you can always use this file to start your server, which should also ease sharing server configurations.](#now-you-can-always-use-this-file-to-start-your-server-which-should-also-ease-sharing-server-configurations)
    * [status](#status-)
    * [stop](#stop)
    * [unlock](#unlock-)
    * [unpack](#unpack-)
  * [7. Namespaces](#7-namespaces)
    * [namespace](#namespace)
        * [To select a namespace by defining a namespace by default:](#to-select-a-namespace-by-defining-a-namespace-by-default)
        * [To select a namespace with the  --namespace option](#to-select-a-namespace-with-the---namespace-option)
        * [To select a namespace using the canonical form](#to-select-a-namespace-using-the-canonical-form)
      * [GENSERVE_NAMESPACE environment variable](#genserve_namespace-environment-variable)
  * [8. Batch Operations](#8-batch-operations)
      * [Examples](#examples-2)
  * [9. Selected/Selecting](#9-selectedselecting)
  * [10. Options](#10-options)
    * [Options modifiable via CLI](#options-modifiable-via-cli)
      * [--cert](#--cert)
      * [--key](#--key)
      * [--openApp](#--openapp)
      * [--clean](#--clean)
      * [--platform](#--platform)
      * [--section](#--section)
      * [--ssl](#--ssl)
      * [Enable CORS](#enable-cors)
    * [Global Options modifiable Via Configuration file](#global-options-modifiable-via-configuration-file)
      * [Some options](#some-options)
        * [dynamicDirs](#dynamicdirs)
        * [rewriter](#rewriter)
        * [contentRewriter](#contentrewriter)
  * [11. Examples](#11-examples)
    * [Start server serving multiple directories](#start-server-serving-multiple-directories)
    * [Stop default server](#stop-default-server)
    * [Start a named server on port 10040 serving the working directory](#start-a-named-server-on-port-10040-serving-the-working-directory)
    * [Stop the named server](#stop-the-named-server)
    * [Show list of registered servers](#show-list-of-registered-servers)
    * [Run server from a shell or in a CI system](#run-server-from-a-shell-or-in-a-ci-system)
    * [Run a server from within a script](#run-a-server-from-within-a-script)
  * [12. How to](#12-how-to)
  * [13. Stats Plugins](#13-stats-plugins)
  * [14. Performance](#14-performance)
          * [Performance Tests](#performance-tests-)
  * [15. Stability](#15-stability)
          * [Stability Tests](#stability-tests-)
  * [Changelog](#changelog)
        * [current:](#current)
        * [5.8.1:](#581)
        * [5.8.0:](#580)
        * [5.7.2:](#572)
        * [5.7.0:](#570)
        * [5.6.0:](#560)
        * [5.5.0:](#550)
        * [5.4.7:](#547)
        * [5.4.6:](#546)
        * [5.4.5:](#545)
        * [5.4.4:](#544)
        * [5.4.3:](#543)
        * [5.4.2:](#542)
        * [5.4.1:](#541)
        * [5.4.0:](#540)
        * [5.3.2:](#532)
        * [5.3.1:](#531)
        * [5.3.0:](#530)
        * [5.2.0:](#520)
        * [5.1.0:](#510)
        * [5.0.0:](#500)
<!-- TOC -->

---

## 1. Installation

```shell
npm install genserve -g
```

### Windows

No extra configuration required


### Linux

In the module, servers created with ```sudo``` and the standard user do not share the same directory.

Consequentially, ```genserve scan``` and ```sudo genserve scan``` may not give the same result.

To make both users use the same data directory, you can define the property GENSERVE_DATA to a shared location.
```shell
# Find the directory used by the default user
$> genserve show location main          # => /home/<user>/.local/shared

# Assign it to root
$> sudo genserve define GENSERVE_DATA "/home/<user>/.local/shared"
```

> ** You may need to review the permissions set on the shared folder (```chmod```)

<br/>

---

> It is also possible to set a value to GENSERVE_DATA as an environment variable
> 
> For instance:
> 
> ```shell
> # Define the environment variable GENSERVE_DATA
> $> export GENSERVE_DATA="/home/user/data"
> ```


<br/>


---

## 2. Usage

### In a Terminal

```shell
$> genserve [command] [target] [--port number] [--dir path]
```

<br/>

### In a script

#### For CommonJs

```javascript
// CommonJs
const {startGenServer, stopGenServer, infoGenServer} = require("genserve");

await startGenServer({...});                    // Start a server
await stopGenServer({...});                     // Stop a server
const json = await infoGenServer({...});        // Get server info in a JSON formatted string

```

<br/>

#### For ESM

```javascript
// ESM
import {startGenServer, stopGenServer, infoGenServer} from "genserve";

await startGenServer({...});
await stopGenServer({...});
const json = await infoGenServer({...})
```

<br/>

---

## 3. Notes

* **v5** is downward compatible with **v4**
* **v4** is downward compatible with **v3**
* **v3** is not downward compatible
* **v3** up to **3.7.0** is not production ready
* **v2** is not downward compatible and production-ready
* **v1** is not production ready and uses a different engine


> * **v5** offers greater stability and security
> * **v4** offers mitigated stability and security (after numerous testing)
> * **v3** offers poor stability and security
> * **v1** and **v2** should be used in development mode only
> * The module name may change
> * The latest code is only available in the npm package (MIT License) and is constantly tested for bugs and security 
    issues
> * Bug reports can still be posted at https://github.com/thimpat/genserve/issues


* **Many GenServe functionalities are still undocumented. Some updates soon.**

<br/>

---

## 4. Quick start


### Start a server

```shell
$> genserve start
```

<br/>

### Display the server status

```shell
$> genserve status            # The server [randomname] is up
```


<br/>

### Restart the server using port 5000 and serving a different directory

```shell
$> genserve restart --port 5000 --dir myfolder
```

<br/>

### Stop the server

```shell
$> genserve stop
```


<br/>

### Stop all registered servers

```shell
$> genserve shutdown
```


<br/>


---

## 5. Overview

###### Launch a server in the background and run some tests (using that server) in the same terminal

> * **Step 1: Spawn a non-blocking server**
> ```shell 
> $> genserve start server
> ```
> * **Step 2: Run tests (from the same terminal)**
> ```shell 
> $> npm test
> ```
> * **Step 3: Stop the server**
> ```shell 
> $> genserve stop server
> ```


![tests-from-shell.gif](https://github.com/thimpat/genserve/blob/main/tests-from-shell.gif)

<br/>

---


## 6. Commands

> In the descriptions below,
> **\<servername\>** is a placeholder.

> **NOTE:** Server names and namespaces should be lowercase with no dot symbols



---


### backup

Save namespace

```shell
# Save namespace to ./out/ns1.zip
$> genserve backup ns1 ./out
```

<br/>

---


### build

Build a set of commands

###### sophia.default.json
```javascript
{
    ...
    "build": [
        "node ./node_modules/stylus/bin/stylus -m ./stylus --out ./css",
        "node ./node_modules/sass/sass.js ./scss:./css"
    ]
    ...
}
```

```shell
// Will generate a build based on the build field content
$> genserve build config ./sophia.default.json 
```

If the server is already created, ```genserve build sophia``` is enough

```shell
```shell
$> genserve build sophia 
```

<br/>

---


### clone

Clone a server

```shell
$> genserve clone servername <servertarget>
```

###### Example

```shell
$> genserver clone genesis1 genesis2  
```

<br/>

---

### create

Create a server without starting it

```shell
$> genserve create <servername>
```

or

```shell
# Create a server from a configuration file
$> genserve create config <filepath>
```


<br/>

###### Example

```shell
# Create a server with property port = 3001
$> genserver create genesis1 --port 3001  

# Start server on port 3001
$> genserver start genesis1  

# Stop server
$> genserver stop genesis1
```

<br/>

---

### delete

Alias of the ```remove``` command

```shell
$> genserve delete <servername>
```

<br/>

---

### deploy

Unpack a server archive and start a server against the deployed folder

```shell
$> genserve deploy mypacked.zip ./target
```

<br/>

---


### description

Show a server description

```shell
$> genserve description <servername>
```

<br/>

To set a description, you can use the ```set``` command

```shell
$> genserve set genesis --description "PNG server"
```

<br/>

---


### edit

Edit session file in the O.S. default editor

###### To edit server settings

```shell
$> genserve edit server <servername> 
```

<br/>

examples:

```shell
$> genserve edit server genesis             # Edit settings against the registered server
$> genserve edit settings genesis           # Same as above
$> genserve edit genesis                    # Same as above
```

<br/>

To edit global settings, omit the server name

```shell
$> genserve edit settings                     # Edit global settings
$> genserve edit logs                         # Edit global logs
```


---


### enable

Enable a property on a server

> 🚫 Note: Users must stop the server before being able to change properties.

```shell
$> genserve enable <servername> propertyname 
```

###### Example

```shell
$> genserve enable genesis cors
```

<br/>

#### Activatable Options


| **Options** | **default** | **Expect** | **Description**                          | 
|-------------|-------------|------------|------------------------------------------|
| cors        | false       | boolean    | _Enable CORS on selected server_         |
| ssl         | false       | boolean    | _Enable SSL on selected server_          |
| explore     | true        | boolean    | _Enable listing mode on selected server_ |

<br/>

> NOTE: There are two ways to enable/disable one of these options
>
> Via enable/disable commands
> ```shell
> $> genserve <enable|disable> <servername> [options]
> 
> # example
> $> genserve disable genesis explore
> ```
>
> 2- Via flags
> ```shell
> $> genserve <commands> <servername> <--options on|off> 
> 
> # example
> $> genserve start genesis --explore off
> ```
>

<br/>

Explorer view example:

![tests-from-shell.gif](https://github.com/thimpat/demos/blob/main/genserve/images/explore-view.png)

<br/>

---

### erase

Remove namespace reference.

> You must stop all servers on this namespace; otherwise, the command will fail.

```shell
$> genserve erase ns1
```

<br/>

---



### exec

Execute the given script file

**Example**

```shell
$> genserve exec /path/to/my-script.genserve
```

_Content example_

> `# Comments start with a hash.`
>
> `start my-server-1`
>
> `scan`
>
> `list`
>
> `stop my-server-1`
>
>

The command exec will execute every line from "my-script.genserve" except for the first line (comment).

<br/>

---

### flush

Remove all registered servers (must be stopped and unprotected).

```shell
$> genserve flush
```

<br/>

---


### get

Display server property (Use ```$> genserve info``` command to also have the server instance).

> 🚫 Note: Users must stop the server before being able to change properties.

```shell
$> genserve get tom
```
<br/>

---


### info

Display server information

```shell
$> genserve info genesis
```


 💻↴

```shell
              serverName: genesis
             defaultPage: index.html
                protocol: http://
                    host: localhost
                    port: 57485
               enableapi: true
                 timeout: 12000
               namespace: default
       perMessageDeflate: false
            showRequests: no
   exitWithParentLatency: 30000
       noActivityTimeout: 0
        strictServerPort: yes
                     ssl: off
         allowSelfSigned: no
              enablecors: off
           enableexplore: on
             monitorDirs:
             dynamicExts: .server.[cm]?js
                    runs: 1
                   fails: 0
          serverFullName: genesis.default
                  active: false
```

<br/>



---

### investigate

Display various information (port related)

```shell
$> genserve investigate port 16033
```


 💻↴

```shell
 [17:55:37]     CLIENT: (4308) ▶  Server using port 16033:
 [17:55:37]     CLIENT: (4212) ▶  [server1.genserve-e2e-terminal] is not running, but set to port 16033
 [17:55:37]     CLIENT: (4312) ✨  [server2.genserve-e2e-terminal] is currently using the port 16033
```

<br/>



---

### list

Show list(s) of created named servers.

```shell
$> genserve list [all]
```

> The option "all" will do the listing on all declared namespaces.

<br/>

---


### load

Load a server configuration from a file then restart the targeted server.

```shell
# Load server configuration using a filename
# The file must be located in the current directory. Format: <servername>.<activeNamespace>.json
$> genserve load testfile         # => ./testfile.default.json
```

or

```shell
# Load server configuration from a file path
$> genserve load ./some/path/testfile.default.json

# or

$> genserve load config ./some/path/testfile.default.json
```

<br/>

---



### lock

Prevent a server from being stopped.
The commands `stop [all], start [all], restart [all], set [all] `will have no effect on this
server.

```shell
$> genserve lock <servername>
```

or

```shell
$> genserve start <servername> --lock
```

<br/>

---




### log

Display log for a server. If you set the --open option, genserve will try to open the log in an editor.

```shell
$> genserve log <servername> [--open]
```

<br/>

---


### pack

###### Create 

Create an archive containing all of the files the server uses in its configuration (staticDirs, dynamicDirs, etc.)
This command is useful when you want to run a server in isolation (During a deployment for instance)

```shell
$> genserve pack
```

<br/>

---

### path

###### Show path to a server settings file:

```shell
$> genserve path settings <servername>
```

<br/>

---


### ping

Tell whether the server API is active

```shell
$> genserve ping <servername>
```

<br/>

---


### project

To generate a GenServe project in the current working directory.

```shell
$> genserve project <projectname>
```

###### Example

```shell
$> genserver project myproj  
```


The generated project will follow this structure:

```
📁 projectname                 
│
└───📁 build                      ⇽ A build directory that triggers auto-reload on changes
│
└───📁 dynamic                    ⇽ Directory to hold dynamic pages
│           📝 index.server.cjs   ⇽ A dynamic page example
│           
└───📁 stats               
│                                 ⇽ The statistic plugin installed by default (in a subfolder)
│
└───📁 static                     ⇽ Directory for static pages
│          📝 index.html          ⇽ A static page example   
│   
└───📁 src                        ⇽ Source directory (not used by the system)
│
└───📁 start
           📝 start.js**          ⇽ Every time the server starts or restarts, it will launch this script.  

```

> ##### ** To disable loading plugins, pass an empty array to the "plugins" property in the server configuration.
>
> ---
>
> ##### ** To disable the launching script (start.js), override the "dynStart" property in the server configuration.


---

### protect

Prevent a server from being removed from the registered server list.
The commands `flush, remove [all]` will not affect this server.

```shell
$> genserve protect <servername>
```

or

```shell
$> genserve start <servername> --protect
```

<br/>

---

### pull

Write server info into a file. The filename depends on the server name.

```shell
// Create the config file [tom.default.info.json] 
$> genserve get tom
```

<br/>

---

### push

Update server properties with the one written in the pulled one.

```shell
// Will update the tom server with the content from [tom.default.info.json] 
// You must pull the server config, edit the file, and then push it.
$> genserve push tom 
```

<br/>

---

### remove

Remove a server from the registered server list.

```shell
$> genserve remove <servername>
```

<br/>

---


### rename

Rename a server

```shell
$> genserve rename servername <servertarget>
```

<br/>

---

### reset

Reset application default values to factory values

```shell
$> genserve reset
```

<br/>

---

### restart

Restart a server

```shell
$> genserve restart <servername>
```

---

### restore

Restore namespace

```shell
# Restore namespace from a folder or a file
$> genserve restore ./out/ns1.zip
```

<br/>

---



### save

Save server configuration

```shell
# Save server configuration into a ./testfile.json file
$> genserve save testfile
```

<br/>

---


### scan

Show a list of servers along with which ones are running.

```shell
$> genserve scan [all]
```

> The option [all] will scan all declared namespaces.

<br/>


#### examples

```shell
# Scan the default namespace
$> genserve scan
```

```shell
# Scan a namespace called "special"
$> genserve scan special
```


---



### search

Returns server names with given properties.

```shell
$> genserve search <props>
```

<br/>


#### examples

```shell
# Look for a server whose port equals 16042 in all namespaces
$> genserve search port:16042
```

💻↴

```shell
 [19:04:29]     CLIENT: (4412)   Found [server1.genserve-e2e-terminal]
 [19:04:29]     CLIENT: (4412)   Found [server2.genserve-e2e-terminal]
```

---


### set

Modify server property if not locked.

> 🚫 Note: If the server is running, it will be stopped and then restarted right after the modifications

```shell
$> genserve set tom --port 6000 --dir public 
```

<br/>

---


### show

Display various pieces of information

```shell
# Show all running servers
$> genserve show up
```

```shell
# Show all inactive servers
$> genserve show down
```

```shell
# Show all servers
$> genserve show servers
```

```shell
# Display namespace list
$> genserve show namespaces
```

```shell
# Show active namespace
$> genserve show active namespace
```

```shell
# Show running servers
$> genserve show active servers
```

```shell
# Show default namespace
$> genserve show default namespace
```

```shell
# Show default server for a directory
$> genserve show default server
```

```shell
# Show application data directory
$> genserve show location data
```

```shell
# Show namespaces location
$> genserve show location namespaces
```

```shell
# Show namespace location for "default" namespace 
$> genserve show location namespace default
```

```shell
# Show server setting location for "genesis"  
$> genserve show location server genesis
```

```shell
# Show the server name that will be used against the current directory
# if a command is started with no option 
options
$> genserve show linked server        # i.e. genesis => [genserve start] will launch the "genesis" server
```

```shell
# Show all servers which project root is set to the current directory
$> genserve show linked servers
```


<br/>


---



### Shutdown

Stop all non-locked servers from all namespaces.

```shell
$> genserve shutdown [now]
```


> Use ```$> genserve shutdown now``` to perform the action
> immediately.

<br/>

---



### start

Start a server named `<servername>` on any available port serving the current directory.

When servername is missing, it uses "default" as a name or generates a random name depending on the configuration.

```shell
$> genserve start <servername>
```

###### Example

```shell
# Will generate a server running against the current directory 
$> genserve start
```

```shell
# Will generate a server named genesis
$> genserve start genesis
```

```shell
# Will generate a server from a config file
$> genserve start config ./some/path/genesis.default.json
```

<br/>



#### Start from a config file

You can also start the server from a configuration file after its creation.

###### Example

```shell
# Create a server called genesis 
$> genserve create genesis

# Pull the configuration to the current directory =>  /current-location/genesis.default.json
# You can edit the file (genesis.default.json) to apply your settings.
$> genserve pull genesis

# Start the server from the pulled configuration file
$> genserve start --config ./genesis.default.json
```

###### Now, you can always use this file to start your server, which should also ease sharing server configurations.

By default, when a server configuration file is named ".genserverc", 
you won't need to specify a value for the --config option

```shell
$> genserve start --config

# Same as
$> genserve start --config .genserverc
```

<br/>

---

### status 

Display a server status

```shell
$> genserve status genesis
```

<br/>

---

### stop

Stop a server

```shell
$> genserve stop <servername>
```

<br/>

---

### unlock 

Unlock a locked server.

```shell
$> genserve unlock genesis
```

<br/>


---


### unpack 

Unpack a previously packed archive

```shell
$> genserve unpack mypacked.zip ./target/folder
```

<br/>


---


## 7. Namespaces

<br/>

> All servers are created in the **"default"** namespace.
> It is, however, possible to add more than one namespace.


<br/>

### namespace

<br/>

##### To select a namespace by defining a namespace by default:

```shell
# The namespace "ns1" will be the default for all GenServe commands
$> genserve namespace ns1
```

<br/>


##### To select a namespace with the  --namespace option

```shell
# It will override the default namespace
$> genserve start myserver --namespace ns2
```

<br/>

##### To select a namespace using the canonical form

```shell
# Examples:
$> genserve start myserver.ns2      # server = myserver / namespace = ns2    
$> genserve stop myserver.ns2
$> genserve info myserver.ns2
$> genserve remove myserver.ns2
$> genserve enable myserver.ns2 cors
$> genserve disable myserver.ns2 ssl
```

<br/>

#### GENSERVE_NAMESPACE environment variable

You can also define the environment variable GENSERVE_NAMESPACE with the namespace value you want,
and it will be used by all commands.

<br/>

* **On Windows Powershell:**
```powershell
PS C:\path> $env:GENSERVE_NAMESPACE = "ns3"
PS C:\path> genserve start myserver
```
<br/>

* **On Linux & MAC:**

```shell
$> export GENSERVE_NAMESPACE = "ns3"
$> genserve start myserver
```

<br/>

* **On Windows CMD:**
```shell
$> set GENSERVE_NAMESPACE=ns3
$> genserve start myserver
```

<br/>

>Refer to your O.S. for more advanced options for setting up environment variables.


<br/>


---



## 8. Batch Operations


> ##### The option "all" allows targeting all elements in a namespace

<br/>


#### Examples


```shell
# Start all registered and unlocked servers.
$> genserve start all

# Restart all registered and unlocked servers
$> genserve restart all

# Stop all running and unlocked servers.
$> genserve stop all

# Remove all registered and unprotected servers.
$> genserve remove all

# Display all registered servers' statuses.
$> genserve status all

# Lock all registered servers.
$> genserve lock all

# Unlock all registered servers.
$> genserve unlock all

### etc.
```

<br/>

---

## 9. Selected/Selecting

<br/>

> ##### The options "selected" or "selecting" allow targeting elements defined by a regular expression

All the commands supporting the "all" extension also support the "selected" extension.


```sh
# GenServe will start all servers whose names start with "myserver"
$> genserve start selected "^myserver.*"

or

$> genserve start selecting "^myserver.*"
```



However, the "create" and "project" command requires the use of the option --namespace
```shell
# Invalid:
$> genserve create myserver.ns2

# Valid
$> genserve create myserver --namespace ns2
```

<br/>


---


## 10. Options



### Options modifiable via CLI

> The options can be set with the ```set``` command. They can also be defined with ```start```, ```restart```, ```stop```  
> commands.

| **Options**         | **default** | **Expect**                      | **Description**                                                                                      | 
|---------------------|-------------|---------------------------------|------------------------------------------------------------------------------------------------------|
| --blockmode         | false       | boolean                         | _Run the server without quitting (start and restart commands). <br/> The server stops with CTRL + C_ |
| --build             | false       | boolean                         | _Execute build before starting a server_                                                             |
| --cert              | ""          | string                          | _Path to ssl cert file_                                                                              |           
| --clean             | false       | boolean                         | _Also delete the log file when a server or a <br/>namespace is erased/deleted_                       |       
| --defaultPage       | index.html  | string                          | _Default page to serve_                                                                              |
| --dir               | .           | string[]                        | _Directories to serve_                                                                               |
| --dynStart          | ""          | string                          | _Run some JavaScript files before the <br/>server starts <br/> in the same process as the server_    |
| --force             | false       | boolean                         | _Force the execution of a command even if one or more servers run_                                   |       
| --help              | false       | boolean                         | _Display help_                                                                                       |
| --key               | ""          | string                          | _Path to ssl key file_                                                                               |           
| --mode              | ""          | "production", "development"     | _Server mode_                      <br/> <br/>                                                       |           
| --noActivityTimeout | 0           | number                          | _Stop server if no activity is detected after x milliseconds <br/>(0 for infinity)_                  |           
| --openPage          | ""          | string                          | _Open the given page in a browser when the server starts_                                            |           
| --openApp           | ""          | string[]                        | _Run passed processes or JavaScript files before the server start_                                   |           
| --platform          | "default"   | "darwin", "linux", "win32", ... | _Tell GenServe what platform the host is to load its configuration_                                  |           
| --port              | random      | integer                         | _Port to run the server on_                                                                          |
| --projectroot       | ""          | string                          | _Project root directory_                                                                             |           
| --protocol          | http://     | string                          | _Protocol used by server_                                                                            |
| --silent            | false       | boolean                         | _Whether to display messages_                                                                        |           
| --ssl               | off         | on/off                          | _Enable https_                                                                                       |           
| --unprocessed       | ""          | string                          | _URI to a static or a dynamic page to handle missing and unprocessable requests_                     |           
| --version           | false       | boolean                         | _Display version_                                                                                    |
| ~~--remoteapi~~     | ~~false~~   | ~~boolean~~                     | _~~Enable remote server API~~_                                                                       |           
| --~~apiport~~       | ~~random~~  | ~~integer~~                     | _~~Port to control server~~_                                                                         |              



<br/>

#### --cert

Pass to a server ssl certificate

```shell
$> genserve --cert path
```

<br/>

---

#### --key

Pass to a server private key

```shell
$> genserve --key path
```

<br/>

---

#### --openApp

This option allows invoking processes before the server starts

```shell
$> genserve start [--openApp <myBinary>] [--openApp <myBinary>] ...
```

<br/>

example:

```shell
# Open http://localhost:12000 in Chrome (Canary) with the Chrome flag --no-sandbox enabled 
$> genserve start --openApp "'C:/Users/<me>/AppData/Local/Google/Chrome SxS/Application/chrome.exe' 'http://localhost:12000' --ignore-certificate-errors""
```

<br/>

---

#### --clean

This option allows deleting all created log files for a server or namespace when destroyed

```shell
# Delete server and logs
$> genserve remove genesis4 --clean

# Delete all servers in mynamespace + logs
$> genserve erase mynamespace --clean
```

<br/>

---

#### --platform

This option allows loading some configurations depending on the platform they are running on.
It is helpful to make differences between paths, for instance (Win32, Linux, Mac).

```json
{
    "staticDirs": ["/home/user/mydir"],
    "platforms": {
        "linux": {
            "staticDirs": ["/home/user/mydir1", "/home/user/mydir2"]
        },
        "darwin": {
            "staticDirs": ["/home/user/mydir1", "/home/user/mydir2"]
        },
        "win32": {
            "staticDirs": ["C:/projs/mydir1", "C:/projs/mydir2"]
        },
        "custom": {
            "staticDirs": ["./anywhere"]
        },
        "default": {
            "staticDirs": ["/home/user/mydir"]
        }
    }
}
```

<br/>

In this example, the "linux" section will override the default configuration.

```shell
$> genserve start server1 --platform linux  
```

If platform is not specified, the system detect which platform it is running on and load the appropriate section if 
defined.

<br/>


---

#### --section

This option allows loading some custom configurations depending on the value set to --section

```json
{
    "sections": {
        "localth1": {
            "port": 10230,
            "staticDirs": ["/home/user/mydir1", "/home/user/mydir2"]
        },
        "localth2": {
            "port": 10232,
            "staticDirs": ["/home/user/mydir3", "/home/user/mydir3"]
        }
    }
}
```

<br/>

In this example, the "localth1" section will override the default configuration.

```shell
$> genserve start server1 --section localth1  
```

<br/>

---

#### --ssl

* **Option 1**

Enable SSL via command line:

```shell
$> genserve --ssl --cert /path/to/cert --key /path/to/key
```

<br/>

Enable SSL via config file (See config section for more info)

* **Option 2**


Stop the server

```shell
# default is the namespace by default. You can ignore it if you never use the option.
$> genserve stop yourservername --namespace default     
```

Locate the configuration file


```shell
$> genserve path settings <servername> --namespace default        # => Then edit the given path 

### or

# If you have set a default editor in your O.S. 
$> genserve edit server <servername> --namespace default
```

Edit to update it 

```json
{
  "yourservername": {
    "serverName": "yourservername",
    "defaultPage": "index.html",
    "protocol": "https://",
    "host": "yourservername.live",
    "port": 443,
    "serverUrl": "https://yourservername.com/",
    "ssl": "on",
    "cert": "/path/to/certificates/ssl/yourservername.crt",
    "key": "/path/to/certificates/yourservername/ssl/yourservername.key",
    "ca": "/path/to/certificates/yourservername/ssl/yourservername.ca-bundle",
      ...
  }
}
```

Start the server

```shell
$> genserve start yourservername --namespace default     
```

<br/>

---

#### Enable CORS

To enable CORS:

```shell
$> genserve enable servername cors
```

To customise CORS, edit the server's file.

```shell
$> genserve edit server <servername>
```

<br/>


---

### Global Options modifiable Via Configuration file

To get the path to the file that holds default global settings:

```shell
$> genserve path settings --global
```

To edit

```shell
$> genserve edit settings --global
```

📝 _.genserve.cjs_ ↴

```javascript
module.exports = {
    "protocol": "http://",
    "host"    : "desktop-amd",
    API       : {
        "GREETINGS"    : "Hello!",
        "SERVER_STATUS": {
            "SERVER_STARTED" : "SERVER_STARTED",
            "SERVER_RUNNING" : "SERVER_RUNNING",
            "GET_SERVER_INFO": "GET_SERVER_INFO"
        }
    }
};
```

staticDirs: Directories to serve (The first directory specified has precedence over the other and so on)

<br/>

#### Some options

##### dynamicDirs

    This option allows setting a script that will be called on every request

```json
{
    "dynamicDirs": [
        "./dynamic"
    ]
}
```

```javascript
const onRequest = async (req, res, {loggable} = {}) =>
{
    try
    {
        if (req.method !== "POST")
        {
            return null;
        }

        await sendBackLoginResult(req, res);

        return null;
    }
    catch (e)
    {
        // Don't use console.log as the server is detached from the shell
        loggable.error({lid: 1000}, e.message);
    }

    return {
        content: {error: "Could not proceed"}, mime: "application/json"
    };
};

module.exports.onRequest = onRequest;

```

##### rewriter
```json
{
    "contentRewriter": "./web/html-content-rewriter.cjs"
}
```

```javascript
/**
 * Dynamically translates a URL (Called on every request)
 * When the user enter your-url/gb/index.html, the parser will not look into the gb directory, but into the en/
 * directory to solve index.html (./localdir/en/index.html).
 * The url will not be changed
 * @param pathname
 * @returns {string}
 */
// eslint-disable-next-line no-unused-vars
module.exports.liveRewrite = (pathname, {session, namespace, loggable} = {}) =>
{
    try
    {
        if (pathname === "/gb" || pathname.startsWith("/gb"))
        {
            // gb is what is entered in the url
            // en is the physical path where the target directory is hosted
            return pathname.replace("/gb", "/en");
        }

        if (pathname === "/fr" || pathname.startsWith("/fr/"))
        {
            // fr is what is entered in the url
            // en is the physical path where the target directory is hosted
            return pathname.replace("/fr", "/en");
        }

        if (pathname === "/es" || pathname.startsWith("/es/"))
        {
            // es is what is entered in the url
            // en is the physical path where the target directory is hosted
            return pathname.replace("/es", "/en");
        }
    }
    catch (e)
    {
        loggable.error({lid: 3815}, e.message);
    }

    return pathname;
};

/**
 * Returns a mapping of urls to rewrite (Called only once)
 * The map will be saved by the system
 * @param session
 * @param namespace
 * @returns {{ttt: string}} => your-url/ttt => localdir/index.html
 * @note The url will not change
 */
// eslint-disable-next-line no-unused-vars
module.exports.generateRewriteMap = ({session, namespace} = {}) =>
{
    return {
        "ttt": "index.html"
    };
};

```

##### contentRewriter

    This option allows setting a script that will be modifying the request content before sending back the response 
(modifying html file on the fly for instance)

```json
{
    "contentRewriter": "./web/html-content-rewriter.cjs"
}
```

```javascript
/**
 * Dynamically convert an asset content (Called on every request)
 * @param content
 * @param mime
 * @param session
 * @param namespace
 * @param loggable
 * @returns {string} The new HTML content 
 * If you return null, it means that you already sent the content via the res object
 */
module.exports.liveRewriteContent = (content, {req, res, parsedUri, mime, session, namespace, loggable} = {}) =>
{
    try
    {
        if (mime !== "text/html") {
            return content;
        }
        loggable.log(content);
    }
    catch (e)
    {
        loggable.error({lid: 3815}, e.message);
    }

    return content;
};
```


---

## 11. Examples

<br/>

### Start server serving multiple directories

```shell
$> genserve start --dir public --dir build
```

<br/>

### Stop default server

```shell
$> genserve stop
```

<br/>

### Start a named server on port 10040 serving the working directory

```shell
$> genserve start genesis --port 10040
```

<br/>

### Stop the named server

```shell
$> genserve stop genesis
```

<br/>

### Show list of registered servers

```shell
$> genserve scan
```

<br/>


💻↴

```
active │ serverName │ serverUrl                 │ port  │ staticDirs                         │ defaultPage  │
────── │ ────────── │ ───────────────────────── │ ───── │ ────────────────────────────────── │ ──────────── │
false  │ default    │ http://localhost:60287/   │ 60287 │ C:\projects\genserve\public        │ index.html   │
false  │ genesis    │ http://localhost:10040/   │ 10040 │ C:\projects\genserve               │ index.html   │
```

<br/>

It is possible only to show some columns with the option --columns.

```shell
# This command will only present the columns active, serverUrl, port and serverName
$> genserve scan --columns "serverUrl,port"
```

<br/>

> 🚫 Note: The column "serverName" is always displayed

<br/>
<br/>

---

### Run server from a shell or in a CI system

```shell
# Start the server in the background
$> genserve start testserver --dir . --port 5000

# Run your tests
$> npm test

# Stop the server
$> genserve stop testserver
```

<br/>

---

### Run a server from within a script

```javascript
(async function ()
{

    const {startGenServer, stopGenServer, infoGenServer} = require("genserve");

    // Server name
    const SERVER_NAME = "my-test-server";

    // Start the server, which name will be "my-test-server"
    const serverStarted = await startGenServer({name: SERVER_NAME, port: 9880});
    if (!serverStarted)
    {
        console.error("Failed to start server");
        return ;
    }

    // Display info server (Optional)
    const data = await infoGenServer({name: SERVER_NAME});
    console.log(data);

    // Stop the server "my-test-server"
    await stopGenServer({name: SERVER_NAME});

}())

```

<br/>

---

<br/>

## 12. How to


[https://genserve.net/help.html](https://genserve.net/help.html)

<br/>

---

## 13. Stats Plugins

Web-Analyst plugin is a plugin for Genserve:
https://www.npmjs.com/package/web-analyst

![Screenshot](https://github.com/thimpat/demos/blob/main/web-analyst/images/stats-plugin.png)


<br/>

---

## 14. Performance

**Node v16.17.0** | **O.S.: Windows 11** | **Processor: AMD**



###### Performance Tests 

Five round of short sessions + one longer session

```shell
# 5 rounds
$> loadtest -c 10 --rps 500 -t 10 http://127.0.0.1:xxxx/random.html
$> loadtest -c 10 --rps 500 -t 10 http://127.0.0.1:xxxx/random.html
$> loadtest -c 10 --rps 500 -t 10 http://127.0.0.1:xxxx/random.html
$> loadtest -c 10 --rps 500 -t 10 http://127.0.0.1:xxxx/random.html
$> loadtest -c 10 --rps 500 -t 10 http://127.0.0.1:xxxx/random.html

# 1 round
$> loadtest -c 10 --rps 1000 -t 20 http://127.0.0.1:xxxx/random.html
```

_Every engine uses its default configuration_

| Engine          | Version | RPS* | (5 rounds) Completed Requests in 10s | (1 round) Completed requests in 20s |
|-----------------|---------|------|--------------------------------------|-------------------------------------|
| **nginx**       | 1.22.0  | 468  | 4728 -  4721 - 4717 - 4804 - 4740    | 19571                               |
| **xampp**       | 14.0.0  | 395  | 4663 - 4704 - 4834 - 4747 - 4783     | 19527                               |
| **genserve**    | 4.0.6   | 470  | 4750 - 4723 - 4705 -  4711 - 4789    | **19583**                           |
| **http-server** | 14.0.0  | 468  | 4716 - 4712 - 4800 - 4804 - 4696     | 17940                               |


```
*  Requests per seconds
```

<br/>

---

## 15. Stability

**Node v16.17.0** | **O.S.: Windows 11** | **Processor: AMD**

###### Stability Tests 

Increasing number of requests per seconds

```shell
# Increasing requests per session
$> loadtest -c 20 --rps 2000 -t 20 http://127.0.0.1:xxxx/random.html
$> loadtest -c 50 --rps 5000 -t 20 http://127.0.0.1:xxxx/random.html
$> loadtest -c 100 --rps 10000 -t 20 http://127.0.0.1:xxxx/random.html
```

_Every engine uses its default configuration_

| Engine          | Version | Completed requests in 20s at 1000 RPS* | 2000 RPS           | 5000 RPS           | 10000 RPS          |
|-----------------|---------|----------------------------------------|--------------------|--------------------|--------------------|
| **nginx**       | 1.22.0  | 19571                                  | 38711              | **Errors** (1464)  | **Errors** (20385) |
| **xampp**       | 14.0.0  | 19527                                  | 38834              | 49226              | **Errors** (28076) |
| **genserve**    | 4.0.6   | 19583                                  | 38996              | 46223              | **Errors** (461)   |
| **http-server** | 14.0.0  | 17940                                  | **Errors** (19579) | **Errors** (19184) | **Errors** (18156) |


```
*  Requests per seconds
```

<br/>

---



## Changelog

##### current:
*  Apply --json option to shutdown command


##### 5.8.1:
*  Fix url incorrectly generated when missing forward slashes in urls


##### 5.8.0:
*  Fix commands not generating slug for server name
*  Check whether project root exists
*  Fix --json option not applied on errors
*  Add --blockmode option to non-cli commands
*  Add support to dir option for command run from code (non-cli)


##### 5.7.2:
*  Set project root programmatically


##### 5.7.0:
*  Fix scan all with enabled --json option
*  Enable --json option for scan command


##### 5.6.0:
*  Fix formatted output for --js option


##### 5.5.0:
*  Increase server starting speed
*  Fix server hanging when plugin code not following new convention
*  Add an extra special callback system to plugins


##### 5.4.7:
*  Add an error message in the [info] command


##### 5.4.6:
*  Fix validator not set on the correct static directory


##### 5.4.5:
*  Fix staticDirs populated with same values


##### 5.4.4:
*  Fix plugin not working with dependent servers
*  Fix full server name evaluation


##### 5.4.3:
*  Fix pack process for deployment


##### 5.4.2:
*  Fix plugin support on configuration multi-domains


##### 5.4.1:
*  Always pack on the [deploy] command even when all files on the remote are up-to-date
*  Fix SSH connection not close on remote file listing


##### 5.4.0:
*  Fix local deployment
*  Add an [index] command
*  Reduce generated pack file for deployment to a minimum size by comparing indexes
*  Fix validators not set correctly


##### 5.3.2:
*  Display a message instead of an error when a staticDirs item is not set on disk


##### 5.3.1:
*  Fix deployment closing prematurely


##### 5.3.0:
*  Add [post-pack] build step
*  Add a post-build field


##### 5.2.0:
*  Show process id (pid) on [scan] command
*  Add more information to the [info] command
*  Display server names using the same port instead of host names


##### 5.1.0:
*  Add [extends] field to [errors] for routing errors based on urls


##### 5.0.0:
*  Fix the errors field
*  Show CPU usage and memory consumption of server child
*  Add --monitor option to monitor cpu usage and memory consumption
*  Generate a README file on deployment
*  Update libutils dependency to fix plugin installation breaking
*  Fix platforms fields overwritting sections and remotes fields
*  Fix extra values added to server configuration on pack command
*  Always display output on npm install
*  Remove devDendencies from package.json on deployment
*  Display additionnal information on remote install
*  Display messages instantly on remote install
*  Fix generated archive
*  Display more messages on publish
*  Fix [publish] commands using erroneous arguments
*  Fix [publish] missing .genserverc file
*  Fix an issue with the [publish] command
*  Fix [deploy] to remote command
*  Fix [deploy] command not working with bare --config
*  Allow using the --config option with no predefined value
*  Fix options --section and --platform not working with the [deploy] command
*  Restore [sections] functionalities
*  Fix unsupported request error on child server
*  Prettify json generated files
*  Add property [modulelink] to plugin field for helping with debugging
*  Display installed plugins versions
*  Display installed dependencies versions
*  Do not serve current folder on [project] command
*  Fix autoreload not working with relative paths
*  Add [enable] property to disable a plugin
*  Restore and Reimplement reset command
*  Display more messages when publishing
*  Fix server not starting on undefined session child
*  Fix [remove] command with --force option
*  Fix application not finding template path
*  Allow deleting default attached server with the --force option
*  Fix [project] command not finding the web-analyst plugin
*  Fix [backup] command
*  Fix progress bar on upload
*  Allow assigning namespace from a remote field
*  Fix [publicDirs] property not updated on remote
*  Show progress bar on uploading to remote
*  Display generated archive size
*  Add [publicDirs] property
*  Set highest priority on values set directly on a remote field instead of an external configPath
*  Fix errors not showing on [npm install]
*  Fix permission error on directories
*  Fix js function error not found
*  Add basic forwarding port
*  Fix [publish] command to remote
*  Review session variable solver
*  Add more recognisable variables
*  Fix statistic plugin integration
*  Update statistics plugin
*  Review statistic plugin
*  Add [default] as alias for [show default]
*  Fix error on [info] command with port option
*  Allow installing by copy or not the node_modules directory with the --whole option
*  Add a --whole option to force copy the node_modules directory during packing and deploying
*  Show why a port is unavailable when starting a server
*  Remove symbols on [search] command
*  Add [search] command
*  Add --section option
*  Display log from build section quicker
*  Fix error uninitialised session
*  Show an error if certain symbols are not exported
*  Fix the [eventually] property ignored when triggered on server side
*  Fix module not found error after minification
*  Cancel operation when cannot overwrite log file
*  Fix unauthorized message displayed instead of unsupported request message
*  Review plugin system
*  Review auto-reload
*  Fix staticDirs.filter not a function error
*  Add validators for restricting access to directories
*  Take projectRoot field into account when solving directories
*  Convert tilde ~ symbol when passing the --config option
*  Review priorities for attributing deployment server name
*  Add a message during clean remote deployment
*  Fix html error page not showing
*  Fix remote deployment
*  Review remote deployment
*  Add --clean option force clean deployment
*  Fix local deployment
*  Allow passing --config option without .zip package to [deploy] command
*  Fix an error with non-existent path
*  Allow rendering HTML via configuration errors field
*  Fix error key not taken into account
*  Display server urls by ip
*  Allow using tilde symbol ~ in the --config option
*  Fix remote deployment with the --config option
*  Look for config path in the same location as the session referencing it
*  Review displayed messages
*  Set hostname on deployed file after installation
*  Stop remote deployment earlier when econfig path is non-existent
*  Add --config option to the [update] command
*  Restore note info 4568
*  Fix commands using short filename as server
*  Fix various commands with options
*  Fix commands using batch options
*  Add command [show active] with no extra options
*  Add command [show default] with no extra options
*  FIX [create config] command with absolute path
*  Fix error 4199
*  Allow deployment to remote
*  Remove extra error message on failing deployments
*  Fix local [deploy] command
*  Remove extra error message when a config file is not found
*  Remove [] when config to filepath is miscalculated
*  Fix [push] command
*  File [load] command
*  Fix server selection when no options is passed to a command
*  Fix default platform section automatically applied
*  Fix added command [set] when executing [stop] command
*  Fix error 3131
*  Fix the [erase all] command
*  Fix [update] command
*  Fix [create] command
*  Add [update] command
*  Fix [flush] command
*  Fix deployment tests



---
