├── .github ├── FUNDING.yml └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── README.md ├── archived ├── bridge.html ├── connections.html ├── cpu.html ├── cron.html ├── hdd.html ├── memory.html ├── middlewareexec.html ├── middlewarefunction.html ├── process.html ├── qrgenerator.html ├── rabbitmqconnection.html ├── rabbitmqconsume.html ├── rabbitmqpublish.html ├── range.html ├── restapirouter.html ├── restcors.html ├── restdatabase.html ├── restproxyroute.html ├── restredirect.html ├── restremember.html ├── restresponse.html ├── restroute.html ├── restsql.html ├── resttokenauth.html ├── restworkflow.html ├── rpi-ds18b20.html ├── rpi-gpio.html ├── rpi-i2c-read.html ├── rpi-i2c-write.html ├── rpi-uart-getdevices.html ├── rpi-uart.html └── tail.html ├── components ├── chatgpt.html ├── cheerio.html ├── code.html ├── comment.html ├── confirmation-code.html ├── consolelog.html ├── counter.html ├── crontab.html ├── csvdataset.html ├── dataparser.html ├── datasorter.html ├── date.html ├── debug.html ├── delay.html ├── downloader.html ├── duration.html ├── end.html ├── error.html ├── exec.html ├── extend.html ├── feedtodelay.html ├── filewatcher.html ├── filewriter.html ├── flashback.html ├── flowrecorder.html ├── forward.html ├── googlesearch.html ├── influxdb.html ├── input.html ├── jsonschemavalidator.html ├── kill.html ├── livestats.html ├── localstorage.html ├── logger.html ├── macro.html ├── map-array.html ├── merge.html ├── merginputs.html ├── minutely.html ├── model.html ├── modified.html ├── modify.html ├── mongodb-insert.html ├── mongodb-query.html ├── mqtt-broker.html ├── mqtt-publish.html ├── mqtt-subscribe.html ├── mysql.html ├── nosql.html ├── notify.html ├── oauth2.html ├── object.html ├── opensync.html ├── openweather.html ├── output.html ├── postgresql.html ├── print.html ├── printjson.html ├── publish.html ├── qrcode.html ├── querybuilderpg.html ├── queue.html ├── read.html ├── renderer.html ├── request.html ├── rssreader.html ├── schema.html ├── script.html ├── secrets.html ├── sendandwait.html ├── serverextension.html ├── sms.html ├── snapshot.html ├── split.html ├── sqlite3.html ├── stepper.html ├── stopwatch.html ├── stringoperations.html ├── subscribe.html ├── switch.html ├── taction.html ├── tangular.html ├── tapicaptchaapi.html ├── tapichatgptapi.html ├── tapicheckapi.html ├── tapicheckvatapi.html ├── tapiconvertapi.html ├── tapiexchangeratesapi.html ├── tapigeoipapi.html ├── tapiinvoiceparserapi.html ├── tapiocrapi.html ├── tapiplatenumber.html ├── tapiprintapi.html ├── tapirouter.html ├── tapismsapi.html ├── tapiweatherapi.html ├── tauthtoken.html ├── tcors.html ├── telemetry.html ├── teleport.html ├── throttle.html ├── timeout.html ├── timer.html ├── tlogger.html ├── totp.html ├── transform.html ├── transformer.html ├── tredirect.html ├── tremember.html ├── tresponse.html ├── trigger.html ├── troute.html ├── tsql.html ├── tuploadedfiles.html ├── twebsocketroute.html ├── vs.html └── xmlparser.html ├── db.js ├── db.json ├── package.json ├── tester.js └── tests ├── counter.js ├── example-multiple.js ├── example.js ├── influxdb.js ├── readme.md ├── sqlite3.js ├── test.js └── trigger.js /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: totaljs 4 | open_collective: totalplatform 5 | ko_fi: totaljs 6 | liberapay: totaljs 7 | buy_me_a_coffee: totaljs 8 | custom: https://www.totaljs.com/support/ 9 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Upload to KeyCDN 2 | 3 | on: workflow_dispatch 4 | 5 | jobs: 6 | ftp-upload: 7 | name: 🎉 Upload 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: 🚚 Get latest code 11 | uses: actions/checkout@v2 12 | 13 | - uses: actions/setup-node@v3 14 | with: 15 | node-version: '14' 16 | 17 | - name: Update db.json and move it all to ./build/ 18 | run: | 19 | mkdir dist 20 | mkdir dist/components 21 | cp components/* dist/components 22 | npm install total4 23 | node db.js 24 | cp db.json dist/components/db.json 25 | ls dist/components -la 26 | 27 | - name: FTP Deployer 28 | uses: sand4rt/ftp-deployer@v1.3 29 | with: 30 | host: ${{ secrets.KEYCDN_SERVER }} 31 | username: ${{ secrets.KEYCDN_USERNAME }} 32 | password: ${{ secrets.KEYCDN_PASSWORD }} 33 | remote_folder: /flowstream/webcomponents 34 | local_folder: dist/components # optional, local path, default is: dist 35 | 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | tests/package-lock.json 4 | tests/package.json 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2023 Total.js 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Total.js Flow components 2 | 3 | [![Made in EU](https://cdn.componentator.com/eu-small.png)](https://european-union.europa.eu/) 4 | 5 | - [Documentation](https://docs.totaljs.com) 6 | - [Join Total.js Telegram](https://t.me/totaljs) 7 | - [Support](https://www.totaljs.com/support/) 8 | 9 | This repository contains open-source __Total.js Flow components__. Please keep: 10 | 11 | - [Our coding standards and guidelines](https://docs.totaljs.com/welcome/67b47001ty51c/) 12 | 13 | ## Run unit-test for all tests 14 | 15 | - open terminal/command-line 16 | - `$ cd flowstreamcomponents` 17 | - `$ npm install total4` (only once) 18 | - `$ node tester.js` 19 | 20 | ## Contact 21 | 22 | - 23 | - www.totaljs.com -------------------------------------------------------------------------------- /archived/connections.html: -------------------------------------------------------------------------------- 1 | 56 | 57 | 58 | This component monitors open connections to the specific port in the Linux systems for the specific process. It uses `netstat` command. 59 | 60 | __Data Example__: 61 | 62 | ```js 63 | { 64 | port: 80, 65 | connections: 54 66 | } 67 | ``` 68 | 69 | 70 | 75 | 76 | 77 |
78 |
79 |
80 | Port number 81 |
82 |
83 | Interval 84 |
In seconds
85 |
86 |
87 |
88 |
89 | 90 | 91 |
92 | NAME 93 |
94 | 100 | -------------------------------------------------------------------------------- /archived/cpu.html: -------------------------------------------------------------------------------- 1 | 63 | 64 | 65 | This component monitors CPU `% percentage` consumption in the Linux systems. It uses `mpstat` command with 10 seconds interval. 66 | 67 | __Data Example__: 68 | 69 | ```js 70 | { 71 | cpu: 30, // percentage 72 | cores: [4, 60, 0], // percentage 73 | count: 3 // count of cores 74 | } 75 | ``` 76 | 77 | 78 | 83 | 84 | 85 |
86 | NAME 87 |
88 | 91 | -------------------------------------------------------------------------------- /archived/hdd.html: -------------------------------------------------------------------------------- 1 | 58 | 59 | 60 | This component monitors HDD consumption (in MB) in the Linux systems. It uses `df` command. 61 | 62 | __Data Example__: 63 | 64 | ```js 65 | { 66 | free: 0, 67 | total: 0, 68 | used: 0 69 | } 70 | ``` 71 | 72 | 73 | 78 | 79 | 80 |
81 |
82 |
83 | Interval 84 |
In seconds
85 |
86 |
87 | Path 88 |
89 |
90 |
91 |
92 | 93 | 94 |
95 | NAME 96 |
97 | 106 | -------------------------------------------------------------------------------- /archived/memory.html: -------------------------------------------------------------------------------- 1 | 48 | 49 | 50 | This component monitors a memory consumption (in MB) in the Linux systems. It uses `free` command. 51 | 52 | __Data Example__: 53 | 54 | ```js 55 | { 56 | free: 0, 57 | total: 0, 58 | used: 0 59 | } 60 | ``` 61 | 62 | 63 | 68 | 69 | 70 |
71 |
72 |
73 | Interval 74 |
In seconds
75 |
76 |
77 |
78 |
79 | 80 | 81 |
82 | NAME 83 |
84 | 93 | -------------------------------------------------------------------------------- /archived/middlewareexec.html: -------------------------------------------------------------------------------- 1 | 43 | 44 | 45 | This component executes a custom JavaScript code as it is. 46 | 47 | 48 | 57 | 58 | 59 |
60 | Name 61 |
62 |
63 | 64 | 65 |
66 | NAME 67 |
68 | -------------------------------------------------------------------------------- /archived/middlewarefunction.html: -------------------------------------------------------------------------------- 1 | 42 | 43 | 44 | The code defined in this component can be executed by multiple `Middleware Exec`. 45 | **Example:** 46 | ```js 47 | // available arguments 48 | // instance {FlowStreamComponent} 49 | // $ {FlowStreamMessage} 50 | // data reference to $.data 51 | // repo reference to $.repo 52 | // vars reference to instance.main.variables 53 | 54 | if (data.headers['x-token'] === instance.main.variables.token) 55 | // data will be send to `Output` output of `Middleware Exec` component 56 | callback(null, data); 57 | else 58 | // data will be send to `Error` output of `Middleware Exec` component 59 | callback('an error occured'); 60 | ``` 61 | 62 | 63 | 64 |
65 | Name 66 |
Code
67 | 68 |
69 |
70 | 71 | 74 | 75 | 76 |
77 | NAME 78 |
79 | 80 | -------------------------------------------------------------------------------- /archived/qrgenerator.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 80 | ## Input 81 | 82 | ```js 83 | { 84 | text: 'text to write to qr code', 85 | filename: '/public/img/', // optionaly writes the file to filesystem 86 | ... 87 | } 88 | ``` 89 | ## Output 90 | 91 | ```js 92 | { 93 | text: 'text to write to qr code', 94 | ... 95 | _qrcode: 'base64 encoded buffer' 96 | } 97 | ``` 98 | 99 | 100 | 101 |
102 | NAME 103 |
104 | -------------------------------------------------------------------------------- /archived/range.html: -------------------------------------------------------------------------------- 1 | 56 | 57 | 58 | 59 | 60 | 61 | 62 |
63 | Property (unless the data is the value itself) 64 |
65 |
66 | Input min (defaults to 0) 67 |
68 |
69 | Input max (defaults to 1023) 70 |
71 |
72 |
73 |
74 | Output min (defaults to 0) 75 |
76 |
77 | Output max (defaults to 100) 78 |
79 |
80 |
81 |
82 | Round output 83 |
84 |
85 |
86 |
87 | 88 | 91 | 92 | 95 | 96 | 97 |
98 | NAME 99 |
100 | 101 | -------------------------------------------------------------------------------- /archived/restcors.html: -------------------------------------------------------------------------------- 1 | 32 | 33 | 34 | The component enables Cross-Origin Resource Sharing `CORS`, so the web browser will be able to communicate directly with the REST API. The functionality will work only with a defined Proxy endpoint for this Flow. 35 | 36 | 37 | 38 |
39 | Hostnames with a protocol 40 |
41 |
42 | 43 | 44 |
45 | 46 |
CORS enabled
47 |
48 | -------------------------------------------------------------------------------- /archived/restproxyroute.html: -------------------------------------------------------------------------------- 1 | 47 | 48 | 49 | This component registers an HTTP Proxy route and sends request metadata next. 50 | 51 | < __IMPORTANT__:
The component works only with a defined Proxy endpoint in the Flow settings. 52 | < __URL__:
The URL must be relative to the defined Proxy endpoint. So if the endpoint is `/users/` and the desired address is `http://example.com/users/find` then the value must be `/find` 53 | 54 | __Output data__: 55 | 56 | ```js 57 | { 58 | "query": Object, 59 | "headers": Object, 60 | "url": String, 61 | "ip": String 62 | } 63 | ``` 64 |
65 | 66 | 67 |
68 |
69 |
70 |
No proxy endpoint defined.
This component will not work until then. Please go to main screen, open settings of this FlowStream instance and set the Endpoint.
71 |
72 |
73 |
74 |
75 | Relative URL address 76 |
Relative path to:
77 |
78 |
79 | Proxy address 80 |
81 |
82 |
83 |
84 | Timeout 85 |
86 |
87 |
88 |
89 | 90 | 93 | 94 | 95 |
96 | NAME 97 |
98 | 99 | -------------------------------------------------------------------------------- /archived/restredirect.html: -------------------------------------------------------------------------------- 1 | 31 | 32 | 33 | ## Input 34 | 35 | Incomming data have higher priority than the values set in the Configuration form. Both the `url` and `permanent` are optional. 36 | 37 | ```js 38 | { 39 | url: 'https://example.com', 40 | permanent: true|false 41 | } 42 | ``` 43 | 44 | 45 | 46 |
47 |
Redirect URL address supports dynamic variables in the form {key} or {data.key}. Variables are read from global variables {key} and from the message data {data.key}.
48 | Redirect URL 49 | Permanent redirect 50 |
51 |
52 | 53 | 56 | 57 | 58 |
59 | NAME 60 |
61 | 64 | -------------------------------------------------------------------------------- /archived/restremember.html: -------------------------------------------------------------------------------- 1 | 46 | 47 | 48 | The primary goal of this component is to remember data. The component contains two inputs: 49 | 50 | - Remember input for remembering data 51 | - Request input as a trigger for obtaining data, then remembered data would extend the request message (its data), and the component will send it to the Response output 52 | 53 | 54 | 55 |
56 | NAME 57 |
58 | 59 | 60 | 61 |
62 | Set remembered data to the specific property/field 63 |
If you don't enter the property, the remembered data will replace data on the Request input.
64 |
65 |
-------------------------------------------------------------------------------- /archived/restresponse.html: -------------------------------------------------------------------------------- 1 | 42 | 43 | 44 | This component can respond on the REST Route component. 45 | 46 | 47 | 48 |
49 |
50 |
51 | Type 52 |
53 |
54 | Status code 55 |
56 |
57 |
58 |
59 | 60 | 65 | 66 | 67 |
68 | NAME 69 | 70 | 71 |
72 | -------------------------------------------------------------------------------- /archived/restsql.html: -------------------------------------------------------------------------------- 1 | 40 | 41 | 42 | The component executes SQL command on the specifi connection. This component depends on the `API PostgreSQL` component. 43 | 44 | 45 | 46 |
47 |
Connection and SQL query support dynamic variables in the form {key} or {data.key}. Variables are read from global Variables {key} and from the message data {data.key}. The component encodes all SQL values with except {!key}.
48 |
49 |
50 | Connection 51 |
A connection name/identifier
52 |
53 |
54 | Assign data according to the path 55 |
Otherwise, the response will replace the entire message data.
56 |
57 |
58 | Return only the first row 59 |
60 |
SQL query:
61 | 62 |
63 |
64 | 65 | 68 | 69 | 70 |
71 | NAME 72 |
73 | 78 | -------------------------------------------------------------------------------- /archived/rpi-gpio.html: -------------------------------------------------------------------------------- 1 | 65 | 66 | 67 | # GPIO 68 | 69 | __Write mode__: 70 | 71 | - Select the GPIO you want 72 | - Set the read/write option to write 73 | - Send true to the component to set the GPIO to HIGH 74 | - Send false to the component to set the GPIO to LOW 75 | 76 | __Read mode__: 77 | 78 | - Select the GPIO you want 79 | - Set the read/write option to write 80 | - Send true to the node so read the state of the gpio 81 | 82 | 83 | 84 |
85 | GPIO 86 | read/write 87 |
88 |
89 | 90 | 91 |
92 | Raspberry GPIO 93 |
94 | -------------------------------------------------------------------------------- /archived/rpi-i2c-read.html: -------------------------------------------------------------------------------- 1 | 52 | 53 | 54 | # I2C Read 55 | 56 | Parameters, can be transmitted to the component, or directly set as setting. 57 | 58 | - `address`: The I2C address of the device 59 | - `register`: The (starting) register 60 | - `readLength`: The length of how many bits will be read 61 | 62 | 63 | 64 |
65 |
66 | Predefined Sensor 67 |
68 |
69 | 70 | Sensor 71 | 72 | 77 |
78 |
79 | 80 | 81 |
82 | Raspberry I2C Read 83 |
84 | -------------------------------------------------------------------------------- /archived/rpi-i2c-write.html: -------------------------------------------------------------------------------- 1 | 40 | 41 | 42 | # I2C Write 43 | 44 | Parameters, can be transmitted to the component, or directly set as setting. 45 | 46 | - `address`: The I2C address of the device 47 | - `register`: The (starting) register 48 | - `bytes`: The bytes which will be written 49 | 50 | 51 | 52 |
53 | Address 54 | Register 55 | Data 56 |
57 |
58 | 59 | 60 |
61 | Raspberry I2C Write 62 |
63 | -------------------------------------------------------------------------------- /archived/rpi-uart-getdevices.html: -------------------------------------------------------------------------------- 1 | 22 | 23 | 24 | # UART 25 | 26 | Get all devices which are possible to send 27 | 28 | 29 | 34 | 35 | 44 | 45 | 46 |
47 | Raspberry UART Devices 48 |
49 |
50 | 51 |
52 | -------------------------------------------------------------------------------- /archived/rpi-uart.html: -------------------------------------------------------------------------------- 1 | 65 | 66 | 69 | 70 | 71 | # UART 72 | 73 | - send a string directly to a port 74 | - when device from a port sends data to the host, it will be send to the output of the component 75 | 76 | 77 | 78 |
79 | PORT 80 | Baudrate 81 | Databits 82 | Parity 83 | Stop Bits 84 |
85 |
86 | 87 | 88 |
89 | Raspberry UART 90 |
91 | 100 | 101 | -------------------------------------------------------------------------------- /archived/tail.html: -------------------------------------------------------------------------------- 1 | 54 | 55 | 56 | This component monitors last line in some text file with the help of `tail` command in the Linux systems. 57 | 58 | __Data Example__: 59 | 60 | ```js 61 | { 62 | value: 'Some meessage' 63 | date: Date 64 | } 65 | ``` 66 | 67 | 68 | 71 | 72 | 73 |
74 | Path 75 |
76 |
77 | 78 | 79 |
80 | NAME - 81 |
82 | 90 | -------------------------------------------------------------------------------- /components/comment.html: -------------------------------------------------------------------------------- 1 | 15 | 16 | 17 |
18 | 19 |
Supports Markdown
20 |
21 |
22 | 23 | 29 | 30 | 31 | This component renders a small markdown comment inside the body. 32 | 33 | 34 | 35 |
36 | 37 | NAME 38 |
39 | 40 | 41 | 42 | 53 | -------------------------------------------------------------------------------- /components/consolelog.html: -------------------------------------------------------------------------------- 1 | 20 | 21 | 22 | This component prints a message into the console. 23 | 24 | 25 | 26 |
27 | NAME 28 |
29 | -------------------------------------------------------------------------------- /components/counter.html: -------------------------------------------------------------------------------- 1 | 34 | 35 | 39 | 40 | 41 | The component counts incoming messages. 42 | 43 | 44 | 45 |
46 | 47 | NAME 48 |
49 | 57 | -------------------------------------------------------------------------------- /components/dataparser.html: -------------------------------------------------------------------------------- 1 | 61 | 62 | 63 | The component can parse newline data or begin/end phrases in the buffer or string. In addition, it can help with parsing XML or CSV files. 64 | 65 | 66 | 67 |
68 | 69 |
70 | 71 | CSV 72 |
73 |
74 | 75 | XML 76 |
77 |
78 | Convert parsed value to the object 79 |
80 |
81 | 94 |
95 | 96 | 100 | 101 | 102 |
103 | NAME 104 |
105 | 112 | -------------------------------------------------------------------------------- /components/date.html: -------------------------------------------------------------------------------- 1 | 32 | 33 | 34 | The component will return a Date/Time object (raw or formatted) according to its configuration. 35 | 36 | 37 | 38 |
39 | Date format 40 |
Empty value will return current datetime object.
41 |
42 |

43 | d - day e.g. 1
44 | dd - day e.g. 01
45 | ddd - day (named). MO
46 | dddd - day (named). Monday
47 | M - month e.g. 1
48 | MM - month e.g. 01
49 | MMM - month (named). Jan
50 | MMMM - month (named). January
51 | yy - year e.g. 16
52 | yyyy - year e.g. 2016
53 | w - week number e.g. 1
54 | ww - week number e.g. 01
55 | H - hour e.g. 1
56 | HH - hour e.g. 01
57 | m - minute e.g. 1
58 | mm - minute e.g. 01
59 | s - second e.g. 1
60 | ss - second e.g. 01
61 | a - AM/PM 62 |

63 |
64 |
65 | 66 | 77 | 78 | 79 |
80 | NAME 81 |
82 |
83 | 84 |
85 | 86 | -------------------------------------------------------------------------------- /components/delay.html: -------------------------------------------------------------------------------- 1 | 69 | 70 | 82 | 83 | 84 |
85 |
86 |
87 | Delay 88 |
In milliseconds
89 |
90 |
91 |
92 |
93 | 94 | 95 | The component delays processing of a message. 96 | 97 | 98 | 99 |
100 | NAME 101 |
102 |
103 | 104 |
105 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /components/duration.html: -------------------------------------------------------------------------------- 1 | 52 | 53 | 54 | The component counts message duration. All values except `count` are defined in seconds. 55 | 56 | __Output__: 57 | 58 | ```js 59 | { 60 | min: Number, 61 | max: Number, 62 | avg: Number, 63 | last: Number, 64 | count: Number 65 | } 66 | ``` 67 | 68 | 69 | 74 | 75 | 76 |
77 | NAME 78 |
79 | 106 | -------------------------------------------------------------------------------- /components/end.html: -------------------------------------------------------------------------------- 1 | 20 | 21 | 22 | The component destroys the incoming message. 23 | 24 | 25 | 26 |
27 | NAME 28 |
29 | -------------------------------------------------------------------------------- /components/error.html: -------------------------------------------------------------------------------- 1 | 43 | 44 | 45 | This component transforms incoming data to the Total.js Error structure. 46 | 47 | 48 | 49 |
50 | $NAME 51 |
52 | -------------------------------------------------------------------------------- /components/exec.html: -------------------------------------------------------------------------------- 1 | 20 | 21 | 22 | The component is extraordinary because it must be executed directly from the source code via the `flowstream.exec()` method. The component triggers received data into the Flow. 23 | 24 | ```js 25 | var opt = {}; 26 | opt.id = 'ID_OF_EXEC_INSTANCE'; 27 | opt.data = { custom: 'data' }; 28 | opt.callback = function(err, msg) { 29 | // msg.uid; 30 | // msg.ref; 31 | // msg.repo {Object} 32 | // msg.data {Object} 33 | // msg.cloned {Number} how many times was the message cloned? 34 | // msg.duration {Number} in milliseconds 35 | }; 36 | 37 | // optional: 38 | // opt.vars = {}; --> custom variables 39 | // opt.repo = {}; --> custom repository data and this data will be returned in the callback 40 | // opt.uid; --> for storing some unique ID 41 | // opt.ref; --> for storing some reference ID 42 | flowinstance.exec(opt); 43 | ``` 44 | 45 | 46 | 47 |
48 | NAME 49 |
50 | -------------------------------------------------------------------------------- /components/filewriter.html: -------------------------------------------------------------------------------- 1 | 76 | 77 | 78 |
79 | Path 80 |
Absolute path to the file. The path starts with the ~ char will use a filename in the project's root directory.
81 | Serializer 82 | Rewrite content 83 | 91 |
92 |
93 | 94 | 95 | The component writes incoming data into the file. 96 | 97 | 98 | 102 | 103 | 104 |
105 | NAME 106 |
107 | 113 | -------------------------------------------------------------------------------- /components/forward.html: -------------------------------------------------------------------------------- 1 | 22 | 23 | 24 | The component send message next only. It's targeted for colorized connections to targeted to the same input. 25 | - The data will Flow only from input a specific color (except black) 26 | - The color black is a universal color and it will transport everything 27 | 28 | 29 | 32 | 33 | 34 |
35 | NAME 36 |
37 | -------------------------------------------------------------------------------- /components/googlesearch.html: -------------------------------------------------------------------------------- 1 | 35 | 36 | 37 | This component can google any keyword you want. 38 | 39 | 40 | __Configuration__ 41 | 42 | - `Language (optional)` : Search language; 43 | - `Limit (optional)` : Limit number of results. 44 | 45 | __Input__ 46 | 47 | - `Object` | String : input expects `data: String` or `data.text: String` as search keywords. 48 | 49 | 50 | __Output__ 51 | 52 | - `Array` of found results: 53 | 54 | 55 | 56 |
57 |
58 | Results limit 59 | Language 60 |
61 |
62 |
63 | 64 |
65 | NAME 66 |
67 | -------------------------------------------------------------------------------- /components/input.html: -------------------------------------------------------------------------------- 1 | 22 | 23 | 24 |
25 | Input name 26 | Readme 27 |
Supports markdown format
28 |
29 |
30 | 31 | 32 | The component receives data in an encapsulated FlowStream. 33 | 34 | 35 | 36 |
37 | NAME: 38 |
39 | -------------------------------------------------------------------------------- /components/jsonschemavalidator.html: -------------------------------------------------------------------------------- 1 | 45 | 46 | 47 | [JSON schema documentation](https://json-schema.org/learn/getting-started-step-by-step.html) 48 | 49 | ## Inputs 50 | 51 | - `input` validates data and send the result to output if no error, otherwise send error to error output 52 | - `schema` reads the schema and send it to the schema output 53 | 54 | 55 | 56 |
57 | JSON schema 58 |
59 |
60 | 61 | 62 |
63 | NAME 64 |
65 | -------------------------------------------------------------------------------- /components/kill.html: -------------------------------------------------------------------------------- 1 | 21 | 22 | 23 | Be careful because this component will kill the current Flow instance. It's targeted only for exceptional cases. 24 | 25 | 26 | 27 |
28 | NAME 29 |
30 | -------------------------------------------------------------------------------- /components/macro.html: -------------------------------------------------------------------------------- 1 | 39 | 40 | 41 | The macro component uses Total.js Macro language that allows you to write much simple code like in JavaScript. Macros are targeted for small data transformation. 42 | 43 | - you don't need to solve Upper/Lower case 44 | - `return EXPRESSION` will return data and send them next 45 | - `data` keyword contains a message data 46 | - `temp` keyword can contain a persistent temporary data 47 | 48 | __Example__: 49 | 50 | ```text 51 | IF DATA>20 AND DATA<35 52 | RETURN DATA * 5 53 | FI 54 | ``` 55 | 56 | 57 | 58 |
59 | Clear temporary data 60 | 61 | 62 |
63 |
64 | 65 | 66 |
67 | NAME 68 |
69 | -------------------------------------------------------------------------------- /components/merge.html: -------------------------------------------------------------------------------- 1 | 71 | 72 | 73 | The component merges incoming data into an array. 74 | 75 | 76 | 77 |
78 |
79 |
80 | Limit 81 |
0 means disabled
82 |
83 |
84 | Timeout 85 |
In milliseconds. 0 means disabled
86 |
87 |
88 |
89 |
90 | 91 | 94 | 95 | 96 |
97 | $NAME 98 |
99 | 102 | -------------------------------------------------------------------------------- /components/minutely.html: -------------------------------------------------------------------------------- 1 | 67 | 68 | 73 | 74 | 83 | 84 | 85 |
86 | Type 87 | 96 |
97 |
98 | 99 | 100 | The component triggers data into the Flow in every minute. 101 | 102 | 103 | 104 |
105 | NAME 106 |
107 |
108 | 109 |
110 | -------------------------------------------------------------------------------- /components/modified.html: -------------------------------------------------------------------------------- 1 | 79 | 80 | 90 | 91 | 96 | 97 | 98 | The component compares incoming data with previous data. 99 | 100 | 101 | 102 |
103 | 104 | NAME 105 |
106 | 115 | -------------------------------------------------------------------------------- /components/mqtt-publish.html: -------------------------------------------------------------------------------- 1 | 49 | 50 | 51 | MQTT Publish 52 | 53 | Input: 54 | ```javascript 55 | { 56 | topic: 'some/topic', 57 | message: { some: 'data' }, 58 | // optional 59 | options: { 60 | qos: 0|1|2, 61 | retain: true|false 62 | } 63 | } 64 | ``` 65 | 66 | 67 | 72 | 73 | 80 | 81 | 82 |
83 |
84 |
85 | Broker 86 |
87 |
88 |
89 |
90 | 91 | 92 |
93 | NAME 94 |
95 | 102 | 103 | -------------------------------------------------------------------------------- /components/mqtt-subscribe.html: -------------------------------------------------------------------------------- 1 | 60 | 61 | 62 | MQTT Subscribe 63 | 64 | 65 | 70 | 71 | 78 | 79 | 80 |
81 |
82 |
83 | Broker 84 |
85 |
86 |
87 |
88 | Topic 89 |
90 |
91 |
92 |
93 |

94 | The topic supports wildcards like:
95 | - devices/+/status -> devices/1/status or devices/123456/status etc.
96 | - devices/# -> any topic begining with devices/....... 97 |

98 |
99 |
100 |
101 |
102 | 103 | 104 |
105 | NAME 106 |
107 | 115 | -------------------------------------------------------------------------------- /components/mysql.html: -------------------------------------------------------------------------------- 1 | 79 | 80 | 81 | ## Input 82 | 83 | Expected data: 84 | 85 | ```javascript 86 | { 87 | query: 'SELECT * FROM tblname;' 88 | } 89 | ``` 90 | 91 | 92 | 93 |
94 |
95 |
96 | Connection string 97 |
e.g.: mysql://user:password@localhost:3306/dbname
98 |
99 |
100 |
101 |
102 | 103 | 106 | 107 | 108 |
109 | NAME 110 |
111 | 114 | -------------------------------------------------------------------------------- /components/notify.html: -------------------------------------------------------------------------------- 1 | 38 | 39 | 40 | This component captures data on the `/notify/` endpoint. 41 | 42 | __Output data__: 43 | 44 | ```js 45 | { 46 | "method": String, 47 | "query": Object, 48 | "body": Object, 49 | "headers": Object, 50 | "cookies": Object, 51 | "url": String, 52 | "ip": String 53 | } 54 | ``` 55 | 56 | 57 | 60 | 61 | 62 |
63 |
64 |
65 | HTTP Method 66 |
67 |
68 | Send to output 69 |
70 |
71 |
72 |
73 | 74 | 75 |
76 | $NAME 77 |
78 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /components/object.html: -------------------------------------------------------------------------------- 1 | 77 | 78 | 79 | The component creates an object from the defined string (Tangular) template. With the help of the Tangular template engine, you can use conditions, loops, etc.. 80 | 81 | __Available markup__: 82 | 83 | - `{{ data.key }}` represents data 84 | - `{{ variables.key }}` represents local and global Flow variables 85 | - `{{ hostname }}` contains a current URL address to the main Flow app `{String}` 86 | - `{{ url }}` contains a current URL address to the current Flow `{String}` 87 | - `{{ env }}` contains a current environment `{String}` 88 | 89 | 90 | 91 |
92 |

Design your object with the help of the Tangular template engine. All values are automatically transformed into JavaScript types.

93 | 94 |
95 |
96 | 97 | 98 |
99 | NAME 100 |
101 | -------------------------------------------------------------------------------- /components/opensync.html: -------------------------------------------------------------------------------- 1 | 56 | 57 | 61 | 62 | 63 | This component receives a data from the [OpenSync](https://docs.totaljs.com/opensync/) app. Data example: 64 | 65 | ```js 66 | { 67 | id: String, // Internal ID 68 | type: String, // Parsed content-type (can be empty with the "GET" method) 69 | channel: String, // Channel 70 | ip: String, // Host IP address 71 | method: String, // HTTP method (upper-case) 72 | headers: Object, // Key:value 73 | query: Object, // Key:value 74 | body: Object, // JSON/key:value/String 75 | ua: String, // Parsed user-agent 76 | files: [Object Array] // Uploaded files { filename: String, extension: String, type: String, size: Number, url: String, width: Number, height: Number } 77 | } 78 | ``` 79 | 80 | 81 | 82 |
83 | URL address + token 84 |
Enter URL address + token to the OpenSync server. This component will connect to the OpenSync via WebSocket.
85 |
86 |
87 | 88 | 89 |
90 | NAME 91 |
92 | 100 | -------------------------------------------------------------------------------- /components/output.html: -------------------------------------------------------------------------------- 1 | 22 | 23 | 24 |
25 | Output name 26 | Readme 27 |
Supports markdown format
28 |
29 |
30 | 31 | 32 | The component can send data from an encapsulated FlowStream. 33 | 34 | 35 | 36 |
37 | Output: 38 |
39 | -------------------------------------------------------------------------------- /components/postgresql.html: -------------------------------------------------------------------------------- 1 | 84 | 85 | 86 | PostgreSQL 87 | 88 | ## Input 89 | Expected data: 90 | ```javascript 91 | { 92 | query: 'SELECT * FROM tblname;' 93 | } 94 | ``` 95 | Output: 96 | ```javascript 97 | { 98 | command: 'INSERT', // SELECT, etc. 99 | rows: [], // 100 | rowCount: 1 101 | } 102 | ``` 103 | 104 | 105 | 106 |
107 |
108 |
109 | Connection string 110 |
e.g.: postgresql://user:password@localhost:5432/dbname
111 |
112 |
113 |
114 |
115 | 116 | 119 | 120 | 123 | 124 | 125 |
126 | NAME 127 |
128 | 131 | -------------------------------------------------------------------------------- /components/printjson.html: -------------------------------------------------------------------------------- 1 | 56 | 57 | 70 | 71 | 72 | The component prints incoming data in a JSON format. 73 | 74 | 75 | 76 |
77 | Shows repository 78 | Shows data 79 |
80 |
81 | 82 | 96 | 97 | 98 |
99 | 100 | NAME 101 |
102 | 105 | -------------------------------------------------------------------------------- /components/publish.html: -------------------------------------------------------------------------------- 1 | 70 | 71 | 78 | 79 | 80 |
81 | Input 82 |
83 |
84 | 85 | 86 | The component publish the data to the specific `Input` component. 87 | 88 | 89 | 90 |
91 | NAME: 92 |
93 | -------------------------------------------------------------------------------- /components/qrcode.html: -------------------------------------------------------------------------------- 1 | 36 | 37 | 38 | The component generates QR Code. 39 | 40 | __Input data__: 41 | 42 | ```js 43 | { 44 | text: String 45 | } 46 | ``` 47 | 48 | __Output data__: 49 | 50 | ```js 51 | { 52 | text: String, 53 | data: 'Data URL - BASE64' 54 | } 55 | ``` 56 | 57 | 58 | 59 |
60 | 61 |
62 |
63 | 64 | 65 |
66 | NAME 67 |
68 | -------------------------------------------------------------------------------- /components/querybuilderpg.html: -------------------------------------------------------------------------------- 1 | 46 | 47 | 48 | The component initializes QueryBuilder for the PostgreSQL database. So you can use the 'API Database` component. Each connection must be separated by an alias. 49 | 50 | __Usage in API Database__: 51 | 52 | - `tbl_user` is targeted to the `default/tbl_user` alias connection 53 | - `anotherserver/tbl_user` will use `anotherserver` alias connection 54 | 55 | 56 | 57 |
58 | Name 59 |
60 |
61 | Alias 62 |
The alias separates various DB connections
63 |
64 |
65 | Connection string 66 |
Example: postgresql://user:pass@localhost:5432/database_name
67 |
68 |
69 | Pooling 70 |
How many connections should it keep?
71 |
72 |
73 |
74 |
75 | 76 | 79 | 80 | 81 |
82 | $NAME 83 |
84 | 92 | -------------------------------------------------------------------------------- /components/renderer.html: -------------------------------------------------------------------------------- 1 | 31 | 32 | 33 | The component transforms data in HTML format in the component body. You can easily visualize any data. Data is rendered server-side. 34 | 35 | 36 | 37 |
38 |
Tangular template:
39 | 40 |
41 |
42 | 43 | 46 | 47 | 48 |
49 | NAME 50 |
51 | 54 | -------------------------------------------------------------------------------- /components/rssreader.html: -------------------------------------------------------------------------------- 1 | 83 | 84 | 88 | 89 | 90 |
91 | URL address 92 |
Example: https://blog.totaljs.com/rss/
93 | Output 94 |
95 |
96 | 97 | 98 | The component downloads every item from the RSS source. A message on to this `Trigger` input starts downloading RSS data. 99 | 100 | __Example__: 101 | 102 | ```js 103 | { 104 | title: String, 105 | description: String, 106 | link: String, 107 | image: String, // optional 108 | date: Date // optional 109 | } 110 | ``` 111 | 112 | 113 | 114 |
115 | NAME 116 |
117 |
118 | 119 |
120 | 121 | -------------------------------------------------------------------------------- /components/schema.html: -------------------------------------------------------------------------------- 1 | 34 | 35 | 36 | The component `Schema` can very quickly check incoming data according to the defined schema. 37 | 38 | __Supported types__: 39 | - `string` 40 | - `number` 41 | - `boolean` 42 | - `date` 43 | - `object` 44 | - `email` 45 | - `phone` 46 | - `zip` 47 | - `base64` 48 | - `url` 49 | - `datauri` 50 | - `json` 51 | - `lower` 52 | - `upper` 53 | - `capitalize` all words 54 | - `capitalize2` only first word 55 | - `name` makes a name (capitalizes words and remove special characters) 56 | - `zip` 57 | - `uid` 58 | - `guid` 59 | - `color` 60 | - `icon` 61 | - `search` prepares string to a search string 62 | - `safestring` checks XSS and SQL Injections 63 | - `smallint` 64 | - `tinyint` 65 | - `{A|B|C}` enum type 66 | - `[type]` means array 67 | - `{ name:String, age:Number }` means nested object 68 | - `[ name:String, age:Number ]` means array with an object 69 | - `*something:type` is `required` field 70 | 71 | 72 | 73 |
74 | Schema 75 |
76 | Allow partial data 77 | Convert errors to a string 78 |
79 |
80 | 81 | 84 | 85 | 86 |
87 | $NAME 88 |
89 | 92 | -------------------------------------------------------------------------------- /components/script.html: -------------------------------------------------------------------------------- 1 | 55 | 56 | 57 | This component executes a custom JavaScript code as it is. To send data to the default output use `send(data);` 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |
66 | $NAME 67 |
68 | -------------------------------------------------------------------------------- /components/secrets.html: -------------------------------------------------------------------------------- 1 | 42 | 43 | 44 | The component creates secret variables from the input message data. You can read data easily via `{key}` in the component's settings. Keys and their values must be of String type. 45 | 46 | ```js 47 | { 48 | key1: value1, 49 | key2: value2, 50 | keyN: valueN 51 | } 52 | ``` 53 | 54 | 55 | 58 | 59 | 60 |
61 | NAME 62 |
63 | 70 | -------------------------------------------------------------------------------- /components/sendandwait.html: -------------------------------------------------------------------------------- 1 | 46 | 47 | 50 | 51 | 52 |
53 |
54 |
55 | Interval 56 |
In minutes
57 |
58 |
59 |
60 |
61 | 62 | 63 | This component sends the data next, and then waits for a defined period. 64 | 65 | 66 | 67 |
68 | $NAME 69 |
70 | 73 | -------------------------------------------------------------------------------- /components/serverextension.html: -------------------------------------------------------------------------------- 1 | 49 | 50 | 51 | The component installs Total.js server-side extension. In other words: it can evaluate JavaScript code when the component is initialized or the component settings is changed. 52 | 53 | 54 | 55 |
56 |
57 |
58 | Name 59 |
60 |
61 | Icon 62 |
63 |
64 |
65 |
66 |
Installation code:
67 | 68 |
The code will be executed when the configuration is changed or the component instance is initialized.
69 |
Uninstallation code:
70 | 71 |
The code above will be executed when the configuration is changed or the component instance is removed.
72 |
73 |
74 | 75 | 76 | 77 | 82 | 83 | -------------------------------------------------------------------------------- /components/split.html: -------------------------------------------------------------------------------- 1 | 26 | 27 | 30 | 31 | 32 | The component splits a message with an array of objects on the input into separate messages with individual objects on the output. 33 | 34 | __Input example__: 35 | 36 | ```js 37 | [ 38 | { 39 | "email": "michal@totaljs.com", 40 | "date": 20220202, 41 | "name": "Michal Klacan" 42 | }, 43 | { 44 | "email": "martin@totaljs.com", 45 | "date": 20220204, 46 | "name": "Martin Smola" 47 | }, 48 | { 49 | "email": "peter@totaljs.com", 50 | "datum": 20220210, 51 | "name": "Peter Sirka" 52 | } 53 | ] 54 | ``` 55 | 56 | __Output example__: 57 | 58 | ```js 59 | { 60 | "email": "michal@totaljs.com", 61 | "date": 20220202, 62 | "name": "Michal Klacan" 63 | } 64 | ``` 65 | 66 | ```js 67 | { 68 | "email": "martin@totaljs.com", 69 | "date": 20220204, 70 | "name": "Martin Smola" 71 | } 72 | ``` 73 | 74 | ```js 75 | { 76 | "email": "peter@totaljs.com", 77 | "datum": 20220210, 78 | "name": "Peter Sirka" 79 | } 80 | ``` 81 | 82 | 83 | 84 |
85 | NAME 86 |
87 | 92 | 93 | 94 | 95 |
96 | Load data from the specific property/field 97 |
Optional. The data for the splitting will be loaded from the specific property/field.
98 |
99 |
-------------------------------------------------------------------------------- /components/sqlite3.html: -------------------------------------------------------------------------------- 1 | 87 | 88 | 89 | SQLite3 [Documentation](https://github.com/JoshuaWise/better-sqlite3/blob/HEAD/docs/api.md) 90 | 91 | ```js 92 | { 93 | // query 94 | prepare: 'INSERT INTO cats (name, age) VALUES (?, ?)', 95 | 96 | // function name: run, get, all, exec 97 | fn: 'run', 98 | 99 | // data, optional 100 | data: ['Joey', 2] // string/number or array 101 | 102 | } 103 | ``` 104 | 105 | __Functions:__ 106 | 107 | - [run](https://github.com/JoshuaWise/better-sqlite3/blob/HEAD/docs/api.md#runbindparameters---object) 108 | - [get](https://github.com/JoshuaWise/better-sqlite3/blob/HEAD/docs/api.md#getbindparameters---row) 109 | - [all](https://github.com/JoshuaWise/better-sqlite3/blob/HEAD/docs/api.md#allbindparameters---array-of-rows) 110 | - [exec](https://github.com/JoshuaWise/better-sqlite3/blob/HEAD/docs/api.md#execstring---this) 111 | 112 | 113 | 114 |
115 |
116 |
117 | Filename (optional) 118 |
119 |
120 |
121 |
122 | 123 | 124 |
125 | NAME 126 |
127 | -------------------------------------------------------------------------------- /components/stepper.html: -------------------------------------------------------------------------------- 1 | 54 | 55 | 67 | 68 | 69 | The component postpones incoming messages. Releasing messages must be done by hand. 70 | 71 | 72 | 73 |
74 | NAME 75 |
76 |
77 | 78 |
79 | 84 | -------------------------------------------------------------------------------- /components/stopwatch.html: -------------------------------------------------------------------------------- 1 | 72 | 73 | 80 | 81 | 82 |
83 |
84 |
85 | Name 86 |
87 |
88 | Idle time delay 89 |
90 |
91 |
92 |
93 | 94 | 95 | The component runs a simple stopwatch for incomming messages. 96 | 97 | 98 | 99 |
100 | 101 |
102 | 115 | -------------------------------------------------------------------------------- /components/stringoperations.html: -------------------------------------------------------------------------------- 1 | 64 | 65 | 66 | This components can apply string operation to your components. 67 | 68 | - input: `String` 69 | - output: `String` 70 | 71 | 72 | 73 |
74 | Operation 75 |
76 |
77 | 78 | 83 | 84 | 85 |
86 | NAME 87 |
88 | 93 | 94 | -------------------------------------------------------------------------------- /components/subscribe.html: -------------------------------------------------------------------------------- 1 | 72 | 73 | 80 | 81 | 82 |
83 | Output 84 |
85 |
86 | 87 | 88 | The component subscribes to the specific `Output` component. 89 | 90 | 91 | 92 |
93 | NAME: 94 |
95 | -------------------------------------------------------------------------------- /components/tangular.html: -------------------------------------------------------------------------------- 1 | 35 | 36 | 37 | The component uses server-side implementation of [Tangular template engine](https://docs.totaljs.com/components/40d06002lm50c/). 38 | 39 | ## Example 40 | 41 | __Incomming data__: 42 | 43 | ```js 44 | { 45 | app_name: 'Total.js Flow' 46 | } 47 | ``` 48 | 49 | __Template__: 50 | 51 | ```html 52 | App name: {{ value.app_name }} 53 | ``` 54 | 55 | - `$` type `{MessageInstance}` 56 | 57 | In the example bellow, the $.refs.controller is only available if the message was created by the Route component: 58 | 59 | ```html 60 | URL: {{ $.refs.controller.url }} 61 | ``` 62 | 63 | 64 | 65 |
66 |
Template:
67 | 68 |
69 |
70 | 71 | 72 |
73 | NAME 74 |
75 | -------------------------------------------------------------------------------- /components/tapicaptchaapi.html: -------------------------------------------------------------------------------- 1 | 58 | 59 | 60 | Captcha image generator generates a simple JPEG image. It utilizes the [Total.js Weather API](https://docs.totaljs.com/totalapi/6c221003eo51c/#Ii6INR1cR61f). 61 | 62 | __Input data:__ 63 | 64 | ```js 65 | // {String} Captcha text 66 | '123456' 67 | ``` 68 | 69 | __Output data__: 70 | 71 | ```js 72 | // Returns DataURI 73 | 'data:image/jpeg;base64,/9j/4AAQSkZ...'' 74 | 75 | ``` 76 | 77 | 78 | 79 |
80 |
81 |

Get Total.js API token.
The token field supports variables in the form {variable}.

82 | API token 83 |
84 |
85 | Path for reading input data 86 |
Optional. This component will load input data from a specific property/field according to the path.
87 |
88 |
89 |
90 |
91 |
92 | Width 93 |
94 |
95 | Height 96 |
97 |
98 |
99 | Dark mode 100 |
101 |
102 |
103 | 104 | 105 |
106 | $NAME 107 |
108 | -------------------------------------------------------------------------------- /components/tapicheckapi.html: -------------------------------------------------------------------------------- 1 | 44 | 45 | 46 | Returns a current status for your token. It utilizes the [Total.js Check API](https://docs.totaljs.com/totalapi/6c221003eo51c/#6d397001td51c). 47 | 48 | __Output data__: 49 | 50 | ```js 51 | { 52 | credits: 34.49 53 | } 54 | ``` 55 | 56 | 57 | 58 |
59 |
60 |

Get Total.js API token.
The token field supports variables in the form {variable}.

61 | API token 62 |
63 |
64 |
65 | 66 | 67 |
68 | $NAME 69 |
70 | -------------------------------------------------------------------------------- /components/tapicheckvatapi.html: -------------------------------------------------------------------------------- 1 | 54 | 55 | 56 | Determines whether is a company VAT payer or no. Works only in European Union. It utilizes the [Total.js Check VAT API](https://docs.totaljs.com/totalapi/6c221003eo51c/#6d385001lt51c). 57 | 58 | __Input data:__ 59 | 60 | ```js 61 | // {String} VAT ID 62 | 'SK2120417167' 63 | ``` 64 | 65 | __Output data__: 66 | 67 | ```js 68 | { 69 | is: true, // Is VAT Payer? 70 | vat: 20, // Country VAT 71 | name: 'Total Avengers s. r. o.', 72 | address: 'Viestova 6784/28\n97401 Banská Bystrica\nSlovensko' 73 | } 74 | ``` 75 | 76 | 77 | 78 |
79 |
80 |

Get Total.js API token.
The token field supports variables in the form {variable}.

81 | API token 82 |
83 |
84 | Path for reading input data 85 |
Optional. This component will load input data from a specific property/field according to the path.
86 |
87 |
88 |
89 | 90 | 91 |
92 | $NAME 93 |
94 | -------------------------------------------------------------------------------- /components/tapigeoipapi.html: -------------------------------------------------------------------------------- 1 | 54 | 55 | 56 | Reads GEO information from IP address. It utilizes the [Total.js GEO IP API](https://docs.totaljs.com/totalapi/6c221003eo51c/#6d381001hc51c). 57 | 58 | __Input data:__ 59 | 60 | ```js 61 | // {String} IP address 62 | "78.98.116.204" 63 | ``` 64 | 65 | __Output data__: 66 | 67 | ```js 68 | { 69 | ip: '78.98.95.176', 70 | isp: 'Slovak Telekom, a.s.', 71 | country: 'Slovakia', 72 | country_code: 'SK', 73 | region: 'Banska Bystrica', 74 | region_code: 'BC', 75 | city: 'Banská Bystrica', 76 | zip: '974 01', 77 | continent: 'Europe', 78 | continent_code: 'EU', 79 | lat: 48.804, 80 | lng: 19.1363, 81 | timezone: 'Europe/Bratislava' 82 | } 83 | ``` 84 | 85 | 86 | 87 |
88 |
89 |

Get Total.js API token.
The token field supports variables in the form {variable}.

90 | API token 91 |
92 |
93 | Path for reading input data 94 |
Optional. This component will load input data from a specific property/field according to the path.
95 |
96 |
97 |
98 | 99 | 100 |
101 | $NAME 102 |
103 | -------------------------------------------------------------------------------- /components/tapiinvoiceparserapi.html: -------------------------------------------------------------------------------- 1 | 54 | 55 | 56 | It parses meta data of the invoice from the PDF/JPG/PNG file type. It utilizes the [Total.js Invoiceparser API](https://docs.totaljs.com/totalapi/6c221003eo51c/#130w3001db51d). 57 | 58 | __Input data:__ 59 | 60 | ```js 61 | // {String} dataURI of a file 62 | "data": "data:application/pdf;base64,JVBERi0xLjcN..." 63 | ``` 64 | 65 | __Output data__: 66 | 67 | ```js 68 | { 69 | supplier: { 70 | address: 'Nádražní 44/86 15000 Praha 5', 71 | name: 'DRONPRO', 72 | vatid: 'CZ04587332' 73 | }, 74 | customer: { 75 | name: 'TOTAL AVENGERS S.R.O.', 76 | address: 'Viestova 6784/28 97401 Banská Bystrica, Slovakia', 77 | vatid: 'SK2120417167' 78 | }, 79 | date: '2023-07-17', 80 | number: '23ES04414', 81 | amount: 3445.46, 82 | total: 3445.46, 83 | currency: 'CZK', 84 | language: null, 85 | tax: 0 86 | } 87 | ``` 88 | 89 | 90 | 91 |
92 |
93 |

Get Total.js API token.
The token field supports variables in the form {variable}.

94 | API token 95 |
96 |
97 | Path for reading input data 98 |
Optional. This component will load input data from a specific property/field according to the path.
99 |
100 |
101 |
102 | 103 | 104 |
105 | $NAME 106 |
107 | -------------------------------------------------------------------------------- /components/tapiocrapi.html: -------------------------------------------------------------------------------- 1 | 55 | 56 | 57 | OCR reader for `JPG`, `PNG` or `PDF` files. It utilizes the [Total.js OCR API](https://docs.totaljs.com/totalapi/6c221003eo51c/#If83x81cy61f). 58 | 59 | __Input data:__ 60 | ```js 61 | // {String} dataURI of a file 62 | "data:image/png;base64,iVBORw0KGgo....." 63 | ``` 64 | 65 | __Output data:__ 66 | ```js 67 | { 68 | text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do...' 69 | } 70 | ``` 71 | 72 | 73 | 74 |
75 |
76 |

Get Total.js API token.
The token field supports variables in the form {variable}.

77 | API token 78 |
79 |
80 | Path for reading input data 81 |
Optional. This component will load input data from a specific property/field according to the path.
82 |
83 |
84 |
85 |
86 | Language 87 |
Can be mixed e.g. slk+eng with except pdf files.
88 |
89 |
90 |
91 | 92 | 93 |
94 | $NAME 95 |
96 | -------------------------------------------------------------------------------- /components/tapismsapi.html: -------------------------------------------------------------------------------- 1 | 57 | 58 | 59 | By using this component, you can send SMS. It utilizes the [Total.js SMS API](https://docs.totaljs.com/totalapi/6c221003eo51c/#6d220001ni51c). 60 | 61 | __Input data:__ 62 | 63 | ```js 64 | { 65 | to: "+421903163302", 66 | body: "Your message ..." 67 | } 68 | ``` 69 | 70 | __Output data__: 71 | 72 | ```js 73 | { success: true } 74 | ``` 75 | 76 | 77 | 78 |
79 |
80 |

Get Total.js API token.
The token field supports variables in the form {variable}.

81 | API token 82 |
83 |
84 |
85 |
86 | From 87 |
88 |
89 |
90 | 91 | 92 |
93 | $NAME 94 |
95 | -------------------------------------------------------------------------------- /components/tapiweatherapi.html: -------------------------------------------------------------------------------- 1 | 54 | 55 | 56 | By using this component, you can obtain the current weather by an address. It utilizes the [Total.js Weather API](https://docs.totaljs.com/totalapi/6c221003eo51c/#128f7001kc51d). 57 | 58 | __Input data:__ 59 | 60 | ```js 61 | // {String} address without diacritics 62 | 'Banska Bystrica, Slovakia' 63 | ``` 64 | 65 | __Output data__: 66 | 67 | ```js 68 | { 69 | name: 'Bratislava', 70 | temperature: 22, 71 | wind: 20.2, 72 | humidity: 65, 73 | pressure: 1018, 74 | cloud: 25, 75 | uv: 6, 76 | sky: 'Partly cloudy' 77 | } 78 | ``` 79 | 80 | 81 | 82 |
83 |
84 |

Get Total.js API token.
The token field supports variables in the form {variable}.

85 | API token 86 |
87 |
88 | Path for reading input data 89 |
Optional. This component will load input data from a specific property/field according to the path.
90 |
91 |
92 |
93 | 94 | 95 |
96 | $NAME 97 |
98 | -------------------------------------------------------------------------------- /components/tcors.html: -------------------------------------------------------------------------------- 1 | 32 | 33 | 34 | The component enables Cross-Origin Resource Sharing `CORS`, so the web browser will be able to communicate directly with the REST API. The functionality will work only with a defined Proxy endpoint for this Flow. 35 | 36 | 37 | 38 |
39 | Hostnames with a protocol 40 |
41 |
42 | 43 | 44 |
45 | 46 |
CORS enabled
47 |
48 | -------------------------------------------------------------------------------- /components/throttle.html: -------------------------------------------------------------------------------- 1 | 63 | 64 | 65 | The component sends only limited count of messages. 66 | 67 | 68 | 69 |
70 |
71 |
72 | Limit 73 |
74 |
75 | Delay 76 |
77 |
78 |
79 |
80 | 81 | 84 | 85 | 86 |
87 | 88 | NAME 89 |
90 | 91 | -------------------------------------------------------------------------------- /components/timeout.html: -------------------------------------------------------------------------------- 1 | 51 | 52 | 53 | The component starts a timeout and restarts it when a new message arrives. 54 | 55 | 56 | 60 | 61 | 62 |
63 |
64 |
65 | Timeout 66 |
In seconds
67 |
68 |
69 |
70 |
71 | 72 | 73 |
74 | $NAME 75 |
76 | 81 | -------------------------------------------------------------------------------- /components/tlogger.html: -------------------------------------------------------------------------------- 1 | 32 | 33 | 36 | 37 | 38 | The component logs incoming messages into the Total.js Cloud Logger. 39 | 40 | 41 | 42 |
43 | Total API token 44 |
Supports dynamic arguments in the form {key}
45 |
46 |
47 |
48 |
49 | Type 50 |
51 |
52 | App name 53 |
54 |
55 | Reference 56 |
57 |
58 | URL address 59 |
60 |
61 | Message 62 |
Supports dynamic arguments in the form {key}
63 |
64 |
65 | 66 | 67 |
68 | NAME 69 |
70 | 73 | -------------------------------------------------------------------------------- /components/transform.html: -------------------------------------------------------------------------------- 1 | 33 | 34 | 35 | This component can transform message data. 36 | 37 | 38 | 39 |
40 |
41 |
42 | Transform value according to this path 43 |
Only the value according to the path will be transformed
44 |
45 |
46 | Assign response to the path 47 |
Empty path will replace transformed property
48 |
49 |
50 |
51 |
52 | 53 | 56 | 57 | 58 |
59 | NAME 60 |
61 | 64 | -------------------------------------------------------------------------------- /components/transformer.html: -------------------------------------------------------------------------------- 1 | 54 | 55 | 56 | With this component you can easily modify incoming data. Then the `data` content is delivered. For storing temporary/persistent data you can use `repo {Object}` and `refs {Object}` variables. 57 | 58 | __Example 1__: 59 | 60 | ```js 61 | // "data" is a reference to message data 62 | data.name = data.name.toUpperCase(); 63 | ``` 64 | 65 | __Example 2__: 66 | 67 | ```js 68 | data = data.toUpperCase(); 69 | ``` 70 | 71 | __Example 3__: 72 | 73 | ```js 74 | var tmp = data; 75 | data = {}; 76 | data.name = tmp.Name; 77 | ``` 78 | 79 | 80 | 81 |
82 | 83 | Clear repository object 84 |
85 |
86 | 87 | 88 |
89 | NAME 90 |
91 | -------------------------------------------------------------------------------- /components/tredirect.html: -------------------------------------------------------------------------------- 1 | 31 | 32 | 33 | ## Input 34 | 35 | Incomming data have higher priority than the values set in the Configuration form. Both the `url` and `permanent` are optional. 36 | 37 | ```js 38 | { 39 | url: 'https://example.com', 40 | permanent: true|false 41 | } 42 | ``` 43 | 44 | 45 | 46 |
47 |
Redirect URL address supports dynamic variables in the form {key} or {data.key}. Variables are read from global variables {key} and from the message data {data.key}.
48 | Redirect URL 49 | Permanent redirect 50 |
51 |
52 | 53 | 56 | 57 | 58 |
59 | NAME 60 |
61 | 64 | -------------------------------------------------------------------------------- /components/tremember.html: -------------------------------------------------------------------------------- 1 | 46 | 47 | 48 | The primary goal of this component is to remember the data. The component contains two inputs: 49 | 50 | - Remember input for remembering data. 51 | - Request input as a trigger for obtaining data, then remembered data would extend the request message (its data), and the component would send it to the response output. 52 | 53 | 54 | 55 |
56 | $NAME 57 |
58 | 59 | 60 | 61 |
62 | Set remembered data to the specific property/field 63 |
If you don't enter the property, the remembered data will replace data on the Request input.
64 |
65 |
-------------------------------------------------------------------------------- /components/tsql.html: -------------------------------------------------------------------------------- 1 | 40 | 41 | 42 | The component executes SQL command on the specifi connection. This component depends on the `API PostgreSQL` component. 43 | 44 | 45 | 46 |
47 |
Connection and SQL query support dynamic variables in the form {key} or {data.key}. Variables are read from global Variables {key} and from the message data {data.key}. The component encodes all SQL values with except {!key}.
48 |
49 |
50 | Connection 51 |
A connection name/identifier
52 |
53 |
54 | Assign data according to the path 55 |
Otherwise, the response will replace the entire message data.
56 |
57 |
58 | Return only the first row 59 |
60 |
SQL query:
61 | 62 |
63 |
64 | 65 | 68 | 69 | 70 |
71 | $NAME 72 |
73 | 78 | -------------------------------------------------------------------------------- /components/tuploadedfiles.html: -------------------------------------------------------------------------------- 1 | 59 | 60 | 61 | The component processes files from the Total.js Route component. 62 | 63 | 64 | 65 |
66 | Action 67 | 68 | Type 69 | 70 | 71 | Absolute path 72 | 73 |
74 |
75 | 76 | 79 | 80 | 81 |
82 | $NAME 83 |
84 | 94 | -------------------------------------------------------------------------------- /components/twebsocketroute.html: -------------------------------------------------------------------------------- 1 | 78 | 79 | 80 | This component creates a WebSocket endpoint. Initial message data is stored in the memory of new clients. 81 | 82 | - `message.data {Object}` data from a WebSocket message 83 | - `message.refs.client {Object}` contains a client controller 84 | - `message.refs.controller {Object}` contains a WebSocket controller 85 | 86 | 87 | 88 |
89 |
90 |
91 | Endpoint 92 |
93 |
94 | Communication 95 |
96 |
97 |
98 |
99 | 100 | 103 | 104 | 105 |
106 | $NAME 107 |
108 | 112 | -------------------------------------------------------------------------------- /components/xmlparser.html: -------------------------------------------------------------------------------- 1 | 25 | 26 | 27 | Parse XML from string. 28 | - __Input__: {String} 29 | - __Ouput__: {String} 30 | 31 | 32 | 33 |
34 | NAME 35 |
36 | -------------------------------------------------------------------------------- /db.js: -------------------------------------------------------------------------------- 1 | require('total4'); 2 | 3 | FUNC.indent = function(count, val) { 4 | 5 | var lines = val.split('\n'); 6 | var str = ''; 7 | var total = Math.abs(count); 8 | var is = false; 9 | 10 | for (var i = 0; i < total; i++) 11 | str += '\t'; 12 | 13 | for (var i = 0; i < lines.length; i++) { 14 | if (count > 0 && lines[i]) 15 | lines[i] = str + lines[i]; 16 | else if (lines[i].substring(0, total) === str) { 17 | lines[i] = lines[i].substring(total); 18 | is = true; 19 | } else if (lines[i] && !is) 20 | break; 21 | } 22 | 23 | return lines.join('\n'); 24 | }; 25 | 26 | PATH.fs.readdir('components', function(err, response) { 27 | 28 | var arr = []; 29 | var evaluate = function(code) { 30 | var obj = {}; 31 | new Function('exports', code)(obj); 32 | return obj; 33 | }; 34 | 35 | response.wait(function(filename, next) { 36 | 37 | var data = {}; 38 | data.id = filename.substring(0, filename.length - 5); 39 | 40 | if (data.id === 'example-increment') { 41 | next(); 42 | return; 43 | } 44 | 45 | PATH.fs.readFile('components/' + filename, function(err, response) { 46 | response = response.toString('utf8'); 47 | 48 | var version = response.match(/exports\.version.*?;/); 49 | var author = response.match(/exports\.author.*?;/); 50 | var color = response.match(/exports\.color.*?;/); 51 | var icon = response.match(/exports\.icon.*?;/); 52 | var name = response.match(/exports\.name.*?;/); 53 | var group = response.match(/exports\.group.*?;/); 54 | var kind = response.match(/exports\.kind.*?;/); 55 | 56 | data.group = group ? evaluate(group[0]).group : ''; 57 | data.name = name ? evaluate(name[0]).name : ''; 58 | data.url = 'https://cdn.totaljs.com/flowstream/webcomponents/' + filename; 59 | data.author = author ? evaluate(author[0]).author : ''; 60 | data.icon = icon ? evaluate(icon[0]).icon : ''; 61 | data.color = color ? evaluate(color[0]).color : ''; 62 | data.version = version ? evaluate(version[0]).version : ''; 63 | data.kind = kind ? evaluate(kind[0]).kind : ''; 64 | 65 | var index = response.indexOf(''); 66 | 67 | if (index !== -1) 68 | data.readme = FUNC.indent(-1, response.substring(index + 8, response.indexOf('', index + 8))).trim(); 69 | 70 | arr.push(data); 71 | next(); 72 | }); 73 | 74 | }, function() { 75 | arr.quicksort('name'); 76 | PATH.fs.writeFile('db.json', JSON.stringify(arr, null, '\t'), NOOP); 77 | }); 78 | 79 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "total4": "latest" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/counter.js: -------------------------------------------------------------------------------- 1 | // FlowStream Tester 2 | // Component: counter.html 3 | 4 | require('../tester')(async function(describe, done) { 5 | 6 | await describe(function(test, next) { 7 | 8 | let messages = 0; 9 | let status = 0; 10 | 11 | // Capture component status 12 | test.status = function(data) { 13 | status = data; 14 | }; 15 | 16 | // Send random message to input 17 | test.input('Hello World!'); 18 | messages++; 19 | 20 | // Send another message after 1 second 21 | setTimeout(function() { 22 | test.input('Hello Again!'); 23 | messages++; 24 | }, 1 * 1000); 25 | 26 | setTimeout(function() { 27 | 28 | // Check if message count is as expected 29 | test.ok(status === messages, 'Counting'); 30 | 31 | // Clear counter 32 | test.trigger(); 33 | test.ok(status === 0, 'Clearing'); 34 | 35 | next(); 36 | 37 | }, 2 * 1000); 38 | 39 | }); 40 | 41 | // End tester 42 | done(); 43 | 44 | }); -------------------------------------------------------------------------------- /tests/example-multiple.js: -------------------------------------------------------------------------------- 1 | require('../tester')(async function(describe, done) { 2 | 3 | await describe('example-increment', function(test, next) { 4 | test.ok(); 5 | console.log('Test - 1'); 6 | setTimeout(next, 1000); 7 | }); 8 | 9 | await describe('example-increment', function(test, next) { 10 | test.ok(); 11 | console.log('Test - 2'); 12 | setTimeout(next, 1000); 13 | }); 14 | 15 | await describe('example-increment', function(test, next) { 16 | test.ok(); 17 | console.log('Test - 3'); 18 | setTimeout(next, 1000); 19 | }); 20 | 21 | done(); 22 | }); 23 | 24 | // NOT recommended 25 | // There is big change that tests won't have same order as defined so "Test - 3" will end Tester too early 26 | // tester(function(describe, done) { 27 | // describe('example-increment', function(test) { 28 | // test.ok(); 29 | // console.log('Test - 1'); 30 | // }); 31 | 32 | // describe('example-increment', function(test) { 33 | // test.ok(); 34 | // console.log('Test - 2'); 35 | // }); 36 | 37 | // describe('example-increment', function(test) { 38 | // test.ok(); 39 | // console.log('Test - 3'); 40 | // done(); 41 | // }); 42 | // }); -------------------------------------------------------------------------------- /tests/example.js: -------------------------------------------------------------------------------- 1 | // tester.autoClose = false; // Use "done" to manually end tester 2 | // tester.autoCloseDuration = 5 * 1000; // 5 seconds 3 | 4 | // tester.directory = './components'; 5 | 6 | require('../tester')(async function(describe, done) { 7 | // Pass filename as first argument otherwise filename of this file will be automatically assigned 8 | await describe('example-increment', async function(test, next) { 9 | 10 | // Output messages from component 11 | test.output = function(msg) { 12 | // msg - Message instance from flowstream 13 | // test.ok(); 14 | // test.fail(); 15 | }; 16 | 17 | // Changing component status (or onStatus) 18 | test.status = function(newStatus) { 19 | console.log('[LOG] Component\'s new status is' + newStatus); 20 | }; 21 | 22 | // Reference to flow instance of component 23 | // test.instance 24 | 25 | // Trigger component's trigger event 26 | test.trigger(1); 27 | 28 | // Change component's configuration 29 | test.configure({ increment: 5 }); 30 | 31 | // Change component's configuration without triggering configure function 32 | test.configure({ increment: 5 }, true); 33 | 34 | // Catch error from "instance.throw()" function (or onError) 35 | test.onerror = function(a, b, c, d) { 36 | console.log(a, b, c, d); 37 | } 38 | 39 | // Any output based on input "number" will be flagged as success 40 | // Use "await" so test bellow wont interupt or modify configuration of this test 41 | await test.input('number'); 42 | 43 | // Set config.increment to -10 and sends 10 into input "number". Output 0 is expected 44 | test.configure({ increment: -10 }); 45 | 46 | test.input('number', 10, function(msg) { 47 | test.ok(msg.data === 0, '"-10 + 10 = 0"'); 48 | 49 | // Resolve this test and go to next test 50 | next(); 51 | }); 52 | 53 | }); 54 | 55 | describe('counter', function(test) { 56 | 57 | setTimeout(() => { 58 | // Test was successful 59 | test.ok(); 60 | 61 | // End tester and show results in console 62 | done(); 63 | 64 | }, 1000); 65 | 66 | }); 67 | 68 | }); -------------------------------------------------------------------------------- /tests/influxdb.js: -------------------------------------------------------------------------------- 1 | const token = ''; 2 | const url = ''; 3 | const org = ''; 4 | 5 | require('../tester')(async function(describe, done) { 6 | 7 | await describe('influxdb', async function(test, next) { 8 | 9 | // Output messages from component 10 | test.output = function(msg) { 11 | // msg - Message instance from flowstream 12 | console.log('test.output', msg); 13 | test.ok(); 14 | // test.fail(); 15 | }; 16 | 17 | test.status = function(newStatus) { 18 | console.log('Status:', newStatus); 19 | }; 20 | 21 | // Change component's configuration 22 | test.configure({ 23 | url, 24 | token, 25 | org, 26 | bucket: 'test', 27 | api: 'query', 28 | fields: { cpu: 'int', ram: 'float' }, 29 | tags: ['hostname'] 30 | }); 31 | 32 | // Catch error from "instance.throw()" function (or onError) 33 | test.onerror = function(a, b, c, d) { 34 | console.log('Error -->', a, b, c, d); 35 | } 36 | 37 | console.log('Test.input : start'); 38 | // QUERY 39 | test.input('input', { 40 | query: 'from(bucket: "test") |> range(start: -1h)' 41 | }, function(msg) { 42 | console.log('Test.input : end', msg); 43 | test.ok(typeof msg.data === 'array', 'How knows'); 44 | 45 | // Resolve this test and go to next test 46 | next(); 47 | }); 48 | 49 | // INSERT 50 | /*test.input('input', { 51 | measurement: 'stats', 52 | fields: { 53 | cpu: 100, 54 | ram: 2.9 55 | }, 56 | tags: { 57 | hostname: 'localhost' 58 | } 59 | }, function(msg) { 60 | console.log('Test.input : end', msg); 61 | test.ok(typeof msg.data === 'array', 'How knows'); 62 | 63 | // Resolve this test and go to next test 64 | next(); 65 | });*/ 66 | 67 | }); 68 | 69 | }); -------------------------------------------------------------------------------- /tests/sqlite3.js: -------------------------------------------------------------------------------- 1 | // FlowStream Tester 2 | // Component: counter.html 3 | 4 | require('../tester')(async function(describe, done) { 5 | 6 | await describe('sqlite3', function(test, next) { 7 | 8 | //console.log(test.instance); 9 | test.instance.outputs = [{ id: 'output', name: 'Output' }, { id: 'error', name: 'Error' }, { id: 'output2', name: 'Output2' }]; 10 | 11 | test.input('input', { prepare: 'CREATE TABLE test (name TEXT);', fn: 'run' }); 12 | 13 | // Output messages from component 14 | test.output = function(msg) { 15 | if (msg.data.hasOwnProperty('changes')) { 16 | test.ok('Create table'); 17 | test.input('input', { prepare: 'SELECT * FROM test;', fn: 'all' }); 18 | return; 19 | } 20 | console.log(msg); 21 | test.ok('Select'); 22 | console.log('data', msg.data); 23 | next(); 24 | }; 25 | }); 26 | 27 | // End tester 28 | done(); 29 | }); -------------------------------------------------------------------------------- /tests/test.js: -------------------------------------------------------------------------------- 1 | // FlowStream Tester 2 | // Component: counter.html 3 | 4 | require('../tester')(async function(describe, done) { 5 | 6 | await describe('test', function(test, next) { 7 | 8 | test.configure({ outputs: [{ id: 'output', name: 'Output' }, { id: 'dynamic', name: 'Dynamic' }] }); 9 | 10 | test.input('input', 'Hello world'); 11 | 12 | let i = 0; 13 | test.output = function(msg) { 14 | console.log(msg.data); 15 | i++; 16 | if (i == 1) 17 | return; 18 | test.ok(); 19 | next(); 20 | }; 21 | }); 22 | 23 | // End tester 24 | done(); 25 | }); -------------------------------------------------------------------------------- /tests/trigger.js: -------------------------------------------------------------------------------- 1 | require('../tester')(async function(describe, done) { 2 | 3 | await describe(function(test, next) { 4 | 5 | // If message won't come out in 0.5 second, test will fail 6 | var timeout = setTimeout(() => test.fail('Timeout'), 500); 7 | 8 | test.output = function(msg) { 9 | clearTimeout(timeout); 10 | test.ok('Timeout'); 11 | next(); 12 | }; 13 | 14 | test.trigger(); 15 | }); 16 | 17 | await describe(function(test, next) { 18 | 19 | // Random string 20 | test.configure({ random: true, data: 'NOT_RANDOM' }); 21 | test.output = function(msg) { 22 | test.fail(msg.data === 'NOT_RANDOM', 'Random string'); 23 | }; 24 | 25 | test.trigger(); 26 | 27 | // NOT Random string 28 | setTimeout(function() { 29 | test.configure({ random: false, data: 'NOT_RANDOM' }); 30 | 31 | test.output = function(msg) { 32 | test.ok(msg.data === 'NOT_RANDOM', 'NOT Random string'); 33 | next(); 34 | }; 35 | 36 | test.trigger(); 37 | }, 1000); 38 | 39 | }); 40 | 41 | // End test 42 | done(); 43 | 44 | }); --------------------------------------------------------------------------------