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