@revenexx/integrations-node-sdk 0.12.1 → 0.13.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 +2 -1
- package/dist/cli.cjs +57 -7
- package/dist/cli.js +60 -8
- package/dist/index.d.cts +112 -8
- package/dist/index.d.ts +112 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,8 @@ packages and the workflow engine that runs them.
|
|
|
11
11
|
```
|
|
12
12
|
integrations-node-sdk ← this package (types & helpers only)
|
|
13
13
|
└── integrations-nodes-core ← implements INode, ships dist/manifest.json
|
|
14
|
-
└── integrations-worker ←
|
|
14
|
+
└── integrations-worker ← reads the manifest, executes workflows
|
|
15
|
+
(no SDK dependency — couples via manifestVersion)
|
|
15
16
|
```
|
|
16
17
|
|
|
17
18
|
## Installation
|
package/dist/cli.cjs
CHANGED
|
@@ -24,9 +24,58 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/cli.ts
|
|
27
|
+
var fs2 = __toESM(require("fs"), 1);
|
|
28
|
+
var import_node_path2 = require("path");
|
|
29
|
+
var import_node_url = require("url");
|
|
30
|
+
|
|
31
|
+
// src/images.ts
|
|
27
32
|
var fs = __toESM(require("fs"), 1);
|
|
28
33
|
var import_node_path = require("path");
|
|
29
|
-
|
|
34
|
+
function collectImageSources(manifest) {
|
|
35
|
+
const sources = /* @__PURE__ */ new Set();
|
|
36
|
+
for (const group of [manifest.nodes, manifest.credentials, manifest.templates]) {
|
|
37
|
+
for (const item of group ?? []) {
|
|
38
|
+
for (const image of item.images ?? []) {
|
|
39
|
+
if (typeof image.src === "string" && image.src.length > 0) {
|
|
40
|
+
sources.add(image.src);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return [...sources];
|
|
46
|
+
}
|
|
47
|
+
function copyImages(sources, outDir, rootDir) {
|
|
48
|
+
let copied = 0;
|
|
49
|
+
for (const src of sources) {
|
|
50
|
+
if (!isSafeRelativePath(src)) {
|
|
51
|
+
console.warn(` \u26A0 unsafe image path (absolute or escaping the package root), skipping: ${src}`);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const from = (0, import_node_path.resolve)(rootDir, src);
|
|
55
|
+
if (!fs.existsSync(from)) {
|
|
56
|
+
console.warn(` \u26A0 image not found, skipping: ${src}`);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (!fs.statSync(from).isFile()) {
|
|
60
|
+
console.warn(` \u26A0 image path is not a file, skipping: ${src}`);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
const to = (0, import_node_path.resolve)(outDir, src);
|
|
64
|
+
fs.mkdirSync((0, import_node_path.dirname)(to), { recursive: true });
|
|
65
|
+
fs.copyFileSync(from, to);
|
|
66
|
+
copied++;
|
|
67
|
+
}
|
|
68
|
+
if (sources.length > 0) {
|
|
69
|
+
console.log(` copied ${copied}/${sources.length} image(s) into dist/`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function isSafeRelativePath(src) {
|
|
73
|
+
if ((0, import_node_path.isAbsolute)(src)) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
const normalized = (0, import_node_path.normalize)(src);
|
|
77
|
+
return normalized !== ".." && !normalized.startsWith(".." + import_node_path.sep);
|
|
78
|
+
}
|
|
30
79
|
|
|
31
80
|
// src/extract.ts
|
|
32
81
|
function extractManifest(node) {
|
|
@@ -65,8 +114,8 @@ function fail(message) {
|
|
|
65
114
|
process.exit(1);
|
|
66
115
|
}
|
|
67
116
|
async function runManifest() {
|
|
68
|
-
const distEntry = (0,
|
|
69
|
-
if (!
|
|
117
|
+
const distEntry = (0, import_node_path2.resolve)(projectRoot, "dist", "index.js");
|
|
118
|
+
if (!fs2.existsSync(distEntry)) {
|
|
70
119
|
fail("dist/index.js is missing. Run the build (tsup) before `rvnxx-nodes manifest`.");
|
|
71
120
|
}
|
|
72
121
|
const mod = await import((0, import_node_url.pathToFileURL)(distEntry).href);
|
|
@@ -82,10 +131,10 @@ async function runManifest() {
|
|
|
82
131
|
const credentials = mod.CREDENTIALS ?? [];
|
|
83
132
|
const templates = mod.TEMPLATES ?? [];
|
|
84
133
|
const manifest = buildManifest(mod.NODES, credentials, templates);
|
|
85
|
-
const outDir = (0,
|
|
86
|
-
const outFile = (0,
|
|
87
|
-
|
|
88
|
-
|
|
134
|
+
const outDir = (0, import_node_path2.resolve)(projectRoot, "dist");
|
|
135
|
+
const outFile = (0, import_node_path2.resolve)(outDir, "manifest.json");
|
|
136
|
+
fs2.mkdirSync(outDir, { recursive: true });
|
|
137
|
+
fs2.writeFileSync(outFile, JSON.stringify(manifest, null, 2), "utf-8");
|
|
89
138
|
const credentialCount = manifest.credentials?.length ?? 0;
|
|
90
139
|
const templateCount = manifest.templates?.length ?? 0;
|
|
91
140
|
console.log(
|
|
@@ -100,6 +149,7 @@ async function runManifest() {
|
|
|
100
149
|
for (const t of manifest.templates ?? []) {
|
|
101
150
|
console.log(` template ${t.slug}@${t.version} (${t.level})`);
|
|
102
151
|
}
|
|
152
|
+
copyImages(collectImageSources(manifest), outDir, projectRoot);
|
|
103
153
|
}
|
|
104
154
|
async function main() {
|
|
105
155
|
const command = process.argv[2];
|
package/dist/cli.js
CHANGED
|
@@ -4,17 +4,68 @@ import {
|
|
|
4
4
|
} from "./chunk-X5HI7WPI.js";
|
|
5
5
|
|
|
6
6
|
// src/cli.ts
|
|
7
|
-
import * as
|
|
8
|
-
import { resolve } from "path";
|
|
7
|
+
import * as fs2 from "fs";
|
|
8
|
+
import { resolve as resolve2 } from "path";
|
|
9
9
|
import { pathToFileURL } from "url";
|
|
10
|
+
|
|
11
|
+
// src/images.ts
|
|
12
|
+
import * as fs from "fs";
|
|
13
|
+
import { dirname, isAbsolute, normalize, resolve, sep } from "path";
|
|
14
|
+
function collectImageSources(manifest) {
|
|
15
|
+
const sources = /* @__PURE__ */ new Set();
|
|
16
|
+
for (const group of [manifest.nodes, manifest.credentials, manifest.templates]) {
|
|
17
|
+
for (const item of group ?? []) {
|
|
18
|
+
for (const image of item.images ?? []) {
|
|
19
|
+
if (typeof image.src === "string" && image.src.length > 0) {
|
|
20
|
+
sources.add(image.src);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return [...sources];
|
|
26
|
+
}
|
|
27
|
+
function copyImages(sources, outDir, rootDir) {
|
|
28
|
+
let copied = 0;
|
|
29
|
+
for (const src of sources) {
|
|
30
|
+
if (!isSafeRelativePath(src)) {
|
|
31
|
+
console.warn(` \u26A0 unsafe image path (absolute or escaping the package root), skipping: ${src}`);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const from = resolve(rootDir, src);
|
|
35
|
+
if (!fs.existsSync(from)) {
|
|
36
|
+
console.warn(` \u26A0 image not found, skipping: ${src}`);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (!fs.statSync(from).isFile()) {
|
|
40
|
+
console.warn(` \u26A0 image path is not a file, skipping: ${src}`);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const to = resolve(outDir, src);
|
|
44
|
+
fs.mkdirSync(dirname(to), { recursive: true });
|
|
45
|
+
fs.copyFileSync(from, to);
|
|
46
|
+
copied++;
|
|
47
|
+
}
|
|
48
|
+
if (sources.length > 0) {
|
|
49
|
+
console.log(` copied ${copied}/${sources.length} image(s) into dist/`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function isSafeRelativePath(src) {
|
|
53
|
+
if (isAbsolute(src)) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const normalized = normalize(src);
|
|
57
|
+
return normalized !== ".." && !normalized.startsWith(".." + sep);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/cli.ts
|
|
10
61
|
var projectRoot = process.cwd();
|
|
11
62
|
function fail(message) {
|
|
12
63
|
console.error(`Error: ${message}`);
|
|
13
64
|
process.exit(1);
|
|
14
65
|
}
|
|
15
66
|
async function runManifest() {
|
|
16
|
-
const distEntry =
|
|
17
|
-
if (!
|
|
67
|
+
const distEntry = resolve2(projectRoot, "dist", "index.js");
|
|
68
|
+
if (!fs2.existsSync(distEntry)) {
|
|
18
69
|
fail("dist/index.js is missing. Run the build (tsup) before `rvnxx-nodes manifest`.");
|
|
19
70
|
}
|
|
20
71
|
const mod = await import(pathToFileURL(distEntry).href);
|
|
@@ -30,10 +81,10 @@ async function runManifest() {
|
|
|
30
81
|
const credentials = mod.CREDENTIALS ?? [];
|
|
31
82
|
const templates = mod.TEMPLATES ?? [];
|
|
32
83
|
const manifest = buildManifest(mod.NODES, credentials, templates);
|
|
33
|
-
const outDir =
|
|
34
|
-
const outFile =
|
|
35
|
-
|
|
36
|
-
|
|
84
|
+
const outDir = resolve2(projectRoot, "dist");
|
|
85
|
+
const outFile = resolve2(outDir, "manifest.json");
|
|
86
|
+
fs2.mkdirSync(outDir, { recursive: true });
|
|
87
|
+
fs2.writeFileSync(outFile, JSON.stringify(manifest, null, 2), "utf-8");
|
|
37
88
|
const credentialCount = manifest.credentials?.length ?? 0;
|
|
38
89
|
const templateCount = manifest.templates?.length ?? 0;
|
|
39
90
|
console.log(
|
|
@@ -48,6 +99,7 @@ async function runManifest() {
|
|
|
48
99
|
for (const t of manifest.templates ?? []) {
|
|
49
100
|
console.log(` template ${t.slug}@${t.version} (${t.level})`);
|
|
50
101
|
}
|
|
102
|
+
copyImages(collectImageSources(manifest), outDir, projectRoot);
|
|
51
103
|
}
|
|
52
104
|
async function main() {
|
|
53
105
|
const command = process.argv[2];
|
package/dist/index.d.cts
CHANGED
|
@@ -2,7 +2,25 @@ type LocalizedString = string | Record<string, string>;
|
|
|
2
2
|
type DataType = 'any' | 'object' | 'array' | 'string' | 'number' | 'boolean';
|
|
3
3
|
type OutputKind = 'default' | 'branch' | 'error';
|
|
4
4
|
type NodeCategory = 'trigger' | 'action' | 'transform' | 'control' | 'io';
|
|
5
|
-
type ConfigType = 'string' | 'number' | 'boolean' | 'select' | 'multiselect' | 'object' | 'array' | 'expression' | 'secret-ref' | 'credentials-ref';
|
|
5
|
+
type ConfigType = 'string' | 'number' | 'boolean' | 'select' | 'multiselect' | 'object' | 'array' | 'expression' | 'secret-ref' | 'credentials-ref' | 'dynamic-schema';
|
|
6
|
+
/**
|
|
7
|
+
* Semantic category of an image, driving how the registry/CDN organises and
|
|
8
|
+
* displays it.
|
|
9
|
+
*/
|
|
10
|
+
type ImageCategory = 'screenshot' | 'logo' | 'banner' | 'icon' | 'other';
|
|
11
|
+
/**
|
|
12
|
+
* A single image a node, credential type, or template ships alongside its
|
|
13
|
+
* description (e.g. a screenshot, logo, or banner). The file is bundled into
|
|
14
|
+
* the package tarball and uploaded to the Revenexx CDN when the package is
|
|
15
|
+
* published.
|
|
16
|
+
*/
|
|
17
|
+
interface IImage {
|
|
18
|
+
/** Path to the image file, relative to the package root (e.g. `images/screenshot.png`). */
|
|
19
|
+
src: string;
|
|
20
|
+
alt: LocalizedString;
|
|
21
|
+
title?: LocalizedString;
|
|
22
|
+
category: ImageCategory;
|
|
23
|
+
}
|
|
6
24
|
interface IInputPort {
|
|
7
25
|
dataType: DataType;
|
|
8
26
|
required?: boolean;
|
|
@@ -20,6 +38,14 @@ interface IOutputPort {
|
|
|
20
38
|
description?: LocalizedString;
|
|
21
39
|
fields?: Record<string, IOutputField>;
|
|
22
40
|
sourceFromConfig?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Marks a generic port set resolved at author time by the node's
|
|
43
|
+
* `resolveOutputs` callback (PO-143), rather than a static `name` or a
|
|
44
|
+
* config-driven `sourceFromConfig`. Set at most one of `name`,
|
|
45
|
+
* `sourceFromConfig`, `resolveOutputs` — this is a server-validated
|
|
46
|
+
* constraint on publish, not enforced by this (intentionally flat) type.
|
|
47
|
+
*/
|
|
48
|
+
resolveOutputs?: boolean;
|
|
23
49
|
fallback?: {
|
|
24
50
|
name: string;
|
|
25
51
|
label?: LocalizedString;
|
|
@@ -49,6 +75,23 @@ interface IConfigFieldBase {
|
|
|
49
75
|
multiline?: boolean;
|
|
50
76
|
validation?: IConfigValidation;
|
|
51
77
|
options?: IConfigOption[];
|
|
78
|
+
/**
|
|
79
|
+
* When true, a *known* field's `options` are resolved at author time via the
|
|
80
|
+
* node's `loadOptions` (a live/dependent dropdown) instead of a static
|
|
81
|
+
* `options[]`. Applies to `select` / `multiselect`; left unset for ordinary
|
|
82
|
+
* static fields.
|
|
83
|
+
*
|
|
84
|
+
* Independent of `type: 'dynamic-schema'`: that field type triggers
|
|
85
|
+
* `resolveConfigSchema` on its own and does NOT require `dynamic: true`.
|
|
86
|
+
*/
|
|
87
|
+
dynamic?: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Config keys whose values drive this field's dynamic resolution. The editor
|
|
90
|
+
* re-resolves when one of them changes. A key listed here is
|
|
91
|
+
* *dependency-driving* and MUST be a literal (it may not set
|
|
92
|
+
* `expressionAllowed`), so its value is known at author time.
|
|
93
|
+
*/
|
|
94
|
+
dependsOn?: string[];
|
|
52
95
|
/**
|
|
53
96
|
* Only meaningful when `type === 'credentials-ref'`: the namespaced slug(s) of
|
|
54
97
|
* the credential type(s) this field accepts (e.g. `revenexx:smtp`). The editor
|
|
@@ -70,6 +113,8 @@ interface INodeDescription {
|
|
|
70
113
|
name: LocalizedString;
|
|
71
114
|
description?: LocalizedString;
|
|
72
115
|
icon?: string;
|
|
116
|
+
/** Associated images (screenshots, logos, banners) shipped with the package. */
|
|
117
|
+
images?: IImage[];
|
|
73
118
|
inputs: Record<string, IInputPort>;
|
|
74
119
|
outputs: IOutputPort[];
|
|
75
120
|
config?: IConfigField[];
|
|
@@ -99,18 +144,73 @@ interface INodeResult {
|
|
|
99
144
|
outputs: Record<string, unknown>;
|
|
100
145
|
branch?: string;
|
|
101
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Context handed to a node's *author-time* resolvers (`loadOptions`,
|
|
149
|
+
* `resolveConfigSchema`, `resolveOutputs`). These run in the node-runtime host
|
|
150
|
+
* (a Node side-container) while a user is editing the workflow — never in
|
|
151
|
+
* `execute`. The result is snapshotted into the workflow blob at save, so the
|
|
152
|
+
* runtime never calls these (PO-143).
|
|
153
|
+
*/
|
|
154
|
+
interface INodeAuthorContext {
|
|
155
|
+
signal: AbortSignal;
|
|
156
|
+
logger: {
|
|
157
|
+
info(message: string, meta?: Record<string, unknown>): void;
|
|
158
|
+
warn(message: string, meta?: Record<string, unknown>): void;
|
|
159
|
+
error(message: string, meta?: Record<string, unknown>): void;
|
|
160
|
+
};
|
|
161
|
+
/** The user's current partial config values. */
|
|
162
|
+
config: Record<string, unknown>;
|
|
163
|
+
/**
|
|
164
|
+
* Lazily resolve a `secret-ref` config field's value (a key in the tenant
|
|
165
|
+
* secret store → a single string). Mirrors {@link INodeContext.secrets} so a
|
|
166
|
+
* resolver that authenticates via a secret-ref uses the same call it would in
|
|
167
|
+
* `execute`. Resolves against the internal secret endpoint; only the keys the
|
|
168
|
+
* resolver actually asks for are fetched.
|
|
169
|
+
*/
|
|
170
|
+
secrets: {
|
|
171
|
+
get(key: string): Promise<string>;
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* Lazily resolve a `credentials-ref` instance's access data via the
|
|
175
|
+
* credentials broker (id → structured material, e.g. `{ accessToken }`).
|
|
176
|
+
* Mirrors {@link INodeContext.credentials}.
|
|
177
|
+
*/
|
|
178
|
+
credentials: {
|
|
179
|
+
get(credentialsId: string): Promise<Record<string, unknown>>;
|
|
180
|
+
};
|
|
181
|
+
/** Preferred locale for resolved labels, when the caller supplies one. */
|
|
182
|
+
locale?: string;
|
|
183
|
+
}
|
|
102
184
|
interface INode {
|
|
103
185
|
description: INodeDescription;
|
|
104
186
|
execute(ctx: INodeContext, inputs: Record<string, unknown>): Promise<INodeResult>;
|
|
187
|
+
/**
|
|
188
|
+
* Author-time: resolve the options of a `dynamic` field (a live/dependent
|
|
189
|
+
* dropdown). `fieldKey` is the config key being resolved. Optional — declare
|
|
190
|
+
* it only for nodes with `dynamic` `select`/`multiselect` fields.
|
|
191
|
+
*/
|
|
192
|
+
loadOptions?(ctx: INodeAuthorContext, fieldKey: string): Promise<IConfigOption[]>;
|
|
193
|
+
/**
|
|
194
|
+
* Author-time: resolve the flat set of typed config fields that replaces a
|
|
195
|
+
* `type: 'dynamic-schema'` marker (e.g. an API's parameters once app + API
|
|
196
|
+
* are chosen). Returns fields in the same config-field grammar; the node is
|
|
197
|
+
* responsible for flattening any nested API shape into flat keys.
|
|
198
|
+
*/
|
|
199
|
+
resolveConfigSchema?(ctx: INodeAuthorContext): Promise<IConfigField[]>;
|
|
200
|
+
/**
|
|
201
|
+
* Author-time: resolve a generic output-port set for an output marked
|
|
202
|
+
* `resolveOutputs` (e.g. ports derived from a connected resource's schema).
|
|
203
|
+
*/
|
|
204
|
+
resolveOutputs?(ctx: INodeAuthorContext): Promise<IOutputPort[]>;
|
|
105
205
|
}
|
|
106
206
|
/**
|
|
107
207
|
* Optional capability interface for nodes that iterate over a collection.
|
|
108
|
-
* Implement this alongside {@link INode} to signal to the
|
|
109
|
-
* node drives iteration — the
|
|
208
|
+
* Implement this alongside {@link INode} to signal to the runtime that this
|
|
209
|
+
* node drives iteration — the runtime will call {@link extractItems} instead
|
|
110
210
|
* of relying on slug-based detection.
|
|
111
211
|
*
|
|
112
212
|
* This interface is the designated dispatch point for future child-workflow
|
|
113
|
-
* execution: once per-iteration isolation is needed, the
|
|
213
|
+
* execution: once per-iteration isolation is needed, the runtime can swap the
|
|
114
214
|
* inline loop for `executeChild` calls without any changes to the node or SDK.
|
|
115
215
|
*/
|
|
116
216
|
interface INodeWithIteration {
|
|
@@ -159,6 +259,8 @@ interface ICredentialDescription {
|
|
|
159
259
|
name: LocalizedString;
|
|
160
260
|
description?: LocalizedString;
|
|
161
261
|
icon?: string;
|
|
262
|
+
/** Associated images (screenshots, logos, banners) shipped with the package. */
|
|
263
|
+
images?: IImage[];
|
|
162
264
|
authKind: CredentialAuthKind;
|
|
163
265
|
fields: ICredentialField[];
|
|
164
266
|
}
|
|
@@ -270,6 +372,8 @@ interface ITemplateDescription {
|
|
|
270
372
|
industries?: string[];
|
|
271
373
|
/** Free-form vendor tags (e.g. `pipedrive`, `slack`). */
|
|
272
374
|
vendors?: string[];
|
|
375
|
+
/** Associated images (screenshots, logos, banners) shipped with the package. */
|
|
376
|
+
images?: IImage[];
|
|
273
377
|
/** Workflow-blob schema version `definition` targets (e.g. `v0-draft`). */
|
|
274
378
|
blobVersion: string;
|
|
275
379
|
/** The workflow blob instantiated when a user picks this template. */
|
|
@@ -284,7 +388,7 @@ interface ITemplateDescription {
|
|
|
284
388
|
/**
|
|
285
389
|
* Reduce a {@link LocalizedString} to a single plain string.
|
|
286
390
|
*
|
|
287
|
-
* Every consumer (
|
|
391
|
+
* Every consumer (the UI, the Laravel side) repeats the same "is it a
|
|
288
392
|
* string or a localized map?" branch to render a name/label; this centralizes
|
|
289
393
|
* it so the rules are defined once:
|
|
290
394
|
*
|
|
@@ -302,8 +406,8 @@ declare function normalizeLocalized(value: LocalizedString | undefined | null, f
|
|
|
302
406
|
*
|
|
303
407
|
* The union `string | string[]` exists so node authors can write the common
|
|
304
408
|
* single-type case as a bare string, but every consumer (the editor that
|
|
305
|
-
* lists tenant credential instances, the
|
|
306
|
-
*
|
|
409
|
+
* lists tenant credential instances, the Laravel side) needs a list to
|
|
410
|
+
* iterate. This centralizes the
|
|
307
411
|
* "is it a string or an array?" branch — analogous to {@link normalizeLocalized}
|
|
308
412
|
* for `LocalizedString` — so the rules are defined once:
|
|
309
413
|
*
|
|
@@ -489,4 +593,4 @@ declare abstract class OAuth2AuthCodeCredential extends BaseCredential implement
|
|
|
489
593
|
test(_ctx: ICredentialContext, config: Config): Promise<ICredentialTestResult>;
|
|
490
594
|
}
|
|
491
595
|
|
|
492
|
-
export { ApiKeyCredential, BaseCredential, BasicAuthCredential, type ConfigType, type CredentialAuthKind, type CredentialFieldType, DEFAULT_RETRY_ATTEMPTS, DEFAULT_RETRY_DELAY_MS, DEFAULT_TIMEOUT_MS, type DataType, type IConfigField, type IConfigFieldBase, type IConfigOption, type IConfigValidation, type ICredential, type ICredentialContext, type ICredentialDescription, type ICredentialField, type ICredentialOAuthAuthorize, type ICredentialResolveResult, type ICredentialTestResult, type IInputPort, type INode, type INodeContext, type INodeDescription, type INodeResult, type INodeWithIteration, type IOutputField, type IOutputPort, type ITemplateDescription, type ITemplateTrigger, type LocalizedString, MANIFEST_VERSION, MAX_RETRY_ATTEMPTS, MAX_TIMEOUT_MS, type NodeCategory, NodeError, type NodeManifest, OAuth2AuthCodeCredential, OAuth2ClientCredentialsCredential, type OAuthTokenResponse, type OutputKind, type SafeFetchOptions, type SafeFetchRetry, SimpleValueCredential, type TemplateLevel, type TemplateTriggerType, buildManifest, extractCredentialManifest, extractCredentialManifests, extractManifest, extractManifests, isNodeWithIteration, isOAuthAuthorizeCredential, normalizeCredentialType, normalizeLocalized, retryConfigFields, safeFetch, timeoutConfigField };
|
|
596
|
+
export { ApiKeyCredential, BaseCredential, BasicAuthCredential, type ConfigType, type CredentialAuthKind, type CredentialFieldType, DEFAULT_RETRY_ATTEMPTS, DEFAULT_RETRY_DELAY_MS, DEFAULT_TIMEOUT_MS, type DataType, type IConfigField, type IConfigFieldBase, type IConfigOption, type IConfigValidation, type ICredential, type ICredentialContext, type ICredentialDescription, type ICredentialField, type ICredentialOAuthAuthorize, type ICredentialResolveResult, type ICredentialTestResult, type IImage, type IInputPort, type INode, type INodeAuthorContext, type INodeContext, type INodeDescription, type INodeResult, type INodeWithIteration, type IOutputField, type IOutputPort, type ITemplateDescription, type ITemplateTrigger, type ImageCategory, type LocalizedString, MANIFEST_VERSION, MAX_RETRY_ATTEMPTS, MAX_TIMEOUT_MS, type NodeCategory, NodeError, type NodeManifest, OAuth2AuthCodeCredential, OAuth2ClientCredentialsCredential, type OAuthTokenResponse, type OutputKind, type SafeFetchOptions, type SafeFetchRetry, SimpleValueCredential, type TemplateLevel, type TemplateTriggerType, buildManifest, extractCredentialManifest, extractCredentialManifests, extractManifest, extractManifests, isNodeWithIteration, isOAuthAuthorizeCredential, normalizeCredentialType, normalizeLocalized, retryConfigFields, safeFetch, timeoutConfigField };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,25 @@ type LocalizedString = string | Record<string, string>;
|
|
|
2
2
|
type DataType = 'any' | 'object' | 'array' | 'string' | 'number' | 'boolean';
|
|
3
3
|
type OutputKind = 'default' | 'branch' | 'error';
|
|
4
4
|
type NodeCategory = 'trigger' | 'action' | 'transform' | 'control' | 'io';
|
|
5
|
-
type ConfigType = 'string' | 'number' | 'boolean' | 'select' | 'multiselect' | 'object' | 'array' | 'expression' | 'secret-ref' | 'credentials-ref';
|
|
5
|
+
type ConfigType = 'string' | 'number' | 'boolean' | 'select' | 'multiselect' | 'object' | 'array' | 'expression' | 'secret-ref' | 'credentials-ref' | 'dynamic-schema';
|
|
6
|
+
/**
|
|
7
|
+
* Semantic category of an image, driving how the registry/CDN organises and
|
|
8
|
+
* displays it.
|
|
9
|
+
*/
|
|
10
|
+
type ImageCategory = 'screenshot' | 'logo' | 'banner' | 'icon' | 'other';
|
|
11
|
+
/**
|
|
12
|
+
* A single image a node, credential type, or template ships alongside its
|
|
13
|
+
* description (e.g. a screenshot, logo, or banner). The file is bundled into
|
|
14
|
+
* the package tarball and uploaded to the Revenexx CDN when the package is
|
|
15
|
+
* published.
|
|
16
|
+
*/
|
|
17
|
+
interface IImage {
|
|
18
|
+
/** Path to the image file, relative to the package root (e.g. `images/screenshot.png`). */
|
|
19
|
+
src: string;
|
|
20
|
+
alt: LocalizedString;
|
|
21
|
+
title?: LocalizedString;
|
|
22
|
+
category: ImageCategory;
|
|
23
|
+
}
|
|
6
24
|
interface IInputPort {
|
|
7
25
|
dataType: DataType;
|
|
8
26
|
required?: boolean;
|
|
@@ -20,6 +38,14 @@ interface IOutputPort {
|
|
|
20
38
|
description?: LocalizedString;
|
|
21
39
|
fields?: Record<string, IOutputField>;
|
|
22
40
|
sourceFromConfig?: string;
|
|
41
|
+
/**
|
|
42
|
+
* Marks a generic port set resolved at author time by the node's
|
|
43
|
+
* `resolveOutputs` callback (PO-143), rather than a static `name` or a
|
|
44
|
+
* config-driven `sourceFromConfig`. Set at most one of `name`,
|
|
45
|
+
* `sourceFromConfig`, `resolveOutputs` — this is a server-validated
|
|
46
|
+
* constraint on publish, not enforced by this (intentionally flat) type.
|
|
47
|
+
*/
|
|
48
|
+
resolveOutputs?: boolean;
|
|
23
49
|
fallback?: {
|
|
24
50
|
name: string;
|
|
25
51
|
label?: LocalizedString;
|
|
@@ -49,6 +75,23 @@ interface IConfigFieldBase {
|
|
|
49
75
|
multiline?: boolean;
|
|
50
76
|
validation?: IConfigValidation;
|
|
51
77
|
options?: IConfigOption[];
|
|
78
|
+
/**
|
|
79
|
+
* When true, a *known* field's `options` are resolved at author time via the
|
|
80
|
+
* node's `loadOptions` (a live/dependent dropdown) instead of a static
|
|
81
|
+
* `options[]`. Applies to `select` / `multiselect`; left unset for ordinary
|
|
82
|
+
* static fields.
|
|
83
|
+
*
|
|
84
|
+
* Independent of `type: 'dynamic-schema'`: that field type triggers
|
|
85
|
+
* `resolveConfigSchema` on its own and does NOT require `dynamic: true`.
|
|
86
|
+
*/
|
|
87
|
+
dynamic?: boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Config keys whose values drive this field's dynamic resolution. The editor
|
|
90
|
+
* re-resolves when one of them changes. A key listed here is
|
|
91
|
+
* *dependency-driving* and MUST be a literal (it may not set
|
|
92
|
+
* `expressionAllowed`), so its value is known at author time.
|
|
93
|
+
*/
|
|
94
|
+
dependsOn?: string[];
|
|
52
95
|
/**
|
|
53
96
|
* Only meaningful when `type === 'credentials-ref'`: the namespaced slug(s) of
|
|
54
97
|
* the credential type(s) this field accepts (e.g. `revenexx:smtp`). The editor
|
|
@@ -70,6 +113,8 @@ interface INodeDescription {
|
|
|
70
113
|
name: LocalizedString;
|
|
71
114
|
description?: LocalizedString;
|
|
72
115
|
icon?: string;
|
|
116
|
+
/** Associated images (screenshots, logos, banners) shipped with the package. */
|
|
117
|
+
images?: IImage[];
|
|
73
118
|
inputs: Record<string, IInputPort>;
|
|
74
119
|
outputs: IOutputPort[];
|
|
75
120
|
config?: IConfigField[];
|
|
@@ -99,18 +144,73 @@ interface INodeResult {
|
|
|
99
144
|
outputs: Record<string, unknown>;
|
|
100
145
|
branch?: string;
|
|
101
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Context handed to a node's *author-time* resolvers (`loadOptions`,
|
|
149
|
+
* `resolveConfigSchema`, `resolveOutputs`). These run in the node-runtime host
|
|
150
|
+
* (a Node side-container) while a user is editing the workflow — never in
|
|
151
|
+
* `execute`. The result is snapshotted into the workflow blob at save, so the
|
|
152
|
+
* runtime never calls these (PO-143).
|
|
153
|
+
*/
|
|
154
|
+
interface INodeAuthorContext {
|
|
155
|
+
signal: AbortSignal;
|
|
156
|
+
logger: {
|
|
157
|
+
info(message: string, meta?: Record<string, unknown>): void;
|
|
158
|
+
warn(message: string, meta?: Record<string, unknown>): void;
|
|
159
|
+
error(message: string, meta?: Record<string, unknown>): void;
|
|
160
|
+
};
|
|
161
|
+
/** The user's current partial config values. */
|
|
162
|
+
config: Record<string, unknown>;
|
|
163
|
+
/**
|
|
164
|
+
* Lazily resolve a `secret-ref` config field's value (a key in the tenant
|
|
165
|
+
* secret store → a single string). Mirrors {@link INodeContext.secrets} so a
|
|
166
|
+
* resolver that authenticates via a secret-ref uses the same call it would in
|
|
167
|
+
* `execute`. Resolves against the internal secret endpoint; only the keys the
|
|
168
|
+
* resolver actually asks for are fetched.
|
|
169
|
+
*/
|
|
170
|
+
secrets: {
|
|
171
|
+
get(key: string): Promise<string>;
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* Lazily resolve a `credentials-ref` instance's access data via the
|
|
175
|
+
* credentials broker (id → structured material, e.g. `{ accessToken }`).
|
|
176
|
+
* Mirrors {@link INodeContext.credentials}.
|
|
177
|
+
*/
|
|
178
|
+
credentials: {
|
|
179
|
+
get(credentialsId: string): Promise<Record<string, unknown>>;
|
|
180
|
+
};
|
|
181
|
+
/** Preferred locale for resolved labels, when the caller supplies one. */
|
|
182
|
+
locale?: string;
|
|
183
|
+
}
|
|
102
184
|
interface INode {
|
|
103
185
|
description: INodeDescription;
|
|
104
186
|
execute(ctx: INodeContext, inputs: Record<string, unknown>): Promise<INodeResult>;
|
|
187
|
+
/**
|
|
188
|
+
* Author-time: resolve the options of a `dynamic` field (a live/dependent
|
|
189
|
+
* dropdown). `fieldKey` is the config key being resolved. Optional — declare
|
|
190
|
+
* it only for nodes with `dynamic` `select`/`multiselect` fields.
|
|
191
|
+
*/
|
|
192
|
+
loadOptions?(ctx: INodeAuthorContext, fieldKey: string): Promise<IConfigOption[]>;
|
|
193
|
+
/**
|
|
194
|
+
* Author-time: resolve the flat set of typed config fields that replaces a
|
|
195
|
+
* `type: 'dynamic-schema'` marker (e.g. an API's parameters once app + API
|
|
196
|
+
* are chosen). Returns fields in the same config-field grammar; the node is
|
|
197
|
+
* responsible for flattening any nested API shape into flat keys.
|
|
198
|
+
*/
|
|
199
|
+
resolveConfigSchema?(ctx: INodeAuthorContext): Promise<IConfigField[]>;
|
|
200
|
+
/**
|
|
201
|
+
* Author-time: resolve a generic output-port set for an output marked
|
|
202
|
+
* `resolveOutputs` (e.g. ports derived from a connected resource's schema).
|
|
203
|
+
*/
|
|
204
|
+
resolveOutputs?(ctx: INodeAuthorContext): Promise<IOutputPort[]>;
|
|
105
205
|
}
|
|
106
206
|
/**
|
|
107
207
|
* Optional capability interface for nodes that iterate over a collection.
|
|
108
|
-
* Implement this alongside {@link INode} to signal to the
|
|
109
|
-
* node drives iteration — the
|
|
208
|
+
* Implement this alongside {@link INode} to signal to the runtime that this
|
|
209
|
+
* node drives iteration — the runtime will call {@link extractItems} instead
|
|
110
210
|
* of relying on slug-based detection.
|
|
111
211
|
*
|
|
112
212
|
* This interface is the designated dispatch point for future child-workflow
|
|
113
|
-
* execution: once per-iteration isolation is needed, the
|
|
213
|
+
* execution: once per-iteration isolation is needed, the runtime can swap the
|
|
114
214
|
* inline loop for `executeChild` calls without any changes to the node or SDK.
|
|
115
215
|
*/
|
|
116
216
|
interface INodeWithIteration {
|
|
@@ -159,6 +259,8 @@ interface ICredentialDescription {
|
|
|
159
259
|
name: LocalizedString;
|
|
160
260
|
description?: LocalizedString;
|
|
161
261
|
icon?: string;
|
|
262
|
+
/** Associated images (screenshots, logos, banners) shipped with the package. */
|
|
263
|
+
images?: IImage[];
|
|
162
264
|
authKind: CredentialAuthKind;
|
|
163
265
|
fields: ICredentialField[];
|
|
164
266
|
}
|
|
@@ -270,6 +372,8 @@ interface ITemplateDescription {
|
|
|
270
372
|
industries?: string[];
|
|
271
373
|
/** Free-form vendor tags (e.g. `pipedrive`, `slack`). */
|
|
272
374
|
vendors?: string[];
|
|
375
|
+
/** Associated images (screenshots, logos, banners) shipped with the package. */
|
|
376
|
+
images?: IImage[];
|
|
273
377
|
/** Workflow-blob schema version `definition` targets (e.g. `v0-draft`). */
|
|
274
378
|
blobVersion: string;
|
|
275
379
|
/** The workflow blob instantiated when a user picks this template. */
|
|
@@ -284,7 +388,7 @@ interface ITemplateDescription {
|
|
|
284
388
|
/**
|
|
285
389
|
* Reduce a {@link LocalizedString} to a single plain string.
|
|
286
390
|
*
|
|
287
|
-
* Every consumer (
|
|
391
|
+
* Every consumer (the UI, the Laravel side) repeats the same "is it a
|
|
288
392
|
* string or a localized map?" branch to render a name/label; this centralizes
|
|
289
393
|
* it so the rules are defined once:
|
|
290
394
|
*
|
|
@@ -302,8 +406,8 @@ declare function normalizeLocalized(value: LocalizedString | undefined | null, f
|
|
|
302
406
|
*
|
|
303
407
|
* The union `string | string[]` exists so node authors can write the common
|
|
304
408
|
* single-type case as a bare string, but every consumer (the editor that
|
|
305
|
-
* lists tenant credential instances, the
|
|
306
|
-
*
|
|
409
|
+
* lists tenant credential instances, the Laravel side) needs a list to
|
|
410
|
+
* iterate. This centralizes the
|
|
307
411
|
* "is it a string or an array?" branch — analogous to {@link normalizeLocalized}
|
|
308
412
|
* for `LocalizedString` — so the rules are defined once:
|
|
309
413
|
*
|
|
@@ -489,4 +593,4 @@ declare abstract class OAuth2AuthCodeCredential extends BaseCredential implement
|
|
|
489
593
|
test(_ctx: ICredentialContext, config: Config): Promise<ICredentialTestResult>;
|
|
490
594
|
}
|
|
491
595
|
|
|
492
|
-
export { ApiKeyCredential, BaseCredential, BasicAuthCredential, type ConfigType, type CredentialAuthKind, type CredentialFieldType, DEFAULT_RETRY_ATTEMPTS, DEFAULT_RETRY_DELAY_MS, DEFAULT_TIMEOUT_MS, type DataType, type IConfigField, type IConfigFieldBase, type IConfigOption, type IConfigValidation, type ICredential, type ICredentialContext, type ICredentialDescription, type ICredentialField, type ICredentialOAuthAuthorize, type ICredentialResolveResult, type ICredentialTestResult, type IInputPort, type INode, type INodeContext, type INodeDescription, type INodeResult, type INodeWithIteration, type IOutputField, type IOutputPort, type ITemplateDescription, type ITemplateTrigger, type LocalizedString, MANIFEST_VERSION, MAX_RETRY_ATTEMPTS, MAX_TIMEOUT_MS, type NodeCategory, NodeError, type NodeManifest, OAuth2AuthCodeCredential, OAuth2ClientCredentialsCredential, type OAuthTokenResponse, type OutputKind, type SafeFetchOptions, type SafeFetchRetry, SimpleValueCredential, type TemplateLevel, type TemplateTriggerType, buildManifest, extractCredentialManifest, extractCredentialManifests, extractManifest, extractManifests, isNodeWithIteration, isOAuthAuthorizeCredential, normalizeCredentialType, normalizeLocalized, retryConfigFields, safeFetch, timeoutConfigField };
|
|
596
|
+
export { ApiKeyCredential, BaseCredential, BasicAuthCredential, type ConfigType, type CredentialAuthKind, type CredentialFieldType, DEFAULT_RETRY_ATTEMPTS, DEFAULT_RETRY_DELAY_MS, DEFAULT_TIMEOUT_MS, type DataType, type IConfigField, type IConfigFieldBase, type IConfigOption, type IConfigValidation, type ICredential, type ICredentialContext, type ICredentialDescription, type ICredentialField, type ICredentialOAuthAuthorize, type ICredentialResolveResult, type ICredentialTestResult, type IImage, type IInputPort, type INode, type INodeAuthorContext, type INodeContext, type INodeDescription, type INodeResult, type INodeWithIteration, type IOutputField, type IOutputPort, type ITemplateDescription, type ITemplateTrigger, type ImageCategory, type LocalizedString, MANIFEST_VERSION, MAX_RETRY_ATTEMPTS, MAX_TIMEOUT_MS, type NodeCategory, NodeError, type NodeManifest, OAuth2AuthCodeCredential, OAuth2ClientCredentialsCredential, type OAuthTokenResponse, type OutputKind, type SafeFetchOptions, type SafeFetchRetry, SimpleValueCredential, type TemplateLevel, type TemplateTriggerType, buildManifest, extractCredentialManifest, extractCredentialManifests, extractManifest, extractManifests, isNodeWithIteration, isOAuthAuthorizeCredential, normalizeCredentialType, normalizeLocalized, retryConfigFields, safeFetch, timeoutConfigField };
|