@zapier/zapier-sdk-cli 0.1.1 ā 0.2.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/dist/cli.js +13 -11
- package/dist/commands/configPath.d.ts +2 -0
- package/dist/commands/configPath.js +9 -0
- package/dist/commands/index.d.ts +4 -0
- package/dist/commands/index.js +4 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +25 -0
- package/dist/commands/logout.d.ts +2 -0
- package/dist/commands/logout.js +16 -0
- package/dist/commands/whoami.d.ts +2 -0
- package/dist/commands/whoami.js +17 -0
- package/dist/utils/api/client.d.ts +15 -0
- package/dist/utils/api/client.js +27 -0
- package/dist/utils/auth/login.d.ts +2 -0
- package/dist/utils/auth/login.js +134 -0
- package/dist/utils/cli-generator.js +42 -48
- package/dist/utils/constants.d.ts +5 -0
- package/dist/utils/constants.js +6 -0
- package/dist/utils/getCallablePromise.d.ts +6 -0
- package/dist/utils/getCallablePromise.js +14 -0
- package/dist/utils/log.d.ts +7 -0
- package/dist/utils/log.js +16 -0
- package/dist/utils/pager.js +10 -20
- package/dist/utils/parameter-resolver.js +34 -41
- package/dist/utils/schema-formatter.js +11 -17
- package/dist/utils/serializeAsync.d.ts +2 -0
- package/dist/utils/serializeAsync.js +16 -0
- package/dist/utils/spinner.d.ts +1 -0
- package/dist/utils/spinner.js +13 -0
- package/package.json +8 -2
- package/src/cli.ts +13 -3
- package/src/commands/configPath.ts +10 -0
- package/src/commands/index.ts +4 -0
- package/src/commands/login.ts +34 -0
- package/src/commands/logout.ts +19 -0
- package/src/commands/whoami.ts +25 -0
- package/src/utils/api/client.ts +44 -0
- package/src/utils/auth/login.ts +190 -0
- package/src/utils/constants.ts +9 -0
- package/src/utils/getCallablePromise.ts +21 -0
- package/src/utils/log.ts +18 -0
- package/src/utils/serializeAsync.ts +26 -0
- package/src/utils/spinner.ts +16 -0
- package/tsconfig.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const program = new commander_1.Command();
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { createZapierSdk } from "@zapier/zapier-sdk";
|
|
4
|
+
import { generateCliCommands } from "./utils/cli-generator";
|
|
5
|
+
import { createLoginCommand, createLogoutCommand, createWhoamiCommand, createConfigPathCommand, } from "./commands";
|
|
6
|
+
const program = new Command();
|
|
8
7
|
program
|
|
9
8
|
.name("zapier-sdk")
|
|
10
9
|
.description("CLI for Zapier SDK - Commands auto-generated from SDK schemas")
|
|
@@ -12,12 +11,15 @@ program
|
|
|
12
11
|
.option("--debug", "Enable debug logging");
|
|
13
12
|
// Check for debug flag early
|
|
14
13
|
const isDebugMode = process.env.DEBUG === "true" || process.argv.includes("--debug");
|
|
15
|
-
// Create SDK instance
|
|
16
|
-
|
|
17
|
-
const sdk = (0, zapier_sdk_1.createZapierSdk)({
|
|
18
|
-
// Token will be picked up from ZAPIER_TOKEN env var or provided via options
|
|
14
|
+
// Create SDK instance - automatically handles token resolution
|
|
15
|
+
const sdk = createZapierSdk({
|
|
19
16
|
debug: isDebugMode,
|
|
20
17
|
});
|
|
18
|
+
// Add auth commands before generating SDK commands
|
|
19
|
+
program.addCommand(createLoginCommand());
|
|
20
|
+
program.addCommand(createLogoutCommand());
|
|
21
|
+
program.addCommand(createWhoamiCommand());
|
|
22
|
+
program.addCommand(createConfigPathCommand());
|
|
21
23
|
// Generate CLI commands from SDK schemas
|
|
22
|
-
|
|
24
|
+
generateCliCommands(program, sdk);
|
|
23
25
|
program.parse();
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { getConfigPath } from "@zapier/zapier-sdk";
|
|
3
|
+
export function createConfigPathCommand() {
|
|
4
|
+
return new Command("get-config-path")
|
|
5
|
+
.description("Show the path to the configuration file")
|
|
6
|
+
.action(async () => {
|
|
7
|
+
console.log(`Configuration file: ${getConfigPath()}`);
|
|
8
|
+
});
|
|
9
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import login from "../utils/auth/login";
|
|
3
|
+
import { getLoggedInUser } from "@zapier/zapier-sdk";
|
|
4
|
+
export function createLoginCommand() {
|
|
5
|
+
return new Command("login")
|
|
6
|
+
.description("Log in to Zapier to access your account")
|
|
7
|
+
.option("--timeout <seconds>", "Login timeout in seconds (default: 300)", "300")
|
|
8
|
+
.action(async (options) => {
|
|
9
|
+
try {
|
|
10
|
+
const timeoutSeconds = parseInt(options.timeout, 10);
|
|
11
|
+
if (isNaN(timeoutSeconds) || timeoutSeconds <= 0) {
|
|
12
|
+
throw new Error("Timeout must be a positive number");
|
|
13
|
+
}
|
|
14
|
+
await login(timeoutSeconds * 1000); // Convert to milliseconds
|
|
15
|
+
const user = await getLoggedInUser();
|
|
16
|
+
console.log(`ā
Successfully logged in as ${user.email}`);
|
|
17
|
+
// Force immediate exit to prevent hanging (especially in development with tsx)
|
|
18
|
+
setTimeout(() => process.exit(0), 100);
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
console.error("ā Login failed:", error instanceof Error ? error.message : "Unknown error");
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { logout } from "@zapier/zapier-sdk";
|
|
3
|
+
export function createLogoutCommand() {
|
|
4
|
+
return new Command("logout")
|
|
5
|
+
.description("Log out of your Zapier account")
|
|
6
|
+
.action(async () => {
|
|
7
|
+
try {
|
|
8
|
+
logout();
|
|
9
|
+
console.log("ā
Successfully logged out");
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
console.error("ā Logout failed:", error instanceof Error ? error.message : "Unknown error");
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { getLoggedInUser } from "@zapier/zapier-sdk";
|
|
3
|
+
import { spinPromise } from "../utils/spinner";
|
|
4
|
+
export function createWhoamiCommand() {
|
|
5
|
+
return new Command("whoami")
|
|
6
|
+
.description("Show current login status and user information")
|
|
7
|
+
.action(async () => {
|
|
8
|
+
try {
|
|
9
|
+
const user = await spinPromise(getLoggedInUser(), "Checking login status...");
|
|
10
|
+
console.log(`ā
Logged in as ${user.email} (Account ID: ${user.accountId})`);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
console.log("ā Not logged in. Use 'zapier-sdk login' to authenticate.");
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ApiResponse<T = any> {
|
|
2
|
+
data: T;
|
|
3
|
+
status: number;
|
|
4
|
+
}
|
|
5
|
+
export declare const createApiClient: () => {
|
|
6
|
+
post: <T = any>(url: string, data: any, options?: {
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
}) => Promise<ApiResponse<T>>;
|
|
9
|
+
};
|
|
10
|
+
declare const api: {
|
|
11
|
+
post: <T = any>(url: string, data: any, options?: {
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
}) => Promise<ApiResponse<T>>;
|
|
14
|
+
};
|
|
15
|
+
export default api;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const createApiClient = () => {
|
|
2
|
+
const post = async (url, data, options = {}) => {
|
|
3
|
+
const { headers = {} } = options;
|
|
4
|
+
const response = await fetch(url, {
|
|
5
|
+
method: "POST",
|
|
6
|
+
headers: {
|
|
7
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
8
|
+
Connection: "close",
|
|
9
|
+
...headers,
|
|
10
|
+
},
|
|
11
|
+
body: new URLSearchParams(data),
|
|
12
|
+
});
|
|
13
|
+
if (!response.ok) {
|
|
14
|
+
throw new Error(`${response.status} ${response.statusText}`);
|
|
15
|
+
}
|
|
16
|
+
const responseData = await response.json();
|
|
17
|
+
return {
|
|
18
|
+
data: responseData,
|
|
19
|
+
status: response.status,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
return {
|
|
23
|
+
post,
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
const api = createApiClient();
|
|
27
|
+
export default api;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import open from "open";
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import express from "express";
|
|
4
|
+
import pkceChallenge from "pkce-challenge";
|
|
5
|
+
import { AUTH_MODE_HEADER, LOGIN_CLIENT_ID, LOGIN_PORTS, LOGIN_TIMEOUT_MS, ZAPIER_BASE, } from "../constants";
|
|
6
|
+
import { spinPromise } from "../spinner";
|
|
7
|
+
import log from "../log";
|
|
8
|
+
import api from "../api/client";
|
|
9
|
+
import getCallablePromise from "../getCallablePromise";
|
|
10
|
+
import { updateLogin, logout } from "@zapier/zapier-sdk";
|
|
11
|
+
const findAvailablePort = () => {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
let portIndex = 0;
|
|
14
|
+
const tryPort = (port) => {
|
|
15
|
+
const server = express().listen(port, () => {
|
|
16
|
+
server.close();
|
|
17
|
+
resolve(port);
|
|
18
|
+
});
|
|
19
|
+
server.on("error", (err) => {
|
|
20
|
+
if (err.code === "EADDRINUSE") {
|
|
21
|
+
if (portIndex < LOGIN_PORTS.length) {
|
|
22
|
+
// Try next predefined port
|
|
23
|
+
tryPort(LOGIN_PORTS[portIndex++]);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
// All configured ports are busy
|
|
27
|
+
reject(new Error(`All configured OAuth callback ports are busy: ${LOGIN_PORTS.join(", ")}. Please try again later or close applications using these ports.`));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
reject(err);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
if (LOGIN_PORTS.length > 0) {
|
|
36
|
+
tryPort(LOGIN_PORTS[portIndex++]);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
reject(new Error("No OAuth callback ports configured"));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
const generateRandomString = () => {
|
|
44
|
+
const array = new Uint32Array(28);
|
|
45
|
+
crypto.getRandomValues(array);
|
|
46
|
+
return Array.from(array, (dec) => ("0" + dec.toString(16)).substring(-2)).join("");
|
|
47
|
+
};
|
|
48
|
+
const login = async (timeoutMs = LOGIN_TIMEOUT_MS) => {
|
|
49
|
+
// Force logout
|
|
50
|
+
logout();
|
|
51
|
+
// Find an available port
|
|
52
|
+
const availablePort = await findAvailablePort();
|
|
53
|
+
const redirectUri = `http://localhost:${availablePort}/oauth`;
|
|
54
|
+
log.info(`Using port ${availablePort} for OAuth callback`);
|
|
55
|
+
const { promise: promisedCode, resolve: setCode } = getCallablePromise();
|
|
56
|
+
const app = express();
|
|
57
|
+
app.get("/oauth", (req, res) => {
|
|
58
|
+
setCode(String(req.query.code));
|
|
59
|
+
// Set headers to prevent keep-alive
|
|
60
|
+
res.setHeader("Connection", "close");
|
|
61
|
+
res.end("You can now close this tab and return to the CLI.");
|
|
62
|
+
});
|
|
63
|
+
const server = app.listen(availablePort);
|
|
64
|
+
// Track connections to force close them if needed
|
|
65
|
+
const connections = new Set();
|
|
66
|
+
server.on("connection", (conn) => {
|
|
67
|
+
connections.add(conn);
|
|
68
|
+
conn.on("close", () => connections.delete(conn));
|
|
69
|
+
});
|
|
70
|
+
// Set up signal handlers for graceful shutdown
|
|
71
|
+
const cleanup = () => {
|
|
72
|
+
server.close();
|
|
73
|
+
log.info("\nā Login cancelled by user");
|
|
74
|
+
process.exit(0);
|
|
75
|
+
};
|
|
76
|
+
process.on("SIGINT", cleanup);
|
|
77
|
+
process.on("SIGTERM", cleanup);
|
|
78
|
+
const { code_verifier: codeVerifier, code_challenge: codeChallenge } = await pkceChallenge();
|
|
79
|
+
const authUrl = `${ZAPIER_BASE}/oauth/authorize/?${new URLSearchParams({
|
|
80
|
+
response_type: "code",
|
|
81
|
+
client_id: LOGIN_CLIENT_ID,
|
|
82
|
+
redirect_uri: redirectUri,
|
|
83
|
+
scope: "internal offline_access",
|
|
84
|
+
state: generateRandomString(),
|
|
85
|
+
code_challenge: codeChallenge,
|
|
86
|
+
code_challenge_method: "S256",
|
|
87
|
+
}).toString()}`;
|
|
88
|
+
log.info("Opening your browser to log in.");
|
|
89
|
+
log.info("If it doesn't open, visit:", authUrl);
|
|
90
|
+
open(authUrl);
|
|
91
|
+
try {
|
|
92
|
+
await spinPromise(Promise.race([
|
|
93
|
+
promisedCode,
|
|
94
|
+
new Promise((_resolve, reject) => setTimeout(() => {
|
|
95
|
+
reject(new Error(`Login timed out after ${Math.round(timeoutMs / 1000)} seconds.`));
|
|
96
|
+
}, timeoutMs)),
|
|
97
|
+
]), "Waiting for you to login and authorize");
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
// Remove signal handlers
|
|
101
|
+
process.off("SIGINT", cleanup);
|
|
102
|
+
process.off("SIGTERM", cleanup);
|
|
103
|
+
// Close server with timeout and force-close connections if needed
|
|
104
|
+
await new Promise((resolve) => {
|
|
105
|
+
const timeout = setTimeout(() => {
|
|
106
|
+
log.info("Server close timed out, forcing connection shutdown...");
|
|
107
|
+
// Force close all connections
|
|
108
|
+
connections.forEach((conn) => conn.destroy());
|
|
109
|
+
resolve();
|
|
110
|
+
}, 1000); // 1 second timeout
|
|
111
|
+
server.close(() => {
|
|
112
|
+
clearTimeout(timeout);
|
|
113
|
+
resolve();
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
log.info("Exchanging authorization code for tokens...");
|
|
118
|
+
const { data } = await api.post(`${ZAPIER_BASE}/oauth/token/`, {
|
|
119
|
+
grant_type: "authorization_code",
|
|
120
|
+
code: await promisedCode,
|
|
121
|
+
redirect_uri: redirectUri,
|
|
122
|
+
client_id: LOGIN_CLIENT_ID,
|
|
123
|
+
code_verifier: codeVerifier,
|
|
124
|
+
}, {
|
|
125
|
+
headers: {
|
|
126
|
+
[AUTH_MODE_HEADER]: "no",
|
|
127
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
updateLogin(data);
|
|
131
|
+
log.info("Token exchange completed successfully");
|
|
132
|
+
return data.access_token;
|
|
133
|
+
};
|
|
134
|
+
export default login;
|
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const zapier_sdk_1 = require("@zapier/zapier-sdk");
|
|
9
|
-
const parameter_resolver_1 = require("./parameter-resolver");
|
|
10
|
-
const pager_1 = require("./pager");
|
|
11
|
-
const schema_formatter_1 = require("./schema-formatter");
|
|
12
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
13
|
-
const util_1 = __importDefault(require("util"));
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { hasResolver, isPositional } from "@zapier/zapier-sdk";
|
|
3
|
+
import { SchemaParameterResolver } from "./parameter-resolver";
|
|
4
|
+
import { createPager } from "./pager";
|
|
5
|
+
import { formatItemsFromSchema } from "./schema-formatter";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import util from "util";
|
|
14
8
|
// ============================================================================
|
|
15
9
|
// JSON Formatting
|
|
16
10
|
// ============================================================================
|
|
@@ -20,17 +14,17 @@ function formatJsonOutput(data) {
|
|
|
20
14
|
typeof data === "object" &&
|
|
21
15
|
!Array.isArray(data) &&
|
|
22
16
|
(data.success !== undefined || data.id || data.status)) {
|
|
23
|
-
console.log(
|
|
17
|
+
console.log(chalk.green("ā
Action completed successfully!\n"));
|
|
24
18
|
}
|
|
25
19
|
// Use util.inspect for colored output
|
|
26
|
-
console.log(
|
|
20
|
+
console.log(util.inspect(data, { colors: true, depth: null, breakLength: 80 }));
|
|
27
21
|
}
|
|
28
22
|
// ============================================================================
|
|
29
23
|
// Schema Analysis
|
|
30
24
|
// ============================================================================
|
|
31
25
|
function analyzeZodSchema(schema) {
|
|
32
26
|
const parameters = [];
|
|
33
|
-
if (schema instanceof
|
|
27
|
+
if (schema instanceof z.ZodObject) {
|
|
34
28
|
const shape = schema.shape;
|
|
35
29
|
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
36
30
|
const param = analyzeZodField(key, fieldSchema);
|
|
@@ -46,11 +40,11 @@ function analyzeZodField(name, schema) {
|
|
|
46
40
|
let required = true;
|
|
47
41
|
let defaultValue = undefined;
|
|
48
42
|
// Unwrap optional and default wrappers
|
|
49
|
-
if (baseSchema instanceof
|
|
43
|
+
if (baseSchema instanceof z.ZodOptional) {
|
|
50
44
|
required = false;
|
|
51
45
|
baseSchema = baseSchema._def.innerType;
|
|
52
46
|
}
|
|
53
|
-
if (baseSchema instanceof
|
|
47
|
+
if (baseSchema instanceof z.ZodDefault) {
|
|
54
48
|
required = false;
|
|
55
49
|
defaultValue = baseSchema._def.defaultValue();
|
|
56
50
|
baseSchema = baseSchema._def.innerType;
|
|
@@ -58,23 +52,23 @@ function analyzeZodField(name, schema) {
|
|
|
58
52
|
// Determine parameter type
|
|
59
53
|
let paramType = "string";
|
|
60
54
|
let choices;
|
|
61
|
-
if (baseSchema instanceof
|
|
55
|
+
if (baseSchema instanceof z.ZodString) {
|
|
62
56
|
paramType = "string";
|
|
63
57
|
}
|
|
64
|
-
else if (baseSchema instanceof
|
|
58
|
+
else if (baseSchema instanceof z.ZodNumber) {
|
|
65
59
|
paramType = "number";
|
|
66
60
|
}
|
|
67
|
-
else if (baseSchema instanceof
|
|
61
|
+
else if (baseSchema instanceof z.ZodBoolean) {
|
|
68
62
|
paramType = "boolean";
|
|
69
63
|
}
|
|
70
|
-
else if (baseSchema instanceof
|
|
64
|
+
else if (baseSchema instanceof z.ZodArray) {
|
|
71
65
|
paramType = "array";
|
|
72
66
|
}
|
|
73
|
-
else if (baseSchema instanceof
|
|
67
|
+
else if (baseSchema instanceof z.ZodEnum) {
|
|
74
68
|
paramType = "string";
|
|
75
69
|
choices = baseSchema._def.values;
|
|
76
70
|
}
|
|
77
|
-
else if (baseSchema instanceof
|
|
71
|
+
else if (baseSchema instanceof z.ZodRecord) {
|
|
78
72
|
// Handle Record<string, any> as JSON string input
|
|
79
73
|
paramType = "string";
|
|
80
74
|
}
|
|
@@ -86,8 +80,8 @@ function analyzeZodField(name, schema) {
|
|
|
86
80
|
description: schema.description,
|
|
87
81
|
default: defaultValue,
|
|
88
82
|
choices,
|
|
89
|
-
hasResolver:
|
|
90
|
-
isPositional:
|
|
83
|
+
hasResolver: hasResolver(name),
|
|
84
|
+
isPositional: isPositional(schema),
|
|
91
85
|
};
|
|
92
86
|
}
|
|
93
87
|
// ============================================================================
|
|
@@ -110,7 +104,7 @@ function methodNameToCliCommand(methodName) {
|
|
|
110
104
|
// ============================================================================
|
|
111
105
|
// CLI Command Generation - Completely Generic
|
|
112
106
|
// ============================================================================
|
|
113
|
-
function generateCliCommands(program, sdk) {
|
|
107
|
+
export function generateCliCommands(program, sdk) {
|
|
114
108
|
// Check if SDK has registry
|
|
115
109
|
if (!sdk.__registry) {
|
|
116
110
|
console.error("SDK registry not available");
|
|
@@ -145,7 +139,7 @@ function createCommandConfig(cliCommandName, sdkMethodName, schema, sdk) {
|
|
|
145
139
|
// Convert CLI args to SDK method parameters
|
|
146
140
|
const rawParams = convertCliArgsToSdkParams(parameters, args.slice(0, -1), options);
|
|
147
141
|
// Resolve missing parameters interactively using schema metadata
|
|
148
|
-
const resolver = new
|
|
142
|
+
const resolver = new SchemaParameterResolver();
|
|
149
143
|
const resolvedParams = await resolver.resolveParameters(schema, rawParams, sdk);
|
|
150
144
|
if (shouldUsePaging && !shouldUseJson) {
|
|
151
145
|
// Use interactive paging for list commands
|
|
@@ -172,8 +166,8 @@ function createCommandConfig(cliCommandName, sdkMethodName, schema, sdk) {
|
|
|
172
166
|
}
|
|
173
167
|
else if (hasOutputFile) {
|
|
174
168
|
// Show success message for file output instead of printing generated content
|
|
175
|
-
console.log(
|
|
176
|
-
console.log(
|
|
169
|
+
console.log(chalk.green(`ā
${cliCommandName} completed successfully!`));
|
|
170
|
+
console.log(chalk.gray(`Output written to: ${resolvedParams.output}`));
|
|
177
171
|
}
|
|
178
172
|
}
|
|
179
173
|
}
|
|
@@ -182,19 +176,19 @@ function createCommandConfig(cliCommandName, sdkMethodName, schema, sdk) {
|
|
|
182
176
|
if (error instanceof Error && error.message.includes('"code"')) {
|
|
183
177
|
try {
|
|
184
178
|
const validationErrors = JSON.parse(error.message);
|
|
185
|
-
console.error(
|
|
179
|
+
console.error(chalk.red("ā Validation Error:"));
|
|
186
180
|
validationErrors.forEach((err) => {
|
|
187
181
|
const field = err.path?.join(".") || "unknown";
|
|
188
|
-
console.error(
|
|
182
|
+
console.error(chalk.yellow(` ⢠${field}: ${err.message}`));
|
|
189
183
|
});
|
|
190
|
-
console.error("\n" +
|
|
184
|
+
console.error("\n" + chalk.dim(`Use --help to see available options`));
|
|
191
185
|
}
|
|
192
186
|
catch {
|
|
193
|
-
console.error(
|
|
187
|
+
console.error(chalk.red("Error:"), error.message);
|
|
194
188
|
}
|
|
195
189
|
}
|
|
196
190
|
else {
|
|
197
|
-
console.error(
|
|
191
|
+
console.error(chalk.red("Error:"), error instanceof Error ? error.message : "Unknown error");
|
|
198
192
|
}
|
|
199
193
|
process.exit(1);
|
|
200
194
|
}
|
|
@@ -294,8 +288,8 @@ function convertValue(value, type) {
|
|
|
294
288
|
async function handlePaginatedList(sdkMethodName, baseParams, sdk, schema) {
|
|
295
289
|
const limit = baseParams.limit || 20;
|
|
296
290
|
const itemName = getItemNameFromMethod(sdkMethodName);
|
|
297
|
-
console.log(
|
|
298
|
-
const pager =
|
|
291
|
+
console.log(chalk.blue(`š Fetching ${itemName}...`));
|
|
292
|
+
const pager = createPager({
|
|
299
293
|
pageSize: Math.min(limit, 20),
|
|
300
294
|
itemName,
|
|
301
295
|
});
|
|
@@ -304,14 +298,14 @@ async function handlePaginatedList(sdkMethodName, baseParams, sdk, schema) {
|
|
|
304
298
|
if (items.length > 0) {
|
|
305
299
|
console.clear();
|
|
306
300
|
}
|
|
307
|
-
console.log(
|
|
301
|
+
console.log(chalk.blue(`š ${getListTitleFromMethod(sdkMethodName)}\n`));
|
|
308
302
|
if (items.length === 0) {
|
|
309
|
-
console.log(
|
|
303
|
+
console.log(chalk.yellow(`No ${itemName} found.`));
|
|
310
304
|
return;
|
|
311
305
|
}
|
|
312
306
|
// Use schema for formatting
|
|
313
307
|
if (schema) {
|
|
314
|
-
|
|
308
|
+
formatItemsFromSchema(schema, items);
|
|
315
309
|
}
|
|
316
310
|
else {
|
|
317
311
|
// Fallback to generic formatting
|
|
@@ -320,7 +314,7 @@ async function handlePaginatedList(sdkMethodName, baseParams, sdk, schema) {
|
|
|
320
314
|
const totalInfo = totalAvailable
|
|
321
315
|
? ` of ${totalAvailable.toLocaleString()} total`
|
|
322
316
|
: "";
|
|
323
|
-
console.log(
|
|
317
|
+
console.log(chalk.green(`\nā
Showing ${totalShown}${totalInfo} ${itemName}`));
|
|
324
318
|
};
|
|
325
319
|
await pager.paginate((params) => sdk[sdkMethodName]({
|
|
326
320
|
...baseParams,
|
|
@@ -343,13 +337,13 @@ function formatNonPaginatedResults(result, requestedLimit, userSpecifiedLimit, u
|
|
|
343
337
|
}
|
|
344
338
|
const itemName = methodName ? getItemNameFromMethod(methodName) : "items";
|
|
345
339
|
if (result.length === 0) {
|
|
346
|
-
console.log(
|
|
340
|
+
console.log(chalk.yellow(`No ${itemName} found.`));
|
|
347
341
|
return;
|
|
348
342
|
}
|
|
349
|
-
console.log(
|
|
343
|
+
console.log(chalk.green(`\nā
Found ${result.length} ${itemName}:\n`));
|
|
350
344
|
// Use schema for formatting
|
|
351
345
|
if (schema) {
|
|
352
|
-
|
|
346
|
+
formatItemsFromSchema(schema, result);
|
|
353
347
|
}
|
|
354
348
|
else {
|
|
355
349
|
// Fallback to generic formatting
|
|
@@ -357,19 +351,19 @@ function formatNonPaginatedResults(result, requestedLimit, userSpecifiedLimit, u
|
|
|
357
351
|
}
|
|
358
352
|
// Show appropriate status message
|
|
359
353
|
if (userSpecifiedLimit && requestedLimit) {
|
|
360
|
-
console.log(
|
|
354
|
+
console.log(chalk.gray(`\nš Showing up to ${requestedLimit} ${itemName} (--limit ${requestedLimit})`));
|
|
361
355
|
}
|
|
362
356
|
else {
|
|
363
|
-
console.log(
|
|
357
|
+
console.log(chalk.gray(`\nš All available ${itemName} shown`));
|
|
364
358
|
}
|
|
365
359
|
}
|
|
366
360
|
function formatItemsGeneric(items) {
|
|
367
361
|
// Fallback formatting for items without schema metadata
|
|
368
362
|
items.forEach((item, index) => {
|
|
369
363
|
const name = item.name || item.key || item.id || "Item";
|
|
370
|
-
console.log(`${
|
|
364
|
+
console.log(`${chalk.gray(`${index + 1}.`)} ${chalk.cyan(name)}`);
|
|
371
365
|
if (item.description) {
|
|
372
|
-
console.log(` ${
|
|
366
|
+
console.log(` ${chalk.dim(item.description)}`);
|
|
373
367
|
}
|
|
374
368
|
console.log();
|
|
375
369
|
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const ZAPIER_BASE = "https://zapier.com";
|
|
2
|
+
export declare const LOGIN_CLIENT_ID = "K5eEnRE9TTmSFATdkkWhKF8NOKwoiOnYAyIqJjae";
|
|
3
|
+
export declare const LOGIN_PORTS: number[];
|
|
4
|
+
export declare const LOGIN_TIMEOUT_MS = 300000;
|
|
5
|
+
export declare const AUTH_MODE_HEADER = "X-Auth";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const ZAPIER_BASE = "https://zapier.com";
|
|
2
|
+
// OAuth client ID for zapier-sdk CLI
|
|
3
|
+
export const LOGIN_CLIENT_ID = "K5eEnRE9TTmSFATdkkWhKF8NOKwoiOnYAyIqJjae";
|
|
4
|
+
export const LOGIN_PORTS = [49505, 50575, 52804, 55981, 61010, 63851];
|
|
5
|
+
export const LOGIN_TIMEOUT_MS = 300000; // 5 minutes
|
|
6
|
+
export const AUTH_MODE_HEADER = "X-Auth";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const getCallablePromise = () => {
|
|
2
|
+
let resolve = () => { };
|
|
3
|
+
let reject = () => { };
|
|
4
|
+
const promise = new Promise((_resolve, _reject) => {
|
|
5
|
+
resolve = _resolve;
|
|
6
|
+
reject = _reject;
|
|
7
|
+
});
|
|
8
|
+
return {
|
|
9
|
+
promise,
|
|
10
|
+
resolve,
|
|
11
|
+
reject,
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export default getCallablePromise;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
const log = {
|
|
3
|
+
info: (message, ...args) => {
|
|
4
|
+
console.log(chalk.blue("ā¹"), message, ...args);
|
|
5
|
+
},
|
|
6
|
+
error: (message, ...args) => {
|
|
7
|
+
console.error(chalk.red("ā"), message, ...args);
|
|
8
|
+
},
|
|
9
|
+
success: (message, ...args) => {
|
|
10
|
+
console.log(chalk.green("ā"), message, ...args);
|
|
11
|
+
},
|
|
12
|
+
warn: (message, ...args) => {
|
|
13
|
+
console.log(chalk.yellow("ā "), message, ...args);
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
export default log;
|