@visualautomate/plugin-sdk 0.7.0 → 0.8.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 +10 -23
- package/dist/index.cjs +22 -0
- package/dist/index.cjs.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +22 -0
- package/dist/index.mjs.map +2 -2
- package/dist/manifest-check.d.ts +10 -0
- package/dist/simulate.d.ts +4 -0
- package/dist/types.d.ts +8 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,13 +41,12 @@ in your manifest. `data` is what the next steps read.
|
|
|
41
41
|
| `storage` | the account's files — `put`, `get`, `delete`, `list`, `head`, `signedUrl`, `shareUrl`, `download` |
|
|
42
42
|
| `state` | values that outlive one run, scoped to the workflow — `get`, `set` (at most 128 KB, `ttlSeconds` at least 60), `delete`, `list` (`{ keys: [{ key, expiresAt }], complete }`) |
|
|
43
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, or none was chosen |
|
|
45
44
|
| `workflowId`, `nodeId`, `userId`, `executionId`, `startedAt`, `secrets` | about the run |
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
There is no connected account for your steps: only VisualAutomate's own apps act
|
|
47
|
+
as one (`checkManifest` refuses a `connection` property, `optionsFrom`,
|
|
48
|
+
`action.connection`, a `trigger` and `auth.provider`). A step reaches an API with
|
|
49
|
+
the key a user enters in a `secret` property.
|
|
51
50
|
|
|
52
51
|
## `simulate`
|
|
53
52
|
|
|
@@ -72,22 +71,9 @@ platform's have — `get` on a missing key is `null`, `put` takes a string or by
|
|
|
72
71
|
`list` is prefix-filtered, a state value over 128 KB or a `ttlSeconds` under 60 is
|
|
73
72
|
refused, and an expired value reads as `null`.
|
|
74
73
|
|
|
75
|
-
`
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
```ts
|
|
80
|
-
await simulate(plugin, {
|
|
81
|
-
connections: {
|
|
82
|
-
async get() {
|
|
83
|
-
return { id: "test", async request() { return { ok: true, status: 200, body: {} } } }
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
})
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
Asserting on what your plugin *asked* the provider for is a better test than any
|
|
90
|
-
imitation of the provider would be.
|
|
74
|
+
`media` is not simulated: `context.media` fails with a sentence saying so. Stub
|
|
75
|
+
`fetch` to test the code around an API call; asserting on what your plugin
|
|
76
|
+
*asked* for is a better test than any imitation of the API would be.
|
|
91
77
|
|
|
92
78
|
## The platform's code checks
|
|
93
79
|
|
|
@@ -143,8 +129,9 @@ check.errors // why it would be refused
|
|
|
143
129
|
check.warnings // what it would drop or regret
|
|
144
130
|
```
|
|
145
131
|
|
|
146
|
-
The SDK's own reading of the rules the portal enforces, for code steps
|
|
147
|
-
declared steps (`action`),
|
|
132
|
+
The SDK's own reading of the rules the portal enforces, for code steps and
|
|
133
|
+
declared steps (`action`), and the refusal of anything that would act as a
|
|
134
|
+
connected account (`accountUseIn` lists each way in); the portal's word is final.
|
|
148
135
|
|
|
149
136
|
## The platform's facts
|
|
150
137
|
|
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
ACCOUNTS_ARE_OURS: () => ACCOUNTS_ARE_OURS,
|
|
33
34
|
ALLOWED_PACKAGES: () => ALLOWED_PACKAGES,
|
|
34
35
|
ALLOWED_PACKAGE_NAMES: () => ALLOWED_PACKAGE_NAMES,
|
|
35
36
|
BLOCKED_GLOBALS: () => BLOCKED_GLOBALS,
|
|
@@ -45,6 +46,7 @@ __export(index_exports, {
|
|
|
45
46
|
SANDBOX_TIERS: () => SANDBOX_TIERS,
|
|
46
47
|
SIGNED_URL_SECONDS: () => SIGNED_URL_SECONDS,
|
|
47
48
|
STATE_LIMITS: () => STATE_LIMITS,
|
|
49
|
+
accountUseIn: () => accountUseIn,
|
|
48
50
|
checkManifest: () => checkManifest,
|
|
49
51
|
createLocalState: () => createLocalState,
|
|
50
52
|
createLocalStorage: () => createLocalStorage,
|
|
@@ -1679,6 +1681,23 @@ var MAX_PAGES = 50;
|
|
|
1679
1681
|
var MAX_MEMORY_MB = 128;
|
|
1680
1682
|
var isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1681
1683
|
var isRelativePath = (path) => typeof path === "string" && path.trim() !== "" && !/^[a-z][a-z0-9+.-]*:/i.test(path) && !path.startsWith("//");
|
|
1684
|
+
var ACCOUNTS_ARE_OURS = `Only VisualAutomate's own apps act as a connected account: call the API at its own address instead (action.baseUrl, or fetch in code), with a key the user enters in a property of type "secret"`;
|
|
1685
|
+
function accountUseIn(manifest) {
|
|
1686
|
+
if (!isObject(manifest)) return [];
|
|
1687
|
+
const m = manifest;
|
|
1688
|
+
const uses = [];
|
|
1689
|
+
if (isObject(m.properties)) {
|
|
1690
|
+
for (const [key, value] of Object.entries(m.properties)) {
|
|
1691
|
+
if (!isObject(value)) continue;
|
|
1692
|
+
if (value.type === "connection") uses.push(`properties.${key} is a connection: an account to act as`);
|
|
1693
|
+
if (value.optionsFrom !== void 0) uses.push(`properties.${key}.optionsFrom reads its options as an account`);
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
if (isObject(m.action) && m.action.connection !== void 0) uses.push("action.connection makes the call as an account");
|
|
1697
|
+
if (m.trigger !== void 0) uses.push("trigger watches an account");
|
|
1698
|
+
if (isObject(m.auth) && typeof m.auth.provider === "string" && m.auth.provider) uses.push(`auth.provider names "${m.auth.provider}"`);
|
|
1699
|
+
return uses;
|
|
1700
|
+
}
|
|
1682
1701
|
function checkManifest(raw, hasCode) {
|
|
1683
1702
|
const errors = [];
|
|
1684
1703
|
const warnings = [];
|
|
@@ -1720,6 +1739,8 @@ function checkManifest(raw, hasCode) {
|
|
|
1720
1739
|
else {
|
|
1721
1740
|
if (typeof m.auth.type !== "string" || !AUTH_TYPES.has(m.auth.type)) {
|
|
1722
1741
|
errors.push(`auth.type must be one of ${[...AUTH_TYPES].join(", ")}.`);
|
|
1742
|
+
} else if (m.auth.type !== "none" && !m.auth.provider) {
|
|
1743
|
+
errors.push(`auth.type "${m.auth.type}" needs a provider to sign in to, and only VisualAutomate's own apps name one: use { "type": "none" } and take the user's key in a property of type "secret".`);
|
|
1723
1744
|
}
|
|
1724
1745
|
for (const key of HOST_KEYS) {
|
|
1725
1746
|
if (key in m.auth) errors.push(`auth.${key} is refused: a manifest may not name a host. The provider's base URL belongs to the platform.`);
|
|
@@ -1753,6 +1774,7 @@ function checkManifest(raw, hasCode) {
|
|
|
1753
1774
|
if (kind === "code" && !hasCode) {
|
|
1754
1775
|
errors.push("There is no index.js and no action or trigger block, so this step has nothing to run.");
|
|
1755
1776
|
}
|
|
1777
|
+
for (const use of accountUseIn(m)) errors.push(`${use}. ${ACCOUNTS_ARE_OURS}`);
|
|
1756
1778
|
return { ok: errors.length === 0, kind, errors, warnings };
|
|
1757
1779
|
}
|
|
1758
1780
|
function checkConnectionName(where, name, typeOf, errors) {
|