@visualautomate/plugin-sdk 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/LICENSE +21 -0
- package/README.md +110 -0
- package/dist/context-api.d.ts +41 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +1534 -0
- package/dist/index.js.map +7 -0
- package/dist/index.mjs +1511 -0
- package/dist/index.mjs.map +7 -0
- package/dist/platform-rules.d.ts +14 -0
- package/dist/simulate.d.ts +81 -0
- package/dist/types.d.ts +418 -0
- package/dist/validate.d.ts +46 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 WvB Solutions
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# @visualautomate/plugin-sdk
|
|
2
|
+
|
|
3
|
+
The types a VisualAutomate plugin is written against, and a way to run one on
|
|
4
|
+
your own machine.
|
|
5
|
+
|
|
6
|
+
Most people do not need to install this. `@visualautomate/cli` carries it and
|
|
7
|
+
writes the types into your project, so a scaffolded plugin has no dependencies
|
|
8
|
+
at all. Install it directly if you want the simulator in your own test suite.
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install --save-dev @visualautomate/plugin-sdk
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## A plugin
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import type { PluginModule } from "@visualautomate/plugin-sdk"
|
|
18
|
+
|
|
19
|
+
const plugin: PluginModule = {
|
|
20
|
+
async execute(input, config, context) {
|
|
21
|
+
const bytes = await context.storage.get(config.path as string)
|
|
22
|
+
if (!bytes) return { output: "error", data: { error: "No such file." } }
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
output: "success",
|
|
26
|
+
data: { size: bytes.length },
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default plugin
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`output` names which port the run leaves by, and has to be one of the `outputs`
|
|
35
|
+
in your manifest. `data` is what the next steps read.
|
|
36
|
+
|
|
37
|
+
## What `context` has
|
|
38
|
+
|
|
39
|
+
| | |
|
|
40
|
+
|---|---|
|
|
41
|
+
| `storage` | the account's files — `put`, `get`, `delete`, `list`, `head`, `signedUrl`, `download` |
|
|
42
|
+
| `state` | values that outlive one run, scoped to the workflow — `get`, `set`, `delete`, `list` |
|
|
43
|
+
| `media` | ffmpeg, by operation name. Absent when the server has no sandbox configured |
|
|
44
|
+
| `connections` | the accounts this step was configured with. Absent when it declares none |
|
|
45
|
+
| `workflowId`, `nodeId`, `userId`, `executionId`, `startedAt`, `secrets` | about the run |
|
|
46
|
+
|
|
47
|
+
You never see a credential and you never name a host. `connections.get("account")`
|
|
48
|
+
takes the name of one of *your* properties, and the platform attaches the token
|
|
49
|
+
on the way past — which is what stops a plugin pointing somebody's account
|
|
50
|
+
somewhere it chose.
|
|
51
|
+
|
|
52
|
+
## `simulate`
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { simulate } from "@visualautomate/plugin-sdk"
|
|
56
|
+
import plugin from "./plugin"
|
|
57
|
+
|
|
58
|
+
const result = await simulate(plugin, {
|
|
59
|
+
config: { path: "notes/a.txt" },
|
|
60
|
+
storage: { "notes/a.txt": "hello" },
|
|
61
|
+
state: { runs: 0 },
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
result.status // "success" | "error" | "timeout" | ...
|
|
65
|
+
result.output?.data
|
|
66
|
+
result.files // what storage holds now
|
|
67
|
+
result.state // what state holds now
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Storage and state are real, in memory, with the same edge cases the platform's
|
|
71
|
+
have — `get` on a missing key is `null`, `put` takes a string or bytes, `list`
|
|
72
|
+
is prefix-filtered.
|
|
73
|
+
|
|
74
|
+
`connections` and `media` are not simulated. Pass a stub if you want to test the
|
|
75
|
+
code around them:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
await simulate(plugin, {
|
|
79
|
+
connections: {
|
|
80
|
+
async get() {
|
|
81
|
+
return { id: "test", async request() { return { ok: true, status: 200, body: {} } } }
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Asserting on what your plugin *asked* the provider for is a better test than any
|
|
88
|
+
imitation of the provider would be.
|
|
89
|
+
|
|
90
|
+
## The platform's code checks
|
|
91
|
+
|
|
92
|
+
The rules the platform applies to a plugin's code on upload, so a test can
|
|
93
|
+
refuse what the platform would refuse:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { validatePluginCode, ALLOWED_PACKAGES } from "@visualautomate/plugin-sdk"
|
|
97
|
+
|
|
98
|
+
const check = validatePluginCode(code)
|
|
99
|
+
if (!check.valid) throw new Error(check.error)
|
|
100
|
+
check.packages // the allowed packages this code requires
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`ALLOWED_PACKAGES` lists every npm package a plugin may `require`, with the
|
|
104
|
+
version the sandbox has installed. Nothing else is available: no `fs`, no
|
|
105
|
+
`http`, and no subpaths like `lodash/get`.
|
|
106
|
+
|
|
107
|
+
`sandboxRequire(load)` and `loadPluginCode(code, require)` load code the way
|
|
108
|
+
the sandbox does, as the body of a function given `module`, `exports` and a
|
|
109
|
+
`require` that only hands out allowed packages. `visualautomate test` uses
|
|
110
|
+
them; they are here for your own test runner.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The runtime API, as data.
|
|
3
|
+
*
|
|
4
|
+
* The same things types.ts describes, in a form a tool can read without a
|
|
5
|
+
* TypeScript compiler: an editor's autocomplete, a documentation page, a lint
|
|
6
|
+
* rule. Each entry is a name an author types, what it is, and a one-line
|
|
7
|
+
* description.
|
|
8
|
+
*
|
|
9
|
+
* Plain data with no imports, so it can go into a browser bundle without the
|
|
10
|
+
* rest of the SDK.
|
|
11
|
+
*/
|
|
12
|
+
export interface ContextApiEntry {
|
|
13
|
+
/** What an author types, e.g. `context.storage.put`. */
|
|
14
|
+
path: string;
|
|
15
|
+
/** `property` for a value, `method` for something you call. */
|
|
16
|
+
kind: "variable" | "property" | "method";
|
|
17
|
+
/** The signature, for a method. Shown beside the name. */
|
|
18
|
+
signature?: string;
|
|
19
|
+
/** One line, in the hover card. */
|
|
20
|
+
info: string;
|
|
21
|
+
/**
|
|
22
|
+
* Set when the helper is not always there.
|
|
23
|
+
*
|
|
24
|
+
* The editor says so, because the alternative is an author writing
|
|
25
|
+
* `context.media.run(...)` against a completion that promised it existed
|
|
26
|
+
* and meeting `undefined` on somebody's canvas.
|
|
27
|
+
*/
|
|
28
|
+
conditional?: string;
|
|
29
|
+
}
|
|
30
|
+
/** Everything a plugin is called with, and everything it can reach. */
|
|
31
|
+
export declare const CONTEXT_API: ContextApiEntry[];
|
|
32
|
+
/**
|
|
33
|
+
* The globals a plugin does NOT get, and what to reach for instead.
|
|
34
|
+
*
|
|
35
|
+
* Worth offering in an editor as much as the API is: an author who types
|
|
36
|
+
* `require('fs')` should be told at the keystroke rather than at the push.
|
|
37
|
+
*/
|
|
38
|
+
export declare const BLOCKED_GLOBALS: Array<{
|
|
39
|
+
name: string;
|
|
40
|
+
instead: string;
|
|
41
|
+
}>;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @visualautomate/plugin-sdk
|
|
3
|
+
*
|
|
4
|
+
* Three things: the types a plugin is written against, a way to run one on
|
|
5
|
+
* your own machine before it goes anywhere near a canvas, and the checks the
|
|
6
|
+
* platform applies to a plugin's code before it will accept it.
|
|
7
|
+
*
|
|
8
|
+
* Nothing here runs inside the sandbox. Plugin code is plain JavaScript that
|
|
9
|
+
* the platform loads; this package exists so an editor can tell you what
|
|
10
|
+
* `context` has on it, and so `visualautomate test` can call your execute with
|
|
11
|
+
* a context that behaves like the real one.
|
|
12
|
+
*/
|
|
13
|
+
export * from "./types";
|
|
14
|
+
export * from "./simulate";
|
|
15
|
+
export * from "./validate";
|
|
16
|
+
export { CONTEXT_API, BLOCKED_GLOBALS, type ContextApiEntry } from "./context-api";
|