@superglue/cli 1.1.21 → 1.1.22
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/README.md +1 -7
- package/dist/cli.js +300 -77
- package/dist/skills/superglue/SKILL.md +312 -631
- package/dist/skills/superglue/references/file-handling.md +116 -90
- package/dist/skills/superglue/references/graphql.md +131 -0
- package/dist/skills/superglue/references/http.md +246 -0
- package/dist/skills/superglue/references/integration.md +4 -2
- package/dist/skills/superglue/references/mssql.md +207 -0
- package/dist/skills/superglue/references/postgres.md +154 -0
- package/dist/skills/superglue/references/redis.md +68 -118
- package/dist/skills/superglue/references/sftp-smb.md +156 -0
- package/dist/skills/superglue/references/superglue-info.md +91 -0
- package/package.json +1 -1
- package/skills/superglue/SKILL.md +312 -631
- package/skills/superglue/references/file-handling.md +116 -90
- package/skills/superglue/references/graphql.md +131 -0
- package/skills/superglue/references/http.md +246 -0
- package/skills/superglue/references/integration.md +4 -2
- package/skills/superglue/references/mssql.md +207 -0
- package/skills/superglue/references/postgres.md +154 -0
- package/skills/superglue/references/redis.md +68 -118
- package/skills/superglue/references/sftp-smb.md +156 -0
- package/skills/superglue/references/superglue-info.md +91 -0
- package/dist/skills/superglue/references/data-handling.md +0 -303
- package/dist/skills/superglue/references/databases.md +0 -253
- package/dist/skills/superglue/references/file-servers.md +0 -112
- package/dist/skills/superglue/references/http-apis.md +0 -248
- package/skills/superglue/references/data-handling.md +0 -303
- package/skills/superglue/references/databases.md +0 -253
- package/skills/superglue/references/file-servers.md +0 -112
- package/skills/superglue/references/http-apis.md +0 -248
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
# Data Handling: Variables, Selectors & Transforms
|
|
2
|
-
|
|
3
|
-
Most tool building and editing failures trace back to incorrect variable syntax, wrong data selector returns, or misunderstanding of the tool result envelope.
|
|
4
|
-
|
|
5
|
-
## Variable Replacement (`<<>>` Syntax)
|
|
6
|
-
|
|
7
|
-
The `<<expression>>` syntax injects dynamic values into step config fields (URL, headers, body, queryParams).
|
|
8
|
-
|
|
9
|
-
### Simple Variables (top-level keys only)
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
<<userId>> payload keys
|
|
13
|
-
<<currentItem>> whole current loop item
|
|
14
|
-
<<page>> pagination variable
|
|
15
|
-
<<systemId_api_key>> system credential
|
|
16
|
-
<<systemId_url>> system base URL
|
|
17
|
-
<<sg_auth_email>> email of the authenticated user
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
**CRITICAL**: Simple `<<varName>>` only works for top-level keys. NO dots, NO nesting.
|
|
21
|
-
|
|
22
|
-
- VALID: `<<userId>>`, `<<currentItem>>`, `<<page>>`, `<<stripe_api_key>>`, `<<stripe_url>>`, `<<sg_auth_email>>`
|
|
23
|
-
- INVALID: `<<currentItem.id>>`, `<<sourceData.userId>>`, `<<user.name>>` — these FAIL at runtime
|
|
24
|
-
|
|
25
|
-
### Arrow Function Expressions (for everything else)
|
|
26
|
-
|
|
27
|
-
```
|
|
28
|
-
<<(sourceData) => sourceData.currentItem.player_id>>
|
|
29
|
-
<<(sourceData) => sourceData.getUsers.data.map(u => u.id)>>
|
|
30
|
-
<<(sourceData) => JSON.stringify({ ids: sourceData.fetchUsers.data.map(u => u.id) })>>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Resolution Order
|
|
34
|
-
|
|
35
|
-
1. Direct lookup: check if expression is a top-level key in the merged variable object
|
|
36
|
-
2. Arrow function: execute in Deno subprocess sandbox with full data as `sourceData`
|
|
37
|
-
3. Failure: throws error listing available keys
|
|
38
|
-
|
|
39
|
-
### Variable Sources
|
|
40
|
-
|
|
41
|
-
All variables come from a single merged object:
|
|
42
|
-
|
|
43
|
-
```javascript
|
|
44
|
-
{
|
|
45
|
-
...originalPayload, // user-provided input
|
|
46
|
-
...previousStepResults, // keyed by stepId
|
|
47
|
-
...systemCredentials, // namespaced: systemId_credKey
|
|
48
|
-
...systemUrls, // namespaced: systemId_url
|
|
49
|
-
sg_auth_email, // email of authenticated user (context variable)
|
|
50
|
-
currentItem, // current loop item (if in a loop)
|
|
51
|
-
page, offset, cursor, // pagination variables
|
|
52
|
-
limit, pageSize // pagination size
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Context Variables
|
|
57
|
-
|
|
58
|
-
Context variables provide information about the execution environment:
|
|
59
|
-
|
|
60
|
-
- `<<sg_auth_email>>` — Email address of the authenticated user who triggered the tool execution
|
|
61
|
-
|
|
62
|
-
**Use case**: Personalize tool outputs based on who is running the tool. For example:
|
|
63
|
-
|
|
64
|
-
- Different permissions in Tableau based on user
|
|
65
|
-
- User-specific account lookups
|
|
66
|
-
- Audit logging with user identity
|
|
67
|
-
|
|
68
|
-
**Important**: `sg_auth_email` is NOT available in scheduled executions (cron jobs). If a tool references `<<sg_auth_email>>` and runs via scheduler, it will fail with a clear error message.
|
|
69
|
-
|
|
70
|
-
### Return Type Handling
|
|
71
|
-
|
|
72
|
-
- Objects/arrays returned from expressions → JSON.stringified automatically
|
|
73
|
-
- Resolved values of `"undefined"` or `"null"` → stripped from headers and queryParams
|
|
74
|
-
|
|
75
|
-
### Special: Basic Auth
|
|
76
|
-
|
|
77
|
-
`"Authorization": "Basic <<user>>:<<pass>>"` is auto-converted to Base64. Do NOT manually encode.
|
|
78
|
-
|
|
79
|
-
## Credential Resolution
|
|
80
|
-
|
|
81
|
-
Credentials are available via `<<>>` syntax. Two sources, payload takes precedence:
|
|
82
|
-
|
|
83
|
-
1. **System credentials**: Stored on System, namespaced as `<<systemId_credKey>>`
|
|
84
|
-
|
|
85
|
-
```javascript
|
|
86
|
-
// System id="stripe", credentials={ api_key: "sk_..." }
|
|
87
|
-
// Available as: <<stripe_api_key>>
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
2. **Payload credentials**: Passed at runtime, accessed directly
|
|
91
|
-
```javascript
|
|
92
|
-
// Payload: { user_access_token: "abc" }
|
|
93
|
-
// Available as: <<user_access_token>>
|
|
94
|
-
// Or: <<(sourceData) => sourceData.user_access_token>>
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
For OAuth systems, use `<<systemId_access_token>>` — the token value is auto-refreshed during tool execution, but the header itself must be present in the step config.
|
|
98
|
-
|
|
99
|
-
## System URL Resolution
|
|
100
|
-
|
|
101
|
-
System URLs are available via `<<systemId_url>>` syntax. This enables environment-agnostic tools:
|
|
102
|
-
|
|
103
|
-
```javascript
|
|
104
|
-
// System id="salesforce", url="https://mycompany.salesforce.com"
|
|
105
|
-
// Available as: <<salesforce_url>>
|
|
106
|
-
|
|
107
|
-
// Step config:
|
|
108
|
-
{
|
|
109
|
-
"url": "<<salesforce_url>>/services/data/v58.0/sobjects/Account",
|
|
110
|
-
"headers": { "Authorization": "Bearer <<salesforce_access_token>>" }
|
|
111
|
-
}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
**Why use system URL variables?**
|
|
115
|
-
|
|
116
|
-
- Same tool works across dev/prod environments without modification
|
|
117
|
-
- When switching execution mode, the system URL resolves to the appropriate environment
|
|
118
|
-
- Avoids hardcoding base URLs that differ between environments
|
|
119
|
-
|
|
120
|
-
## Data Selectors
|
|
121
|
-
|
|
122
|
-
Every step has a `dataSelector` — a JS function that controls execution mode and what `currentItem` is.
|
|
123
|
-
|
|
124
|
-
### Returns OBJECT → Single Execution
|
|
125
|
-
|
|
126
|
-
Step runs once. The object becomes `currentItem`.
|
|
127
|
-
|
|
128
|
-
```javascript
|
|
129
|
-
(sourceData) => ({ userId: sourceData.userId })
|
|
130
|
-
(sourceData) => ({}) // run once with no specific input
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
Result stored as:
|
|
134
|
-
|
|
135
|
-
```javascript
|
|
136
|
-
sourceData.stepId = { currentItem: <object>, data: <response>, success: true }
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### Returns ARRAY → Loop Execution
|
|
140
|
-
|
|
141
|
-
Step runs once per array element. Each element becomes `currentItem`.
|
|
142
|
-
|
|
143
|
-
```javascript
|
|
144
|
-
(sourceData) => sourceData.getContacts.data.filter(c => c.active)
|
|
145
|
-
(sourceData) => sourceData.userIds // if userIds is an array from payload
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
Result stored as:
|
|
149
|
-
|
|
150
|
-
```javascript
|
|
151
|
-
sourceData.stepId = [
|
|
152
|
-
{ currentItem: <item1>, data: <response1>, success: true },
|
|
153
|
-
{ currentItem: <item2>, data: <response2>, success: true },
|
|
154
|
-
...
|
|
155
|
-
]
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
Empty arrays are valid — step just skips execution.
|
|
159
|
-
|
|
160
|
-
### Accessing currentItem in Step Config
|
|
161
|
-
|
|
162
|
-
```
|
|
163
|
-
<<currentItem>> // whole value
|
|
164
|
-
<<(sourceData) => sourceData.currentItem.id>> // property
|
|
165
|
-
<<(sourceData) => sourceData.currentItem.name.toUpperCase()>> // with transform
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
## Result Envelope
|
|
169
|
-
|
|
170
|
-
**Every** step result (request or transform) is wrapped identically:
|
|
171
|
-
|
|
172
|
-
### From Object Selector
|
|
173
|
-
|
|
174
|
-
```javascript
|
|
175
|
-
sourceData.stepId = {
|
|
176
|
-
currentItem: <selectorOutput>,
|
|
177
|
-
data: <apiResponse or transformResult>,
|
|
178
|
-
success: true
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Access:
|
|
182
|
-
sourceData.stepId.data // the response
|
|
183
|
-
sourceData.stepId.currentItem // what was passed in
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
### From Array Selector
|
|
187
|
-
|
|
188
|
-
```javascript
|
|
189
|
-
sourceData.stepId = [
|
|
190
|
-
{ currentItem: <item1>, data: <response1>, success: true },
|
|
191
|
-
{ currentItem: <item2>, data: <response2>, success: false, error: "..." },
|
|
192
|
-
...
|
|
193
|
-
]
|
|
194
|
-
|
|
195
|
-
// Access:
|
|
196
|
-
sourceData.stepId.map(item => item.data) // all responses
|
|
197
|
-
sourceData.stepId.flatMap(item => item.data.results) // nested arrays
|
|
198
|
-
sourceData.stepId.filter(item => item.success).map(i => i.data) // only successes
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
### From Paginated Step
|
|
202
|
-
|
|
203
|
-
Paginated steps merge all pages server-side into a **single** result. The result is always a single envelope, NOT an array — even though multiple pages were fetched.
|
|
204
|
-
|
|
205
|
-
```javascript
|
|
206
|
-
sourceData.stepId = {
|
|
207
|
-
data: <merged response from all pages>,
|
|
208
|
-
success: true
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Access:
|
|
212
|
-
sourceData.stepId.data // the merged response
|
|
213
|
-
sourceData.stepId.data.items // if the API wraps results in .items
|
|
214
|
-
|
|
215
|
-
// WRONG — do NOT treat paginated results as an array of envelopes:
|
|
216
|
-
sourceData.stepId.map(...) // FAILS — stepId is an object, not an array
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
## sourceData Structure
|
|
220
|
-
|
|
221
|
-
`sourceData` is the cumulative state available to data selectors, variable expressions, and transforms:
|
|
222
|
-
|
|
223
|
-
```javascript
|
|
224
|
-
sourceData = {
|
|
225
|
-
// Original payload fields at ROOT level (NOT under .payload)
|
|
226
|
-
userId: "abc",
|
|
227
|
-
date: "2024-01-15",
|
|
228
|
-
companies: ["acme", "globex"],
|
|
229
|
-
|
|
230
|
-
// Previous step results, keyed by step ID
|
|
231
|
-
getUsers: { currentItem: {}, data: { users: [...] }, success: true },
|
|
232
|
-
fetchDetails: [
|
|
233
|
-
{ currentItem: { id: 1 }, data: { name: "Alice" }, success: true },
|
|
234
|
-
{ currentItem: { id: 2 }, data: { name: "Bob" }, success: true },
|
|
235
|
-
],
|
|
236
|
-
|
|
237
|
-
// Current item (only within a loop step's config)
|
|
238
|
-
currentItem: { id: 1 },
|
|
239
|
-
|
|
240
|
-
// Runtime file map — see file-handling skill for full reference
|
|
241
|
-
__files__: { ... }
|
|
242
|
-
}
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
Treat `sourceData.__files__` as read-only. See the file-handling skill for file detection, the `RuntimeExecutionFile` shape, aliasing rules, and how to access files in transforms.
|
|
246
|
-
|
|
247
|
-
## Three Transformation Points
|
|
248
|
-
|
|
249
|
-
| Point | When it runs | Purpose |
|
|
250
|
-
| -------------------------------- | ------------------------ | ------------------------------------ |
|
|
251
|
-
| `dataSelector` | Before step executes | Controls input + single vs loop mode |
|
|
252
|
-
| Transform step (`transformCode`) | As the step itself | Reshape data between request steps |
|
|
253
|
-
| `outputTransform` | After all steps complete | Shape final tool output |
|
|
254
|
-
|
|
255
|
-
## Transform Steps
|
|
256
|
-
|
|
257
|
-
Transform steps use `type: "transform"` with a `transformCode` function. They do NOT have: systemId, url, method, headers, body, queryParams, or pagination.
|
|
258
|
-
|
|
259
|
-
Results are wrapped in the **same envelope** as request steps:
|
|
260
|
-
|
|
261
|
-
```javascript
|
|
262
|
-
sourceData.formatForInsert = { currentItem: <dataSelector output>, data: <transformCode result>, success: true }
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
If the step has a dataSelector returning an array, the transform runs once per item. See tool-building guidelines for when to use transform steps vs dataSelectors vs outputTransform.
|
|
266
|
-
|
|
267
|
-
### Returning Files From a Transform
|
|
268
|
-
|
|
269
|
-
Transform steps can produce files by returning a reserved `__files__` key in the result. See the file-handling skill for the full shape, aliasing rules, and access patterns.
|
|
270
|
-
|
|
271
|
-
## Output Transform
|
|
272
|
-
|
|
273
|
-
Final transformation shaping the tool's output. Runs after all steps complete. Can access cumulative step result data and payloads.
|
|
274
|
-
|
|
275
|
-
### Requirements
|
|
276
|
-
|
|
277
|
-
- Function signature: `(sourceData) => { ... }`
|
|
278
|
-
- **Must have a return statement**
|
|
279
|
-
- Async/await IS supported (same Deno sandbox as transform steps)
|
|
280
|
-
- NEVER include newlines or tabs in the code string
|
|
281
|
-
|
|
282
|
-
## JS Code Constraints (all transform points)
|
|
283
|
-
|
|
284
|
-
Runs in a Deno subprocess sandbox:
|
|
285
|
-
|
|
286
|
-
- 8192 MB memory limit, 10 min timeout (transforms/selectors), 3s timeout (pagination stops)
|
|
287
|
-
- Async/await IS supported in transforms
|
|
288
|
-
- No filesystem access — `--deny-read`, `--deny-write`
|
|
289
|
-
- No subprocess spawning — `--deny-run`
|
|
290
|
-
- Network access IS available (`--allow-net`) — transforms can make HTTP requests
|
|
291
|
-
- Environment variables are sandboxed — only safe vars (PATH, HOME, DENO_DIR) are visible, no server secrets
|
|
292
|
-
- JSON-serializable I/O only
|
|
293
|
-
- Must return a value (undefined returns null)
|
|
294
|
-
|
|
295
|
-
### Serialization Safety
|
|
296
|
-
|
|
297
|
-
All JS code is stored as a JSON string, then MessagePack-serialized to the Deno subprocess, then `eval()`'d. Patterns that break across this pipeline:
|
|
298
|
-
|
|
299
|
-
- **Regex literals with `/`** — `/https?:\/\/([^/]+)/` corrupts. Use `new URL(str).hostname` or `str.split("//")[1].split("/")[0]` instead.
|
|
300
|
-
- **Backslash-heavy patterns** — `\n`, `\t`, `\\` in regex/strings get misinterpreted. Prefer string methods (`.split()`, `.indexOf()`, `.includes()`) over regex.
|
|
301
|
-
- **Literal newlines** — code string must be single-line. Use `;` between statements.
|
|
302
|
-
|
|
303
|
-
**Rule of thumb**: prefer string methods over regex. When regex is unavoidable, use `new RegExp("pattern")` constructor over `/pattern/` literals.
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
# Database Steps
|
|
2
|
-
|
|
3
|
-
Superglue supports both PostgreSQL and Microsoft SQL Server (including Azure SQL).
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## PostgreSQL
|
|
8
|
-
|
|
9
|
-
### Step Configuration
|
|
10
|
-
|
|
11
|
-
```typescript
|
|
12
|
-
{
|
|
13
|
-
type: "request",
|
|
14
|
-
systemId: "my_postgres_db",
|
|
15
|
-
url: "postgres://<<my_postgres_db_user>>:<<my_postgres_db_password>>@<<my_postgres_db_host>>:<<my_postgres_db_port>>/<<my_postgres_db_database>>",
|
|
16
|
-
body: '{"query": "SELECT * FROM users WHERE id = $1", "params": [<<userId>>]}'
|
|
17
|
-
}
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Configure the connection url depending on which credentials are saved in the stored db system - reference them accordingly.
|
|
21
|
-
|
|
22
|
-
## URL Format
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
postgres://user:password@host:port/database
|
|
26
|
-
postgresql://user:password@host:port/database
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
All credential variables are resolved before connecting. Trailing slashes and extra slashes before query strings are cleaned.
|
|
30
|
-
|
|
31
|
-
## Body Format
|
|
32
|
-
|
|
33
|
-
JSON string with `query` and optional `params` (or `values`):
|
|
34
|
-
|
|
35
|
-
```json
|
|
36
|
-
{ "query": "SELECT * FROM users WHERE age > $1 AND status = $2", "params": [25, "active"] }
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### Parameterized Queries
|
|
40
|
-
|
|
41
|
-
**Always use parameterized queries** with `$1`, `$2`, etc. — prevents SQL injection.
|
|
42
|
-
|
|
43
|
-
```json
|
|
44
|
-
{ "query": "SELECT * FROM orders WHERE customer_id = $1", "params": ["<<customerId>>"] }
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
With expressions:
|
|
48
|
-
|
|
49
|
-
```json
|
|
50
|
-
{
|
|
51
|
-
"query": "INSERT INTO logs (message, level) VALUES ($1, $2)",
|
|
52
|
-
"params": ["<<(sourceData) => sourceData.message>>", "error"]
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
With RETURNING:
|
|
57
|
-
|
|
58
|
-
```json
|
|
59
|
-
{
|
|
60
|
-
"query": "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *",
|
|
61
|
-
"params": [
|
|
62
|
-
"<<(sourceData) => sourceData.currentItem.name>>",
|
|
63
|
-
"<<(sourceData) => sourceData.currentItem.email>>"
|
|
64
|
-
]
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Connection Pooling
|
|
69
|
-
|
|
70
|
-
- Pools cached by connection string, max 10 clients, 5s connection timeout
|
|
71
|
-
- Idle pools cleaned up automatically
|
|
72
|
-
- SSL auto-configured: enabled (with `rejectUnauthorized: false`) unless connecting to localhost without explicit sslmode
|
|
73
|
-
|
|
74
|
-
## Retry Logic
|
|
75
|
-
|
|
76
|
-
Default retries from server config. On final failure, error includes query text and params.
|
|
77
|
-
|
|
78
|
-
## Return Value
|
|
79
|
-
|
|
80
|
-
Returns `result.rows` — array of row objects with column names as keys.
|
|
81
|
-
|
|
82
|
-
- `SELECT`: array of matching rows
|
|
83
|
-
- `INSERT/UPDATE/DELETE` with `RETURNING`: array of returned rows
|
|
84
|
-
- Mutations without `RETURNING`: empty array
|
|
85
|
-
|
|
86
|
-
### Batch Operations via Loop
|
|
87
|
-
|
|
88
|
-
Use a data selector returning an array to execute a query per item:
|
|
89
|
-
|
|
90
|
-
```javascript
|
|
91
|
-
// dataSelector: (sourceData) => sourceData.newUsers
|
|
92
|
-
// body: {"query": "INSERT INTO users (name) VALUES ($1)", "params": ["<<(sourceData) => sourceData.currentItem.name>>"]}
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
---
|
|
96
|
-
|
|
97
|
-
## Microsoft SQL Server / Azure SQL
|
|
98
|
-
|
|
99
|
-
### Step Configuration
|
|
100
|
-
|
|
101
|
-
```typescript
|
|
102
|
-
{
|
|
103
|
-
type: "request",
|
|
104
|
-
systemId: "my_azure_sql",
|
|
105
|
-
url: "mssql://<<my_azure_sql_user>>:<<my_azure_sql_password>>@<<my_azure_sql_host>>:<<my_azure_sql_port>>/<<my_azure_sql_database>>",
|
|
106
|
-
body: '{"query": "SELECT * FROM users WHERE id = @param1", "params": [<<userId>>]}'
|
|
107
|
-
}
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Configure the connection url depending on which credentials are saved in the stored db system - reference them accordingly.
|
|
111
|
-
|
|
112
|
-
### URL Format
|
|
113
|
-
|
|
114
|
-
```
|
|
115
|
-
mssql://user:password@host:port/database
|
|
116
|
-
sqlserver://user:password@host:port/database
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
Both `mssql://` and `sqlserver://` protocols are supported. All credential variables are resolved before connecting.
|
|
120
|
-
|
|
121
|
-
#### Azure SQL Database Connection
|
|
122
|
-
|
|
123
|
-
For Azure SQL Database, use the fully qualified server name:
|
|
124
|
-
|
|
125
|
-
```
|
|
126
|
-
mssql://myuser:mypassword@myserver.database.windows.net:1433/mydatabase
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
Note: Azure SQL usernames often include `@servername` suffix (e.g., `myuser@myserver`). When using in URLs, encode the @ as `%40`:
|
|
130
|
-
|
|
131
|
-
```
|
|
132
|
-
mssql://myuser%40myserver:mypassword@myserver.database.windows.net:1433/mydatabase
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
You can include connection parameters as query strings:
|
|
136
|
-
|
|
137
|
-
```
|
|
138
|
-
mssql://user:password@host:port/database?encrypt=true&trustServerCertificate=false
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
**Connection Parameters:**
|
|
142
|
-
|
|
143
|
-
- `encrypt` (default: `true`) - Enable/disable encryption (required for Azure SQL)
|
|
144
|
-
- `trustServerCertificate` (default: `false`) - Whether to trust the server certificate
|
|
145
|
-
- `database` - Database name (can be in URL path or query parameter)
|
|
146
|
-
|
|
147
|
-
### Body Format
|
|
148
|
-
|
|
149
|
-
JSON string with `query` and optional `params` (or `values`):
|
|
150
|
-
|
|
151
|
-
```json
|
|
152
|
-
{
|
|
153
|
-
"query": "SELECT * FROM users WHERE age > @param1 AND status = @param2",
|
|
154
|
-
"params": [25, "active"]
|
|
155
|
-
}
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### Parameterized Queries
|
|
159
|
-
|
|
160
|
-
**Always use parameterized queries** with `@param1`, `@param2`, etc. — prevents SQL injection.
|
|
161
|
-
|
|
162
|
-
```json
|
|
163
|
-
{ "query": "SELECT * FROM orders WHERE customer_id = @param1", "params": ["<<customerId>>"] }
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
With expressions:
|
|
167
|
-
|
|
168
|
-
```json
|
|
169
|
-
{
|
|
170
|
-
"query": "INSERT INTO logs (message, level) VALUES (@param1, @param2)",
|
|
171
|
-
"params": ["<<(sourceData) => sourceData.message>>", "error"]
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
With OUTPUT (MSSQL equivalent of RETURNING):
|
|
176
|
-
|
|
177
|
-
```json
|
|
178
|
-
{
|
|
179
|
-
"query": "INSERT INTO users (name, email) OUTPUT INSERTED.* VALUES (@param1, @param2)",
|
|
180
|
-
"params": [
|
|
181
|
-
"<<(sourceData) => sourceData.currentItem.name>>",
|
|
182
|
-
"<<(sourceData) => sourceData.currentItem.email>>"
|
|
183
|
-
]
|
|
184
|
-
}
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
**Parameter Naming**: MSSQL uses named parameters with `@` prefix. The params array maps positionally: `params[0]` → `@param1`, `params[1]` → `@param2`, etc.
|
|
188
|
-
|
|
189
|
-
### Connection Pooling
|
|
190
|
-
|
|
191
|
-
- Pools cached by connection string, max 10 clients per pool
|
|
192
|
-
- 5s connection timeout, configurable request timeout
|
|
193
|
-
- Idle pools cleaned up automatically
|
|
194
|
-
- SSL/TLS encryption enabled by default for Azure SQL
|
|
195
|
-
|
|
196
|
-
### Retry Logic
|
|
197
|
-
|
|
198
|
-
Default retries from server config. On final failure, error includes query text and params.
|
|
199
|
-
|
|
200
|
-
### Return Value
|
|
201
|
-
|
|
202
|
-
Returns the recordset — array of row objects with column names as keys.
|
|
203
|
-
|
|
204
|
-
- `SELECT`: array of matching rows
|
|
205
|
-
- `INSERT/UPDATE/DELETE` with `OUTPUT`: array of returned rows
|
|
206
|
-
- Mutations without `OUTPUT`: empty array
|
|
207
|
-
|
|
208
|
-
### Batch Operations via Loop
|
|
209
|
-
|
|
210
|
-
Use a data selector returning an array to execute a query per item:
|
|
211
|
-
|
|
212
|
-
```javascript
|
|
213
|
-
// dataSelector: (sourceData) => sourceData.newUsers
|
|
214
|
-
// body: {"query": "INSERT INTO users (name) VALUES (@param1)", "params": ["<<(sourceData) => sourceData.currentItem.name>>"]}
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
### Common Patterns
|
|
218
|
-
|
|
219
|
-
**Simple SELECT:**
|
|
220
|
-
|
|
221
|
-
```json
|
|
222
|
-
{
|
|
223
|
-
"query": "SELECT id, name, email FROM users WHERE status = @param1",
|
|
224
|
-
"params": ["active"]
|
|
225
|
-
}
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
**INSERT with OUTPUT:**
|
|
229
|
-
|
|
230
|
-
```json
|
|
231
|
-
{
|
|
232
|
-
"query": "INSERT INTO users (name, email, created_at) OUTPUT INSERTED.id, INSERTED.created_at VALUES (@param1, @param2, GETUTCDATE())",
|
|
233
|
-
"params": ["John Doe", "john@example.com"]
|
|
234
|
-
}
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
**UPDATE with OUTPUT:**
|
|
238
|
-
|
|
239
|
-
```json
|
|
240
|
-
{
|
|
241
|
-
"query": "UPDATE users SET last_login = GETUTCDATE() OUTPUT INSERTED.id, INSERTED.last_login WHERE id = @param1",
|
|
242
|
-
"params": [123]
|
|
243
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
**Stored Procedure Call:**
|
|
247
|
-
|
|
248
|
-
```json
|
|
249
|
-
{
|
|
250
|
-
"query": "EXEC dbo.GetUserById @param1",
|
|
251
|
-
"params": [123]
|
|
252
|
-
}
|
|
253
|
-
```
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
# File Server Steps (FTP / SFTP / SMB)
|
|
2
|
-
|
|
3
|
-
FTP, SFTP, and SMB share an identical operation interface. Only the URL protocol and connection details differ.
|
|
4
|
-
|
|
5
|
-
## URL Formats
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
ftp://user:password@host:port/basePath (port 21)
|
|
9
|
-
ftps://user:password@host:port/basePath (port 21, TLS)
|
|
10
|
-
sftp://user:password@host:port/basePath (port 22)
|
|
11
|
-
smb://user:password@host/sharename/basePath (port 445)
|
|
12
|
-
smb://domain\user:password@host/sharename/ (domain auth)
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
All support `<<variable>>` syntax in the URL. **For password-based auth, explicitly include credentials in the connection URL** using `<<systemId_username>>` and `<<systemId_password>>` placeholders (e.g. `sftp://<<mySystem_username>>:<<mySystem_password>>@host/path`). Authentication is never automatic. For SFTP private-key auth, use `credentials.privateKey`/`credentials.passphrase` instead of URL placeholders.
|
|
16
|
-
|
|
17
|
-
SMB requires a share name as the first path segment. Additional segments become a base path prepended to all operation paths.
|
|
18
|
-
|
|
19
|
-
## System Credentials
|
|
20
|
-
|
|
21
|
-
Only store connection credentials: `host`, `port`, `username`, `password`, `privateKey`, `passphrase`, `domain` (SMB), `home_dir`. Paths and share names belong in the URL, not credentials.
|
|
22
|
-
|
|
23
|
-
## Path Handling
|
|
24
|
-
|
|
25
|
-
**All operation paths are relative to the base path in the URL.** Do NOT use absolute filesystem paths.
|
|
26
|
-
|
|
27
|
-
If the system URL is `sftp://user:pass@host/home/sftptest/uploads`:
|
|
28
|
-
|
|
29
|
-
- `report.csv` → `/home/sftptest/uploads/report.csv`
|
|
30
|
-
- `subdir/data.csv` → `/home/sftptest/uploads/subdir/data.csv`
|
|
31
|
-
|
|
32
|
-
Do NOT use `/home/sftptest/uploads/report.csv` — the base path is already set in the URL.
|
|
33
|
-
|
|
34
|
-
If the URL has no base path (e.g., `sftp://user:pass@host`), operation paths are used as-is from the server root.
|
|
35
|
-
|
|
36
|
-
## Body Format
|
|
37
|
-
|
|
38
|
-
JSON string — single operation or array of operations (batch):
|
|
39
|
-
|
|
40
|
-
### Single
|
|
41
|
-
|
|
42
|
-
```json
|
|
43
|
-
{ "operation": "get", "path": "data/report.csv" }
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Batch (sequential, same connection)
|
|
47
|
-
|
|
48
|
-
```json
|
|
49
|
-
[
|
|
50
|
-
{ "operation": "mkdir", "path": "backup" },
|
|
51
|
-
{ "operation": "get", "path": "data/report.csv" },
|
|
52
|
-
{ "operation": "put", "path": "backup/report.csv", "content": "data here" }
|
|
53
|
-
]
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Supported Operations
|
|
57
|
-
|
|
58
|
-
| Operation | Required fields | Returns |
|
|
59
|
-
| --------- | ----------------- | ----------------------------------------------------------------------- |
|
|
60
|
-
| `list` | `path` | Array of `{ name, path, size, type, modifyTime, ... }` |
|
|
61
|
-
| `get` | `path` | Auto-parsed file content (CSV→objects, JSON→parsed, etc.) or raw string |
|
|
62
|
-
| `put` | `path`, `content` | `{ success, message, size }` |
|
|
63
|
-
| `delete` | `path` | `{ success, message }` |
|
|
64
|
-
| `rename` | `path`, `newPath` | `{ success, message }` |
|
|
65
|
-
| `mkdir` | `path` | `{ success, message }` |
|
|
66
|
-
| `rmdir` | `path` | `{ success, message }` |
|
|
67
|
-
| `exists` | `path` | `{ exists: boolean, path }` |
|
|
68
|
-
| `stat` | `path` | File metadata or `{ exists: false }` |
|
|
69
|
-
|
|
70
|
-
### `get` — Step File Keys
|
|
71
|
-
|
|
72
|
-
Downloaded files are added to the runtime file store. See the file-handling skill for the full reference on file detection, aliasing, and the `RuntimeExecutionFile` shape.
|
|
73
|
-
|
|
74
|
-
- `data` contains the auto-parsed content (CSV -> objects, JSON -> parsed, PDF -> structured, etc.)
|
|
75
|
-
- the step result exposes `stepFileKeys`
|
|
76
|
-
- later steps can reference downloaded files via `file::<stepId>.raw` (exact bytes), `file::<stepId>.base64` (base64 string), or `file::<stepId>.extracted` (parsed content)
|
|
77
|
-
- for multi-file operations, use bracket notation: `file::<stepId>["report.csv"].raw`
|
|
78
|
-
|
|
79
|
-
### `put` — Content Handling
|
|
80
|
-
|
|
81
|
-
- `RawFileBytes` (from `file::<key>.raw`) → written as exact original bytes
|
|
82
|
-
- String → written as-is
|
|
83
|
-
- Buffer → written directly
|
|
84
|
-
- Object/Array → JSON.stringified with 2-space indent
|
|
85
|
-
|
|
86
|
-
## Connection Details
|
|
87
|
-
|
|
88
|
-
### SFTP
|
|
89
|
-
|
|
90
|
-
Uses `ssh2-sftp-client`. Supports password + private key auth (`credentials.privateKey`, `credentials.passphrase`).
|
|
91
|
-
|
|
92
|
-
### FTP/FTPS
|
|
93
|
-
|
|
94
|
-
Uses `basic-ftp`. FTPS uses TLS with `rejectUnauthorized: false`.
|
|
95
|
-
|
|
96
|
-
### SMB
|
|
97
|
-
|
|
98
|
-
Uses `@awo00/smb2`. Connection lifecycle: create client → authenticate (domain optional) → connect tree (share) → execute → disconnect/logoff/close. Entire operation wrapped in timeout race.
|
|
99
|
-
|
|
100
|
-
All paths use forward slashes (`/`) — SMB library handles Windows conversion internally.
|
|
101
|
-
|
|
102
|
-
Credentials must be injected into the URL using placeholders:
|
|
103
|
-
|
|
104
|
-
```
|
|
105
|
-
smb://<<systemId_username>>:<<systemId_password>>@fileserver.example.com/ShareName
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
For private systems via Secure Gateway, the host is `tunnelId.tunnel` (e.g., `my_tunnel.tunnel`).
|
|
109
|
-
|
|
110
|
-
## Return Value
|
|
111
|
-
|
|
112
|
-
Single operation → result directly. Multiple operations → array of results.
|