@zapier/zapier-sdk-cli 0.44.1 → 0.46.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 (45) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +381 -29
  3. package/bin/zapier-sdk-experimental.mjs +14 -0
  4. package/dist/cli.cjs +608 -38
  5. package/dist/cli.mjs +607 -37
  6. package/dist/experimental.cjs +3519 -0
  7. package/dist/experimental.d.mts +39 -0
  8. package/dist/experimental.d.ts +39 -0
  9. package/dist/experimental.mjs +3483 -0
  10. package/dist/index.cjs +507 -26
  11. package/dist/index.d.mts +3 -514
  12. package/dist/index.d.ts +3 -514
  13. package/dist/index.mjs +505 -24
  14. package/dist/package.json +14 -2
  15. package/dist/sdk-B3nKAZdN.d.mts +516 -0
  16. package/dist/sdk-B3nKAZdN.d.ts +516 -0
  17. package/dist/src/cli.js +26 -2
  18. package/dist/src/experimental.d.ts +33 -0
  19. package/dist/src/experimental.js +83 -0
  20. package/dist/src/generators/ast-generator.d.ts +2 -2
  21. package/dist/src/generators/ast-generator.js +1 -1
  22. package/dist/src/plugins/add/index.d.ts +2 -2
  23. package/dist/src/plugins/bundleCode/index.js +3 -12
  24. package/dist/src/plugins/curl/index.js +2 -2
  25. package/dist/src/plugins/curl/utils.d.ts +11 -1
  26. package/dist/src/plugins/curl/utils.js +14 -5
  27. package/dist/src/plugins/drainTriggerInbox/index.d.ts +46 -0
  28. package/dist/src/plugins/drainTriggerInbox/index.js +178 -0
  29. package/dist/src/plugins/generateAppTypes/index.d.ts +2 -2
  30. package/dist/src/plugins/index.d.ts +2 -0
  31. package/dist/src/plugins/index.js +2 -0
  32. package/dist/src/plugins/mcp/index.d.ts +1 -0
  33. package/dist/src/plugins/mcp/index.js +5 -1
  34. package/dist/src/plugins/watchTriggerInbox/index.d.ts +45 -0
  35. package/dist/src/plugins/watchTriggerInbox/index.js +157 -0
  36. package/dist/src/sdk.js +5 -1
  37. package/dist/src/utils/cli-generator.js +18 -1
  38. package/dist/src/utils/cli-renderer.d.ts +12 -0
  39. package/dist/src/utils/cli-renderer.js +22 -1
  40. package/dist/src/utils/parameter-resolver.d.ts +1 -0
  41. package/dist/src/utils/parameter-resolver.js +81 -10
  42. package/dist/src/utils/triggerDrain.d.ts +144 -0
  43. package/dist/src/utils/triggerDrain.js +351 -0
  44. package/dist/tsconfig.tsbuildinfo +1 -1
  45. package/package.json +16 -4
package/dist/cli.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command, CommanderError, Option } from 'commander';
3
3
  import { z } from 'zod';
4
- import { definePlugin, createPluginMethod, buildApplicationLifecycleEvent, OutputPropertySchema, DEFAULT_CONFIG_PATH, ZapierValidationError, ZapierUnknownError, injectCliLogin, BaseSdkOptionsSchema, isCredentialsObject, batch, toSnakeCase, createZapierSdk, ZapierError, isPositional, runWithTelemetryContext, buildCapabilityMessage, formatErrorMessage, getOsInfo, getPlatformVersions, getCiPlatform, isCi, getReleaseId, getCurrentTimestamp, generateEventId } from '@zapier/zapier-sdk';
4
+ import { definePlugin, createPluginMethod, buildApplicationLifecycleEvent, OutputPropertySchema, ZapierBundleError, DEFAULT_CONFIG_PATH, ZapierValidationError, ZapierUnknownError, ZapierReleaseTriggerMessageSignal, injectCliLogin, BaseSdkOptionsSchema, isCredentialsObject, batch, toSnakeCase, ZapierAbortDrainSignal, createZapierSdk as createZapierSdk$1, ZapierError, isPositional, runWithTelemetryContext, buildCapabilityMessage, formatErrorMessage, getOsInfo, getPlatformVersions, getCiPlatform, isCi, getReleaseId, getCurrentTimestamp, generateEventId } from '@zapier/zapier-sdk';
5
5
  import inquirer from 'inquirer';
6
6
  import chalk7 from 'chalk';
7
7
  import ora from 'ora';
@@ -24,9 +24,10 @@ import { buildSync } from 'esbuild';
24
24
  import { mkdir, writeFile, access } from 'fs/promises';
25
25
  import * as ts from 'typescript';
26
26
  import isInstalledGlobally from 'is-installed-globally';
27
- import { execSync } from 'child_process';
27
+ import { execSync, spawn } from 'child_process';
28
28
  import Handlebars from 'handlebars';
29
29
  import { fileURLToPath } from 'url';
30
+ import { injectCliLogin as injectCliLogin$1, createZapierSdk } from '@zapier/zapier-sdk/experimental';
30
31
  import packageJsonLib from 'package-json';
31
32
  import semver from 'semver';
32
33
 
@@ -82,7 +83,7 @@ function formatZodError(error) {
82
83
  }
83
84
  function getLocalResolutionOrder(paramName, resolvers, resolved = /* @__PURE__ */ new Set()) {
84
85
  const resolver = resolvers[paramName];
85
- if (!resolver || resolver.type === "static") {
86
+ if (!resolver || resolver.type === "static" || resolver.type === "constant") {
86
87
  return [paramName];
87
88
  }
88
89
  const order = [];
@@ -165,7 +166,11 @@ var SchemaParameterResolver = class {
165
166
  }
166
167
  return parseResult.data;
167
168
  }
168
- const resolvedParams = { ...providedParams };
169
+ const resolverConstants = this.getResolverConstants(sdk, functionName);
170
+ const resolvedParams = {
171
+ ...resolverConstants,
172
+ ...providedParams
173
+ };
169
174
  const context = {
170
175
  sdk,
171
176
  currentParams: providedParams,
@@ -326,12 +331,22 @@ var SchemaParameterResolver = class {
326
331
  const missingParams = [];
327
332
  for (const param of params) {
328
333
  const resolver = this.getResolver(param.name, context.sdk, functionName);
329
- const autoResolution = resolver?.type === "dynamic" ? await this.tryAutoResolve(resolver, context) : null;
330
- if (autoResolution != null) {
334
+ let autoResolved = null;
335
+ if (resolver?.type === "constant") {
336
+ autoResolved = {
337
+ resolvedValue: resolver.value
338
+ };
339
+ } else if (resolver?.type === "dynamic") {
340
+ autoResolved = await this.tryAutoResolve(
341
+ resolver,
342
+ context
343
+ );
344
+ }
345
+ if (autoResolved != null) {
331
346
  this.setNestedValue(
332
347
  resolvedParams,
333
348
  param.path,
334
- autoResolution.resolvedValue
349
+ autoResolved.resolvedValue
335
350
  );
336
351
  context.resolvedParams = resolvedParams;
337
352
  } else {
@@ -365,7 +380,11 @@ var SchemaParameterResolver = class {
365
380
  const promptLabel = inArrayContext ? `${param.name}[${arrayIndex}]` : param.name;
366
381
  const promptName = inArrayContext ? "value" : param.name;
367
382
  this.debugLog(`Resolving ${promptLabel}${isOptional ? " (optional)" : ""}`);
368
- if (resolver.type === "static") {
383
+ if (resolver.type === "constant") {
384
+ const constantResolver = resolver;
385
+ this.stopSpinner();
386
+ return constantResolver.value;
387
+ } else if (resolver.type === "static") {
369
388
  const staticResolver = resolver;
370
389
  const promptConfig = {
371
390
  type: staticResolver.inputType === "password" ? "password" : "input",
@@ -425,6 +444,7 @@ var SchemaParameterResolver = class {
425
444
  }
426
445
  const LOAD_MORE_SENTINEL = Symbol("LOAD_MORE");
427
446
  const SKIP_SENTINEL = Symbol("SKIP");
447
+ const CUSTOM_VALUE_SENTINEL = Symbol("CUSTOM_VALUE");
428
448
  let newItemsStartIndex = -1;
429
449
  this.stopSpinner();
430
450
  while (true) {
@@ -433,12 +453,27 @@ var SchemaParameterResolver = class {
433
453
  context.resolvedParams
434
454
  );
435
455
  promptConfig.name = promptName;
456
+ const hasSelectableChoice = promptConfig.choices?.some(
457
+ (c) => !c.disabled
458
+ );
459
+ if (!hasSelectableChoice && !hasMore) {
460
+ throw new ZapierCliValidationError(
461
+ `No ${promptLabel} available to select.`
462
+ );
463
+ }
436
464
  if (isOptional && promptConfig.choices) {
437
465
  promptConfig.choices.unshift({
438
466
  name: chalk7.dim("(Skip)"),
439
467
  value: SKIP_SENTINEL
440
468
  });
441
469
  }
470
+ if (promptConfig.choices && promptConfig.type === "list") {
471
+ const insertAt = isOptional ? 1 : 0;
472
+ promptConfig.choices.splice(insertAt, 0, {
473
+ name: chalk7.dim("(Enter custom value)"),
474
+ value: CUSTOM_VALUE_SENTINEL
475
+ });
476
+ }
442
477
  if (hasMore && pageIterator && promptConfig.choices) {
443
478
  promptConfig.choices.push({
444
479
  name: chalk7.dim("(Load more...)"),
@@ -461,7 +496,7 @@ var SchemaParameterResolver = class {
461
496
  }
462
497
  }
463
498
  if (newItemsStartIndex >= 0 && promptConfig.choices) {
464
- const injectedBefore = isOptional ? 1 : 0;
499
+ const injectedBefore = (isOptional ? 1 : 0) + (promptConfig.type === "list" ? 1 : 0);
465
500
  const adjustedIndex = newItemsStartIndex + injectedBefore;
466
501
  if (promptConfig.choices[adjustedIndex]) {
467
502
  promptConfig.default = promptConfig.choices[adjustedIndex].value;
@@ -473,6 +508,20 @@ var SchemaParameterResolver = class {
473
508
  if (selected === SKIP_SENTINEL) {
474
509
  return void 0;
475
510
  }
511
+ if (selected === CUSTOM_VALUE_SENTINEL) {
512
+ const customAnswer = await inquirer.prompt([
513
+ {
514
+ type: "input",
515
+ name: promptName,
516
+ message: `Enter ${promptLabel}${isOptional ? " (optional)" : ""}:`
517
+ }
518
+ ]);
519
+ const value = customAnswer[promptName];
520
+ if (isOptional && (value === void 0 || value === "")) {
521
+ return void 0;
522
+ }
523
+ return value;
524
+ }
476
525
  const wantsMore = Array.isArray(selected) ? selected.includes(LOAD_MORE_SENTINEL) : selected === LOAD_MORE_SENTINEL;
477
526
  if (wantsMore && pageIterator) {
478
527
  if (Array.isArray(selected)) {
@@ -803,7 +852,7 @@ Optional fields${pathContext}:`));
803
852
  cursor ? `Fetching more choices for ${fieldMeta.title}` : `Fetching choices for ${fieldMeta.title}`
804
853
  );
805
854
  this.startSpinner();
806
- const page = await context.sdk.listInputFieldChoices({
855
+ const page = await context.sdk.listActionInputFieldChoices({
807
856
  app: context.resolvedParams.app,
808
857
  action: context.resolvedParams.action,
809
858
  actionType: context.resolvedParams.actionType,
@@ -1040,6 +1089,23 @@ Optional fields${pathContext}:`));
1040
1089
  );
1041
1090
  return functionInfo?.resolvers || {};
1042
1091
  }
1092
+ getResolverConstants(sdk, functionName) {
1093
+ if (!functionName || typeof sdk.getRegistry !== "function") {
1094
+ return {};
1095
+ }
1096
+ const registry = sdk.getRegistry();
1097
+ const functionInfo = registry.functions.find(
1098
+ (f) => f.name === functionName
1099
+ );
1100
+ const resolvers = functionInfo?.resolvers ?? {};
1101
+ const constants = {};
1102
+ for (const [key, resolver] of Object.entries(resolvers)) {
1103
+ if (resolver && typeof resolver === "object" && resolver.type === "constant") {
1104
+ constants[key] = resolver.value;
1105
+ }
1106
+ }
1107
+ return constants;
1108
+ }
1043
1109
  };
1044
1110
 
1045
1111
  // src/utils/cli-options.ts
@@ -1072,7 +1138,7 @@ var SHARED_COMMAND_CLI_OPTIONS = [
1072
1138
 
1073
1139
  // package.json
1074
1140
  var package_default = {
1075
- version: "0.44.1"};
1141
+ version: "0.46.0"};
1076
1142
 
1077
1143
  // src/telemetry/builders.ts
1078
1144
  function createCliBaseEvent(context = {}) {
@@ -1283,8 +1349,18 @@ async function unwrapHttpResponse(response) {
1283
1349
  );
1284
1350
  }
1285
1351
  }
1352
+ function jsonReplacer(_key, value) {
1353
+ if (value instanceof Error) {
1354
+ return {
1355
+ name: value.name,
1356
+ message: value.message,
1357
+ ...value.stack ? { stack: value.stack } : {}
1358
+ };
1359
+ }
1360
+ return value;
1361
+ }
1286
1362
  function outputJson(envelope) {
1287
- console.log(JSON.stringify(envelope, null, 2));
1363
+ console.log(JSON.stringify(envelope, jsonReplacer, 2));
1288
1364
  }
1289
1365
  function createJsonRenderer() {
1290
1366
  return {
@@ -1685,6 +1761,10 @@ function analyzeZodField(name, schema, functionInfo) {
1685
1761
  break;
1686
1762
  }
1687
1763
  }
1764
+ const baseSchemaDef = baseSchema._zod?.def;
1765
+ if (baseSchema instanceof z.ZodFunction || baseSchemaDef?.type === "custom") {
1766
+ return null;
1767
+ }
1688
1768
  let paramType = "string";
1689
1769
  let elementType;
1690
1770
  let choices;
@@ -1879,7 +1959,8 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
1879
1959
  }
1880
1960
  }
1881
1961
  }
1882
- const description = functionInfo.description || schema?.description || `${cliCommandName} command`;
1962
+ const baseDescription = functionInfo.description || schema?.description || `${cliCommandName} command`;
1963
+ const description = functionInfo.experimental ? `${baseDescription} (experimental)` : baseDescription;
1883
1964
  const handler = async (...args) => {
1884
1965
  const startTime = Date.now();
1885
1966
  let success = true;
@@ -3115,7 +3196,8 @@ var mcpPlugin = definePlugin(
3115
3196
  await startMcpServer({
3116
3197
  ...options,
3117
3198
  debug: sdk2.context.options?.debug,
3118
- extensions: sdk2.context.extensions
3199
+ extensions: sdk2.context.extensions,
3200
+ experimental: sdk2.context.experimental
3119
3201
  });
3120
3202
  }
3121
3203
  })
@@ -3138,15 +3220,6 @@ var bundleCodePlugin = definePlugin(
3138
3220
  handler: async ({ options }) => bundleCode(options)
3139
3221
  })
3140
3222
  );
3141
- var ZapierBundleError = class extends Error {
3142
- constructor(message, details, originalError) {
3143
- super(message);
3144
- this.code = "ZAPIER_BUNDLE_ERROR";
3145
- this.name = "ZapierBundleError";
3146
- this.details = details;
3147
- this.originalError = originalError;
3148
- }
3149
- };
3150
3223
  async function bundleCode(options) {
3151
3224
  const {
3152
3225
  input,
@@ -3176,7 +3249,7 @@ async function bundleCode(options) {
3176
3249
  const errorMessages = result.errors.map((e) => e.text);
3177
3250
  throw new ZapierBundleError(
3178
3251
  `Bundle failed: ${errorMessages.join(", ")}`,
3179
- errorMessages
3252
+ { buildErrors: errorMessages }
3180
3253
  );
3181
3254
  }
3182
3255
  const bundledCode = result.outputFiles?.[0]?.text;
@@ -3198,8 +3271,7 @@ async function bundleCode(options) {
3198
3271
  }
3199
3272
  throw new ZapierBundleError(
3200
3273
  `Bundle failed: ${error instanceof Error ? error.message : "Unknown error"}`,
3201
- void 0,
3202
- error instanceof Error ? error : void 0
3274
+ { cause: error instanceof Error ? error : void 0 }
3203
3275
  );
3204
3276
  }
3205
3277
  }
@@ -3374,7 +3446,7 @@ var AstTypeGenerator = class {
3374
3446
  const actions = actionsResult.data;
3375
3447
  const actionsWithFields = [];
3376
3448
  const inputFieldsTasks = actions.map(
3377
- (action) => () => sdk.listInputFields({
3449
+ (action) => () => sdk.listActionInputFields({
3378
3450
  appKey: app.implementation_id,
3379
3451
  actionKey: action.key,
3380
3452
  actionType: action.action_type,
@@ -4251,11 +4323,12 @@ var CurlSchema = z.object({
4251
4323
  /** @deprecated Use `connection` instead. */
4252
4324
  connectionId: z.union([z.string(), z.number()]).optional().meta({ deprecated: true })
4253
4325
  }).describe("Make HTTP requests through Zapier Relay with curl-like options");
4254
- var CurlExitError = class extends Error {
4326
+ var ZapierCurlExitError = class extends ZapierError {
4255
4327
  constructor(message, exitCode) {
4256
4328
  super(message);
4329
+ this.name = "ZapierCurlExitError";
4330
+ this.code = "ZAPIER_CURL_EXIT_ERROR";
4257
4331
  this.exitCode = exitCode;
4258
- this.name = "CurlExitError";
4259
4332
  }
4260
4333
  };
4261
4334
  function parseHeaderLine(input) {
@@ -4347,7 +4420,7 @@ async function resolveDataArgBinary(raw) {
4347
4420
  }
4348
4421
  async function buildFormData(formArgs, formStringArgs) {
4349
4422
  if (typeof FormData === "undefined") {
4350
- throw new CurlExitError(
4423
+ throw new ZapierCurlExitError(
4351
4424
  "FormData is not available in this runtime; cannot use --form.",
4352
4425
  2
4353
4426
  );
@@ -4356,7 +4429,7 @@ async function buildFormData(formArgs, formStringArgs) {
4356
4429
  const addField = async (item, forceString) => {
4357
4430
  const idx = item.indexOf("=");
4358
4431
  if (idx === -1) {
4359
- throw new CurlExitError(
4432
+ throw new ZapierCurlExitError(
4360
4433
  `Invalid form field: '${item}'. Expected 'name=value' or 'name=@file'.`,
4361
4434
  2
4362
4435
  );
@@ -4364,7 +4437,7 @@ async function buildFormData(formArgs, formStringArgs) {
4364
4437
  const name = item.slice(0, idx);
4365
4438
  const value = item.slice(idx + 1);
4366
4439
  if (!name) {
4367
- throw new CurlExitError(
4440
+ throw new ZapierCurlExitError(
4368
4441
  `Invalid form field: '${item}'. Field name cannot be empty.`,
4369
4442
  2
4370
4443
  );
@@ -4601,7 +4674,7 @@ ${Array.from(
4601
4674
  `
4602
4675
  );
4603
4676
  }
4604
- throw new CurlExitError("HTTP request failed", 22);
4677
+ throw new ZapierCurlExitError("HTTP request failed", 22);
4605
4678
  }
4606
4679
  return void 0;
4607
4680
  }
@@ -5147,11 +5220,481 @@ var initPlugin = definePlugin(
5147
5220
  }
5148
5221
  })
5149
5222
  );
5223
+ var CliSkipLeaseExpireError = class extends Error {
5224
+ constructor() {
5225
+ super("user skipped (let lease expire)");
5226
+ this.name = "CliSkipLeaseExpireError";
5227
+ }
5228
+ };
5229
+ function createInteractiveCallback() {
5230
+ let messageNumber = 0;
5231
+ return async (message) => {
5232
+ messageNumber++;
5233
+ const attrs = message.message_attributes;
5234
+ console.log(
5235
+ `
5236
+ ${chalk7.bold(`Message #${messageNumber}`)} ${chalk7.dim(message.id)} ${chalk7.dim(`(lease #${attrs.lease_count})`)}`
5237
+ );
5238
+ if (attrs.error_message) {
5239
+ console.log(chalk7.yellow(` upstream error: ${attrs.error_message}`));
5240
+ }
5241
+ if (attrs.possible_duplicate_data) {
5242
+ console.log(chalk7.yellow(" possible duplicate data"));
5243
+ }
5244
+ while (true) {
5245
+ let action;
5246
+ try {
5247
+ const answer = await inquirer.prompt([
5248
+ {
5249
+ type: "list",
5250
+ name: "action",
5251
+ message: "Action?",
5252
+ choices: [
5253
+ { name: "Ack (remove from inbox)", value: "ack" },
5254
+ {
5255
+ name: "Skip (release after draining)",
5256
+ value: "skip-release"
5257
+ },
5258
+ { name: "Skip (let lease expire)", value: "skip-expire" },
5259
+ { name: "View payload", value: "view" },
5260
+ { name: "Quit", value: "quit" }
5261
+ ]
5262
+ }
5263
+ ]);
5264
+ action = answer.action;
5265
+ } catch (error) {
5266
+ if (error instanceof Error && error.name === "ExitPromptError") {
5267
+ throw new ZapierAbortDrainSignal("user pressed Ctrl-C");
5268
+ }
5269
+ throw error;
5270
+ }
5271
+ if (action === "view") {
5272
+ console.log(chalk7.dim(JSON.stringify(message.payload, null, 2)));
5273
+ continue;
5274
+ }
5275
+ if (action === "ack") {
5276
+ return;
5277
+ }
5278
+ if (action === "skip-release") {
5279
+ throw new ZapierReleaseTriggerMessageSignal("user skipped (release)");
5280
+ }
5281
+ if (action === "skip-expire") {
5282
+ throw new CliSkipLeaseExpireError();
5283
+ }
5284
+ if (action === "quit") {
5285
+ throw new ZapierAbortDrainSignal("user requested quit");
5286
+ }
5287
+ }
5288
+ };
5289
+ }
5290
+ function createNdjsonCallback() {
5291
+ return (message) => new Promise((resolve4, reject) => {
5292
+ process.stdout.write(JSON.stringify(message) + "\n", (err) => {
5293
+ if (err) reject(err);
5294
+ else resolve4();
5295
+ });
5296
+ });
5297
+ }
5298
+ function runSubprocess(options) {
5299
+ const { command, args, shell, label, message, signal } = options;
5300
+ return new Promise((resolve4, reject) => {
5301
+ const child = spawn(command, args, {
5302
+ shell,
5303
+ stdio: ["pipe", "inherit", "inherit"]
5304
+ });
5305
+ let abortListener;
5306
+ if (signal) {
5307
+ if (signal.aborted) {
5308
+ child.kill();
5309
+ } else {
5310
+ abortListener = () => {
5311
+ child.kill();
5312
+ };
5313
+ signal.addEventListener("abort", abortListener, { once: true });
5314
+ }
5315
+ }
5316
+ child.on("error", (err) => {
5317
+ if (signal && abortListener) {
5318
+ signal.removeEventListener("abort", abortListener);
5319
+ }
5320
+ reject(err);
5321
+ });
5322
+ child.on("close", (code) => {
5323
+ if (signal && abortListener) {
5324
+ signal.removeEventListener("abort", abortListener);
5325
+ }
5326
+ if (signal?.aborted) {
5327
+ reject(new ZapierAbortDrainSignal(`${label} aborted`));
5328
+ return;
5329
+ }
5330
+ if (code === 0) resolve4();
5331
+ else
5332
+ reject(
5333
+ new Error(
5334
+ `${label} exited with code ${code} for message ${message.id}`
5335
+ )
5336
+ );
5337
+ });
5338
+ child.stdin.on("error", (err) => {
5339
+ if (err.code !== "EPIPE") reject(err);
5340
+ });
5341
+ child.stdin.end(JSON.stringify(message) + "\n");
5342
+ });
5343
+ }
5344
+ function runShellCommand(command, message, signal) {
5345
+ return runSubprocess({
5346
+ command,
5347
+ args: [],
5348
+ shell: true,
5349
+ label: "exec-shell",
5350
+ message,
5351
+ signal
5352
+ });
5353
+ }
5354
+ function runExecCommand(argv, message, signal) {
5355
+ if (argv.length === 0) {
5356
+ return Promise.reject(
5357
+ new Error("exec requires at least one element (the binary)")
5358
+ );
5359
+ }
5360
+ const [command, ...args] = argv;
5361
+ return runSubprocess({
5362
+ command,
5363
+ args,
5364
+ shell: false,
5365
+ label: "exec",
5366
+ message,
5367
+ signal
5368
+ });
5369
+ }
5370
+ function describeReason(reason) {
5371
+ return reason instanceof Error ? reason.message : String(reason);
5372
+ }
5373
+ function printDrainError(reason, message) {
5374
+ console.error(
5375
+ chalk7.red(`Error processing ${message.id}: ${describeReason(reason)}`)
5376
+ );
5377
+ }
5378
+ function printDrainSummary(counts) {
5379
+ const skipped = counts.skipped ?? 0;
5380
+ const total = counts.fulfilled + counts.rejected + skipped;
5381
+ const parts = [`${counts.fulfilled} fulfilled`];
5382
+ if (skipped > 0) parts.push(`${skipped} skipped`);
5383
+ parts.push(`${counts.rejected} rejected`);
5384
+ console.log(
5385
+ chalk7.dim(
5386
+ `
5387
+ Processed ${total} message${total === 1 ? "" : "s"} (${parts.join(", ")}).`
5388
+ )
5389
+ );
5390
+ }
5391
+ function warnInteractiveContinueOnErrorOverride() {
5392
+ console.warn(
5393
+ chalk7.yellow(
5394
+ 'Note: continueOnError=false is overridden to true in interactive mode (the "Skip (let lease expire)" choice would otherwise terminate the drain).'
5395
+ )
5396
+ );
5397
+ }
5398
+ function requireInteractiveTty(commandName) {
5399
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
5400
+ throw new ZapierCliValidationError(
5401
+ `${commandName} needs an interactive terminal by default. Pass --exec '<bin>' (with optional \`-- args...\`) or --exec-shell '<cmd>' to run a script per message, or --json for non-interactive output.`
5402
+ );
5403
+ }
5404
+ }
5405
+ function rejectExecJsonMutex(opts) {
5406
+ const picked = [
5407
+ opts.exec ? "--exec" : null,
5408
+ opts.execShell ? "--exec-shell" : null,
5409
+ opts.json ? "--json" : null
5410
+ ].filter((x) => x !== null);
5411
+ if (picked.length > 1) {
5412
+ throw new ZapierCliValidationError(
5413
+ `${picked.join(", ")} are mutually exclusive. Pick one.`
5414
+ );
5415
+ }
5416
+ }
5417
+ function getPostDashArgs(argv = process.argv) {
5418
+ const idx = argv.indexOf("--");
5419
+ if (idx === -1) return [];
5420
+ return argv.slice(idx + 1);
5421
+ }
5422
+ function combineSignals(a, b) {
5423
+ if (!a) {
5424
+ return { signal: b, dispose: () => void 0 };
5425
+ }
5426
+ const controller = new AbortController();
5427
+ const onAbort = () => controller.abort();
5428
+ if (a.aborted || b.aborted) controller.abort();
5429
+ else {
5430
+ a.addEventListener("abort", onAbort, { once: true });
5431
+ b.addEventListener("abort", onAbort, { once: true });
5432
+ }
5433
+ return {
5434
+ signal: controller.signal,
5435
+ dispose: () => {
5436
+ a.removeEventListener("abort", onAbort);
5437
+ b.removeEventListener("abort", onAbort);
5438
+ }
5439
+ };
5440
+ }
5441
+
5442
+ // src/plugins/drainTriggerInbox/index.ts
5443
+ var JsonProperty = z.boolean().optional().describe(
5444
+ "Format the drained result as a JSON object on stdout: { data, errors }. Use for scripts or piping. Mutually exclusive with --exec / --exec-shell and the interactive default."
5445
+ );
5446
+ var ExecCliProperty = z.string().optional().describe(
5447
+ "Run a binary per message with no shell interpretation. Message JSON is piped to stdin; exit code 0 acks, non-zero records the error per the same rules as a thrown handler. Pass extra argv after `--` (e.g. `--exec ./handler -- --verbose`). Mutually exclusive with --exec-shell and --json."
5448
+ );
5449
+ var ExecShellCliProperty = z.string().optional().describe(
5450
+ "Run a shell command per message. Message JSON is piped to the subprocess on stdin; exit code 0 acks, non-zero records the error per the same rules as a thrown handler. Interpreted by the platform's default shell (sh on POSIX, cmd.exe on Windows). Mutually exclusive with --exec and --json."
5451
+ );
5452
+ var drainTriggerInboxCliPlugin = definePlugin(
5453
+ (sdk) => {
5454
+ const original = sdk.drainTriggerInbox;
5455
+ const existingMeta = sdk.context.meta.drainTriggerInbox;
5456
+ const baseInputSchema = existingMeta.inputSchema;
5457
+ const extendedInputSchema = baseInputSchema ? baseInputSchema.extend({
5458
+ exec: ExecCliProperty,
5459
+ execShell: ExecShellCliProperty,
5460
+ json: JsonProperty
5461
+ }) : z.object({
5462
+ exec: ExecCliProperty,
5463
+ execShell: ExecShellCliProperty,
5464
+ json: JsonProperty
5465
+ });
5466
+ return {
5467
+ drainTriggerInbox: async (options) => {
5468
+ const { json, exec, execShell, ...sdkArgs } = options;
5469
+ rejectExecJsonMutex({ exec, execShell, json });
5470
+ if (!exec && !execShell && !json) {
5471
+ requireInteractiveTty("drain-trigger-inbox");
5472
+ }
5473
+ const sigintController = new AbortController();
5474
+ const onSigint = () => sigintController.abort();
5475
+ process.on("SIGINT", onSigint);
5476
+ const combined = combineSignals(
5477
+ sdkArgs.signal,
5478
+ sigintController.signal
5479
+ );
5480
+ let fulfilled = 0;
5481
+ let rejected = 0;
5482
+ let skipped = 0;
5483
+ const liveOnError = (reason, message) => {
5484
+ rejected++;
5485
+ printDrainError(reason, message);
5486
+ };
5487
+ try {
5488
+ if (exec) {
5489
+ const execArgv = [exec, ...getPostDashArgs()];
5490
+ await original({
5491
+ ...sdkArgs,
5492
+ signal: combined.signal,
5493
+ onMessage: async (message) => {
5494
+ await runExecCommand(execArgv, message, combined.signal);
5495
+ fulfilled++;
5496
+ },
5497
+ onError: liveOnError
5498
+ });
5499
+ return;
5500
+ }
5501
+ if (execShell) {
5502
+ await original({
5503
+ ...sdkArgs,
5504
+ signal: combined.signal,
5505
+ onMessage: async (message) => {
5506
+ await runShellCommand(execShell, message, combined.signal);
5507
+ fulfilled++;
5508
+ },
5509
+ onError: liveOnError
5510
+ });
5511
+ return;
5512
+ }
5513
+ if (json) {
5514
+ const data = [];
5515
+ const errors = [];
5516
+ await original({
5517
+ ...sdkArgs,
5518
+ signal: combined.signal,
5519
+ continueOnError: true,
5520
+ onMessage: (message) => {
5521
+ data.push(message);
5522
+ },
5523
+ onError: (reason, message) => {
5524
+ errors.push({ reason, message });
5525
+ }
5526
+ });
5527
+ process.stdout.write(
5528
+ JSON.stringify({ data, errors }, jsonReplacer, 2) + "\n"
5529
+ );
5530
+ return;
5531
+ }
5532
+ if (sdkArgs.continueOnError === false) {
5533
+ warnInteractiveContinueOnErrorOverride();
5534
+ }
5535
+ const interactive = createInteractiveCallback();
5536
+ await original({
5537
+ ...sdkArgs,
5538
+ signal: combined.signal,
5539
+ concurrency: 1,
5540
+ continueOnError: true,
5541
+ onMessage: async (message) => {
5542
+ try {
5543
+ await interactive(message);
5544
+ fulfilled++;
5545
+ } catch (err) {
5546
+ if (err instanceof ZapierReleaseTriggerMessageSignal || err instanceof CliSkipLeaseExpireError) {
5547
+ skipped++;
5548
+ }
5549
+ throw err;
5550
+ }
5551
+ }
5552
+ });
5553
+ } finally {
5554
+ process.off("SIGINT", onSigint);
5555
+ combined.dispose();
5556
+ if (!json) {
5557
+ printDrainSummary({ fulfilled, rejected, skipped });
5558
+ }
5559
+ }
5560
+ },
5561
+ context: {
5562
+ meta: {
5563
+ drainTriggerInbox: {
5564
+ ...existingMeta,
5565
+ inputSchema: extendedInputSchema,
5566
+ packages: void 0
5567
+ }
5568
+ }
5569
+ }
5570
+ };
5571
+ }
5572
+ );
5573
+ var JsonProperty2 = z.boolean().optional().describe(
5574
+ "Stream each message as JSON to stdout (one record per line, NDJSON), acking as each write completes. Use for piping to other tools. Mutually exclusive with --exec / --exec-shell and the interactive default."
5575
+ );
5576
+ var ExecCliProperty2 = z.string().optional().describe(
5577
+ "Run a binary per message with no shell interpretation. Message JSON is piped to stdin; exit code 0 acks, non-zero records the error per the same rules as a thrown handler. Pass extra argv after `--` (e.g. `--exec ./handler -- --verbose`). Mutually exclusive with --exec-shell and --json."
5578
+ );
5579
+ var ExecShellCliProperty2 = z.string().optional().describe(
5580
+ "Run a shell command per message. Message JSON is piped to the subprocess on stdin; exit code 0 acks, non-zero records the error per the same rules as a thrown handler. Interpreted by the platform's default shell (sh on POSIX, cmd.exe on Windows). Mutually exclusive with --exec and --json."
5581
+ );
5582
+ var watchTriggerInboxCliPlugin = definePlugin(
5583
+ (sdk) => {
5584
+ const original = sdk.watchTriggerInbox;
5585
+ const existingMeta = sdk.context.meta.watchTriggerInbox;
5586
+ const baseInputSchema = existingMeta.inputSchema;
5587
+ const extendedInputSchema = baseInputSchema ? baseInputSchema.extend({
5588
+ exec: ExecCliProperty2,
5589
+ execShell: ExecShellCliProperty2,
5590
+ json: JsonProperty2
5591
+ }) : z.object({
5592
+ exec: ExecCliProperty2,
5593
+ execShell: ExecShellCliProperty2,
5594
+ json: JsonProperty2
5595
+ });
5596
+ return {
5597
+ watchTriggerInbox: async (options) => {
5598
+ const { json, exec, execShell, ...sdkArgs } = options;
5599
+ rejectExecJsonMutex({ exec, execShell, json });
5600
+ if (!exec && !execShell && !json) {
5601
+ requireInteractiveTty("watch-trigger-inbox");
5602
+ }
5603
+ const sigintController = new AbortController();
5604
+ const onSigint = () => sigintController.abort();
5605
+ process.on("SIGINT", onSigint);
5606
+ const combined = combineSignals(
5607
+ sdkArgs.signal,
5608
+ sigintController.signal
5609
+ );
5610
+ let fulfilled = 0;
5611
+ let rejected = 0;
5612
+ let skipped = 0;
5613
+ const liveOnError = (reason, message) => {
5614
+ rejected++;
5615
+ printDrainError(reason, message);
5616
+ };
5617
+ try {
5618
+ if (exec) {
5619
+ const execArgv = [exec, ...getPostDashArgs()];
5620
+ await original({
5621
+ ...sdkArgs,
5622
+ signal: combined.signal,
5623
+ onMessage: async (message) => {
5624
+ await runExecCommand(execArgv, message, combined.signal);
5625
+ fulfilled++;
5626
+ },
5627
+ onError: liveOnError
5628
+ });
5629
+ } else if (execShell) {
5630
+ await original({
5631
+ ...sdkArgs,
5632
+ signal: combined.signal,
5633
+ onMessage: async (message) => {
5634
+ await runShellCommand(execShell, message, combined.signal);
5635
+ fulfilled++;
5636
+ },
5637
+ onError: liveOnError
5638
+ });
5639
+ } else if (json) {
5640
+ const ndjson = createNdjsonCallback();
5641
+ await original({
5642
+ ...sdkArgs,
5643
+ signal: combined.signal,
5644
+ onMessage: async (message) => {
5645
+ await ndjson(message);
5646
+ fulfilled++;
5647
+ },
5648
+ onError: liveOnError
5649
+ });
5650
+ } else {
5651
+ if (sdkArgs.continueOnError === false) {
5652
+ warnInteractiveContinueOnErrorOverride();
5653
+ }
5654
+ const interactive = createInteractiveCallback();
5655
+ await original({
5656
+ ...sdkArgs,
5657
+ signal: combined.signal,
5658
+ concurrency: 1,
5659
+ continueOnError: true,
5660
+ onMessage: async (message) => {
5661
+ try {
5662
+ await interactive(message);
5663
+ fulfilled++;
5664
+ } catch (err) {
5665
+ if (err instanceof ZapierReleaseTriggerMessageSignal || err instanceof CliSkipLeaseExpireError) {
5666
+ skipped++;
5667
+ }
5668
+ throw err;
5669
+ }
5670
+ }
5671
+ });
5672
+ }
5673
+ } finally {
5674
+ process.off("SIGINT", onSigint);
5675
+ combined.dispose();
5676
+ if (!json) {
5677
+ printDrainSummary({ fulfilled, rejected, skipped });
5678
+ }
5679
+ }
5680
+ },
5681
+ context: {
5682
+ meta: {
5683
+ watchTriggerInbox: {
5684
+ ...existingMeta,
5685
+ inputSchema: extendedInputSchema,
5686
+ packages: void 0
5687
+ }
5688
+ }
5689
+ }
5690
+ };
5691
+ }
5692
+ );
5150
5693
 
5151
5694
  // package.json with { type: 'json' }
5152
5695
  var package_default2 = {
5153
5696
  name: "@zapier/zapier-sdk-cli",
5154
- version: "0.44.1"};
5697
+ version: "0.46.0"};
5155
5698
 
5156
5699
  // src/sdk.ts
5157
5700
  injectCliLogin(login_exports);
@@ -5160,7 +5703,7 @@ function createZapierCliSdk(options = {}) {
5160
5703
  const extensionsContextPlugin = () => ({
5161
5704
  context: { extensions }
5162
5705
  });
5163
- let chain = createZapierSdk({
5706
+ let chain = createZapierSdk$1({
5164
5707
  ...sdkOptions,
5165
5708
  eventEmission: { ...sdkOptions.eventEmission, callContext: "cli" },
5166
5709
  callerPackage: { name: package_default2.name, version: package_default2.version }
@@ -5176,6 +5719,31 @@ function createZapierCliSdk(options = {}) {
5176
5719
  }
5177
5720
  return chain;
5178
5721
  }
5722
+ injectCliLogin$1(login_exports);
5723
+ function createZapierCliSdk2(options = {}) {
5724
+ const { extensions = [], ...sdkOptions } = options;
5725
+ const extensionsContextPlugin = () => ({
5726
+ context: { extensions }
5727
+ });
5728
+ const experimentalContextPlugin = () => ({
5729
+ context: { experimental: true }
5730
+ });
5731
+ let chain = createZapierSdk({
5732
+ ...sdkOptions,
5733
+ eventEmission: { ...sdkOptions.eventEmission, callContext: "cli" },
5734
+ callerPackage: { name: package_default2.name, version: package_default2.version }
5735
+ }).addPlugin(extensionsContextPlugin).addPlugin(experimentalContextPlugin).addPlugin(generateAppTypesPlugin).addPlugin(buildManifestPlugin).addPlugin(bundleCodePlugin).addPlugin(getLoginConfigPathPlugin).addPlugin(addPlugin).addPlugin(feedbackPlugin).addPlugin(curlPlugin).addPlugin(initPlugin).addPlugin(drainTriggerInboxCliPlugin, { override: true }).addPlugin(watchTriggerInboxCliPlugin, { override: true }).addPlugin(mcpPlugin).addPlugin(loginPlugin).addPlugin(logoutPlugin).addPlugin(cliOverridesPlugin);
5736
+ for (const ext of extensions) {
5737
+ try {
5738
+ chain = chain.addPlugin(ext);
5739
+ } catch (err) {
5740
+ console.warn(
5741
+ `Extension plugin failed to construct: ${err.message}; skipping.`
5742
+ );
5743
+ }
5744
+ }
5745
+ return chain;
5746
+ }
5179
5747
 
5180
5748
  // src/utils/extensions.ts
5181
5749
  var ENV_VAR = "ZAPIER_SDK_EXTENSIONS";
@@ -5388,7 +5956,7 @@ program.name("zapier-sdk").description("CLI for Zapier SDK").version(
5388
5956
  ).option(
5389
5957
  "--max-network-retry-delay-ms <ms>",
5390
5958
  "Max delay in ms to wait for rate limit retry (default: 60000)"
5391
- );
5959
+ ).option("--experimental", "Use the experimental SDK / CLI surface");
5392
5960
  var booleanFlags = [];
5393
5961
  for (const [key, fieldSchema] of Object.entries(
5394
5962
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -5453,11 +6021,13 @@ for (const { camelName, kebabFlag } of booleanFlags) {
5453
6021
  flagOverrides[camelName] = true;
5454
6022
  }
5455
6023
  }
6024
+ var useExperimental = process.argv.includes("--experimental") || process.env.ZAPIER_EXPERIMENTAL === "1" || process.env.ZAPIER_EXPERIMENTAL === "true";
6025
+ var createZapierCliSdk3 = useExperimental ? createZapierCliSdk2 : createZapierCliSdk;
5456
6026
  program.exitOverride();
5457
6027
  (async () => {
5458
6028
  let exitCode = 0;
5459
6029
  const extensions = await resolveExtensions();
5460
- const sdk = createZapierCliSdk({
6030
+ const sdk = createZapierCliSdk3({
5461
6031
  debug: isDebugMode,
5462
6032
  credentials,
5463
6033
  baseUrl,