@superglue/cli 1.1.18 → 1.1.20
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/.claude-plugin/plugin.json +1 -1
- package/dist/cli.js +832 -23922
- package/dist/skills/superglue/SKILL.md +240 -27
- package/dist/skills/superglue/references/access-rules.md +137 -0
- package/dist/skills/superglue/references/data-handling.md +303 -0
- package/dist/skills/superglue/references/databases.md +7 -3
- package/dist/skills/superglue/references/file-handling.md +160 -0
- package/dist/skills/superglue/references/file-servers.md +13 -37
- package/dist/skills/superglue/references/http-apis.md +248 -0
- package/dist/skills/superglue/references/redis.md +4 -5
- package/package.json +2 -1
- package/skills/superglue/SKILL.md +240 -27
- package/skills/superglue/references/access-rules.md +137 -0
- package/skills/superglue/references/data-handling.md +303 -0
- package/skills/superglue/references/databases.md +7 -3
- package/skills/superglue/references/file-handling.md +160 -0
- package/skills/superglue/references/file-servers.md +13 -37
- package/skills/superglue/references/http-apis.md +248 -0
- package/skills/superglue/references/redis.md +4 -5
- package/dist/dist/cli.js +0 -24370
- package/dist/dist/skills/superglue/SKILL.md +0 -678
- package/dist/dist/skills/superglue/agents/openai.yaml +0 -7
- package/dist/dist/skills/superglue/assets/superglue.png +0 -0
- package/dist/dist/skills/superglue/references/databases.md +0 -249
- package/dist/dist/skills/superglue/references/file-servers.md +0 -136
- package/dist/dist/skills/superglue/references/integration.md +0 -279
- package/dist/dist/skills/superglue/references/redis.md +0 -190
- package/dist/dist/skills/superglue/references/transforms-and-output.md +0 -92
- package/dist/skills/superglue/references/transforms-and-output.md +0 -92
- package/skills/superglue/references/transforms-and-output.md +0 -92
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
# Redis Steps
|
|
2
|
-
|
|
3
|
-
## Step Configuration
|
|
4
|
-
|
|
5
|
-
```typescript
|
|
6
|
-
{
|
|
7
|
-
type: "request",
|
|
8
|
-
systemId: "my_redis",
|
|
9
|
-
url: "redis://<<my_redis_username>>:<<my_redis_password>>@<<my_redis_host>>:<<my_redis_port>>/<<my_redis_database>>",
|
|
10
|
-
method: "POST", // ignored for Redis but required by schema
|
|
11
|
-
body: '{"command": "GET", "args": ["<<keyName>>"]}'
|
|
12
|
-
}
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Configure the connection URL depending on which credentials are saved in the stored Redis system - reference them accordingly.
|
|
16
|
-
|
|
17
|
-
## URL Format
|
|
18
|
-
|
|
19
|
-
```
|
|
20
|
-
redis://user:password@host:port/database
|
|
21
|
-
rediss://user:password@host:port/database (TLS)
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
- `redis://` for standard connections
|
|
25
|
-
- `rediss://` for TLS-encrypted connections (e.g. Redis Cloud, AWS ElastiCache with encryption)
|
|
26
|
-
- `/database` is the database number (0-15), defaults to 0 if omitted
|
|
27
|
-
|
|
28
|
-
All credential variables are resolved before connecting. Trailing slashes are cleaned.
|
|
29
|
-
|
|
30
|
-
## Body Format
|
|
31
|
-
|
|
32
|
-
JSON string with `command` (required) and optional `args` array. Body can be a single command object or an array of commands (pipelined in a single round-trip):
|
|
33
|
-
|
|
34
|
-
```json
|
|
35
|
-
{ "command": "GET", "args": ["mykey"] }
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Multiple commands:
|
|
39
|
-
|
|
40
|
-
```json
|
|
41
|
-
[
|
|
42
|
-
{ "command": "GET", "args": ["user:1:name"] },
|
|
43
|
-
{ "command": "HGETALL", "args": ["user:1"] }
|
|
44
|
-
]
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### Common Commands
|
|
48
|
-
|
|
49
|
-
**String operations:**
|
|
50
|
-
|
|
51
|
-
```json
|
|
52
|
-
{ "command": "GET", "args": ["user:123:name"] }
|
|
53
|
-
{ "command": "SET", "args": ["user:123:name", "Alice"] }
|
|
54
|
-
{ "command": "MGET", "args": ["key1", "key2", "key3"] }
|
|
55
|
-
{ "command": "INCR", "args": ["counter"] }
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
**Hash operations:**
|
|
59
|
-
|
|
60
|
-
```json
|
|
61
|
-
{ "command": "HGETALL", "args": ["user:123"] }
|
|
62
|
-
{ "command": "HGET", "args": ["user:123", "email"] }
|
|
63
|
-
{ "command": "HSET", "args": ["user:123", "email", "alice@example.com"] }
|
|
64
|
-
{ "command": "HMGET", "args": ["user:123", "name", "email"] }
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**List operations:**
|
|
68
|
-
|
|
69
|
-
```json
|
|
70
|
-
{ "command": "LRANGE", "args": ["queue:tasks", "0", "-1"] }
|
|
71
|
-
{ "command": "LPUSH", "args": ["queue:tasks", "task1"] }
|
|
72
|
-
{ "command": "RPOP", "args": ["queue:tasks"] }
|
|
73
|
-
{ "command": "LLEN", "args": ["queue:tasks"] }
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
**Set operations:**
|
|
77
|
-
|
|
78
|
-
```json
|
|
79
|
-
{ "command": "SMEMBERS", "args": ["tags:post:1"] }
|
|
80
|
-
{ "command": "SADD", "args": ["tags:post:1", "redis", "database"] }
|
|
81
|
-
{ "command": "SISMEMBER", "args": ["tags:post:1", "redis"] }
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
**Sorted set operations:**
|
|
85
|
-
|
|
86
|
-
```json
|
|
87
|
-
{ "command": "ZRANGE", "args": ["leaderboard", "0", "-1", "WITHSCORES"] }
|
|
88
|
-
{ "command": "ZADD", "args": ["leaderboard", "100", "player1"] }
|
|
89
|
-
{ "command": "ZRANK", "args": ["leaderboard", "player1"] }
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
**Key operations:**
|
|
93
|
-
|
|
94
|
-
```json
|
|
95
|
-
{ "command": "KEYS", "args": ["user:*"] }
|
|
96
|
-
{ "command": "EXISTS", "args": ["mykey"] }
|
|
97
|
-
{ "command": "TTL", "args": ["session:abc"] }
|
|
98
|
-
{ "command": "EXPIRE", "args": ["session:abc", "3600"] }
|
|
99
|
-
{ "command": "DEL", "args": ["mykey"] }
|
|
100
|
-
{ "command": "TYPE", "args": ["mykey"] }
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
**Scan (safe iteration):**
|
|
104
|
-
|
|
105
|
-
```json
|
|
106
|
-
{ "command": "SCAN", "args": ["0", "MATCH", "user:*", "COUNT", "100"] }
|
|
107
|
-
{ "command": "HSCAN", "args": ["myhash", "0", "MATCH", "field*"] }
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### Dynamic Arguments with Variables
|
|
111
|
-
|
|
112
|
-
```json
|
|
113
|
-
{ "command": "GET", "args": ["<<(sourceData) => `user:${sourceData.userId}:profile`>>"] }
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
```json
|
|
117
|
-
{ "command": "HSET", "args": ["<<userKey>>", "<<fieldName>>", "<<fieldValue>>"] }
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
## Connection Management
|
|
121
|
-
|
|
122
|
-
- A fresh connection is created per execution and closed after completion
|
|
123
|
-
- TLS auto-configured for `rediss://` URLs (with `rejectUnauthorized: false`)
|
|
124
|
-
- 5-second connection timeout, 30-second command timeout
|
|
125
|
-
- Array commands (pipeline) run on a single connection for efficiency
|
|
126
|
-
|
|
127
|
-
## Retry Logic
|
|
128
|
-
|
|
129
|
-
Default retries from server config. On final failure, error includes command and args.
|
|
130
|
-
|
|
131
|
-
## Return Value
|
|
132
|
-
|
|
133
|
-
Returns the raw Redis response:
|
|
134
|
-
|
|
135
|
-
- `GET` / `HGET`: string or null
|
|
136
|
-
- `HGETALL`: object with field-value pairs (flattened array from Redis, parsed by ioredis)
|
|
137
|
-
- `LRANGE` / `SMEMBERS` / `KEYS`: array of strings
|
|
138
|
-
- `SET` / `DEL` / `EXPIRE`: "OK" or integer
|
|
139
|
-
- `INCR` / `LLEN` / `SADD`: integer
|
|
140
|
-
- `MGET` / `HMGET`: array (nulls for missing keys)
|
|
141
|
-
- `SCAN` / `HSCAN`: array of [cursor, results]
|
|
142
|
-
|
|
143
|
-
## Multiple Commands (Pipeline)
|
|
144
|
-
|
|
145
|
-
Pass an array of commands to execute them in a single round-trip (like FTP/SFTP batch operations):
|
|
146
|
-
|
|
147
|
-
```json
|
|
148
|
-
[
|
|
149
|
-
{ "command": "GET", "args": ["user:1:name"] },
|
|
150
|
-
{ "command": "HGETALL", "args": ["user:1"] },
|
|
151
|
-
{ "command": "LRANGE", "args": ["tasks", "0", "-1"] }
|
|
152
|
-
]
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
Returns an array of results, one per command:
|
|
156
|
-
|
|
157
|
-
```json
|
|
158
|
-
[
|
|
159
|
-
{ "command": "GET", "result": "Alice" },
|
|
160
|
-
{ "command": "HGETALL", "result": ["name", "Alice", "email", "alice@example.com"] },
|
|
161
|
-
{ "command": "LRANGE", "result": ["task3", "task2", "task1"] }
|
|
162
|
-
]
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
If an individual command fails, that entry has `error` instead of `result`:
|
|
166
|
-
|
|
167
|
-
```json
|
|
168
|
-
[
|
|
169
|
-
{ "command": "GET", "result": "Alice" },
|
|
170
|
-
{ "command": "WRONGCMD", "error": "ERR unknown command 'WRONGCMD'" }
|
|
171
|
-
]
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
A single command returns a single result. Multiple commands return an array — same pattern as FTP/SFTP operations.
|
|
175
|
-
|
|
176
|
-
## Batch Operations via Loop
|
|
177
|
-
|
|
178
|
-
Use a data selector returning an array to execute a command per item:
|
|
179
|
-
|
|
180
|
-
```javascript
|
|
181
|
-
// dataSelector: (sourceData) => sourceData.userIds
|
|
182
|
-
// body: {"command": "HGETALL", "args": ["<<(sourceData) => `user:${sourceData.currentItem}`>>"]}
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
## Important Notes
|
|
186
|
-
|
|
187
|
-
- All args must be strings (Redis protocol is text-based) - numbers are auto-coerced
|
|
188
|
-
- Use `SCAN` instead of `KEYS` in production for large keyspaces
|
|
189
|
-
- `HGETALL` returns an empty object `{}` for non-existent keys
|
|
190
|
-
- Use array body for multi-command pipelines instead of separate steps
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
# Transforms & Output Shaping
|
|
2
|
-
|
|
3
|
-
Covers transform steps, output transforms, and response filters.
|
|
4
|
-
|
|
5
|
-
## Three Transformation Points
|
|
6
|
-
|
|
7
|
-
| Point | When it runs | Purpose |
|
|
8
|
-
| -------------------------------- | ------------------------ | ------------------------------------ |
|
|
9
|
-
| `dataSelector` | Before step executes | Controls input + single vs loop mode |
|
|
10
|
-
| Transform step (`transformCode`) | As the step itself | Reshape data between request steps |
|
|
11
|
-
| `outputTransform` | After all steps complete | Shape final tool output |
|
|
12
|
-
|
|
13
|
-
## Transform Steps
|
|
14
|
-
|
|
15
|
-
Use when you need intermediate data reshaping that can't wait until outputTransform (because a subsequent request step needs the data).
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
{
|
|
19
|
-
id: "formatForInsert",
|
|
20
|
-
config: {
|
|
21
|
-
type: "transform",
|
|
22
|
-
transformCode: "(sourceData) => sourceData.getCustomers.data.map(c => ({ id: c.id, name: c.fullName }))"
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Transform steps do NOT have: systemId, url, method, headers, body, queryParams, or pagination.
|
|
28
|
-
|
|
29
|
-
Results are wrapped in the **same envelope** as request steps:
|
|
30
|
-
|
|
31
|
-
```javascript
|
|
32
|
-
sourceData.formatForInsert = { currentItem: <dataSelector output>, data: <transformCode result>, success: true }
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
If the step has a dataSelector returning an array, the transform runs once per item.
|
|
36
|
-
|
|
37
|
-
### When to Use
|
|
38
|
-
|
|
39
|
-
- Data needed by a subsequent request step (can't defer to outputTransform)
|
|
40
|
-
- Aggregating/combining results from multiple previous steps
|
|
41
|
-
- Complex filtering or restructuring between API calls
|
|
42
|
-
- Preparing data in a specific format for the next step
|
|
43
|
-
|
|
44
|
-
### When NOT to Use
|
|
45
|
-
|
|
46
|
-
- Simple input selection → use `dataSelector` instead
|
|
47
|
-
- Final output shaping → use `outputTransform` instead
|
|
48
|
-
- Simple filtering within a single step → use `dataSelector` returning a filtered array
|
|
49
|
-
- As the final step before the outputTransform → merge into outputTransform code
|
|
50
|
-
|
|
51
|
-
## Output Transform
|
|
52
|
-
|
|
53
|
-
Final transformation shaping the tool's output. Runs after all steps complete.
|
|
54
|
-
|
|
55
|
-
Access patterns depend on how the step was executed:
|
|
56
|
-
|
|
57
|
-
- **Object-selector step**: `sourceData.stepId.data` — single envelope
|
|
58
|
-
- **Array-selector (loop) step**: `sourceData.stepId.map(i => i.data)` — array of envelopes
|
|
59
|
-
|
|
60
|
-
```javascript
|
|
61
|
-
// Object-selector step — single result
|
|
62
|
-
sourceData.getUsers.data; // the API response
|
|
63
|
-
sourceData.getUsers.data.results; // nested field
|
|
64
|
-
|
|
65
|
-
// Array-selector (loop) step — array of results
|
|
66
|
-
sourceData.fetchDetails.map((i) => i.data); // all responses
|
|
67
|
-
sourceData.fetchDetails.flatMap((i) => i.data.items); // nested arrays
|
|
68
|
-
sourceData.fetchDetails.filter((i) => i.success).map((i) => i.data); // only successes
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Payload fields are at root level — **NEVER** use `sourceData.payload.*`.
|
|
72
|
-
|
|
73
|
-
### Requirements
|
|
74
|
-
|
|
75
|
-
- Function signature: `(sourceData) => { ... }`
|
|
76
|
-
- **Must have a return statement**
|
|
77
|
-
- Pure synchronous — no async/await, no side effects
|
|
78
|
-
- Handle missing data with `?.` and defaults
|
|
79
|
-
- Validate arrays with `Array.isArray()` before array methods
|
|
80
|
-
- Throw when expected required data is missing (enables self-healing)
|
|
81
|
-
- NEVER include newlines or tabs in the code string
|
|
82
|
-
|
|
83
|
-
## JS Code Constraints (all transform points)
|
|
84
|
-
|
|
85
|
-
Runs in Deno subprocess sandbox:
|
|
86
|
-
|
|
87
|
-
- 8192 MB memory limit, 10 minute timeout per transform
|
|
88
|
-
- Synchronous only — no async/await, no Promises, no setTimeout
|
|
89
|
-
- No side effects — no network, filesystem, or console access
|
|
90
|
-
- No external dependencies — only standard JS built-ins (Array, Object, String, Math, Date, JSON, etc.)
|
|
91
|
-
- JSON-serializable I/O only
|
|
92
|
-
- Must return a value (undefined returns null)
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
# Transforms & Output Shaping
|
|
2
|
-
|
|
3
|
-
Covers transform steps, output transforms, and response filters.
|
|
4
|
-
|
|
5
|
-
## Three Transformation Points
|
|
6
|
-
|
|
7
|
-
| Point | When it runs | Purpose |
|
|
8
|
-
| -------------------------------- | ------------------------ | ------------------------------------ |
|
|
9
|
-
| `dataSelector` | Before step executes | Controls input + single vs loop mode |
|
|
10
|
-
| Transform step (`transformCode`) | As the step itself | Reshape data between request steps |
|
|
11
|
-
| `outputTransform` | After all steps complete | Shape final tool output |
|
|
12
|
-
|
|
13
|
-
## Transform Steps
|
|
14
|
-
|
|
15
|
-
Use when you need intermediate data reshaping that can't wait until outputTransform (because a subsequent request step needs the data).
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
{
|
|
19
|
-
id: "formatForInsert",
|
|
20
|
-
config: {
|
|
21
|
-
type: "transform",
|
|
22
|
-
transformCode: "(sourceData) => sourceData.getCustomers.data.map(c => ({ id: c.id, name: c.fullName }))"
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Transform steps do NOT have: systemId, url, method, headers, body, queryParams, or pagination.
|
|
28
|
-
|
|
29
|
-
Results are wrapped in the **same envelope** as request steps:
|
|
30
|
-
|
|
31
|
-
```javascript
|
|
32
|
-
sourceData.formatForInsert = { currentItem: <dataSelector output>, data: <transformCode result>, success: true }
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
If the step has a dataSelector returning an array, the transform runs once per item.
|
|
36
|
-
|
|
37
|
-
### When to Use
|
|
38
|
-
|
|
39
|
-
- Data needed by a subsequent request step (can't defer to outputTransform)
|
|
40
|
-
- Aggregating/combining results from multiple previous steps
|
|
41
|
-
- Complex filtering or restructuring between API calls
|
|
42
|
-
- Preparing data in a specific format for the next step
|
|
43
|
-
|
|
44
|
-
### When NOT to Use
|
|
45
|
-
|
|
46
|
-
- Simple input selection → use `dataSelector` instead
|
|
47
|
-
- Final output shaping → use `outputTransform` instead
|
|
48
|
-
- Simple filtering within a single step → use `dataSelector` returning a filtered array
|
|
49
|
-
- As the final step before the outputTransform → merge into outputTransform code
|
|
50
|
-
|
|
51
|
-
## Output Transform
|
|
52
|
-
|
|
53
|
-
Final transformation shaping the tool's output. Runs after all steps complete.
|
|
54
|
-
|
|
55
|
-
Access patterns depend on how the step was executed:
|
|
56
|
-
|
|
57
|
-
- **Object-selector step**: `sourceData.stepId.data` — single envelope
|
|
58
|
-
- **Array-selector (loop) step**: `sourceData.stepId.map(i => i.data)` — array of envelopes
|
|
59
|
-
|
|
60
|
-
```javascript
|
|
61
|
-
// Object-selector step — single result
|
|
62
|
-
sourceData.getUsers.data; // the API response
|
|
63
|
-
sourceData.getUsers.data.results; // nested field
|
|
64
|
-
|
|
65
|
-
// Array-selector (loop) step — array of results
|
|
66
|
-
sourceData.fetchDetails.map((i) => i.data); // all responses
|
|
67
|
-
sourceData.fetchDetails.flatMap((i) => i.data.items); // nested arrays
|
|
68
|
-
sourceData.fetchDetails.filter((i) => i.success).map((i) => i.data); // only successes
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Payload fields are at root level — **NEVER** use `sourceData.payload.*`.
|
|
72
|
-
|
|
73
|
-
### Requirements
|
|
74
|
-
|
|
75
|
-
- Function signature: `(sourceData) => { ... }`
|
|
76
|
-
- **Must have a return statement**
|
|
77
|
-
- Pure synchronous — no async/await, no side effects
|
|
78
|
-
- Handle missing data with `?.` and defaults
|
|
79
|
-
- Validate arrays with `Array.isArray()` before array methods
|
|
80
|
-
- Throw when expected required data is missing (enables self-healing)
|
|
81
|
-
- NEVER include newlines or tabs in the code string
|
|
82
|
-
|
|
83
|
-
## JS Code Constraints (all transform points)
|
|
84
|
-
|
|
85
|
-
Runs in Deno subprocess sandbox:
|
|
86
|
-
|
|
87
|
-
- 8192 MB memory limit, 10 minute timeout per transform
|
|
88
|
-
- Synchronous only — no async/await, no Promises, no setTimeout
|
|
89
|
-
- No side effects — no network, filesystem, or console access
|
|
90
|
-
- No external dependencies — only standard JS built-ins (Array, Object, String, Math, Date, JSON, etc.)
|
|
91
|
-
- JSON-serializable I/O only
|
|
92
|
-
- Must return a value (undefined returns null)
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
# Transforms & Output Shaping
|
|
2
|
-
|
|
3
|
-
Covers transform steps, output transforms, and response filters.
|
|
4
|
-
|
|
5
|
-
## Three Transformation Points
|
|
6
|
-
|
|
7
|
-
| Point | When it runs | Purpose |
|
|
8
|
-
| -------------------------------- | ------------------------ | ------------------------------------ |
|
|
9
|
-
| `dataSelector` | Before step executes | Controls input + single vs loop mode |
|
|
10
|
-
| Transform step (`transformCode`) | As the step itself | Reshape data between request steps |
|
|
11
|
-
| `outputTransform` | After all steps complete | Shape final tool output |
|
|
12
|
-
|
|
13
|
-
## Transform Steps
|
|
14
|
-
|
|
15
|
-
Use when you need intermediate data reshaping that can't wait until outputTransform (because a subsequent request step needs the data).
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
{
|
|
19
|
-
id: "formatForInsert",
|
|
20
|
-
config: {
|
|
21
|
-
type: "transform",
|
|
22
|
-
transformCode: "(sourceData) => sourceData.getCustomers.data.map(c => ({ id: c.id, name: c.fullName }))"
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Transform steps do NOT have: systemId, url, method, headers, body, queryParams, or pagination.
|
|
28
|
-
|
|
29
|
-
Results are wrapped in the **same envelope** as request steps:
|
|
30
|
-
|
|
31
|
-
```javascript
|
|
32
|
-
sourceData.formatForInsert = { currentItem: <dataSelector output>, data: <transformCode result>, success: true }
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
If the step has a dataSelector returning an array, the transform runs once per item.
|
|
36
|
-
|
|
37
|
-
### When to Use
|
|
38
|
-
|
|
39
|
-
- Data needed by a subsequent request step (can't defer to outputTransform)
|
|
40
|
-
- Aggregating/combining results from multiple previous steps
|
|
41
|
-
- Complex filtering or restructuring between API calls
|
|
42
|
-
- Preparing data in a specific format for the next step
|
|
43
|
-
|
|
44
|
-
### When NOT to Use
|
|
45
|
-
|
|
46
|
-
- Simple input selection → use `dataSelector` instead
|
|
47
|
-
- Final output shaping → use `outputTransform` instead
|
|
48
|
-
- Simple filtering within a single step → use `dataSelector` returning a filtered array
|
|
49
|
-
- As the final step before the outputTransform → merge into outputTransform code
|
|
50
|
-
|
|
51
|
-
## Output Transform
|
|
52
|
-
|
|
53
|
-
Final transformation shaping the tool's output. Runs after all steps complete.
|
|
54
|
-
|
|
55
|
-
Access patterns depend on how the step was executed:
|
|
56
|
-
|
|
57
|
-
- **Object-selector step**: `sourceData.stepId.data` — single envelope
|
|
58
|
-
- **Array-selector (loop) step**: `sourceData.stepId.map(i => i.data)` — array of envelopes
|
|
59
|
-
|
|
60
|
-
```javascript
|
|
61
|
-
// Object-selector step — single result
|
|
62
|
-
sourceData.getUsers.data; // the API response
|
|
63
|
-
sourceData.getUsers.data.results; // nested field
|
|
64
|
-
|
|
65
|
-
// Array-selector (loop) step — array of results
|
|
66
|
-
sourceData.fetchDetails.map((i) => i.data); // all responses
|
|
67
|
-
sourceData.fetchDetails.flatMap((i) => i.data.items); // nested arrays
|
|
68
|
-
sourceData.fetchDetails.filter((i) => i.success).map((i) => i.data); // only successes
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Payload fields are at root level — **NEVER** use `sourceData.payload.*`.
|
|
72
|
-
|
|
73
|
-
### Requirements
|
|
74
|
-
|
|
75
|
-
- Function signature: `(sourceData) => { ... }`
|
|
76
|
-
- **Must have a return statement**
|
|
77
|
-
- Pure synchronous — no async/await, no side effects
|
|
78
|
-
- Handle missing data with `?.` and defaults
|
|
79
|
-
- Validate arrays with `Array.isArray()` before array methods
|
|
80
|
-
- Throw when expected required data is missing (enables self-healing)
|
|
81
|
-
- NEVER include newlines or tabs in the code string
|
|
82
|
-
|
|
83
|
-
## JS Code Constraints (all transform points)
|
|
84
|
-
|
|
85
|
-
Runs in Deno subprocess sandbox:
|
|
86
|
-
|
|
87
|
-
- 8192 MB memory limit, 10 minute timeout per transform
|
|
88
|
-
- Synchronous only — no async/await, no Promises, no setTimeout
|
|
89
|
-
- No side effects — no network, filesystem, or console access
|
|
90
|
-
- No external dependencies — only standard JS built-ins (Array, Object, String, Math, Date, JSON, etc.)
|
|
91
|
-
- JSON-serializable I/O only
|
|
92
|
-
- Must return a value (undefined returns null)
|