@superglue/cli 1.1.20 → 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.
Files changed (32) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +1 -7
  3. package/dist/cli.js +303 -74
  4. package/dist/skills/superglue/SKILL.md +313 -621
  5. package/dist/skills/superglue/references/file-handling.md +116 -90
  6. package/dist/skills/superglue/references/graphql.md +131 -0
  7. package/dist/skills/superglue/references/http.md +246 -0
  8. package/dist/skills/superglue/references/integration.md +4 -2
  9. package/dist/skills/superglue/references/mssql.md +207 -0
  10. package/dist/skills/superglue/references/postgres.md +154 -0
  11. package/dist/skills/superglue/references/redis.md +68 -118
  12. package/dist/skills/superglue/references/sftp-smb.md +156 -0
  13. package/dist/skills/superglue/references/superglue-info.md +91 -0
  14. package/package.json +1 -1
  15. package/skills/superglue/SKILL.md +313 -621
  16. package/skills/superglue/references/file-handling.md +116 -90
  17. package/skills/superglue/references/graphql.md +131 -0
  18. package/skills/superglue/references/http.md +246 -0
  19. package/skills/superglue/references/integration.md +4 -2
  20. package/skills/superglue/references/mssql.md +207 -0
  21. package/skills/superglue/references/postgres.md +154 -0
  22. package/skills/superglue/references/redis.md +68 -118
  23. package/skills/superglue/references/sftp-smb.md +156 -0
  24. package/skills/superglue/references/superglue-info.md +91 -0
  25. package/dist/skills/superglue/references/data-handling.md +0 -303
  26. package/dist/skills/superglue/references/databases.md +0 -253
  27. package/dist/skills/superglue/references/file-servers.md +0 -112
  28. package/dist/skills/superglue/references/http-apis.md +0 -248
  29. package/skills/superglue/references/data-handling.md +0 -303
  30. package/skills/superglue/references/databases.md +0 -253
  31. package/skills/superglue/references/file-servers.md +0 -112
  32. package/skills/superglue/references/http-apis.md +0 -248
@@ -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.
@@ -1,248 +0,0 @@
1
- # HTTP APIs
2
-
3
- Covers REST APIs, GraphQL, webhooks, and any HTTP-based service.
4
-
5
- ## Step Configuration
6
-
7
- ```typescript
8
- {
9
- type: "request",
10
- systemId: "my_api",
11
- url: "<<my_api_url>>/v1/users", // RECOMMENDED: use system URL variable for base URL
12
- method: "GET", // GET, POST, PUT, DELETE, PATCH
13
- headers: { "Authorization": "Bearer <<my_api_access_token>>" }, // supports <<variables>> and JS expressions
14
- queryParams: { "limit": "<<limit>>", "status": "active" }, // supports <<variables>> and JS expressions
15
- body: '{"name": "<<(sourceData) => sourceData.currentItem.name>>"}', // supports <<variables>> and JS expressions
16
- pagination: { ... } // optional
17
- }
18
- ```
19
-
20
- ### URL Best Practices
21
-
22
- **Prefer system URL variables over hardcoded URLs:**
23
-
24
- ```typescript
25
- // RECOMMENDED: Environment-agnostic (works with dev/prod switching)
26
- { "url": "<<salesforce_url>>/services/data/v58.0/sobjects/Account" }
27
-
28
- // ACCEPTABLE: When URL differs significantly from system base URL
29
- { "url": "https://api.stripe.com/v1/customers" }
30
-
31
- // AVOID: Hardcoding URLs that match the system's base URL
32
- { "url": "https://mycompany.salesforce.com/services/data/v58.0/sobjects/Account" }
33
- ```
34
-
35
- Using `<<systemId_url>>` enables the same tool to work across different environments (dev/prod) without modification. The URL resolves dynamically based on execution mode.
36
-
37
- ## Authentication Patterns
38
-
39
- ```javascript
40
- // Bearer token
41
- { "Authorization": "Bearer <<systemId_access_token>>" }
42
-
43
- // API key in header
44
- { "X-API-Key": "<<systemId_api_key>>" }
45
-
46
- // Basic Auth — auto-encoded to Base64, do NOT manually encode
47
- { "Authorization": "Basic <<systemId_username>>:<<systemId_password>>" }
48
-
49
- // Runtime credentials from payload
50
- { "Authorization": "Bearer <<(sourceData) => sourceData.user_access_token>>" }
51
- ```
52
-
53
- Headers starting with `x-` are treated as custom headers.
54
- Modern APIs expect auth in headers, NOT query parameters, unless docs explicitly say otherwise.
55
-
56
- ## Request Behavior
57
-
58
- - **GET, HEAD, DELETE, OPTIONS**: Body is always stripped
59
- - **POST, PUT, PATCH**: Body with leading `{` is JSON-parsed; empty body becomes undefined
60
- - Default headers: `Accept: */*`, Chrome-like `User-Agent`
61
- - HTTPS: `rejectUnauthorized: false` (accepts self-signed certs)
62
-
63
- ### Response Handling
64
-
65
- All HTTP responses are read as raw bytes, then classified by `detectFileType` (byte-level detection). See the file-handling skill for the full detection logic and file type reference.
66
-
67
- - **Binary types** (PDF, Excel, DOCX, ZIP, GZIP): treated as files. Parsed content also becomes `data`. Later steps can reference the file via `file::<stepId>.raw/base64/extracted`.
68
- - **`application/octet-stream`**: always treated as a file, even if byte-level detection falls back to `RAW`.
69
- - **Large responses over 25 MB**: treated as files as a safety fallback so the runtime does not try to parse a huge unknown blob as RAW text/JSON.
70
- - **RAW + Content-Disposition attachment**: treated as a file.
71
- - **Smaller structured/text responses** (JSON, XML, CSV, YAML, HTML, plain text under the size limit): parsed inline to `data` only.
72
-
73
- This means an HTTP step downloading a PDF or large `.bin` file will expose `stepFileKeys` and populate `sourceData.__files__`, while an ordinary JSON API response will usually just populate `sourceData.stepId.data`.
74
-
75
- ### Body Resolution Order
76
-
77
- For HTTP request steps, the runtime processes the body in this order:
78
-
79
- 1. `<<>>` template variables are resolved via `replaceVariables`
80
- 2. The resulting body string is JSON-parsed when possible
81
- 3. `file::...` references are resolved on the parsed body object
82
- 4. The HTTP strategy decides how to send the final body:
83
- - raw bytes for `file::<key>.raw` when the **entire body** is a file ref
84
- - base64 string content for `file::<key>.base64` when the API expects base64 inside JSON/XML
85
- - `multipart/form-data` when the `Content-Type` header requests it and the body resolves to an object
86
- - plain string body for strings
87
- - `JSON.stringify(...)` for ordinary objects
88
-
89
- File references are resolved **only in the body**, not in headers, query params, or URLs.
90
-
91
- **Avoiding double-encoding:** The runtime stringifies objects at both step 1 (expression → template) and step 4 (object → fetch body). When the body contains nested JSON (e.g. LLM APIs), have `<<>>` expressions return a string via `JSON.stringify(...)`, or use a preceding transform step.
92
-
93
- ### File Uploads
94
-
95
- #### Raw Body Uploads
96
-
97
- If the endpoint expects the file as the entire HTTP body, use:
98
-
99
- ```typescript
100
- {
101
- method: "PUT",
102
- headers: { "Content-Type": "application/pdf" },
103
- body: "file::document.raw"
104
- }
105
- ```
106
-
107
- This sends the exact original file bytes as the request body.
108
-
109
- #### Base64-In-JSON/XML Uploads
110
-
111
- If the endpoint expects the file encoded as base64 inside a structured payload, use:
112
-
113
- ```typescript
114
- {
115
- method: "POST",
116
- headers: { "Content-Type": "application/json" },
117
- body: '{"fileBase64":"file::document.base64"}'
118
- }
119
- ```
120
-
121
- This resolves the file bytes to a base64 string before the final `JSON.stringify(...)`.
122
-
123
- #### Automatic Multipart Uploads
124
-
125
- If the endpoint expects `multipart/form-data`, set the header and make the body a JSON object of form fields:
126
-
127
- ```typescript
128
- {
129
- method: "POST",
130
- headers: { "Content-Type": "multipart/form-data" },
131
- body: '{"file":"file::report.raw","description":"monthly export"}'
132
- }
133
- ```
134
-
135
- The runtime will:
136
-
137
- - build a real `FormData` request
138
- - turn `file::...raw` values into file parts using the stored filename and content type
139
- - turn scalar values into text parts
140
- - JSON-stringify non-file objects/arrays into text parts
141
- - remove the user-supplied `Content-Type` header and let `fetch` set the multipart boundary automatically
142
-
143
- Restrictions:
144
-
145
- - the multipart body must resolve to an object of top-level form fields
146
- - nested file refs inside objects are not supported
147
- - do **not** manually include a multipart boundary in the header
148
- - use `.raw` for file parts, `.base64` for base64 text fields, and `.extracted` only for text fields that should contain parsed content
149
-
150
- ## Error Detection
151
-
152
- ### HTTP Status Errors
153
-
154
- Non-2xx responses throw with: method, URL, response body preview (1000 chars), masked config, retry count.
155
-
156
- ### Smart Error Detection in 2xx Responses
157
-
158
- Even successful responses are scanned for error indicators:
159
-
160
- - `response.code` or `response.status` is 400-599 → throws
161
- - Keys matching `error`, `errors`, `error_message`, `failure_reason`, `failure`, `failed` (up to depth 2) with non-empty values → throws
162
- - Error message includes: _"To prevent this from happening, enable 'Continue on failure' in the step's Advanced Settings."_
163
-
164
- Bypass: `failureBehavior: "continue"` skips all error checking. Can be set in the tool playground.
165
-
166
- ## Retry Logic
167
-
168
- ### Connection/Server Errors
169
-
170
- - Default 1 retry (3 if keep-alive disabled), capped at server max
171
- - Only retries if response was fast (under quick-retry threshold)
172
- - Configurable delay between retries
173
-
174
- ### Rate Limiting (429)
175
-
176
- - Respects `Retry-After` header (seconds or date)
177
- - Without header: exponential backoff `10^n * 1000ms + jitter` (max 1hr per wait)
178
- - Total wait capped at `MAX_RATE_LIMIT_WAIT_MS`
179
- - Separate from general retry count
180
-
181
- ## Pagination
182
-
183
- Makes multiple requests in a loop, merging results. Only configure if you've verified the exact API pagination mechanism from docs.
184
-
185
- ### Configuration
186
-
187
- ```typescript
188
- pagination: {
189
- type: "offsetBased" | "pageBased" | "cursorBased",
190
- pageSize: "50",
191
- cursorPath: "meta.next_cursor", // cursorBased only — JSONPath to cursor
192
- stopCondition: "(response, pageInfo) => !response.data.meta.next_cursor"
193
- }
194
- ```
195
-
196
- ### Variables (auto-injected)
197
-
198
- | Type | Variable | Starts at | Increments by |
199
- | ----------- | ---------------------------- | --------- | ------------------------ |
200
- | pageBased | `<<page>>` | 1 | 1 |
201
- | offsetBased | `<<offset>>` | 0 | pageSize |
202
- | cursorBased | `<<cursor>>` | null | extracted via cursorPath |
203
- | all | `<<limit>>` / `<<pageSize>>` | pageSize | — |
204
-
205
- **CRITICAL**: The matching pagination variable MUST appear in the request (URL, queryParams, headers, or body). Throws if missing.
206
-
207
- ### Stop Conditions
208
-
209
- JS expression evaluated in sandbox. Receives `(response, pageInfo)`:
210
-
211
- - `response.data` = parsed API response body
212
- - `response.headers` = response headers
213
- - `pageInfo = { page, offset, cursor, totalFetched }`
214
- - Return `true` to **STOP**
215
-
216
- Examples:
217
-
218
- ```javascript
219
- "!response.data.meta.next_cursor"; // no next cursor
220
- "response.data.items.length === 0"; // empty page
221
- "response.data.hasMore === false"; // explicit flag
222
- "pageInfo.totalFetched >= 1000"; // item cap
223
- ```
224
-
225
- ### Safety Checks (only when stopCondition is set)
226
-
227
- 1. **Identical pages 1 & 2** (both with data): Throws — pagination params aren't being applied
228
- 2. **Both pages empty + stop didn't trigger**: Throws — broken stop condition
229
- 3. **Duplicate consecutive response (after page 2)**: Auto-stops
230
-
231
- ### Without stopCondition (fallback)
232
-
233
- - Array shorter than pageSize → stop
234
- - Duplicate response hash (against any previously seen page) → stop
235
- - Non-array response → stop after first request
236
- - Max 500 requests (vs 1000 max with a stopCondition)
237
-
238
- ### Cursor Extraction
239
-
240
- `cursorPath` is a JSONPath expression (auto-prefixed with `$.` if needed). Extracted via `jsonpath-plus`. Null cursor → stop.
241
-
242
- **Special characters in cursorPath:** For property names containing `@` (e.g. OData's `@odata.nextLink`), use the property name directly as the cursorPath: `cursorPath: "@odata.nextLink"`. The engine handles `@`-prefixed paths automatically.
243
-
244
- ## Output
245
-
246
- Paginated steps merge all pages into a **single** result object. The step result is always accessed via `sourceData.stepId.data` — it is NOT an array of per-page results. Do NOT call `.map()` on a paginated step result.
247
-
248
- Returns single object if one result, array if multiple (unwrapped from single-element array).