@zapier/zapier-sdk-cli 0.30.0 → 0.31.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/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @zapier/zapier-sdk-cli
2
2
 
3
+ ## 0.31.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ad5ee3b: Adds a new curl plugin.
8
+ Switch -v flag to -V for version information.
9
+ Fix CLI to properly handle string and object types.
10
+ Add redirect passthrough to fetch plugin (to support curl plugin).
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated dependencies [ad5ee3b]
15
+ - @zapier/zapier-sdk@0.29.0
16
+ - @zapier/zapier-sdk-mcp@0.9.4
17
+
3
18
  ## 0.30.0
4
19
 
5
20
  ### Minor Changes
package/README.md CHANGED
@@ -30,7 +30,7 @@
30
30
  - [`get-connection`](#get-connection)
31
31
  - [`list-connections`](#list-connections)
32
32
  - [HTTP Requests](#http-requests)
33
- - [`fetch`](#fetch)
33
+ - [`curl`](#curl)
34
34
  - [Utilities](#utilities)
35
35
  - [`add`](#add)
36
36
  - [`build-manifest`](#build-manifest)
@@ -85,7 +85,7 @@ These options are available for all commands:
85
85
 
86
86
  | Option | Short | Description |
87
87
  | -------------------------------------- | ----- | -------------------------------------------------- |
88
- | `--version` | `-v` | Display version number |
88
+ | `--version` | `-V` | Display version number |
89
89
  | `--help` | `-h` | Display help for command |
90
90
  | `--debug` | | Enable debug logging |
91
91
  | `--json` | | Output raw JSON instead of formatted results |
@@ -450,25 +450,46 @@ npx zapier-sdk list-connections [--search] [--title] [--owner] [--app-key] [--co
450
450
 
451
451
  ### HTTP Requests
452
452
 
453
- #### `fetch`
453
+ #### `curl`
454
454
 
455
- Make authenticated HTTP requests to any API through Zapier's Relay service. Pass a connectionId to automatically inject the user's stored credentials (OAuth tokens, API keys, etc.) into the outgoing request. Mirrors the native fetch(url, init?) signature with additional Zapier-specific options.
455
+ Make authenticated HTTP requests to any API through Zapier. Pass a connection ID to automatically inject the user's stored credentials (OAuth tokens, API keys, etc.) into the outgoing request. Use it in place of the native curl command with additional Zapier-specific options.
456
456
 
457
457
  **Options:**
458
458
 
459
- | Option | Type | Required | Default | Possible Values | Description |
460
- | ----------------- | -------------------------------- | -------- | ------- | ---------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
461
- | `<url>` | `string, custom` | ✅ | — | — | The full URL of the API endpoint to call (proxied through Zapier's Relay service) |
462
- | `--method` | `string` | ❌ | — | `GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`, `OPTIONS` | HTTP method for the request (defaults to GET) |
463
- | `--headers` | `object` | ❌ | — | — | HTTP headers to include in the request |
464
- | `--body` | `string, custom, custom, record` | ❌ | — | — | Request body plain objects and JSON strings are auto-detected and Content-Type is set accordingly |
465
- | `--connection-id` | `string, number` | ❌ | — | — | Connection ID to use for this action |
466
- | `--callback-url` | `string` | ❌ | — | — | URL to send async response to (makes request async) |
459
+ | Option | Type | Required | Default | Possible Values | Description |
460
+ | ------------------ | ---------------- | -------- | ------- | ---------------------------------------------------------- | ------------------------------------------------------------ |
461
+ | `<url>` | `string` | ✅ | — | — | Request URL |
462
+ | `--request` | `string` | ❌ | — | `GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`, `OPTIONS` | HTTP method (defaults to GET, or POST if data is provided) |
463
+ | `--header` | `array` | ❌ | — | — | HTTP headers in 'Key: Value' format (repeatable) |
464
+ | `--data` | `array` | ❌ | — | — | HTTP POST data (repeatable, joined with &) |
465
+ | `--data-raw` | `array` | ❌ | — | — | HTTP POST data without special interpretation (repeatable) |
466
+ | `--data-ascii` | `array` | ❌ | — | — | HTTP POST ASCII data (repeatable) |
467
+ | `--data-binary` | `array` | ❌ | — | — | HTTP POST binary data (repeatable) |
468
+ | `--data-urlencode` | `array` | ❌ | — | — | HTTP POST data, URL-encoded (repeatable) |
469
+ | `--json` | `string` | ❌ | — | — | Send JSON body (sets Content-Type and Accept headers) |
470
+ | `--form` | `array` | ❌ | — | — | Multipart form data as 'name=value' (repeatable) |
471
+ | `--form-string` | `array` | ❌ | — | — | Multipart form string field (repeatable) |
472
+ | `--get` | `boolean` | ❌ | — | — | Force GET method and append data to query string |
473
+ | `--head` | `boolean` | ❌ | — | — | Fetch headers only (HEAD request) |
474
+ | `--location` | `boolean` | ❌ | — | — | Follow redirects |
475
+ | `--include` | `boolean` | ❌ | — | — | Include response headers in output |
476
+ | `--output` | `string` | ❌ | — | — | Write output to file instead of stdout |
477
+ | `--remote-name` | `boolean` | ❌ | — | — | Write output to file named like the remote file |
478
+ | `--verbose` | `boolean` | ❌ | — | — | Verbose output (show request/response headers on stderr) |
479
+ | `--silent` | `boolean` | ❌ | — | — | Silent mode (suppress errors) |
480
+ | `--show-error` | `boolean` | ❌ | — | — | Show errors even when in silent mode |
481
+ | `--fail` | `boolean` | ❌ | — | — | Fail silently on HTTP errors (exit code 22) |
482
+ | `--fail-with-body` | `boolean` | ❌ | — | — | Fail on HTTP errors but still output the body |
483
+ | `--write-out` | `string` | ❌ | — | — | Output format string after completion (e.g., '%{http_code}') |
484
+ | `--max-time` | `number` | ❌ | — | — | Maximum time in seconds for the request |
485
+ | `--user` | `string` | ❌ | — | — | Basic auth credentials as 'user:password' |
486
+ | `--compressed` | `boolean` | ❌ | — | — | Request compressed response (sends Accept-Encoding header) |
487
+ | `--connection-id` | `string, number` | ❌ | — | — | Zapier connection ID for authentication |
467
488
 
468
489
  **Usage:**
469
490
 
470
491
  ```bash
471
- npx zapier-sdk fetch <url> [--method] [--headers] [--body] [--connection-id] [--callback-url]
492
+ npx zapier-sdk curl <url> [--request] [--header] [--data] [--data-raw] [--data-ascii] [--data-binary] [--data-urlencode] [--json] [--form] [--form-string] [--get] [--head] [--location] [--include] [--output] [--remote-name] [--verbose] [--silent] [--show-error] [--fail] [--fail-with-body] [--write-out] [--max-time] [--user] [--compressed] [--connection-id]
472
493
  ```
473
494
 
474
495
  ### Utilities
package/dist/cli.cjs CHANGED
@@ -963,7 +963,7 @@ function analyzeZodField(name, schema, functionInfo) {
963
963
  paramType = "string";
964
964
  choices = baseSchema.options;
965
965
  } else if (baseSchema instanceof zod.z.ZodRecord) {
966
- paramType = "string";
966
+ paramType = "object";
967
967
  }
968
968
  let paramHasResolver = false;
969
969
  if (functionInfo?.resolvers?.[name]) {
@@ -1278,9 +1278,14 @@ ${confirmMessageAfter}`));
1278
1278
  description,
1279
1279
  parameters,
1280
1280
  handler,
1281
- hidden: functionInfo.categories?.includes("deprecated") ?? false
1281
+ hidden: functionInfo.categories?.includes("deprecated") ?? false,
1282
+ aliases: functionInfo.aliases
1282
1283
  };
1283
1284
  }
1285
+ function collect(value, previous = []) {
1286
+ previous.push(value);
1287
+ return previous;
1288
+ }
1284
1289
  function addCommand(program2, commandName, config2) {
1285
1290
  const command = program2.command(commandName, { hidden: config2.hidden ?? false }).description(config2.description);
1286
1291
  let hasPositionalArray = false;
@@ -1299,10 +1304,12 @@ function addCommand(program2, commandName, config2) {
1299
1304
  );
1300
1305
  } else if (param.required && param.type === "array") {
1301
1306
  const flags = [`--${kebabName}`];
1302
- const flagSignature = flags.join(", ") + ` <values...>`;
1307
+ const flagSignature = flags.join(", ") + ` <value>`;
1303
1308
  command.requiredOption(
1304
1309
  flagSignature,
1305
- param.description || `${kebabName} parameter (required)`
1310
+ param.description || `${kebabName} parameter (required, repeatable)`,
1311
+ collect,
1312
+ []
1306
1313
  );
1307
1314
  } else if (param.required) {
1308
1315
  command.argument(
@@ -1315,16 +1322,17 @@ function addCommand(program2, commandName, config2) {
1315
1322
  param.description || `${kebabName} parameter`
1316
1323
  );
1317
1324
  } else {
1318
- const flags = [`--${kebabName}`];
1325
+ const flags = [];
1326
+ const alias = config2.aliases?.[param.name];
1327
+ if (alias && alias.length === 1) {
1328
+ flags.push(`-${alias}`);
1329
+ }
1330
+ flags.push(`--${kebabName}`);
1319
1331
  if (param.type === "boolean") {
1320
1332
  command.option(flags.join(", "), param.description);
1321
1333
  } else if (param.type === "array") {
1322
- const flagSignature = flags.join(", ") + ` <values...>`;
1323
- command.option(
1324
- flagSignature,
1325
- param.description,
1326
- param.default
1327
- );
1334
+ const flagSignature = flags.join(", ") + ` <value>`;
1335
+ command.option(flagSignature, param.description || "", collect, []);
1328
1336
  } else {
1329
1337
  const flagSignature = flags.join(", ") + ` <${param.type}>`;
1330
1338
  command.option(
@@ -1335,7 +1343,10 @@ function addCommand(program2, commandName, config2) {
1335
1343
  }
1336
1344
  }
1337
1345
  });
1338
- command.option("--json", "Output raw JSON instead of formatted results");
1346
+ const hasJsonParam = config2.parameters.some((p) => p.name === "json");
1347
+ if (!hasJsonParam) {
1348
+ command.option("--json", "Output raw JSON instead of formatted results");
1349
+ }
1339
1350
  command.action(config2.handler);
1340
1351
  }
1341
1352
  function convertCliArgsToSdkParams(parameters, positionalArgs, options) {
@@ -1371,6 +1382,16 @@ function convertValue(value, type) {
1371
1382
  case "array":
1372
1383
  return Array.isArray(value) ? value : [value];
1373
1384
  case "string":
1385
+ return value;
1386
+ case "object":
1387
+ if (typeof value === "string") {
1388
+ try {
1389
+ return JSON.parse(value);
1390
+ } catch {
1391
+ return value;
1392
+ }
1393
+ }
1394
+ return value;
1374
1395
  default:
1375
1396
  if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) {
1376
1397
  try {
@@ -1780,7 +1801,7 @@ var LoginSchema = zod.z.object({
1780
1801
 
1781
1802
  // package.json
1782
1803
  var package_default = {
1783
- version: "0.30.0"};
1804
+ version: "0.31.0"};
1784
1805
 
1785
1806
  // src/telemetry/builders.ts
1786
1807
  function createCliBaseEvent(context = {}) {
@@ -3116,18 +3137,450 @@ var feedbackPlugin = ({
3116
3137
  }
3117
3138
  };
3118
3139
  };
3140
+ var CurlSchema = zod.z.object({
3141
+ url: zod.z.string().describe("Request URL"),
3142
+ request: zod.z.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]).optional().describe("HTTP method (defaults to GET, or POST if data is provided)"),
3143
+ header: zod.z.array(zod.z.string()).optional().describe("HTTP headers in 'Key: Value' format (repeatable)"),
3144
+ data: zod.z.array(zod.z.string()).optional().describe("HTTP POST data (repeatable, joined with &)"),
3145
+ dataRaw: zod.z.array(zod.z.string()).optional().describe("HTTP POST data without special interpretation (repeatable)"),
3146
+ dataAscii: zod.z.array(zod.z.string()).optional().describe("HTTP POST ASCII data (repeatable)"),
3147
+ dataBinary: zod.z.array(zod.z.string()).optional().describe("HTTP POST binary data (repeatable)"),
3148
+ dataUrlencode: zod.z.array(zod.z.string()).optional().describe("HTTP POST data, URL-encoded (repeatable)"),
3149
+ json: zod.z.string().optional().describe("Send JSON body (sets Content-Type and Accept headers)"),
3150
+ form: zod.z.array(zod.z.string()).optional().describe("Multipart form data as 'name=value' (repeatable)"),
3151
+ formString: zod.z.array(zod.z.string()).optional().describe("Multipart form string field (repeatable)"),
3152
+ get: zod.z.boolean().optional().describe("Force GET method and append data to query string"),
3153
+ head: zod.z.boolean().optional().describe("Fetch headers only (HEAD request)"),
3154
+ location: zod.z.boolean().optional().describe("Follow redirects"),
3155
+ include: zod.z.boolean().optional().describe("Include response headers in output"),
3156
+ output: zod.z.string().optional().describe("Write output to file instead of stdout"),
3157
+ remoteName: zod.z.boolean().optional().describe("Write output to file named like the remote file"),
3158
+ verbose: zod.z.boolean().optional().describe("Verbose output (show request/response headers on stderr)"),
3159
+ silent: zod.z.boolean().optional().describe("Silent mode (suppress errors)"),
3160
+ showError: zod.z.boolean().optional().describe("Show errors even when in silent mode"),
3161
+ fail: zod.z.boolean().optional().describe("Fail silently on HTTP errors (exit code 22)"),
3162
+ failWithBody: zod.z.boolean().optional().describe("Fail on HTTP errors but still output the body"),
3163
+ writeOut: zod.z.string().optional().describe("Output format string after completion (e.g., '%{http_code}')"),
3164
+ maxTime: zod.z.number().optional().describe("Maximum time in seconds for the request"),
3165
+ user: zod.z.string().optional().describe("Basic auth credentials as 'user:password'"),
3166
+ compressed: zod.z.boolean().optional().describe("Request compressed response (sends Accept-Encoding header)"),
3167
+ connectionId: zod.z.union([zod.z.string(), zod.z.number()]).optional().describe("Zapier connection ID for authentication")
3168
+ }).describe("Make HTTP requests through Zapier Relay with curl-like options");
3169
+ var CurlExitError = class extends Error {
3170
+ constructor(message, exitCode) {
3171
+ super(message);
3172
+ this.exitCode = exitCode;
3173
+ this.name = "CurlExitError";
3174
+ }
3175
+ };
3176
+ function parseHeaderLine(input) {
3177
+ const idx = input.indexOf(":");
3178
+ if (idx === -1) {
3179
+ return null;
3180
+ }
3181
+ const key = input.slice(0, idx).trim();
3182
+ const value = input.slice(idx + 1).trim();
3183
+ if (!key) {
3184
+ return null;
3185
+ }
3186
+ return { key, value };
3187
+ }
3188
+ function basicAuthHeader(userpass) {
3189
+ const idx = userpass.indexOf(":");
3190
+ const user = idx === -1 ? userpass : userpass.slice(0, idx);
3191
+ const pass = idx === -1 ? "" : userpass.slice(idx + 1);
3192
+ const token = Buffer.from(`${user}:${pass}`, "utf8").toString("base64");
3193
+ return `Basic ${token}`;
3194
+ }
3195
+ function deriveRemoteFilename(url) {
3196
+ const path2 = url.pathname;
3197
+ const candidate = path2.endsWith("/") ? "index.html" : path.basename(path2);
3198
+ return candidate || "index.html";
3199
+ }
3200
+ function decodeWriteOutEscapes(input) {
3201
+ return input.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ");
3202
+ }
3203
+ function formatWriteOut(params) {
3204
+ const { template } = params;
3205
+ const replacements = {
3206
+ "%{http_code}": String(params.httpCode).padStart(3, "0"),
3207
+ "%{time_total}": params.timeTotalSeconds.toFixed(3),
3208
+ "%{size_download}": String(params.sizeDownloadBytes),
3209
+ "%{url_effective}": params.urlEffective,
3210
+ "%{content_type}": params.contentType ?? ""
3211
+ };
3212
+ let out = template;
3213
+ for (const [token, value] of Object.entries(replacements)) {
3214
+ out = out.split(token).join(value);
3215
+ }
3216
+ return decodeWriteOutEscapes(out);
3217
+ }
3218
+ function appendQueryParams(url, dataParts) {
3219
+ const out = new URL(url.toString());
3220
+ for (const part of dataParts) {
3221
+ const segments = part.split("&");
3222
+ for (const seg of segments) {
3223
+ if (!seg) continue;
3224
+ const idx = seg.indexOf("=");
3225
+ if (idx === -1) {
3226
+ out.searchParams.append(seg, "");
3227
+ } else {
3228
+ out.searchParams.append(seg.slice(0, idx), seg.slice(idx + 1));
3229
+ }
3230
+ }
3231
+ }
3232
+ return out;
3233
+ }
3234
+ async function readAllStdin() {
3235
+ const chunks = [];
3236
+ for await (const chunk of process.stdin) {
3237
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
3238
+ }
3239
+ return Buffer.concat(chunks);
3240
+ }
3241
+ async function resolveDataArgText(raw) {
3242
+ if (!raw.startsWith("@")) {
3243
+ return raw;
3244
+ }
3245
+ const source = raw.slice(1);
3246
+ if (source === "-") {
3247
+ const buf2 = await readAllStdin();
3248
+ return buf2.toString("utf8");
3249
+ }
3250
+ const buf = await fs.promises.readFile(source);
3251
+ return buf.toString("utf8");
3252
+ }
3253
+ async function resolveDataArgBinary(raw) {
3254
+ if (!raw.startsWith("@")) {
3255
+ return Buffer.from(raw, "utf8");
3256
+ }
3257
+ const source = raw.slice(1);
3258
+ if (source === "-") {
3259
+ return await readAllStdin();
3260
+ }
3261
+ return await fs.promises.readFile(source);
3262
+ }
3263
+ async function buildFormData(formArgs, formStringArgs) {
3264
+ if (typeof FormData === "undefined") {
3265
+ throw new CurlExitError(
3266
+ "FormData is not available in this runtime; cannot use --form.",
3267
+ 2
3268
+ );
3269
+ }
3270
+ const fd = new FormData();
3271
+ const addField = async (item, forceString) => {
3272
+ const idx = item.indexOf("=");
3273
+ if (idx === -1) {
3274
+ throw new CurlExitError(
3275
+ `Invalid form field: '${item}'. Expected 'name=value' or 'name=@file'.`,
3276
+ 2
3277
+ );
3278
+ }
3279
+ const name = item.slice(0, idx);
3280
+ const value = item.slice(idx + 1);
3281
+ if (!name) {
3282
+ throw new CurlExitError(
3283
+ `Invalid form field: '${item}'. Field name cannot be empty.`,
3284
+ 2
3285
+ );
3286
+ }
3287
+ if (!forceString && value.startsWith("@")) {
3288
+ const filePath = value.slice(1);
3289
+ const buf = filePath === "-" ? await readAllStdin() : await fs.promises.readFile(filePath);
3290
+ if (typeof Blob === "undefined") {
3291
+ fd.append(name, buf.toString("utf8"));
3292
+ return;
3293
+ }
3294
+ const blob = new Blob([buf]);
3295
+ const filename = filePath === "-" ? `stdin-${crypto.createHash("sha1").update(buf).digest("hex").slice(0, 8)}` : path.basename(filePath);
3296
+ fd.append(name, blob, filename);
3297
+ return;
3298
+ }
3299
+ fd.append(name, value);
3300
+ };
3301
+ for (const item of formArgs) {
3302
+ await addField(item, false);
3303
+ }
3304
+ for (const item of formStringArgs) {
3305
+ await addField(item, true);
3306
+ }
3307
+ return fd;
3308
+ }
3309
+
3310
+ // src/plugins/curl/index.ts
3311
+ var curlPlugin = ({
3312
+ sdk: sdk2
3313
+ }) => {
3314
+ async function curl(options) {
3315
+ const {
3316
+ url: rawUrl,
3317
+ request,
3318
+ header = [],
3319
+ data = [],
3320
+ dataRaw = [],
3321
+ dataAscii = [],
3322
+ dataBinary = [],
3323
+ dataUrlencode = [],
3324
+ json,
3325
+ form = [],
3326
+ formString = [],
3327
+ get: forceGet,
3328
+ head: forceHead,
3329
+ location,
3330
+ include,
3331
+ output,
3332
+ remoteName,
3333
+ verbose,
3334
+ silent,
3335
+ showError,
3336
+ fail,
3337
+ failWithBody,
3338
+ writeOut,
3339
+ maxTime,
3340
+ user,
3341
+ compressed,
3342
+ connectionId
3343
+ } = options;
3344
+ const parsedUrl = new URL(rawUrl);
3345
+ const headers = {};
3346
+ for (const h of header) {
3347
+ const parsed = parseHeaderLine(h);
3348
+ if (parsed) {
3349
+ headers[parsed.key] = parsed.value;
3350
+ }
3351
+ }
3352
+ if (user) {
3353
+ headers["Authorization"] = basicAuthHeader(user);
3354
+ }
3355
+ if (compressed) {
3356
+ headers["Accept-Encoding"] = "gzip, deflate, br";
3357
+ }
3358
+ const rawTextDataArgs = [...data, ...dataRaw, ...dataAscii];
3359
+ const rawBinaryDataArgs = [...dataBinary];
3360
+ const rawUrlencodeArgs = [...dataUrlencode];
3361
+ const hasForm = form.length > 0 || formString.length > 0;
3362
+ const hasJson = json !== void 0;
3363
+ const hasAnyData = hasJson || hasForm || rawTextDataArgs.length > 0 || rawBinaryDataArgs.length > 0 || rawUrlencodeArgs.length > 0;
3364
+ let method = "GET";
3365
+ if (forceHead) {
3366
+ method = "HEAD";
3367
+ } else if (request) {
3368
+ method = request;
3369
+ } else if (forceGet) {
3370
+ method = "GET";
3371
+ } else if (hasAnyData) {
3372
+ method = "POST";
3373
+ }
3374
+ let body;
3375
+ let effectiveUrl = parsedUrl;
3376
+ if (hasJson) {
3377
+ if (!headers["Content-Type"]) {
3378
+ headers["Content-Type"] = "application/json";
3379
+ }
3380
+ if (!headers["Accept"]) {
3381
+ headers["Accept"] = "application/json";
3382
+ }
3383
+ body = json;
3384
+ } else if (hasForm) {
3385
+ body = await buildFormData(form, formString);
3386
+ } else {
3387
+ const resolvedTextParts = [];
3388
+ for (const raw of rawTextDataArgs) {
3389
+ resolvedTextParts.push(await resolveDataArgText(raw));
3390
+ }
3391
+ const resolvedUrlEncodeParts = [];
3392
+ for (const raw of rawUrlencodeArgs) {
3393
+ if (raw.startsWith("@")) {
3394
+ const content = await resolveDataArgText(raw);
3395
+ resolvedUrlEncodeParts.push(encodeURIComponent(content));
3396
+ continue;
3397
+ }
3398
+ const atIdx = raw.indexOf("@");
3399
+ const eqIdx = raw.indexOf("=");
3400
+ if (eqIdx !== -1) {
3401
+ const key = raw.slice(0, eqIdx);
3402
+ const value = raw.slice(eqIdx + 1);
3403
+ resolvedUrlEncodeParts.push(
3404
+ `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
3405
+ );
3406
+ } else if (atIdx !== -1) {
3407
+ const key = raw.slice(0, atIdx);
3408
+ const filePath = raw.slice(atIdx + 1);
3409
+ const buf2 = filePath === "-" ? await readAllStdin() : await fs.promises.readFile(filePath);
3410
+ resolvedUrlEncodeParts.push(
3411
+ `${encodeURIComponent(key)}=${encodeURIComponent(buf2.toString("utf8"))}`
3412
+ );
3413
+ } else {
3414
+ resolvedUrlEncodeParts.push(encodeURIComponent(raw));
3415
+ }
3416
+ }
3417
+ const resolvedBinaryParts = [];
3418
+ for (const raw of rawBinaryDataArgs) {
3419
+ resolvedBinaryParts.push(await resolveDataArgBinary(raw));
3420
+ }
3421
+ const allTextParts = [...resolvedTextParts, ...resolvedUrlEncodeParts];
3422
+ if (forceGet && allTextParts.length > 0) {
3423
+ effectiveUrl = appendQueryParams(parsedUrl, allTextParts);
3424
+ } else if (resolvedBinaryParts.length > 0) {
3425
+ body = Buffer.concat(resolvedBinaryParts);
3426
+ } else if (allTextParts.length > 0) {
3427
+ body = allTextParts.join("&");
3428
+ if (!headers["Content-Type"]) {
3429
+ headers["Content-Type"] = "application/x-www-form-urlencoded";
3430
+ }
3431
+ }
3432
+ }
3433
+ const redirect = location ? "follow" : "manual";
3434
+ if (verbose && !silent) {
3435
+ process.stderr.write(`> ${method} ${effectiveUrl.toString()}
3436
+ `);
3437
+ for (const [k, v] of Object.entries(headers)) {
3438
+ process.stderr.write(`> ${k}: ${v}
3439
+ `);
3440
+ }
3441
+ process.stderr.write(">\n");
3442
+ }
3443
+ const signal = maxTime ? AbortSignal.timeout(maxTime * 1e3) : void 0;
3444
+ const start = performance.now();
3445
+ const response = await sdk2.fetch(effectiveUrl.toString(), {
3446
+ method,
3447
+ headers,
3448
+ body,
3449
+ redirect,
3450
+ signal,
3451
+ connectionId
3452
+ });
3453
+ const timeTotalSeconds = (performance.now() - start) / 1e3;
3454
+ if (verbose && !silent) {
3455
+ process.stderr.write(
3456
+ `< HTTP ${response.status} ${response.statusText}
3457
+ `
3458
+ );
3459
+ response.headers.forEach((value, key) => {
3460
+ process.stderr.write(`< ${key}: ${value}
3461
+ `);
3462
+ });
3463
+ process.stderr.write("<\n");
3464
+ }
3465
+ const isHttpError = response.status >= 400;
3466
+ const shouldFail = (fail || failWithBody) && isHttpError;
3467
+ const shouldOutputBody = !shouldFail || !!failWithBody;
3468
+ const headerText = include ? `HTTP ${response.status} ${response.statusText}
3469
+ ${Array.from(
3470
+ response.headers.entries()
3471
+ ).map(([k, v]) => `${k}: ${v}`).join("\n")}
3472
+
3473
+ ` : "";
3474
+ let bodyBytes = 0;
3475
+ const buf = shouldOutputBody ? Buffer.from(await response.arrayBuffer()) : Buffer.alloc(0);
3476
+ bodyBytes = buf.length;
3477
+ const outputFile = output && output !== "-" ? output : remoteName ? deriveRemoteFilename(parsedUrl) : void 0;
3478
+ if (outputFile) {
3479
+ const dir = path.dirname(outputFile);
3480
+ if (dir !== ".") {
3481
+ await fs.promises.mkdir(dir, { recursive: true });
3482
+ }
3483
+ const ws = fs.createWriteStream(outputFile);
3484
+ if (headerText) {
3485
+ ws.write(headerText);
3486
+ }
3487
+ if (buf.length) {
3488
+ ws.write(buf);
3489
+ }
3490
+ await new Promise((resolve4, reject) => {
3491
+ ws.end(() => resolve4());
3492
+ ws.on("error", reject);
3493
+ });
3494
+ } else {
3495
+ if (headerText) {
3496
+ process.stdout.write(headerText);
3497
+ }
3498
+ if (buf.length) {
3499
+ process.stdout.write(buf);
3500
+ }
3501
+ }
3502
+ if (writeOut) {
3503
+ const formatted = formatWriteOut({
3504
+ template: writeOut,
3505
+ urlEffective: response.url || effectiveUrl.toString(),
3506
+ httpCode: response.status,
3507
+ timeTotalSeconds,
3508
+ sizeDownloadBytes: bodyBytes,
3509
+ contentType: response.headers.get("content-type")
3510
+ });
3511
+ process.stdout.write(formatted);
3512
+ }
3513
+ if (shouldFail) {
3514
+ if (!silent || showError) {
3515
+ process.stderr.write(
3516
+ `curl: (22) The requested URL returned error: ${response.status}
3517
+ `
3518
+ );
3519
+ }
3520
+ throw new CurlExitError("HTTP request failed", 22);
3521
+ }
3522
+ return void 0;
3523
+ }
3524
+ return {
3525
+ curl,
3526
+ context: {
3527
+ meta: {
3528
+ curl: {
3529
+ description: "Make authenticated HTTP requests to any API through Zapier. Pass a connection ID to automatically inject the user's stored credentials (OAuth tokens, API keys, etc.) into the outgoing request. Use it in place of the native curl command with additional Zapier-specific options.",
3530
+ categories: ["http"],
3531
+ inputSchema: CurlSchema,
3532
+ aliases: {
3533
+ request: "X",
3534
+ header: "H",
3535
+ data: "d",
3536
+ form: "F",
3537
+ get: "G",
3538
+ head: "I",
3539
+ location: "L",
3540
+ include: "i",
3541
+ output: "o",
3542
+ remoteName: "O",
3543
+ verbose: "v",
3544
+ silent: "s",
3545
+ showError: "S",
3546
+ writeOut: "w",
3547
+ maxTime: "m",
3548
+ user: "u"
3549
+ }
3550
+ }
3551
+ }
3552
+ }
3553
+ };
3554
+ };
3555
+
3556
+ // src/plugins/cliOverrides/index.ts
3557
+ var cliOverridesPlugin = ({ context }) => {
3558
+ if (!context.meta.fetch) {
3559
+ return { context: { meta: {} } };
3560
+ }
3561
+ return {
3562
+ context: {
3563
+ meta: {
3564
+ fetch: {
3565
+ ...context.meta.fetch,
3566
+ categories: [...context.meta.fetch.categories || [], "deprecated"]
3567
+ }
3568
+ }
3569
+ }
3570
+ };
3571
+ };
3119
3572
 
3120
3573
  // src/sdk.ts
3121
3574
  function createZapierCliSdk(options = {}) {
3122
3575
  return zapierSdk.createZapierSdkWithoutRegistry({
3123
3576
  ...options
3124
- }).addPlugin(generateAppTypesPlugin).addPlugin(buildManifestPlugin).addPlugin(bundleCodePlugin).addPlugin(getLoginConfigPathPlugin).addPlugin(addPlugin).addPlugin(feedbackPlugin).addPlugin(mcpPlugin).addPlugin(loginPlugin).addPlugin(logoutPlugin).addPlugin(zapierSdk.registryPlugin);
3577
+ }).addPlugin(generateAppTypesPlugin).addPlugin(buildManifestPlugin).addPlugin(bundleCodePlugin).addPlugin(getLoginConfigPathPlugin).addPlugin(addPlugin).addPlugin(feedbackPlugin).addPlugin(curlPlugin).addPlugin(mcpPlugin).addPlugin(loginPlugin).addPlugin(logoutPlugin).addPlugin(cliOverridesPlugin).addPlugin(zapierSdk.registryPlugin);
3125
3578
  }
3126
3579
 
3127
3580
  // package.json with { type: 'json' }
3128
3581
  var package_default2 = {
3129
3582
  name: "@zapier/zapier-sdk-cli",
3130
- version: "0.30.0"};
3583
+ version: "0.31.0"};
3131
3584
  function detectPackageManager(cwd = process.cwd()) {
3132
3585
  const ua = process.env.npm_config_user_agent;
3133
3586
  if (ua) {
@@ -3330,7 +3783,7 @@ async function checkAndNotifyUpdates({
3330
3783
 
3331
3784
  // src/cli.ts
3332
3785
  var program = new commander.Command();
3333
- program.name("zapier-sdk").description("CLI for Zapier SDK").version(package_default2.version, "-v, --version", "display version number").option("--debug", "Enable debug logging").option("--base-url <url>", "Base URL for Zapier API endpoints").option("--credentials <token>", "Authentication token").option("--credentials-client-id <id>", "OAuth client ID for authentication").option(
3786
+ program.name("zapier-sdk").description("CLI for Zapier SDK").version(package_default2.version, void 0, "Display version number").option("--debug", "Enable debug logging").option("--base-url <url>", "Base URL for Zapier API endpoints").option("--credentials <token>", "Authentication token").option("--credentials-client-id <id>", "OAuth client ID for authentication").option(
3334
3787
  "--credentials-client-secret <secret>",
3335
3788
  "OAuth client secret for authentication"
3336
3789
  ).option(
@@ -3342,7 +3795,7 @@ program.name("zapier-sdk").description("CLI for Zapier SDK").version(package_def
3342
3795
  ).option(
3343
3796
  "--max-network-retry-delay-ms <ms>",
3344
3797
  "Max delay in ms to wait for rate limit retry (default: 60000)"
3345
- );
3798
+ ).helpOption("-h, --help", "Display help for command");
3346
3799
  var isDebugMode = process.env.DEBUG === "true" || process.argv.includes("--debug");
3347
3800
  function getFlagValue(flagName) {
3348
3801
  const index = process.argv.indexOf(flagName);