@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/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 {
|
|
@@ -1548,6 +1554,148 @@ Optional fields${pathContext}:`));
|
|
|
1548
1554
|
return constants;
|
|
1549
1555
|
}
|
|
1550
1556
|
};
|
|
1557
|
+
function offers(question, action) {
|
|
1558
|
+
return question.actions.some((a) => a.action === action);
|
|
1559
|
+
}
|
|
1560
|
+
function isActionRow(value) {
|
|
1561
|
+
return typeof value === "object" && value !== null && "action" in value;
|
|
1562
|
+
}
|
|
1563
|
+
async function promptText({
|
|
1564
|
+
message,
|
|
1565
|
+
password
|
|
1566
|
+
}) {
|
|
1567
|
+
const { value } = await inquirer__default.default.prompt([
|
|
1568
|
+
{ type: password ? "password" : "input", name: "value", message }
|
|
1569
|
+
]);
|
|
1570
|
+
return value;
|
|
1571
|
+
}
|
|
1572
|
+
async function answerSelect(question, field) {
|
|
1573
|
+
const display = (c) => c.hint ? `${c.label} ${chalk__default.default.dim(`(${c.hint})`)}` : c.label;
|
|
1574
|
+
if (question.multiple) {
|
|
1575
|
+
const choices = [
|
|
1576
|
+
...question.choices.map((c) => ({ name: display(c), value: c.value })),
|
|
1577
|
+
...offers(question, "more") ? [
|
|
1578
|
+
{
|
|
1579
|
+
name: chalk__default.default.dim("Load more\u2026"),
|
|
1580
|
+
value: { action: "more" }
|
|
1581
|
+
}
|
|
1582
|
+
] : [],
|
|
1583
|
+
...(question.notes ?? []).map((note) => ({
|
|
1584
|
+
name: chalk__default.default.dim(note),
|
|
1585
|
+
value: note,
|
|
1586
|
+
disabled: true
|
|
1587
|
+
}))
|
|
1588
|
+
];
|
|
1589
|
+
const { values } = await inquirer__default.default.prompt([
|
|
1590
|
+
{ type: "checkbox", name: "values", message: question.message, choices }
|
|
1591
|
+
]);
|
|
1592
|
+
const selected = values;
|
|
1593
|
+
if (selected.some(isActionRow)) return { type: "more" };
|
|
1594
|
+
if (selected.length === 0 && offers(question, "skip")) {
|
|
1595
|
+
return { type: "skip" };
|
|
1596
|
+
}
|
|
1597
|
+
return { type: "choose", value: selected };
|
|
1598
|
+
}
|
|
1599
|
+
const row = (name, action) => ({
|
|
1600
|
+
name,
|
|
1601
|
+
value: { action }
|
|
1602
|
+
});
|
|
1603
|
+
const value = await search__default.default({
|
|
1604
|
+
message: question.message,
|
|
1605
|
+
source: (term) => {
|
|
1606
|
+
const t = (term ?? "").trim().toLowerCase();
|
|
1607
|
+
const matched = t ? question.choices.filter(
|
|
1608
|
+
(c) => `${c.label} ${c.hint ?? ""}`.toLowerCase().includes(t)
|
|
1609
|
+
) : question.choices;
|
|
1610
|
+
const rows = matched.map((c) => ({
|
|
1611
|
+
name: display(c),
|
|
1612
|
+
value: c.value
|
|
1613
|
+
}));
|
|
1614
|
+
if (offers(question, "search"))
|
|
1615
|
+
rows.push(row(chalk__default.default.cyan("Search\u2026"), "search"));
|
|
1616
|
+
if (offers(question, "more"))
|
|
1617
|
+
rows.push(row(chalk__default.default.dim("Load more\u2026"), "more"));
|
|
1618
|
+
if (offers(question, "custom"))
|
|
1619
|
+
rows.push(row(chalk__default.default.dim("Enter a value manually\u2026"), "custom"));
|
|
1620
|
+
if (offers(question, "retry"))
|
|
1621
|
+
rows.push(row(chalk__default.default.yellow("Retry"), "retry"));
|
|
1622
|
+
if (offers(question, "skip"))
|
|
1623
|
+
rows.push(row(chalk__default.default.dim("Skip (optional)"), "skip"));
|
|
1624
|
+
if (offers(question, "cancel"))
|
|
1625
|
+
rows.push(row(chalk__default.default.dim("Cancel"), "cancel"));
|
|
1626
|
+
for (const note of question.notes ?? [])
|
|
1627
|
+
rows.push({ name: chalk__default.default.dim(note), value: note, disabled: true });
|
|
1628
|
+
return rows;
|
|
1629
|
+
}
|
|
1630
|
+
});
|
|
1631
|
+
if (!isActionRow(value)) {
|
|
1632
|
+
return { type: "choose", value };
|
|
1633
|
+
}
|
|
1634
|
+
switch (value.action) {
|
|
1635
|
+
case "search": {
|
|
1636
|
+
const term = await promptText({
|
|
1637
|
+
message: `Search ${field}:`,
|
|
1638
|
+
password: false
|
|
1639
|
+
});
|
|
1640
|
+
return { type: "search", term };
|
|
1641
|
+
}
|
|
1642
|
+
case "custom": {
|
|
1643
|
+
const custom = await promptText({
|
|
1644
|
+
message: `Enter ${field}:`,
|
|
1645
|
+
password: false
|
|
1646
|
+
});
|
|
1647
|
+
return { type: "custom", value: custom };
|
|
1648
|
+
}
|
|
1649
|
+
case "more":
|
|
1650
|
+
return { type: "more" };
|
|
1651
|
+
case "retry":
|
|
1652
|
+
return { type: "retry" };
|
|
1653
|
+
case "skip":
|
|
1654
|
+
return { type: "skip" };
|
|
1655
|
+
case "cancel":
|
|
1656
|
+
return { type: "cancel" };
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
async function answerInput(question) {
|
|
1660
|
+
const value = await promptText({
|
|
1661
|
+
message: question.message,
|
|
1662
|
+
password: question.inputType === "password"
|
|
1663
|
+
});
|
|
1664
|
+
if (value === "" && offers(question, "skip")) {
|
|
1665
|
+
return { type: "skip" };
|
|
1666
|
+
}
|
|
1667
|
+
return { type: "custom", value };
|
|
1668
|
+
}
|
|
1669
|
+
async function answerCollection(question) {
|
|
1670
|
+
if (!offers(question, "done")) {
|
|
1671
|
+
return { type: "add" };
|
|
1672
|
+
}
|
|
1673
|
+
const { again } = await inquirer__default.default.prompt([
|
|
1674
|
+
{
|
|
1675
|
+
type: "confirm",
|
|
1676
|
+
name: "again",
|
|
1677
|
+
message: question.message,
|
|
1678
|
+
default: false
|
|
1679
|
+
}
|
|
1680
|
+
]);
|
|
1681
|
+
return again ? { type: "add" } : { type: "done" };
|
|
1682
|
+
}
|
|
1683
|
+
var answerViaCli = ({ state, result }) => {
|
|
1684
|
+
if (result.error !== void 0) {
|
|
1685
|
+
const message = typeof result.error === "string" ? result.error : result.error.message;
|
|
1686
|
+
console.log(chalk__default.default.yellow(`! ${message}`));
|
|
1687
|
+
}
|
|
1688
|
+
const field = state.current?.join(".") ?? "value";
|
|
1689
|
+
const question = result.question;
|
|
1690
|
+
switch (question.type) {
|
|
1691
|
+
case "select":
|
|
1692
|
+
return answerSelect(question, field);
|
|
1693
|
+
case "input":
|
|
1694
|
+
return answerInput(question);
|
|
1695
|
+
case "collection":
|
|
1696
|
+
return answerCollection(question);
|
|
1697
|
+
}
|
|
1698
|
+
};
|
|
1551
1699
|
|
|
1552
1700
|
// src/utils/cli-options.ts
|
|
1553
1701
|
var RESERVED_CLI_OPTIONS = [
|
|
@@ -1579,7 +1727,7 @@ var SHARED_COMMAND_CLI_OPTIONS = [
|
|
|
1579
1727
|
|
|
1580
1728
|
// package.json
|
|
1581
1729
|
var package_default = {
|
|
1582
|
-
version: "0.
|
|
1730
|
+
version: "0.61.1"};
|
|
1583
1731
|
|
|
1584
1732
|
// src/telemetry/builders.ts
|
|
1585
1733
|
function createCliBaseEvent(context = {}) {
|
|
@@ -1654,7 +1802,7 @@ async function formatItemsFromSchema(_functionInfo, items, startingNumber = 0, o
|
|
|
1654
1802
|
if (options?.formatter) {
|
|
1655
1803
|
const formatter = options.formatter;
|
|
1656
1804
|
const input = options.input ?? {};
|
|
1657
|
-
const context = formatter.
|
|
1805
|
+
const context = formatter.getContext ? await formatter.getContext({ items, input }) : void 0;
|
|
1658
1806
|
items.forEach((item, index) => {
|
|
1659
1807
|
const formatted = formatter.format({ item, input, context });
|
|
1660
1808
|
formatSingleItem(formatted, startingNumber + index);
|
|
@@ -2249,7 +2397,7 @@ function analyzeZodField(name, schema, functionInfo) {
|
|
|
2249
2397
|
paramType = "object";
|
|
2250
2398
|
}
|
|
2251
2399
|
let paramHasResolver = false;
|
|
2252
|
-
if (functionInfo?.resolvers?.[name]) {
|
|
2400
|
+
if (functionInfo?.resolvers?.[name] || functionInfo?.boundResolvers?.[name]) {
|
|
2253
2401
|
paramHasResolver = true;
|
|
2254
2402
|
}
|
|
2255
2403
|
return {
|
|
@@ -2408,6 +2556,9 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
|
|
|
2408
2556
|
const usesInputParameters = !functionInfo.inputSchema && !!functionInfo.inputParameters;
|
|
2409
2557
|
const schema = functionInfo.inputSchema;
|
|
2410
2558
|
const parameters = usesInputParameters ? analyzeInputParameters(functionInfo.inputParameters, functionInfo) : analyzeZodSchema(schema, functionInfo);
|
|
2559
|
+
if (functionInfo.boundResolvers && Object.keys(functionInfo.boundResolvers).length > 0) {
|
|
2560
|
+
for (const param of parameters) param.hasResolver = true;
|
|
2561
|
+
}
|
|
2411
2562
|
const schemaAliases = getSchemaAliases(schema);
|
|
2412
2563
|
if (schemaAliases) {
|
|
2413
2564
|
const aliasedNames = new Set(Object.keys(schemaAliases));
|
|
@@ -2460,7 +2611,35 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
|
|
|
2460
2611
|
}
|
|
2461
2612
|
}
|
|
2462
2613
|
}
|
|
2463
|
-
|
|
2614
|
+
const boundResolvers = functionInfo.boundResolvers;
|
|
2615
|
+
if (boundResolvers && Object.keys(boundResolvers).length > 0) {
|
|
2616
|
+
const seedInput = Object.fromEntries(
|
|
2617
|
+
Object.entries(rawParams).filter(([, v]) => v !== void 0)
|
|
2618
|
+
);
|
|
2619
|
+
const controller = zapierSdk.createController(sdk);
|
|
2620
|
+
let resolved;
|
|
2621
|
+
try {
|
|
2622
|
+
resolved = await controller.resolve({
|
|
2623
|
+
method: functionInfo.name,
|
|
2624
|
+
input: seedInput,
|
|
2625
|
+
answer: interactiveMode ? answerViaCli : ({ state }) => {
|
|
2626
|
+
throw new ZapierCliMissingParametersError([
|
|
2627
|
+
{
|
|
2628
|
+
name: state.current?.join(".") ?? "value",
|
|
2629
|
+
isPositional: false
|
|
2630
|
+
}
|
|
2631
|
+
]);
|
|
2632
|
+
},
|
|
2633
|
+
interactive: interactiveMode
|
|
2634
|
+
});
|
|
2635
|
+
} catch (err) {
|
|
2636
|
+
if (err instanceof zapierSdk.CoreCancelledSignal) {
|
|
2637
|
+
throw new ZapierCliUserCancellationError();
|
|
2638
|
+
}
|
|
2639
|
+
throw err;
|
|
2640
|
+
}
|
|
2641
|
+
Object.assign(resolvedParams, resolved);
|
|
2642
|
+
} else if (schema && !usesInputParameters) {
|
|
2464
2643
|
const resolver = new SchemaParameterResolver();
|
|
2465
2644
|
const resolved = await resolver.resolveParameters(
|
|
2466
2645
|
schema,
|
|
@@ -2553,7 +2732,7 @@ ${confirmMessageAfter}`));
|
|
|
2553
2732
|
}
|
|
2554
2733
|
}
|
|
2555
2734
|
} catch (error) {
|
|
2556
|
-
success = false;
|
|
2735
|
+
success = error instanceof ZapierCliError ? error.exitCode === 0 : false;
|
|
2557
2736
|
errorMessage = error instanceof Error ? error.message : String(error);
|
|
2558
2737
|
if (error instanceof ZapierCliMissingParametersError) {
|
|
2559
2738
|
renderer.renderError(error);
|
|
@@ -3765,41 +3944,165 @@ var spinPromise = async (promise, text) => {
|
|
|
3765
3944
|
}
|
|
3766
3945
|
};
|
|
3767
3946
|
|
|
3947
|
+
// src/utils/auth/oauth-errors.ts
|
|
3948
|
+
var OauthFlowTimeoutError = class _OauthFlowTimeoutError extends ZapierCliValidationError {
|
|
3949
|
+
constructor({
|
|
3950
|
+
timeoutMs,
|
|
3951
|
+
message = "OAuth flow timed out"
|
|
3952
|
+
}) {
|
|
3953
|
+
super(message, {
|
|
3954
|
+
name: "OauthFlowTimeoutError",
|
|
3955
|
+
code: "ZAPIER_OAUTH_FLOW_TIMEOUT"
|
|
3956
|
+
});
|
|
3957
|
+
this.timeoutMs = timeoutMs;
|
|
3958
|
+
}
|
|
3959
|
+
withMessage(message) {
|
|
3960
|
+
return new _OauthFlowTimeoutError({ timeoutMs: this.timeoutMs, message });
|
|
3961
|
+
}
|
|
3962
|
+
};
|
|
3963
|
+
var OauthAuthorizationDeniedError = class _OauthAuthorizationDeniedError extends ZapierCliValidationError {
|
|
3964
|
+
constructor({
|
|
3965
|
+
reason,
|
|
3966
|
+
message = "OAuth authorization denied"
|
|
3967
|
+
}) {
|
|
3968
|
+
super(message, {
|
|
3969
|
+
name: "OauthAuthorizationDeniedError",
|
|
3970
|
+
code: "ZAPIER_OAUTH_AUTHORIZATION_DENIED"
|
|
3971
|
+
});
|
|
3972
|
+
this.reason = reason;
|
|
3973
|
+
}
|
|
3974
|
+
withMessage(message) {
|
|
3975
|
+
return new _OauthAuthorizationDeniedError({
|
|
3976
|
+
reason: this.reason,
|
|
3977
|
+
message
|
|
3978
|
+
});
|
|
3979
|
+
}
|
|
3980
|
+
};
|
|
3981
|
+
var OauthFlowError = class _OauthFlowError extends ZapierCliValidationError {
|
|
3982
|
+
constructor({ message }) {
|
|
3983
|
+
super(message, {
|
|
3984
|
+
name: "OauthFlowError",
|
|
3985
|
+
code: "ZAPIER_OAUTH_FLOW"
|
|
3986
|
+
});
|
|
3987
|
+
}
|
|
3988
|
+
withMessage(message) {
|
|
3989
|
+
return new _OauthFlowError({ message });
|
|
3990
|
+
}
|
|
3991
|
+
};
|
|
3992
|
+
var OauthCallbackError = class _OauthCallbackError extends ZapierCliValidationError {
|
|
3993
|
+
constructor({ kind, message }) {
|
|
3994
|
+
super(message, {
|
|
3995
|
+
name: "OauthCallbackError",
|
|
3996
|
+
code: "ZAPIER_OAUTH_CALLBACK"
|
|
3997
|
+
});
|
|
3998
|
+
this.kind = kind;
|
|
3999
|
+
}
|
|
4000
|
+
withMessage(message) {
|
|
4001
|
+
return new _OauthCallbackError({ kind: this.kind, message });
|
|
4002
|
+
}
|
|
4003
|
+
};
|
|
4004
|
+
var OauthTokenExchangeError = class _OauthTokenExchangeError extends ZapierCliValidationError {
|
|
4005
|
+
constructor({ message }) {
|
|
4006
|
+
super(message, {
|
|
4007
|
+
name: "OauthTokenExchangeError",
|
|
4008
|
+
code: "ZAPIER_OAUTH_TOKEN_EXCHANGE"
|
|
4009
|
+
});
|
|
4010
|
+
}
|
|
4011
|
+
withMessage(message) {
|
|
4012
|
+
return new _OauthTokenExchangeError({ message });
|
|
4013
|
+
}
|
|
4014
|
+
};
|
|
4015
|
+
var SENSITIVE_OAUTH_FIELDS = [
|
|
4016
|
+
"access_token",
|
|
4017
|
+
"refresh_token",
|
|
4018
|
+
"id_token",
|
|
4019
|
+
"client_secret",
|
|
4020
|
+
"code_verifier",
|
|
4021
|
+
"code_challenge"
|
|
4022
|
+
];
|
|
4023
|
+
function getErrorMessage(error) {
|
|
4024
|
+
return error instanceof Error ? error.message : String(error);
|
|
4025
|
+
}
|
|
4026
|
+
function toCamelCase(field) {
|
|
4027
|
+
return field.replace(
|
|
4028
|
+
/_([a-z])/g,
|
|
4029
|
+
(_match, letter) => letter.toUpperCase()
|
|
4030
|
+
);
|
|
4031
|
+
}
|
|
4032
|
+
function escapeRegExp(value) {
|
|
4033
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4034
|
+
}
|
|
4035
|
+
var sensitiveOauthFieldPattern = Array.from(
|
|
4036
|
+
new Set(
|
|
4037
|
+
SENSITIVE_OAUTH_FIELDS.flatMap((field) => [field, toCamelCase(field)])
|
|
4038
|
+
)
|
|
4039
|
+
).map(escapeRegExp).join("|");
|
|
4040
|
+
var sensitiveQueryParamPattern = new RegExp(
|
|
4041
|
+
`([?&])(${sensitiveOauthFieldPattern})(=)[^&#\\s"'<>]*`,
|
|
4042
|
+
"gi"
|
|
4043
|
+
);
|
|
4044
|
+
function redactSensitiveOauthErrorMessage(message) {
|
|
4045
|
+
return message.replace(
|
|
4046
|
+
sensitiveQueryParamPattern,
|
|
4047
|
+
(_match, prefix, key, separator) => `${prefix}${key}${separator}[REDACTED]`
|
|
4048
|
+
).replace(
|
|
4049
|
+
new RegExp(`"(${sensitiveOauthFieldPattern})"(\\s*:\\s*)"[^"]*"`, "g"),
|
|
4050
|
+
(_match, key, separator) => `"${key}"${separator}"[REDACTED]"`
|
|
4051
|
+
);
|
|
4052
|
+
}
|
|
4053
|
+
function toRedactedOauthError(error) {
|
|
4054
|
+
const message = redactSensitiveOauthErrorMessage(getErrorMessage(error));
|
|
4055
|
+
if (error instanceof ZapierCliValidationError) {
|
|
4056
|
+
return error.withMessage(message);
|
|
4057
|
+
}
|
|
4058
|
+
return new OauthFlowError({ message });
|
|
4059
|
+
}
|
|
4060
|
+
function toOauthTokenExchangeError(error) {
|
|
4061
|
+
return new OauthTokenExchangeError({
|
|
4062
|
+
message: redactSensitiveOauthErrorMessage(getErrorMessage(error))
|
|
4063
|
+
});
|
|
4064
|
+
}
|
|
4065
|
+
|
|
3768
4066
|
// src/utils/auth/oauth-callback.ts
|
|
3769
4067
|
function getCallbackCode({
|
|
3770
4068
|
callbackUrl,
|
|
3771
|
-
transaction
|
|
3772
|
-
recoveryMessage
|
|
4069
|
+
transaction
|
|
3773
4070
|
}) {
|
|
3774
4071
|
let parsed;
|
|
3775
4072
|
try {
|
|
3776
4073
|
parsed = new URL(callbackUrl.trim());
|
|
3777
4074
|
} catch {
|
|
3778
|
-
throw new
|
|
3779
|
-
|
|
3780
|
-
|
|
4075
|
+
throw new OauthCallbackError({
|
|
4076
|
+
kind: "invalid_url",
|
|
4077
|
+
message: "Paste the final OAuth callback URL from your browser."
|
|
4078
|
+
});
|
|
3781
4079
|
}
|
|
3782
4080
|
const expected = new URL(transaction.redirectUri);
|
|
3783
4081
|
if (parsed.protocol !== "http:" || parsed.hostname !== expected.hostname || parsed.pathname !== expected.pathname || parsed.port !== expected.port) {
|
|
3784
|
-
throw new
|
|
3785
|
-
|
|
3786
|
-
|
|
4082
|
+
throw new OauthCallbackError({
|
|
4083
|
+
kind: "redirect_mismatch",
|
|
4084
|
+
message: `Expected the final OAuth callback URL to start with ${transaction.redirectUri}.`
|
|
4085
|
+
});
|
|
3787
4086
|
}
|
|
3788
4087
|
if (parsed.searchParams.get("state") !== transaction.state) {
|
|
3789
|
-
throw new
|
|
3790
|
-
|
|
3791
|
-
|
|
4088
|
+
throw new OauthCallbackError({
|
|
4089
|
+
kind: "state_mismatch",
|
|
4090
|
+
message: "OAuth state mismatch."
|
|
4091
|
+
});
|
|
3792
4092
|
}
|
|
3793
4093
|
if (parsed.searchParams.has("error")) {
|
|
3794
|
-
throw new
|
|
3795
|
-
|
|
3796
|
-
|
|
4094
|
+
throw new OauthAuthorizationDeniedError({
|
|
4095
|
+
reason: String(
|
|
4096
|
+
parsed.searchParams.get("error_description") ?? parsed.searchParams.get("error")
|
|
4097
|
+
)
|
|
4098
|
+
});
|
|
3797
4099
|
}
|
|
3798
4100
|
const code = parsed.searchParams.get("code");
|
|
3799
4101
|
if (!code) {
|
|
3800
|
-
throw new
|
|
3801
|
-
|
|
3802
|
-
|
|
4102
|
+
throw new OauthCallbackError({
|
|
4103
|
+
kind: "missing_code",
|
|
4104
|
+
message: "No authorization code found in the pasted callback URL."
|
|
4105
|
+
});
|
|
3803
4106
|
}
|
|
3804
4107
|
return code;
|
|
3805
4108
|
}
|
|
@@ -3914,7 +4217,9 @@ async function exchangeOauthCode({
|
|
|
3914
4217
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
3915
4218
|
}
|
|
3916
4219
|
}
|
|
3917
|
-
)
|
|
4220
|
+
).catch((error) => {
|
|
4221
|
+
throw toOauthTokenExchangeError(error);
|
|
4222
|
+
});
|
|
3918
4223
|
return {
|
|
3919
4224
|
accessToken: data.access_token,
|
|
3920
4225
|
refreshToken: data.refresh_token,
|
|
@@ -3923,19 +4228,15 @@ async function exchangeOauthCode({
|
|
|
3923
4228
|
}
|
|
3924
4229
|
|
|
3925
4230
|
// src/utils/auth/oauth-flow.ts
|
|
3926
|
-
var
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
this.name = "OauthFlowTimeoutError";
|
|
3931
|
-
}
|
|
4231
|
+
var LOGIN_OAUTH_COPY = {
|
|
4232
|
+
flowName: "Login",
|
|
4233
|
+
action: "log in",
|
|
4234
|
+
urlLabel: "login URL"
|
|
3932
4235
|
};
|
|
3933
|
-
var
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
this.name = "OauthAuthorizationDeniedError";
|
|
3938
|
-
}
|
|
4236
|
+
var SIGNUP_OAUTH_COPY = {
|
|
4237
|
+
flowName: "Signup",
|
|
4238
|
+
action: "sign up",
|
|
4239
|
+
urlLabel: "signup URL"
|
|
3939
4240
|
};
|
|
3940
4241
|
function findAvailablePort() {
|
|
3941
4242
|
return new Promise((resolve4, reject) => {
|
|
@@ -3950,70 +4251,86 @@ function findAvailablePort() {
|
|
|
3950
4251
|
tryPort(LOGIN_PORTS[portIndex++]);
|
|
3951
4252
|
} else if (err.code === "EADDRINUSE") {
|
|
3952
4253
|
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
|
-
)
|
|
4254
|
+
new OauthFlowError({
|
|
4255
|
+
message: `All configured OAuth callback ports are busy: ${LOGIN_PORTS.join(", ")}. Please try again later or close applications using these ports.`
|
|
4256
|
+
})
|
|
3956
4257
|
);
|
|
3957
4258
|
} else {
|
|
3958
4259
|
reject(err);
|
|
3959
4260
|
}
|
|
3960
4261
|
});
|
|
3961
4262
|
};
|
|
3962
|
-
if (LOGIN_PORTS.length > 0)
|
|
3963
|
-
|
|
4263
|
+
if (LOGIN_PORTS.length > 0) {
|
|
4264
|
+
tryPort(LOGIN_PORTS[portIndex++]);
|
|
4265
|
+
return;
|
|
4266
|
+
}
|
|
4267
|
+
reject(
|
|
4268
|
+
new OauthFlowError({ message: "No OAuth callback ports configured" })
|
|
4269
|
+
);
|
|
3964
4270
|
});
|
|
3965
4271
|
}
|
|
3966
4272
|
async function runLoginOauthFlow(options) {
|
|
3967
|
-
return
|
|
3968
|
-
|
|
4273
|
+
return runOauthFlowForEntryPoint({
|
|
4274
|
+
options,
|
|
3969
4275
|
entryPoint: "login",
|
|
3970
|
-
|
|
3971
|
-
flowName: "Login"
|
|
4276
|
+
copy: LOGIN_OAUTH_COPY
|
|
3972
4277
|
});
|
|
3973
4278
|
}
|
|
3974
4279
|
async function runSignupOauthFlow(options) {
|
|
4280
|
+
return runOauthFlowForEntryPoint({
|
|
4281
|
+
options,
|
|
4282
|
+
entryPoint: "signup",
|
|
4283
|
+
copy: SIGNUP_OAUTH_COPY
|
|
4284
|
+
});
|
|
4285
|
+
}
|
|
4286
|
+
function runOauthFlowForEntryPoint({
|
|
4287
|
+
options,
|
|
4288
|
+
entryPoint,
|
|
4289
|
+
copy
|
|
4290
|
+
}) {
|
|
3975
4291
|
if (options.headless) {
|
|
3976
4292
|
return runOauthFlowEntryPoint({
|
|
3977
4293
|
...options,
|
|
3978
|
-
entryPoint
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
headless: true
|
|
4294
|
+
entryPoint,
|
|
4295
|
+
headless: true,
|
|
4296
|
+
copy
|
|
3982
4297
|
});
|
|
3983
4298
|
}
|
|
3984
4299
|
return runOauthFlowEntryPoint({
|
|
3985
4300
|
...options,
|
|
3986
|
-
entryPoint
|
|
3987
|
-
|
|
3988
|
-
|
|
4301
|
+
entryPoint,
|
|
4302
|
+
copy,
|
|
4303
|
+
headless: false
|
|
3989
4304
|
});
|
|
3990
4305
|
}
|
|
3991
|
-
async function runOauthFlowEntryPoint({
|
|
3992
|
-
flowName,
|
|
3993
|
-
...options
|
|
3994
|
-
}) {
|
|
4306
|
+
async function runOauthFlowEntryPoint(options) {
|
|
3995
4307
|
try {
|
|
3996
|
-
return options.headless ? await
|
|
4308
|
+
return options.headless ? await runHeadlessOauthFlow(options) : await runOauthFlow(options);
|
|
3997
4309
|
} catch (error) {
|
|
3998
4310
|
if (error instanceof OauthFlowTimeoutError) {
|
|
3999
|
-
throw
|
|
4311
|
+
throw error.withMessage(
|
|
4000
4312
|
withRecoveryMessage(
|
|
4001
|
-
`${flowName} timed out after ${Math.round(error.timeoutMs / 1e3)} seconds.`,
|
|
4313
|
+
`${options.copy.flowName} timed out after ${Math.round(error.timeoutMs / 1e3)} seconds.`,
|
|
4002
4314
|
options.recoveryMessage
|
|
4003
4315
|
)
|
|
4004
4316
|
);
|
|
4005
4317
|
}
|
|
4006
4318
|
if (error instanceof OauthAuthorizationDeniedError) {
|
|
4007
|
-
throw
|
|
4319
|
+
throw error.withMessage(
|
|
4008
4320
|
withRecoveryMessage(
|
|
4009
4321
|
`Authorization denied: ${error.reason}.`,
|
|
4010
4322
|
options.recoveryMessage
|
|
4011
4323
|
)
|
|
4012
4324
|
);
|
|
4013
4325
|
}
|
|
4326
|
+
if (error instanceof OauthCallbackError && options.recoveryMessage) {
|
|
4327
|
+
throw error.withMessage(
|
|
4328
|
+
withRecoveryMessage(error.message, options.recoveryMessage)
|
|
4329
|
+
);
|
|
4330
|
+
}
|
|
4014
4331
|
if (error instanceof ZapierCliUserCancellationError && !options.silent) {
|
|
4015
4332
|
log_default.info(`
|
|
4016
|
-
\u274C ${flowName} cancelled by user`);
|
|
4333
|
+
\u274C ${options.copy.flowName} cancelled by user`);
|
|
4017
4334
|
}
|
|
4018
4335
|
throw error;
|
|
4019
4336
|
}
|
|
@@ -4021,12 +4338,22 @@ async function runOauthFlowEntryPoint({
|
|
|
4021
4338
|
function withRecoveryMessage(message, recoveryMessage) {
|
|
4022
4339
|
return recoveryMessage ? `${message} ${recoveryMessage}` : message;
|
|
4023
4340
|
}
|
|
4341
|
+
function createMissingHeadlessCallbackUrlError() {
|
|
4342
|
+
return new OauthCallbackError({
|
|
4343
|
+
kind: "missing_callback_url",
|
|
4344
|
+
message: "Paste the final OAuth callback URL from your browser."
|
|
4345
|
+
});
|
|
4346
|
+
}
|
|
4347
|
+
function writeHeadlessOauthStatus(message) {
|
|
4348
|
+
process.stderr.write(`${message}
|
|
4349
|
+
`);
|
|
4350
|
+
}
|
|
4024
4351
|
async function runOauthFlow({
|
|
4025
4352
|
timeoutMs = LOGIN_TIMEOUT_MS,
|
|
4026
4353
|
pkceCredentials,
|
|
4027
4354
|
baseUrl: baseUrl2,
|
|
4028
4355
|
entryPoint,
|
|
4029
|
-
|
|
4356
|
+
copy,
|
|
4030
4357
|
silent = false,
|
|
4031
4358
|
onProgress
|
|
4032
4359
|
}) {
|
|
@@ -4041,7 +4368,7 @@ async function runOauthFlow({
|
|
|
4041
4368
|
const code = await collectLocalCallbackCode({
|
|
4042
4369
|
transaction,
|
|
4043
4370
|
timeoutMs,
|
|
4044
|
-
|
|
4371
|
+
action: copy.action,
|
|
4045
4372
|
silent,
|
|
4046
4373
|
onProgress
|
|
4047
4374
|
});
|
|
@@ -4055,92 +4382,104 @@ async function runOauthFlow({
|
|
|
4055
4382
|
}
|
|
4056
4383
|
async function readHeadlessCallbackUrl({
|
|
4057
4384
|
timeoutMs,
|
|
4058
|
-
interactive
|
|
4059
|
-
recoveryMessage
|
|
4385
|
+
interactive
|
|
4060
4386
|
}) {
|
|
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
4387
|
const rl = promises$1.createInterface({ input: process.stdin, output: process.stderr });
|
|
4070
4388
|
const abortController = new AbortController();
|
|
4071
4389
|
const timeoutTimer = setTimeout(() => abortController.abort(), timeoutMs);
|
|
4072
|
-
const readUrl =
|
|
4073
|
-
signal: abortController.signal
|
|
4074
|
-
}) : new Promise((resolve4, reject) => {
|
|
4390
|
+
const readUrl = new Promise((resolve4, reject) => {
|
|
4075
4391
|
let settled = false;
|
|
4076
|
-
const
|
|
4392
|
+
const handleLine = (value) => settleResolve(value);
|
|
4393
|
+
const handleAbort = () => settleReject(new OauthFlowTimeoutError({ timeoutMs }));
|
|
4394
|
+
const handleClose = () => settleReject(createMissingHeadlessCallbackUrlError());
|
|
4395
|
+
const handleError = (error) => settleReject(error);
|
|
4396
|
+
const handleCancellation = () => settleReject(new ZapierCliUserCancellationError());
|
|
4397
|
+
const cleanupListeners = () => {
|
|
4398
|
+
abortController.signal.removeEventListener("abort", handleAbort);
|
|
4399
|
+
rl.off("line", handleLine);
|
|
4400
|
+
rl.off("close", handleClose);
|
|
4401
|
+
rl.off("error", handleError);
|
|
4402
|
+
rl.off("SIGINT", handleCancellation);
|
|
4403
|
+
process.off("SIGINT", handleCancellation);
|
|
4404
|
+
process.off("SIGTERM", handleCancellation);
|
|
4405
|
+
};
|
|
4406
|
+
function settleResolve(value) {
|
|
4407
|
+
if (settled) return;
|
|
4077
4408
|
settled = true;
|
|
4409
|
+
cleanupListeners();
|
|
4078
4410
|
resolve4(value);
|
|
4079
|
-
}
|
|
4080
|
-
|
|
4411
|
+
}
|
|
4412
|
+
function settleReject(error) {
|
|
4081
4413
|
if (settled) return;
|
|
4082
4414
|
settled = true;
|
|
4415
|
+
cleanupListeners();
|
|
4083
4416
|
reject(error);
|
|
4084
|
-
}
|
|
4085
|
-
abortController.signal.addEventListener(
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
);
|
|
4090
|
-
rl.once("
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4417
|
+
}
|
|
4418
|
+
abortController.signal.addEventListener("abort", handleAbort, {
|
|
4419
|
+
once: true
|
|
4420
|
+
});
|
|
4421
|
+
rl.once("close", handleClose);
|
|
4422
|
+
rl.once("error", handleError);
|
|
4423
|
+
rl.once("SIGINT", handleCancellation);
|
|
4424
|
+
process.once("SIGINT", handleCancellation);
|
|
4425
|
+
process.once("SIGTERM", handleCancellation);
|
|
4426
|
+
if (interactive) {
|
|
4427
|
+
void rl.question("Paste the final OAuth callback URL: ", {
|
|
4428
|
+
signal: abortController.signal
|
|
4429
|
+
}).then(settleResolve).catch((error) => {
|
|
4430
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
4431
|
+
settleReject(new OauthFlowTimeoutError({ timeoutMs }));
|
|
4432
|
+
return;
|
|
4433
|
+
}
|
|
4434
|
+
settleReject(error);
|
|
4435
|
+
});
|
|
4436
|
+
return;
|
|
4437
|
+
}
|
|
4438
|
+
rl.once("line", handleLine);
|
|
4096
4439
|
});
|
|
4097
4440
|
try {
|
|
4098
|
-
return await readUrl
|
|
4099
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
4100
|
-
throw new Error(timeoutMessage);
|
|
4101
|
-
}
|
|
4102
|
-
throw error;
|
|
4103
|
-
});
|
|
4441
|
+
return await readUrl;
|
|
4104
4442
|
} finally {
|
|
4105
4443
|
clearTimeout(timeoutTimer);
|
|
4106
4444
|
rl.close();
|
|
4107
4445
|
}
|
|
4108
4446
|
}
|
|
4109
|
-
async function
|
|
4447
|
+
async function runHeadlessOauthFlow({
|
|
4110
4448
|
timeoutMs = LOGIN_TIMEOUT_MS,
|
|
4111
4449
|
pkceCredentials,
|
|
4112
4450
|
baseUrl: baseUrl2,
|
|
4451
|
+
entryPoint,
|
|
4113
4452
|
interactive = true,
|
|
4114
4453
|
onProgress,
|
|
4115
|
-
|
|
4454
|
+
copy
|
|
4116
4455
|
}) {
|
|
4117
4456
|
const port = LOGIN_PORTS[0];
|
|
4118
4457
|
const transaction = await prepareOauthTransaction({
|
|
4119
4458
|
pkceCredentials,
|
|
4120
4459
|
baseUrl: baseUrl2,
|
|
4121
4460
|
redirectUri: `http://${OAUTH_LOOPBACK_HOST}:${port}/oauth`,
|
|
4122
|
-
entryPoint
|
|
4461
|
+
entryPoint
|
|
4123
4462
|
});
|
|
4124
|
-
|
|
4125
|
-
|
|
4463
|
+
writeHeadlessOauthStatus(
|
|
4464
|
+
`Use this mode to ${copy.action} from a machine that has no browser.`
|
|
4465
|
+
);
|
|
4466
|
+
writeHeadlessOauthStatus(
|
|
4467
|
+
`Open this ${copy.urlLabel} in a browser on another machine:`
|
|
4126
4468
|
);
|
|
4127
|
-
console.log("Open this signup URL in a browser on another machine:");
|
|
4128
4469
|
console.log(transaction.browserAuthUrl);
|
|
4129
|
-
|
|
4470
|
+
writeHeadlessOauthStatus(
|
|
4130
4471
|
`When the browser lands on ${transaction.redirectUri} and cannot connect, paste the full final URL back here.`
|
|
4131
4472
|
);
|
|
4132
4473
|
const callbackUrl = await readHeadlessCallbackUrl({
|
|
4133
4474
|
timeoutMs,
|
|
4134
|
-
interactive
|
|
4135
|
-
recoveryMessage
|
|
4475
|
+
interactive
|
|
4136
4476
|
});
|
|
4137
4477
|
const code = getCallbackCode({
|
|
4138
4478
|
callbackUrl,
|
|
4139
|
-
transaction
|
|
4140
|
-
recoveryMessage
|
|
4479
|
+
transaction
|
|
4141
4480
|
});
|
|
4142
4481
|
onProgress?.({ type: "callback_accepted" });
|
|
4143
|
-
|
|
4482
|
+
writeHeadlessOauthStatus("Exchanging authorization code for tokens...");
|
|
4144
4483
|
onProgress?.({ type: "token_exchange_started" });
|
|
4145
4484
|
const tokens = await exchangeOauthCode({ ...transaction, code });
|
|
4146
4485
|
onProgress?.({ type: "token_exchange_completed" });
|
|
@@ -4149,7 +4488,7 @@ async function runHeadlessSignupOauthFlow({
|
|
|
4149
4488
|
async function collectLocalCallbackCode({
|
|
4150
4489
|
transaction,
|
|
4151
4490
|
timeoutMs,
|
|
4152
|
-
|
|
4491
|
+
action,
|
|
4153
4492
|
silent,
|
|
4154
4493
|
onProgress
|
|
4155
4494
|
}) {
|
|
@@ -4157,21 +4496,26 @@ async function collectLocalCallbackCode({
|
|
|
4157
4496
|
const app = express__default.default();
|
|
4158
4497
|
app.get("/oauth", (req, res) => {
|
|
4159
4498
|
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));
|
|
4499
|
+
try {
|
|
4500
|
+
const code = getCallbackCode({
|
|
4501
|
+
callbackUrl: new URL(
|
|
4502
|
+
req.originalUrl,
|
|
4503
|
+
transaction.redirectUri
|
|
4504
|
+
).toString(),
|
|
4505
|
+
transaction
|
|
4506
|
+
});
|
|
4507
|
+
resolve4(code);
|
|
4174
4508
|
res.end("You can now close this tab and return to the CLI.");
|
|
4509
|
+
} catch (error) {
|
|
4510
|
+
if (error instanceof OauthCallbackError && error.kind === "state_mismatch") {
|
|
4511
|
+
res.status(400).end("Invalid state. You can close this tab.");
|
|
4512
|
+
} else if (error instanceof OauthAuthorizationDeniedError) {
|
|
4513
|
+
reject(error);
|
|
4514
|
+
res.end("Authorization was denied. You can close this tab.");
|
|
4515
|
+
} else {
|
|
4516
|
+
reject(error);
|
|
4517
|
+
res.end("No authorization code received. You can close this tab.");
|
|
4518
|
+
}
|
|
4175
4519
|
}
|
|
4176
4520
|
});
|
|
4177
4521
|
const server = app.listen(
|
|
@@ -4192,19 +4536,19 @@ async function collectLocalCallbackCode({
|
|
|
4192
4536
|
let timeoutTimer;
|
|
4193
4537
|
try {
|
|
4194
4538
|
await waitForServerListening(server);
|
|
4195
|
-
await openBrowser({ transaction,
|
|
4539
|
+
await openBrowser({ transaction, action, silent, onProgress });
|
|
4196
4540
|
const waitForCode = Promise.race([
|
|
4197
4541
|
promise,
|
|
4198
4542
|
new Promise((_resolve, rejectTimeout) => {
|
|
4199
4543
|
timeoutTimer = setTimeout(() => {
|
|
4200
|
-
rejectTimeout(new OauthFlowTimeoutError(timeoutMs));
|
|
4544
|
+
rejectTimeout(new OauthFlowTimeoutError({ timeoutMs }));
|
|
4201
4545
|
}, timeoutMs);
|
|
4202
4546
|
})
|
|
4203
4547
|
]);
|
|
4204
4548
|
onProgress?.({ type: "callback_waiting" });
|
|
4205
4549
|
return silent ? await waitForCode : await spinPromise(
|
|
4206
4550
|
waitForCode,
|
|
4207
|
-
`Waiting for you to ${
|
|
4551
|
+
`Waiting for you to ${action} and authorize`
|
|
4208
4552
|
);
|
|
4209
4553
|
} finally {
|
|
4210
4554
|
if (timeoutTimer) clearTimeout(timeoutTimer);
|
|
@@ -4234,12 +4578,12 @@ async function waitForServerListening(server) {
|
|
|
4234
4578
|
}
|
|
4235
4579
|
async function openBrowser({
|
|
4236
4580
|
transaction,
|
|
4237
|
-
|
|
4581
|
+
action,
|
|
4238
4582
|
silent,
|
|
4239
4583
|
onProgress
|
|
4240
4584
|
}) {
|
|
4241
4585
|
if (!silent) {
|
|
4242
|
-
log_default.info(`Opening your browser to ${
|
|
4586
|
+
log_default.info(`Opening your browser to ${action}.`);
|
|
4243
4587
|
log_default.info("If it doesn't open, visit:", transaction.browserAuthUrl);
|
|
4244
4588
|
}
|
|
4245
4589
|
onProgress?.({ type: "browser_opening", url: transaction.browserAuthUrl });
|
|
@@ -4249,9 +4593,7 @@ async function openBrowser({
|
|
|
4249
4593
|
} catch (err) {
|
|
4250
4594
|
const reason = err instanceof Error ? err.message : String(err);
|
|
4251
4595
|
if (!silent) {
|
|
4252
|
-
log_default.info(
|
|
4253
|
-
`Browser did not open automatically to ${authAction}: ${reason}`
|
|
4254
|
-
);
|
|
4596
|
+
log_default.info(`Browser did not open automatically to ${action}: ${reason}`);
|
|
4255
4597
|
log_default.info("Visit this URL manually:", transaction.browserAuthUrl);
|
|
4256
4598
|
}
|
|
4257
4599
|
onProgress?.({
|
|
@@ -4280,61 +4622,10 @@ async function closeServer({
|
|
|
4280
4622
|
});
|
|
4281
4623
|
}
|
|
4282
4624
|
|
|
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
4625
|
// src/utils/auth/account-auth.ts
|
|
4336
4626
|
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
4627
|
var SIGNUP_RECOVERY_MESSAGE = "Restart `zapier-sdk signup` to generate a fresh signup URL and try again.";
|
|
4628
|
+
var HEADLESS_LOGIN_RECOVERY_MESSAGE = "Restart `zapier-sdk login --headless` to generate a fresh login URL and try again.";
|
|
4338
4629
|
var HEADLESS_SIGNUP_RECOVERY_MESSAGE = "Restart `zapier-sdk signup --headless` to generate a fresh signup URL and try again.";
|
|
4339
4630
|
function getEntryPointLabel(entryPoint) {
|
|
4340
4631
|
return entryPoint === "signup" ? "Signup" : "Login";
|
|
@@ -4454,7 +4745,8 @@ Logging out will delete these credentials and may interrupt other Zapier SDK or
|
|
|
4454
4745
|
Log out and ${getActiveCredentialsAction(entryPoint)}?`
|
|
4455
4746
|
}) : promptlessCredentialResetError(activeCredentials);
|
|
4456
4747
|
if (!confirmed) {
|
|
4457
|
-
|
|
4748
|
+
process.stderr.write(`${flowLabel} cancelled.
|
|
4749
|
+
`);
|
|
4458
4750
|
return false;
|
|
4459
4751
|
}
|
|
4460
4752
|
try {
|
|
@@ -4473,7 +4765,8 @@ Log out and ${getActiveCredentialsAction(entryPoint)}?`
|
|
|
4473
4765
|
message: `${flowLabel} cleanup failed. Reset local session state and continue?`
|
|
4474
4766
|
});
|
|
4475
4767
|
if (!reset) {
|
|
4476
|
-
|
|
4768
|
+
process.stderr.write(`${flowLabel} cancelled.
|
|
4769
|
+
`);
|
|
4477
4770
|
return false;
|
|
4478
4771
|
}
|
|
4479
4772
|
await deleteStoredClientCredentials({
|
|
@@ -4487,7 +4780,8 @@ Log out and ${getActiveCredentialsAction(entryPoint)}?`
|
|
|
4487
4780
|
message: LEGACY_JWT_UPGRADE_PROMPT
|
|
4488
4781
|
}) : promptlessLegacyJwtUpgradeError();
|
|
4489
4782
|
if (!confirmed) {
|
|
4490
|
-
|
|
4783
|
+
process.stderr.write(`${flowLabel} cancelled.
|
|
4784
|
+
`);
|
|
4491
4785
|
return false;
|
|
4492
4786
|
}
|
|
4493
4787
|
}
|
|
@@ -4582,7 +4876,14 @@ async function runOauthForEntryPoint({
|
|
|
4582
4876
|
);
|
|
4583
4877
|
}
|
|
4584
4878
|
return runOauthWithRedaction(
|
|
4585
|
-
() => runLoginOauthFlow({
|
|
4879
|
+
() => runLoginOauthFlow({
|
|
4880
|
+
timeoutMs,
|
|
4881
|
+
pkceCredentials,
|
|
4882
|
+
baseUrl: baseUrl2,
|
|
4883
|
+
headless,
|
|
4884
|
+
interactive,
|
|
4885
|
+
recoveryMessage: headless ? HEADLESS_LOGIN_RECOVERY_MESSAGE : void 0
|
|
4886
|
+
})
|
|
4586
4887
|
);
|
|
4587
4888
|
}
|
|
4588
4889
|
async function runAccountAuth({
|
|
@@ -4594,6 +4895,7 @@ async function runAccountAuth({
|
|
|
4594
4895
|
const interactive = !resolveNonInteractive(options);
|
|
4595
4896
|
const resolvedCredentials = await sdk.context.resolveCredentials();
|
|
4596
4897
|
const pkceCredentials = toPkceCredentials(resolvedCredentials);
|
|
4898
|
+
const headless = options.headless === true;
|
|
4597
4899
|
const credentialsBaseUrl2 = await resolveCredentialsBaseUrl({
|
|
4598
4900
|
...sdk.context,
|
|
4599
4901
|
resolvedCredentials
|
|
@@ -4623,7 +4925,7 @@ async function runAccountAuth({
|
|
|
4623
4925
|
timeoutMs: timeoutSeconds * 1e3,
|
|
4624
4926
|
pkceCredentials,
|
|
4625
4927
|
baseUrl: credentialsBaseUrl2,
|
|
4626
|
-
headless
|
|
4928
|
+
headless,
|
|
4627
4929
|
interactive
|
|
4628
4930
|
});
|
|
4629
4931
|
const scopedApi = zapierSdk.getOrCreateApiClient({
|
|
@@ -4631,9 +4933,10 @@ async function runAccountAuth({
|
|
|
4631
4933
|
baseUrl: credentialsBaseUrl2
|
|
4632
4934
|
});
|
|
4633
4935
|
const profile = await getProfile(scopedApi);
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4936
|
+
process.stderr.write(`${getProfileMessage(entryPoint, profile.email)}
|
|
4937
|
+
`);
|
|
4938
|
+
process.stderr.write(
|
|
4939
|
+
"\nGenerating credentials so this machine can make authenticated requests on your behalf.\n"
|
|
4637
4940
|
);
|
|
4638
4941
|
const credentialName = providedName ?? await resolveCredentialName({
|
|
4639
4942
|
email: profile.email,
|
|
@@ -4649,11 +4952,12 @@ async function runAccountAuth({
|
|
|
4649
4952
|
useApprovals,
|
|
4650
4953
|
cleanupLogPrefix: entryPoint
|
|
4651
4954
|
});
|
|
4652
|
-
|
|
4653
|
-
`\u2705 Credentials "${credentialName}" created and set as default. You are ready to use the Zapier SDK
|
|
4955
|
+
process.stderr.write(
|
|
4956
|
+
`\u2705 Credentials "${credentialName}" created and set as default. You are ready to use the Zapier SDK.
|
|
4957
|
+
`
|
|
4654
4958
|
);
|
|
4655
4959
|
if (useApprovals) {
|
|
4656
|
-
|
|
4960
|
+
process.stderr.write("\u{1F510} Approvals are enabled for these credentials.\n");
|
|
4657
4961
|
}
|
|
4658
4962
|
emitAccountAuthSuccess({ sdk, profile, clientId });
|
|
4659
4963
|
}
|
|
@@ -4672,7 +4976,10 @@ var LoginSchema = zod.z.object({
|
|
|
4672
4976
|
skipPrompts: zod.z.boolean().optional().meta({
|
|
4673
4977
|
deprecated: true,
|
|
4674
4978
|
deprecationMessage: "Use --non-interactive instead."
|
|
4675
|
-
})
|
|
4979
|
+
}),
|
|
4980
|
+
headless: zod.z.boolean().optional().describe(
|
|
4981
|
+
"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."
|
|
4982
|
+
)
|
|
4676
4983
|
}).describe("Log in to Zapier to access your account");
|
|
4677
4984
|
|
|
4678
4985
|
// src/plugins/login/index.ts
|
|
@@ -7304,7 +7611,7 @@ function buildBoxLines(message) {
|
|
|
7304
7611
|
// package.json with { type: 'json' }
|
|
7305
7612
|
var package_default2 = {
|
|
7306
7613
|
name: "@zapier/zapier-sdk-cli",
|
|
7307
|
-
version: "0.
|
|
7614
|
+
version: "0.61.1"};
|
|
7308
7615
|
|
|
7309
7616
|
// src/sdk.ts
|
|
7310
7617
|
zapierSdk.injectCliLogin(login_exports);
|
|
@@ -7381,6 +7688,9 @@ function createZapierCliSdk2(options = {}) {
|
|
|
7381
7688
|
|
|
7382
7689
|
// src/utils/extensions.ts
|
|
7383
7690
|
var ENV_VAR = "ZAPIER_SDK_EXTENSIONS";
|
|
7691
|
+
function isModelPlugin(value) {
|
|
7692
|
+
return typeof value === "object" && value !== null && "pluginType" in value && typeof value.pluginType === "string";
|
|
7693
|
+
}
|
|
7384
7694
|
async function resolveExtensions() {
|
|
7385
7695
|
const seen = /* @__PURE__ */ new Set();
|
|
7386
7696
|
const specs = readEnvSpecs().filter((spec) => {
|
|
@@ -7413,8 +7723,11 @@ function normalizeExtension(exported) {
|
|
|
7413
7723
|
if (typeof exported === "function") {
|
|
7414
7724
|
return [exported];
|
|
7415
7725
|
}
|
|
7726
|
+
if (isModelPlugin(exported)) {
|
|
7727
|
+
return [exported];
|
|
7728
|
+
}
|
|
7416
7729
|
if (Array.isArray(exported)) {
|
|
7417
|
-
if (exported.every((e) => typeof e === "function")) {
|
|
7730
|
+
if (exported.every((e) => typeof e === "function" || isModelPlugin(e))) {
|
|
7418
7731
|
return exported;
|
|
7419
7732
|
}
|
|
7420
7733
|
return null;
|