@zapier/zapier-sdk-cli 0.60.0 → 0.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +2 -1
- package/dist/cli.cjs +330 -196
- package/dist/cli.mjs +330 -196
- package/dist/experimental.cjs +329 -195
- package/dist/experimental.mjs +329 -195
- package/dist/index.cjs +330 -196
- package/dist/index.mjs +330 -196
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -343,12 +343,18 @@ var ZapierCliExitError = class extends ZapierCliError {
|
|
|
343
343
|
this.exitCode = exitCode;
|
|
344
344
|
}
|
|
345
345
|
};
|
|
346
|
-
var ZapierCliValidationError = class extends ZapierCliError {
|
|
347
|
-
constructor(message) {
|
|
346
|
+
var ZapierCliValidationError = class _ZapierCliValidationError extends ZapierCliError {
|
|
347
|
+
constructor(message, options = {}) {
|
|
348
348
|
super(message);
|
|
349
|
-
this.name = "ZapierCliValidationError";
|
|
350
|
-
this.code = "ZAPIER_CLI_VALIDATION_ERROR";
|
|
351
349
|
this.exitCode = 1;
|
|
350
|
+
this.name = options.name ?? "ZapierCliValidationError";
|
|
351
|
+
this.code = options.code ?? "ZAPIER_CLI_VALIDATION_ERROR";
|
|
352
|
+
}
|
|
353
|
+
withMessage(message) {
|
|
354
|
+
return new _ZapierCliValidationError(message, {
|
|
355
|
+
name: this.name,
|
|
356
|
+
code: this.code
|
|
357
|
+
});
|
|
352
358
|
}
|
|
353
359
|
};
|
|
354
360
|
|
|
@@ -1109,41 +1115,165 @@ var spinPromise = async (promise, text) => {
|
|
|
1109
1115
|
}
|
|
1110
1116
|
};
|
|
1111
1117
|
|
|
1118
|
+
// src/utils/auth/oauth-errors.ts
|
|
1119
|
+
var OauthFlowTimeoutError = class _OauthFlowTimeoutError extends ZapierCliValidationError {
|
|
1120
|
+
constructor({
|
|
1121
|
+
timeoutMs,
|
|
1122
|
+
message = "OAuth flow timed out"
|
|
1123
|
+
}) {
|
|
1124
|
+
super(message, {
|
|
1125
|
+
name: "OauthFlowTimeoutError",
|
|
1126
|
+
code: "ZAPIER_OAUTH_FLOW_TIMEOUT"
|
|
1127
|
+
});
|
|
1128
|
+
this.timeoutMs = timeoutMs;
|
|
1129
|
+
}
|
|
1130
|
+
withMessage(message) {
|
|
1131
|
+
return new _OauthFlowTimeoutError({ timeoutMs: this.timeoutMs, message });
|
|
1132
|
+
}
|
|
1133
|
+
};
|
|
1134
|
+
var OauthAuthorizationDeniedError = class _OauthAuthorizationDeniedError extends ZapierCliValidationError {
|
|
1135
|
+
constructor({
|
|
1136
|
+
reason,
|
|
1137
|
+
message = "OAuth authorization denied"
|
|
1138
|
+
}) {
|
|
1139
|
+
super(message, {
|
|
1140
|
+
name: "OauthAuthorizationDeniedError",
|
|
1141
|
+
code: "ZAPIER_OAUTH_AUTHORIZATION_DENIED"
|
|
1142
|
+
});
|
|
1143
|
+
this.reason = reason;
|
|
1144
|
+
}
|
|
1145
|
+
withMessage(message) {
|
|
1146
|
+
return new _OauthAuthorizationDeniedError({
|
|
1147
|
+
reason: this.reason,
|
|
1148
|
+
message
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
};
|
|
1152
|
+
var OauthFlowError = class _OauthFlowError extends ZapierCliValidationError {
|
|
1153
|
+
constructor({ message }) {
|
|
1154
|
+
super(message, {
|
|
1155
|
+
name: "OauthFlowError",
|
|
1156
|
+
code: "ZAPIER_OAUTH_FLOW"
|
|
1157
|
+
});
|
|
1158
|
+
}
|
|
1159
|
+
withMessage(message) {
|
|
1160
|
+
return new _OauthFlowError({ message });
|
|
1161
|
+
}
|
|
1162
|
+
};
|
|
1163
|
+
var OauthCallbackError = class _OauthCallbackError extends ZapierCliValidationError {
|
|
1164
|
+
constructor({ kind, message }) {
|
|
1165
|
+
super(message, {
|
|
1166
|
+
name: "OauthCallbackError",
|
|
1167
|
+
code: "ZAPIER_OAUTH_CALLBACK"
|
|
1168
|
+
});
|
|
1169
|
+
this.kind = kind;
|
|
1170
|
+
}
|
|
1171
|
+
withMessage(message) {
|
|
1172
|
+
return new _OauthCallbackError({ kind: this.kind, message });
|
|
1173
|
+
}
|
|
1174
|
+
};
|
|
1175
|
+
var OauthTokenExchangeError = class _OauthTokenExchangeError extends ZapierCliValidationError {
|
|
1176
|
+
constructor({ message }) {
|
|
1177
|
+
super(message, {
|
|
1178
|
+
name: "OauthTokenExchangeError",
|
|
1179
|
+
code: "ZAPIER_OAUTH_TOKEN_EXCHANGE"
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
withMessage(message) {
|
|
1183
|
+
return new _OauthTokenExchangeError({ message });
|
|
1184
|
+
}
|
|
1185
|
+
};
|
|
1186
|
+
var SENSITIVE_OAUTH_FIELDS = [
|
|
1187
|
+
"access_token",
|
|
1188
|
+
"refresh_token",
|
|
1189
|
+
"id_token",
|
|
1190
|
+
"client_secret",
|
|
1191
|
+
"code_verifier",
|
|
1192
|
+
"code_challenge"
|
|
1193
|
+
];
|
|
1194
|
+
function getErrorMessage(error) {
|
|
1195
|
+
return error instanceof Error ? error.message : String(error);
|
|
1196
|
+
}
|
|
1197
|
+
function toCamelCase(field) {
|
|
1198
|
+
return field.replace(
|
|
1199
|
+
/_([a-z])/g,
|
|
1200
|
+
(_match, letter) => letter.toUpperCase()
|
|
1201
|
+
);
|
|
1202
|
+
}
|
|
1203
|
+
function escapeRegExp(value) {
|
|
1204
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1205
|
+
}
|
|
1206
|
+
var sensitiveOauthFieldPattern = Array.from(
|
|
1207
|
+
new Set(
|
|
1208
|
+
SENSITIVE_OAUTH_FIELDS.flatMap((field) => [field, toCamelCase(field)])
|
|
1209
|
+
)
|
|
1210
|
+
).map(escapeRegExp).join("|");
|
|
1211
|
+
var sensitiveQueryParamPattern = new RegExp(
|
|
1212
|
+
`([?&])(${sensitiveOauthFieldPattern})(=)[^&#\\s"'<>]*`,
|
|
1213
|
+
"gi"
|
|
1214
|
+
);
|
|
1215
|
+
function redactSensitiveOauthErrorMessage(message) {
|
|
1216
|
+
return message.replace(
|
|
1217
|
+
sensitiveQueryParamPattern,
|
|
1218
|
+
(_match, prefix, key, separator) => `${prefix}${key}${separator}[REDACTED]`
|
|
1219
|
+
).replace(
|
|
1220
|
+
new RegExp(`"(${sensitiveOauthFieldPattern})"(\\s*:\\s*)"[^"]*"`, "g"),
|
|
1221
|
+
(_match, key, separator) => `"${key}"${separator}"[REDACTED]"`
|
|
1222
|
+
);
|
|
1223
|
+
}
|
|
1224
|
+
function toRedactedOauthError(error) {
|
|
1225
|
+
const message = redactSensitiveOauthErrorMessage(getErrorMessage(error));
|
|
1226
|
+
if (error instanceof ZapierCliValidationError) {
|
|
1227
|
+
return error.withMessage(message);
|
|
1228
|
+
}
|
|
1229
|
+
return new OauthFlowError({ message });
|
|
1230
|
+
}
|
|
1231
|
+
function toOauthTokenExchangeError(error) {
|
|
1232
|
+
return new OauthTokenExchangeError({
|
|
1233
|
+
message: redactSensitiveOauthErrorMessage(getErrorMessage(error))
|
|
1234
|
+
});
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1112
1237
|
// src/utils/auth/oauth-callback.ts
|
|
1113
1238
|
function getCallbackCode({
|
|
1114
1239
|
callbackUrl,
|
|
1115
|
-
transaction
|
|
1116
|
-
recoveryMessage
|
|
1240
|
+
transaction
|
|
1117
1241
|
}) {
|
|
1118
1242
|
let parsed;
|
|
1119
1243
|
try {
|
|
1120
1244
|
parsed = new URL(callbackUrl.trim());
|
|
1121
1245
|
} catch {
|
|
1122
|
-
throw new
|
|
1123
|
-
|
|
1124
|
-
|
|
1246
|
+
throw new OauthCallbackError({
|
|
1247
|
+
kind: "invalid_url",
|
|
1248
|
+
message: "Paste the final OAuth callback URL from your browser."
|
|
1249
|
+
});
|
|
1125
1250
|
}
|
|
1126
1251
|
const expected = new URL(transaction.redirectUri);
|
|
1127
1252
|
if (parsed.protocol !== "http:" || parsed.hostname !== expected.hostname || parsed.pathname !== expected.pathname || parsed.port !== expected.port) {
|
|
1128
|
-
throw new
|
|
1129
|
-
|
|
1130
|
-
|
|
1253
|
+
throw new OauthCallbackError({
|
|
1254
|
+
kind: "redirect_mismatch",
|
|
1255
|
+
message: `Expected the final OAuth callback URL to start with ${transaction.redirectUri}.`
|
|
1256
|
+
});
|
|
1131
1257
|
}
|
|
1132
1258
|
if (parsed.searchParams.get("state") !== transaction.state) {
|
|
1133
|
-
throw new
|
|
1134
|
-
|
|
1135
|
-
|
|
1259
|
+
throw new OauthCallbackError({
|
|
1260
|
+
kind: "state_mismatch",
|
|
1261
|
+
message: "OAuth state mismatch."
|
|
1262
|
+
});
|
|
1136
1263
|
}
|
|
1137
1264
|
if (parsed.searchParams.has("error")) {
|
|
1138
|
-
throw new
|
|
1139
|
-
|
|
1140
|
-
|
|
1265
|
+
throw new OauthAuthorizationDeniedError({
|
|
1266
|
+
reason: String(
|
|
1267
|
+
parsed.searchParams.get("error_description") ?? parsed.searchParams.get("error")
|
|
1268
|
+
)
|
|
1269
|
+
});
|
|
1141
1270
|
}
|
|
1142
1271
|
const code = parsed.searchParams.get("code");
|
|
1143
1272
|
if (!code) {
|
|
1144
|
-
throw new
|
|
1145
|
-
|
|
1146
|
-
|
|
1273
|
+
throw new OauthCallbackError({
|
|
1274
|
+
kind: "missing_code",
|
|
1275
|
+
message: "No authorization code found in the pasted callback URL."
|
|
1276
|
+
});
|
|
1147
1277
|
}
|
|
1148
1278
|
return code;
|
|
1149
1279
|
}
|
|
@@ -1258,7 +1388,9 @@ async function exchangeOauthCode({
|
|
|
1258
1388
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
1259
1389
|
}
|
|
1260
1390
|
}
|
|
1261
|
-
)
|
|
1391
|
+
).catch((error) => {
|
|
1392
|
+
throw toOauthTokenExchangeError(error);
|
|
1393
|
+
});
|
|
1262
1394
|
return {
|
|
1263
1395
|
accessToken: data.access_token,
|
|
1264
1396
|
refreshToken: data.refresh_token,
|
|
@@ -1267,19 +1399,15 @@ async function exchangeOauthCode({
|
|
|
1267
1399
|
}
|
|
1268
1400
|
|
|
1269
1401
|
// src/utils/auth/oauth-flow.ts
|
|
1270
|
-
var
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
this.name = "OauthFlowTimeoutError";
|
|
1275
|
-
}
|
|
1402
|
+
var LOGIN_OAUTH_COPY = {
|
|
1403
|
+
flowName: "Login",
|
|
1404
|
+
action: "log in",
|
|
1405
|
+
urlLabel: "login URL"
|
|
1276
1406
|
};
|
|
1277
|
-
var
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
this.name = "OauthAuthorizationDeniedError";
|
|
1282
|
-
}
|
|
1407
|
+
var SIGNUP_OAUTH_COPY = {
|
|
1408
|
+
flowName: "Signup",
|
|
1409
|
+
action: "sign up",
|
|
1410
|
+
urlLabel: "signup URL"
|
|
1283
1411
|
};
|
|
1284
1412
|
function findAvailablePort() {
|
|
1285
1413
|
return new Promise((resolve4, reject) => {
|
|
@@ -1294,70 +1422,86 @@ function findAvailablePort() {
|
|
|
1294
1422
|
tryPort(LOGIN_PORTS[portIndex++]);
|
|
1295
1423
|
} else if (err.code === "EADDRINUSE") {
|
|
1296
1424
|
reject(
|
|
1297
|
-
new
|
|
1298
|
-
`All configured OAuth callback ports are busy: ${LOGIN_PORTS.join(", ")}. Please try again later or close applications using these ports.`
|
|
1299
|
-
)
|
|
1425
|
+
new OauthFlowError({
|
|
1426
|
+
message: `All configured OAuth callback ports are busy: ${LOGIN_PORTS.join(", ")}. Please try again later or close applications using these ports.`
|
|
1427
|
+
})
|
|
1300
1428
|
);
|
|
1301
1429
|
} else {
|
|
1302
1430
|
reject(err);
|
|
1303
1431
|
}
|
|
1304
1432
|
});
|
|
1305
1433
|
};
|
|
1306
|
-
if (LOGIN_PORTS.length > 0)
|
|
1307
|
-
|
|
1434
|
+
if (LOGIN_PORTS.length > 0) {
|
|
1435
|
+
tryPort(LOGIN_PORTS[portIndex++]);
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
reject(
|
|
1439
|
+
new OauthFlowError({ message: "No OAuth callback ports configured" })
|
|
1440
|
+
);
|
|
1308
1441
|
});
|
|
1309
1442
|
}
|
|
1310
1443
|
async function runLoginOauthFlow(options) {
|
|
1311
|
-
return
|
|
1312
|
-
|
|
1444
|
+
return runOauthFlowForEntryPoint({
|
|
1445
|
+
options,
|
|
1313
1446
|
entryPoint: "login",
|
|
1314
|
-
|
|
1315
|
-
flowName: "Login"
|
|
1447
|
+
copy: LOGIN_OAUTH_COPY
|
|
1316
1448
|
});
|
|
1317
1449
|
}
|
|
1318
1450
|
async function runSignupOauthFlow(options) {
|
|
1451
|
+
return runOauthFlowForEntryPoint({
|
|
1452
|
+
options,
|
|
1453
|
+
entryPoint: "signup",
|
|
1454
|
+
copy: SIGNUP_OAUTH_COPY
|
|
1455
|
+
});
|
|
1456
|
+
}
|
|
1457
|
+
function runOauthFlowForEntryPoint({
|
|
1458
|
+
options,
|
|
1459
|
+
entryPoint,
|
|
1460
|
+
copy
|
|
1461
|
+
}) {
|
|
1319
1462
|
if (options.headless) {
|
|
1320
1463
|
return runOauthFlowEntryPoint({
|
|
1321
1464
|
...options,
|
|
1322
|
-
entryPoint
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
headless: true
|
|
1465
|
+
entryPoint,
|
|
1466
|
+
headless: true,
|
|
1467
|
+
copy
|
|
1326
1468
|
});
|
|
1327
1469
|
}
|
|
1328
1470
|
return runOauthFlowEntryPoint({
|
|
1329
1471
|
...options,
|
|
1330
|
-
entryPoint
|
|
1331
|
-
|
|
1332
|
-
|
|
1472
|
+
entryPoint,
|
|
1473
|
+
copy,
|
|
1474
|
+
headless: false
|
|
1333
1475
|
});
|
|
1334
1476
|
}
|
|
1335
|
-
async function runOauthFlowEntryPoint({
|
|
1336
|
-
flowName,
|
|
1337
|
-
...options
|
|
1338
|
-
}) {
|
|
1477
|
+
async function runOauthFlowEntryPoint(options) {
|
|
1339
1478
|
try {
|
|
1340
|
-
return options.headless ? await
|
|
1479
|
+
return options.headless ? await runHeadlessOauthFlow(options) : await runOauthFlow(options);
|
|
1341
1480
|
} catch (error) {
|
|
1342
1481
|
if (error instanceof OauthFlowTimeoutError) {
|
|
1343
|
-
throw
|
|
1482
|
+
throw error.withMessage(
|
|
1344
1483
|
withRecoveryMessage(
|
|
1345
|
-
`${flowName} timed out after ${Math.round(error.timeoutMs / 1e3)} seconds.`,
|
|
1484
|
+
`${options.copy.flowName} timed out after ${Math.round(error.timeoutMs / 1e3)} seconds.`,
|
|
1346
1485
|
options.recoveryMessage
|
|
1347
1486
|
)
|
|
1348
1487
|
);
|
|
1349
1488
|
}
|
|
1350
1489
|
if (error instanceof OauthAuthorizationDeniedError) {
|
|
1351
|
-
throw
|
|
1490
|
+
throw error.withMessage(
|
|
1352
1491
|
withRecoveryMessage(
|
|
1353
1492
|
`Authorization denied: ${error.reason}.`,
|
|
1354
1493
|
options.recoveryMessage
|
|
1355
1494
|
)
|
|
1356
1495
|
);
|
|
1357
1496
|
}
|
|
1497
|
+
if (error instanceof OauthCallbackError && options.recoveryMessage) {
|
|
1498
|
+
throw error.withMessage(
|
|
1499
|
+
withRecoveryMessage(error.message, options.recoveryMessage)
|
|
1500
|
+
);
|
|
1501
|
+
}
|
|
1358
1502
|
if (error instanceof ZapierCliUserCancellationError && !options.silent) {
|
|
1359
1503
|
log_default.info(`
|
|
1360
|
-
\u274C ${flowName} cancelled by user`);
|
|
1504
|
+
\u274C ${options.copy.flowName} cancelled by user`);
|
|
1361
1505
|
}
|
|
1362
1506
|
throw error;
|
|
1363
1507
|
}
|
|
@@ -1365,12 +1509,22 @@ async function runOauthFlowEntryPoint({
|
|
|
1365
1509
|
function withRecoveryMessage(message, recoveryMessage) {
|
|
1366
1510
|
return recoveryMessage ? `${message} ${recoveryMessage}` : message;
|
|
1367
1511
|
}
|
|
1512
|
+
function createMissingHeadlessCallbackUrlError() {
|
|
1513
|
+
return new OauthCallbackError({
|
|
1514
|
+
kind: "missing_callback_url",
|
|
1515
|
+
message: "Paste the final OAuth callback URL from your browser."
|
|
1516
|
+
});
|
|
1517
|
+
}
|
|
1518
|
+
function writeHeadlessOauthStatus(message) {
|
|
1519
|
+
process.stderr.write(`${message}
|
|
1520
|
+
`);
|
|
1521
|
+
}
|
|
1368
1522
|
async function runOauthFlow({
|
|
1369
1523
|
timeoutMs = LOGIN_TIMEOUT_MS,
|
|
1370
1524
|
pkceCredentials,
|
|
1371
1525
|
baseUrl,
|
|
1372
1526
|
entryPoint,
|
|
1373
|
-
|
|
1527
|
+
copy,
|
|
1374
1528
|
silent = false,
|
|
1375
1529
|
onProgress
|
|
1376
1530
|
}) {
|
|
@@ -1385,7 +1539,7 @@ async function runOauthFlow({
|
|
|
1385
1539
|
const code = await collectLocalCallbackCode({
|
|
1386
1540
|
transaction,
|
|
1387
1541
|
timeoutMs,
|
|
1388
|
-
|
|
1542
|
+
action: copy.action,
|
|
1389
1543
|
silent,
|
|
1390
1544
|
onProgress
|
|
1391
1545
|
});
|
|
@@ -1399,92 +1553,104 @@ async function runOauthFlow({
|
|
|
1399
1553
|
}
|
|
1400
1554
|
async function readHeadlessCallbackUrl({
|
|
1401
1555
|
timeoutMs,
|
|
1402
|
-
interactive
|
|
1403
|
-
recoveryMessage
|
|
1556
|
+
interactive
|
|
1404
1557
|
}) {
|
|
1405
|
-
const timeoutMessage = withRecoveryMessage(
|
|
1406
|
-
`Signup timed out after ${Math.round(timeoutMs / 1e3)} seconds.`,
|
|
1407
|
-
recoveryMessage
|
|
1408
|
-
);
|
|
1409
|
-
const missingCallbackUrlMessage = withRecoveryMessage(
|
|
1410
|
-
"Paste the final OAuth callback URL from your browser.",
|
|
1411
|
-
recoveryMessage
|
|
1412
|
-
);
|
|
1413
1558
|
const rl = promises$1.createInterface({ input: process.stdin, output: process.stderr });
|
|
1414
1559
|
const abortController = new AbortController();
|
|
1415
1560
|
const timeoutTimer = setTimeout(() => abortController.abort(), timeoutMs);
|
|
1416
|
-
const readUrl =
|
|
1417
|
-
signal: abortController.signal
|
|
1418
|
-
}) : new Promise((resolve4, reject) => {
|
|
1561
|
+
const readUrl = new Promise((resolve4, reject) => {
|
|
1419
1562
|
let settled = false;
|
|
1420
|
-
const
|
|
1563
|
+
const handleLine = (value) => settleResolve(value);
|
|
1564
|
+
const handleAbort = () => settleReject(new OauthFlowTimeoutError({ timeoutMs }));
|
|
1565
|
+
const handleClose = () => settleReject(createMissingHeadlessCallbackUrlError());
|
|
1566
|
+
const handleError = (error) => settleReject(error);
|
|
1567
|
+
const handleCancellation = () => settleReject(new ZapierCliUserCancellationError());
|
|
1568
|
+
const cleanupListeners = () => {
|
|
1569
|
+
abortController.signal.removeEventListener("abort", handleAbort);
|
|
1570
|
+
rl.off("line", handleLine);
|
|
1571
|
+
rl.off("close", handleClose);
|
|
1572
|
+
rl.off("error", handleError);
|
|
1573
|
+
rl.off("SIGINT", handleCancellation);
|
|
1574
|
+
process.off("SIGINT", handleCancellation);
|
|
1575
|
+
process.off("SIGTERM", handleCancellation);
|
|
1576
|
+
};
|
|
1577
|
+
function settleResolve(value) {
|
|
1578
|
+
if (settled) return;
|
|
1421
1579
|
settled = true;
|
|
1580
|
+
cleanupListeners();
|
|
1422
1581
|
resolve4(value);
|
|
1423
|
-
}
|
|
1424
|
-
|
|
1582
|
+
}
|
|
1583
|
+
function settleReject(error) {
|
|
1425
1584
|
if (settled) return;
|
|
1426
1585
|
settled = true;
|
|
1586
|
+
cleanupListeners();
|
|
1427
1587
|
reject(error);
|
|
1428
|
-
}
|
|
1429
|
-
abortController.signal.addEventListener(
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
);
|
|
1434
|
-
rl.once("
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1588
|
+
}
|
|
1589
|
+
abortController.signal.addEventListener("abort", handleAbort, {
|
|
1590
|
+
once: true
|
|
1591
|
+
});
|
|
1592
|
+
rl.once("close", handleClose);
|
|
1593
|
+
rl.once("error", handleError);
|
|
1594
|
+
rl.once("SIGINT", handleCancellation);
|
|
1595
|
+
process.once("SIGINT", handleCancellation);
|
|
1596
|
+
process.once("SIGTERM", handleCancellation);
|
|
1597
|
+
if (interactive) {
|
|
1598
|
+
void rl.question("Paste the final OAuth callback URL: ", {
|
|
1599
|
+
signal: abortController.signal
|
|
1600
|
+
}).then(settleResolve).catch((error) => {
|
|
1601
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
1602
|
+
settleReject(new OauthFlowTimeoutError({ timeoutMs }));
|
|
1603
|
+
return;
|
|
1604
|
+
}
|
|
1605
|
+
settleReject(error);
|
|
1606
|
+
});
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
rl.once("line", handleLine);
|
|
1440
1610
|
});
|
|
1441
1611
|
try {
|
|
1442
|
-
return await readUrl
|
|
1443
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
1444
|
-
throw new Error(timeoutMessage);
|
|
1445
|
-
}
|
|
1446
|
-
throw error;
|
|
1447
|
-
});
|
|
1612
|
+
return await readUrl;
|
|
1448
1613
|
} finally {
|
|
1449
1614
|
clearTimeout(timeoutTimer);
|
|
1450
1615
|
rl.close();
|
|
1451
1616
|
}
|
|
1452
1617
|
}
|
|
1453
|
-
async function
|
|
1618
|
+
async function runHeadlessOauthFlow({
|
|
1454
1619
|
timeoutMs = LOGIN_TIMEOUT_MS,
|
|
1455
1620
|
pkceCredentials,
|
|
1456
1621
|
baseUrl,
|
|
1622
|
+
entryPoint,
|
|
1457
1623
|
interactive = true,
|
|
1458
1624
|
onProgress,
|
|
1459
|
-
|
|
1625
|
+
copy
|
|
1460
1626
|
}) {
|
|
1461
1627
|
const port = LOGIN_PORTS[0];
|
|
1462
1628
|
const transaction = await prepareOauthTransaction({
|
|
1463
1629
|
pkceCredentials,
|
|
1464
1630
|
baseUrl,
|
|
1465
1631
|
redirectUri: `http://${OAUTH_LOOPBACK_HOST}:${port}/oauth`,
|
|
1466
|
-
entryPoint
|
|
1632
|
+
entryPoint
|
|
1467
1633
|
});
|
|
1468
|
-
|
|
1469
|
-
|
|
1634
|
+
writeHeadlessOauthStatus(
|
|
1635
|
+
`Use this mode to ${copy.action} from a machine that has no browser.`
|
|
1636
|
+
);
|
|
1637
|
+
writeHeadlessOauthStatus(
|
|
1638
|
+
`Open this ${copy.urlLabel} in a browser on another machine:`
|
|
1470
1639
|
);
|
|
1471
|
-
console.log("Open this signup URL in a browser on another machine:");
|
|
1472
1640
|
console.log(transaction.browserAuthUrl);
|
|
1473
|
-
|
|
1641
|
+
writeHeadlessOauthStatus(
|
|
1474
1642
|
`When the browser lands on ${transaction.redirectUri} and cannot connect, paste the full final URL back here.`
|
|
1475
1643
|
);
|
|
1476
1644
|
const callbackUrl = await readHeadlessCallbackUrl({
|
|
1477
1645
|
timeoutMs,
|
|
1478
|
-
interactive
|
|
1479
|
-
recoveryMessage
|
|
1646
|
+
interactive
|
|
1480
1647
|
});
|
|
1481
1648
|
const code = getCallbackCode({
|
|
1482
1649
|
callbackUrl,
|
|
1483
|
-
transaction
|
|
1484
|
-
recoveryMessage
|
|
1650
|
+
transaction
|
|
1485
1651
|
});
|
|
1486
1652
|
onProgress?.({ type: "callback_accepted" });
|
|
1487
|
-
|
|
1653
|
+
writeHeadlessOauthStatus("Exchanging authorization code for tokens...");
|
|
1488
1654
|
onProgress?.({ type: "token_exchange_started" });
|
|
1489
1655
|
const tokens = await exchangeOauthCode({ ...transaction, code });
|
|
1490
1656
|
onProgress?.({ type: "token_exchange_completed" });
|
|
@@ -1493,7 +1659,7 @@ async function runHeadlessSignupOauthFlow({
|
|
|
1493
1659
|
async function collectLocalCallbackCode({
|
|
1494
1660
|
transaction,
|
|
1495
1661
|
timeoutMs,
|
|
1496
|
-
|
|
1662
|
+
action,
|
|
1497
1663
|
silent,
|
|
1498
1664
|
onProgress
|
|
1499
1665
|
}) {
|
|
@@ -1501,21 +1667,26 @@ async function collectLocalCallbackCode({
|
|
|
1501
1667
|
const app = express__default.default();
|
|
1502
1668
|
app.get("/oauth", (req, res) => {
|
|
1503
1669
|
res.setHeader("Connection", "close");
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
);
|
|
1512
|
-
|
|
1513
|
-
} else if (!req.query.code) {
|
|
1514
|
-
reject(new Error("No authorization code received"));
|
|
1515
|
-
res.end("No authorization code received. You can close this tab.");
|
|
1516
|
-
} else {
|
|
1517
|
-
resolve4(String(req.query.code));
|
|
1670
|
+
try {
|
|
1671
|
+
const code = getCallbackCode({
|
|
1672
|
+
callbackUrl: new URL(
|
|
1673
|
+
req.originalUrl,
|
|
1674
|
+
transaction.redirectUri
|
|
1675
|
+
).toString(),
|
|
1676
|
+
transaction
|
|
1677
|
+
});
|
|
1678
|
+
resolve4(code);
|
|
1518
1679
|
res.end("You can now close this tab and return to the CLI.");
|
|
1680
|
+
} catch (error) {
|
|
1681
|
+
if (error instanceof OauthCallbackError && error.kind === "state_mismatch") {
|
|
1682
|
+
res.status(400).end("Invalid state. You can close this tab.");
|
|
1683
|
+
} else if (error instanceof OauthAuthorizationDeniedError) {
|
|
1684
|
+
reject(error);
|
|
1685
|
+
res.end("Authorization was denied. You can close this tab.");
|
|
1686
|
+
} else {
|
|
1687
|
+
reject(error);
|
|
1688
|
+
res.end("No authorization code received. You can close this tab.");
|
|
1689
|
+
}
|
|
1519
1690
|
}
|
|
1520
1691
|
});
|
|
1521
1692
|
const server = app.listen(
|
|
@@ -1536,19 +1707,19 @@ async function collectLocalCallbackCode({
|
|
|
1536
1707
|
let timeoutTimer;
|
|
1537
1708
|
try {
|
|
1538
1709
|
await waitForServerListening(server);
|
|
1539
|
-
await openBrowser({ transaction,
|
|
1710
|
+
await openBrowser({ transaction, action, silent, onProgress });
|
|
1540
1711
|
const waitForCode = Promise.race([
|
|
1541
1712
|
promise,
|
|
1542
1713
|
new Promise((_resolve, rejectTimeout) => {
|
|
1543
1714
|
timeoutTimer = setTimeout(() => {
|
|
1544
|
-
rejectTimeout(new OauthFlowTimeoutError(timeoutMs));
|
|
1715
|
+
rejectTimeout(new OauthFlowTimeoutError({ timeoutMs }));
|
|
1545
1716
|
}, timeoutMs);
|
|
1546
1717
|
})
|
|
1547
1718
|
]);
|
|
1548
1719
|
onProgress?.({ type: "callback_waiting" });
|
|
1549
1720
|
return silent ? await waitForCode : await spinPromise(
|
|
1550
1721
|
waitForCode,
|
|
1551
|
-
`Waiting for you to ${
|
|
1722
|
+
`Waiting for you to ${action} and authorize`
|
|
1552
1723
|
);
|
|
1553
1724
|
} finally {
|
|
1554
1725
|
if (timeoutTimer) clearTimeout(timeoutTimer);
|
|
@@ -1578,12 +1749,12 @@ async function waitForServerListening(server) {
|
|
|
1578
1749
|
}
|
|
1579
1750
|
async function openBrowser({
|
|
1580
1751
|
transaction,
|
|
1581
|
-
|
|
1752
|
+
action,
|
|
1582
1753
|
silent,
|
|
1583
1754
|
onProgress
|
|
1584
1755
|
}) {
|
|
1585
1756
|
if (!silent) {
|
|
1586
|
-
log_default.info(`Opening your browser to ${
|
|
1757
|
+
log_default.info(`Opening your browser to ${action}.`);
|
|
1587
1758
|
log_default.info("If it doesn't open, visit:", transaction.browserAuthUrl);
|
|
1588
1759
|
}
|
|
1589
1760
|
onProgress?.({ type: "browser_opening", url: transaction.browserAuthUrl });
|
|
@@ -1593,9 +1764,7 @@ async function openBrowser({
|
|
|
1593
1764
|
} catch (err) {
|
|
1594
1765
|
const reason = err instanceof Error ? err.message : String(err);
|
|
1595
1766
|
if (!silent) {
|
|
1596
|
-
log_default.info(
|
|
1597
|
-
`Browser did not open automatically to ${authAction}: ${reason}`
|
|
1598
|
-
);
|
|
1767
|
+
log_default.info(`Browser did not open automatically to ${action}: ${reason}`);
|
|
1599
1768
|
log_default.info("Visit this URL manually:", transaction.browserAuthUrl);
|
|
1600
1769
|
}
|
|
1601
1770
|
onProgress?.({
|
|
@@ -1624,61 +1793,10 @@ async function closeServer({
|
|
|
1624
1793
|
});
|
|
1625
1794
|
}
|
|
1626
1795
|
|
|
1627
|
-
// src/utils/auth/oauth-errors.ts
|
|
1628
|
-
var SENSITIVE_OAUTH_FIELDS = [
|
|
1629
|
-
"access_token",
|
|
1630
|
-
"refresh_token",
|
|
1631
|
-
"id_token",
|
|
1632
|
-
"client_secret",
|
|
1633
|
-
"code_verifier",
|
|
1634
|
-
"code_challenge"
|
|
1635
|
-
];
|
|
1636
|
-
function getErrorMessage(error) {
|
|
1637
|
-
return error instanceof Error ? error.message : String(error);
|
|
1638
|
-
}
|
|
1639
|
-
function toCamelCase(field) {
|
|
1640
|
-
return field.replace(
|
|
1641
|
-
/_([a-z])/g,
|
|
1642
|
-
(_match, letter) => letter.toUpperCase()
|
|
1643
|
-
);
|
|
1644
|
-
}
|
|
1645
|
-
function escapeRegExp(value) {
|
|
1646
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1647
|
-
}
|
|
1648
|
-
var sensitiveOauthFieldPattern = Array.from(
|
|
1649
|
-
new Set(
|
|
1650
|
-
SENSITIVE_OAUTH_FIELDS.flatMap((field) => [field, toCamelCase(field)])
|
|
1651
|
-
)
|
|
1652
|
-
).map(escapeRegExp).join("|");
|
|
1653
|
-
var sensitiveQueryParamPattern = new RegExp(
|
|
1654
|
-
`([?&])(${sensitiveOauthFieldPattern})(=)[^&#\\s"'<>]*`,
|
|
1655
|
-
"gi"
|
|
1656
|
-
);
|
|
1657
|
-
function redactSensitiveOauthErrorMessage(message) {
|
|
1658
|
-
return message.replace(
|
|
1659
|
-
sensitiveQueryParamPattern,
|
|
1660
|
-
(_match, prefix, key, separator) => `${prefix}${key}${separator}[REDACTED]`
|
|
1661
|
-
).replace(
|
|
1662
|
-
new RegExp(`"(${sensitiveOauthFieldPattern})"(\\s*:\\s*)"[^"]*"`, "g"),
|
|
1663
|
-
(_match, key, separator) => `"${key}"${separator}"[REDACTED]"`
|
|
1664
|
-
);
|
|
1665
|
-
}
|
|
1666
|
-
function toRedactedOauthError(error) {
|
|
1667
|
-
const message = redactSensitiveOauthErrorMessage(getErrorMessage(error));
|
|
1668
|
-
if (error instanceof ZapierCliValidationError) {
|
|
1669
|
-
return new ZapierCliValidationError(message);
|
|
1670
|
-
}
|
|
1671
|
-
if (error instanceof Error) {
|
|
1672
|
-
const redactedError = new Error(message);
|
|
1673
|
-
redactedError.name = error.name;
|
|
1674
|
-
return redactedError;
|
|
1675
|
-
}
|
|
1676
|
-
return new ZapierCliValidationError(message);
|
|
1677
|
-
}
|
|
1678
|
-
|
|
1679
1796
|
// src/utils/auth/account-auth.ts
|
|
1680
1797
|
var LEGACY_JWT_UPGRADE_PROMPT = "We're upgrading your login to client credentials for a simpler, more reliable experience and to support future security controls. Older Zapier SDK/CLI versions on this machine may stop working after the upgrade. Continue?";
|
|
1681
1798
|
var SIGNUP_RECOVERY_MESSAGE = "Restart `zapier-sdk signup` to generate a fresh signup URL and try again.";
|
|
1799
|
+
var HEADLESS_LOGIN_RECOVERY_MESSAGE = "Restart `zapier-sdk login --headless` to generate a fresh login URL and try again.";
|
|
1682
1800
|
var HEADLESS_SIGNUP_RECOVERY_MESSAGE = "Restart `zapier-sdk signup --headless` to generate a fresh signup URL and try again.";
|
|
1683
1801
|
function getEntryPointLabel(entryPoint) {
|
|
1684
1802
|
return entryPoint === "signup" ? "Signup" : "Login";
|
|
@@ -1798,7 +1916,8 @@ Logging out will delete these credentials and may interrupt other Zapier SDK or
|
|
|
1798
1916
|
Log out and ${getActiveCredentialsAction(entryPoint)}?`
|
|
1799
1917
|
}) : promptlessCredentialResetError(activeCredentials);
|
|
1800
1918
|
if (!confirmed) {
|
|
1801
|
-
|
|
1919
|
+
process.stderr.write(`${flowLabel} cancelled.
|
|
1920
|
+
`);
|
|
1802
1921
|
return false;
|
|
1803
1922
|
}
|
|
1804
1923
|
try {
|
|
@@ -1817,7 +1936,8 @@ Log out and ${getActiveCredentialsAction(entryPoint)}?`
|
|
|
1817
1936
|
message: `${flowLabel} cleanup failed. Reset local session state and continue?`
|
|
1818
1937
|
});
|
|
1819
1938
|
if (!reset) {
|
|
1820
|
-
|
|
1939
|
+
process.stderr.write(`${flowLabel} cancelled.
|
|
1940
|
+
`);
|
|
1821
1941
|
return false;
|
|
1822
1942
|
}
|
|
1823
1943
|
await deleteStoredClientCredentials({
|
|
@@ -1831,7 +1951,8 @@ Log out and ${getActiveCredentialsAction(entryPoint)}?`
|
|
|
1831
1951
|
message: LEGACY_JWT_UPGRADE_PROMPT
|
|
1832
1952
|
}) : promptlessLegacyJwtUpgradeError();
|
|
1833
1953
|
if (!confirmed) {
|
|
1834
|
-
|
|
1954
|
+
process.stderr.write(`${flowLabel} cancelled.
|
|
1955
|
+
`);
|
|
1835
1956
|
return false;
|
|
1836
1957
|
}
|
|
1837
1958
|
}
|
|
@@ -1926,7 +2047,14 @@ async function runOauthForEntryPoint({
|
|
|
1926
2047
|
);
|
|
1927
2048
|
}
|
|
1928
2049
|
return runOauthWithRedaction(
|
|
1929
|
-
() => runLoginOauthFlow({
|
|
2050
|
+
() => runLoginOauthFlow({
|
|
2051
|
+
timeoutMs,
|
|
2052
|
+
pkceCredentials,
|
|
2053
|
+
baseUrl,
|
|
2054
|
+
headless,
|
|
2055
|
+
interactive,
|
|
2056
|
+
recoveryMessage: headless ? HEADLESS_LOGIN_RECOVERY_MESSAGE : void 0
|
|
2057
|
+
})
|
|
1930
2058
|
);
|
|
1931
2059
|
}
|
|
1932
2060
|
async function runAccountAuth({
|
|
@@ -1938,6 +2066,7 @@ async function runAccountAuth({
|
|
|
1938
2066
|
const interactive = !resolveNonInteractive(options);
|
|
1939
2067
|
const resolvedCredentials = await sdk.context.resolveCredentials();
|
|
1940
2068
|
const pkceCredentials = toPkceCredentials(resolvedCredentials);
|
|
2069
|
+
const headless = options.headless === true;
|
|
1941
2070
|
const credentialsBaseUrl = await resolveCredentialsBaseUrl({
|
|
1942
2071
|
...sdk.context,
|
|
1943
2072
|
resolvedCredentials
|
|
@@ -1967,7 +2096,7 @@ async function runAccountAuth({
|
|
|
1967
2096
|
timeoutMs: timeoutSeconds * 1e3,
|
|
1968
2097
|
pkceCredentials,
|
|
1969
2098
|
baseUrl: credentialsBaseUrl,
|
|
1970
|
-
headless
|
|
2099
|
+
headless,
|
|
1971
2100
|
interactive
|
|
1972
2101
|
});
|
|
1973
2102
|
const scopedApi = zapierSdk.getOrCreateApiClient({
|
|
@@ -1975,9 +2104,10 @@ async function runAccountAuth({
|
|
|
1975
2104
|
baseUrl: credentialsBaseUrl
|
|
1976
2105
|
});
|
|
1977
2106
|
const profile = await getProfile(scopedApi);
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
2107
|
+
process.stderr.write(`${getProfileMessage(entryPoint, profile.email)}
|
|
2108
|
+
`);
|
|
2109
|
+
process.stderr.write(
|
|
2110
|
+
"\nGenerating credentials so this machine can make authenticated requests on your behalf.\n"
|
|
1981
2111
|
);
|
|
1982
2112
|
const credentialName = providedName ?? await resolveCredentialName({
|
|
1983
2113
|
email: profile.email,
|
|
@@ -1993,11 +2123,12 @@ async function runAccountAuth({
|
|
|
1993
2123
|
useApprovals,
|
|
1994
2124
|
cleanupLogPrefix: entryPoint
|
|
1995
2125
|
});
|
|
1996
|
-
|
|
1997
|
-
`\u2705 Credentials "${credentialName}" created and set as default. You are ready to use the Zapier SDK
|
|
2126
|
+
process.stderr.write(
|
|
2127
|
+
`\u2705 Credentials "${credentialName}" created and set as default. You are ready to use the Zapier SDK.
|
|
2128
|
+
`
|
|
1998
2129
|
);
|
|
1999
2130
|
if (useApprovals) {
|
|
2000
|
-
|
|
2131
|
+
process.stderr.write("\u{1F510} Approvals are enabled for these credentials.\n");
|
|
2001
2132
|
}
|
|
2002
2133
|
emitAccountAuthSuccess({ sdk, profile, clientId });
|
|
2003
2134
|
}
|
|
@@ -2016,7 +2147,10 @@ var LoginSchema = zod.z.object({
|
|
|
2016
2147
|
skipPrompts: zod.z.boolean().optional().meta({
|
|
2017
2148
|
deprecated: true,
|
|
2018
2149
|
deprecationMessage: "Use --non-interactive instead."
|
|
2019
|
-
})
|
|
2150
|
+
}),
|
|
2151
|
+
headless: zod.z.boolean().optional().describe(
|
|
2152
|
+
"Use when logging in from a machine that has no browser. Prints a login link to open elsewhere, then accepts the pasted loopback callback URL."
|
|
2153
|
+
)
|
|
2020
2154
|
}).describe("Log in to Zapier to access your account");
|
|
2021
2155
|
|
|
2022
2156
|
// src/plugins/login/index.ts
|
|
@@ -4605,7 +4739,7 @@ function collectDeprecationNoticeAndForward(event, onEvent) {
|
|
|
4605
4739
|
// package.json with { type: 'json' }
|
|
4606
4740
|
var package_default = {
|
|
4607
4741
|
name: "@zapier/zapier-sdk-cli",
|
|
4608
|
-
version: "0.
|
|
4742
|
+
version: "0.61.0"};
|
|
4609
4743
|
|
|
4610
4744
|
// src/sdk.ts
|
|
4611
4745
|
zapierSdk.injectCliLogin(login_exports);
|
|
@@ -4645,7 +4779,7 @@ function createZapierCliSdk(options = {}) {
|
|
|
4645
4779
|
|
|
4646
4780
|
// package.json
|
|
4647
4781
|
var package_default2 = {
|
|
4648
|
-
version: "0.
|
|
4782
|
+
version: "0.61.0"};
|
|
4649
4783
|
|
|
4650
4784
|
// src/telemetry/builders.ts
|
|
4651
4785
|
function createCliBaseEvent(context = {}) {
|