@superglue/cli 1.0.0 → 1.1.1

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.
@@ -0,0 +1,7 @@
1
+ interface:
2
+ display_name: "superglue"
3
+ short_description: "Build, test, deploy, and integrate superglue API tools via the sg CLI and SDK"
4
+ icon_small: "./assets/superglue.png"
5
+ icon_large: "./assets/superglue.png"
6
+ brand_color: "#FFA500"
7
+ default_prompt: "I need help building a superglue integration tool"
@@ -0,0 +1,88 @@
1
+ # Database Steps (PostgreSQL)
2
+
3
+ ## Step Configuration
4
+
5
+ ```typescript
6
+ {
7
+ type: "request",
8
+ systemId: "my_postgres_db",
9
+ url: "postgres://<<my_postgres_db_user>>:<<my_postgres_db_password>>@<<my_postgres_db_host>>:<<my_postgres_db_port>>/<<my_postgres_db_database>>",
10
+ method: "POST", // ignored for Postgres but required by schema
11
+ body: '{"query": "SELECT * FROM users WHERE id = $1", "params": [<<userId>>]}'
12
+ }
13
+ ```
14
+
15
+ Configure the connection url depending on which credentials are saved in the stored db system - reference them accordingly.
16
+
17
+ ## URL Format
18
+
19
+ ```
20
+ postgres://user:password@host:port/database
21
+ postgresql://user:password@host:port/database
22
+ ```
23
+
24
+ All credential variables are resolved before connecting. Trailing slashes and extra slashes before query strings are cleaned.
25
+
26
+ ## Body Format
27
+
28
+ JSON string with `query` and optional `params` (or `values`):
29
+
30
+ ```json
31
+ { "query": "SELECT * FROM users WHERE age > $1 AND status = $2", "params": [25, "active"] }
32
+ ```
33
+
34
+ ### Parameterized Queries
35
+
36
+ **Always use parameterized queries** with `$1`, `$2`, etc. — prevents SQL injection.
37
+
38
+ ```json
39
+ { "query": "SELECT * FROM orders WHERE customer_id = $1", "params": ["<<customerId>>"] }
40
+ ```
41
+
42
+ With expressions:
43
+
44
+ ```json
45
+ {
46
+ "query": "INSERT INTO logs (message, level) VALUES ($1, $2)",
47
+ "params": ["<<(sourceData) => sourceData.message>>", "error"]
48
+ }
49
+ ```
50
+
51
+ With RETURNING:
52
+
53
+ ```json
54
+ {
55
+ "query": "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *",
56
+ "params": [
57
+ "<<(sourceData) => sourceData.currentItem.name>>",
58
+ "<<(sourceData) => sourceData.currentItem.email>>"
59
+ ]
60
+ }
61
+ ```
62
+
63
+ ## Connection Pooling
64
+
65
+ - Pools cached by connection string, max 10 clients, 5s connection timeout
66
+ - Idle pools cleaned up automatically
67
+ - SSL auto-configured: enabled (with `rejectUnauthorized: false`) unless connecting to localhost without explicit sslmode
68
+
69
+ ## Retry Logic
70
+
71
+ Default retries from server config. On final failure, error includes query text and params.
72
+
73
+ ## Return Value
74
+
75
+ Returns `result.rows` — array of row objects with column names as keys.
76
+
77
+ - `SELECT`: array of matching rows
78
+ - `INSERT/UPDATE/DELETE` with `RETURNING`: array of returned rows
79
+ - Mutations without `RETURNING`: empty array
80
+
81
+ ## Batch Operations via Loop
82
+
83
+ Use a data selector returning an array to execute a query per item:
84
+
85
+ ```javascript
86
+ // dataSelector: (sourceData) => sourceData.newUsers
87
+ // body: {"query": "INSERT INTO users (name) VALUES ($1)", "params": ["<<(sourceData) => sourceData.currentItem.name>>"]}
88
+ ```
@@ -0,0 +1,136 @@
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.
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
+ ## Path Handling
20
+
21
+ **All operation paths are relative to the base path in the URL.** Do NOT use absolute filesystem paths.
22
+
23
+ If the system URL is `sftp://user:pass@host/home/sftptest/uploads`:
24
+
25
+ - `report.csv` → `/home/sftptest/uploads/report.csv`
26
+ - `subdir/data.csv` → `/home/sftptest/uploads/subdir/data.csv`
27
+
28
+ Do NOT use `/home/sftptest/uploads/report.csv` — the base path is already set in the URL.
29
+
30
+ If the URL has no base path (e.g., `sftp://user:pass@host`), operation paths are used as-is from the server root.
31
+
32
+ ## Body Format
33
+
34
+ JSON string — single operation or array of operations (batch):
35
+
36
+ ### Single
37
+
38
+ ```json
39
+ { "operation": "get", "path": "data/report.csv" }
40
+ ```
41
+
42
+ ### Batch (sequential, same connection)
43
+
44
+ ```json
45
+ [
46
+ { "operation": "mkdir", "path": "backup" },
47
+ { "operation": "get", "path": "data/report.csv" },
48
+ { "operation": "put", "path": "backup/report.csv", "content": "data here" }
49
+ ]
50
+ ```
51
+
52
+ ## Supported Operations
53
+
54
+ | Operation | Required fields | Returns |
55
+ | --------- | ----------------- | ----------------------------------------------------------------------- |
56
+ | `list` | `path` | Array of `{ name, path, size, type, modifyTime, ... }` |
57
+ | `get` | `path` | Auto-parsed file content (CSV→objects, JSON→parsed, etc.) or raw string |
58
+ | `put` | `path`, `content` | `{ success, message, size }` |
59
+ | `delete` | `path` | `{ success, message }` |
60
+ | `rename` | `path`, `newPath` | `{ success, message }` |
61
+ | `mkdir` | `path` | `{ success, message }` |
62
+ | `rmdir` | `path` | `{ success, message }` |
63
+ | `exists` | `path` | `{ exists: boolean, path }` |
64
+ | `stat` | `path` | File metadata or `{ exists: false }` |
65
+
66
+ ### `get` — Auto-Parsing
67
+
68
+ Downloaded files are all parsed automatically:
69
+
70
+ - CSV, JSON, XML, Excel, PDF, etc. → parsed to JS objects
71
+ - Falls back to UTF-8 string
72
+ - SMB additionally detects binary files (returns `{ _binary: true, encoding: "base64", data: "..." }`)
73
+
74
+ ### `put` — Content Handling
75
+
76
+ - String → written as-is
77
+ - Buffer → written directly
78
+ - Object/Array → `JSON.stringify` with 2-space indent
79
+
80
+ ## Connection Details
81
+
82
+ ### SFTP
83
+
84
+ Uses `ssh2-sftp-client`. Supports password + private key auth (`credentials.privateKey`, `credentials.passphrase`).
85
+
86
+ ### FTP/FTPS
87
+
88
+ Uses `basic-ftp`. FTPS uses TLS with `rejectUnauthorized: false`.
89
+
90
+ ### SMB
91
+
92
+ Uses `@awo00/smb2`. Connection lifecycle: create client → authenticate (domain optional) → connect tree (share) → execute → disconnect/logoff/close. Entire operation wrapped in timeout race.
93
+
94
+ All paths use forward slashes (`/`) — SMB library handles Windows conversion internally.
95
+
96
+ Credentials must be injected into the URL using placeholders:
97
+
98
+ ```
99
+ smb://<<systemId_username>>:<<systemId_password>>@fileserver.example.com/ShareName
100
+ ```
101
+
102
+ For private systems via Secure Gateway, the host is `tunnelId.tunnel` (e.g., `my_tunnel.tunnel`).
103
+
104
+ ## Return Value
105
+
106
+ Single operation → result directly. Multiple operations → array of results.
107
+
108
+ ## Common Patterns
109
+
110
+ ### Download and process
111
+
112
+ ```json
113
+ { "operation": "get", "path": "incoming/<<(sourceData) => sourceData.currentItem.filename>>" }
114
+ ```
115
+
116
+ ### Upload results
117
+
118
+ ```json
119
+ {
120
+ "operation": "put",
121
+ "path": "output/results.json",
122
+ "content": "<<(sourceData) => JSON.stringify(sourceData.processData.data)>>"
123
+ }
124
+ ```
125
+
126
+ ### List then loop
127
+
128
+ Step 1 lists files, step 2 uses data selector to loop over them:
129
+
130
+ ```javascript
131
+ // Step 1: list files
132
+ // body: {"operation": "list", "path": "incoming"}
133
+
134
+ // Step 2 dataSelector: (sourceData) => sourceData.listFiles.data.filter(f => f.type === "file")
135
+ // body: {"operation": "get", "path": "<<(sourceData) => sourceData.currentItem.path>>"}
136
+ ```
@@ -0,0 +1,274 @@
1
+ # Integrating superglue into Your Codebase
2
+
3
+ After building and saving tools with the CLI, integrate them into your application.
4
+
5
+ ## Quick Reference: REST API (curl)
6
+
7
+ For any language, use the REST API directly:
8
+
9
+ ```bash
10
+ # Set your API key and endpoint
11
+ export SUPERGLUE_API_KEY="your-api-key"
12
+ export SUPERGLUE_API_ENDPOINT="https://api.superglue.cloud"
13
+
14
+ # Run a tool (sync - waits for completion)
15
+ curl -X POST "$SUPERGLUE_API_ENDPOINT/v1/tools/my-tool-id/run" \
16
+ -H "Authorization: Bearer $SUPERGLUE_API_KEY" \
17
+ -H "Content-Type: application/json" \
18
+ -d '{"inputs": {"userId": "123"}, "options": {"async": false}}'
19
+
20
+ # Run a tool (async - returns immediately)
21
+ curl -X POST "$SUPERGLUE_API_ENDPOINT/v1/tools/my-tool-id/run" \
22
+ -H "Authorization: Bearer $SUPERGLUE_API_KEY" \
23
+ -H "Content-Type: application/json" \
24
+ -d '{"inputs": {"userId": "123"}, "options": {"async": true}}'
25
+
26
+ # Get run status/result
27
+ curl "$SUPERGLUE_API_ENDPOINT/v1/runs/{runId}" \
28
+ -H "Authorization: Bearer $SUPERGLUE_API_KEY"
29
+
30
+ # List tools
31
+ curl "$SUPERGLUE_API_ENDPOINT/v1/tools?page=1&limit=50" \
32
+ -H "Authorization: Bearer $SUPERGLUE_API_KEY"
33
+
34
+ # Get tool details
35
+ curl "$SUPERGLUE_API_ENDPOINT/v1/tools/my-tool-id" \
36
+ -H "Authorization: Bearer $SUPERGLUE_API_KEY"
37
+
38
+ # Cancel a running tool
39
+ curl -X POST "$SUPERGLUE_API_ENDPOINT/v1/runs/{runId}/cancel" \
40
+ -H "Authorization: Bearer $SUPERGLUE_API_KEY"
41
+ ```
42
+
43
+ ### Response Format
44
+
45
+ **Sync execution (200 OK):**
46
+
47
+ ```json
48
+ {
49
+ "runId": "7f3e9c1a-2b4d-4e8f-9a3b-1c5d7e9f2a4b",
50
+ "toolId": "my-tool-id",
51
+ "status": "success",
52
+ "data": { "result": "..." },
53
+ "metadata": {
54
+ "startedAt": "2024-01-15T10:00:00Z",
55
+ "completedAt": "2024-01-15T10:00:05Z",
56
+ "durationMs": 5234
57
+ }
58
+ }
59
+ ```
60
+
61
+ **Async execution (202 Accepted):**
62
+
63
+ ```json
64
+ {
65
+ "runId": "7f3e9c1a-2b4d-4e8f-9a3b-1c5d7e9f2a4b",
66
+ "toolId": "my-tool-id",
67
+ "status": "running"
68
+ }
69
+ ```
70
+
71
+ ---
72
+
73
+ ## SDK Installation
74
+
75
+ ```bash
76
+ # TypeScript/JavaScript
77
+ npm install @superglue/client
78
+
79
+ # Python
80
+ pip install superglue-client
81
+ ```
82
+
83
+ ## TypeScript/JavaScript Usage
84
+
85
+ ```typescript
86
+ import { configure, listTools, runTool, getRun } from "@superglue/client";
87
+
88
+ // Configure once at startup
89
+ configure({
90
+ apiKey: process.env.SUPERGLUE_API_KEY,
91
+ baseUrl: "https://api.superglue.cloud/v1", // or your self-hosted endpoint
92
+ });
93
+
94
+ // Run a tool (sync - waits for completion)
95
+ const { data: result } = await runTool("my-tool-id", {
96
+ inputs: { userId: "123", date: "2024-01-15" },
97
+ options: { async: false },
98
+ });
99
+
100
+ if (result.status === "success") {
101
+ console.log(result.data);
102
+ } else {
103
+ console.error(result.error);
104
+ }
105
+ ```
106
+
107
+ ### Async Execution (Fire-and-Forget)
108
+
109
+ ```typescript
110
+ // Run async - returns immediately
111
+ const { data: run } = await runTool("my-tool-id", {
112
+ inputs: { userId: "123" },
113
+ options: { async: true },
114
+ });
115
+
116
+ console.log(`Run started: ${run.runId}`);
117
+
118
+ // Poll for completion if needed
119
+ let status = run;
120
+ while (status.status === "running") {
121
+ await new Promise((r) => setTimeout(r, 1000));
122
+ const { data } = await getRun(status.runId);
123
+ status = data;
124
+ }
125
+ ```
126
+
127
+ ### List and Discover Tools
128
+
129
+ ```typescript
130
+ import { listTools, getTool, listSystems } from "@superglue/client";
131
+
132
+ // List all tools
133
+ const { data: tools } = await listTools({ page: 1, limit: 50 });
134
+ console.log(tools.data);
135
+
136
+ // Get tool details (including inputSchema)
137
+ const { data: tool } = await getTool("my-tool-id");
138
+ console.log(tool.inputSchema);
139
+
140
+ // List systems
141
+ const { data: systems } = await listSystems();
142
+ ```
143
+
144
+ ## Python Usage
145
+
146
+ ```python
147
+ import os
148
+ from superglue_client import SuperglueClient
149
+ from superglue_client.api.tools import run_tool, list_tools, get_tool
150
+ from superglue_client.api.runs import get_run
151
+
152
+ # Create authenticated client
153
+ client = SuperglueClient(
154
+ base_url="https://api.superglue.cloud/v1",
155
+ token=os.environ["SUPERGLUE_API_KEY"]
156
+ )
157
+
158
+ # Run a tool (sync)
159
+ with client as c:
160
+ result = run_tool.sync(
161
+ client=c,
162
+ tool_id="my-tool-id",
163
+ body={"inputs": {"userId": "123"}, "options": {"async": False}}
164
+ )
165
+
166
+ if result.status == "success":
167
+ print(result.data)
168
+ else:
169
+ print(result.error)
170
+ ```
171
+
172
+ ### Async Python
173
+
174
+ ```python
175
+ async with client as c:
176
+ result = await run_tool.asyncio(
177
+ client=c,
178
+ tool_id="my-tool-id",
179
+ body={"inputs": {"userId": "123"}}
180
+ )
181
+ ```
182
+
183
+ ## Webhook Triggers
184
+
185
+ Trigger tools via HTTP POST without SDK. Webhooks execute asynchronously.
186
+
187
+ ```bash
188
+ curl -X POST "https://api.superglue.cloud/v1/hooks/{toolId}?token={apiKey}" \
189
+ -H "Content-Type: application/json" \
190
+ -d '{"userId": "123"}'
191
+ ```
192
+
193
+ ### Webhook URL Pattern
194
+
195
+ ```
196
+ POST {endpoint}/v1/hooks/{toolId}?token={apiKey}
197
+ ```
198
+
199
+ - `endpoint` — Your superglue API endpoint
200
+ - `toolId` — The saved tool ID (from `sg tool save`)
201
+ - `apiKey` — Your superglue API key (passed as `token` query param)
202
+
203
+ ### Webhook Response
204
+
205
+ Webhooks return `202 Accepted` immediately:
206
+
207
+ ```json
208
+ {
209
+ "runId": "uuid-of-execution",
210
+ "status": "accepted",
211
+ "toolId": "my-tool-id"
212
+ }
213
+ ```
214
+
215
+ To get the result, poll the run status:
216
+
217
+ ```bash
218
+ curl "https://api.superglue.cloud/v1/runs/{runId}" \
219
+ -H "Authorization: Bearer {apiKey}"
220
+ ```
221
+
222
+ ## Error Handling
223
+
224
+ ### Retry Pattern (TypeScript)
225
+
226
+ ```typescript
227
+ async function runToolWithRetry(toolId: string, inputs: Record<string, any>, maxRetries = 3) {
228
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
229
+ const { data: result } = await runTool(toolId, { inputs, options: { async: false } });
230
+
231
+ if (result.status === "success") return result;
232
+
233
+ // Don't retry on validation errors
234
+ if (result.error?.includes("validation")) throw new Error(result.error);
235
+
236
+ // Exponential backoff for transient errors
237
+ if (attempt < maxRetries) {
238
+ await new Promise((r) => setTimeout(r, 1000 * Math.pow(2, attempt)));
239
+ }
240
+ }
241
+ throw new Error(`Tool ${toolId} failed after ${maxRetries} attempts`);
242
+ }
243
+ ```
244
+
245
+ ### Fallback Pattern
246
+
247
+ ```typescript
248
+ async function runWithFallback(inputs: Record<string, any>) {
249
+ const { data: primary } = await runTool("primary-tool", { inputs, options: { async: false } });
250
+ if (primary.status === "success") return primary;
251
+
252
+ console.warn("Primary tool failed, using fallback");
253
+ const { data: fallback } = await runTool("fallback-tool", { inputs, options: { async: false } });
254
+ return fallback;
255
+ }
256
+ ```
257
+
258
+ ## Environment Configuration
259
+
260
+ ```bash
261
+ # Required
262
+ SUPERGLUE_API_KEY=your-api-key
263
+
264
+ # Optional (defaults to hosted)
265
+ SUPERGLUE_API_ENDPOINT=https://api.superglue.cloud
266
+ ```
267
+
268
+ ## Best Practices
269
+
270
+ 1. **Store API keys in secrets** — Never commit to version control
271
+ 2. **Validate payloads client-side** — Check against `inputSchema` before calling
272
+ 3. **Handle errors gracefully** — Tools can fail due to external API issues
273
+ 4. **Monitor run history** — Use `sg run list` or the web UI to track executions
274
+ 5. **Use async mode for long-running tools** — Avoid timeouts on complex workflows
@@ -0,0 +1,92 @@
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 `isolated-vm` sandbox:
86
+
87
+ - 4096 MB memory limit, 10s timeout (transforms/selectors), 3s timeout (pagination stops)
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)