@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/CHANGELOG.md +29 -0
- package/README.md +136 -12
- package/dist/cli.cjs +56 -59
- package/dist/cli.mjs +56 -59
- package/dist/experimental.cjs +55 -58
- package/dist/experimental.mjs +55 -58
- package/dist/index.cjs +56 -59
- package/dist/index.mjs +56 -59
- package/dist/package.json +1 -1
- package/dist/src/login/credentials-revoke.js +13 -6
- package/dist/src/login/credentials-store.d.ts +0 -4
- package/dist/src/login/credentials-store.js +0 -3
- package/dist/src/plugins/init/display.js +2 -2
- package/dist/src/plugins/init/index.d.ts +1 -0
- package/dist/src/plugins/init/index.js +4 -2
- package/dist/src/plugins/init/schemas.d.ts +1 -0
- package/dist/src/plugins/init/schemas.js +6 -1
- package/dist/src/plugins/init/steps.d.ts +2 -2
- package/dist/src/plugins/init/steps.js +3 -3
- package/dist/src/plugins/init/types.d.ts +1 -1
- package/dist/src/plugins/init/utils.d.ts +2 -2
- package/dist/src/plugins/init/utils.js +2 -2
- package/dist/src/plugins/login/index.d.ts +1 -0
- package/dist/src/plugins/login/index.js +15 -22
- package/dist/src/plugins/login/schemas.d.ts +1 -0
- package/dist/src/plugins/login/schemas.js +6 -1
- package/dist/src/plugins/logout/index.js +0 -15
- package/dist/src/plugins/logout/schemas.d.ts +0 -1
- package/dist/src/plugins/logout/schemas.js +0 -1
- package/dist/src/utils/non-interactive.d.ts +13 -0
- package/dist/src/utils/non-interactive.js +14 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
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
|
|
819
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
1246
|
-
if (
|
|
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(
|
|
1268
|
-
if (
|
|
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(
|
|
1288
|
-
if (
|
|
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,
|
|
1328
|
+
async function promptCredentialsName(email, nonInteractive) {
|
|
1315
1329
|
const fallback = `${email}@${hostname()}`;
|
|
1316
|
-
if (
|
|
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
|
|
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,
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3100
|
+
nonInteractive
|
|
3105
3101
|
}) {
|
|
3106
|
-
if (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3367
|
+
nonInteractive
|
|
3372
3368
|
}) => {
|
|
3373
3369
|
const progressMessage = `${description}...`;
|
|
3374
3370
|
const stepCounter = chalk3.dim(`${stepNumber}/${totalSteps}`);
|
|
3375
|
-
if (
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
4007
|
+
version: "0.52.7"};
|
|
4011
4008
|
|
|
4012
4009
|
// src/telemetry/builders.ts
|
|
4013
4010
|
function createCliBaseEvent(context = {}) {
|
package/dist/package.json
CHANGED
|
@@ -9,11 +9,11 @@ export function emitAuthLogout(onEvent) {
|
|
|
9
9
|
timestamp: Date.now(),
|
|
10
10
|
});
|
|
11
11
|
}
|
|
12
|
-
function
|
|
13
|
-
|
|
14
|
-
err
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
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,
|
|
8
|
+
onStepStart: ({ description, stepNumber, totalSteps, command, nonInteractive, }) => {
|
|
9
9
|
const progressMessage = `${description}...`;
|
|
10
10
|
const stepCounter = chalk.dim(`${stepNumber}/${totalSteps}`);
|
|
11
|
-
if (
|
|
11
|
+
if (nonInteractive) {
|
|
12
12
|
console.log("\n" +
|
|
13
13
|
chalk.bold(`❯ ${progressMessage}`) +
|
|
14
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
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
21
|
+
export declare function runStep({ step, stepNumber, totalSteps, nonInteractive, displayHooks, }: {
|
|
22
22
|
step: RunnableSetupStep;
|
|
23
23
|
stepNumber: number;
|
|
24
24
|
totalSteps: number;
|
|
25
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
60
|
+
nonInteractive,
|
|
61
61
|
});
|
|
62
62
|
try {
|
|
63
63
|
await step.run();
|
|
@@ -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,
|
|
15
|
+
export declare function promptYesNo({ message, defaultValue, nonInteractive, }: {
|
|
16
16
|
message: string;
|
|
17
17
|
defaultValue: boolean;
|
|
18
|
-
|
|
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,
|
|
49
|
-
if (
|
|
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 },
|
|
@@ -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,
|
|
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,
|
|
26
|
-
if (
|
|
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(
|
|
46
|
-
if (
|
|
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(
|
|
67
|
-
if (
|
|
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,
|
|
92
|
+
async function promptCredentialsName(email, nonInteractive) {
|
|
92
93
|
const fallback = `${email}@${hostname()}`;
|
|
93
|
-
if (
|
|
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
|
|
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,
|
|
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(
|
|
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(
|
|
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,
|
|
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
|
-
|
|
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");
|