fyflow-plugin-sdk 0.2.0 → 0.3.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 CHANGED
@@ -50,11 +50,11 @@ export default definePlugin({
50
50
 
51
51
  | Field | What it is |
52
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. |
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 }, context)` does one Task (see [Workers](#workers)). Schemas are JSON Schema in fyflow's subset. A Worker's `outputSchema`, what `run` returns (accepted by every version of the SDK, as fyflow's own Worker entry), is the form a person fills in to mark a failed Task done, and the paths the editor suggests for conditions on its Node's Edges and gates before any Run. |
54
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
55
  | `gateTypes` | Gate types by name: their routes, default route, settings schema, and the decision `fn`. |
56
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. |
57
+ | `groups` | Resource Groups by key, of fyflow's built-in types (`ConcurrentLimitGroup`, `RateLimitGroup`, `KeyedRateLimitGroup`) or this Plugin's own. A Node Type may use its own Plugin's groups, and the built-in Plugin's `disk` group (below). |
58
58
 
59
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
60
 
@@ -77,11 +77,55 @@ Declare the SDK versions your Plugin works with as a peer dependency:
77
77
  { "peerDependencies": { "fyflow-plugin-sdk": "^0.2.0" } }
78
78
  ```
79
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`.
80
+ A Host implements its SDK version (`SDK_VERSION`, exported here) and the earlier ones it is compatible with (`SDK_COMPATIBLE`): a 0.3 Host still loads a Plugin declaring `^0.2.0` or `^0.1.0`. It skips, with the reason, a Plugin whose range excludes them all. Raise the range only for what a Host must do at run time: declare `^0.2.0` when you use `icon` or `description`. The Worker types of 0.3.0 vanish at run time (`import type`), so take 0.3 as a devDependency for them and leave the peer range as it was.
81
81
 
82
82
  ## Icons
83
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.
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`, `trash`, `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
+ ## Workers
87
+
88
+ A Worker module's default export is a class. The Host builds each instance (one per worker of the pool: a thread, or on an inline pool an object on the Host's own thread) with the config of the Profile the pool is for, and reuses it across Tasks, so keep per-Task state out of fields. `run` gets the Task's envelope (the Node's `settings` and the Task input) and a context; what it returns is the Task's result, and throwing fails the Task with the error's message. Since 0.3.0 the SDK types all of it:
89
+
90
+ ```ts
91
+ import type { TaskEnvelope, Worker, WorkerContext } from "fyflow-plugin-sdk";
92
+
93
+ type Config = { key?: string };
94
+ type Settings = { field?: string };
95
+
96
+ export default class Sign implements Worker<Settings> {
97
+ readonly #config: Config;
98
+
99
+ constructor(config: Config) {
100
+ this.#config = config;
101
+ }
102
+
103
+ async run({ settings, input }: TaskEnvelope<Settings>, context: WorkerContext) {
104
+ if (this.#config.key === undefined) throw new Error("No key: set `key` on this Node's Profile");
105
+ context.sendProgress(0, "signing"); // a fraction from 0 to 1, not a percentage
106
+ context.signal.throwIfAborted(); // aborted when the Task is Cancelled
107
+ const value = settings.field === undefined ? input : (input as Record<string, unknown>)[settings.field];
108
+ return { signed: await hmac(this.#config.key, value) }; // hmac: your own signing function
109
+ }
110
+ }
111
+ ```
112
+
113
+ `WorkerClass<Config, Settings, Input, Output>` types the class itself, constructor included. Check `context.signal` between steps, or pass it to anything that takes one (`fetch`, streams): a Worker that stops promptly frees its slot sooner, and what it returns after a Cancel is discarded. Use `import type`, so a Worker module needs nothing from the SDK at run time. The context offers what the Host shows (progress) and Cancel; fyflow's scheduler passes more, but the SDK promises only these.
114
+
115
+ ## The `disk` group
116
+
117
+ The Host's built-in Plugin declares one Resource Group any Plugin's Node Types may name: `disk` (exported as `DISK_GROUP` since 0.3.0), a concurrency limit on Tasks that read or write the Host's disks. It is 4 unless the Host overrides it on its Resource Groups page. Name it when your Tasks do heavy disk work (copying, transcoding, indexing), so they share one budget with the Host's own file system Node Types instead of thrashing the disk beside them:
118
+
119
+ ```ts
120
+ import { DISK_GROUP, definePlugin } from "fyflow-plugin-sdk";
121
+
122
+ export default definePlugin({
123
+ // …
124
+ nodeTypes: { Transcode: { worker: "transcode", groups: [DISK_GROUP] } },
125
+ });
126
+ ```
127
+
128
+ Other Plugins' groups stay out of reach, so Disabling one Plugin never breaks another. `DISK_GROUP` is a value, so a Plugin that imports it needs the SDK at run time; writing `"disk"` instead works on any Host that has the group.
85
129
 
86
130
  ## Profiles and secrets
87
131
 
package/dist/index.d.ts CHANGED
@@ -5,12 +5,19 @@ export type { GateContext, GateType, GroupInstance, GroupType, JsonSchema, NodeT
5
5
  * `fyflow-plugin-sdk` peer range excludes it, and every one in `SDK_COMPATIBLE`, is not loaded. Kept equal to
6
6
  * package.json's `version` (tested).
7
7
  */
8
- export declare const SDK_VERSION = "0.2.0";
8
+ export declare const SDK_VERSION = "0.3.0";
9
9
  /**
10
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.
11
+ * so a Host implements them too (ADR-0021). 0.2.0 only added optional fields, and 0.3.0 only types.
12
12
  */
13
13
  export declare const SDK_COMPATIBLE: readonly string[];
14
+ /**
15
+ * The key of the `disk` Resource Group the Host's built-in Plugin declares (exported since 0.3.0): a concurrency
16
+ * limit (4 unless the Host overrides it) on Tasks that read or write the Host's disks. Any Plugin's Node Type may
17
+ * name it in `groups`, so a Plugin doing heavy disk work shares one budget with every other. Other Plugins' groups
18
+ * are out of reach.
19
+ */
20
+ export declare const DISK_GROUP = "disk";
14
21
  /** A Node Type as a Plugin declares it: fyflow's declaration, and how the app shows it (since 0.2.0). */
15
22
  export interface PluginNodeType extends NodeTypeDeclaration {
16
23
  /** An icon from the app's icon set (Lucide names, listed in the README); an unknown one shows its Kind's icon. */
@@ -41,5 +48,33 @@ export interface Plugin {
41
48
  /** Resource Groups by key: an instance of a group type (fyflow's built-ins or this plugin's), with its config. */
42
49
  groups?: Readonly<Record<string, GroupInstance>>;
43
50
  }
51
+ /**
52
+ * What a Worker's `run` is handed for one Task: the Node's `settings` (checked by the Worker's `settingsSchema`)
53
+ * and the Task input, after the Node's transform if it has one (since 0.3.0).
54
+ */
55
+ export interface TaskEnvelope<Settings = Record<string, unknown>, Input = unknown> {
56
+ settings: Settings;
57
+ input: Input;
58
+ }
59
+ /** The second argument to a Worker's `run`: what it may do while its Task runs (since 0.3.0). */
60
+ export interface WorkerContext {
61
+ /** Reports how far the Task is, as a fraction from 0 to 1 (not a percentage), with an optional message. */
62
+ sendProgress(progress: number, message?: string): void;
63
+ /**
64
+ * Aborted when the Task is Cancelled. Pass it on to anything that takes one, or check it between steps: a Worker
65
+ * that stops promptly frees its slot sooner. What `run` returns after it aborts is discarded.
66
+ */
67
+ readonly signal: AbortSignal;
68
+ }
69
+ /** One instance of a Worker, reused across the Tasks of its pool (since 0.3.0). */
70
+ export interface Worker<Settings = Record<string, unknown>, Input = unknown, Output = unknown> {
71
+ /** Does one Task. Throwing fails it; the error's message is what the Host shows. */
72
+ run(envelope: TaskEnvelope<Settings, Input>, context: WorkerContext): Output | Promise<Output>;
73
+ }
74
+ /**
75
+ * A Worker module's default export: a class whose constructor gets the config of the Profile its pool was built
76
+ * for (the Worker's `configSchema` checks it), once per instance (since 0.3.0).
77
+ */
78
+ export type WorkerClass<Config = Record<string, unknown>, Settings = Record<string, unknown>, Input = unknown, Output = unknown> = new (config: Config) => Worker<Settings, Input, Output>;
44
79
  /** Identity at runtime; gives plugin authors type checking and a single import. */
45
80
  export declare function definePlugin(plugin: Plugin): Plugin;
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
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`.
2
+ // `fyflow-plugin-sdk`: everything here is types but `definePlugin`, `SDK_VERSION`, `SDK_COMPATIBLE` and
3
+ // `DISK_GROUP`.
3
4
 
4
5
 
5
6
 
@@ -24,13 +25,21 @@
24
25
  * `fyflow-plugin-sdk` peer range excludes it, and every one in `SDK_COMPATIBLE`, is not loaded. Kept equal to
25
26
  * package.json's `version` (tested).
26
27
  */
27
- export const SDK_VERSION = "0.2.0";
28
+ export const SDK_VERSION = "0.3.0";
28
29
 
29
30
  /**
30
31
  * 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
+ * so a Host implements them too (ADR-0021). 0.2.0 only added optional fields, and 0.3.0 only types.
32
33
  */
33
- export const SDK_COMPATIBLE = ["0.1.0"];
34
+ export const SDK_COMPATIBLE = ["0.2.0", "0.1.0"];
35
+
36
+ /**
37
+ * The key of the `disk` Resource Group the Host's built-in Plugin declares (exported since 0.3.0): a concurrency
38
+ * limit (4 unless the Host overrides it) on Tasks that read or write the Host's disks. Any Plugin's Node Type may
39
+ * name it in `groups`, so a Plugin doing heavy disk work shares one budget with every other. Other Plugins' groups
40
+ * are out of reach.
41
+ */
42
+ export const DISK_GROUP = "disk";
34
43
 
35
44
  /** A Node Type as a Plugin declares it: fyflow's declaration, and how the app shows it (since 0.2.0). */
36
45
 
@@ -63,6 +72,43 @@ export const SDK_COMPATIBLE = ["0.1.0"];
63
72
 
64
73
 
65
74
 
75
+
76
+ /**
77
+ * What a Worker's `run` is handed for one Task: the Node's `settings` (checked by the Worker's `settingsSchema`)
78
+ * and the Task input, after the Node's transform if it has one (since 0.3.0).
79
+ */
80
+
81
+
82
+
83
+
84
+
85
+ /** The second argument to a Worker's `run`: what it may do while its Task runs (since 0.3.0). */
86
+
87
+
88
+
89
+
90
+
91
+
92
+
93
+
94
+
95
+
96
+ /** One instance of a Worker, reused across the Tasks of its pool (since 0.3.0). */
97
+
98
+
99
+
100
+
101
+
102
+ /**
103
+ * A Worker module's default export: a class whose constructor gets the config of the Profile its pool was built
104
+ * for (the Worker's `configSchema` checks it), once per instance (since 0.3.0).
105
+ */
106
+
107
+
108
+
109
+
110
+
111
+
66
112
 
67
113
  /** Identity at runtime; gives plugin authors type checking and a single import. */
68
114
  export function definePlugin(plugin ) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fyflow-plugin-sdk",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Types and definePlugin for fyflow-app Plugins: Node Types, Workers, gate types and Resource Groups",
5
5
  "keywords": [
6
6
  "fyflow",
@@ -20,7 +20,7 @@
20
20
  "access": "public"
21
21
  },
22
22
  "peerDependencies": {
23
- "fyflow-orchestration": "^0.11.0"
23
+ "fyflow-orchestration": "^0.12.0"
24
24
  },
25
25
  "peerDependenciesMeta": {
26
26
  "fyflow-orchestration": {
@@ -28,7 +28,7 @@
28
28
  }
29
29
  },
30
30
  "devDependencies": {
31
- "fyflow-orchestration": "0.11.0"
31
+ "fyflow-orchestration": "0.12.0"
32
32
  },
33
33
  "files": [
34
34
  "dist",
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
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`.
2
+ // `fyflow-plugin-sdk`: everything here is types but `definePlugin`, `SDK_VERSION`, `SDK_COMPATIBLE` and
3
+ // `DISK_GROUP`.
3
4
  import type {
4
5
  GateType,
5
6
  GroupInstance,
@@ -24,13 +25,21 @@ export type {
24
25
  * `fyflow-plugin-sdk` peer range excludes it, and every one in `SDK_COMPATIBLE`, is not loaded. Kept equal to
25
26
  * package.json's `version` (tested).
26
27
  */
27
- export const SDK_VERSION = "0.2.0";
28
+ export const SDK_VERSION = "0.3.0";
28
29
 
29
30
  /**
30
31
  * 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
+ * so a Host implements them too (ADR-0021). 0.2.0 only added optional fields, and 0.3.0 only types.
32
33
  */
33
- export const SDK_COMPATIBLE: readonly string[] = ["0.1.0"];
34
+ export const SDK_COMPATIBLE: readonly string[] = ["0.2.0", "0.1.0"];
35
+
36
+ /**
37
+ * The key of the `disk` Resource Group the Host's built-in Plugin declares (exported since 0.3.0): a concurrency
38
+ * limit (4 unless the Host overrides it) on Tasks that read or write the Host's disks. Any Plugin's Node Type may
39
+ * name it in `groups`, so a Plugin doing heavy disk work shares one budget with every other. Other Plugins' groups
40
+ * are out of reach.
41
+ */
42
+ export const DISK_GROUP = "disk";
34
43
 
35
44
  /** A Node Type as a Plugin declares it: fyflow's declaration, and how the app shows it (since 0.2.0). */
36
45
  export interface PluginNodeType extends NodeTypeDeclaration {
@@ -64,6 +73,43 @@ export interface Plugin {
64
73
  groups?: Readonly<Record<string, GroupInstance>>;
65
74
  }
66
75
 
76
+ /**
77
+ * What a Worker's `run` is handed for one Task: the Node's `settings` (checked by the Worker's `settingsSchema`)
78
+ * and the Task input, after the Node's transform if it has one (since 0.3.0).
79
+ */
80
+ export interface TaskEnvelope<Settings = Record<string, unknown>, Input = unknown> {
81
+ settings: Settings;
82
+ input: Input;
83
+ }
84
+
85
+ /** The second argument to a Worker's `run`: what it may do while its Task runs (since 0.3.0). */
86
+ export interface WorkerContext {
87
+ /** Reports how far the Task is, as a fraction from 0 to 1 (not a percentage), with an optional message. */
88
+ sendProgress(progress: number, message?: string): void;
89
+ /**
90
+ * Aborted when the Task is Cancelled. Pass it on to anything that takes one, or check it between steps: a Worker
91
+ * that stops promptly frees its slot sooner. What `run` returns after it aborts is discarded.
92
+ */
93
+ readonly signal: AbortSignal;
94
+ }
95
+
96
+ /** One instance of a Worker, reused across the Tasks of its pool (since 0.3.0). */
97
+ export interface Worker<Settings = Record<string, unknown>, Input = unknown, Output = unknown> {
98
+ /** Does one Task. Throwing fails it; the error's message is what the Host shows. */
99
+ run(envelope: TaskEnvelope<Settings, Input>, context: WorkerContext): Output | Promise<Output>;
100
+ }
101
+
102
+ /**
103
+ * A Worker module's default export: a class whose constructor gets the config of the Profile its pool was built
104
+ * for (the Worker's `configSchema` checks it), once per instance (since 0.3.0).
105
+ */
106
+ export type WorkerClass<
107
+ Config = Record<string, unknown>,
108
+ Settings = Record<string, unknown>,
109
+ Input = unknown,
110
+ Output = unknown,
111
+ > = new (config: Config) => Worker<Settings, Input, Output>;
112
+
67
113
  /** Identity at runtime; gives plugin authors type checking and a single import. */
68
114
  export function definePlugin(plugin: Plugin): Plugin {
69
115
  return plugin;