@zapier/zapier-sdk-cli 0.13.15 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/cli.cjs +296 -20
- package/dist/cli.mjs +296 -22
- package/dist/index.cjs +29 -5
- package/dist/index.mjs +30 -6
- package/dist/package.json +4 -1
- package/dist/src/cli.js +32 -2
- package/dist/src/plugins/login/index.js +0 -2
- package/dist/src/utils/auth/login.js +3 -2
- package/dist/src/utils/cli-generator.js +10 -2
- package/dist/src/utils/errors.d.ts +16 -0
- package/dist/src/utils/errors.js +19 -0
- package/dist/src/utils/log.d.ts +1 -0
- package/dist/src/utils/log.js +5 -0
- package/dist/src/utils/package-manager-detector.d.ts +16 -0
- package/dist/src/utils/package-manager-detector.js +77 -0
- package/dist/src/utils/parameter-resolver.js +6 -5
- package/dist/src/utils/spinner.js +9 -1
- package/dist/src/utils/version-checker.d.ts +17 -0
- package/dist/src/utils/version-checker.js +154 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -3
- package/src/cli.ts +34 -2
- package/src/plugins/login/index.ts +0 -3
- package/src/utils/auth/login.ts +7 -3
- package/src/utils/cli-generator.ts +15 -2
- package/src/utils/errors.ts +26 -0
- package/src/utils/log.ts +5 -0
- package/src/utils/package-manager-detector.ts +83 -0
- package/src/utils/parameter-resolver.ts +6 -5
- package/src/utils/spinner.ts +8 -1
- package/src/utils/version-checker.test.ts +199 -0
- package/src/utils/version-checker.ts +236 -0
|
@@ -20,8 +20,6 @@ const loginWithSdk = createFunction(async (options) => {
|
|
|
20
20
|
});
|
|
21
21
|
const user = await getLoggedInUser();
|
|
22
22
|
console.log(`✅ Successfully logged in as ${user.email}`);
|
|
23
|
-
// Force immediate exit to prevent hanging (especially in development with tsx)
|
|
24
|
-
setTimeout(() => process.exit(0), 100);
|
|
25
23
|
});
|
|
26
24
|
export const loginPlugin = ({ context }) => {
|
|
27
25
|
// Wrap the login function to emit telemetry events
|
|
@@ -8,6 +8,7 @@ import log from "../log";
|
|
|
8
8
|
import api from "../api/client";
|
|
9
9
|
import getCallablePromise from "../getCallablePromise";
|
|
10
10
|
import { updateLogin, logout, getAuthTokenUrl, getAuthAuthorizeUrl, } from "@zapier/zapier-sdk-cli-login";
|
|
11
|
+
import { ZapierCliUserCancellationError } from "../errors";
|
|
11
12
|
const findAvailablePort = () => {
|
|
12
13
|
return new Promise((resolve, reject) => {
|
|
13
14
|
let portIndex = 0;
|
|
@@ -55,7 +56,7 @@ const login = async ({ timeoutMs = LOGIN_TIMEOUT_MS, baseUrl, authBaseUrl, authC
|
|
|
55
56
|
const availablePort = await findAvailablePort();
|
|
56
57
|
const redirectUri = `http://localhost:${availablePort}/oauth`;
|
|
57
58
|
log.info(`Using port ${availablePort} for OAuth callback`);
|
|
58
|
-
const { promise: promisedCode, resolve: setCode } = getCallablePromise();
|
|
59
|
+
const { promise: promisedCode, resolve: setCode, reject: rejectCode, } = getCallablePromise();
|
|
59
60
|
const app = express();
|
|
60
61
|
app.get("/oauth", (req, res) => {
|
|
61
62
|
setCode(String(req.query.code));
|
|
@@ -74,7 +75,7 @@ const login = async ({ timeoutMs = LOGIN_TIMEOUT_MS, baseUrl, authBaseUrl, authC
|
|
|
74
75
|
const cleanup = () => {
|
|
75
76
|
server.close();
|
|
76
77
|
log.info("\n❌ Login cancelled by user");
|
|
77
|
-
|
|
78
|
+
rejectCode(new ZapierCliUserCancellationError());
|
|
78
79
|
};
|
|
79
80
|
process.on("SIGINT", cleanup);
|
|
80
81
|
process.on("SIGTERM", cleanup);
|
|
@@ -4,6 +4,7 @@ import { SchemaParameterResolver } from "./parameter-resolver";
|
|
|
4
4
|
import { formatItemsFromSchema, formatJsonOutput } from "./schema-formatter";
|
|
5
5
|
import chalk from "chalk";
|
|
6
6
|
import inquirer from "inquirer";
|
|
7
|
+
import { ZapierCliError, ZapierCliExitError } from "./errors";
|
|
7
8
|
// ============================================================================
|
|
8
9
|
// Schema Analysis
|
|
9
10
|
// ============================================================================
|
|
@@ -254,22 +255,29 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
|
|
|
254
255
|
console.error(chalk.yellow(` • ${field}: ${errorObj?.message || "Unknown error"}`));
|
|
255
256
|
});
|
|
256
257
|
console.error("\n" + chalk.dim(`Use --help to see available options`));
|
|
258
|
+
throw new ZapierCliExitError("Validation failed", 1);
|
|
257
259
|
}
|
|
258
260
|
catch {
|
|
259
|
-
console.error(chalk.red("Error:"), error.message);
|
|
261
|
+
console.error(chalk.red("Error:"), error instanceof Error ? error.message : String(error));
|
|
262
|
+
throw new ZapierCliExitError(error instanceof Error ? error.message : String(error), 1);
|
|
260
263
|
}
|
|
261
264
|
}
|
|
265
|
+
else if (error instanceof ZapierCliError) {
|
|
266
|
+
// Re-throw all CLI errors as-is
|
|
267
|
+
throw error;
|
|
268
|
+
}
|
|
262
269
|
else if (error instanceof ZapierError) {
|
|
263
270
|
// Handle SDK errors with clean, user-friendly messages using our formatter
|
|
264
271
|
const formattedMessage = formatErrorMessage(error);
|
|
265
272
|
console.error(chalk.red("❌ Error:"), formattedMessage);
|
|
273
|
+
throw new ZapierCliExitError(formattedMessage, 1);
|
|
266
274
|
}
|
|
267
275
|
else {
|
|
268
276
|
// Handle other errors
|
|
269
277
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
270
278
|
console.error(chalk.red("❌ Error:"), errorMessage);
|
|
279
|
+
throw new ZapierCliExitError(errorMessage, 1);
|
|
271
280
|
}
|
|
272
|
-
process.exit(1);
|
|
273
281
|
}
|
|
274
282
|
};
|
|
275
283
|
return {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ZapierError } from "@zapier/zapier-sdk";
|
|
2
|
+
export declare abstract class ZapierCliError extends ZapierError {
|
|
3
|
+
abstract readonly exitCode: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class ZapierCliUserCancellationError extends ZapierCliError {
|
|
6
|
+
readonly name = "ZapierCliUserCancellationError";
|
|
7
|
+
readonly code = "ZAPIER_CLI_USER_CANCELLATION";
|
|
8
|
+
readonly exitCode = 0;
|
|
9
|
+
constructor(message?: string);
|
|
10
|
+
}
|
|
11
|
+
export declare class ZapierCliExitError extends ZapierCliError {
|
|
12
|
+
readonly name = "ZapierCliExitError";
|
|
13
|
+
readonly code = "ZAPIER_CLI_EXIT";
|
|
14
|
+
readonly exitCode: number;
|
|
15
|
+
constructor(message: string, exitCode?: number);
|
|
16
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ZapierError } from "@zapier/zapier-sdk";
|
|
2
|
+
export class ZapierCliError extends ZapierError {
|
|
3
|
+
}
|
|
4
|
+
export class ZapierCliUserCancellationError extends ZapierCliError {
|
|
5
|
+
constructor(message = "Operation cancelled by user") {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "ZapierCliUserCancellationError";
|
|
8
|
+
this.code = "ZAPIER_CLI_USER_CANCELLATION";
|
|
9
|
+
this.exitCode = 0;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export class ZapierCliExitError extends ZapierCliError {
|
|
13
|
+
constructor(message, exitCode = 1) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = "ZapierCliExitError";
|
|
16
|
+
this.code = "ZAPIER_CLI_EXIT";
|
|
17
|
+
this.exitCode = exitCode;
|
|
18
|
+
}
|
|
19
|
+
}
|
package/dist/src/utils/log.d.ts
CHANGED
|
@@ -3,5 +3,6 @@ declare const log: {
|
|
|
3
3
|
error: (message: string, ...args: unknown[]) => void;
|
|
4
4
|
success: (message: string, ...args: unknown[]) => void;
|
|
5
5
|
warn: (message: string, ...args: unknown[]) => void;
|
|
6
|
+
debug: (message: string, ...args: unknown[]) => void;
|
|
6
7
|
};
|
|
7
8
|
export default log;
|
package/dist/src/utils/log.js
CHANGED
|
@@ -12,5 +12,10 @@ const log = {
|
|
|
12
12
|
warn: (message, ...args) => {
|
|
13
13
|
console.log(chalk.yellow("⚠"), message, ...args);
|
|
14
14
|
},
|
|
15
|
+
debug: (message, ...args) => {
|
|
16
|
+
if (process.env.DEBUG === "true" || process.argv.includes("--debug")) {
|
|
17
|
+
console.log(chalk.gray("🐛"), message, ...args);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
15
20
|
};
|
|
16
21
|
export default log;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface PackageManagerInfo {
|
|
2
|
+
name: "npm" | "yarn" | "pnpm" | "bun" | "unknown";
|
|
3
|
+
source: "runtime" | "lockfile" | "fallback";
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Detect which package manager is being used or configured for this project.
|
|
7
|
+
*
|
|
8
|
+
* Returns an object like:
|
|
9
|
+
* { name: 'npm' | 'yarn' | 'pnpm' | 'bun' | 'unknown', source: 'runtime' | 'lockfile' | 'fallback' }
|
|
10
|
+
*/
|
|
11
|
+
export declare function detectPackageManager(cwd?: string): PackageManagerInfo;
|
|
12
|
+
/**
|
|
13
|
+
* Get the appropriate update command for the detected package manager.
|
|
14
|
+
* Returns global update commands if globally installed, local commands if locally installed.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getUpdateCommand(packageName: string): string;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import isInstalledGlobally from "is-installed-globally";
|
|
4
|
+
/**
|
|
5
|
+
* Detect which package manager is being used or configured for this project.
|
|
6
|
+
*
|
|
7
|
+
* Returns an object like:
|
|
8
|
+
* { name: 'npm' | 'yarn' | 'pnpm' | 'bun' | 'unknown', source: 'runtime' | 'lockfile' | 'fallback' }
|
|
9
|
+
*/
|
|
10
|
+
export function detectPackageManager(cwd = process.cwd()) {
|
|
11
|
+
// --- 1. Runtime detection (based on env)
|
|
12
|
+
const ua = process.env.npm_config_user_agent;
|
|
13
|
+
if (ua) {
|
|
14
|
+
if (ua.includes("yarn"))
|
|
15
|
+
return { name: "yarn", source: "runtime" };
|
|
16
|
+
if (ua.includes("pnpm"))
|
|
17
|
+
return { name: "pnpm", source: "runtime" };
|
|
18
|
+
if (ua.includes("bun"))
|
|
19
|
+
return { name: "bun", source: "runtime" };
|
|
20
|
+
if (ua.includes("npm"))
|
|
21
|
+
return { name: "npm", source: "runtime" };
|
|
22
|
+
}
|
|
23
|
+
// --- 2. Lockfile detection (based on files in cwd)
|
|
24
|
+
const files = [
|
|
25
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
26
|
+
["yarn.lock", "yarn"],
|
|
27
|
+
["bun.lockb", "bun"],
|
|
28
|
+
["package-lock.json", "npm"],
|
|
29
|
+
];
|
|
30
|
+
for (const [file, name] of files) {
|
|
31
|
+
if (existsSync(join(cwd, file))) {
|
|
32
|
+
return { name, source: "lockfile" };
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// --- 3. Fallback
|
|
36
|
+
return { name: "unknown", source: "fallback" };
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get the appropriate update command for the detected package manager.
|
|
40
|
+
* Returns global update commands if globally installed, local commands if locally installed.
|
|
41
|
+
*/
|
|
42
|
+
export function getUpdateCommand(packageName) {
|
|
43
|
+
const pm = detectPackageManager();
|
|
44
|
+
const isGlobal = isInstalledGlobally;
|
|
45
|
+
if (isGlobal) {
|
|
46
|
+
// Global update commands
|
|
47
|
+
switch (pm.name) {
|
|
48
|
+
case "yarn":
|
|
49
|
+
return `yarn global upgrade ${packageName}`;
|
|
50
|
+
case "pnpm":
|
|
51
|
+
return `pnpm update -g ${packageName}`;
|
|
52
|
+
case "bun":
|
|
53
|
+
return `bun update -g ${packageName}`;
|
|
54
|
+
case "npm":
|
|
55
|
+
return `npm update -g ${packageName}`;
|
|
56
|
+
case "unknown":
|
|
57
|
+
// Default to npm since it's most widely supported
|
|
58
|
+
return `npm update -g ${packageName}`;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// Local update commands
|
|
63
|
+
switch (pm.name) {
|
|
64
|
+
case "yarn":
|
|
65
|
+
return `yarn upgrade ${packageName}`;
|
|
66
|
+
case "pnpm":
|
|
67
|
+
return `pnpm update ${packageName}`;
|
|
68
|
+
case "bun":
|
|
69
|
+
return `bun update ${packageName}`;
|
|
70
|
+
case "npm":
|
|
71
|
+
return `npm update ${packageName}`;
|
|
72
|
+
case "unknown":
|
|
73
|
+
// Default to npm since it's most widely supported
|
|
74
|
+
return `npm update ${packageName}`;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import inquirer from "inquirer";
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
+
import { ZapierCliUserCancellationError } from "./errors";
|
|
4
5
|
// ============================================================================
|
|
5
6
|
// Local Resolution Helper Functions
|
|
6
7
|
// ============================================================================
|
|
@@ -137,7 +138,7 @@ export class SchemaParameterResolver {
|
|
|
137
138
|
catch (error) {
|
|
138
139
|
if (this.isUserCancellation(error)) {
|
|
139
140
|
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
140
|
-
|
|
141
|
+
throw new ZapierCliUserCancellationError();
|
|
141
142
|
}
|
|
142
143
|
throw error;
|
|
143
144
|
}
|
|
@@ -164,7 +165,7 @@ export class SchemaParameterResolver {
|
|
|
164
165
|
catch (error) {
|
|
165
166
|
if (this.isUserCancellation(error)) {
|
|
166
167
|
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
167
|
-
|
|
168
|
+
throw new ZapierCliUserCancellationError();
|
|
168
169
|
}
|
|
169
170
|
throw error;
|
|
170
171
|
}
|
|
@@ -198,7 +199,7 @@ export class SchemaParameterResolver {
|
|
|
198
199
|
catch (error) {
|
|
199
200
|
if (this.isUserCancellation(error)) {
|
|
200
201
|
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
201
|
-
|
|
202
|
+
throw new ZapierCliUserCancellationError();
|
|
202
203
|
}
|
|
203
204
|
throw error;
|
|
204
205
|
}
|
|
@@ -431,7 +432,7 @@ export class SchemaParameterResolver {
|
|
|
431
432
|
catch (error) {
|
|
432
433
|
if (this.isUserCancellation(error)) {
|
|
433
434
|
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
434
|
-
|
|
435
|
+
throw new ZapierCliUserCancellationError();
|
|
435
436
|
}
|
|
436
437
|
throw error;
|
|
437
438
|
}
|
|
@@ -492,7 +493,7 @@ export class SchemaParameterResolver {
|
|
|
492
493
|
catch (error) {
|
|
493
494
|
if (this.isUserCancellation(error)) {
|
|
494
495
|
console.log(chalk.yellow("\n\nOperation cancelled by user"));
|
|
495
|
-
|
|
496
|
+
throw new ZapierCliUserCancellationError();
|
|
496
497
|
}
|
|
497
498
|
throw error;
|
|
498
499
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import ora from "ora";
|
|
2
|
+
import { ZapierCliUserCancellationError } from "./errors";
|
|
2
3
|
export const spinPromise = async (promise, text) => {
|
|
3
4
|
const spinner = ora(text).start();
|
|
4
5
|
try {
|
|
@@ -7,7 +8,14 @@ export const spinPromise = async (promise, text) => {
|
|
|
7
8
|
return result;
|
|
8
9
|
}
|
|
9
10
|
catch (error) {
|
|
10
|
-
|
|
11
|
+
if (error instanceof ZapierCliUserCancellationError) {
|
|
12
|
+
// For user cancellation, just stop the spinner without showing failure
|
|
13
|
+
spinner.stop();
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
// For actual errors, show failure
|
|
17
|
+
spinner.fail();
|
|
18
|
+
}
|
|
11
19
|
throw error;
|
|
12
20
|
}
|
|
13
21
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface VersionInfo {
|
|
2
|
+
hasUpdate: boolean;
|
|
3
|
+
latestVersion?: string;
|
|
4
|
+
currentVersion: string;
|
|
5
|
+
isDeprecated: boolean;
|
|
6
|
+
deprecationMessage?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function checkForUpdates({ packageName, currentVersion, }: {
|
|
9
|
+
packageName: string;
|
|
10
|
+
currentVersion: string;
|
|
11
|
+
}): Promise<VersionInfo>;
|
|
12
|
+
export declare function displayUpdateNotification(versionInfo: VersionInfo, packageName: string): void;
|
|
13
|
+
export declare function checkAndNotifyUpdates({ packageName, currentVersion, }: {
|
|
14
|
+
packageName: string;
|
|
15
|
+
currentVersion: string;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import packageJsonLib from "package-json";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import log from "./log";
|
|
4
|
+
import Conf from "conf";
|
|
5
|
+
import { getUpdateCommand } from "./package-manager-detector";
|
|
6
|
+
let config = null;
|
|
7
|
+
function getConfig() {
|
|
8
|
+
if (!config) {
|
|
9
|
+
config = new Conf({ projectName: "zapier-sdk-cli" });
|
|
10
|
+
}
|
|
11
|
+
return config;
|
|
12
|
+
}
|
|
13
|
+
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
|
|
14
|
+
const CACHE_RESET_INTERVAL_MS = (() => {
|
|
15
|
+
const { ZAPIER_SDK_UPDATE_CHECK_INTERVAL_MS = `${ONE_DAY_MS}` } = process.env;
|
|
16
|
+
const interval = parseInt(ZAPIER_SDK_UPDATE_CHECK_INTERVAL_MS);
|
|
17
|
+
if (isNaN(interval) || interval < 0) {
|
|
18
|
+
return -1;
|
|
19
|
+
}
|
|
20
|
+
return interval;
|
|
21
|
+
})();
|
|
22
|
+
function getVersionCache() {
|
|
23
|
+
try {
|
|
24
|
+
const cache = getConfig().get("version_cache");
|
|
25
|
+
const now = Date.now();
|
|
26
|
+
// If no cache, missing timestamp, or it's been more than a day, reset the cache
|
|
27
|
+
if (!cache ||
|
|
28
|
+
!cache.last_reset_timestamp ||
|
|
29
|
+
now - cache.last_reset_timestamp >= CACHE_RESET_INTERVAL_MS) {
|
|
30
|
+
const newCache = {
|
|
31
|
+
last_reset_timestamp: now,
|
|
32
|
+
packages: {},
|
|
33
|
+
};
|
|
34
|
+
getConfig().set("version_cache", newCache);
|
|
35
|
+
return newCache;
|
|
36
|
+
}
|
|
37
|
+
return cache;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
log.debug(`Failed to read version cache: ${error}`);
|
|
41
|
+
return {
|
|
42
|
+
last_reset_timestamp: Date.now(),
|
|
43
|
+
packages: {},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function setCachedPackageInfo(packageName, version, info) {
|
|
48
|
+
try {
|
|
49
|
+
const cache = getVersionCache();
|
|
50
|
+
if (!cache.packages[packageName]) {
|
|
51
|
+
cache.packages[packageName] = {};
|
|
52
|
+
}
|
|
53
|
+
cache.packages[packageName][version] = info;
|
|
54
|
+
getConfig().set("version_cache", cache);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
log.debug(`Failed to cache package info: ${error}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function getCachedPackageInfo(packageName, version) {
|
|
61
|
+
try {
|
|
62
|
+
const cache = getVersionCache();
|
|
63
|
+
return cache.packages[packageName]?.[version];
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
log.debug(`Failed to get cached package info: ${error}`);
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function fetchCachedPackageInfo(packageName, version) {
|
|
71
|
+
const cacheKey = version || "latest";
|
|
72
|
+
// Try cache first
|
|
73
|
+
let cachedInfo = getCachedPackageInfo(packageName, cacheKey);
|
|
74
|
+
if (cachedInfo) {
|
|
75
|
+
return cachedInfo;
|
|
76
|
+
}
|
|
77
|
+
// Not in cache, fetch from npm
|
|
78
|
+
const packageInfo = await packageJsonLib(packageName, {
|
|
79
|
+
version,
|
|
80
|
+
fullMetadata: true,
|
|
81
|
+
});
|
|
82
|
+
const info = {
|
|
83
|
+
version: packageInfo.version,
|
|
84
|
+
deprecated: packageInfo.deprecated,
|
|
85
|
+
fetched_at: new Date().toISOString(),
|
|
86
|
+
};
|
|
87
|
+
// Cache for next time
|
|
88
|
+
setCachedPackageInfo(packageName, cacheKey, info);
|
|
89
|
+
return info;
|
|
90
|
+
}
|
|
91
|
+
export async function checkForUpdates({ packageName, currentVersion, }) {
|
|
92
|
+
try {
|
|
93
|
+
// Get latest version info (with caching)
|
|
94
|
+
const latestPackageInfo = await fetchCachedPackageInfo(packageName);
|
|
95
|
+
const latestVersion = latestPackageInfo.version;
|
|
96
|
+
const hasUpdate = currentVersion !== latestVersion;
|
|
97
|
+
// Check deprecation status of the current version (with caching)
|
|
98
|
+
let currentPackageInfo;
|
|
99
|
+
try {
|
|
100
|
+
currentPackageInfo = await fetchCachedPackageInfo(packageName, currentVersion);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
// If we can't fetch the current version info, use the latest version info
|
|
104
|
+
log.debug(`Failed to check deprecation for current version: ${error}`);
|
|
105
|
+
currentPackageInfo = latestPackageInfo;
|
|
106
|
+
}
|
|
107
|
+
const isDeprecated = Boolean(currentPackageInfo.deprecated);
|
|
108
|
+
const deprecationMessage = isDeprecated
|
|
109
|
+
? String(currentPackageInfo.deprecated)
|
|
110
|
+
: undefined;
|
|
111
|
+
return {
|
|
112
|
+
hasUpdate,
|
|
113
|
+
latestVersion,
|
|
114
|
+
currentVersion,
|
|
115
|
+
isDeprecated,
|
|
116
|
+
deprecationMessage,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
// If we can't check for updates (network issues, etc.), fail silently
|
|
121
|
+
log.debug(`Failed to check for updates: ${error}`);
|
|
122
|
+
return {
|
|
123
|
+
hasUpdate: false,
|
|
124
|
+
currentVersion,
|
|
125
|
+
isDeprecated: false,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
export function displayUpdateNotification(versionInfo, packageName) {
|
|
130
|
+
if (versionInfo.isDeprecated) {
|
|
131
|
+
console.error();
|
|
132
|
+
console.error(chalk.red.bold("⚠️ DEPRECATION WARNING") +
|
|
133
|
+
chalk.red(` - ${packageName} v${versionInfo.currentVersion} is deprecated.`));
|
|
134
|
+
if (versionInfo.deprecationMessage) {
|
|
135
|
+
console.error(chalk.red(` ${versionInfo.deprecationMessage}`));
|
|
136
|
+
}
|
|
137
|
+
console.error(chalk.red(` Please update to the latest version.`));
|
|
138
|
+
console.error();
|
|
139
|
+
}
|
|
140
|
+
if (versionInfo.hasUpdate) {
|
|
141
|
+
console.log();
|
|
142
|
+
console.log(chalk.yellow.bold("📦 Update available!") +
|
|
143
|
+
chalk.yellow(` ${packageName} v${versionInfo.currentVersion} → v${versionInfo.latestVersion}`));
|
|
144
|
+
console.log(chalk.yellow(` Run ${chalk.bold(getUpdateCommand(packageName))} to update.`));
|
|
145
|
+
console.log();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
export async function checkAndNotifyUpdates({ packageName, currentVersion, }) {
|
|
149
|
+
if (CACHE_RESET_INTERVAL_MS < 0) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const versionInfo = await checkForUpdates({ packageName, currentVersion });
|
|
153
|
+
displayUpdateNotification(versionInfo, packageName);
|
|
154
|
+
}
|