Denoflow
Table of Contents
About
Denoflow is a serverless, automated workflow based yaml
workflow file, you can use any Deno module or Typescript/Javascript code to run your workflow.
It’s still at a very early stage, use with care!
The Ideal result is having some app schemas, using rjsf to render a web gui, gui can help us to generate yaml configs.
The Ideal runtime is using cloud serverless platform, or CI platform, like Github Actions, Gitlab CI, self-hosted with Deno, or any Docker runtime.
Deno Deploy is not supported yet, because it doesn’t support Code generation from strings, Error Detail:
Code generation from strings disallowed for this context
See Github Actions Example: test.yml
Now we can only write yaml by ourself, and actually, it’s not that hard.
Join our Discord chat channel to discuss about Denoflow!
Stable deno land version see Denoflow
Getting Started
Fetch from Hacker News API to webhook example:
mkdir workflows
touch workflows/fetch.yml
sources:
- use: fetch
args:
- https://test.owenyoung.com/slim.json
run: return ctx.result.json()
itemsPath: hits
key: objectID
limit: 1
steps:
- use: fetch
args:
- https://enyvb91j5zjv9.x.pipedream.net/
- method: POST
headers:
Content-Type: application/json
body: ${{JSON.stringify(ctx.item)}}
Open: https://requestbin.com/r/enyvb91j5zjv9/23eNPamD4DK4YK1rfEB1FAQOKIj , See live webhook request.
deno run --allow-read --allow-net --allow-write --allow-env --allow-run https://deno.land/x/denoflow/cli.ts run
It will scan the
workflows
directory and run all valid.yml
files.
latest version:
https://denopkg.com/denoflow/denoflow@main/cli.ts
RSS Feed to Discord Webhook Message
touch workflows/rss.yml
sources:
- use: fetch
args:
- https://actionsflow.github.io/test-page/hn-rss.xml
run: |
const rss = await import("https://deno.land/x/rss/mod.ts");
const xml = await ctx.result.text();
const feed = await rss.parseFeed(xml);
return feed.entries;
steps:
- use: fetch
args:
- ${{ctx.env.DISCORD_WEBHOOK}}
- method: POST
headers:
'Content-Type': 'application/json'
body: ${{ JSON.stringify({content:ctx.item.title.value}) }}
deno run --allow-read --allow-net --allow-write --allow-run --allow-env https://deno.land/x/denoflow/cli.ts run
Life Cycle
on?
: when to run the workflow,Record<EventType,EventConfig>
, can beschedule
orhttp
,always
, default isalways
. (Now, only supportalways
)sources?
: where to fetch the data,Source[]
, can be one or more sources. Every source should return an array of items.from
?: import ts/js script fromurl
orfile path
use
?: runmoduleName
from abovefrom
, or iffrom
is not provided, runglobalFunction
likefetch
,args
will be passed to the function, the return value will be attached toctx.result
andctx.sources[index].result
, ifuse
is a class, thenctx.result
will be the instance of the class.run
?: run ts/js code, you can handleuse
result here. Return a result that can be stringified to json. The return value will be attached toctx.result
andctx.sources[index].result
itemsPath
?: the path to the items in the result, likehits
inhttps://test.owenyoung.com/slim.json
key
?: the key to identify the item, likeobjectID
inhttps://test.owenyoung.com/slim.json
, if not provided, will useid
, denoflow will hash the id, then the same item withid
will be skipped.filter?
,string
, script code, should handlectx.item
-> returntrue
orfalse
reverse?
,boolean
, reverse the itemscmd
:string
, exec a shell command after all other task, the return value will be attached toctx.cmdResult
andctx.sources[index].cmdResult
post?
: post script code, you can do some check, clean, things here, change ctx.state
filter
? filter from all sources items, handlectx.items
, expected return a newboolean[]
,from
?: import ts/js script fromurl
orfile path
use
?: runmoduleName
from abovefrom
, or iffrom
is not provided, runglobalFunction
likefetch
,args
will be passed to the function, the return value will be attached toctx.result
andfilter.result
. ifuse
is a class, thenctx.result
will be the instance of the class.run
?: run ts/js code, you can handleuse
result here.handlectx.items
, expected return a newboolean[]
, flag which item will be used. e.g.run: return ctx.items.map(item => item.title.value.includes('test'))
cmd
?:string
, exec a shell command after all other task, the return value will be attached toctx.cmdResult
andfilter.cmdResult
post?
: post script code, you can do some check, clean, things here, change ctx.state
steps
? the steps to run,Step[]
, can be one or more steps.from
?: import script fromurl
orfile path
use
?: runmoduleName
from abovefrom
, or iffrom
is not provided, runglobalFunction
likefetch
,args
will be passed to the function. ifuse
is a class, thenctx.result
will be the instance of the class.run
?: run ts/js code, you can handleuse
result here. Return a result that can be stringified to json. the result will be attached to thectx.steps[index].result
cmd
?: exec shell commands, will be run afterrun
, the result will be attached to thectx.steps[index].cmdResult
.
post?`: post script code, you can do some check, clean, things here, change ctx.state
Prerequisites
Install Deno first.
Installing
deno install -n denoflow --allow-read --allow-net --allow-write --allow-run --allow-env https://deno.land/x/denoflow/cli.ts
Then, you can run it with denoflow run
, or denoflow run <files>
Update to latest version
deno cache --reload https://deno.land/x/denoflow/cli.ts
Usage
Usage:
$ denoflow run [...files]
Options:
--force Force run workflow files, if true, will ignore to read/save state
--debug Debug mode, will print more info
--database Database uri, default json://data
--limit max items for workflow every runs
--sleep sleep time between sources, filter, steps, unit seconds
--stdin read yaml file from stdin, e.g. cat test.yml | denoflow run --stdin
-h, --help Display this message
YAML Syntax
You can use ${{variable}}
in any fields to inject variables into your workflow, we inject ctx
variable in template and script. For example:
Expressions
steps:
- if: ${{ctx.items.lengh>10}}
run: console.log(ctx.item);
All ctx
see [Context] in the following doc.
State
You can simply use ctx.state
to get or set state, for example:
let currentState = ctx.state || {};
let sent = ctx.state.sent || [];
if(sent.includes(ctx.item.id)){
sent.push(ctx.item.id);
}
ctx.state = {
sent
};
// deno flow will save the state for you , next you can read it.
return;
The state will be saved to data
folder in json
format. You can also use sqlite to store the state. Just set database: sqlite://data.sqlite
in your workflow config file.
Syntax
All workflow syntax:
See Interface
Todo
- Support Sleep Option
- Support GUI generated workflow
- Support
on
options,schedule
andhttp
- Support
clean
command - denoflow playground
- support new instance