@zapier/zapier-sdk-cli 0.60.0 → 0.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +2 -1
- package/dist/cli.cjs +330 -196
- package/dist/cli.mjs +330 -196
- package/dist/experimental.cjs +329 -195
- package/dist/experimental.mjs +329 -195
- package/dist/index.cjs +330 -196
- package/dist/index.mjs +330 -196
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -102,12 +102,18 @@ var ZapierCliExitError = class extends ZapierCliError {
|
|
|
102
102
|
this.exitCode = exitCode;
|
|
103
103
|
}
|
|
104
104
|
};
|
|
105
|
-
var ZapierCliValidationError = class extends ZapierCliError {
|
|
106
|
-
constructor(message) {
|
|
105
|
+
var ZapierCliValidationError = class _ZapierCliValidationError extends ZapierCliError {
|
|
106
|
+
constructor(message, options = {}) {
|
|
107
107
|
super(message);
|
|
108
|
-
this.name = "ZapierCliValidationError";
|
|
109
|
-
this.code = "ZAPIER_CLI_VALIDATION_ERROR";
|
|
110
108
|
this.exitCode = 1;
|
|
109
|
+
this.name = options.name ?? "ZapierCliValidationError";
|
|
110
|
+
this.code = options.code ?? "ZAPIER_CLI_VALIDATION_ERROR";
|
|
111
|
+
}
|
|
112
|
+
withMessage(message) {
|
|
113
|
+
return new _ZapierCliValidationError(message, {
|
|
114
|
+
name: this.name,
|
|
115
|
+
code: this.code
|
|
116
|
+
});
|
|
111
117
|
}
|
|
112
118
|
};
|
|
113
119
|
var ZapierCliMissingParametersError = class extends ZapierCliError {
|
|
@@ -1579,7 +1585,7 @@ var SHARED_COMMAND_CLI_OPTIONS = [
|
|
|
1579
1585
|
|
|
1580
1586
|
// package.json
|
|
1581
1587
|
var package_default = {
|
|
1582
|
-
version: "0.
|
|
1588
|
+
version: "0.61.0"};
|
|
1583
1589
|
|
|
1584
1590
|
// src/telemetry/builders.ts
|
|
1585
1591
|
function createCliBaseEvent(context = {}) {
|
|
@@ -3765,41 +3771,165 @@ var spinPromise = async (promise, text) => {
|
|
|
3765
3771
|
}
|
|
3766
3772
|
};
|
|
3767
3773
|
|
|
3774
|
+
// src/utils/auth/oauth-errors.ts
|
|
3775
|
+
var OauthFlowTimeoutError = class _OauthFlowTimeoutError extends ZapierCliValidationError {
|
|
3776
|
+
constructor({
|
|
3777
|
+
timeoutMs,
|
|
3778
|
+
message = "OAuth flow timed out"
|
|
3779
|
+
}) {
|
|
3780
|
+
super(message, {
|
|
3781
|
+
name: "OauthFlowTimeoutError",
|
|
3782
|
+
code: "ZAPIER_OAUTH_FLOW_TIMEOUT"
|
|
3783
|
+
});
|
|
3784
|
+
this.timeoutMs = timeoutMs;
|
|
3785
|
+
}
|
|
3786
|
+
withMessage(message) {
|
|
3787
|
+
return new _OauthFlowTimeoutError({ timeoutMs: this.timeoutMs, message });
|
|
3788
|
+
}
|
|
3789
|
+
};
|
|
3790
|
+
var OauthAuthorizationDeniedError = class _OauthAuthorizationDeniedError extends ZapierCliValidationError {
|
|
3791
|
+
constructor({
|
|
3792
|
+
reason,
|
|
3793
|
+
message = "OAuth authorization denied"
|
|
3794
|
+
}) {
|
|
3795
|
+
super(message, {
|
|
3796
|
+
name: "OauthAuthorizationDeniedError",
|
|
3797
|
+
code: "ZAPIER_OAUTH_AUTHORIZATION_DENIED"
|
|
3798
|
+
});
|
|
3799
|
+
this.reason = reason;
|
|
3800
|
+
}
|
|
3801
|
+
withMessage(message) {
|
|
3802
|
+
return new _OauthAuthorizationDeniedError({
|
|
3803
|
+
reason: this.reason,
|
|
3804
|
+
message
|
|
3805
|
+
});
|
|
3806
|
+
}
|
|
3807
|
+
};
|
|
3808
|
+
var OauthFlowError = class _OauthFlowError extends ZapierCliValidationError {
|
|
3809
|
+
constructor({ message }) {
|
|
3810
|
+
super(message, {
|
|
3811
|
+
name: "OauthFlowError",
|
|
3812
|
+
code: "ZAPIER_OAUTH_FLOW"
|
|
3813
|
+
});
|
|
3814
|
+
}
|
|
3815
|
+
withMessage(message) {
|
|
3816
|
+
return new _OauthFlowError({ message });
|
|
3817
|
+
}
|
|
3818
|
+
};
|
|
3819
|
+
var OauthCallbackError = class _OauthCallbackError extends ZapierCliValidationError {
|
|
3820
|
+
constructor({ kind, message }) {
|
|
3821
|
+
super(message, {
|
|
3822
|
+
name: "OauthCallbackError",
|
|
3823
|
+
code: "ZAPIER_OAUTH_CALLBACK"
|
|
3824
|
+
});
|
|
3825
|
+
this.kind = kind;
|
|
3826
|
+
}
|
|
3827
|
+
withMessage(message) {
|
|
3828
|
+
return new _OauthCallbackError({ kind: this.kind, message });
|
|
3829
|
+
}
|
|
3830
|
+
};
|
|
3831
|
+
var OauthTokenExchangeError = class _OauthTokenExchangeError extends ZapierCliValidationError {
|
|
3832
|
+
constructor({ message }) {
|
|
3833
|
+
super(message, {
|
|
3834
|
+
name: "OauthTokenExchangeError",
|
|
3835
|
+
code: "ZAPIER_OAUTH_TOKEN_EXCHANGE"
|
|
3836
|
+
});
|
|
3837
|
+
}
|
|
3838
|
+
withMessage(message) {
|
|
3839
|
+
return new _OauthTokenExchangeError({ message });
|
|
3840
|
+
}
|
|
3841
|
+
};
|
|
3842
|
+
var SENSITIVE_OAUTH_FIELDS = [
|
|
3843
|
+
"access_token",
|
|
3844
|
+
"refresh_token",
|
|
3845
|
+
"id_token",
|
|
3846
|
+
"client_secret",
|
|
3847
|
+
"code_verifier",
|
|
3848
|
+
"code_challenge"
|
|
3849
|
+
];
|
|
3850
|
+
function getErrorMessage(error) {
|
|
3851
|
+
return error instanceof Error ? error.message : String(error);
|
|
3852
|
+
}
|
|
3853
|
+
function toCamelCase(field) {
|
|
3854
|
+
return field.replace(
|
|
3855
|
+
/_([a-z])/g,
|
|
3856
|
+
(_match, letter) => letter.toUpperCase()
|
|
3857
|
+
);
|
|
3858
|
+
}
|
|
3859
|
+
function escapeRegExp(value) {
|
|
3860
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3861
|
+
}
|
|
3862
|
+
var sensitiveOauthFieldPattern = Array.from(
|
|
3863
|
+
new Set(
|
|
3864
|
+
SENSITIVE_OAUTH_FIELDS.flatMap((field) => [field, toCamelCase(field)])
|
|
3865
|
+
)
|
|
3866
|
+
).map(escapeRegExp).join("|");
|
|
3867
|
+
var sensitiveQueryParamPattern = new RegExp(
|
|
3868
|
+
`([?&])(${sensitiveOauthFieldPattern})(=)[^&#\\s"'<>]*`,
|
|
3869
|
+
"gi"
|
|
3870
|
+
);
|
|
3871
|
+
function redactSensitiveOauthErrorMessage(message) {
|
|
3872
|
+
return message.replace(
|
|
3873
|
+
sensitiveQueryParamPattern,
|
|
3874
|
+
(_match, prefix, key, separator) => `${prefix}${key}${separator}[REDACTED]`
|
|
3875
|
+
).replace(
|
|
3876
|
+
new RegExp(`"(${sensitiveOauthFieldPattern})"(\\s*:\\s*)"[^"]*"`, "g"),
|
|
3877
|
+
(_match, key, separator) => `"${key}"${separator}"[REDACTED]"`
|
|
3878
|
+
);
|
|
3879
|
+
}
|
|
3880
|
+
function toRedactedOauthError(error) {
|
|
3881
|
+
const message = redactSensitiveOauthErrorMessage(getErrorMessage(error));
|
|
3882
|
+
if (error instanceof ZapierCliValidationError) {
|
|
3883
|
+
return error.withMessage(message);
|
|
3884
|
+
}
|
|
3885
|
+
return new OauthFlowError({ message });
|
|
3886
|
+
}
|
|
3887
|
+
function toOauthTokenExchangeError(error) {
|
|
3888
|
+
return new OauthTokenExchangeError({
|
|
3889
|
+
message: redactSensitiveOauthErrorMessage(getErrorMessage(error))
|
|
3890
|
+
});
|
|
3891
|
+
}
|
|
3892
|
+
|
|
3768
3893
|
// src/utils/auth/oauth-callback.ts
|
|
3769
3894
|
function getCallbackCode({
|
|
3770
3895
|
callbackUrl,
|
|
3771
|
-
transaction
|
|
3772
|
-
recoveryMessage
|
|
3896
|
+
transaction
|
|
3773
3897
|
}) {
|
|
3774
3898
|
let parsed;
|
|
3775
3899
|
try {
|
|
3776
3900
|
parsed = new URL(callbackUrl.trim());
|
|
3777
3901
|
} catch {
|
|
3778
|
-
throw new
|
|
3779
|
-
|
|
3780
|
-
|
|
3902
|
+
throw new OauthCallbackError({
|
|
3903
|
+
kind: "invalid_url",
|
|
3904
|
+
message: "Paste the final OAuth callback URL from your browser."
|
|
3905
|
+
});
|
|
3781
3906
|
}
|
|
3782
3907
|
const expected = new URL(transaction.redirectUri);
|
|
3783
3908
|
if (parsed.protocol !== "http:" || parsed.hostname !== expected.hostname || parsed.pathname !== expected.pathname || parsed.port !== expected.port) {
|
|
3784
|
-
throw new
|
|
3785
|
-
|
|
3786
|
-
|
|
3909
|
+
throw new OauthCallbackError({
|
|
3910
|
+
kind: "redirect_mismatch",
|
|
3911
|
+
message: `Expected the final OAuth callback URL to start with ${transaction.redirectUri}.`
|
|
3912
|
+
});
|
|
3787
3913
|
}
|
|
3788
3914
|
if (parsed.searchParams.get("state") !== transaction.state) {
|
|
3789
|
-
throw new
|
|
3790
|
-
|
|
3791
|
-
|
|
3915
|
+
throw new OauthCallbackError({
|
|
3916
|
+
kind: "state_mismatch",
|
|
3917
|
+
message: "OAuth state mismatch."
|
|
3918
|
+
});
|
|
3792
3919
|
}
|
|
3793
3920
|
if (parsed.searchParams.has("error")) {
|
|
3794
|
-
throw new
|
|
3795
|
-
|
|
3796
|
-
|
|
3921
|
+
throw new OauthAuthorizationDeniedError({
|
|
3922
|
+
reason: String(
|
|
3923
|
+
parsed.searchParams.get("error_description") ?? parsed.searchParams.get("error")
|
|
3924
|
+
)
|
|
3925
|
+
});
|
|
3797
3926
|
}
|
|
3798
3927
|
const code = parsed.searchParams.get("code");
|
|
3799
3928
|
if (!code) {
|
|
3800
|
-
throw new
|
|
3801
|
-
|
|
3802
|
-
|
|
3929
|
+
throw new OauthCallbackError({
|
|
3930
|
+
kind: "missing_code",
|
|
3931
|
+
message: "No authorization code found in the pasted callback URL."
|
|
3932
|
+
});
|
|
3803
3933
|
}
|
|
3804
3934
|
return code;
|
|
3805
3935
|
}
|
|
@@ -3914,7 +4044,9 @@ async function exchangeOauthCode({
|
|
|
3914
4044
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
3915
4045
|
}
|
|
3916
4046
|
}
|
|
3917
|
-
)
|
|
4047
|
+
).catch((error) => {
|
|
4048
|
+
throw toOauthTokenExchangeError(error);
|
|
4049
|
+
});
|
|
3918
4050
|
return {
|
|
3919
4051
|
accessToken: data.access_token,
|
|
3920
4052
|
refreshToken: data.refresh_token,
|
|
@@ -3923,19 +4055,15 @@ async function exchangeOauthCode({
|
|
|
3923
4055
|
}
|
|
3924
4056
|
|
|
3925
4057
|
// src/utils/auth/oauth-flow.ts
|
|
3926
|
-
var
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
this.name = "OauthFlowTimeoutError";
|
|
3931
|
-
}
|
|
4058
|
+
var LOGIN_OAUTH_COPY = {
|
|
4059
|
+
flowName: "Login",
|
|
4060
|
+
action: "log in",
|
|
4061
|
+
urlLabel: "login URL"
|
|
3932
4062
|
};
|
|
3933
|
-
var
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
this.name = "OauthAuthorizationDeniedError";
|
|
3938
|
-
}
|
|
4063
|
+
var SIGNUP_OAUTH_COPY = {
|
|
4064
|
+
flowName: "Signup",
|
|
4065
|
+
action: "sign up",
|
|
4066
|
+
urlLabel: "signup URL"
|
|
3939
4067
|
};
|
|
3940
4068
|
function findAvailablePort() {
|
|
3941
4069
|
return new Promise((resolve4, reject) => {
|
|
@@ -3950,70 +4078,86 @@ function findAvailablePort() {
|
|
|
3950
4078
|
tryPort(LOGIN_PORTS[portIndex++]);
|
|
3951
4079
|
} else if (err.code === "EADDRINUSE") {
|
|
3952
4080
|
reject(
|
|
3953
|
-
new
|
|
3954
|
-
`All configured OAuth callback ports are busy: ${LOGIN_PORTS.join(", ")}. Please try again later or close applications using these ports.`
|
|
3955
|
-
)
|
|
4081
|
+
new OauthFlowError({
|
|
4082
|
+
message: `All configured OAuth callback ports are busy: ${LOGIN_PORTS.join(", ")}. Please try again later or close applications using these ports.`
|
|
4083
|
+
})
|
|
3956
4084
|
);
|
|
3957
4085
|
} else {
|
|
3958
4086
|
reject(err);
|
|
3959
4087
|
}
|
|
3960
4088
|
});
|
|
3961
4089
|
};
|
|
3962
|
-
if (LOGIN_PORTS.length > 0)
|
|
3963
|
-
|
|
4090
|
+
if (LOGIN_PORTS.length > 0) {
|
|
4091
|
+
tryPort(LOGIN_PORTS[portIndex++]);
|
|
4092
|
+
return;
|
|
4093
|
+
}
|
|
4094
|
+
reject(
|
|
4095
|
+
new OauthFlowError({ message: "No OAuth callback ports configured" })
|
|
4096
|
+
);
|
|
3964
4097
|
});
|
|
3965
4098
|
}
|
|
3966
4099
|
async function runLoginOauthFlow(options) {
|
|
3967
|
-
return
|
|
3968
|
-
|
|
4100
|
+
return runOauthFlowForEntryPoint({
|
|
4101
|
+
options,
|
|
3969
4102
|
entryPoint: "login",
|
|
3970
|
-
|
|
3971
|
-
flowName: "Login"
|
|
4103
|
+
copy: LOGIN_OAUTH_COPY
|
|
3972
4104
|
});
|
|
3973
4105
|
}
|
|
3974
4106
|
async function runSignupOauthFlow(options) {
|
|
4107
|
+
return runOauthFlowForEntryPoint({
|
|
4108
|
+
options,
|
|
4109
|
+
entryPoint: "signup",
|
|
4110
|
+
copy: SIGNUP_OAUTH_COPY
|
|
4111
|
+
});
|
|
4112
|
+
}
|
|
4113
|
+
function runOauthFlowForEntryPoint({
|
|
4114
|
+
options,
|
|
4115
|
+
entryPoint,
|
|
4116
|
+
copy
|
|
4117
|
+
}) {
|
|
3975
4118
|
if (options.headless) {
|
|
3976
4119
|
return runOauthFlowEntryPoint({
|
|
3977
4120
|
...options,
|
|
3978
|
-
entryPoint
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
headless: true
|
|
4121
|
+
entryPoint,
|
|
4122
|
+
headless: true,
|
|
4123
|
+
copy
|
|
3982
4124
|
});
|
|
3983
4125
|
}
|
|
3984
4126
|
return runOauthFlowEntryPoint({
|
|
3985
4127
|
...options,
|
|
3986
|
-
entryPoint
|
|
3987
|
-
|
|
3988
|
-
|
|
4128
|
+
entryPoint,
|
|
4129
|
+
copy,
|
|
4130
|
+
headless: false
|
|
3989
4131
|
});
|
|
3990
4132
|
}
|
|
3991
|
-
async function runOauthFlowEntryPoint({
|
|
3992
|
-
flowName,
|
|
3993
|
-
...options
|
|
3994
|
-
}) {
|
|
4133
|
+
async function runOauthFlowEntryPoint(options) {
|
|
3995
4134
|
try {
|
|
3996
|
-
return options.headless ? await
|
|
4135
|
+
return options.headless ? await runHeadlessOauthFlow(options) : await runOauthFlow(options);
|
|
3997
4136
|
} catch (error) {
|
|
3998
4137
|
if (error instanceof OauthFlowTimeoutError) {
|
|
3999
|
-
throw
|
|
4138
|
+
throw error.withMessage(
|
|
4000
4139
|
withRecoveryMessage(
|
|
4001
|
-
`${flowName} timed out after ${Math.round(error.timeoutMs / 1e3)} seconds.`,
|
|
4140
|
+
`${options.copy.flowName} timed out after ${Math.round(error.timeoutMs / 1e3)} seconds.`,
|
|
4002
4141
|
options.recoveryMessage
|
|
4003
4142
|
)
|
|
4004
4143
|
);
|
|
4005
4144
|
}
|
|
4006
4145
|
if (error instanceof OauthAuthorizationDeniedError) {
|
|
4007
|
-
throw
|
|
4146
|
+
throw error.withMessage(
|
|
4008
4147
|
withRecoveryMessage(
|
|
4009
4148
|
`Authorization denied: ${error.reason}.`,
|
|
4010
4149
|
options.recoveryMessage
|
|
4011
4150
|
)
|
|
4012
4151
|
);
|
|
4013
4152
|
}
|
|
4153
|
+
if (error instanceof OauthCallbackError && options.recoveryMessage) {
|
|
4154
|
+
throw error.withMessage(
|
|
4155
|
+
withRecoveryMessage(error.message, options.recoveryMessage)
|
|
4156
|
+
);
|
|
4157
|
+
}
|
|
4014
4158
|
if (error instanceof ZapierCliUserCancellationError && !options.silent) {
|
|
4015
4159
|
log_default.info(`
|
|
4016
|
-
\u274C ${flowName} cancelled by user`);
|
|
4160
|
+
\u274C ${options.copy.flowName} cancelled by user`);
|
|
4017
4161
|
}
|
|
4018
4162
|
throw error;
|
|
4019
4163
|
}
|
|
@@ -4021,12 +4165,22 @@ async function runOauthFlowEntryPoint({
|
|
|
4021
4165
|
function withRecoveryMessage(message, recoveryMessage) {
|
|
4022
4166
|
return recoveryMessage ? `${message} ${recoveryMessage}` : message;
|
|
4023
4167
|
}
|
|
4168
|
+
function createMissingHeadlessCallbackUrlError() {
|
|
4169
|
+
return new OauthCallbackError({
|
|
4170
|
+
kind: "missing_callback_url",
|
|
4171
|
+
message: "Paste the final OAuth callback URL from your browser."
|
|
4172
|
+
});
|
|
4173
|
+
}
|
|
4174
|
+
function writeHeadlessOauthStatus(message) {
|
|
4175
|
+
process.stderr.write(`${message}
|
|
4176
|
+
`);
|
|
4177
|
+
}
|
|
4024
4178
|
async function runOauthFlow({
|
|
4025
4179
|
timeoutMs = LOGIN_TIMEOUT_MS,
|
|
4026
4180
|
pkceCredentials,
|
|
4027
4181
|
baseUrl: baseUrl2,
|
|
4028
4182
|
entryPoint,
|
|
4029
|
-
|
|
4183
|
+
copy,
|
|
4030
4184
|
silent = false,
|
|
4031
4185
|
onProgress
|
|
4032
4186
|
}) {
|
|
@@ -4041,7 +4195,7 @@ async function runOauthFlow({
|
|
|
4041
4195
|
const code = await collectLocalCallbackCode({
|
|
4042
4196
|
transaction,
|
|
4043
4197
|
timeoutMs,
|
|
4044
|
-
|
|
4198
|
+
action: copy.action,
|
|
4045
4199
|
silent,
|
|
4046
4200
|
onProgress
|
|
4047
4201
|
});
|
|
@@ -4055,92 +4209,104 @@ async function runOauthFlow({
|
|
|
4055
4209
|
}
|
|
4056
4210
|
async function readHeadlessCallbackUrl({
|
|
4057
4211
|
timeoutMs,
|
|
4058
|
-
interactive
|
|
4059
|
-
recoveryMessage
|
|
4212
|
+
interactive
|
|
4060
4213
|
}) {
|
|
4061
|
-
const timeoutMessage = withRecoveryMessage(
|
|
4062
|
-
`Signup timed out after ${Math.round(timeoutMs / 1e3)} seconds.`,
|
|
4063
|
-
recoveryMessage
|
|
4064
|
-
);
|
|
4065
|
-
const missingCallbackUrlMessage = withRecoveryMessage(
|
|
4066
|
-
"Paste the final OAuth callback URL from your browser.",
|
|
4067
|
-
recoveryMessage
|
|
4068
|
-
);
|
|
4069
4214
|
const rl = promises$1.createInterface({ input: process.stdin, output: process.stderr });
|
|
4070
4215
|
const abortController = new AbortController();
|
|
4071
4216
|
const timeoutTimer = setTimeout(() => abortController.abort(), timeoutMs);
|
|
4072
|
-
const readUrl =
|
|
4073
|
-
signal: abortController.signal
|
|
4074
|
-
}) : new Promise((resolve4, reject) => {
|
|
4217
|
+
const readUrl = new Promise((resolve4, reject) => {
|
|
4075
4218
|
let settled = false;
|
|
4076
|
-
const
|
|
4219
|
+
const handleLine = (value) => settleResolve(value);
|
|
4220
|
+
const handleAbort = () => settleReject(new OauthFlowTimeoutError({ timeoutMs }));
|
|
4221
|
+
const handleClose = () => settleReject(createMissingHeadlessCallbackUrlError());
|
|
4222
|
+
const handleError = (error) => settleReject(error);
|
|
4223
|
+
const handleCancellation = () => settleReject(new ZapierCliUserCancellationError());
|
|
4224
|
+
const cleanupListeners = () => {
|
|
4225
|
+
abortController.signal.removeEventListener("abort", handleAbort);
|
|
4226
|
+
rl.off("line", handleLine);
|
|
4227
|
+
rl.off("close", handleClose);
|
|
4228
|
+
rl.off("error", handleError);
|
|
4229
|
+
rl.off("SIGINT", handleCancellation);
|
|
4230
|
+
process.off("SIGINT", handleCancellation);
|
|
4231
|
+
process.off("SIGTERM", handleCancellation);
|
|
4232
|
+
};
|
|
4233
|
+
function settleResolve(value) {
|
|
4234
|
+
if (settled) return;
|
|
4077
4235
|
settled = true;
|
|
4236
|
+
cleanupListeners();
|
|
4078
4237
|
resolve4(value);
|
|
4079
|
-
}
|
|
4080
|
-
|
|
4238
|
+
}
|
|
4239
|
+
function settleReject(error) {
|
|
4081
4240
|
if (settled) return;
|
|
4082
4241
|
settled = true;
|
|
4242
|
+
cleanupListeners();
|
|
4083
4243
|
reject(error);
|
|
4084
|
-
}
|
|
4085
|
-
abortController.signal.addEventListener(
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
);
|
|
4090
|
-
rl.once("
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4244
|
+
}
|
|
4245
|
+
abortController.signal.addEventListener("abort", handleAbort, {
|
|
4246
|
+
once: true
|
|
4247
|
+
});
|
|
4248
|
+
rl.once("close", handleClose);
|
|
4249
|
+
rl.once("error", handleError);
|
|
4250
|
+
rl.once("SIGINT", handleCancellation);
|
|
4251
|
+
process.once("SIGINT", handleCancellation);
|
|
4252
|
+
process.once("SIGTERM", handleCancellation);
|
|
4253
|
+
if (interactive) {
|
|
4254
|
+
void rl.question("Paste the final OAuth callback URL: ", {
|
|
4255
|
+
signal: abortController.signal
|
|
4256
|
+
}).then(settleResolve).catch((error) => {
|
|
4257
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
4258
|
+
settleReject(new OauthFlowTimeoutError({ timeoutMs }));
|
|
4259
|
+
return;
|
|
4260
|
+
}
|
|
4261
|
+
settleReject(error);
|
|
4262
|
+
});
|
|
4263
|
+
return;
|
|
4264
|
+
}
|
|
4265
|
+
rl.once("line", handleLine);
|
|
4096
4266
|
});
|
|
4097
4267
|
try {
|
|
4098
|
-
return await readUrl
|
|
4099
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
4100
|
-
throw new Error(timeoutMessage);
|
|
4101
|
-
}
|
|
4102
|
-
throw error;
|
|
4103
|
-
});
|
|
4268
|
+
return await readUrl;
|
|
4104
4269
|
} finally {
|
|
4105
4270
|
clearTimeout(timeoutTimer);
|
|
4106
4271
|
rl.close();
|
|
4107
4272
|
}
|
|
4108
4273
|
}
|
|
4109
|
-
async function
|
|
4274
|
+
async function runHeadlessOauthFlow({
|
|
4110
4275
|
timeoutMs = LOGIN_TIMEOUT_MS,
|
|
4111
4276
|
pkceCredentials,
|
|
4112
4277
|
baseUrl: baseUrl2,
|
|
4278
|
+
entryPoint,
|
|
4113
4279
|
interactive = true,
|
|
4114
4280
|
onProgress,
|
|
4115
|
-
|
|
4281
|
+
copy
|
|
4116
4282
|
}) {
|
|
4117
4283
|
const port = LOGIN_PORTS[0];
|
|
4118
4284
|
const transaction = await prepareOauthTransaction({
|
|
4119
4285
|
pkceCredentials,
|
|
4120
4286
|
baseUrl: baseUrl2,
|
|
4121
4287
|
redirectUri: `http://${OAUTH_LOOPBACK_HOST}:${port}/oauth`,
|
|
4122
|
-
entryPoint
|
|
4288
|
+
entryPoint
|
|
4123
4289
|
});
|
|
4124
|
-
|
|
4125
|
-
|
|
4290
|
+
writeHeadlessOauthStatus(
|
|
4291
|
+
`Use this mode to ${copy.action} from a machine that has no browser.`
|
|
4292
|
+
);
|
|
4293
|
+
writeHeadlessOauthStatus(
|
|
4294
|
+
`Open this ${copy.urlLabel} in a browser on another machine:`
|
|
4126
4295
|
);
|
|
4127
|
-
console.log("Open this signup URL in a browser on another machine:");
|
|
4128
4296
|
console.log(transaction.browserAuthUrl);
|
|
4129
|
-
|
|
4297
|
+
writeHeadlessOauthStatus(
|
|
4130
4298
|
`When the browser lands on ${transaction.redirectUri} and cannot connect, paste the full final URL back here.`
|
|
4131
4299
|
);
|
|
4132
4300
|
const callbackUrl = await readHeadlessCallbackUrl({
|
|
4133
4301
|
timeoutMs,
|
|
4134
|
-
interactive
|
|
4135
|
-
recoveryMessage
|
|
4302
|
+
interactive
|
|
4136
4303
|
});
|
|
4137
4304
|
const code = getCallbackCode({
|
|
4138
4305
|
callbackUrl,
|
|
4139
|
-
transaction
|
|
4140
|
-
recoveryMessage
|
|
4306
|
+
transaction
|
|
4141
4307
|
});
|
|
4142
4308
|
onProgress?.({ type: "callback_accepted" });
|
|
4143
|
-
|
|
4309
|
+
writeHeadlessOauthStatus("Exchanging authorization code for tokens...");
|
|
4144
4310
|
onProgress?.({ type: "token_exchange_started" });
|
|
4145
4311
|
const tokens = await exchangeOauthCode({ ...transaction, code });
|
|
4146
4312
|
onProgress?.({ type: "token_exchange_completed" });
|
|
@@ -4149,7 +4315,7 @@ async function runHeadlessSignupOauthFlow({
|
|
|
4149
4315
|
async function collectLocalCallbackCode({
|
|
4150
4316
|
transaction,
|
|
4151
4317
|
timeoutMs,
|
|
4152
|
-
|
|
4318
|
+
action,
|
|
4153
4319
|
silent,
|
|
4154
4320
|
onProgress
|
|
4155
4321
|
}) {
|
|
@@ -4157,21 +4323,26 @@ async function collectLocalCallbackCode({
|
|
|
4157
4323
|
const app = express__default.default();
|
|
4158
4324
|
app.get("/oauth", (req, res) => {
|
|
4159
4325
|
res.setHeader("Connection", "close");
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
);
|
|
4168
|
-
|
|
4169
|
-
} else if (!req.query.code) {
|
|
4170
|
-
reject(new Error("No authorization code received"));
|
|
4171
|
-
res.end("No authorization code received. You can close this tab.");
|
|
4172
|
-
} else {
|
|
4173
|
-
resolve4(String(req.query.code));
|
|
4326
|
+
try {
|
|
4327
|
+
const code = getCallbackCode({
|
|
4328
|
+
callbackUrl: new URL(
|
|
4329
|
+
req.originalUrl,
|
|
4330
|
+
transaction.redirectUri
|
|
4331
|
+
).toString(),
|
|
4332
|
+
transaction
|
|
4333
|
+
});
|
|
4334
|
+
resolve4(code);
|
|
4174
4335
|
res.end("You can now close this tab and return to the CLI.");
|
|
4336
|
+
} catch (error) {
|
|
4337
|
+
if (error instanceof OauthCallbackError && error.kind === "state_mismatch") {
|
|
4338
|
+
res.status(400).end("Invalid state. You can close this tab.");
|
|
4339
|
+
} else if (error instanceof OauthAuthorizationDeniedError) {
|
|
4340
|
+
reject(error);
|
|
4341
|
+
res.end("Authorization was denied. You can close this tab.");
|
|
4342
|
+
} else {
|
|
4343
|
+
reject(error);
|
|
4344
|
+
res.end("No authorization code received. You can close this tab.");
|
|
4345
|
+
}
|
|
4175
4346
|
}
|
|
4176
4347
|
});
|
|
4177
4348
|
const server = app.listen(
|
|
@@ -4192,19 +4363,19 @@ async function collectLocalCallbackCode({
|
|
|
4192
4363
|
let timeoutTimer;
|
|
4193
4364
|
try {
|
|
4194
4365
|
await waitForServerListening(server);
|
|
4195
|
-
await openBrowser({ transaction,
|
|
4366
|
+
await openBrowser({ transaction, action, silent, onProgress });
|
|
4196
4367
|
const waitForCode = Promise.race([
|
|
4197
4368
|
promise,
|
|
4198
4369
|
new Promise((_resolve, rejectTimeout) => {
|
|
4199
4370
|
timeoutTimer = setTimeout(() => {
|
|
4200
|
-
rejectTimeout(new OauthFlowTimeoutError(timeoutMs));
|
|
4371
|
+
rejectTimeout(new OauthFlowTimeoutError({ timeoutMs }));
|
|
4201
4372
|
}, timeoutMs);
|
|
4202
4373
|
})
|
|
4203
4374
|
]);
|
|
4204
4375
|
onProgress?.({ type: "callback_waiting" });
|
|
4205
4376
|
return silent ? await waitForCode : await spinPromise(
|
|
4206
4377
|
waitForCode,
|
|
4207
|
-
`Waiting for you to ${
|
|
4378
|
+
`Waiting for you to ${action} and authorize`
|
|
4208
4379
|
);
|
|
4209
4380
|
} finally {
|
|
4210
4381
|
if (timeoutTimer) clearTimeout(timeoutTimer);
|
|
@@ -4234,12 +4405,12 @@ async function waitForServerListening(server) {
|
|
|
4234
4405
|
}
|
|
4235
4406
|
async function openBrowser({
|
|
4236
4407
|
transaction,
|
|
4237
|
-
|
|
4408
|
+
action,
|
|
4238
4409
|
silent,
|
|
4239
4410
|
onProgress
|
|
4240
4411
|
}) {
|
|
4241
4412
|
if (!silent) {
|
|
4242
|
-
log_default.info(`Opening your browser to ${
|
|
4413
|
+
log_default.info(`Opening your browser to ${action}.`);
|
|
4243
4414
|
log_default.info("If it doesn't open, visit:", transaction.browserAuthUrl);
|
|
4244
4415
|
}
|
|
4245
4416
|
onProgress?.({ type: "browser_opening", url: transaction.browserAuthUrl });
|
|
@@ -4249,9 +4420,7 @@ async function openBrowser({
|
|
|
4249
4420
|
} catch (err) {
|
|
4250
4421
|
const reason = err instanceof Error ? err.message : String(err);
|
|
4251
4422
|
if (!silent) {
|
|
4252
|
-
log_default.info(
|
|
4253
|
-
`Browser did not open automatically to ${authAction}: ${reason}`
|
|
4254
|
-
);
|
|
4423
|
+
log_default.info(`Browser did not open automatically to ${action}: ${reason}`);
|
|
4255
4424
|
log_default.info("Visit this URL manually:", transaction.browserAuthUrl);
|
|
4256
4425
|
}
|
|
4257
4426
|
onProgress?.({
|
|
@@ -4280,61 +4449,10 @@ async function closeServer({
|
|
|
4280
4449
|
});
|
|
4281
4450
|
}
|
|
4282
4451
|
|
|
4283
|
-
// src/utils/auth/oauth-errors.ts
|
|
4284
|
-
var SENSITIVE_OAUTH_FIELDS = [
|
|
4285
|
-
"access_token",
|
|
4286
|
-
"refresh_token",
|
|
4287
|
-
"id_token",
|
|
4288
|
-
"client_secret",
|
|
4289
|
-
"code_verifier",
|
|
4290
|
-
"code_challenge"
|
|
4291
|
-
];
|
|
4292
|
-
function getErrorMessage(error) {
|
|
4293
|
-
return error instanceof Error ? error.message : String(error);
|
|
4294
|
-
}
|
|
4295
|
-
function toCamelCase(field) {
|
|
4296
|
-
return field.replace(
|
|
4297
|
-
/_([a-z])/g,
|
|
4298
|
-
(_match, letter) => letter.toUpperCase()
|
|
4299
|
-
);
|
|
4300
|
-
}
|
|
4301
|
-
function escapeRegExp(value) {
|
|
4302
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4303
|
-
}
|
|
4304
|
-
var sensitiveOauthFieldPattern = Array.from(
|
|
4305
|
-
new Set(
|
|
4306
|
-
SENSITIVE_OAUTH_FIELDS.flatMap((field) => [field, toCamelCase(field)])
|
|
4307
|
-
)
|
|
4308
|
-
).map(escapeRegExp).join("|");
|
|
4309
|
-
var sensitiveQueryParamPattern = new RegExp(
|
|
4310
|
-
`([?&])(${sensitiveOauthFieldPattern})(=)[^&#\\s"'<>]*`,
|
|
4311
|
-
"gi"
|
|
4312
|
-
);
|
|
4313
|
-
function redactSensitiveOauthErrorMessage(message) {
|
|
4314
|
-
return message.replace(
|
|
4315
|
-
sensitiveQueryParamPattern,
|
|
4316
|
-
(_match, prefix, key, separator) => `${prefix}${key}${separator}[REDACTED]`
|
|
4317
|
-
).replace(
|
|
4318
|
-
new RegExp(`"(${sensitiveOauthFieldPattern})"(\\s*:\\s*)"[^"]*"`, "g"),
|
|
4319
|
-
(_match, key, separator) => `"${key}"${separator}"[REDACTED]"`
|
|
4320
|
-
);
|
|
4321
|
-
}
|
|
4322
|
-
function toRedactedOauthError(error) {
|
|
4323
|
-
const message = redactSensitiveOauthErrorMessage(getErrorMessage(error));
|
|
4324
|
-
if (error instanceof ZapierCliValidationError) {
|
|
4325
|
-
return new ZapierCliValidationError(message);
|
|
4326
|
-
}
|
|
4327
|
-
if (error instanceof Error) {
|
|
4328
|
-
const redactedError = new Error(message);
|
|
4329
|
-
redactedError.name = error.name;
|
|
4330
|
-
return redactedError;
|
|
4331
|
-
}
|
|
4332
|
-
return new ZapierCliValidationError(message);
|
|
4333
|
-
}
|
|
4334
|
-
|
|
4335
4452
|
// src/utils/auth/account-auth.ts
|
|
4336
4453
|
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?";
|
|
4337
4454
|
var SIGNUP_RECOVERY_MESSAGE = "Restart `zapier-sdk signup` to generate a fresh signup URL and try again.";
|
|
4455
|
+
var HEADLESS_LOGIN_RECOVERY_MESSAGE = "Restart `zapier-sdk login --headless` to generate a fresh login URL and try again.";
|
|
4338
4456
|
var HEADLESS_SIGNUP_RECOVERY_MESSAGE = "Restart `zapier-sdk signup --headless` to generate a fresh signup URL and try again.";
|
|
4339
4457
|
function getEntryPointLabel(entryPoint) {
|
|
4340
4458
|
return entryPoint === "signup" ? "Signup" : "Login";
|
|
@@ -4454,7 +4572,8 @@ Logging out will delete these credentials and may interrupt other Zapier SDK or
|
|
|
4454
4572
|
Log out and ${getActiveCredentialsAction(entryPoint)}?`
|
|
4455
4573
|
}) : promptlessCredentialResetError(activeCredentials);
|
|
4456
4574
|
if (!confirmed) {
|
|
4457
|
-
|
|
4575
|
+
process.stderr.write(`${flowLabel} cancelled.
|
|
4576
|
+
`);
|
|
4458
4577
|
return false;
|
|
4459
4578
|
}
|
|
4460
4579
|
try {
|
|
@@ -4473,7 +4592,8 @@ Log out and ${getActiveCredentialsAction(entryPoint)}?`
|
|
|
4473
4592
|
message: `${flowLabel} cleanup failed. Reset local session state and continue?`
|
|
4474
4593
|
});
|
|
4475
4594
|
if (!reset) {
|
|
4476
|
-
|
|
4595
|
+
process.stderr.write(`${flowLabel} cancelled.
|
|
4596
|
+
`);
|
|
4477
4597
|
return false;
|
|
4478
4598
|
}
|
|
4479
4599
|
await deleteStoredClientCredentials({
|
|
@@ -4487,7 +4607,8 @@ Log out and ${getActiveCredentialsAction(entryPoint)}?`
|
|
|
4487
4607
|
message: LEGACY_JWT_UPGRADE_PROMPT
|
|
4488
4608
|
}) : promptlessLegacyJwtUpgradeError();
|
|
4489
4609
|
if (!confirmed) {
|
|
4490
|
-
|
|
4610
|
+
process.stderr.write(`${flowLabel} cancelled.
|
|
4611
|
+
`);
|
|
4491
4612
|
return false;
|
|
4492
4613
|
}
|
|
4493
4614
|
}
|
|
@@ -4582,7 +4703,14 @@ async function runOauthForEntryPoint({
|
|
|
4582
4703
|
);
|
|
4583
4704
|
}
|
|
4584
4705
|
return runOauthWithRedaction(
|
|
4585
|
-
() => runLoginOauthFlow({
|
|
4706
|
+
() => runLoginOauthFlow({
|
|
4707
|
+
timeoutMs,
|
|
4708
|
+
pkceCredentials,
|
|
4709
|
+
baseUrl: baseUrl2,
|
|
4710
|
+
headless,
|
|
4711
|
+
interactive,
|
|
4712
|
+
recoveryMessage: headless ? HEADLESS_LOGIN_RECOVERY_MESSAGE : void 0
|
|
4713
|
+
})
|
|
4586
4714
|
);
|
|
4587
4715
|
}
|
|
4588
4716
|
async function runAccountAuth({
|
|
@@ -4594,6 +4722,7 @@ async function runAccountAuth({
|
|
|
4594
4722
|
const interactive = !resolveNonInteractive(options);
|
|
4595
4723
|
const resolvedCredentials = await sdk.context.resolveCredentials();
|
|
4596
4724
|
const pkceCredentials = toPkceCredentials(resolvedCredentials);
|
|
4725
|
+
const headless = options.headless === true;
|
|
4597
4726
|
const credentialsBaseUrl2 = await resolveCredentialsBaseUrl({
|
|
4598
4727
|
...sdk.context,
|
|
4599
4728
|
resolvedCredentials
|
|
@@ -4623,7 +4752,7 @@ async function runAccountAuth({
|
|
|
4623
4752
|
timeoutMs: timeoutSeconds * 1e3,
|
|
4624
4753
|
pkceCredentials,
|
|
4625
4754
|
baseUrl: credentialsBaseUrl2,
|
|
4626
|
-
headless
|
|
4755
|
+
headless,
|
|
4627
4756
|
interactive
|
|
4628
4757
|
});
|
|
4629
4758
|
const scopedApi = zapierSdk.getOrCreateApiClient({
|
|
@@ -4631,9 +4760,10 @@ async function runAccountAuth({
|
|
|
4631
4760
|
baseUrl: credentialsBaseUrl2
|
|
4632
4761
|
});
|
|
4633
4762
|
const profile = await getProfile(scopedApi);
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4763
|
+
process.stderr.write(`${getProfileMessage(entryPoint, profile.email)}
|
|
4764
|
+
`);
|
|
4765
|
+
process.stderr.write(
|
|
4766
|
+
"\nGenerating credentials so this machine can make authenticated requests on your behalf.\n"
|
|
4637
4767
|
);
|
|
4638
4768
|
const credentialName = providedName ?? await resolveCredentialName({
|
|
4639
4769
|
email: profile.email,
|
|
@@ -4649,11 +4779,12 @@ async function runAccountAuth({
|
|
|
4649
4779
|
useApprovals,
|
|
4650
4780
|
cleanupLogPrefix: entryPoint
|
|
4651
4781
|
});
|
|
4652
|
-
|
|
4653
|
-
`\u2705 Credentials "${credentialName}" created and set as default. You are ready to use the Zapier SDK
|
|
4782
|
+
process.stderr.write(
|
|
4783
|
+
`\u2705 Credentials "${credentialName}" created and set as default. You are ready to use the Zapier SDK.
|
|
4784
|
+
`
|
|
4654
4785
|
);
|
|
4655
4786
|
if (useApprovals) {
|
|
4656
|
-
|
|
4787
|
+
process.stderr.write("\u{1F510} Approvals are enabled for these credentials.\n");
|
|
4657
4788
|
}
|
|
4658
4789
|
emitAccountAuthSuccess({ sdk, profile, clientId });
|
|
4659
4790
|
}
|
|
@@ -4672,7 +4803,10 @@ var LoginSchema = zod.z.object({
|
|
|
4672
4803
|
skipPrompts: zod.z.boolean().optional().meta({
|
|
4673
4804
|
deprecated: true,
|
|
4674
4805
|
deprecationMessage: "Use --non-interactive instead."
|
|
4675
|
-
})
|
|
4806
|
+
}),
|
|
4807
|
+
headless: zod.z.boolean().optional().describe(
|
|
4808
|
+
"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."
|
|
4809
|
+
)
|
|
4676
4810
|
}).describe("Log in to Zapier to access your account");
|
|
4677
4811
|
|
|
4678
4812
|
// src/plugins/login/index.ts
|
|
@@ -7304,7 +7438,7 @@ function buildBoxLines(message) {
|
|
|
7304
7438
|
// package.json with { type: 'json' }
|
|
7305
7439
|
var package_default2 = {
|
|
7306
7440
|
name: "@zapier/zapier-sdk-cli",
|
|
7307
|
-
version: "0.
|
|
7441
|
+
version: "0.61.0"};
|
|
7308
7442
|
|
|
7309
7443
|
// src/sdk.ts
|
|
7310
7444
|
zapierSdk.injectCliLogin(login_exports);
|