@zapier/zapier-sdk-cli 0.52.5 → 0.52.7

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/dist/index.mjs CHANGED
@@ -374,12 +374,6 @@ async function storeClientCredentials({
374
374
  await deleteKeychainSecret(existingEntry);
375
375
  }
376
376
  }
377
- function credentialsNameExists({
378
- name,
379
- baseUrl
380
- }) {
381
- return !!findEntry(readRegistry(), name, normalizeBaseUrl(baseUrl));
382
- }
383
377
  async function getStoredClientCredentials(options) {
384
378
  const entry = options?.name ? findEntry(readRegistry(), options.name, normalizeBaseUrl(options.baseUrl)) : getActiveCredentials(options);
385
379
  if (!entry) return void 0;
@@ -815,8 +809,11 @@ function emitAuthLogout(onEvent) {
815
809
  timestamp: Date.now()
816
810
  });
817
811
  }
818
- function isNotFoundError(err) {
819
- return typeof err === "object" && err !== null && "statusCode" in err && err.statusCode === 404;
812
+ function getStatusCode(err) {
813
+ if (typeof err === "object" && err !== null && "statusCode" in err) {
814
+ return err.statusCode;
815
+ }
816
+ return void 0;
820
817
  }
821
818
  async function revokeCredentials({
822
819
  api: api2,
@@ -832,7 +829,14 @@ async function revokeCredentials({
832
829
  { authRequired: true, requiredScopes: ["credentials"] }
833
830
  );
834
831
  } catch (err) {
835
- if (isNotFoundError(err)) return;
832
+ const status = getStatusCode(err);
833
+ if (status === 404) return;
834
+ if (status === 401) {
835
+ console.warn(
836
+ "Could not revoke credentials on the server (unauthorized). Local state will be cleared, but the credential may still be active. Verify or revoke via `list-client-credentials` or `delete-client-credentials`."
837
+ );
838
+ return;
839
+ }
836
840
  throw err;
837
841
  }
838
842
  }
@@ -1220,14 +1224,24 @@ async function resolveCredentialsBaseUrl(context) {
1220
1224
  const resolvedCredentials = "resolvedCredentials" in context ? context.resolvedCredentials : await context.resolveCredentials?.();
1221
1225
  return getBaseUrlFromResolvedCredentials(resolvedCredentials) ?? getBaseUrlFromOptionsCredentials(context.options?.credentials) ?? context.options?.baseUrl;
1222
1226
  }
1227
+
1228
+ // src/utils/non-interactive.ts
1229
+ function resolveNonInteractive(options) {
1230
+ return (options.nonInteractive ?? options.skipPrompts) === true || !process.stdin.isTTY || !process.stdout.isTTY;
1231
+ }
1223
1232
  var LoginSchema = z.object({
1224
1233
  timeout: z.string().optional().describe("Login timeout in seconds (default: 300)"),
1225
1234
  useApprovals: z.boolean().optional().describe(
1226
1235
  "Require approvals for actions performed with these credentials"
1227
1236
  ),
1228
- skipPrompts: z.boolean().optional().describe(
1237
+ nonInteractive: z.boolean().optional().describe(
1229
1238
  "Skip interactive prompts. Uses defaults where possible; errors instead of prompting when input is required. Useful in CI, piped output, or environments where TTY detection is unreliable."
1230
- )
1239
+ ),
1240
+ /** @deprecated Use `nonInteractive` instead. */
1241
+ skipPrompts: z.boolean().optional().meta({
1242
+ deprecated: true,
1243
+ deprecationMessage: "Use --non-interactive instead."
1244
+ })
1231
1245
  }).describe("Log in to Zapier to access your account");
1232
1246
 
1233
1247
  // src/plugins/login/index.ts
@@ -1242,8 +1256,8 @@ function toPkceCredentials(credentials) {
1242
1256
  }
1243
1257
  return void 0;
1244
1258
  }
1245
- async function confirmRevokeAndRelogin(activeCredentials, skipPrompts) {
1246
- if (skipPrompts) {
1259
+ async function confirmRevokeAndRelogin(activeCredentials, nonInteractive) {
1260
+ if (nonInteractive) {
1247
1261
  throw new ZapierCliValidationError(
1248
1262
  `Already logged in as "${activeCredentials.name}". Run \`logout\` first or use an interactive terminal to re-authenticate.`
1249
1263
  );
@@ -1264,8 +1278,8 @@ Log out and log in again?`,
1264
1278
  }
1265
1279
  return true;
1266
1280
  }
1267
- async function confirmJwtMigration(skipPrompts) {
1268
- if (skipPrompts) {
1281
+ async function confirmJwtMigration(nonInteractive) {
1282
+ if (nonInteractive) {
1269
1283
  throw new ZapierCliValidationError(
1270
1284
  "Legacy JWT login detected. Run `logout` first or use an interactive terminal to migrate to client credentials."
1271
1285
  );
@@ -1284,8 +1298,8 @@ async function confirmJwtMigration(skipPrompts) {
1284
1298
  }
1285
1299
  return true;
1286
1300
  }
1287
- async function confirmLocalLoginReset(skipPrompts) {
1288
- if (skipPrompts) {
1301
+ async function confirmLocalLoginReset(nonInteractive) {
1302
+ if (nonInteractive) {
1289
1303
  throw new ZapierCliValidationError(
1290
1304
  "Login cleanup failed and cannot be reset without confirmation. Re-run with an interactive terminal."
1291
1305
  );
@@ -1311,14 +1325,9 @@ function parseTimeoutSeconds(timeout) {
1311
1325
  }
1312
1326
  return timeoutSeconds;
1313
1327
  }
1314
- async function promptCredentialsName(email, skipPrompts, baseUrl) {
1328
+ async function promptCredentialsName(email, nonInteractive) {
1315
1329
  const fallback = `${email}@${hostname()}`;
1316
- if (skipPrompts) {
1317
- if (credentialsNameExists({ name: fallback, baseUrl })) {
1318
- throw new ZapierCliValidationError(
1319
- `Credentials named "${fallback}" already exist. Run \`logout\` first or use an interactive terminal to choose a different name.`
1320
- );
1321
- }
1330
+ if (nonInteractive) {
1322
1331
  return fallback;
1323
1332
  }
1324
1333
  const { credentialName } = await inquirer.prompt([
@@ -1329,9 +1338,6 @@ async function promptCredentialsName(email, skipPrompts, baseUrl) {
1329
1338
  default: fallback,
1330
1339
  validate: (input) => {
1331
1340
  if (!input.trim()) return "Name cannot be empty";
1332
- if (credentialsNameExists({ name: input.trim(), baseUrl })) {
1333
- return `Credentials named "${input.trim()}" already exist. Please provide a different name.`;
1334
- }
1335
1341
  return true;
1336
1342
  }
1337
1343
  }
@@ -1375,7 +1381,7 @@ var loginPlugin = definePlugin(
1375
1381
  supportsJsonOutput: false,
1376
1382
  handler: async ({ sdk: sdk2, options }) => {
1377
1383
  const timeoutSeconds = parseTimeoutSeconds(options.timeout);
1378
- const skipPrompts = options.skipPrompts === true || !process.stdin.isTTY || !process.stdout.isTTY;
1384
+ const nonInteractive = resolveNonInteractive(options);
1379
1385
  const resolvedCredentials = await sdk2.context.resolveCredentials();
1380
1386
  const pkceCredentials = toPkceCredentials(resolvedCredentials);
1381
1387
  const credentialsBaseUrl = await resolveCredentialsBaseUrl({
@@ -1386,7 +1392,7 @@ var loginPlugin = definePlugin(
1386
1392
  baseUrl: credentialsBaseUrl
1387
1393
  });
1388
1394
  if (activeCredentials) {
1389
- if (!await confirmRevokeAndRelogin(activeCredentials, skipPrompts))
1395
+ if (!await confirmRevokeAndRelogin(activeCredentials, nonInteractive))
1390
1396
  return;
1391
1397
  try {
1392
1398
  await revokeCredentials({
@@ -1394,14 +1400,14 @@ var loginPlugin = definePlugin(
1394
1400
  credentials: activeCredentials
1395
1401
  });
1396
1402
  } catch {
1397
- if (!await confirmLocalLoginReset(skipPrompts)) return;
1403
+ if (!await confirmLocalLoginReset(nonInteractive)) return;
1398
1404
  await deleteStoredClientCredentials({
1399
1405
  name: activeCredentials.name,
1400
1406
  baseUrl: activeCredentials.baseUrl
1401
1407
  });
1402
1408
  }
1403
1409
  } else if (hasLegacyJwtConfig()) {
1404
- if (!await confirmJwtMigration(skipPrompts)) return;
1410
+ if (!await confirmJwtMigration(nonInteractive)) return;
1405
1411
  }
1406
1412
  const { accessToken } = await runOauthFlow({
1407
1413
  timeoutMs: timeoutSeconds * 1e3,
@@ -1419,8 +1425,7 @@ var loginPlugin = definePlugin(
1419
1425
  );
1420
1426
  const credentialName = await promptCredentialsName(
1421
1427
  profile.email,
1422
- skipPrompts,
1423
- credentialsBaseUrl
1428
+ nonInteractive
1424
1429
  );
1425
1430
  const useApprovals = options.useApprovals === true;
1426
1431
  await setupClientCredentials({
@@ -1460,20 +1465,6 @@ var logoutPlugin = definePlugin(
1460
1465
  console.log("\u2705 Successfully logged out");
1461
1466
  return;
1462
1467
  }
1463
- const { confirmed } = await inquirer.prompt([
1464
- {
1465
- type: "confirm",
1466
- name: "confirmed",
1467
- message: `Logging out will delete credentials "${activeCredentials.name}".
1468
- This may interrupt other Zapier SDK or CLI sessions using them.
1469
- Do you want to continue?`,
1470
- default: true
1471
- }
1472
- ]);
1473
- if (!confirmed) {
1474
- console.log("Logout cancelled.");
1475
- return;
1476
- }
1477
1468
  await revokeCredentials({
1478
1469
  api: sdk2.context.api,
1479
1470
  credentials: activeCredentials,
@@ -3033,7 +3024,12 @@ var cliOverridesPlugin = definePlugin(
3033
3024
  var TEMPLATES = ["basic"];
3034
3025
  var InitSchema = z.object({
3035
3026
  projectName: z.string().min(1).describe("Name of the project directory to create"),
3036
- skipPrompts: z.boolean().optional().describe("Skip all interactive prompts and accept all defaults")
3027
+ nonInteractive: z.boolean().optional().describe("Skip all interactive prompts and accept all defaults"),
3028
+ /** @deprecated Use `nonInteractive` instead. */
3029
+ skipPrompts: z.boolean().optional().meta({
3030
+ deprecated: true,
3031
+ deprecationMessage: "Use --non-interactive instead."
3032
+ })
3037
3033
  }).describe(
3038
3034
  "Create a new Zapier SDK project in a new directory with starter files"
3039
3035
  );
@@ -3101,9 +3097,9 @@ function createExec({ cwd }) {
3101
3097
  async function promptYesNo({
3102
3098
  message,
3103
3099
  defaultValue,
3104
- skipPrompts
3100
+ nonInteractive
3105
3101
  }) {
3106
- if (skipPrompts) return defaultValue;
3102
+ if (nonInteractive) return defaultValue;
3107
3103
  const { answer } = await inquirer.prompt([
3108
3104
  { type: "confirm", name: "answer", message, default: defaultValue }
3109
3105
  ]);
@@ -3251,14 +3247,14 @@ async function runStep({
3251
3247
  step,
3252
3248
  stepNumber,
3253
3249
  totalSteps,
3254
- skipPrompts,
3250
+ nonInteractive,
3255
3251
  displayHooks
3256
3252
  }) {
3257
3253
  if (step.askConfirmation) {
3258
3254
  const should = await promptYesNo({
3259
3255
  message: step.description,
3260
3256
  defaultValue: true,
3261
- skipPrompts
3257
+ nonInteractive
3262
3258
  });
3263
3259
  if (!should) return false;
3264
3260
  }
@@ -3267,7 +3263,7 @@ async function runStep({
3267
3263
  stepNumber,
3268
3264
  totalSteps,
3269
3265
  command: step.command,
3270
- skipPrompts
3266
+ nonInteractive
3271
3267
  });
3272
3268
  try {
3273
3269
  await step.run();
@@ -3368,11 +3364,11 @@ function createConsoleDisplayHooks() {
3368
3364
  stepNumber,
3369
3365
  totalSteps,
3370
3366
  command,
3371
- skipPrompts
3367
+ nonInteractive
3372
3368
  }) => {
3373
3369
  const progressMessage = `${description}...`;
3374
3370
  const stepCounter = chalk3.dim(`${stepNumber}/${totalSteps}`);
3375
- if (skipPrompts) {
3371
+ if (nonInteractive) {
3376
3372
  console.log(
3377
3373
  "\n" + chalk3.bold(`\u276F ${progressMessage}`) + " " + stepCounter + "\n"
3378
3374
  );
@@ -3448,7 +3444,8 @@ var initPlugin = definePlugin(
3448
3444
  inputSchema: InitSchema,
3449
3445
  supportsJsonOutput: false,
3450
3446
  handler: async ({ options }) => {
3451
- const { projectName: rawName, skipPrompts = false } = options;
3447
+ const { projectName: rawName } = options;
3448
+ const nonInteractive = resolveNonInteractive(options);
3452
3449
  const cwd = process.cwd();
3453
3450
  const { projectName, projectDir } = validateInitOptions({ rawName, cwd });
3454
3451
  const displayHooks = createConsoleDisplayHooks();
@@ -3474,7 +3471,7 @@ var initPlugin = definePlugin(
3474
3471
  step,
3475
3472
  stepNumber: i + 1,
3476
3473
  totalSteps: steps.length,
3477
- skipPrompts,
3474
+ nonInteractive,
3478
3475
  displayHooks
3479
3476
  })
3480
3477
  );
@@ -3979,7 +3976,7 @@ definePlugin(
3979
3976
  // package.json with { type: 'json' }
3980
3977
  var package_default = {
3981
3978
  name: "@zapier/zapier-sdk-cli",
3982
- version: "0.52.5"};
3979
+ version: "0.52.7"};
3983
3980
 
3984
3981
  // src/sdk.ts
3985
3982
  injectCliLogin(login_exports);
@@ -4007,7 +4004,7 @@ function createZapierCliSdk(options = {}) {
4007
4004
 
4008
4005
  // package.json
4009
4006
  var package_default2 = {
4010
- version: "0.52.5"};
4007
+ version: "0.52.7"};
4011
4008
 
4012
4009
  // src/telemetry/builders.ts
4013
4010
  function createCliBaseEvent(context = {}) {
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zapier/zapier-sdk-cli",
3
- "version": "0.52.5",
3
+ "version": "0.52.7",
4
4
  "description": "Command line interface for Zapier SDK",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
@@ -9,11 +9,11 @@ export function emitAuthLogout(onEvent) {
9
9
  timestamp: Date.now(),
10
10
  });
11
11
  }
12
- function isNotFoundError(err) {
13
- return (typeof err === "object" &&
14
- err !== null &&
15
- "statusCode" in err &&
16
- err.statusCode === 404);
12
+ function getStatusCode(err) {
13
+ if (typeof err === "object" && err !== null && "statusCode" in err) {
14
+ return err.statusCode;
15
+ }
16
+ return undefined;
17
17
  }
18
18
  // Re-login flows pass no emitter so credential rotation stays silent.
19
19
  export async function revokeCredentials({ api, credentials, onEvent, }) {
@@ -23,8 +23,15 @@ export async function revokeCredentials({ api, credentials, onEvent, }) {
23
23
  await api.delete(`/api/v0/client-credentials/${credentials.clientId}`, undefined, { authRequired: true, requiredScopes: ["credentials"] });
24
24
  }
25
25
  catch (err) {
26
- if (isNotFoundError(err))
26
+ const status = getStatusCode(err);
27
+ if (status === 404)
28
+ return;
29
+ if (status === 401) {
30
+ console.warn("Could not revoke credentials on the server (unauthorized). " +
31
+ "Local state will be cleared, but the credential may still be active. " +
32
+ "Verify or revoke via `list-client-credentials` or `delete-client-credentials`.");
27
33
  return;
34
+ }
28
35
  throw err;
29
36
  }
30
37
  },
@@ -18,10 +18,6 @@ export declare function storeClientCredentials({ name, clientId, clientSecret, s
18
18
  scopes: string[];
19
19
  baseUrl?: string;
20
20
  }): Promise<void>;
21
- export declare function credentialsNameExists({ name, baseUrl, }: {
22
- name: string;
23
- baseUrl?: string;
24
- }): boolean;
25
21
  export declare function getStoredClientCredentials(options?: {
26
22
  name?: string;
27
23
  baseUrl?: string;
@@ -81,9 +81,6 @@ export async function storeClientCredentials({ name, clientId, clientSecret, sco
81
81
  await deleteKeychainSecret(existingEntry);
82
82
  }
83
83
  }
84
- export function credentialsNameExists({ name, baseUrl, }) {
85
- return !!findEntry(readRegistry(), name, normalizeBaseUrl(baseUrl));
86
- }
87
84
  export async function getStoredClientCredentials(options) {
88
85
  const entry = options?.name
89
86
  ? findEntry(readRegistry(), options.name, normalizeBaseUrl(options.baseUrl))
@@ -5,10 +5,10 @@ export function createConsoleDisplayHooks() {
5
5
  return {
6
6
  onItemComplete: (message) => console.log(" " + chalk.green("✓") + " " + chalk.dim(message)),
7
7
  onWarn: (message) => console.warn(chalk.yellow("!") + " " + message),
8
- onStepStart: ({ description, stepNumber, totalSteps, command, skipPrompts, }) => {
8
+ onStepStart: ({ description, stepNumber, totalSteps, command, nonInteractive, }) => {
9
9
  const progressMessage = `${description}...`;
10
10
  const stepCounter = chalk.dim(`${stepNumber}/${totalSteps}`);
11
- if (skipPrompts) {
11
+ if (nonInteractive) {
12
12
  console.log("\n" +
13
13
  chalk.bold(`❯ ${progressMessage}`) +
14
14
  " " +
@@ -8,6 +8,7 @@ export declare const initPlugin: (sdk: {
8
8
  }) => {
9
9
  init: (options?: {
10
10
  projectName: string;
11
+ nonInteractive?: boolean | undefined;
11
12
  skipPrompts?: boolean | undefined;
12
13
  } | undefined) => Promise<void>;
13
14
  } & {
@@ -5,6 +5,7 @@ import { validateInitOptions, withInterruptCleanup } from "./utils";
5
5
  import { getInitSteps, runStep } from "./steps";
6
6
  import { createConsoleDisplayHooks, displaySummaryAndNextSteps, } from "./display";
7
7
  import { ZapierCliExitError } from "../../utils/errors";
8
+ import { resolveNonInteractive } from "../../utils/non-interactive";
8
9
  export { toProjectName } from "./utils";
9
10
  export const initPlugin = definePlugin((sdk) => createPluginMethod(sdk, {
10
11
  name: "init",
@@ -12,7 +13,8 @@ export const initPlugin = definePlugin((sdk) => createPluginMethod(sdk, {
12
13
  inputSchema: InitSchema,
13
14
  supportsJsonOutput: false,
14
15
  handler: async ({ options }) => {
15
- const { projectName: rawName, skipPrompts = false } = options;
16
+ const { projectName: rawName } = options;
17
+ const nonInteractive = resolveNonInteractive(options);
16
18
  const cwd = process.cwd();
17
19
  const { projectName, projectDir } = validateInitOptions({ rawName, cwd });
18
20
  const displayHooks = createConsoleDisplayHooks();
@@ -34,7 +36,7 @@ export const initPlugin = definePlugin((sdk) => createPluginMethod(sdk, {
34
36
  step,
35
37
  stepNumber: i + 1,
36
38
  totalSteps: steps.length,
37
- skipPrompts,
39
+ nonInteractive,
38
40
  displayHooks,
39
41
  }));
40
42
  if (!succeeded)
@@ -3,6 +3,7 @@ export declare const TEMPLATES: readonly ["basic"];
3
3
  export type TemplateName = (typeof TEMPLATES)[number];
4
4
  export declare const InitSchema: z.ZodObject<{
5
5
  projectName: z.ZodString;
6
+ nonInteractive: z.ZodOptional<z.ZodBoolean>;
6
7
  skipPrompts: z.ZodOptional<z.ZodBoolean>;
7
8
  }, z.core.$strip>;
8
9
  export type InitOptions = z.infer<typeof InitSchema>;
@@ -6,9 +6,14 @@ export const InitSchema = z
6
6
  .string()
7
7
  .min(1)
8
8
  .describe("Name of the project directory to create"),
9
- skipPrompts: z
9
+ nonInteractive: z
10
10
  .boolean()
11
11
  .optional()
12
12
  .describe("Skip all interactive prompts and accept all defaults"),
13
+ /** @deprecated Use `nonInteractive` instead. */
14
+ skipPrompts: z.boolean().optional().meta({
15
+ deprecated: true,
16
+ deprecationMessage: "Use --non-interactive instead.",
17
+ }),
13
18
  })
14
19
  .describe("Create a new Zapier SDK project in a new directory with starter files");
@@ -18,11 +18,11 @@ export declare function scaffoldProject({ projectDir, projectName, packageManage
18
18
  template?: TemplateName;
19
19
  displayHooks?: DisplayHooks;
20
20
  }): void;
21
- export declare function runStep({ step, stepNumber, totalSteps, skipPrompts, displayHooks, }: {
21
+ export declare function runStep({ step, stepNumber, totalSteps, nonInteractive, displayHooks, }: {
22
22
  step: RunnableSetupStep;
23
23
  stepNumber: number;
24
24
  totalSteps: number;
25
- skipPrompts: boolean;
25
+ nonInteractive: boolean;
26
26
  displayHooks?: DisplayHooks;
27
27
  }): Promise<boolean>;
28
28
  export declare function getInitSteps({ projectDir, projectName, packageManager, template, displayHooks, }: {
@@ -42,12 +42,12 @@ export function scaffoldProject({ projectDir, projectName, packageManager, templ
42
42
  createProjectDir({ projectDir, projectName });
43
43
  scaffoldFiles({ projectDir, templatesDir, variables, displayHooks });
44
44
  }
45
- export async function runStep({ step, stepNumber, totalSteps, skipPrompts, displayHooks, }) {
45
+ export async function runStep({ step, stepNumber, totalSteps, nonInteractive, displayHooks, }) {
46
46
  if (step.askConfirmation) {
47
47
  const should = await promptYesNo({
48
48
  message: step.description,
49
49
  defaultValue: true,
50
- skipPrompts,
50
+ nonInteractive,
51
51
  });
52
52
  if (!should)
53
53
  return false;
@@ -57,7 +57,7 @@ export async function runStep({ step, stepNumber, totalSteps, skipPrompts, displ
57
57
  stepNumber,
58
58
  totalSteps,
59
59
  command: step.command,
60
- skipPrompts,
60
+ nonInteractive,
61
61
  });
62
62
  try {
63
63
  await step.run();
@@ -6,7 +6,7 @@ export interface DisplayHooks {
6
6
  stepNumber: number;
7
7
  totalSteps: number;
8
8
  command?: string;
9
- skipPrompts: boolean;
9
+ nonInteractive: boolean;
10
10
  }) => void;
11
11
  onStepSuccess: (params: {
12
12
  stepNumber: number;
@@ -12,10 +12,10 @@ export declare function validateInitOptions({ rawName, cwd, }: {
12
12
  export declare function createExec({ cwd }: {
13
13
  cwd: string;
14
14
  }): (cmd: string) => void;
15
- export declare function promptYesNo({ message, defaultValue, skipPrompts, }: {
15
+ export declare function promptYesNo({ message, defaultValue, nonInteractive, }: {
16
16
  message: string;
17
17
  defaultValue: boolean;
18
- skipPrompts: boolean;
18
+ nonInteractive: boolean;
19
19
  }): Promise<boolean>;
20
20
  export declare function getPackageManagerCommands({ packageManager, }: {
21
21
  packageManager: PackageManager;
@@ -45,8 +45,8 @@ export function createExec({ cwd }) {
45
45
  shell: process.platform === "win32" ? "cmd.exe" : "/bin/sh",
46
46
  });
47
47
  }
48
- export async function promptYesNo({ message, defaultValue, skipPrompts, }) {
49
- if (skipPrompts)
48
+ export async function promptYesNo({ message, defaultValue, nonInteractive, }) {
49
+ if (nonInteractive)
50
50
  return defaultValue;
51
51
  const { answer } = await inquirer.prompt([
52
52
  { type: "confirm", name: "answer", message, default: defaultValue },
@@ -23,6 +23,7 @@ export declare const loginPlugin: (sdk: {
23
23
  login: (options?: {
24
24
  timeout?: string | undefined;
25
25
  useApprovals?: boolean | undefined;
26
+ nonInteractive?: boolean | undefined;
26
27
  skipPrompts?: boolean | undefined;
27
28
  } | undefined) => Promise<void>;
28
29
  } & {
@@ -2,12 +2,13 @@ import { hostname } from "os";
2
2
  import { createPluginMethod, definePlugin, getOrCreateApiClient, isCredentialsObject, buildApplicationLifecycleEvent, } from "@zapier/zapier-sdk";
3
3
  import inquirer from "inquirer";
4
4
  import { clearLegacyJwtState, hasLegacyJwtConfig, } from "../../login/legacy-jwt";
5
- import { getActiveCredentials, credentialsNameExists, deleteStoredClientCredentials, } from "../../login/credentials-store";
5
+ import { getActiveCredentials, deleteStoredClientCredentials, } from "../../login/credentials-store";
6
6
  import { revokeCredentials } from "../../login/credentials-revoke";
7
7
  import { runOauthFlow } from "../../utils/auth/oauth-flow";
8
8
  import { EMPTY_POLICY, setupClientCredentials, } from "../../utils/auth/client-credentials";
9
9
  import { resolveCredentialsBaseUrl } from "../auth/credentials-base-url";
10
10
  import { ZapierCliValidationError } from "../../utils/errors";
11
+ import { resolveNonInteractive } from "../../utils/non-interactive";
11
12
  import { LoginSchema } from "./schemas";
12
13
  function toPkceCredentials(credentials) {
13
14
  if (credentials &&
@@ -22,8 +23,8 @@ function toPkceCredentials(credentials) {
22
23
  }
23
24
  return undefined;
24
25
  }
25
- async function confirmRevokeAndRelogin(activeCredentials, skipPrompts) {
26
- if (skipPrompts) {
26
+ async function confirmRevokeAndRelogin(activeCredentials, nonInteractive) {
27
+ if (nonInteractive) {
27
28
  throw new ZapierCliValidationError(`Already logged in as "${activeCredentials.name}". Run \`logout\` first or use an interactive terminal to re-authenticate.`);
28
29
  }
29
30
  const { confirmed } = await inquirer.prompt([
@@ -42,8 +43,8 @@ async function confirmRevokeAndRelogin(activeCredentials, skipPrompts) {
42
43
  }
43
44
  return true;
44
45
  }
45
- async function confirmJwtMigration(skipPrompts) {
46
- if (skipPrompts) {
46
+ async function confirmJwtMigration(nonInteractive) {
47
+ if (nonInteractive) {
47
48
  throw new ZapierCliValidationError("Legacy JWT login detected. Run `logout` first or use an interactive terminal to migrate to client credentials.");
48
49
  }
49
50
  const { confirmed } = await inquirer.prompt([
@@ -63,8 +64,8 @@ async function confirmJwtMigration(skipPrompts) {
63
64
  }
64
65
  return true;
65
66
  }
66
- async function confirmLocalLoginReset(skipPrompts) {
67
- if (skipPrompts) {
67
+ async function confirmLocalLoginReset(nonInteractive) {
68
+ if (nonInteractive) {
68
69
  throw new ZapierCliValidationError("Login cleanup failed and cannot be reset without confirmation. Re-run with an interactive terminal.");
69
70
  }
70
71
  const { confirmed } = await inquirer.prompt([
@@ -88,12 +89,9 @@ function parseTimeoutSeconds(timeout) {
88
89
  }
89
90
  return timeoutSeconds;
90
91
  }
91
- async function promptCredentialsName(email, skipPrompts, baseUrl) {
92
+ async function promptCredentialsName(email, nonInteractive) {
92
93
  const fallback = `${email}@${hostname()}`;
93
- if (skipPrompts) {
94
- if (credentialsNameExists({ name: fallback, baseUrl })) {
95
- throw new ZapierCliValidationError(`Credentials named "${fallback}" already exist. Run \`logout\` first or use an interactive terminal to choose a different name.`);
96
- }
94
+ if (nonInteractive) {
97
95
  return fallback;
98
96
  }
99
97
  const { credentialName } = await inquirer.prompt([
@@ -105,9 +103,6 @@ async function promptCredentialsName(email, skipPrompts, baseUrl) {
105
103
  validate: (input) => {
106
104
  if (!input.trim())
107
105
  return "Name cannot be empty";
108
- if (credentialsNameExists({ name: input.trim(), baseUrl })) {
109
- return `Credentials named "${input.trim()}" already exist. Please provide a different name.`;
110
- }
111
106
  return true;
112
107
  },
113
108
  },
@@ -143,9 +138,7 @@ export const loginPlugin = definePlugin((sdk) => createPluginMethod(sdk, {
143
138
  supportsJsonOutput: false,
144
139
  handler: async ({ sdk, options }) => {
145
140
  const timeoutSeconds = parseTimeoutSeconds(options.timeout);
146
- const skipPrompts = options.skipPrompts === true ||
147
- !process.stdin.isTTY ||
148
- !process.stdout.isTTY;
141
+ const nonInteractive = resolveNonInteractive(options);
149
142
  const resolvedCredentials = await sdk.context.resolveCredentials();
150
143
  const pkceCredentials = toPkceCredentials(resolvedCredentials);
151
144
  const credentialsBaseUrl = await resolveCredentialsBaseUrl({
@@ -156,7 +149,7 @@ export const loginPlugin = definePlugin((sdk) => createPluginMethod(sdk, {
156
149
  baseUrl: credentialsBaseUrl,
157
150
  });
158
151
  if (activeCredentials) {
159
- if (!(await confirmRevokeAndRelogin(activeCredentials, skipPrompts)))
152
+ if (!(await confirmRevokeAndRelogin(activeCredentials, nonInteractive)))
160
153
  return;
161
154
  try {
162
155
  await revokeCredentials({
@@ -165,7 +158,7 @@ export const loginPlugin = definePlugin((sdk) => createPluginMethod(sdk, {
165
158
  });
166
159
  }
167
160
  catch {
168
- if (!(await confirmLocalLoginReset(skipPrompts)))
161
+ if (!(await confirmLocalLoginReset(nonInteractive)))
169
162
  return;
170
163
  await deleteStoredClientCredentials({
171
164
  name: activeCredentials.name,
@@ -174,7 +167,7 @@ export const loginPlugin = definePlugin((sdk) => createPluginMethod(sdk, {
174
167
  }
175
168
  }
176
169
  else if (hasLegacyJwtConfig()) {
177
- if (!(await confirmJwtMigration(skipPrompts)))
170
+ if (!(await confirmJwtMigration(nonInteractive)))
178
171
  return;
179
172
  }
180
173
  const { accessToken } = await runOauthFlow({
@@ -189,7 +182,7 @@ export const loginPlugin = definePlugin((sdk) => createPluginMethod(sdk, {
189
182
  const profile = await getProfile(scopedApi);
190
183
  console.log(`👤 Logged in as ${profile.email}`);
191
184
  console.log("\nGenerating credentials so this machine can make authenticated requests on your behalf.");
192
- const credentialName = await promptCredentialsName(profile.email, skipPrompts, credentialsBaseUrl);
185
+ const credentialName = await promptCredentialsName(profile.email, nonInteractive);
193
186
  const useApprovals = options.useApprovals === true;
194
187
  await setupClientCredentials({
195
188
  api: scopedApi,
@@ -2,6 +2,7 @@ import { z } from "zod";
2
2
  export declare const LoginSchema: z.ZodObject<{
3
3
  timeout: z.ZodOptional<z.ZodString>;
4
4
  useApprovals: z.ZodOptional<z.ZodBoolean>;
5
+ nonInteractive: z.ZodOptional<z.ZodBoolean>;
5
6
  skipPrompts: z.ZodOptional<z.ZodBoolean>;
6
7
  }, z.core.$strip>;
7
8
  export type LoginOptions = z.infer<typeof LoginSchema>;
@@ -10,9 +10,14 @@ export const LoginSchema = z
10
10
  .boolean()
11
11
  .optional()
12
12
  .describe("Require approvals for actions performed with these credentials"),
13
- skipPrompts: z
13
+ nonInteractive: z
14
14
  .boolean()
15
15
  .optional()
16
16
  .describe("Skip interactive prompts. Uses defaults where possible; errors instead of prompting when input is required. Useful in CI, piped output, or environments where TTY detection is unreliable."),
17
+ /** @deprecated Use `nonInteractive` instead. */
18
+ skipPrompts: z.boolean().optional().meta({
19
+ deprecated: true,
20
+ deprecationMessage: "Use --non-interactive instead.",
21
+ }),
17
22
  })
18
23
  .describe("Log in to Zapier to access your account");