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