@picahq/cli 1.11.1 → 1.12.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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +69 -14
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -201,6 +201,7 @@ one actions execute stripe <actionId> <connectionKey> \
201
201
  | `--headers <json>` | Additional request headers |
202
202
  | `--form-data` | Send as multipart/form-data |
203
203
  | `--form-url-encoded` | Send as application/x-www-form-urlencoded |
204
+ | `--dry-run` | Show the request without executing it |
204
205
 
205
206
  ### `one guide [topic]`
206
207
 
package/dist/index.js CHANGED
@@ -483,6 +483,12 @@ var OneApi = class {
483
483
  ) : void 0,
484
484
  data: requestData
485
485
  };
486
+ if (args.dryRun) {
487
+ return {
488
+ requestConfig: sanitizedConfig,
489
+ responseData: null
490
+ };
491
+ }
486
492
  const response = await fetch(fullUrl, fetchOpts);
487
493
  if (!response.ok) {
488
494
  const text4 = await response.text();
@@ -1841,7 +1847,7 @@ async function actionsExecuteCommand(platform, actionId, connectionKey, options)
1841
1847
  const queryParams = options.queryParams ? parseJsonArg(options.queryParams, "--query-params") : void 0;
1842
1848
  const headers = options.headers ? parseJsonArg(options.headers, "--headers") : void 0;
1843
1849
  const execSpinner = createSpinner();
1844
- execSpinner.start("Executing action...");
1850
+ execSpinner.start(options.dryRun ? "Building request..." : "Executing action...");
1845
1851
  const result = await api.executePassthroughRequest(
1846
1852
  {
1847
1853
  platform,
@@ -1852,18 +1858,22 @@ async function actionsExecuteCommand(platform, actionId, connectionKey, options)
1852
1858
  queryParams,
1853
1859
  headers,
1854
1860
  isFormData: options.formData,
1855
- isFormUrlEncoded: options.formUrlEncoded
1861
+ isFormUrlEncoded: options.formUrlEncoded,
1862
+ dryRun: options.dryRun
1856
1863
  },
1857
1864
  actionDetails
1858
1865
  );
1859
- execSpinner.stop("Action executed successfully");
1866
+ execSpinner.stop(options.dryRun ? "Dry run \u2014 request not sent" : "Action executed successfully");
1860
1867
  if (isAgentMode()) {
1861
1868
  json({
1869
+ dryRun: options.dryRun || false,
1862
1870
  request: {
1863
1871
  method: result.requestConfig.method,
1864
- url: result.requestConfig.url
1872
+ url: result.requestConfig.url,
1873
+ headers: options.dryRun ? result.requestConfig.headers : void 0,
1874
+ data: options.dryRun ? result.requestConfig.data : void 0
1865
1875
  },
1866
- response: result.responseData
1876
+ response: options.dryRun ? void 0 : result.responseData
1867
1877
  });
1868
1878
  return;
1869
1879
  }
@@ -1874,9 +1884,19 @@ async function actionsExecuteCommand(platform, actionId, connectionKey, options)
1874
1884
  ` ${result.requestConfig.method} ${result.requestConfig.url}`
1875
1885
  )
1876
1886
  );
1877
- console.log();
1878
- console.log(pc6.bold("Response:"));
1879
- console.log(JSON.stringify(result.responseData, null, 2));
1887
+ if (options.dryRun) {
1888
+ if (result.requestConfig.data) {
1889
+ console.log();
1890
+ console.log(pc6.dim("Body:"));
1891
+ console.log(pc6.dim(JSON.stringify(result.requestConfig.data, null, 2)));
1892
+ }
1893
+ console.log();
1894
+ note2("Dry run \u2014 request was not sent", "Dry Run");
1895
+ } else {
1896
+ console.log();
1897
+ console.log(pc6.bold("Response:"));
1898
+ console.log(JSON.stringify(result.responseData, null, 2));
1899
+ }
1880
1900
  } catch (error2) {
1881
1901
  spinner5.stop("Execution failed");
1882
1902
  error(
@@ -2355,12 +2375,42 @@ async function executeLoopStep(step, context, api, permissions, allowedActionIds
2355
2375
  throw new Error(`Loop "over" must resolve to an array, got ${typeof items}`);
2356
2376
  }
2357
2377
  const maxIterations = loop.maxIterations || 1e3;
2358
- const results = [];
2378
+ const bounded = items.slice(0, maxIterations);
2359
2379
  const savedLoop = { ...context.loop };
2360
- for (let i = 0; i < Math.min(items.length, maxIterations); i++) {
2380
+ if (loop.maxConcurrency && loop.maxConcurrency > 1) {
2381
+ const results2 = new Array(bounded.length);
2382
+ for (let batchStart = 0; batchStart < bounded.length; batchStart += loop.maxConcurrency) {
2383
+ const batch = bounded.slice(batchStart, batchStart + loop.maxConcurrency);
2384
+ const batchResults = await Promise.all(
2385
+ batch.map(async (item, batchIdx) => {
2386
+ const i = batchStart + batchIdx;
2387
+ const iterContext = {
2388
+ ...context,
2389
+ loop: {
2390
+ [loop.as]: item,
2391
+ item,
2392
+ i,
2393
+ ...loop.indexAs ? { [loop.indexAs]: i } : {}
2394
+ },
2395
+ steps: { ...context.steps }
2396
+ };
2397
+ await executeSteps(loop.steps, iterContext, api, permissions, allowedActionIds, options);
2398
+ Object.assign(context.steps, iterContext.steps);
2399
+ return iterContext.loop[loop.as];
2400
+ })
2401
+ );
2402
+ for (let j = 0; j < batchResults.length; j++) {
2403
+ results2[batchStart + j] = batchResults[j];
2404
+ }
2405
+ }
2406
+ context.loop = savedLoop;
2407
+ return { status: "success", output: results2, response: results2 };
2408
+ }
2409
+ const results = [];
2410
+ for (let i = 0; i < bounded.length; i++) {
2361
2411
  context.loop = {
2362
- [loop.as]: items[i],
2363
- item: items[i],
2412
+ [loop.as]: bounded[i],
2413
+ item: bounded[i],
2364
2414
  i
2365
2415
  };
2366
2416
  if (loop.indexAs) {
@@ -3343,6 +3393,7 @@ Options:
3343
3393
  - \`--headers <json>\` \u2014 Additional headers as JSON
3344
3394
  - \`--form-data\` \u2014 Send as multipart/form-data instead of JSON
3345
3395
  - \`--form-url-encoded\` \u2014 Send as application/x-www-form-urlencoded
3396
+ - \`--dry-run\` \u2014 Show the request that would be sent without executing it
3346
3397
 
3347
3398
  Examples:
3348
3399
  \`\`\`bash
@@ -3605,6 +3656,7 @@ The \`source\` field contains a JS function body. The flow context is available
3605
3656
  "as": "order",
3606
3657
  "indexAs": "i",
3607
3658
  "maxIterations": 1000,
3659
+ "maxConcurrency": 5,
3608
3660
  "steps": [
3609
3661
  {
3610
3662
  "id": "createInvoice",
@@ -3622,6 +3674,8 @@ The \`source\` field contains a JS function body. The flow context is available
3622
3674
  }
3623
3675
  \`\`\`
3624
3676
 
3677
+ - \`maxConcurrency\` (optional): When set > 1, loop iterations run in parallel batches of that size. Default is sequential (1).
3678
+
3625
3679
  ### \`parallel\` \u2014 Run steps concurrently
3626
3680
 
3627
3681
  \`\`\`json
@@ -4084,14 +4138,15 @@ actions.command("search <platform> <query>").description('Search for actions on
4084
4138
  actions.command("knowledge <platform> <actionId>").alias("k").description("Get full docs for an action \u2014 MUST call before execute to know required params").action(async (platform, actionId) => {
4085
4139
  await actionsKnowledgeCommand(platform, actionId);
4086
4140
  });
4087
- actions.command("execute <platform> <actionId> <connectionKey>").alias("x").description('Execute an action \u2014 pass connectionKey from "one list", actionId from "actions search"').option("-d, --data <json>", "Request body as JSON").option("--path-vars <json>", "Path variables as JSON").option("--query-params <json>", "Query parameters as JSON").option("--headers <json>", "Additional headers as JSON").option("--form-data", "Send as multipart/form-data").option("--form-url-encoded", "Send as application/x-www-form-urlencoded").action(async (platform, actionId, connectionKey, options) => {
4141
+ actions.command("execute <platform> <actionId> <connectionKey>").alias("x").description('Execute an action \u2014 pass connectionKey from "one list", actionId from "actions search"').option("-d, --data <json>", "Request body as JSON").option("--path-vars <json>", "Path variables as JSON").option("--query-params <json>", "Query parameters as JSON").option("--headers <json>", "Additional headers as JSON").option("--form-data", "Send as multipart/form-data").option("--form-url-encoded", "Send as application/x-www-form-urlencoded").option("--dry-run", "Show request that would be sent without executing").action(async (platform, actionId, connectionKey, options) => {
4088
4142
  await actionsExecuteCommand(platform, actionId, connectionKey, {
4089
4143
  data: options.data,
4090
4144
  pathVars: options.pathVars,
4091
4145
  queryParams: options.queryParams,
4092
4146
  headers: options.headers,
4093
4147
  formData: options.formData,
4094
- formUrlEncoded: options.formUrlEncoded
4148
+ formUrlEncoded: options.formUrlEncoded,
4149
+ dryRun: options.dryRun
4095
4150
  });
4096
4151
  });
4097
4152
  var flow = program.command("flow").alias("f").description("Create, execute, and manage multi-step API workflows");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@picahq/cli",
3
- "version": "1.11.1",
3
+ "version": "1.12.0",
4
4
  "description": "CLI for managing One",
5
5
  "type": "module",
6
6
  "files": [