fyflow-plugin-sdk 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -2
- package/dist/index.d.ts +45 -0
- package/dist/index.js +70 -0
- package/package.json +37 -3
- package/src/index.ts +70 -0
package/README.md
CHANGED
|
@@ -1,3 +1,94 @@
|
|
|
1
|
-
#
|
|
1
|
+
# fyflow-plugin-sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Types and `definePlugin` for writing **Plugins** for fyflow-app, the visual builder and Host for [fyflow-orchestration](https://www.npmjs.com/package/fyflow-orchestration) flows. A Plugin contributes Node Types (with the Workers that run their Tasks), gate types, Resource Group types and Resource Groups.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm install --save-peer fyflow-plugin-sdk
|
|
7
|
+
npm install --save-dev fyflow-orchestration # its types, for type checking; the Host brings its own at run time
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## The contract
|
|
11
|
+
|
|
12
|
+
A Plugin is a module whose default export is a plain object. `definePlugin` returns its argument unchanged; it only gives you type checking. Depend on the SDK as a peer and do not bundle it: the Host provides it at run time (see below), and a copy of your own would only report its own `SDK_VERSION`, not the Host's.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { definePlugin } from "fyflow-plugin-sdk";
|
|
16
|
+
|
|
17
|
+
export default definePlugin({
|
|
18
|
+
id: "acme.signer", // stable and unique across Plugins
|
|
19
|
+
version: "1.0.0",
|
|
20
|
+
base: import.meta.url, // what Worker `url`s resolve against
|
|
21
|
+
workers: {
|
|
22
|
+
sign: {
|
|
23
|
+
url: "./sign.worker.js",
|
|
24
|
+
configSchema: {
|
|
25
|
+
type: "object",
|
|
26
|
+
properties: { key: { type: "string", writeOnly: true } }, // a Profile secret
|
|
27
|
+
},
|
|
28
|
+
settingsSchema: { type: "object", properties: { field: { type: "string" } } },
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
nodeTypes: {
|
|
32
|
+
Sign: {
|
|
33
|
+
worker: "sign",
|
|
34
|
+
inline: true,
|
|
35
|
+
groups: ["acme.signing"],
|
|
36
|
+
icon: "signature", // from the app's icon set, below
|
|
37
|
+
description: "Signs a field with HMAC.",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
groups: { "acme.signing": { type: "ConcurrentLimitGroup", config: { limit: 2 } } },
|
|
41
|
+
gateTypes: {
|
|
42
|
+
threshold: {
|
|
43
|
+
routes: ["below", "at-or-above"],
|
|
44
|
+
defaultRoute: "below",
|
|
45
|
+
fn: ({ key, settings }) => (Number(key) >= Number(settings.at) ? "at-or-above" : "below"),
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
| Field | What it is |
|
|
52
|
+
| --- | --- |
|
|
53
|
+
| `workers` | Worker modules by key. A Worker module's default export is a class: its constructor gets the Profile's config, and `run({ settings, input })` does one Task. Schemas are JSON Schema in fyflow's subset. |
|
|
54
|
+
| `nodeTypes` | Node Types by name, each naming one of this Plugin's `workers`, with fyflow's declaration fields (`inline`, `pool`, `config`, `settings` defaults, `retryPolicy`, `groups`), and, since 0.2.0, how the app shows it: an optional `icon` and a one-line `description`. |
|
|
55
|
+
| `gateTypes` | Gate types by name: their routes, default route, settings schema, and the decision `fn`. |
|
|
56
|
+
| `groupTypes` | Resource Group types by name: a `create(config, key)` factory for the scheduler's limit, and a `configSchema`. |
|
|
57
|
+
| `groups` | Resource Groups by key, of fyflow's built-in types (`ConcurrentLimitGroup`, `RateLimitGroup`, `KeyedRateLimitGroup`) or this Plugin's own. A Node Type may only use its own Plugin's groups. |
|
|
58
|
+
|
|
59
|
+
Do not name a setting like a member of every JavaScript object (`constructor`, `toString`, `valueOf`, `hasOwnProperty`, `__proto__`). The Host hands Agents a Flow Definition's shape as a JSON Schema that includes your `settingsSchema`, and some JSON Schema validators misread such a property: they refuse, or throw, on a Flow that is valid.
|
|
60
|
+
|
|
61
|
+
Every name a Plugin contributes (Node Type, gate type, Resource Group type, Resource Group) must be unique across the Plugins a Host loads: the Plugin the Host saw first keeps a name, and a later one that repeats it is skipped with the reason.
|
|
62
|
+
|
|
63
|
+
## The Plugin directory
|
|
64
|
+
|
|
65
|
+
A Host loads Plugins from its Plugin directory (`<dataDir>/plugins` unless `pluginDir`, `FYFLOW_PLUGIN_DIR` or `--plugin-dir` says otherwise):
|
|
66
|
+
|
|
67
|
+
- a **folder** holding `plugin.ts` or `plugin.js`, or a package (`package.json` and its entry), as the Host lays out a Plugin installed from the app;
|
|
68
|
+
- a **package** named `fyflow-plugin-*` or `@scope/fyflow-plugin-*` under the directory's `node_modules`, installed with npm. A package must ship JavaScript: Node does not strip TypeScript under `node_modules`.
|
|
69
|
+
|
|
70
|
+
A Plugin's own imports resolve from the Plugin directory's `node_modules`, so `npm install` your other dependencies there (or bundle them). The SDK is the Host's to provide: on a server, `npm install fyflow-plugin-sdk` there (npm also installs it as your package's peer); the desktop app puts its own there by itself. Changes take effect when the Host is told to **Reload**.
|
|
71
|
+
|
|
72
|
+
## Peer range
|
|
73
|
+
|
|
74
|
+
Declare the SDK versions your Plugin works with as a peer dependency:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{ "peerDependencies": { "fyflow-plugin-sdk": "^0.2.0" } }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
A Host implements its SDK version (`SDK_VERSION`, exported here) and the earlier ones it is compatible with (`SDK_COMPATIBLE`): a 0.2 Host still loads a Plugin declaring `^0.1.0`. It skips, with the reason, a Plugin whose range excludes them all. Declare `^0.2.0` when you use `icon` or `description`.
|
|
81
|
+
|
|
82
|
+
## Icons
|
|
83
|
+
|
|
84
|
+
A Node Type's `icon` names one of the app's icons, from [Lucide](https://lucide.dev/icons/): `activity`, `archive`, `bell`, `bot`, `box`, `braces`, `brain`, `calculator`, `calendar`, `camera`, `chart-bar`, `check`, `clock`, `cloud`, `code`, `cpu`, `credit-card`, `database`, `download`, `file`, `file-text`, `filter`, `flag`, `folder`, `git-branch`, `globe`, `hash`, `image`, `key`, `link`, `list`, `lock`, `mail`, `map-pin`, `message-square`, `package`, `pen-tool`, `play`, `plug`, `repeat`, `search`, `send`, `server`, `settings`, `shield`, `shopping-cart`, `signature`, `sparkles`, `table`, `tag`, `terminal`, `timer`, `upload`, `user`, `users`, `wand-sparkles`, `webhook`, `zap`. A name outside the set is not an error: the Node Type shows its Kind's icon, and the Plugins page shows a warning.
|
|
85
|
+
|
|
86
|
+
## Profiles and secrets
|
|
87
|
+
|
|
88
|
+
A Node Type's Worker config lives on the Host, not in Flows: a **Profile** is a named configuration of a Node Type, edited in the Host's UI with a form built from the Worker's `configSchema`, and a task Node chooses one. Every Node Type has a default Profile seeded from its declaration's `config`. A Profile's config is merged over the default's, which is merged over yours.
|
|
89
|
+
|
|
90
|
+
Mark a config property `writeOnly: true` to make it a **secret**: the Host never shows it again, only whether it is set, and redacts its value from errors and logs. Only properties of the config object can be secrets.
|
|
91
|
+
|
|
92
|
+
## Versioning
|
|
93
|
+
|
|
94
|
+
This package follows semver. `SDK_VERSION` always equals the package version.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { GateType, GroupInstance, GroupType, NodeTypeDeclaration, WorkerEntry } from "fyflow-orchestration";
|
|
2
|
+
export type { GateContext, GateType, GroupInstance, GroupType, JsonSchema, NodeTypeDeclaration, RetryPolicy, WorkerEntry, } from "fyflow-orchestration";
|
|
3
|
+
/**
|
|
4
|
+
* The SDK version this package is, and so the one a Host built with it implements. A Plugin whose
|
|
5
|
+
* `fyflow-plugin-sdk` peer range excludes it, and every one in `SDK_COMPATIBLE`, is not loaded. Kept equal to
|
|
6
|
+
* package.json's `version` (tested).
|
|
7
|
+
*/
|
|
8
|
+
export declare const SDK_VERSION = "0.2.0";
|
|
9
|
+
/**
|
|
10
|
+
* The earlier SDK versions this one is a superset of: nothing a Plugin written for them says has changed meaning,
|
|
11
|
+
* so a Host implements them too (ADR-0021). 0.2.0 only added optional fields.
|
|
12
|
+
*/
|
|
13
|
+
export declare const SDK_COMPATIBLE: readonly string[];
|
|
14
|
+
/** A Node Type as a Plugin declares it: fyflow's declaration, and how the app shows it (since 0.2.0). */
|
|
15
|
+
export interface PluginNodeType extends NodeTypeDeclaration {
|
|
16
|
+
/** An icon from the app's icon set (Lucide names, listed in the README); an unknown one shows its Kind's icon. */
|
|
17
|
+
icon?: string;
|
|
18
|
+
/** One line on what it does, shown in the palette. */
|
|
19
|
+
description?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface Plugin {
|
|
22
|
+
/** Stable, unique id, e.g. `acme.images`. */
|
|
23
|
+
id: string;
|
|
24
|
+
version: string;
|
|
25
|
+
/** What worker `url`s resolve against: the plugin module's own `import.meta.url`. */
|
|
26
|
+
base: string;
|
|
27
|
+
/**
|
|
28
|
+
* Worker modules by key; `url` is relative to `base`. A property of a `configSchema` marked `writeOnly: true` is
|
|
29
|
+
* a Profile secret: a Host never shows it (ADR-0016).
|
|
30
|
+
*/
|
|
31
|
+
workers?: Readonly<Record<string, WorkerEntry>>;
|
|
32
|
+
/**
|
|
33
|
+
* Node Types by name, each naming one of this plugin's `workers`; `groups` names Resource Groups (from this
|
|
34
|
+
* plugin's `groups`) every Task of the type acquires.
|
|
35
|
+
*/
|
|
36
|
+
nodeTypes?: Readonly<Record<string, PluginNodeType>>;
|
|
37
|
+
/** Gate types by name: the routes a gate of the type takes, and its decision. */
|
|
38
|
+
gateTypes?: Readonly<Record<string, GateType>>;
|
|
39
|
+
/** Resource Group types by name: a factory for the scheduler's limit, from a Resource Group's `config`. */
|
|
40
|
+
groupTypes?: Readonly<Record<string, GroupType>>;
|
|
41
|
+
/** Resource Groups by key: an instance of a group type (fyflow's built-ins or this plugin's), with its config. */
|
|
42
|
+
groups?: Readonly<Record<string, GroupInstance>>;
|
|
43
|
+
}
|
|
44
|
+
/** Identity at runtime; gives plugin authors type checking and a single import. */
|
|
45
|
+
export declare function definePlugin(plugin: Plugin): Plugin;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// The contract between fyflow-app and the code that extends it (ADR-0007, ADR-0015, ADR-0016). Published as
|
|
2
|
+
// `fyflow-plugin-sdk`: everything here is types but `definePlugin`, `SDK_VERSION` and `SDK_COMPATIBLE`.
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The SDK version this package is, and so the one a Host built with it implements. A Plugin whose
|
|
24
|
+
* `fyflow-plugin-sdk` peer range excludes it, and every one in `SDK_COMPATIBLE`, is not loaded. Kept equal to
|
|
25
|
+
* package.json's `version` (tested).
|
|
26
|
+
*/
|
|
27
|
+
export const SDK_VERSION = "0.2.0";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The earlier SDK versions this one is a superset of: nothing a Plugin written for them says has changed meaning,
|
|
31
|
+
* so a Host implements them too (ADR-0021). 0.2.0 only added optional fields.
|
|
32
|
+
*/
|
|
33
|
+
export const SDK_COMPATIBLE = ["0.1.0"];
|
|
34
|
+
|
|
35
|
+
/** A Node Type as a Plugin declares it: fyflow's declaration, and how the app shows it (since 0.2.0). */
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
/** Identity at runtime; gives plugin authors type checking and a single import. */
|
|
68
|
+
export function definePlugin(plugin ) {
|
|
69
|
+
return plugin;
|
|
70
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fyflow-plugin-sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Types and definePlugin for fyflow-app Plugins: Node Types, Workers, gate types and Resource Groups",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"fyflow",
|
|
7
|
+
"fyflow-plugin",
|
|
8
|
+
"plugin",
|
|
9
|
+
"workflow"
|
|
10
|
+
],
|
|
11
|
+
"type": "module",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"fyflow-orchestration": "^0.11.0"
|
|
24
|
+
},
|
|
25
|
+
"peerDependenciesMeta": {
|
|
26
|
+
"fyflow-orchestration": {
|
|
27
|
+
"optional": true
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"fyflow-orchestration": "0.11.0"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"src",
|
|
36
|
+
"!src/**/*.test.ts"
|
|
37
|
+
],
|
|
38
|
+
"main": "./dist/index.js",
|
|
39
|
+
"types": "./dist/index.d.ts"
|
|
6
40
|
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// The contract between fyflow-app and the code that extends it (ADR-0007, ADR-0015, ADR-0016). Published as
|
|
2
|
+
// `fyflow-plugin-sdk`: everything here is types but `definePlugin`, `SDK_VERSION` and `SDK_COMPATIBLE`.
|
|
3
|
+
import type {
|
|
4
|
+
GateType,
|
|
5
|
+
GroupInstance,
|
|
6
|
+
GroupType,
|
|
7
|
+
NodeTypeDeclaration,
|
|
8
|
+
WorkerEntry,
|
|
9
|
+
} from "fyflow-orchestration";
|
|
10
|
+
|
|
11
|
+
export type {
|
|
12
|
+
GateContext,
|
|
13
|
+
GateType,
|
|
14
|
+
GroupInstance,
|
|
15
|
+
GroupType,
|
|
16
|
+
JsonSchema,
|
|
17
|
+
NodeTypeDeclaration,
|
|
18
|
+
RetryPolicy,
|
|
19
|
+
WorkerEntry,
|
|
20
|
+
} from "fyflow-orchestration";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The SDK version this package is, and so the one a Host built with it implements. A Plugin whose
|
|
24
|
+
* `fyflow-plugin-sdk` peer range excludes it, and every one in `SDK_COMPATIBLE`, is not loaded. Kept equal to
|
|
25
|
+
* package.json's `version` (tested).
|
|
26
|
+
*/
|
|
27
|
+
export const SDK_VERSION = "0.2.0";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The earlier SDK versions this one is a superset of: nothing a Plugin written for them says has changed meaning,
|
|
31
|
+
* so a Host implements them too (ADR-0021). 0.2.0 only added optional fields.
|
|
32
|
+
*/
|
|
33
|
+
export const SDK_COMPATIBLE: readonly string[] = ["0.1.0"];
|
|
34
|
+
|
|
35
|
+
/** A Node Type as a Plugin declares it: fyflow's declaration, and how the app shows it (since 0.2.0). */
|
|
36
|
+
export interface PluginNodeType extends NodeTypeDeclaration {
|
|
37
|
+
/** An icon from the app's icon set (Lucide names, listed in the README); an unknown one shows its Kind's icon. */
|
|
38
|
+
icon?: string;
|
|
39
|
+
/** One line on what it does, shown in the palette. */
|
|
40
|
+
description?: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface Plugin {
|
|
44
|
+
/** Stable, unique id, e.g. `acme.images`. */
|
|
45
|
+
id: string;
|
|
46
|
+
version: string;
|
|
47
|
+
/** What worker `url`s resolve against: the plugin module's own `import.meta.url`. */
|
|
48
|
+
base: string;
|
|
49
|
+
/**
|
|
50
|
+
* Worker modules by key; `url` is relative to `base`. A property of a `configSchema` marked `writeOnly: true` is
|
|
51
|
+
* a Profile secret: a Host never shows it (ADR-0016).
|
|
52
|
+
*/
|
|
53
|
+
workers?: Readonly<Record<string, WorkerEntry>>;
|
|
54
|
+
/**
|
|
55
|
+
* Node Types by name, each naming one of this plugin's `workers`; `groups` names Resource Groups (from this
|
|
56
|
+
* plugin's `groups`) every Task of the type acquires.
|
|
57
|
+
*/
|
|
58
|
+
nodeTypes?: Readonly<Record<string, PluginNodeType>>;
|
|
59
|
+
/** Gate types by name: the routes a gate of the type takes, and its decision. */
|
|
60
|
+
gateTypes?: Readonly<Record<string, GateType>>;
|
|
61
|
+
/** Resource Group types by name: a factory for the scheduler's limit, from a Resource Group's `config`. */
|
|
62
|
+
groupTypes?: Readonly<Record<string, GroupType>>;
|
|
63
|
+
/** Resource Groups by key: an instance of a group type (fyflow's built-ins or this plugin's), with its config. */
|
|
64
|
+
groups?: Readonly<Record<string, GroupInstance>>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Identity at runtime; gives plugin authors type checking and a single import. */
|
|
68
|
+
export function definePlugin(plugin: Plugin): Plugin {
|
|
69
|
+
return plugin;
|
|
70
|
+
}
|