npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ymlr

v2.0.0

Published

A platform helps to do everythings base on a yaml script file

Readme

ymlr

A platform helps to run everythings base on a yaml script file

Installation

Install via npm

  npm install -g ymlr

Install via yarn

  yarn global add ymlr

Supported tags

  1. ymlr-mqtt Pub/sub messages to channels in mqtt
  2. ymlr-redis Handle redis into ymlr platform
  3. ymlr-telegram Send telegram text, photo..., support "listen", "command", "hears"... in telegram bot
  4. ymlr-sql Execute query to mysql, postgresql, orable, sqlite...
  5. ymlr-cron Schedule jobs to do something base on cron pattern

Run a scene

Run a scene file

  ymlr $PATH_TO_SCENE_FILE

Run a encrypted scene file with a password

  ymlr $PATH_TO_SCENE_FILE $PASSWORD

Override env variables then run

  ymlr -e "port=80" -e "log=error" -- $PATH_TO_SCENE_FILE

CLI

Show helps

  ymlr -h

Show all tags version

  ymlr

Add new external tags, libraries which is used in the scene

  ymlr add ymlr-telegram@latest

Upgrade external tags, libraries which is used in the scene

  ymlr up ymlr-telegram@latest

Remove external tags, libraries which is used in the scene

  ymlr rm ymlr-telegram@latest

Customize source paths which are registed tags in your application

  ymlr --tag-dirs /myapp1 --tag-dirs /myapp2 -- myapp.yaml     # "/myapp1", "/myapp2" are includes source code

Override show debug log for all of tags

  ymlr --debug=all -- myapp.yaml

Docker

Docker image file: circle2jt/ymlr

Run a scene file.
Default is /script/index.yaml, you can override it in commands
$PASSWORD is optional when run a encrypted scene file

  docker run -v $PATH_TO_SCENE_FILE:/scripts/index.yaml --rm -it circle2jt/ymlr /scripts/index.yaml $PASSWORD

Run a specific file

  docker run -v $PATH_TO_SCENE_DIR:/scripts --rm -it circle2jt/ymlr /scripts/$PATH_TO_SCENE_FILE

Example

  1. Create a scene file at test.yaml
name: Test scene
runs:
  - echo: Hello world

  - name: Get post data
    http'get:
      url: http://localhost:3000/posts
    vars: postData

  - echo: ${ $vars.postData }
  1. Run
  ymlr test.yaml

Visual Studio Code extensions

  • ymlr-vscode Play ymlr scenarios in vscode.
    After install the extension, please open a scenario file then press shift+alt+r to run the scenario.

  • Hightlight variables, utils, constants... in yaml scenarios.

    Add the below configuration to your settings.json

    {
      "highlight.regexes": {
          "(\\$v\\.)|(\\$vars\\.)": {
              "regexFlags": "gm",
              "filterLanguageRegex": "yaml",
              "filterFileRegex": ".*\\.yaml",
              "decorations": [
                  {
                      "color": "#98ffa0",
                      "fontWeight": "bold"
                  },
                  {
                      "color": "#98ffa0",
                      "fontWeight": "bold"
                  }
              ]
          },
          "(\\$ps\\.)|(\\$parentState\\.)|(this\\.)": {
              "regexFlags": "g",
              "filterLanguageRegex": "yaml",
              "filterFileRegex": ".*\\.yaml",
              "decorations": [
                  {
                      "color": "#55b85d",
                      "fontWeight": "bold"
                  },
                  {
                      "color": "#55b85d",
                      "fontWeight": "bold"
                  }
              ]
          },
          "(\\$loopValue[\\. ])|(\\$lv[\\. ])|(\\.loopValue)|(\\$loopKey[\\. ])|(\\$lk[\\. ]|(\\.loopKey))": {
              "regexFlags": "g",
              "filterLanguageRegex": "yaml",
              "filterFileRegex": ".*\\.yaml",
              "decorations": [
                  {
                      "color": "#40723a",
                      "fontWeight": "bold"
                  },
                  {
                      "color": "#40723a",
                      "fontWeight": "bold"
                  },
                  {
                      "color": "#509549",
                      "fontWeight": "bold"
                  },
                  {
                      "color": "#509549",
                      "fontWeight": "bold"
                  }
              ]
          },
          "(\\$u\\.)|(\\$utils\\.)": {
              "regexFlags": "g",
              "filterLanguageRegex": "yaml",
              "filterFileRegex": ".*\\.yaml",
              "decorations": [
                  {
                      "color": "#70aeff",
                      "fontWeight": "bold"
                  },
                  {
                      "color": "#70aeff",
                      "fontWeight": "bold"
                  }
              ]
          },
          "(\\$\\{[^}]+\\})": { // A regex will be created from this string, don't forget to double escape it
              "regexFlags": "g", // Flags used when building this regex
              "filterLanguageRegex": "yaml",
              "filterFileRegex": ".*\\.yaml",
              "decorations": [
                  {
                      "color": "#6267f8",
                      "fontStyle": "italic"
                  }
              ]
          }
      }
    }

Common tags which is used in the program

| Tags | Description | |---|---| | md'doc | Generate comment in a file to document | | echo | Print to console screen | | echo'debug | Add more information when print to console screen | | clear | Clear console screen | | event'emit | Send data via global event | | event'on | Handle global events in app | | fn-debounce | Debounce function (#Ref: lodash.debounce) | | fn-debounce'cancel | Cancel debounce function (#Ref: lodash.debounce) | | fn-debounce'del | Cancel & remove debounce function (#Ref: lodash.debounce) | | fn-debounce'flush | Force to call debounce function ASAP if it's called before that (#Ref: lodash.debounce) | | fn-debounce'touch | touch debounce function. Reused last agruments(#Ref: lodash.debounce) | | fn-queue | Register a queue job | | fn-queue'del | Stop and remove a queue | | fn-singleton | This is locked before run and unlock after done. When it's called many time, this is only run after unlock | | fn-singleton'del | Remove singleton function | | fn-throttle | Throttle function (#Ref: lodash.throttle) | | fn-throttle'cancel | Cancel throttle function (#Ref: lodash.throttle) | | fn-throttle'del | Cancel & remove throttle function (#Ref: lodash.throttle) | | fn-throttle'flush | Force to call throttle function ASAP if it's called before that (#Ref: lodash.throttle) | | fn-throttle'touch | touch throttle function. Reused last agruments (#Ref: lodash.throttle) | | exit | Stop then quit the program | | fetch'del | Send a http request with DELETE method | | fetch'get | Send a http request with GET method | | fetch'head | Send a http request with HEAD method | | fetch'patch | Send a http request with PATCH method | | fetch'post | Send a http request with POST method | | fetch'put | Send a http request with PUT method | | file'read | Read a file then load data into a variable | | file'store | Store data to file | | file'write | Write data to file | | http'del | Send a http request with DELETE method | | http'get | Send a http request with GET method | | http'head | Send a http request with HEAD method | | http'patch | Send a http request with PATCH method | | http'post | Send a http request with POST method | | http'put | Send a http request with PUT method | | http'server | Create a http server to serve content via http | | include | Include a scene file or list scene files in a folder | | input'confirm | Get user confirm (yes/no) | | input'multiselect | Suggest a list of choices for user then allow pick multiple choices | | input'number | Get user input from keyboard then convert to number | | input'password | Get user input from keyboard but hide them then convert to text | | input'select | Suggest a list of choices for user then allow pick a choice | | input'suggest | Suggest a list of choices for user then allow pick a choice or create a new one | | input'text | Get user input from keyboard then convert to text | | js | Execute a nodejs code | | npm'install | Install librarries to use in the scene. | | npm'uninstall | Uninstall librarries to use in the scene. | | pause | Pause the program then wait to user enter to continue | | runs | Group elements | | scene | Load another scene into the running program | | scene'returns | Return value to parent scene | | scene'thread | Same "scene" but it run in a new thread | | sh | Execute a bash script or shell file | | sleep | Sleep the program then wait to user enter to continue | | tag'register | Register custom tags from code or npm module, github.... | | test | Check conditions in the program | | view'flow | View flows in a scene | | ymlr'load | Merge, replace env variable in yaml files to a yaml file |

Root scene

It's a scene file
Root scene file includes all of steps to run

Example:

  name: Scene name                  # Scene name
  description: Scene description    # Scene description
  summary: true                     # Show log result after finished
  debug: info                       # Show log when run. Default is info. [silent, error, warn, info, debug, trace, all]
  password:                         # Encrypted this file with the password. To run this file, need to provides a password in the command line
  vars:                             # Declare global variables which are used in the program.
    env: production                 # |- Only the variables which are declared in the top of root scene just can be overrided by environment variables
  env:                              # Set value to environment variable (process.env)
    DEBUG: all
    NODE_ENV: production
    env: dev                        # It overrides to $vars.env
    # - NODE_ENV=production
  envFiles:                         # Load env variable from files (string | string[])
    - .env
    - .env.dev
  varsFiles:                        # Load vars from json or yaml files (string | string[])
    - ./var1.json
    - ./var2.yaml
  runs:                             # Defined all of steps which will be run in the scene
    - echo: Hello world
    - test: test props
  catch:
    - name: handle error here ${ $wps.deref().error }
  finally:
    - name: always handle these steps before exit

->

It's a property in a tag
Expose item properties for others extends

Example:

Use a shortcut ;

  - ->: helloTemplate
    ;echo: Hello              # Not run. ";" is same "template: true"

  - <-: helloTemplate         # => Hello

Use template

  - ->: helloTemplate         # Not run
    template: true
    echo: Hello

  - <-: helloTemplate         # => Hello

Use template

  - ->: hiTemplate            # Not run
    ;event'emit:
      name: test-event
      data: Hi

  - <-: hiTemplate            # => send "Hi" to "test-event"

  - <-: hiTemplate            # => send "Hello" to "test-event"
    props:
      data: Hello

# @include

It's a yaml comment type
Include the content file to current position. This is will be read a file then copy file content into current position If you want to use expresion ${}, you can use tag "include". Useful for import var file ....

Example:

  - vars:
      # @include ./.env

.env file is

ENV: production
APP: test

<-

It's a property in a tag
Copy properties from others (a item, or list items)

Example:

  - ->: baseRequest
    ;props:
      baseURL: http://localhost

  - <-: baseRequest
    ->: user1Request
    ;props:
      headers:
        authorization: Bearer user1_token

  - ->: user2RequestWithoutBaseURL
    ;props:
      headers:
        authorization: Bearer user2_token

  - <-: user1Request
    http'get:                      # Send a get request with baseURL is "http://localhost" and headers.authorization is "Bearer user1_token"
      url: /posts
    vars: user1Posts

  - <-: [baseRequest, user2RequestWithoutBaseURL]
    http'get:                      # Send a get request with baseURL is "http://localhost" and headers.authorization is "Bearer user2_token"
      url: /posts
    vars: user2Posts

async

It's a property in a tag
Execute parallel tasks

Example:

  - async: true
    http'get:
      url: /categories
    vars: categories
  - ~http'get:            # Can use shortcut by add "~"" before tag name
      url: /product/1
    vars: product

  - name: The product ${$vars.product.name} is in the categories ${$vars.categories.map(c => c.name)}

case

It's a property in a tag
shortcut for if + skipNext

Example:

  - vars:
      number: 11

  - case: ${$vars.number === 11}        # When reach the conditional then execute and skip the next steps
    echo: Value is 11

  - case: ${$vars.number > 10}
    echo: Value is greater than 10      # When reach the conditional then execute and skip the next steps

  - echo: Done                          # Never echo when reach the any conditional

catch

It's a property in a tag
After retried and keep failing, it will execute steps in this block and ignore throw error. If you want throw error, you need throw in catch

Example:

  - js: throw new Error('Should error here')
    failure:
      restart: 2
    catch:
      - name: Print the rror is ${ $ws().error.message } after retried 2 times    # => Should error here
        js: throw $ws().error                                                     # Throw error

context

It's a property in a tag
Context logger name which is allow filter log by cli "ymlr --debug-context context_name=level --"

Example:

  - name: Get list user
    context: userapi
    debug: warn
    http'get: ...

  - name: Get user details
    context: userapi
    debug: warn
    http'get: ...

  - name: Get product details
    context: productapi
    debug: warn
    http'get: ...

Now, we have 2 choices to debug all of user APIs and product APIs

  1. Replace all "debug: warn" to "debug: debug"
  2. Only run cli as below
  ymlr --debug-context userapi=debug --debug-context productapi=trace -- $SCENE_FILE.yaml

debug

It's a property in a tag
How to print log details for each of item. Default is info Value must be in:

  • true: is debug
  • all: Same trace
  • trace: Print all of messages
  • debug: Print of debug, info, warn, error, fatal messages
  • info: Print info, warn, error, fatal messages
  • warn: Print warn, error, fatal messages
  • error: Print error, fatal messages
  • fatal: Print fatal messages
  • secret: Only show secret log. Example config, password, keys...
  • silent: Not print anything

Example:

  - name: Get data from a API
    debug: debug
    http'get:
      url: http://...../data.json

detach

It's a property in a tag
Push the tag execution to background jobs to run async, the next steps will be run ASAP. Before the program is exited, it will be released

Example:

  - name: job1
    detach: true
    loop: ${[1,2,3]}
    runs:
      - echo: Hello ${this.parentProxy.loopValue}
      - sleep: 1s
  - name: job2
    echo: first
  - name: job3
    echo: second

In above example, job2, job3 will run step by step, but job1 run in background, the program will wait job1 done then finish the program

else

It's a property in a tag
Check condition before run the item and skip the next cases when it passed

Example:

  - vars:
      number: 11

  - if: ${$vars.number === 11}
    echo: Value is 11                   # => Value is 11

  - elseif: ${$vars.number > 10}
    echo: Value is greater than 10      # =>

  - else:
    echo: Value is lessthan than 10     # =>

  - echo: Done                          # => Done

elseif

It's a property in a tag
Check condition before run the item and skip the next cases when it passed

Example:

  - vars:
      number: 11

  - if: ${$vars.number === 11}
    echo: Value is 11                   # => Value is 11

  - elseif: ${$vars.number > 10}
    echo: Value is greater than 10      # =>

  - elseif: ${$vars.number < 10}
    echo: Value is lessthan than 10     # =>

  - echo: Done                          # => Done

failure

It's a property in a tag
Handle error when do something wrong. Default it will exit app when something error.

  • ignore: Ignore error then keep playing the next
  • restart: max: 3 When got something error, it will be restarted automatically ASAP (-1/0 is same) sleep: 3000

Example:

  - failure:
      debug: warn                  # Show warning when failed
      filterDebug: |-              # Filter error. Example: error message includes the text "ignore print error here" then not show log
        return !error?.message?.includes('ignore print error here')
      restart:                     # Try to restart 3 time before exit app. Each of retry, it will be sleep 3s before restart
        max: 3
        sleep: 3s                  # wait 3s before retry
        sequence:                  # all of failed elements in same name will be restart sequence after sleep time
          name: test
          sleep: 1s
      retryEvent: retryIt          # After could not restart (reach of limit restart) then it wait event "retryIt" then retry. (Use "event'emit" for the trigger)
      ignore: true                 # After retry 3 time failed, it keeps playing, not exit
    js: |
      const a = 1/0
  - failure:
      ignore: true                 # Ignore error then play the next
    js: |
      const a = 1/0

finally

It's a property in a tag
Always run this block when finish success or error

Example:

  - js: throw new Error('Should error here')
    failure:
      restart: 2
    catch:
      - name: Print the error is ${ $ws().error.message } after retried 2 times     # => Should error here
        js: throw new Error('Error in catch')
    finally:
      - name: Should show error in catch is ${ $ws().error.message }                # => Error in catch

icon

It's a property in a tag
Icon which is prepended before the step name

Example:

  - ->: sleepID
    icon: ⏳
    ;sleep: 1000

  - name: Sleep in 1s       # => ⏳ Sleep in 1s
    <-: sleepID
    props: 1s

  - name: Sleep in 2s       # => ⏳ Sleep in 2s
    <-: sleepID
    props: 2s

id

It's a property in a tag
ID Reference to element object in the $vars

Example:

  - id: echo1
    echo: Hello

  - js: |
      this.logger.debug($vars.echo1.content)

if

It's a property in a tag
Check condition before run the item

Example:

  - vars:
      number: 11

  - if: ${$vars.number === 11}
    echo: Value is 11                   # => Value is 11

  - if: ${$vars.number > 10}
    echo: Value is greater than 10      # => Value is greater than 10

  - if: ${$vars.number < 10}
    echo: Value is lessthan than 10     # =>

  - echo: Done                          # => Done

loop

It's a property in a tag
Loop to run items with a condition. Variables:

  • $lv, $loopValue: Get loop value
  • $lk, $loopKey: Get loop key

Example:

Loop in array

  - vars:
      arrs: [1,2,3,4]
  - loop: ${$vars.arrs}
    echo: Index is ${$loopKey}, value is ${$loopValue}    # $loopKey ~ this.loopKey AND $loopValue ~ this.loopValue
  # =>
  # Index is 0, value is 1
  # Index is 1, value is 2
  # Index is 2, value is 3
  # Index is 3, value is 4

Loop in object

  - vars:
      obj: {
        "name": "thanh",
        "sex": "male"
      }
  - loop: ${$vars.obj}
    echo: Key is ${$loopKey}, value is ${$loopValue}
  # =>
  # Key is name, value is thanh
  # Key is sex, value is male

Dynamic loop in a condition

  - vars:
      i: 0
  - loop: ${$vars.i < 3}
    echo: value is ${$vars.i++}
  # =>
  # value is 0
  # value is 1
  # value is 2

Loop in nested items

  - vars:
      arrs: [1,2,3]
  - loop: ${$vars.arrs}
    name: group ${$loopValue}
    runs:
      - echo: value is ${$loopValue}                                  # => item value is "1" then "2" then "3"

      - loop: ${ [4,5,6] }
        runs:
          - echo: value is ${$loopValue}                              # => item value is "4" then "5" then "6"

          - echo: parent is ${this.parentProxy.parentProxy.loopValue} # => item value is "1" then "2" then "3"
  # =>
  # group 1
  # item value is 1

name

It's a property in a tag
Step name

Example:

  - name: Sleep in 1s
    sleep: 1000

only

It's a property in a tag
Only run this

Example:

  - echo: Hi                   # No print "hi"

  - only: true
    echo: Hello                # Only print "Hello"

  - echo: world                # No print "world"

  - only: true
    echo: Bye                  # Only print "Bye"

parentState

It's used in js code

  • Set/Get value to context variables. Used in tags support runs and support parentState Variables:
  • $wps.deref(), $ws(): Reference to context state

Example:

  - name: listen to handle an events
    event'on:
      name: test-event
    runs:
      - echo: ${ $ws().eventData }   # => { name: Test event, data: Hello }
      - echo: ${ $ws().eventOpts }            # => [ params 1, params 2 ]

  - event'emit:
      name: test-event
      data:
        name: Test event
        data: Hello
      opts:
        - params 1
        - params 2

Access $ws() incursive

  - name: Connect to redis
    ymlr-redis:
      uri: redis://localhost:6379
    runs:
      - name: access redis
        js: |
          await $ws().redis.client.publish('test-event/ping', 'level 1')

      - name: after redis is connected, start listening to handle an events
        event'on:
          name: test-event
        runs:
          - echo: ${ $ws().eventData }   # => { name: Test event, data: Hello }
          - echo: ${ $ws().eventOpts }            # => [ params 1, params 2 ]

          - name: access redis
            js: |
              await $ws().redis.client.publish('test-event/ping', 'level 2')

  - event'emit:
      name: test-event
      data:
        name: Test event
        data: Hello
      opts:
        - params 1
        - params 2

placeholder

It's a property in a tag
It store values which are overrided when inherit a template

Example:

  - ->: printMyLog
    placeholder:
      name: ""
    ;js: this.logger("[MyLog] %s", this.placeholder.name)

  - <-: printMyLog        # expected print to "[MyLog] Test 1"
    placeholder:
      name: Test 1

  - <-: printMyLog        # expected print to "[MyLog] Test 2"
    placeholder:
      name: Test 2

Prefix path

Global Notes
Prefix path which is support in all of tags. Can used in code by: proxy.getPath(pathOfFile: string)

Example:

  cd /app
  yaml /scene/my-root-scene.yaml
  • ~~/: map to run dir /app/
  • ~/: map to root scene dir /scene/
  • ~./: map to current scene dir
  • ../: map to parent directory of the current working file
  • ./: map to directory of the current working file
  • /: absolute path

runs

It's a property in a tag
Steps will be run in the running element

Example:

  - http'server:
      address: 0.0.0.0:1234
    runs:
      - echo: Do something when a request comes
      - echo: Do something when a request comes...
      ...

skip

It's a property in a tag
No run this

Example:

  - echo: Hi                   # Print "hi"

  - skip: true
    echo: Hello                # No print "Hello"

  - echo: world                # Print "world"

  - ->: testEvent
    ;event'emit:
      name: test_event
      data:
        hello: ${ this.$.cusName }

  - name: say hello to A
    <-: testEvent
    props:
      cusName: A

  - name: say hello to B
    <-: testEvent
    props:
      cusName: B

skipNext

It's a property in a tag
Skip the next steps in the same parent group when done this

Example:

  - loop: ${ [1,2,3] }
    runs:
      - echo: begin                                          # Always print begin

      - echo: ${ this.parentProxy.loopValue }
        skipNext: ${ this.parentProxy.loopValue === 2 }      # When $loopValue is 2, skip the next step

      - echo: end                                            # Only print end when $loopValue is not equals 2

template

It's a property in a tag
Declare a template to extends later

Example:

  - ->: localhost
    template: true          # Template is true then it will be not run
    props:
      baseURL: http://localhost:3000

  - ->: localhost
    ;props:                 # Same with "template: true" then it will be not run
      baseURL: http://localhost:3000

  - <-: localhost           # Auto inherits "baseURL" from localhost
    http'get:               # => make a http request to http://localhost:3000/items
      url: /items

vars

It's a property in a tag

  • Set value in the item to global vars to reused later
  • Declare and set value to variables to reused in the scene/global scope
  • If the first character is uppercase, it's auto assigned to global which is used in the program (all of scenes)
  • If the first character is NOT uppercase, it will be assigned to scene scope which is only used in the scene Variables:
  • $v, $vars: Reference to variables

Example:

A main scene file

  - echo: Hello world
    vars: helloText             # Save output from echo to global variable "helloText"
  - echo: ${$vars.helloText}    # => Hello world

  - vars:
      MainName: global var      # Is used in all of scenes
      mainName: local var       # Only used in this scene

  - name: test weak ref variables in parent state
    runs:
      - vars:
          url@wps: http://localhost/data.json
      - fetch'get:
          url: ${ $wps.deref().url }                        # Refer to "url@wps". It will be revoked after "test weak ref variables" finished
        vars:
          weakResponseData@wps: ${ this.$.response.data }   # Create a "weakResponseData" weakref state which is only available in "test weak ref variables" lifecycle

      - echo: ${ $wps.deref().weakResponseData }

  - name: test weak ref variables
    runs:
      - vars:
          url@wps: http://localhost/data.json
      - fetch'get:
          url: ${ $wps.deref().url }                        # Refer to "url@wps". It will be revoked after "test weak ref variables" finished
        vars:
          weakResponseData@wps: ${ this.$.response.data }   # Create a "weakResponseData" weakref state which is only available in "test weak ref variables" lifecycle

  - scene:
      path: ./child.scene.yaml

  - fetch'get:
      url: http://localhost/data.json
    vars:
      myResponseData: ${ this.$.response.data }                         # Assign response data to scene variable
      MyResponseData: ${ this.$.response.data }                         # Assign response data to global variable
      _: ${ $ws().responseDataInContext = this.$.response.data } # Assign response data to context variable

  - echo: ${$vars.MainName}      # => global var
  - echo: ${$vars.mainName}      # => local var
  - echo: ${$vars.name}          # => undefined
  - echo: ${$vars.Name}          # => global name here

A scene file child.scene.yaml is:

  - vars:
      Name: global name here
      name: scene name here     # Only used in this scene

  - echo: ${$vars.MainName}      # => global var
  - echo: ${$vars.mainName}      # => undefined
  - echo: ${$vars.name}          # => scene name here
  - echo: ${$vars.Name}          # => global name here

md'doc

doc
Generate comment in a file to document

Example:

  - doc'md:
      includeDirs:
        - /workspaces/ymlr/src/components/doc/md.ts
      includePattern: "^(?!.*\\.spec\\.ts$)"
      excludeDirs:
        - node_modules
      prependMDs:                                     # Prepend content in the document (Optional)
        - path: ../INSTALLATION.md                    # |- {path}: Read file content then copy it into document
        - ---                                         # |- string: Markdown content
      appendMDs:                                      # Append content in the document
        - ---
        - "### Have fun :)"
      saveTo: /workspaces/ymlr/test/thanh.doc.md

Declare doc in file Example

echo

Print to console screen

Example:

Print a message

  - echo: Hello world

  - echo:
      if: ${true}
      content: Hello

Print a variable

  - vars:
      name: thanh
  - echo: ${ $vars.name }

Print text with custom type. (Follow "chalk")

  - echo: Color is white

  - echo:
      styles: [red]
      content: Color is red
  - echo:
      styles: [red, bold]
      content: Content is red and bold

echo'debug

Add more information when print to console screen

Example:

Print a message

                                            # Default prepend execution time into log
  - echo'debug: Hello world                 # => 01:01:01.101    Hello world

  - echo'debug:
      formatTime: YYYY/MM/DD hh:mm:ss.ms    # Default format is "hh:mm:ss.ms"
      content: Hello                        # => 2023/01/01 01:01:01.101    Hello

clear

Clear console screen

Example:

  - clear:

event'emit

Send data via global event

Example:

  - name: send data to an event
    event'emit:
      name: test-event
      data:
        name: Test event
        data: Hello
      opts:
        - params 1
        - params 2

  - name: send data to multiple events
    event'emit:
      names:
        - test-event1
        - test-event2
        - test-event3
      data:
        name: Test event
        data: Hello
      opts:
        - params 1
        - params 2

  - name: quick to emit multiple event with eventData is empty
    event'emit: [test-event1, test-event2]

  - name: quick to emit an event with eventData is empty
    event'emit: test-event1

event'on

Handle global events in app

Example:

  - name: listen to handle an events
    event'on:
      name: test-event
    runs:
      - echo: ${ $ws().eventData }   # => { name: Test event, data: Hello }
      - echo: ${ $ws().eventOpts }   # => [ params 1, params 2 ]

  - name: listen to handle multiple events
    event'on:
      names:
        - test-event1
        - test-event2
        - test-event3
    runs:
      - echo: ${ $ws().eventName }   # => test-event1 or test-event2 or test-event3
      - echo: ${ $ws().eventData }   # => { name: Test event, data: Hello }
      - echo: ${ $ws().eventOpts }   # => [ params 1, params 2 ]
  - event'emit:
      name: test-event
      data:
        name: Test event
        data: Hello
      opts:
        - params 1
        - params 2

fn-debounce

Debounce function (#Ref: lodash.debounce)

  • Without "wait" and "runs" then it's only touch with last agruments
  • Specific "wait" and "runs" then it's run with new agruments

Example:

  - fn-debounce:
      name: Delay to do something
      wait: 1s                # The number of milliseconds to delay.
      trailing: true          # Specify invoking on the trailing edge of the timeout. Default is true
      leading: false          # Specify invoking on the leading edge of the timeout. Default is false
      maxWait: 2s             # The maximum time func is allowed to be delayed before it's invoked.
      autoRemove: true        # Auto remove it when reached the event. Default is false.
      debounceData:           # Pass input debounceData to debounce to do async task
        dataFromParentState: ${ $ws().channelData.name }
    runs:
      - name: Do this when it's free for 1s
        echo: ${ $ws().debounceData.dataFromParentState }

  # touch if debounce is existed
  - fn-debounce:                          # Touch the existed throttle with last agruments
      name: Delay to do something
  # OR
  - fn-debounce: Delay to do something    # Touch the existed throttle with last agruments

fn-debounce'cancel

Cancel debounce function (#Ref: lodash.debounce)

Example:

  - fn-debounce'cancel:
      name: Delay to do something               # Debounce name to cancel
  # OR
  - fn-debounce'cancel: Delay to do something   # Debounce name to cancel
  # OR
  - fn-debounce'cancel:
      - delay1
      - delay2

fn-debounce'del

Cancel & remove debounce function (#Ref: lodash.debounce)

Example:

  - fn-debounce'del:
      name: Delay to do something               # Debounce name to delete
  # OR
  - fn-debounce'del: Delay to do something      # Debounce name to delete
  # OR
  - fn-debounce'del:
      - delay1
      - delay2

fn-debounce'flush

Force to call debounce function ASAP if it's called before that (#Ref: lodash.debounce)

Example:

  - fn-debounce'flush:
      name: Delay to do something                 # Debounce name to delete
  # OR
  - fn-debounce'flush: Delay to do something      # Debounce name to delete
  # OR
  - fn-debounce'flush:
      - delay1
      - delay2

fn-debounce'touch

touch debounce function. Reused last agruments(#Ref: lodash.debounce)

Example:

  - fn-debounce'touch:
      name: Delay to do something               # Debounce name to touch
  # OR
  - fn-debounce'touch: Delay to do something    # Debounce name to touch
  # OR
  - fn-debounce'touch:
      - delay1
      - delay2

fn-queue

Register a queue job

Example:

  - id: myQueue
    fn-queue:
      name: My Queue 1        # Use stateless queue, not reload after startup
      concurrent: 2
      startup: true           # Run ASAP. Default is true. If its false then it only declare job, not run yet, need call $v.myQueue.$.start() to manual start.
      timeout: 1000           # Timeout for each job. Default is 0 (no timeout)
      queueFilter:
        expiredJobAfter: 6000 # When jobs are pending after 6s, then auto be removed
      autoRemove: true        # Auto remove queue after finshed all of jobs. Default is false
      queueData:              # Pass input data to queue to do async task
        dataFromParentState: ${ $ws().channelData.name }
    runs:
      - echo: ${ $ws().queueData.key1 } is ${ $ws().queueData.value1 }
      - echo: ${ $ws().queueData.dataFromParentState }

      - echo: ${ $ws().queueData }        # Queue data
      - echo: ${ $ws().queueErrorCount }  # Num of error when retry this job
      - echo: ${ $ws().queueCreatedAt }   # Time which a queue is created for the first time
      - echo: ${ $ws().queueCount }       # Count of queue which not done
      - echo: ${ $ws().queueName }        # Queue name

  - fn-queue:
      name: My Queue 1
      queueData:
        key1: value1
        key2: value 2

File Store

  - fn-queue:
      name: My Queue 1
      concurrent: 2
      skipError: false       # Not throw error when a job failed
      db:                    # Optional: Statefull queue, it's will reload after startup
        path: /tmp/db        #  - Optional: Default is "tempdir/queuename"
        password: abc        #  - Optional: Default is no encrypted by password
    runs:
      - echo: ${ $ws().queueData.key1 } is ${ $ws().queueData.value1 }

  - fn-queue:
      name: My Queue 1
      queueData:
        key1: value1
        key2: value 2

External Store

  - id: fileDataStore
    file'store:
      path: /tmp/data.json      # Path to store data
      password:                 # Password to encrypt/decrypt data content
      initData: []              # Default data will be stored when file not found

  - fn-queue:
      name: My Queue 1
      concurrent: 2
      skipError: false       # Not throw error when a job failed
      store: ${ $v.fileDataStore.$.store }
    runs:
      - echo: ${ $ws().queueData.key1 } is ${ $ws().queueData.value1 }

  - fn-queue:
      name: My Queue 1
      queueData:
        key1: value1
        key2: value 2

fn-queue'del

Stop and remove a queue

Example:

  - fn-queue'del:
      name: My Queue 1                 # Queue name to delete

  - fn-queue'del: My Queue 1           # Queue name to delete

  - fn-queue'del:
      - My Queue 1                    # List Queues name to delete
      - My Queue 2

fn-singleton

This is locked before run and unlock after done. When it's called many time, this is only run after unlock

Example:

  - fn-singleton:
      name: Only run 1 time
      trailing: true              # In the processing which not finished yet, if it's called by others, it keeps the last params to cached then make the last call before done
      autoRemove: true            # Auto remove after done
      singletonData:              # Pass input data to singleton to do async task
        dataFromParentState: ${ $ws().channelData.name }
    runs:
      - echo: Do this when it's free for 1s

fn-singleton'del

Remove singleton function

Example:

  - fn-singleton'del:
      name: Delay to do something                 # Singleton name to delete
  # OR
  - fn-singleton'del: Delay to do something       # Singleton name to delete

fn-throttle

Throttle function (#Ref: lodash.throttle)

  • Without "wait" and "runs" then it's only touch with last agruments
  • Specific "wait" and "runs" then it's run with new agruments

Example:

  - fn-throttle:
      name: Delay to do something
      wait: 1s            # The number of milliseconds to throttle invocations to.
      trailing: true      # Specify invoking on the trailing edge of the timeout. Default is true
      leading: true       # Specify invoking on the leading edge of the timeout. Default is true
      autoRemove: true    # Auto remove it when reached the event. Default is false
      throttleData:       # Pass input debounceData to debounce to do async task
        dataFromParentState: ${ $ws().channelData.name }
    runs:
      - name: Do this ASAP and do again when it's called more than 1 times
        echo: ${ $ws().throttleData.dataFromParentState }

  # Call if throttle is existed
  - fn-throttle:                         # Touch the existed throttle with last agruments
      name: Delay to do something
  # OR
  - fn-throttle: Delay to do something   # Touch the existed throttle with last agruments

fn-throttle'cancel

Cancel throttle function (#Ref: lodash.throttle)

Example:

  - fn-throttle'cancel:
      name: Delay to do something               # Throttle name to cancel
  # OR
  - fn-throttle'cancel: Delay to do something   # Throttle name to cancel
  # OR
  - fn-throttle'cancel:
      - delay1
      - delay2

fn-throttle'del

Cancel & remove throttle function (#Ref: lodash.throttle)

Example:

  - fn-throttle'del:
      name: Delay to do something               # Throttle name to delete
  # OR
  - fn-throttle'del: Delay to do something      # Throttle name to delete
  # OR
  - fn-throttle'del:
      - delay1
      - delay2

fn-throttle'flush

Force to call throttle function ASAP if it's called before that (#Ref: lodash.throttle)

Example:

  - fn-throttle'flush:
      name: Delay to do something                 # Throttle name to delete
  # OR
  - fn-throttle'flush: Delay to do something      # Throttle name to delete
  # OR
  - fn-throttle'flush:
      - delay1
      - delay2

fn-throttle'touch

touch throttle function. Reused last agruments (#Ref: lodash.throttle)

Example:

  - fn-throttle'touch:
      name: Delay to do something               # Throttle name to touch
  # OR
  - fn-throttle'touch: Delay to do something   # Throttle name to touch
  # OR
  - fn-throttle'touch:
      - delay1
      - delay2

exit

Stop then quit the program

Example:

  - exit: 0

  - name: Throw error
    exit: 1

fetch'del

Send a http request with DELETE method

Example:

  # DELETE http://localhost:3000/posts/1?method=check_existed
  - name: Delete a post
    fetch'del:
      url: /posts/1
      baseURL: http://localhost:3000  # !optional - Request base url
      query:                          # !optional - Request query string
        method: check_existed
      headers:                        # !optional - Request headers
        authorization: Bearer TOKEN
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      validStatus: [200, 204, 400]    # !optional - Expect these response status codes is success and not throw error
    vars:                             # !optional - Global variable which store value after executed
      status: ${this.$.response.status}

fetch'get

Send a http request with GET method

Example:

Get data from API then store value in vars.posts

  # GET http://localhost:3000/posts?category=users
  - name: Get list posts
    fetch'get:
      url: /posts
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      baseURL: http://localhost:3000  # !optional - Request base url
      query:                          # !optional - Request query string
        category: users
      headers:                        # !optional - Request headers
        authorization: Bearer TOKEN
      responseType: json              # !optional - Default is json ['json' | 'blob' | 'text' | 'buffer' | 'none']
      validStatus: [200, 204, 400]    # !optional - Expect these response status codes is success and not throw error
    vars: posts                       # !optional - Global variable which store value after executed

Download file from a API

  # GET http://localhost:3000/posts?category=users
  - name: Download a file
    fetch'get:
      baseURL: http://localhost:3000
      url: /posts
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      saveTo: /tmp/post.json

fetch'head

Send a http request with HEAD method

Example:

  # HEAD http://localhost:3000/posts/1?method=check_existed
  - name: Check post is existed or not
    fetch'head:
      baseURL: http://localhost:
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
                                      # supported: d h m s ~ day, hour, minute, seconds
                                      # example: 1h2m3s ~ 1 hour, 2 minutes, 3 seconds
      url: /posts/1
      query:
        method: check_existed
      headers:
        authorization: Bearer TOKEN
      validStatus: [200, 204, 400]    # !optional - Expect these response status codes is success and not throw error
    vars:
      status: ${this.response?.status}

fetch'patch

Send a http request with PATCH method

Example:

Update apart of data to API then store value in vars.posts

  # PATCH http://localhost:3000/posts/ID?category=users
  - name: Update a post
    fetch'patch:
      baseURL: http://localhost:3000
      url: /posts/ID
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      type: json                      # 'json' | 'form' | 'raw' | 'multipart' | 'text'
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      body: {
        "title": "My title",
        "description": "My description"
      }
      responseType: json              # 'json' | 'blob' | 'text' | 'buffer' | 'none'
      validStatus: [200, 204, 400]    # !optional - Expect these response status codes is success and not throw error
    vars: newPost

Upload file to server

  # PATCH http://localhost:3000/upload/ID_UPLOADER_TO_REPLACE
  - name: Upload and update data
    fetch'patch:
      baseURL: http://localhost:3000
      url: /upload/ID_UPLOADER_TO_REPLACE
      headers:
        authorization: Bearer TOKEN
      type: multipart
      body: {
        "file": { # File upload must includes path of file, name is optional
          "path": "/tmp/new_my_avatar.jpg",
          "name": "thanh_avatar"
        }
      }
    vars:
      status: ${this.$.response.status}

fetch'post

Send a http request with POST method

Example:

Post data to API then store value in vars.posts

  # POST http://localhost:3000/posts?category=users
  - name: Create a new post
    fetch'post:
      baseURL: http://localhost:3000
      url: /posts
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      type: json                      # 'json' | 'form' | 'raw' | 'multipart' | 'text'
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      body: {
        "title": "My title",
        "description": "My description"
      }
      responseType: json              # 'json' | 'blob' | 'text' | 'buffer' | 'none'
    vars: newPost

Upload file to server

  # POST http://localhost:3000/upload
  - name: Upload a new avatar
    fetch'post:
      baseURL: http://localhost:3000
      url: /upload
      headers:
        authorization: Bearer TOKEN
      type: multipart
      body: {
        "category": "avatar",
        "file": { # File upload must includes path of file, name is optional
          "path": "/tmp/my_avatar.jpg",
          "name": "thanh_avatar"
        }
      }
      validStatus: [200, 204, 400]    # !optional - Expect these response status codes is success and not throw error
    vars:
      status: ${this.$.response.status}

fetch'put

Send a http request with PUT method

Example:

Update data to API then store value in vars.posts

  # PUT http://localhost:3000/posts/ID?category=users
  - name: Update a post
    fetch'put:
      baseURL: http://localhost:3000
      url: /posts/ID
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      type: json                      # 'json' | 'form' | 'raw' | 'multipart' | 'text'
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      body: {
        "title": "My title",
        "description": "My description"
      }
      responseType: json              # 'json' | 'blob' | 'text' | 'buffer' | 'none'
      validStatus: [200, 204, 400]    # !optional - Expect these response status codes is success and not throw error
    vars: newPost

Upload file to server

  # PUT http://localhost:3000/upload/ID_UPLOADER_TO_REPLACE
  - name: Upload and update data
    fetch'put:
      baseURL: http://localhost:3000
      url: /upload/ID_UPLOADER_TO_REPLACE
      headers:
        authorization: Bearer TOKEN
      type: multipart
      body: {
        "category": "avatar updated",
        "file": { # File upload must includes path of file, name is optional
          "path": "/tmp/new_my_avatar.jpg",
          "name": "thanh_avatar"
        }
      }
    vars:
      status: ${this.$.response.status}

file'read

Read a file then load data into a variable

Example:

Read a json file

  - file'read:
      path: /tmp/data.json
      format: json  # !optional
    vars: fileData

Read a yaml file

  - file'read:
      path: /tmp/data.yaml
      format: yaml  # !optional
    vars: fileData

Read a text file

  - file'read:
      path: /tmp/data.txt
    vars: fileContent

file'store

Store data to file

Example:

  - file'store:
      path: /tmp/data.json      # Path to store data
      password:                 # Password to encrypt/decrypt data content
      initData: []              # Default data will be stored when file not found

Use in global by reference

  - file'store:
      path: /tmp/data.yaml
      initData: []
    vars:
      fileDB: ${this}         # Store this element to "fileDB" in vars

  - js: |
      const { fileDB } = vars
      fileDB.data.push('item 1')
      fileDB.data.push('item 2')
      // Save data to file
      fileDB.save()

  - echo: ${$vars.fileDB.data}   # => ['item 1', 'item 2']

file'write

Write data to file

Example:

Write a json file

  - file'write:
      path: /tmp/data.json
      content: {
        "say": "hello"
      }
      format: json  # !optional
      pretty: true  # !optional
      opts:             # ref: https://nodejs.org/api/fs.html#fswritefilefile-data-options-callback
        mode: 775
        flag: r         # ref: https://nodejs.org/api/fs.html#file-system-flags

Write a yaml file

  - file'write:
      path: /tmp/data.yaml
      content: ${$vars.fileData}
      format: yaml  # !optional

Write a text file

  - file'write:
      path: /tmp/data.txt
      content: Hello world

http'del

Send a http request with DELETE method

Example:

  # DELETE http://localhost:3000/posts/1?method=check_existed
  - name: Delete a post
    http'del:
      url: /posts/1
      baseURL: http://localhost:3000  # !optional - Request base url
      query:                          # !optional - Request query string
        method: check_existed
      headers:                        # !optional - Request headers
        authorization: Bearer TOKEN
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      validStatus: [200, 204, 400]    # !optional - Expect these response status codes is success and not throw error
    vars:                             # !optional - Global variable which store value after executed
      status: ${this.$.response.status}

http'get

Send a http request with GET method

Example:

Get data from API then store value in vars.posts

  # GET http://localhost:3000/posts?category=users
  - name: Get list posts
    http'get:
      url: /posts
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      baseURL: http://localhost:3000  # !optional - Request base url
      query:                          # !optional - Request query string
        category: users
      headers:                        # !optional - Request headers
        authorization: Bearer TOKEN
      responseType: json              # !optional - Default is json ['json' | 'blob' | 'text' | 'buffer' | 'none']
      validStatus: [200, 204, 400]    # !optional - Expect these response status codes is success and not throw error
    vars: posts                       # !optional - Global variable which store value after executed

Download file from a API

  # GET http://localhost:3000/posts?category=users
  - name: Download a file
    http'get:
      baseURL: http://localhost:3000
      url: /posts
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      saveTo: /tmp/post.json

http'head

Send a http request with HEAD method

Example:

  # HEAD http://localhost:3000/posts/1?method=check_existed
  - name: Check post is existed or not
    http'head:
      baseURL: http://localhost:
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
                                      # supported: d h m s ~ day, hour, minute, seconds
                                      # example: 1h2m3s ~ 1 hour, 2 minutes, 3 seconds
      url: /posts/1
      query:
        method: check_existed
      headers:
        authorization: Bearer TOKEN
      validStatus: [200, 204, 400]    # !optional - Expect these response status codes is success and not throw error
    vars:
      status: ${this.response?.status}

http'patch

Send a http request with PATCH method

Example:

Update apart of data to API then store value in vars.posts

  # PATCH http://localhost:3000/posts/ID?category=users
  - name: Update a post
    http'patch:
      baseURL: http://localhost:3000
      url: /posts/ID
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      type: json                      # 'json' | 'form' | 'raw' | 'multipart' | 'text'
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      body: {
        "title": "My title",
        "description": "My description"
      }
      responseType: json              # 'json' | 'blob' | 'text' | 'buffer' | 'none'
      validStatus: [200, 204, 400]    # !optional - Expect these response status codes is success and not throw error
    vars: newPost

Upload file to server

  # PATCH http://localhost:3000/upload/ID_UPLOADER_TO_REPLACE
  - name: Upload and update data
    http'patch:
      baseURL: http://localhost:3000
      url: /upload/ID_UPLOADER_TO_REPLACE
      headers:
        authorization: Bearer TOKEN
      type: multipart
      body: {
        "file": { # File upload must includes path of file, name is optional
          "path": "/tmp/new_my_avatar.jpg",
          "name": "thanh_avatar"
        }
      }
    vars:
      status: ${this.$.response.status}

http'post

Send a http request with POST method

Example:

Post data to API then store value in vars.posts

  # POST http://localhost:3000/posts?category=users
  - name: Create a new post
    http'post:
      baseURL: http://localhost:3000
      url: /posts
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      type: json                      # 'json' | 'form' | 'raw' | 'multipart' | 'text'
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      body: {
        "title": "My title",
        "description": "My description"
      }
      responseType: json              # 'json' | 'blob' | 'text' | 'buffer' | 'none'
      validStatus: [200, 204, 400]    # !optional - Expect these response status codes is success and not throw error
    vars: newPost

Upload file to server

  # POST http://localhost:3000/upload
  - name: Upload a new avatar
    http'post:
      baseURL: http://localhost:3000
      url: /upload
      headers:
        authorization: Bearer TOKEN
      type: multipart
      body: {
        "category": "avatar",
        "file": { # File upload must includes path of file, name is optional
          "path": "/tmp/my_avatar.jpg",
          "name": "thanh_avatar"
        }
      }
    vars:
      status: ${this.$.response.status}

http'put

Send a http request with PUT method

Example:

Update data to API then store value in vars.posts

  # PUT http://localhost:3000/posts/ID?category=users
  - name: Update a post
    http'put:
      baseURL: http://localhost:3000
      url: /posts/ID
      query:
        category: users
      headers:
        authorization: Bearer TOKEN
      type: json                      # 'json' | 'form' | 'raw' | 'multipart' | 'text'
      timeout: 5000                   # !optional - Request timeout. Default is no timeout
      body: {
        "title": "My title",
        "description": "My description"
      }
      responseType: json              # 'json' | 'blob' | 'text' | 'buffer' | 'none'
      validStatus: [200, 204, 400]    # !optional - Expect these response status codes is success and not throw error
    vars: newPost

Upload file to server

  # PUT http://localhost:3000/upload/ID_UPLOADER_TO_REPLACE
  - name: Upload and update data
    http'put:
      baseURL: http://localhost:3000
      url: /upload/ID_UPLOADER_TO_REPLACE
      headers:
        authorization: Bearer TOKEN
      type: multipart
      body: {
        "category": "avatar updated",
        "file": { # File upload must includes path of file, name is optional
          "path": "/tmp/new_my_avatar.jpg",
          "name": "thanh_avatar"
        }
      }
    vars:
      status: ${this.$.response.status}

http'server

Create a http server to serve content via http

Example:

  - http'server:
      address: 0.0.0.0:8811                   # Address to listen
      auth:                                   # Check authentication
        basic:                                # 'Basic ' + base64(`${username}:${password}`)
          username: username
          password: password
        custom:
          secret: 'SERVER_SECRET_TOKEN'
          secretKey: SECRET_HEADER_KEY
          onCheck: |
            return $ws().headers[this.secretKey] === this.secret
      // cors: {}                           # enable all cors requests
      cors:                                 # Ref: https://www.npmjs.com/package/cors#configuring-cors
        origin: '*'
        methods: ['GET', 'HEAD', 'PUT', 'PATCH', 'POST', 'DELETE']
        allowedHeaders: ['Content-Type', 'Authorization']
        exposedHeaders: ['Content-Range', 'X-Content-Range']
        credentials?: boolean | undefined;
        maxAge?: number | undefined;
        preflightContinue: false
        optionsSuccessStatus: 204
      opts:
        timeout: 0                          # The number of milliseconds of inactivity before a socket is presumed to have timed out.
        keepAliveTimeout: 0                 # The number of milliseconds of inactivity a server needs to wait for additional incoming data, after it has finished writing the last response, before a socket will be destroyed
        headersTimeout: 0                   # Limit the amount of time the parser will wait to receive the complete HTTP headers.
        maxConnections: 0                   # Set this property to reject connections when the server's connection count gets high.
        maxHeadersCount: 0                  # Limits maximum incoming headers count. If set to 0, no limit will be applied.
        maxRequestsPerSocket: 0             # The maximum number of requests socket can handle before closing keep alive connection.
        requestTimeout: 0                   # Sets the timeout value in milliseconds for receiving the entire request from the client.
    runs:                                   # Execute when a request comes
      - echo: ${ $ws().httpRequest.path }     # Get request path
      - echo: ${ $ws().httpRequest.method }   # Get request method
      - echo: ${ $ws().httpRequest.headers }  # Get request headers
      - echo: ${ $ws().httpRequest.query }    # Get request query string
      - echo: ${ $ws().httpRequest.body }     # Get request body
      - echo: ${ $ws().httpRequest.response } # Set response data
                                            # - status: 200       - http response status
                                            # - statusMessage: OK - http response status message
                                            # - headers: {}       - Set response headers
                                            # - data: {}          - Set response data
      - echo: ${ $ws().httpRequest.req }      # Ref to req in http.IncomingMessage in nodejs
      - echo: ${ $ws().httpRequest.res }      # Ref to res in http.ServerResponse in nodejs
      - js: |                               # Handle response by yourself (When $ws().response is undefined)
          $ws().httpRequest.res.status = 200
          $ws().httpRequest.res.statusMessage = 'OK'
          $ws().httpRequest.res.write('OK')
          $ws().httpRequest.res.end()

include

Include a scene file or list scene files in a folder

Example:

  - include: ./my-scenes/scene1.yaml                    # Includes a only file "scene1.yaml"

  - include:
      cached: true                                      # Load file for the first time, the next will get from caches
      files: ./my-scenes                                # Includes all of files (.yaml, .yml) which in the directory (./my-scenes)
      validFilePattern: ^[a-zA-Z0-9].*?\.stack\.ya?ml$  # Only load files which ends with .stack.yaml
      validDirPattern: ^[a-zA-Z0-9]                     # Only scan files in these valid directories
      maxDeepLevel: 0                                   # Max deep child directories to scan files

  - include:
      - file1.yaml
      - file2.yaml
      - file3.yaml

  - include:
      cached: true
      files:
        - file1.yaml
        - file2.yaml
        - file3.yaml

input'confirm

Get user confirm (yes/no)

Example:

# - input'conf:
  - input'confirm:
      title: Are you sure to delete it ?
      default: false  # !optional
      required: true  # !optional
    vars: userWantToDelete

input'multiselect

Suggest a list of choices for user then allow pick multiple choices

Example:

# - input'msel:
  - input'multiselect:
      title: Please select your hobbies ?
      choices:
        - title: Tennis
          value: tn
        - title: Football
          value: fb
        - title: Basket ball
          value: bb
      default: [tn, fb]   # !optional
      required: true      # !optional
    vars: hobbies

input'number

Get user input from keyboard then convert to number

Example:

# - input'num:
  - input'number:
      title: Enter your age ?
      default: 18     # !optional
      required: true  # !optional
    vars: age

input'password

Get user input from keyboard but hide them then convert to text

Example:

# - input'pwd:
  - input'password:
      title: Enter your password ?
      required: true  # !optional
    vars: password

input'select

Suggest a list of choices for user then allow pick a choice

Example:

# - input'sel:
  - input'select:
      title: Your sex ?
      choices:
        - title: male
          value: m
        - title: female
          value: f
      default: m      # !optional
      required: true  # !optional
    vars: sex

input'suggest

Suggest a list of choices for user then allow pick a choice or create a new one

Example:

# - input'sug:
  - input'suggest:
      title: Your hobby
      choices:
        - title: Football
          value: football
        - title: Basket Ball
          value: backetball
      default: football