@zapier/zapier-sdk-cli 0.32.4 → 0.34.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 +28 -0
- package/README.md +39 -2
- package/dist/cli.cjs +589 -110
- package/dist/cli.mjs +580 -102
- package/dist/index.cjs +531 -18
- package/dist/index.mjs +525 -15
- package/dist/package.json +3 -2
- package/dist/src/cli.js +11 -1
- package/dist/src/paths.d.ts +1 -0
- package/dist/src/paths.js +6 -0
- package/dist/src/plugins/index.d.ts +1 -0
- package/dist/src/plugins/index.js +1 -0
- package/dist/src/plugins/init/display.d.ts +9 -0
- package/dist/src/plugins/init/display.js +72 -0
- package/dist/src/plugins/init/index.d.ts +16 -0
- package/dist/src/plugins/init/index.js +61 -0
- package/dist/src/plugins/init/schemas.d.ts +8 -0
- package/dist/src/plugins/init/schemas.js +14 -0
- package/dist/src/plugins/init/steps.d.ts +39 -0
- package/dist/src/plugins/init/steps.js +141 -0
- package/dist/src/plugins/init/types.d.ts +31 -0
- package/dist/src/plugins/init/types.js +1 -0
- package/dist/src/plugins/init/utils.d.ts +48 -0
- package/dist/src/plugins/init/utils.js +135 -0
- package/dist/src/plugins/logout/index.js +1 -1
- package/dist/src/sdk.js +5 -2
- package/dist/src/utils/auth/login.js +33 -4
- package/dist/src/utils/package-manager-detector.d.ts +3 -1
- package/dist/src/utils/package-manager-detector.js +1 -0
- package/dist/src/utils/version-checker.js +1 -8
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -5
- package/templates/basic/AGENTS.md.hbs +15 -0
- package/templates/basic/README.md.hbs +21 -0
- package/templates/basic/package.json.hbs +17 -0
- package/templates/basic/src/index.ts +46 -0
- package/templates/basic/tsconfig.json +12 -0
package/dist/index.mjs
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as cliLogin from '@zapier/zapier-sdk-cli-login';
|
|
2
|
+
import { logout, getConfigPath, getLoggedInUser, getPkceLoginConfig, AUTH_MODE_HEADER, getLoginStorageMode, updateLogin } from '@zapier/zapier-sdk-cli-login';
|
|
3
|
+
import { createFunction, OutputPropertySchema, DEFAULT_CONFIG_PATH, injectCliLogin, getOsInfo, getPlatformVersions, getCiPlatform, isCi, createZapierSdkWithoutRegistry, registryPlugin, getReleaseId, getCurrentTimestamp, generateEventId, ZapierValidationError, ZapierUnknownError, batch, toSnakeCase, ZapierError, isCredentialsObject } from '@zapier/zapier-sdk';
|
|
2
4
|
import open from 'open';
|
|
3
5
|
import crypto, { createHash } from 'crypto';
|
|
4
6
|
import express from 'express';
|
|
5
7
|
import pkceChallenge from 'pkce-challenge';
|
|
6
|
-
import { logout, getConfigPath, getLoggedInUser, getPkceLoginConfig, AUTH_MODE_HEADER, updateLogin } from '@zapier/zapier-sdk-cli-login';
|
|
7
8
|
import ora from 'ora';
|
|
8
|
-
import
|
|
9
|
+
import chalk3 from 'chalk';
|
|
10
|
+
import inquirer from 'inquirer';
|
|
9
11
|
import { z } from 'zod';
|
|
10
12
|
import { startMcpServer } from '@zapier/zapier-sdk-mcp';
|
|
11
13
|
import { buildSync } from 'esbuild';
|
|
12
14
|
import * as fs from 'fs';
|
|
13
|
-
import { promises, createWriteStream } from 'fs';
|
|
15
|
+
import { promises, createWriteStream, existsSync, readdirSync, rmSync, mkdirSync, writeFileSync, copyFileSync, readFileSync } from 'fs';
|
|
14
16
|
import * as path from 'path';
|
|
15
|
-
import { resolve, join, dirname, basename } from 'path';
|
|
17
|
+
import { resolve, join, dirname, basename, relative, extname } from 'path';
|
|
16
18
|
import { mkdir, writeFile, access } from 'fs/promises';
|
|
17
19
|
import * as ts from 'typescript';
|
|
20
|
+
import 'is-installed-globally';
|
|
21
|
+
import { execSync } from 'child_process';
|
|
22
|
+
import Handlebars from 'handlebars';
|
|
23
|
+
import { fileURLToPath } from 'url';
|
|
18
24
|
|
|
19
25
|
// src/sdk.ts
|
|
20
26
|
var LOGIN_PORTS = [49505, 50575, 52804, 55981, 61010, 63851];
|
|
@@ -29,6 +35,14 @@ var ZapierCliUserCancellationError = class extends ZapierCliError {
|
|
|
29
35
|
this.exitCode = 0;
|
|
30
36
|
}
|
|
31
37
|
};
|
|
38
|
+
var ZapierCliExitError = class extends ZapierCliError {
|
|
39
|
+
constructor(message, exitCode = 1) {
|
|
40
|
+
super(message);
|
|
41
|
+
this.name = "ZapierCliExitError";
|
|
42
|
+
this.code = "ZAPIER_CLI_EXIT";
|
|
43
|
+
this.exitCode = exitCode;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
32
46
|
|
|
33
47
|
// src/utils/spinner.ts
|
|
34
48
|
var spinPromise = async (promise, text) => {
|
|
@@ -48,20 +62,20 @@ var spinPromise = async (promise, text) => {
|
|
|
48
62
|
};
|
|
49
63
|
var log = {
|
|
50
64
|
info: (message, ...args) => {
|
|
51
|
-
console.log(
|
|
65
|
+
console.log(chalk3.blue("\u2139"), message, ...args);
|
|
52
66
|
},
|
|
53
67
|
error: (message, ...args) => {
|
|
54
|
-
console.error(
|
|
68
|
+
console.error(chalk3.red("\u2716"), message, ...args);
|
|
55
69
|
},
|
|
56
70
|
success: (message, ...args) => {
|
|
57
|
-
console.log(
|
|
71
|
+
console.log(chalk3.green("\u2713"), message, ...args);
|
|
58
72
|
},
|
|
59
73
|
warn: (message, ...args) => {
|
|
60
|
-
console.log(
|
|
74
|
+
console.log(chalk3.yellow("\u26A0"), message, ...args);
|
|
61
75
|
},
|
|
62
76
|
debug: (message, ...args) => {
|
|
63
77
|
if (process.env.DEBUG === "true" || process.argv.includes("--debug")) {
|
|
64
|
-
console.log(
|
|
78
|
+
console.log(chalk3.gray("\u{1F41B}"), message, ...args);
|
|
65
79
|
}
|
|
66
80
|
}
|
|
67
81
|
};
|
|
@@ -168,7 +182,7 @@ var login = async ({
|
|
|
168
182
|
const scope = ensureOfflineAccess(
|
|
169
183
|
credentials?.scope || "internal credentials"
|
|
170
184
|
);
|
|
171
|
-
logout();
|
|
185
|
+
await logout();
|
|
172
186
|
const availablePort = await findAvailablePort();
|
|
173
187
|
const redirectUri = `http://localhost:${availablePort}/oauth`;
|
|
174
188
|
log_default.info(`Using port ${availablePort} for OAuth callback`);
|
|
@@ -261,7 +275,32 @@ var login = async ({
|
|
|
261
275
|
}
|
|
262
276
|
}
|
|
263
277
|
);
|
|
264
|
-
|
|
278
|
+
let targetStorage;
|
|
279
|
+
if (getLoginStorageMode() === "config") {
|
|
280
|
+
const { upgrade } = await inquirer.prompt([
|
|
281
|
+
{
|
|
282
|
+
type: "confirm",
|
|
283
|
+
name: "upgrade",
|
|
284
|
+
message: "Would you like to upgrade to system keychain storage? This is recommended to securely store your credentials. However, note that older SDK/CLI versions will NOT be able to read these credentials, so you will want to upgrade them to the latest version.",
|
|
285
|
+
default: true
|
|
286
|
+
}
|
|
287
|
+
]);
|
|
288
|
+
targetStorage = upgrade ? "keychain" : "config";
|
|
289
|
+
} else {
|
|
290
|
+
targetStorage = "keychain";
|
|
291
|
+
}
|
|
292
|
+
try {
|
|
293
|
+
await updateLogin(data, { storage: targetStorage });
|
|
294
|
+
} catch (err) {
|
|
295
|
+
if (targetStorage === "keychain") {
|
|
296
|
+
log_default.warn(
|
|
297
|
+
`Could not store credentials in system keychain. Storing in plaintext at ${getConfigPath()}.`
|
|
298
|
+
);
|
|
299
|
+
await updateLogin(data, { storage: "config" });
|
|
300
|
+
} else {
|
|
301
|
+
throw err;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
265
304
|
log_default.info("Token exchange completed successfully");
|
|
266
305
|
return data.access_token;
|
|
267
306
|
};
|
|
@@ -272,7 +311,7 @@ var LoginSchema = z.object({
|
|
|
272
311
|
|
|
273
312
|
// package.json
|
|
274
313
|
var package_default = {
|
|
275
|
-
version: "0.
|
|
314
|
+
version: "0.34.1"};
|
|
276
315
|
|
|
277
316
|
// src/telemetry/builders.ts
|
|
278
317
|
function createCliBaseEvent(context = {}) {
|
|
@@ -411,7 +450,7 @@ var LogoutSchema = z.object({}).describe("Log out of your Zapier account");
|
|
|
411
450
|
|
|
412
451
|
// src/plugins/logout/index.ts
|
|
413
452
|
var logoutWithSdk = createFunction(async function logoutWithSdk2(_options) {
|
|
414
|
-
logout();
|
|
453
|
+
await logout();
|
|
415
454
|
console.log("\u2705 Successfully logged out");
|
|
416
455
|
}, LogoutSchema);
|
|
417
456
|
var logoutPlugin = () => ({
|
|
@@ -2040,13 +2079,484 @@ var cliOverridesPlugin = ({ context }) => {
|
|
|
2040
2079
|
}
|
|
2041
2080
|
};
|
|
2042
2081
|
};
|
|
2082
|
+
var TEMPLATES = ["basic"];
|
|
2083
|
+
var InitSchema = z.object({
|
|
2084
|
+
projectName: z.string().min(1).describe("Name of the project directory to create"),
|
|
2085
|
+
skipPrompts: z.boolean().optional().describe("Skip all interactive prompts and accept all defaults")
|
|
2086
|
+
}).describe(
|
|
2087
|
+
"Create a new Zapier SDK project in a new directory with starter files"
|
|
2088
|
+
);
|
|
2089
|
+
function detectPackageManager(cwd = process.cwd()) {
|
|
2090
|
+
const ua = process.env.npm_config_user_agent;
|
|
2091
|
+
if (ua) {
|
|
2092
|
+
if (ua.includes("yarn")) return { name: "yarn", source: "runtime" };
|
|
2093
|
+
if (ua.includes("pnpm")) return { name: "pnpm", source: "runtime" };
|
|
2094
|
+
if (ua.includes("bun")) return { name: "bun", source: "runtime" };
|
|
2095
|
+
if (ua.includes("npm")) return { name: "npm", source: "runtime" };
|
|
2096
|
+
}
|
|
2097
|
+
const files = [
|
|
2098
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
2099
|
+
["yarn.lock", "yarn"],
|
|
2100
|
+
["bun.lockb", "bun"],
|
|
2101
|
+
["package-lock.json", "npm"]
|
|
2102
|
+
];
|
|
2103
|
+
for (const [file, name] of files) {
|
|
2104
|
+
if (existsSync(join(cwd, file))) {
|
|
2105
|
+
return { name, source: "lockfile" };
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
return { name: "unknown", source: "fallback" };
|
|
2109
|
+
}
|
|
2110
|
+
function getDirentParentPath(entry) {
|
|
2111
|
+
const e = entry;
|
|
2112
|
+
const parent = e.parentPath ?? e.path;
|
|
2113
|
+
if (!parent)
|
|
2114
|
+
throw new Error(
|
|
2115
|
+
"readdirSync entry missing parentPath/path \u2014 unsupported Node version"
|
|
2116
|
+
);
|
|
2117
|
+
return parent;
|
|
2118
|
+
}
|
|
2119
|
+
function toProjectName(name) {
|
|
2120
|
+
return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
2121
|
+
}
|
|
2122
|
+
function validateInitOptions({
|
|
2123
|
+
rawName,
|
|
2124
|
+
cwd
|
|
2125
|
+
}) {
|
|
2126
|
+
const projectName = toProjectName(rawName);
|
|
2127
|
+
if (!projectName) {
|
|
2128
|
+
throw new Error(
|
|
2129
|
+
`"${rawName}" results in an empty project name. Provide a name with at least one letter or number.`
|
|
2130
|
+
);
|
|
2131
|
+
}
|
|
2132
|
+
const projectDir = join(cwd, projectName);
|
|
2133
|
+
if (existsSync(projectDir)) {
|
|
2134
|
+
const contents = readdirSync(projectDir);
|
|
2135
|
+
if (contents.length > 0) {
|
|
2136
|
+
throw new Error(
|
|
2137
|
+
`Directory "${projectName}" already exists and is not empty. Choose a different name.`
|
|
2138
|
+
);
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
return { projectName, projectDir };
|
|
2142
|
+
}
|
|
2143
|
+
function createExec({ cwd }) {
|
|
2144
|
+
return (cmd) => execSync(cmd, {
|
|
2145
|
+
cwd,
|
|
2146
|
+
stdio: "inherit",
|
|
2147
|
+
shell: process.platform === "win32" ? "cmd.exe" : "/bin/sh"
|
|
2148
|
+
});
|
|
2149
|
+
}
|
|
2150
|
+
async function promptYesNo({
|
|
2151
|
+
message,
|
|
2152
|
+
defaultValue,
|
|
2153
|
+
skipPrompts
|
|
2154
|
+
}) {
|
|
2155
|
+
if (skipPrompts) return defaultValue;
|
|
2156
|
+
const { answer } = await inquirer.prompt([
|
|
2157
|
+
{ type: "confirm", name: "answer", message, default: defaultValue }
|
|
2158
|
+
]);
|
|
2159
|
+
return answer;
|
|
2160
|
+
}
|
|
2161
|
+
function getPackageManagerCommands({
|
|
2162
|
+
packageManager
|
|
2163
|
+
}) {
|
|
2164
|
+
return {
|
|
2165
|
+
installCmd: `${packageManager} install`,
|
|
2166
|
+
devCmd: packageManager === "yarn" ? "yarn dev" : `${packageManager} run dev`,
|
|
2167
|
+
devScript: packageManager === "bun" ? "bun src/index.ts" : "tsx src/index.ts",
|
|
2168
|
+
execCmd: {
|
|
2169
|
+
npm: "npx",
|
|
2170
|
+
yarn: "yarn dlx",
|
|
2171
|
+
pnpm: "pnpm dlx",
|
|
2172
|
+
bun: "bunx"
|
|
2173
|
+
}[packageManager]
|
|
2174
|
+
};
|
|
2175
|
+
}
|
|
2176
|
+
function isTemplateFile(name) {
|
|
2177
|
+
return extname(name) === ".hbs";
|
|
2178
|
+
}
|
|
2179
|
+
function getDestRelPath(relPath, isTemplate) {
|
|
2180
|
+
return isTemplate ? relPath.slice(0, -extname(relPath).length) : relPath;
|
|
2181
|
+
}
|
|
2182
|
+
function renderTemplate(srcPath, variables) {
|
|
2183
|
+
const source = readFileSync(srcPath, "utf-8");
|
|
2184
|
+
const template = Handlebars.compile(source, { noEscape: true });
|
|
2185
|
+
return template(variables);
|
|
2186
|
+
}
|
|
2187
|
+
function buildTemplateVariables({
|
|
2188
|
+
projectName,
|
|
2189
|
+
packageManager
|
|
2190
|
+
}) {
|
|
2191
|
+
const { execCmd, devScript, devCmd } = getPackageManagerCommands({
|
|
2192
|
+
packageManager
|
|
2193
|
+
});
|
|
2194
|
+
return {
|
|
2195
|
+
projectName,
|
|
2196
|
+
execCmd,
|
|
2197
|
+
devScript,
|
|
2198
|
+
devCmd,
|
|
2199
|
+
includeTsx: packageManager !== "bun"
|
|
2200
|
+
};
|
|
2201
|
+
}
|
|
2202
|
+
function cleanupProject({ projectDir }) {
|
|
2203
|
+
console.log("\n" + chalk3.yellow("!") + " Cleaning up...");
|
|
2204
|
+
rmSync(projectDir, { recursive: true, force: true });
|
|
2205
|
+
}
|
|
2206
|
+
async function withInterruptCleanup(cleanup, fn) {
|
|
2207
|
+
if (!cleanup) return fn();
|
|
2208
|
+
const handler = () => {
|
|
2209
|
+
cleanup();
|
|
2210
|
+
process.removeListener("SIGINT", handler);
|
|
2211
|
+
process.kill(process.pid, "SIGINT");
|
|
2212
|
+
};
|
|
2213
|
+
process.on("SIGINT", handler);
|
|
2214
|
+
try {
|
|
2215
|
+
return await fn();
|
|
2216
|
+
} finally {
|
|
2217
|
+
process.removeListener("SIGINT", handler);
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
function createProjectDir({
|
|
2221
|
+
projectDir,
|
|
2222
|
+
projectName
|
|
2223
|
+
}) {
|
|
2224
|
+
try {
|
|
2225
|
+
mkdirSync(projectDir, { recursive: true });
|
|
2226
|
+
} catch (err) {
|
|
2227
|
+
if (err instanceof Error) {
|
|
2228
|
+
const code = err.code;
|
|
2229
|
+
if (code === "EACCES") {
|
|
2230
|
+
throw new Error(
|
|
2231
|
+
`Permission denied creating "${projectName}". Check directory permissions.`
|
|
2232
|
+
);
|
|
2233
|
+
}
|
|
2234
|
+
if (code === "ENOSPC") {
|
|
2235
|
+
throw new Error("No space left on device.");
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
throw err;
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
var TEMPLATES_DIR = fileURLToPath(
|
|
2242
|
+
new URL("../templates", import.meta.url)
|
|
2243
|
+
);
|
|
2244
|
+
|
|
2245
|
+
// src/plugins/init/steps.ts
|
|
2246
|
+
var DEFAULT_TEMPLATE = "basic";
|
|
2247
|
+
function getTemplateDir({
|
|
2248
|
+
template = DEFAULT_TEMPLATE
|
|
2249
|
+
} = {}) {
|
|
2250
|
+
const dirPath = join(TEMPLATES_DIR, template);
|
|
2251
|
+
if (!existsSync(dirPath)) {
|
|
2252
|
+
throw new Error(
|
|
2253
|
+
`Template "${template}" not found at ${dirPath}. Available templates: ${TEMPLATES.join(", ")}`
|
|
2254
|
+
);
|
|
2255
|
+
}
|
|
2256
|
+
return dirPath;
|
|
2257
|
+
}
|
|
2258
|
+
function scaffoldFiles({
|
|
2259
|
+
projectDir,
|
|
2260
|
+
templatesDir,
|
|
2261
|
+
variables = {},
|
|
2262
|
+
displayHooks
|
|
2263
|
+
}) {
|
|
2264
|
+
const entries = readdirSync(templatesDir, {
|
|
2265
|
+
withFileTypes: true,
|
|
2266
|
+
recursive: true
|
|
2267
|
+
});
|
|
2268
|
+
const files = entries.filter((e) => e.isFile());
|
|
2269
|
+
if (files.length === 0) {
|
|
2270
|
+
throw new Error(`Template directory "${templatesDir}" contains no files.`);
|
|
2271
|
+
}
|
|
2272
|
+
for (const entry of files) {
|
|
2273
|
+
const srcPath = join(getDirentParentPath(entry), entry.name);
|
|
2274
|
+
const relPath = relative(templatesDir, srcPath);
|
|
2275
|
+
const isTemplate = isTemplateFile(entry.name);
|
|
2276
|
+
const destRelPath = getDestRelPath(relPath, isTemplate);
|
|
2277
|
+
const destPath = join(projectDir, destRelPath);
|
|
2278
|
+
mkdirSync(dirname(destPath), { recursive: true });
|
|
2279
|
+
if (isTemplate) {
|
|
2280
|
+
writeFileSync(destPath, renderTemplate(srcPath, variables));
|
|
2281
|
+
} else {
|
|
2282
|
+
copyFileSync(srcPath, destPath);
|
|
2283
|
+
}
|
|
2284
|
+
displayHooks?.onItemComplete?.(destRelPath);
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
function scaffoldProject({
|
|
2288
|
+
projectDir,
|
|
2289
|
+
projectName,
|
|
2290
|
+
packageManager,
|
|
2291
|
+
template,
|
|
2292
|
+
displayHooks
|
|
2293
|
+
}) {
|
|
2294
|
+
const variables = buildTemplateVariables({ projectName, packageManager });
|
|
2295
|
+
const templatesDir = getTemplateDir({ template });
|
|
2296
|
+
createProjectDir({ projectDir, projectName });
|
|
2297
|
+
scaffoldFiles({ projectDir, templatesDir, variables, displayHooks });
|
|
2298
|
+
}
|
|
2299
|
+
async function runStep({
|
|
2300
|
+
step,
|
|
2301
|
+
stepNumber,
|
|
2302
|
+
totalSteps,
|
|
2303
|
+
skipPrompts,
|
|
2304
|
+
displayHooks
|
|
2305
|
+
}) {
|
|
2306
|
+
if (step.askConfirmation) {
|
|
2307
|
+
const should = await promptYesNo({
|
|
2308
|
+
message: step.description,
|
|
2309
|
+
defaultValue: true,
|
|
2310
|
+
skipPrompts
|
|
2311
|
+
});
|
|
2312
|
+
if (!should) return false;
|
|
2313
|
+
}
|
|
2314
|
+
displayHooks?.onStepStart({
|
|
2315
|
+
description: step.description,
|
|
2316
|
+
stepNumber,
|
|
2317
|
+
totalSteps,
|
|
2318
|
+
command: step.command,
|
|
2319
|
+
skipPrompts
|
|
2320
|
+
});
|
|
2321
|
+
try {
|
|
2322
|
+
await step.run();
|
|
2323
|
+
displayHooks?.onStepSuccess({ stepNumber, totalSteps });
|
|
2324
|
+
return true;
|
|
2325
|
+
} catch (err) {
|
|
2326
|
+
step.cleanup?.();
|
|
2327
|
+
displayHooks?.onStepError({
|
|
2328
|
+
description: step.description,
|
|
2329
|
+
command: step.command,
|
|
2330
|
+
err
|
|
2331
|
+
});
|
|
2332
|
+
return false;
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
function getInitSteps({
|
|
2336
|
+
projectDir,
|
|
2337
|
+
projectName,
|
|
2338
|
+
packageManager,
|
|
2339
|
+
template,
|
|
2340
|
+
displayHooks
|
|
2341
|
+
}) {
|
|
2342
|
+
if (template !== void 0 && !TEMPLATES.includes(template)) {
|
|
2343
|
+
throw new Error(
|
|
2344
|
+
`Unknown template "${template}". Available templates: ${TEMPLATES.join(", ")}`
|
|
2345
|
+
);
|
|
2346
|
+
}
|
|
2347
|
+
const { installCmd, execCmd, devCmd } = getPackageManagerCommands({
|
|
2348
|
+
packageManager
|
|
2349
|
+
});
|
|
2350
|
+
const exec = createExec({ cwd: projectDir });
|
|
2351
|
+
return [
|
|
2352
|
+
{
|
|
2353
|
+
id: "scaffold",
|
|
2354
|
+
description: "Scaffold project files",
|
|
2355
|
+
cleanup: () => cleanupProject({ projectDir }),
|
|
2356
|
+
run: () => scaffoldProject({
|
|
2357
|
+
projectDir,
|
|
2358
|
+
projectName,
|
|
2359
|
+
packageManager,
|
|
2360
|
+
template,
|
|
2361
|
+
displayHooks
|
|
2362
|
+
})
|
|
2363
|
+
},
|
|
2364
|
+
{
|
|
2365
|
+
id: "install-deps",
|
|
2366
|
+
description: "Install dependencies",
|
|
2367
|
+
askConfirmation: true,
|
|
2368
|
+
command: installCmd,
|
|
2369
|
+
run: () => exec(installCmd)
|
|
2370
|
+
},
|
|
2371
|
+
{
|
|
2372
|
+
id: "login",
|
|
2373
|
+
description: "Log in to Zapier",
|
|
2374
|
+
askConfirmation: true,
|
|
2375
|
+
command: `${execCmd} zapier-sdk login`,
|
|
2376
|
+
run: () => exec(`${execCmd} zapier-sdk login`)
|
|
2377
|
+
},
|
|
2378
|
+
{
|
|
2379
|
+
id: "run",
|
|
2380
|
+
description: "Run your app",
|
|
2381
|
+
askConfirmation: true,
|
|
2382
|
+
command: devCmd,
|
|
2383
|
+
run: () => exec(devCmd)
|
|
2384
|
+
}
|
|
2385
|
+
];
|
|
2386
|
+
}
|
|
2387
|
+
function buildNextSteps({
|
|
2388
|
+
projectName,
|
|
2389
|
+
leftoverSteps,
|
|
2390
|
+
execCmd
|
|
2391
|
+
}) {
|
|
2392
|
+
return [
|
|
2393
|
+
{
|
|
2394
|
+
description: "Change into your project directory",
|
|
2395
|
+
command: `cd ${projectName}`
|
|
2396
|
+
},
|
|
2397
|
+
...leftoverSteps.map(({ description, command }) => ({
|
|
2398
|
+
description,
|
|
2399
|
+
command
|
|
2400
|
+
})),
|
|
2401
|
+
{
|
|
2402
|
+
description: "Search for an app to integrate",
|
|
2403
|
+
command: `${execCmd} zapier-sdk list-apps --search "<app name>"`
|
|
2404
|
+
},
|
|
2405
|
+
{
|
|
2406
|
+
description: "Add an app and generate TypeScript types",
|
|
2407
|
+
command: `${execCmd} zapier-sdk add <app-key>`
|
|
2408
|
+
}
|
|
2409
|
+
];
|
|
2410
|
+
}
|
|
2411
|
+
function createConsoleDisplayHooks() {
|
|
2412
|
+
return {
|
|
2413
|
+
onItemComplete: (message) => console.log(" " + chalk3.green("\u2713") + " " + chalk3.dim(message)),
|
|
2414
|
+
onWarn: (message) => console.warn(chalk3.yellow("!") + " " + message),
|
|
2415
|
+
onStepStart: ({
|
|
2416
|
+
description,
|
|
2417
|
+
stepNumber,
|
|
2418
|
+
totalSteps,
|
|
2419
|
+
command,
|
|
2420
|
+
skipPrompts
|
|
2421
|
+
}) => {
|
|
2422
|
+
const progressMessage = `${description}...`;
|
|
2423
|
+
const stepCounter = chalk3.dim(`${stepNumber}/${totalSteps}`);
|
|
2424
|
+
if (skipPrompts) {
|
|
2425
|
+
console.log(
|
|
2426
|
+
"\n" + chalk3.bold(`\u276F ${progressMessage}`) + " " + stepCounter + "\n"
|
|
2427
|
+
);
|
|
2428
|
+
} else {
|
|
2429
|
+
console.log(
|
|
2430
|
+
chalk3.dim("\u2192") + " " + progressMessage + " " + stepCounter
|
|
2431
|
+
);
|
|
2432
|
+
}
|
|
2433
|
+
if (command) {
|
|
2434
|
+
console.log(" " + chalk3.cyan(`$ ${command}`));
|
|
2435
|
+
}
|
|
2436
|
+
},
|
|
2437
|
+
onStepSuccess: ({ stepNumber, totalSteps }) => console.log(
|
|
2438
|
+
"\n" + chalk3.green("\u2713") + " " + chalk3.dim(`Step ${stepNumber}/${totalSteps} complete`) + "\n"
|
|
2439
|
+
),
|
|
2440
|
+
onStepError: ({ description, command, err }) => {
|
|
2441
|
+
const detail = err instanceof Error && err.message ? `
|
|
2442
|
+
${chalk3.dim(err.message)}` : "";
|
|
2443
|
+
const hint = command ? `
|
|
2444
|
+
${chalk3.dim("run manually:")} ${chalk3.cyan(`$ ${command}`)}` : "";
|
|
2445
|
+
console.error(
|
|
2446
|
+
`
|
|
2447
|
+
${chalk3.red("\u2716")} ${chalk3.bold(description)}${chalk3.dim(" failed")}${detail}${hint}`
|
|
2448
|
+
);
|
|
2449
|
+
}
|
|
2450
|
+
};
|
|
2451
|
+
}
|
|
2452
|
+
function displaySummaryAndNextSteps({
|
|
2453
|
+
projectName,
|
|
2454
|
+
steps,
|
|
2455
|
+
completedSetupStepIds,
|
|
2456
|
+
packageManager
|
|
2457
|
+
}) {
|
|
2458
|
+
const formatStatus = (complete) => ({
|
|
2459
|
+
icon: complete ? chalk3.green("\u2713") : chalk3.yellow("!"),
|
|
2460
|
+
text: complete ? chalk3.green("Setup complete") : chalk3.yellow("Setup interrupted")
|
|
2461
|
+
});
|
|
2462
|
+
const formatNextStep = (step, i) => " " + chalk3.dim(`${i + 1}.`) + " " + chalk3.bold(step.description);
|
|
2463
|
+
const formatCommand = (cmd) => " " + chalk3.cyan(`$ ${cmd}`);
|
|
2464
|
+
const formatCompletedStep = (step) => " " + chalk3.green("\u2713") + " " + step.description;
|
|
2465
|
+
const { execCmd } = getPackageManagerCommands({ packageManager });
|
|
2466
|
+
const leftoverSteps = steps.filter(
|
|
2467
|
+
(s) => !completedSetupStepIds.includes(s.id)
|
|
2468
|
+
);
|
|
2469
|
+
const isComplete = leftoverSteps.length === 0;
|
|
2470
|
+
const status = formatStatus(isComplete);
|
|
2471
|
+
console.log("\n" + chalk3.bold("\u276F Summary") + "\n");
|
|
2472
|
+
console.log(" " + chalk3.dim("Project") + " " + chalk3.bold(projectName));
|
|
2473
|
+
console.log(
|
|
2474
|
+
" " + chalk3.dim("Status") + " " + status.icon + " " + status.text
|
|
2475
|
+
);
|
|
2476
|
+
const completedSteps = steps.filter(
|
|
2477
|
+
(s) => completedSetupStepIds.includes(s.id)
|
|
2478
|
+
);
|
|
2479
|
+
if (completedSteps.length > 0) {
|
|
2480
|
+
console.log();
|
|
2481
|
+
for (const step of completedSteps) console.log(formatCompletedStep(step));
|
|
2482
|
+
}
|
|
2483
|
+
const nextSteps = buildNextSteps({ projectName, leftoverSteps, execCmd });
|
|
2484
|
+
console.log("\n" + chalk3.bold("\u276F Next Steps") + "\n");
|
|
2485
|
+
nextSteps.forEach((step, i) => {
|
|
2486
|
+
console.log(formatNextStep(step, i));
|
|
2487
|
+
if (step.command) console.log(formatCommand(step.command));
|
|
2488
|
+
console.log();
|
|
2489
|
+
});
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2492
|
+
// src/plugins/init/index.ts
|
|
2493
|
+
var initPlugin = () => {
|
|
2494
|
+
const init = createFunction(async function init2(options) {
|
|
2495
|
+
const { projectName: rawName, skipPrompts = false } = options;
|
|
2496
|
+
const cwd = process.cwd();
|
|
2497
|
+
const { projectName, projectDir } = validateInitOptions({ rawName, cwd });
|
|
2498
|
+
const displayHooks = createConsoleDisplayHooks();
|
|
2499
|
+
const packageManagerInfo = detectPackageManager(cwd);
|
|
2500
|
+
if (packageManagerInfo.name === "unknown") {
|
|
2501
|
+
displayHooks.onWarn(
|
|
2502
|
+
"Could not detect package manager, defaulting to npm."
|
|
2503
|
+
);
|
|
2504
|
+
}
|
|
2505
|
+
const packageManager = packageManagerInfo.name === "unknown" ? "npm" : packageManagerInfo.name;
|
|
2506
|
+
const steps = getInitSteps({
|
|
2507
|
+
projectDir,
|
|
2508
|
+
projectName,
|
|
2509
|
+
packageManager,
|
|
2510
|
+
displayHooks
|
|
2511
|
+
});
|
|
2512
|
+
const completedSetupStepIds = [];
|
|
2513
|
+
for (let i = 0; i < steps.length; i++) {
|
|
2514
|
+
const step = steps[i];
|
|
2515
|
+
const succeeded = await withInterruptCleanup(
|
|
2516
|
+
step.cleanup,
|
|
2517
|
+
() => runStep({
|
|
2518
|
+
step,
|
|
2519
|
+
stepNumber: i + 1,
|
|
2520
|
+
totalSteps: steps.length,
|
|
2521
|
+
skipPrompts,
|
|
2522
|
+
displayHooks
|
|
2523
|
+
})
|
|
2524
|
+
);
|
|
2525
|
+
if (!succeeded) break;
|
|
2526
|
+
completedSetupStepIds.push(step.id);
|
|
2527
|
+
}
|
|
2528
|
+
if (completedSetupStepIds.length === 0) {
|
|
2529
|
+
throw new ZapierCliExitError(
|
|
2530
|
+
"Project setup failed \u2014 no steps completed."
|
|
2531
|
+
);
|
|
2532
|
+
}
|
|
2533
|
+
displaySummaryAndNextSteps({
|
|
2534
|
+
projectName,
|
|
2535
|
+
steps,
|
|
2536
|
+
completedSetupStepIds,
|
|
2537
|
+
packageManager
|
|
2538
|
+
});
|
|
2539
|
+
}, InitSchema);
|
|
2540
|
+
return {
|
|
2541
|
+
init,
|
|
2542
|
+
context: {
|
|
2543
|
+
meta: {
|
|
2544
|
+
init: {
|
|
2545
|
+
categories: ["utility"],
|
|
2546
|
+
inputSchema: InitSchema
|
|
2547
|
+
}
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
};
|
|
2551
|
+
};
|
|
2043
2552
|
|
|
2044
2553
|
// src/sdk.ts
|
|
2554
|
+
injectCliLogin(cliLogin);
|
|
2045
2555
|
function createZapierCliSdk(options = {}) {
|
|
2046
2556
|
return createZapierSdkWithoutRegistry({
|
|
2047
2557
|
...options,
|
|
2048
2558
|
eventEmission: { ...options.eventEmission, callContext: "cli" }
|
|
2049
|
-
}).addPlugin(generateAppTypesPlugin).addPlugin(buildManifestPlugin).addPlugin(bundleCodePlugin).addPlugin(getLoginConfigPathPlugin).addPlugin(addPlugin).addPlugin(feedbackPlugin).addPlugin(curlPlugin).addPlugin(mcpPlugin).addPlugin(loginPlugin).addPlugin(logoutPlugin).addPlugin(cliOverridesPlugin).addPlugin(registryPlugin);
|
|
2559
|
+
}).addPlugin(generateAppTypesPlugin).addPlugin(buildManifestPlugin).addPlugin(bundleCodePlugin).addPlugin(getLoginConfigPathPlugin).addPlugin(addPlugin).addPlugin(feedbackPlugin).addPlugin(curlPlugin).addPlugin(initPlugin).addPlugin(mcpPlugin).addPlugin(loginPlugin).addPlugin(logoutPlugin).addPlugin(cliOverridesPlugin).addPlugin(registryPlugin);
|
|
2050
2560
|
}
|
|
2051
2561
|
|
|
2052
2562
|
// src/utils/cli-options.ts
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zapier/zapier-sdk-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.34.1",
|
|
4
4
|
"description": "Command line interface for Zapier SDK",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"files": [
|
|
50
50
|
"dist",
|
|
51
51
|
"bin",
|
|
52
|
+
"templates",
|
|
52
53
|
"README.md",
|
|
53
54
|
"CHANGELOG.md",
|
|
54
55
|
"CLAUDE.md"
|
|
@@ -63,9 +64,9 @@
|
|
|
63
64
|
"chalk": "^5.3.0",
|
|
64
65
|
"cli-table3": "^0.6.5",
|
|
65
66
|
"commander": "^12.0.0",
|
|
66
|
-
"conf": "^14.0.0",
|
|
67
67
|
"esbuild": "^0.25.5",
|
|
68
68
|
"express": "^5.1.0",
|
|
69
|
+
"handlebars": "^4.7.8",
|
|
69
70
|
"inquirer": "^12.6.3",
|
|
70
71
|
"is-installed-globally": "^1.0.0",
|
|
71
72
|
"jsonwebtoken": "^9.0.2",
|
package/dist/src/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import packageJson from "../package.json" with { type: "json" };
|
|
|
6
6
|
import { ZapierCliError } from "./utils/errors";
|
|
7
7
|
import { checkAndNotifyUpdates } from "./utils/version-checker";
|
|
8
8
|
import { ReservedCliParameter, getReservedCliOption, } from "./utils/cli-options";
|
|
9
|
+
const EXIT_GRACE_PERIOD_MS = 500;
|
|
9
10
|
const program = new Command();
|
|
10
11
|
const versionOption = getReservedCliOption(ReservedCliParameter.Version);
|
|
11
12
|
const helpOption = getReservedCliOption(ReservedCliParameter.Help);
|
|
@@ -116,6 +117,15 @@ program.exitOverride();
|
|
|
116
117
|
}
|
|
117
118
|
// Wait for version checking to complete
|
|
118
119
|
await versionCheckPromise;
|
|
119
|
-
//
|
|
120
|
+
// Flush the exit telemetry event before we force-terminate. The async
|
|
121
|
+
// transport needs an explicit await because process.on("exit") only
|
|
122
|
+
// allows synchronous work.
|
|
123
|
+
await sdk.getContext().eventEmission.close(exitCode);
|
|
124
|
+
// Force exit after a short grace period. We can't rely on process.exitCode
|
|
125
|
+
// alone because background handles (stdin, pending file closes) keep the
|
|
126
|
+
// event loop alive indefinitely. The unref'd timer won't prevent natural
|
|
127
|
+
// exit, but guarantees the process terminates if the loop doesn't drain.
|
|
128
|
+
const exitTimeout = setTimeout(() => process.exit(exitCode), EXIT_GRACE_PERIOD_MS);
|
|
129
|
+
exitTimeout.unref();
|
|
120
130
|
process.exitCode = exitCode;
|
|
121
131
|
})();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const TEMPLATES_DIR: string;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { fileURLToPath } from "url";
|
|
2
|
+
// src/ and dist/ are both one level below the package root, so "../templates"
|
|
3
|
+
// resolves correctly in both the unbundled source context and the bundled
|
|
4
|
+
// dist/index.mjs runtime. Moving this expression into a deeper file would
|
|
5
|
+
// break one of the two contexts.
|
|
6
|
+
export const TEMPLATES_DIR = fileURLToPath(new URL("../templates", import.meta.url));
|