@withone/cli 1.34.0 → 1.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -39,7 +39,14 @@ npm install -g @withone/cli
|
|
|
39
39
|
one init
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
`one init` walks you through setup: enter your [API key](https://app.withone.ai/settings/api-keys), pick your AI agents, and you're done. The MCP server gets installed automatically.
|
|
42
|
+
`one init` walks you through setup: authenticate via browser or enter your [API key](https://app.withone.ai/settings/api-keys), pick your AI agents, and you're done. The MCP server gets installed automatically.
|
|
43
|
+
|
|
44
|
+
Or authenticate directly:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
one login # Opens browser for authentication (global or per-directory)
|
|
48
|
+
one logout # Clear credentials (with scope picker and confirmation)
|
|
49
|
+
```
|
|
43
50
|
|
|
44
51
|
Requires Node.js 18+.
|
|
45
52
|
|
|
@@ -248,6 +255,7 @@ one actions execute stripe <actionId> <connectionKey> \
|
|
|
248
255
|
| `--dry-run` | Show the request without executing it |
|
|
249
256
|
| `--mock` | Return example response without making an API call |
|
|
250
257
|
| `--skip-validation` | Skip input validation against the action schema |
|
|
258
|
+
| `--output <path>` | Save response to a file (for binary downloads) |
|
|
251
259
|
|
|
252
260
|
The CLI validates required parameters (path variables, query params, body fields) against the action schema before executing. Missing params return a clear error with the flag name and description. Pass `--skip-validation` to bypass.
|
|
253
261
|
|
|
@@ -11,6 +11,10 @@ import { exec, spawn } from "child_process";
|
|
|
11
11
|
import { promisify } from "util";
|
|
12
12
|
|
|
13
13
|
// src/lib/api.ts
|
|
14
|
+
import { createWriteStream } from "fs";
|
|
15
|
+
import { resolve } from "path";
|
|
16
|
+
import { pipeline } from "stream/promises";
|
|
17
|
+
import { Readable } from "stream";
|
|
14
18
|
var ApiError = class extends Error {
|
|
15
19
|
constructor(status, message, retryAfterSeconds) {
|
|
16
20
|
super(message);
|
|
@@ -328,12 +332,45 @@ var OneApi = class {
|
|
|
328
332
|
const text = await response.text();
|
|
329
333
|
throw new ApiError(response.status, text || `HTTP ${response.status}`);
|
|
330
334
|
}
|
|
335
|
+
const responseContentType = response.headers.get("content-type") || "";
|
|
336
|
+
const isExplicitJson = responseContentType.includes("application/json") || responseContentType.includes("text/");
|
|
337
|
+
if (isExplicitJson || !responseContentType) {
|
|
338
|
+
const responseText2 = await response.text();
|
|
339
|
+
const responseData = responseText2 ? JSON.parse(responseText2) : {};
|
|
340
|
+
return { requestConfig: sanitizedConfig, responseData };
|
|
341
|
+
}
|
|
342
|
+
if (args.output) {
|
|
343
|
+
const outputPath = resolve(args.output);
|
|
344
|
+
const body = response.body;
|
|
345
|
+
if (!body) {
|
|
346
|
+
throw new ApiError(0, "Response body is null \u2014 cannot save to file");
|
|
347
|
+
}
|
|
348
|
+
const nodeReadable = Readable.fromWeb(body);
|
|
349
|
+
await pipeline(nodeReadable, createWriteStream(outputPath));
|
|
350
|
+
const contentLength = response.headers.get("content-length");
|
|
351
|
+
const size = contentLength ? parseInt(contentLength, 10) : void 0;
|
|
352
|
+
return {
|
|
353
|
+
requestConfig: sanitizedConfig,
|
|
354
|
+
responseData: { saved: true, path: outputPath, size, contentType: responseContentType }
|
|
355
|
+
};
|
|
356
|
+
}
|
|
331
357
|
const responseText = await response.text();
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
requestConfig: sanitizedConfig,
|
|
335
|
-
|
|
336
|
-
|
|
358
|
+
try {
|
|
359
|
+
const responseData = responseText ? JSON.parse(responseText) : {};
|
|
360
|
+
return { requestConfig: sanitizedConfig, responseData };
|
|
361
|
+
} catch {
|
|
362
|
+
const contentLength = response.headers.get("content-length");
|
|
363
|
+
const size = contentLength ? parseInt(contentLength, 10) : responseText.length;
|
|
364
|
+
return {
|
|
365
|
+
requestConfig: sanitizedConfig,
|
|
366
|
+
responseData: {
|
|
367
|
+
binary: true,
|
|
368
|
+
size,
|
|
369
|
+
contentType: responseContentType,
|
|
370
|
+
message: "Binary response received. Use --output <path> to save to a file."
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
}
|
|
337
374
|
}
|
|
338
375
|
// Webhook Relay methods
|
|
339
376
|
async createRelayEndpoint(body) {
|
|
@@ -394,7 +431,7 @@ var TimeoutError = class extends Error {
|
|
|
394
431
|
}
|
|
395
432
|
};
|
|
396
433
|
function sleep(ms) {
|
|
397
|
-
return new Promise((
|
|
434
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
398
435
|
}
|
|
399
436
|
function replacePathVariables(path3, variables) {
|
|
400
437
|
if (!path3) return path3;
|
|
@@ -532,7 +569,7 @@ function setByDotPath(obj, dotPath, value) {
|
|
|
532
569
|
// src/lib/flow-engine.ts
|
|
533
570
|
var execAsync = promisify(exec);
|
|
534
571
|
function sleep2(ms) {
|
|
535
|
-
return new Promise((
|
|
572
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
536
573
|
}
|
|
537
574
|
var StepTimeoutError = class extends Error {
|
|
538
575
|
errorCode = "TIMEOUT";
|
|
@@ -843,7 +880,7 @@ async function executeCodeModule(stepId, modulePath, context, options) {
|
|
|
843
880
|
const { env: _omitEnv, ...safeContext } = context;
|
|
844
881
|
void _omitEnv;
|
|
845
882
|
const stdinPayload = JSON.stringify(safeContext);
|
|
846
|
-
return await new Promise((
|
|
883
|
+
return await new Promise((resolve2, reject) => {
|
|
847
884
|
const child = spawn(process.execPath, [absPath], {
|
|
848
885
|
cwd: rootDir,
|
|
849
886
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -862,11 +899,11 @@ async function executeCodeModule(stepId, modulePath, context, options) {
|
|
|
862
899
|
}
|
|
863
900
|
const trimmed = stdout.trim();
|
|
864
901
|
if (trimmed === "") {
|
|
865
|
-
|
|
902
|
+
resolve2(void 0);
|
|
866
903
|
return;
|
|
867
904
|
}
|
|
868
905
|
try {
|
|
869
|
-
|
|
906
|
+
resolve2(JSON.parse(stripCodeFences(trimmed)));
|
|
870
907
|
} catch (err) {
|
|
871
908
|
reject(new Error(`Code module "${modulePath}" did not print valid JSON to stdout: ${err.message}`));
|
|
872
909
|
}
|
|
@@ -1042,7 +1079,7 @@ async function executeSubflowStep(step, context, api, permissions, allowedAction
|
|
|
1042
1079
|
if (flowStack.includes(resolvedKey)) {
|
|
1043
1080
|
throw new Error(`Circular flow detected: ${[...flowStack, resolvedKey].join(" \u2192 ")}`);
|
|
1044
1081
|
}
|
|
1045
|
-
const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-
|
|
1082
|
+
const { loadFlowWithMeta: loadFlowWithMeta2 } = await import("./flow-runner-OVOGDXNR.js");
|
|
1046
1083
|
const { flow: subFlow, rootDir: subRootDir } = loadFlowWithMeta2(resolvedKey);
|
|
1047
1084
|
const subContext = await executeFlow(
|
|
1048
1085
|
subFlow,
|