@zapier/zapier-sdk-cli 0.60.0 → 0.61.1
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 +16 -0
- package/README.md +2 -1
- package/dist/cli.cjs +514 -201
- package/dist/cli.mjs +515 -202
- package/dist/experimental.cjs +329 -195
- package/dist/experimental.d.mts +3 -3
- package/dist/experimental.d.ts +3 -3
- package/dist/experimental.mjs +329 -195
- package/dist/{sdk-SOLizjno.d.mts → extensions-DXyB9Vsr.d.mts} +11 -2
- package/dist/{sdk-SOLizjno.d.ts → extensions-DXyB9Vsr.d.ts} +11 -2
- package/dist/index.cjs +330 -196
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +330 -196
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -307,12 +307,18 @@ var ZapierCliExitError = class extends ZapierCliError {
|
|
|
307
307
|
this.exitCode = exitCode;
|
|
308
308
|
}
|
|
309
309
|
};
|
|
310
|
-
var ZapierCliValidationError = class extends ZapierCliError {
|
|
311
|
-
constructor(message) {
|
|
310
|
+
var ZapierCliValidationError = class _ZapierCliValidationError extends ZapierCliError {
|
|
311
|
+
constructor(message, options = {}) {
|
|
312
312
|
super(message);
|
|
313
|
-
this.name = "ZapierCliValidationError";
|
|
314
|
-
this.code = "ZAPIER_CLI_VALIDATION_ERROR";
|
|
315
313
|
this.exitCode = 1;
|
|
314
|
+
this.name = options.name ?? "ZapierCliValidationError";
|
|
315
|
+
this.code = options.code ?? "ZAPIER_CLI_VALIDATION_ERROR";
|
|
316
|
+
}
|
|
317
|
+
withMessage(message) {
|
|
318
|
+
return new _ZapierCliValidationError(message, {
|
|
319
|
+
name: this.name,
|
|
320
|
+
code: this.code
|
|
321
|
+
});
|
|
316
322
|
}
|
|
317
323
|
};
|
|
318
324
|
|
|
@@ -1073,41 +1079,165 @@ var spinPromise = async (promise, text) => {
|
|
|
1073
1079
|
}
|
|
1074
1080
|
};
|
|
1075
1081
|
|
|
1082
|
+
// src/utils/auth/oauth-errors.ts
|
|
1083
|
+
var OauthFlowTimeoutError = class _OauthFlowTimeoutError extends ZapierCliValidationError {
|
|
1084
|
+
constructor({
|
|
1085
|
+
timeoutMs,
|
|
1086
|
+
message = "OAuth flow timed out"
|
|
1087
|
+
}) {
|
|
1088
|
+
super(message, {
|
|
1089
|
+
name: "OauthFlowTimeoutError",
|
|
1090
|
+
code: "ZAPIER_OAUTH_FLOW_TIMEOUT"
|
|
1091
|
+
});
|
|
1092
|
+
this.timeoutMs = timeoutMs;
|
|
1093
|
+
}
|
|
1094
|
+
withMessage(message) {
|
|
1095
|
+
return new _OauthFlowTimeoutError({ timeoutMs: this.timeoutMs, message });
|
|
1096
|
+
}
|
|
1097
|
+
};
|
|
1098
|
+
var OauthAuthorizationDeniedError = class _OauthAuthorizationDeniedError extends ZapierCliValidationError {
|
|
1099
|
+
constructor({
|
|
1100
|
+
reason,
|
|
1101
|
+
message = "OAuth authorization denied"
|
|
1102
|
+
}) {
|
|
1103
|
+
super(message, {
|
|
1104
|
+
name: "OauthAuthorizationDeniedError",
|
|
1105
|
+
code: "ZAPIER_OAUTH_AUTHORIZATION_DENIED"
|
|
1106
|
+
});
|
|
1107
|
+
this.reason = reason;
|
|
1108
|
+
}
|
|
1109
|
+
withMessage(message) {
|
|
1110
|
+
return new _OauthAuthorizationDeniedError({
|
|
1111
|
+
reason: this.reason,
|
|
1112
|
+
message
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
};
|
|
1116
|
+
var OauthFlowError = class _OauthFlowError extends ZapierCliValidationError {
|
|
1117
|
+
constructor({ message }) {
|
|
1118
|
+
super(message, {
|
|
1119
|
+
name: "OauthFlowError",
|
|
1120
|
+
code: "ZAPIER_OAUTH_FLOW"
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
withMessage(message) {
|
|
1124
|
+
return new _OauthFlowError({ message });
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1127
|
+
var OauthCallbackError = class _OauthCallbackError extends ZapierCliValidationError {
|
|
1128
|
+
constructor({ kind, message }) {
|
|
1129
|
+
super(message, {
|
|
1130
|
+
name: "OauthCallbackError",
|
|
1131
|
+
code: "ZAPIER_OAUTH_CALLBACK"
|
|
1132
|
+
});
|
|
1133
|
+
this.kind = kind;
|
|
1134
|
+
}
|
|
1135
|
+
withMessage(message) {
|
|
1136
|
+
return new _OauthCallbackError({ kind: this.kind, message });
|
|
1137
|
+
}
|
|
1138
|
+
};
|
|
1139
|
+
var OauthTokenExchangeError = class _OauthTokenExchangeError extends ZapierCliValidationError {
|
|
1140
|
+
constructor({ message }) {
|
|
1141
|
+
super(message, {
|
|
1142
|
+
name: "OauthTokenExchangeError",
|
|
1143
|
+
code: "ZAPIER_OAUTH_TOKEN_EXCHANGE"
|
|
1144
|
+
});
|
|
1145
|
+
}
|
|
1146
|
+
withMessage(message) {
|
|
1147
|
+
return new _OauthTokenExchangeError({ message });
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
var SENSITIVE_OAUTH_FIELDS = [
|
|
1151
|
+
"access_token",
|
|
1152
|
+
"refresh_token",
|
|
1153
|
+
"id_token",
|
|
1154
|
+
"client_secret",
|
|
1155
|
+
"code_verifier",
|
|
1156
|
+
"code_challenge"
|
|
1157
|
+
];
|
|
1158
|
+
function getErrorMessage(error) {
|
|
1159
|
+
return error instanceof Error ? error.message : String(error);
|
|
1160
|
+
}
|
|
1161
|
+
function toCamelCase(field) {
|
|
1162
|
+
return field.replace(
|
|
1163
|
+
/_([a-z])/g,
|
|
1164
|
+
(_match, letter) => letter.toUpperCase()
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
function escapeRegExp(value) {
|
|
1168
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1169
|
+
}
|
|
1170
|
+
var sensitiveOauthFieldPattern = Array.from(
|
|
1171
|
+
new Set(
|
|
1172
|
+
SENSITIVE_OAUTH_FIELDS.flatMap((field) => [field, toCamelCase(field)])
|
|
1173
|
+
)
|
|
1174
|
+
).map(escapeRegExp).join("|");
|
|
1175
|
+
var sensitiveQueryParamPattern = new RegExp(
|
|
1176
|
+
`([?&])(${sensitiveOauthFieldPattern})(=)[^&#\\s"'<>]*`,
|
|
1177
|
+
"gi"
|
|
1178
|
+
);
|
|
1179
|
+
function redactSensitiveOauthErrorMessage(message) {
|
|
1180
|
+
return message.replace(
|
|
1181
|
+
sensitiveQueryParamPattern,
|
|
1182
|
+
(_match, prefix, key, separator) => `${prefix}${key}${separator}[REDACTED]`
|
|
1183
|
+
).replace(
|
|
1184
|
+
new RegExp(`"(${sensitiveOauthFieldPattern})"(\\s*:\\s*)"[^"]*"`, "g"),
|
|
1185
|
+
(_match, key, separator) => `"${key}"${separator}"[REDACTED]"`
|
|
1186
|
+
);
|
|
1187
|
+
}
|
|
1188
|
+
function toRedactedOauthError(error) {
|
|
1189
|
+
const message = redactSensitiveOauthErrorMessage(getErrorMessage(error));
|
|
1190
|
+
if (error instanceof ZapierCliValidationError) {
|
|
1191
|
+
return error.withMessage(message);
|
|
1192
|
+
}
|
|
1193
|
+
return new OauthFlowError({ message });
|
|
1194
|
+
}
|
|
1195
|
+
function toOauthTokenExchangeError(error) {
|
|
1196
|
+
return new OauthTokenExchangeError({
|
|
1197
|
+
message: redactSensitiveOauthErrorMessage(getErrorMessage(error))
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1076
1201
|
// src/utils/auth/oauth-callback.ts
|
|
1077
1202
|
function getCallbackCode({
|
|
1078
1203
|
callbackUrl,
|
|
1079
|
-
transaction
|
|
1080
|
-
recoveryMessage
|
|
1204
|
+
transaction
|
|
1081
1205
|
}) {
|
|
1082
1206
|
let parsed;
|
|
1083
1207
|
try {
|
|
1084
1208
|
parsed = new URL(callbackUrl.trim());
|
|
1085
1209
|
} catch {
|
|
1086
|
-
throw new
|
|
1087
|
-
|
|
1088
|
-
|
|
1210
|
+
throw new OauthCallbackError({
|
|
1211
|
+
kind: "invalid_url",
|
|
1212
|
+
message: "Paste the final OAuth callback URL from your browser."
|
|
1213
|
+
});
|
|
1089
1214
|
}
|
|
1090
1215
|
const expected = new URL(transaction.redirectUri);
|
|
1091
1216
|
if (parsed.protocol !== "http:" || parsed.hostname !== expected.hostname || parsed.pathname !== expected.pathname || parsed.port !== expected.port) {
|
|
1092
|
-
throw new
|
|
1093
|
-
|
|
1094
|
-
|
|
1217
|
+
throw new OauthCallbackError({
|
|
1218
|
+
kind: "redirect_mismatch",
|
|
1219
|
+
message: `Expected the final OAuth callback URL to start with ${transaction.redirectUri}.`
|
|
1220
|
+
});
|
|
1095
1221
|
}
|
|
1096
1222
|
if (parsed.searchParams.get("state") !== transaction.state) {
|
|
1097
|
-
throw new
|
|
1098
|
-
|
|
1099
|
-
|
|
1223
|
+
throw new OauthCallbackError({
|
|
1224
|
+
kind: "state_mismatch",
|
|
1225
|
+
message: "OAuth state mismatch."
|
|
1226
|
+
});
|
|
1100
1227
|
}
|
|
1101
1228
|
if (parsed.searchParams.has("error")) {
|
|
1102
|
-
throw new
|
|
1103
|
-
|
|
1104
|
-
|
|
1229
|
+
throw new OauthAuthorizationDeniedError({
|
|
1230
|
+
reason: String(
|
|
1231
|
+
parsed.searchParams.get("error_description") ?? parsed.searchParams.get("error")
|
|
1232
|
+
)
|
|
1233
|
+
});
|
|
1105
1234
|
}
|
|
1106
1235
|
const code = parsed.searchParams.get("code");
|
|
1107
1236
|
if (!code) {
|
|
1108
|
-
throw new
|
|
1109
|
-
|
|
1110
|
-
|
|
1237
|
+
throw new OauthCallbackError({
|
|
1238
|
+
kind: "missing_code",
|
|
1239
|
+
message: "No authorization code found in the pasted callback URL."
|
|
1240
|
+
});
|
|
1111
1241
|
}
|
|
1112
1242
|
return code;
|
|
1113
1243
|
}
|
|
@@ -1222,7 +1352,9 @@ async function exchangeOauthCode({
|
|
|
1222
1352
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
1223
1353
|
}
|
|
1224
1354
|
}
|
|
1225
|
-
)
|
|
1355
|
+
).catch((error) => {
|
|
1356
|
+
throw toOauthTokenExchangeError(error);
|
|
1357
|
+
});
|
|
1226
1358
|
return {
|
|
1227
1359
|
accessToken: data.access_token,
|
|
1228
1360
|
refreshToken: data.refresh_token,
|
|
@@ -1231,19 +1363,15 @@ async function exchangeOauthCode({
|
|
|
1231
1363
|
}
|
|
1232
1364
|
|
|
1233
1365
|
// src/utils/auth/oauth-flow.ts
|
|
1234
|
-
var
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
this.name = "OauthFlowTimeoutError";
|
|
1239
|
-
}
|
|
1366
|
+
var LOGIN_OAUTH_COPY = {
|
|
1367
|
+
flowName: "Login",
|
|
1368
|
+
action: "log in",
|
|
1369
|
+
urlLabel: "login URL"
|
|
1240
1370
|
};
|
|
1241
|
-
var
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
this.name = "OauthAuthorizationDeniedError";
|
|
1246
|
-
}
|
|
1371
|
+
var SIGNUP_OAUTH_COPY = {
|
|
1372
|
+
flowName: "Signup",
|
|
1373
|
+
action: "sign up",
|
|
1374
|
+
urlLabel: "signup URL"
|
|
1247
1375
|
};
|
|
1248
1376
|
function findAvailablePort() {
|
|
1249
1377
|
return new Promise((resolve4, reject) => {
|
|
@@ -1258,70 +1386,86 @@ function findAvailablePort() {
|
|
|
1258
1386
|
tryPort(LOGIN_PORTS[portIndex++]);
|
|
1259
1387
|
} else if (err.code === "EADDRINUSE") {
|
|
1260
1388
|
reject(
|
|
1261
|
-
new
|
|
1262
|
-
`All configured OAuth callback ports are busy: ${LOGIN_PORTS.join(", ")}. Please try again later or close applications using these ports.`
|
|
1263
|
-
)
|
|
1389
|
+
new OauthFlowError({
|
|
1390
|
+
message: `All configured OAuth callback ports are busy: ${LOGIN_PORTS.join(", ")}. Please try again later or close applications using these ports.`
|
|
1391
|
+
})
|
|
1264
1392
|
);
|
|
1265
1393
|
} else {
|
|
1266
1394
|
reject(err);
|
|
1267
1395
|
}
|
|
1268
1396
|
});
|
|
1269
1397
|
};
|
|
1270
|
-
if (LOGIN_PORTS.length > 0)
|
|
1271
|
-
|
|
1398
|
+
if (LOGIN_PORTS.length > 0) {
|
|
1399
|
+
tryPort(LOGIN_PORTS[portIndex++]);
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
reject(
|
|
1403
|
+
new OauthFlowError({ message: "No OAuth callback ports configured" })
|
|
1404
|
+
);
|
|
1272
1405
|
});
|
|
1273
1406
|
}
|
|
1274
1407
|
async function runLoginOauthFlow(options) {
|
|
1275
|
-
return
|
|
1276
|
-
|
|
1408
|
+
return runOauthFlowForEntryPoint({
|
|
1409
|
+
options,
|
|
1277
1410
|
entryPoint: "login",
|
|
1278
|
-
|
|
1279
|
-
flowName: "Login"
|
|
1411
|
+
copy: LOGIN_OAUTH_COPY
|
|
1280
1412
|
});
|
|
1281
1413
|
}
|
|
1282
1414
|
async function runSignupOauthFlow(options) {
|
|
1415
|
+
return runOauthFlowForEntryPoint({
|
|
1416
|
+
options,
|
|
1417
|
+
entryPoint: "signup",
|
|
1418
|
+
copy: SIGNUP_OAUTH_COPY
|
|
1419
|
+
});
|
|
1420
|
+
}
|
|
1421
|
+
function runOauthFlowForEntryPoint({
|
|
1422
|
+
options,
|
|
1423
|
+
entryPoint,
|
|
1424
|
+
copy
|
|
1425
|
+
}) {
|
|
1283
1426
|
if (options.headless) {
|
|
1284
1427
|
return runOauthFlowEntryPoint({
|
|
1285
1428
|
...options,
|
|
1286
|
-
entryPoint
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
headless: true
|
|
1429
|
+
entryPoint,
|
|
1430
|
+
headless: true,
|
|
1431
|
+
copy
|
|
1290
1432
|
});
|
|
1291
1433
|
}
|
|
1292
1434
|
return runOauthFlowEntryPoint({
|
|
1293
1435
|
...options,
|
|
1294
|
-
entryPoint
|
|
1295
|
-
|
|
1296
|
-
|
|
1436
|
+
entryPoint,
|
|
1437
|
+
copy,
|
|
1438
|
+
headless: false
|
|
1297
1439
|
});
|
|
1298
1440
|
}
|
|
1299
|
-
async function runOauthFlowEntryPoint({
|
|
1300
|
-
flowName,
|
|
1301
|
-
...options
|
|
1302
|
-
}) {
|
|
1441
|
+
async function runOauthFlowEntryPoint(options) {
|
|
1303
1442
|
try {
|
|
1304
|
-
return options.headless ? await
|
|
1443
|
+
return options.headless ? await runHeadlessOauthFlow(options) : await runOauthFlow(options);
|
|
1305
1444
|
} catch (error) {
|
|
1306
1445
|
if (error instanceof OauthFlowTimeoutError) {
|
|
1307
|
-
throw
|
|
1446
|
+
throw error.withMessage(
|
|
1308
1447
|
withRecoveryMessage(
|
|
1309
|
-
`${flowName} timed out after ${Math.round(error.timeoutMs / 1e3)} seconds.`,
|
|
1448
|
+
`${options.copy.flowName} timed out after ${Math.round(error.timeoutMs / 1e3)} seconds.`,
|
|
1310
1449
|
options.recoveryMessage
|
|
1311
1450
|
)
|
|
1312
1451
|
);
|
|
1313
1452
|
}
|
|
1314
1453
|
if (error instanceof OauthAuthorizationDeniedError) {
|
|
1315
|
-
throw
|
|
1454
|
+
throw error.withMessage(
|
|
1316
1455
|
withRecoveryMessage(
|
|
1317
1456
|
`Authorization denied: ${error.reason}.`,
|
|
1318
1457
|
options.recoveryMessage
|
|
1319
1458
|
)
|
|
1320
1459
|
);
|
|
1321
1460
|
}
|
|
1461
|
+
if (error instanceof OauthCallbackError && options.recoveryMessage) {
|
|
1462
|
+
throw error.withMessage(
|
|
1463
|
+
withRecoveryMessage(error.message, options.recoveryMessage)
|
|
1464
|
+
);
|
|
1465
|
+
}
|
|
1322
1466
|
if (error instanceof ZapierCliUserCancellationError && !options.silent) {
|
|
1323
1467
|
log_default.info(`
|
|
1324
|
-
\u274C ${flowName} cancelled by user`);
|
|
1468
|
+
\u274C ${options.copy.flowName} cancelled by user`);
|
|
1325
1469
|
}
|
|
1326
1470
|
throw error;
|
|
1327
1471
|
}
|
|
@@ -1329,12 +1473,22 @@ async function runOauthFlowEntryPoint({
|
|
|
1329
1473
|
function withRecoveryMessage(message, recoveryMessage) {
|
|
1330
1474
|
return recoveryMessage ? `${message} ${recoveryMessage}` : message;
|
|
1331
1475
|
}
|
|
1476
|
+
function createMissingHeadlessCallbackUrlError() {
|
|
1477
|
+
return new OauthCallbackError({
|
|
1478
|
+
kind: "missing_callback_url",
|
|
1479
|
+
message: "Paste the final OAuth callback URL from your browser."
|
|
1480
|
+
});
|
|
1481
|
+
}
|
|
1482
|
+
function writeHeadlessOauthStatus(message) {
|
|
1483
|
+
process.stderr.write(`${message}
|
|
1484
|
+
`);
|
|
1485
|
+
}
|
|
1332
1486
|
async function runOauthFlow({
|
|
1333
1487
|
timeoutMs = LOGIN_TIMEOUT_MS,
|
|
1334
1488
|
pkceCredentials,
|
|
1335
1489
|
baseUrl,
|
|
1336
1490
|
entryPoint,
|
|
1337
|
-
|
|
1491
|
+
copy,
|
|
1338
1492
|
silent = false,
|
|
1339
1493
|
onProgress
|
|
1340
1494
|
}) {
|
|
@@ -1349,7 +1503,7 @@ async function runOauthFlow({
|
|
|
1349
1503
|
const code = await collectLocalCallbackCode({
|
|
1350
1504
|
transaction,
|
|
1351
1505
|
timeoutMs,
|
|
1352
|
-
|
|
1506
|
+
action: copy.action,
|
|
1353
1507
|
silent,
|
|
1354
1508
|
onProgress
|
|
1355
1509
|
});
|
|
@@ -1363,92 +1517,104 @@ async function runOauthFlow({
|
|
|
1363
1517
|
}
|
|
1364
1518
|
async function readHeadlessCallbackUrl({
|
|
1365
1519
|
timeoutMs,
|
|
1366
|
-
interactive
|
|
1367
|
-
recoveryMessage
|
|
1520
|
+
interactive
|
|
1368
1521
|
}) {
|
|
1369
|
-
const timeoutMessage = withRecoveryMessage(
|
|
1370
|
-
`Signup timed out after ${Math.round(timeoutMs / 1e3)} seconds.`,
|
|
1371
|
-
recoveryMessage
|
|
1372
|
-
);
|
|
1373
|
-
const missingCallbackUrlMessage = withRecoveryMessage(
|
|
1374
|
-
"Paste the final OAuth callback URL from your browser.",
|
|
1375
|
-
recoveryMessage
|
|
1376
|
-
);
|
|
1377
1522
|
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
1378
1523
|
const abortController = new AbortController();
|
|
1379
1524
|
const timeoutTimer = setTimeout(() => abortController.abort(), timeoutMs);
|
|
1380
|
-
const readUrl =
|
|
1381
|
-
signal: abortController.signal
|
|
1382
|
-
}) : new Promise((resolve4, reject) => {
|
|
1525
|
+
const readUrl = new Promise((resolve4, reject) => {
|
|
1383
1526
|
let settled = false;
|
|
1384
|
-
const
|
|
1527
|
+
const handleLine = (value) => settleResolve(value);
|
|
1528
|
+
const handleAbort = () => settleReject(new OauthFlowTimeoutError({ timeoutMs }));
|
|
1529
|
+
const handleClose = () => settleReject(createMissingHeadlessCallbackUrlError());
|
|
1530
|
+
const handleError = (error) => settleReject(error);
|
|
1531
|
+
const handleCancellation = () => settleReject(new ZapierCliUserCancellationError());
|
|
1532
|
+
const cleanupListeners = () => {
|
|
1533
|
+
abortController.signal.removeEventListener("abort", handleAbort);
|
|
1534
|
+
rl.off("line", handleLine);
|
|
1535
|
+
rl.off("close", handleClose);
|
|
1536
|
+
rl.off("error", handleError);
|
|
1537
|
+
rl.off("SIGINT", handleCancellation);
|
|
1538
|
+
process.off("SIGINT", handleCancellation);
|
|
1539
|
+
process.off("SIGTERM", handleCancellation);
|
|
1540
|
+
};
|
|
1541
|
+
function settleResolve(value) {
|
|
1542
|
+
if (settled) return;
|
|
1385
1543
|
settled = true;
|
|
1544
|
+
cleanupListeners();
|
|
1386
1545
|
resolve4(value);
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1546
|
+
}
|
|
1547
|
+
function settleReject(error) {
|
|
1389
1548
|
if (settled) return;
|
|
1390
1549
|
settled = true;
|
|
1550
|
+
cleanupListeners();
|
|
1391
1551
|
reject(error);
|
|
1392
|
-
}
|
|
1393
|
-
abortController.signal.addEventListener(
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
);
|
|
1398
|
-
rl.once("
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1552
|
+
}
|
|
1553
|
+
abortController.signal.addEventListener("abort", handleAbort, {
|
|
1554
|
+
once: true
|
|
1555
|
+
});
|
|
1556
|
+
rl.once("close", handleClose);
|
|
1557
|
+
rl.once("error", handleError);
|
|
1558
|
+
rl.once("SIGINT", handleCancellation);
|
|
1559
|
+
process.once("SIGINT", handleCancellation);
|
|
1560
|
+
process.once("SIGTERM", handleCancellation);
|
|
1561
|
+
if (interactive) {
|
|
1562
|
+
void rl.question("Paste the final OAuth callback URL: ", {
|
|
1563
|
+
signal: abortController.signal
|
|
1564
|
+
}).then(settleResolve).catch((error) => {
|
|
1565
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
1566
|
+
settleReject(new OauthFlowTimeoutError({ timeoutMs }));
|
|
1567
|
+
return;
|
|
1568
|
+
}
|
|
1569
|
+
settleReject(error);
|
|
1570
|
+
});
|
|
1571
|
+
return;
|
|
1572
|
+
}
|
|
1573
|
+
rl.once("line", handleLine);
|
|
1404
1574
|
});
|
|
1405
1575
|
try {
|
|
1406
|
-
return await readUrl
|
|
1407
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
1408
|
-
throw new Error(timeoutMessage);
|
|
1409
|
-
}
|
|
1410
|
-
throw error;
|
|
1411
|
-
});
|
|
1576
|
+
return await readUrl;
|
|
1412
1577
|
} finally {
|
|
1413
1578
|
clearTimeout(timeoutTimer);
|
|
1414
1579
|
rl.close();
|
|
1415
1580
|
}
|
|
1416
1581
|
}
|
|
1417
|
-
async function
|
|
1582
|
+
async function runHeadlessOauthFlow({
|
|
1418
1583
|
timeoutMs = LOGIN_TIMEOUT_MS,
|
|
1419
1584
|
pkceCredentials,
|
|
1420
1585
|
baseUrl,
|
|
1586
|
+
entryPoint,
|
|
1421
1587
|
interactive = true,
|
|
1422
1588
|
onProgress,
|
|
1423
|
-
|
|
1589
|
+
copy
|
|
1424
1590
|
}) {
|
|
1425
1591
|
const port = LOGIN_PORTS[0];
|
|
1426
1592
|
const transaction = await prepareOauthTransaction({
|
|
1427
1593
|
pkceCredentials,
|
|
1428
1594
|
baseUrl,
|
|
1429
1595
|
redirectUri: `http://${OAUTH_LOOPBACK_HOST}:${port}/oauth`,
|
|
1430
|
-
entryPoint
|
|
1596
|
+
entryPoint
|
|
1431
1597
|
});
|
|
1432
|
-
|
|
1433
|
-
|
|
1598
|
+
writeHeadlessOauthStatus(
|
|
1599
|
+
`Use this mode to ${copy.action} from a machine that has no browser.`
|
|
1600
|
+
);
|
|
1601
|
+
writeHeadlessOauthStatus(
|
|
1602
|
+
`Open this ${copy.urlLabel} in a browser on another machine:`
|
|
1434
1603
|
);
|
|
1435
|
-
console.log("Open this signup URL in a browser on another machine:");
|
|
1436
1604
|
console.log(transaction.browserAuthUrl);
|
|
1437
|
-
|
|
1605
|
+
writeHeadlessOauthStatus(
|
|
1438
1606
|
`When the browser lands on ${transaction.redirectUri} and cannot connect, paste the full final URL back here.`
|
|
1439
1607
|
);
|
|
1440
1608
|
const callbackUrl = await readHeadlessCallbackUrl({
|
|
1441
1609
|
timeoutMs,
|
|
1442
|
-
interactive
|
|
1443
|
-
recoveryMessage
|
|
1610
|
+
interactive
|
|
1444
1611
|
});
|
|
1445
1612
|
const code = getCallbackCode({
|
|
1446
1613
|
callbackUrl,
|
|
1447
|
-
transaction
|
|
1448
|
-
recoveryMessage
|
|
1614
|
+
transaction
|
|
1449
1615
|
});
|
|
1450
1616
|
onProgress?.({ type: "callback_accepted" });
|
|
1451
|
-
|
|
1617
|
+
writeHeadlessOauthStatus("Exchanging authorization code for tokens...");
|
|
1452
1618
|
onProgress?.({ type: "token_exchange_started" });
|
|
1453
1619
|
const tokens = await exchangeOauthCode({ ...transaction, code });
|
|
1454
1620
|
onProgress?.({ type: "token_exchange_completed" });
|
|
@@ -1457,7 +1623,7 @@ async function runHeadlessSignupOauthFlow({
|
|
|
1457
1623
|
async function collectLocalCallbackCode({
|
|
1458
1624
|
transaction,
|
|
1459
1625
|
timeoutMs,
|
|
1460
|
-
|
|
1626
|
+
action,
|
|
1461
1627
|
silent,
|
|
1462
1628
|
onProgress
|
|
1463
1629
|
}) {
|
|
@@ -1465,21 +1631,26 @@ async function collectLocalCallbackCode({
|
|
|
1465
1631
|
const app = express();
|
|
1466
1632
|
app.get("/oauth", (req, res) => {
|
|
1467
1633
|
res.setHeader("Connection", "close");
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
);
|
|
1476
|
-
|
|
1477
|
-
} else if (!req.query.code) {
|
|
1478
|
-
reject(new Error("No authorization code received"));
|
|
1479
|
-
res.end("No authorization code received. You can close this tab.");
|
|
1480
|
-
} else {
|
|
1481
|
-
resolve4(String(req.query.code));
|
|
1634
|
+
try {
|
|
1635
|
+
const code = getCallbackCode({
|
|
1636
|
+
callbackUrl: new URL(
|
|
1637
|
+
req.originalUrl,
|
|
1638
|
+
transaction.redirectUri
|
|
1639
|
+
).toString(),
|
|
1640
|
+
transaction
|
|
1641
|
+
});
|
|
1642
|
+
resolve4(code);
|
|
1482
1643
|
res.end("You can now close this tab and return to the CLI.");
|
|
1644
|
+
} catch (error) {
|
|
1645
|
+
if (error instanceof OauthCallbackError && error.kind === "state_mismatch") {
|
|
1646
|
+
res.status(400).end("Invalid state. You can close this tab.");
|
|
1647
|
+
} else if (error instanceof OauthAuthorizationDeniedError) {
|
|
1648
|
+
reject(error);
|
|
1649
|
+
res.end("Authorization was denied. You can close this tab.");
|
|
1650
|
+
} else {
|
|
1651
|
+
reject(error);
|
|
1652
|
+
res.end("No authorization code received. You can close this tab.");
|
|
1653
|
+
}
|
|
1483
1654
|
}
|
|
1484
1655
|
});
|
|
1485
1656
|
const server = app.listen(
|
|
@@ -1500,19 +1671,19 @@ async function collectLocalCallbackCode({
|
|
|
1500
1671
|
let timeoutTimer;
|
|
1501
1672
|
try {
|
|
1502
1673
|
await waitForServerListening(server);
|
|
1503
|
-
await openBrowser({ transaction,
|
|
1674
|
+
await openBrowser({ transaction, action, silent, onProgress });
|
|
1504
1675
|
const waitForCode = Promise.race([
|
|
1505
1676
|
promise,
|
|
1506
1677
|
new Promise((_resolve, rejectTimeout) => {
|
|
1507
1678
|
timeoutTimer = setTimeout(() => {
|
|
1508
|
-
rejectTimeout(new OauthFlowTimeoutError(timeoutMs));
|
|
1679
|
+
rejectTimeout(new OauthFlowTimeoutError({ timeoutMs }));
|
|
1509
1680
|
}, timeoutMs);
|
|
1510
1681
|
})
|
|
1511
1682
|
]);
|
|
1512
1683
|
onProgress?.({ type: "callback_waiting" });
|
|
1513
1684
|
return silent ? await waitForCode : await spinPromise(
|
|
1514
1685
|
waitForCode,
|
|
1515
|
-
`Waiting for you to ${
|
|
1686
|
+
`Waiting for you to ${action} and authorize`
|
|
1516
1687
|
);
|
|
1517
1688
|
} finally {
|
|
1518
1689
|
if (timeoutTimer) clearTimeout(timeoutTimer);
|
|
@@ -1542,12 +1713,12 @@ async function waitForServerListening(server) {
|
|
|
1542
1713
|
}
|
|
1543
1714
|
async function openBrowser({
|
|
1544
1715
|
transaction,
|
|
1545
|
-
|
|
1716
|
+
action,
|
|
1546
1717
|
silent,
|
|
1547
1718
|
onProgress
|
|
1548
1719
|
}) {
|
|
1549
1720
|
if (!silent) {
|
|
1550
|
-
log_default.info(`Opening your browser to ${
|
|
1721
|
+
log_default.info(`Opening your browser to ${action}.`);
|
|
1551
1722
|
log_default.info("If it doesn't open, visit:", transaction.browserAuthUrl);
|
|
1552
1723
|
}
|
|
1553
1724
|
onProgress?.({ type: "browser_opening", url: transaction.browserAuthUrl });
|
|
@@ -1557,9 +1728,7 @@ async function openBrowser({
|
|
|
1557
1728
|
} catch (err) {
|
|
1558
1729
|
const reason = err instanceof Error ? err.message : String(err);
|
|
1559
1730
|
if (!silent) {
|
|
1560
|
-
log_default.info(
|
|
1561
|
-
`Browser did not open automatically to ${authAction}: ${reason}`
|
|
1562
|
-
);
|
|
1731
|
+
log_default.info(`Browser did not open automatically to ${action}: ${reason}`);
|
|
1563
1732
|
log_default.info("Visit this URL manually:", transaction.browserAuthUrl);
|
|
1564
1733
|
}
|
|
1565
1734
|
onProgress?.({
|
|
@@ -1588,61 +1757,10 @@ async function closeServer({
|
|
|
1588
1757
|
});
|
|
1589
1758
|
}
|
|
1590
1759
|
|
|
1591
|
-
// src/utils/auth/oauth-errors.ts
|
|
1592
|
-
var SENSITIVE_OAUTH_FIELDS = [
|
|
1593
|
-
"access_token",
|
|
1594
|
-
"refresh_token",
|
|
1595
|
-
"id_token",
|
|
1596
|
-
"client_secret",
|
|
1597
|
-
"code_verifier",
|
|
1598
|
-
"code_challenge"
|
|
1599
|
-
];
|
|
1600
|
-
function getErrorMessage(error) {
|
|
1601
|
-
return error instanceof Error ? error.message : String(error);
|
|
1602
|
-
}
|
|
1603
|
-
function toCamelCase(field) {
|
|
1604
|
-
return field.replace(
|
|
1605
|
-
/_([a-z])/g,
|
|
1606
|
-
(_match, letter) => letter.toUpperCase()
|
|
1607
|
-
);
|
|
1608
|
-
}
|
|
1609
|
-
function escapeRegExp(value) {
|
|
1610
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1611
|
-
}
|
|
1612
|
-
var sensitiveOauthFieldPattern = Array.from(
|
|
1613
|
-
new Set(
|
|
1614
|
-
SENSITIVE_OAUTH_FIELDS.flatMap((field) => [field, toCamelCase(field)])
|
|
1615
|
-
)
|
|
1616
|
-
).map(escapeRegExp).join("|");
|
|
1617
|
-
var sensitiveQueryParamPattern = new RegExp(
|
|
1618
|
-
`([?&])(${sensitiveOauthFieldPattern})(=)[^&#\\s"'<>]*`,
|
|
1619
|
-
"gi"
|
|
1620
|
-
);
|
|
1621
|
-
function redactSensitiveOauthErrorMessage(message) {
|
|
1622
|
-
return message.replace(
|
|
1623
|
-
sensitiveQueryParamPattern,
|
|
1624
|
-
(_match, prefix, key, separator) => `${prefix}${key}${separator}[REDACTED]`
|
|
1625
|
-
).replace(
|
|
1626
|
-
new RegExp(`"(${sensitiveOauthFieldPattern})"(\\s*:\\s*)"[^"]*"`, "g"),
|
|
1627
|
-
(_match, key, separator) => `"${key}"${separator}"[REDACTED]"`
|
|
1628
|
-
);
|
|
1629
|
-
}
|
|
1630
|
-
function toRedactedOauthError(error) {
|
|
1631
|
-
const message = redactSensitiveOauthErrorMessage(getErrorMessage(error));
|
|
1632
|
-
if (error instanceof ZapierCliValidationError) {
|
|
1633
|
-
return new ZapierCliValidationError(message);
|
|
1634
|
-
}
|
|
1635
|
-
if (error instanceof Error) {
|
|
1636
|
-
const redactedError = new Error(message);
|
|
1637
|
-
redactedError.name = error.name;
|
|
1638
|
-
return redactedError;
|
|
1639
|
-
}
|
|
1640
|
-
return new ZapierCliValidationError(message);
|
|
1641
|
-
}
|
|
1642
|
-
|
|
1643
1760
|
// src/utils/auth/account-auth.ts
|
|
1644
1761
|
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?";
|
|
1645
1762
|
var SIGNUP_RECOVERY_MESSAGE = "Restart `zapier-sdk signup` to generate a fresh signup URL and try again.";
|
|
1763
|
+
var HEADLESS_LOGIN_RECOVERY_MESSAGE = "Restart `zapier-sdk login --headless` to generate a fresh login URL and try again.";
|
|
1646
1764
|
var HEADLESS_SIGNUP_RECOVERY_MESSAGE = "Restart `zapier-sdk signup --headless` to generate a fresh signup URL and try again.";
|
|
1647
1765
|
function getEntryPointLabel(entryPoint) {
|
|
1648
1766
|
return entryPoint === "signup" ? "Signup" : "Login";
|
|
@@ -1762,7 +1880,8 @@ Logging out will delete these credentials and may interrupt other Zapier SDK or
|
|
|
1762
1880
|
Log out and ${getActiveCredentialsAction(entryPoint)}?`
|
|
1763
1881
|
}) : promptlessCredentialResetError(activeCredentials);
|
|
1764
1882
|
if (!confirmed) {
|
|
1765
|
-
|
|
1883
|
+
process.stderr.write(`${flowLabel} cancelled.
|
|
1884
|
+
`);
|
|
1766
1885
|
return false;
|
|
1767
1886
|
}
|
|
1768
1887
|
try {
|
|
@@ -1781,7 +1900,8 @@ Log out and ${getActiveCredentialsAction(entryPoint)}?`
|
|
|
1781
1900
|
message: `${flowLabel} cleanup failed. Reset local session state and continue?`
|
|
1782
1901
|
});
|
|
1783
1902
|
if (!reset) {
|
|
1784
|
-
|
|
1903
|
+
process.stderr.write(`${flowLabel} cancelled.
|
|
1904
|
+
`);
|
|
1785
1905
|
return false;
|
|
1786
1906
|
}
|
|
1787
1907
|
await deleteStoredClientCredentials({
|
|
@@ -1795,7 +1915,8 @@ Log out and ${getActiveCredentialsAction(entryPoint)}?`
|
|
|
1795
1915
|
message: LEGACY_JWT_UPGRADE_PROMPT
|
|
1796
1916
|
}) : promptlessLegacyJwtUpgradeError();
|
|
1797
1917
|
if (!confirmed) {
|
|
1798
|
-
|
|
1918
|
+
process.stderr.write(`${flowLabel} cancelled.
|
|
1919
|
+
`);
|
|
1799
1920
|
return false;
|
|
1800
1921
|
}
|
|
1801
1922
|
}
|
|
@@ -1890,7 +2011,14 @@ async function runOauthForEntryPoint({
|
|
|
1890
2011
|
);
|
|
1891
2012
|
}
|
|
1892
2013
|
return runOauthWithRedaction(
|
|
1893
|
-
() => runLoginOauthFlow({
|
|
2014
|
+
() => runLoginOauthFlow({
|
|
2015
|
+
timeoutMs,
|
|
2016
|
+
pkceCredentials,
|
|
2017
|
+
baseUrl,
|
|
2018
|
+
headless,
|
|
2019
|
+
interactive,
|
|
2020
|
+
recoveryMessage: headless ? HEADLESS_LOGIN_RECOVERY_MESSAGE : void 0
|
|
2021
|
+
})
|
|
1894
2022
|
);
|
|
1895
2023
|
}
|
|
1896
2024
|
async function runAccountAuth({
|
|
@@ -1902,6 +2030,7 @@ async function runAccountAuth({
|
|
|
1902
2030
|
const interactive = !resolveNonInteractive(options);
|
|
1903
2031
|
const resolvedCredentials = await sdk.context.resolveCredentials();
|
|
1904
2032
|
const pkceCredentials = toPkceCredentials(resolvedCredentials);
|
|
2033
|
+
const headless = options.headless === true;
|
|
1905
2034
|
const credentialsBaseUrl = await resolveCredentialsBaseUrl({
|
|
1906
2035
|
...sdk.context,
|
|
1907
2036
|
resolvedCredentials
|
|
@@ -1931,7 +2060,7 @@ async function runAccountAuth({
|
|
|
1931
2060
|
timeoutMs: timeoutSeconds * 1e3,
|
|
1932
2061
|
pkceCredentials,
|
|
1933
2062
|
baseUrl: credentialsBaseUrl,
|
|
1934
|
-
headless
|
|
2063
|
+
headless,
|
|
1935
2064
|
interactive
|
|
1936
2065
|
});
|
|
1937
2066
|
const scopedApi = getOrCreateApiClient({
|
|
@@ -1939,9 +2068,10 @@ async function runAccountAuth({
|
|
|
1939
2068
|
baseUrl: credentialsBaseUrl
|
|
1940
2069
|
});
|
|
1941
2070
|
const profile = await getProfile(scopedApi);
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
2071
|
+
process.stderr.write(`${getProfileMessage(entryPoint, profile.email)}
|
|
2072
|
+
`);
|
|
2073
|
+
process.stderr.write(
|
|
2074
|
+
"\nGenerating credentials so this machine can make authenticated requests on your behalf.\n"
|
|
1945
2075
|
);
|
|
1946
2076
|
const credentialName = providedName ?? await resolveCredentialName({
|
|
1947
2077
|
email: profile.email,
|
|
@@ -1957,11 +2087,12 @@ async function runAccountAuth({
|
|
|
1957
2087
|
useApprovals,
|
|
1958
2088
|
cleanupLogPrefix: entryPoint
|
|
1959
2089
|
});
|
|
1960
|
-
|
|
1961
|
-
`\u2705 Credentials "${credentialName}" created and set as default. You are ready to use the Zapier SDK
|
|
2090
|
+
process.stderr.write(
|
|
2091
|
+
`\u2705 Credentials "${credentialName}" created and set as default. You are ready to use the Zapier SDK.
|
|
2092
|
+
`
|
|
1962
2093
|
);
|
|
1963
2094
|
if (useApprovals) {
|
|
1964
|
-
|
|
2095
|
+
process.stderr.write("\u{1F510} Approvals are enabled for these credentials.\n");
|
|
1965
2096
|
}
|
|
1966
2097
|
emitAccountAuthSuccess({ sdk, profile, clientId });
|
|
1967
2098
|
}
|
|
@@ -1980,7 +2111,10 @@ var LoginSchema = z.object({
|
|
|
1980
2111
|
skipPrompts: z.boolean().optional().meta({
|
|
1981
2112
|
deprecated: true,
|
|
1982
2113
|
deprecationMessage: "Use --non-interactive instead."
|
|
1983
|
-
})
|
|
2114
|
+
}),
|
|
2115
|
+
headless: z.boolean().optional().describe(
|
|
2116
|
+
"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."
|
|
2117
|
+
)
|
|
1984
2118
|
}).describe("Log in to Zapier to access your account");
|
|
1985
2119
|
|
|
1986
2120
|
// src/plugins/login/index.ts
|
|
@@ -4569,7 +4703,7 @@ function collectDeprecationNoticeAndForward(event, onEvent) {
|
|
|
4569
4703
|
// package.json with { type: 'json' }
|
|
4570
4704
|
var package_default = {
|
|
4571
4705
|
name: "@zapier/zapier-sdk-cli",
|
|
4572
|
-
version: "0.
|
|
4706
|
+
version: "0.61.1"};
|
|
4573
4707
|
|
|
4574
4708
|
// src/sdk.ts
|
|
4575
4709
|
injectCliLogin(login_exports);
|
|
@@ -4609,7 +4743,7 @@ function createZapierCliSdk(options = {}) {
|
|
|
4609
4743
|
|
|
4610
4744
|
// package.json
|
|
4611
4745
|
var package_default2 = {
|
|
4612
|
-
version: "0.
|
|
4746
|
+
version: "0.61.1"};
|
|
4613
4747
|
|
|
4614
4748
|
// src/telemetry/builders.ts
|
|
4615
4749
|
function createCliBaseEvent(context = {}) {
|