A lightweight workflow engine for all runtimes. Highly extensive with minimal core and no dependencies.
- 📦 no dependencies and no runtime-specific dependencies (besides ES6 + Promises)
- 🪶 minimal core with (xkb; see the sizes table)
- 🧠 very easy to use API
- 🧩 highly extensible from the ground up
- 📝 use declarative workflows and enrich them with custom functionality
Our goal is to make Tinyflow usable anyhwere JavaScript is running.
The following table shows some options to install Tinyflow's core
package, the most minimal deliverable:
name | command | tested |
---|---|---|
npm | npm install @tinyflow/core |
|
yarn | yarn add @tinyflow/core |
|
deno (npm) | import { Tinyflow } from "npm:@tinyflow/core"; |
|
deno (cdn) | import { Tinyflow } from "https://esm.sh/@tinyflow/core"; |
|
bun | bun install @tinyflow/core |
- unpkg
- jsdelivr
- cdnjs
- esm.sh
- jspm
- github (not for production!)
Tonyflow packages offer multiple entry point files, suited for different environments. Nowadays, you might want to stick with ESM but we also provide cjs, es5 and iife versions of the build, including sourcemaps and a minified version, too.
They're all placed in the respective package's /dist
folder and committed to this repository.
Internally there are two classes, Workflow
and Step
that act for the whole engine.
If you only want the core
package then you will have to manage them manually.
Depending on your use-case, this might be exactly what you want or not want.
If you want a more comfortable solution (suitable for beginners), you might also want to install @tinyflow/instances
.
If you want to have the most minimal size, then you will have to manage everything on your own. Here is an example for that:
import { Workflow } from '@tinyflow/core'
// create a new workflow
const workflow = new Workflow({
name: 'checkout-cart',
steps: {
visit: {},
paymentOptions: {},
complete: {}
}
})
// listen to workflow events
workflow.on('started', () => console.debug('workflow started'))
workflow.on('step', () => console.debug('new step is mounted', workflow.current))
workflow.on('error', ({ error }) => console.error(error))
workflow.on('end', () => {
workflow.off() // remove all events
console.debug('workflow ended with data', workflow.data)
})
workflow.start()
// ... at some point in your code
// update the current step's data
workflow.current.update({ some: 'data' })
// or complete the current step, causing
// workflow to move to the next step or end
workflow.current.complete()
The real power of Tinyflow is it's ability to easily extend functionality.
For this, there are two main methods (in fact, the Tinyflow
object in core
contains only them):
As a very simple example, we can create an id function that uses the Browser's crypto API to generate uuids:
const restoreId = Tinyflow.extend(internals => {
const original = internals.id
internals.id = () => window.crypto.randomUUID()
// calling this method will rstore the default id generation
return () => {
internals.id = original
}
})
const wf = new Workflow({ name: 'foo', steps: { one: {} }})
wf.id // "54b281b4-6ee1-4747-97a5-46543f71f359"
// call he restore function if your extension
// should exist only for a limited time
restoreId()
As you can see, all internals remain scoped within that function (unless you intend to do fancy stuff...).
As a very simple example for this one, we can create a simple
We have more examples ready in our documentation's examples section. Some of them can be executed directly in the browser or using node/deno/bun.
Some extensions might not be ready to be published yet. They are currently located the in the /next folder. If you think you have a good idea for a core extension, then please open an issue and choose the issue template for extensions.
The core
package brings two main classes that emit several events during the engine execution.
Name | Info | Data |
---|---|---|
started |
fired when the workflow has started, after all extensions were executed without error | |
step |
fired when a new step has entered | the workflow's data property will contain the data from the previous step at this point |
end |
fired when the workflow ended; read the workflow state to know whether it ended by complete or by cancel | the workflow's data property will contain all steps data |
error |
fired when an error has been caught |
Name | Info | Data |
---|---|---|
started |
fired when the step has started, after all extensions were executed without error | |
update |
fired when a step has received new data via update
|
the data will contain the latest updated data |
end |
fired when the step ended; read the it's state to know whether it ended by complete or by cancel |
the step's data property will contain all steps final data |
error |
fired when an error has been caught |
Our goal is to Tinyflow executable in as many environments as possible. The following list shows, what's currently covered:
Environment | latest versions | known issues |
---|---|---|
Node.js | ||
Deno | ||
Bun | ||
Cloudflare workers |
Browser | tested versions | known issues |
---|---|---|
Chrome | ||
Safari | ||
Safari (iOS) | ||
Firefox | ||
Opera | ||
Android Webview | ||
... |
You can help out with testing for these environments, so we can maximize the compatibility overall.
Tinyflow comes with a minimal core but also provides extensions out-of-the-box. At the same time we build Tinyflow for multiple outputs.
The following table shows the size of the various builds, available in their respective /dist
folders.
Note, that this overview shows only the sizes for the minified versions of each, excluding sourcemaps.
package | mjs | cjs | es5 | iife |
---|---|---|---|---|
@tinyflow/core |
||||
@tinyflow/instances |
We provide an extensive contribution guideline and a code of conduct to help you in making your contribution a success!
- 🗪 Babel for transpiling
- 🪄 Standard for linting
- ⚗️ Mocha and Chai for testing
- 🔍 c8 for code coverage
- 📚 JSDoc for documentation and jsdoc-to-markdown to create docs as markdown files
- ⚡ GitHub actions for continuous integration
- 📦 Rollup for bundling
All tools are defined as dev-dependencies
!
We provide a default set of dev-tools via npm scripts. Run a script via
$ npm run <command>
where <command>
is one of the following available commands:
command | description | output |
---|---|---|
lint |
runs the linter in read-mode | |
lint:fix |
runs the linter; fixes minor issues automatically | |
test |
runs the tests once | |
test:watch |
runs the tests; re-runs them on code changes | |
test:coverage |
runs the tests once and creates a coverage report | coverage |
docs |
creates API documentation | docs |
build |
builds the bundles for several target platforms | dist |
build:full |
runs build and docs
|
see above |
Please read our security policy to get to know which versions are covered.
MIT, see license file