@zapier/zapier-sdk-cli 0.16.1 → 0.16.4
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 +26 -0
- package/dist/cli.cjs +7 -7
- package/dist/cli.mjs +7 -7
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/package.json +8 -2
- package/dist/src/cli.js +2 -1
- package/dist/src/utils/cli-generator.js +8 -7
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +11 -5
- package/src/cli.test.ts +0 -28
- package/src/cli.ts +0 -96
- package/src/generators/ast-generator.test.ts +0 -908
- package/src/generators/ast-generator.ts +0 -774
- package/src/index.ts +0 -12
- package/src/plugins/add/index.test.ts +0 -58
- package/src/plugins/add/index.ts +0 -177
- package/src/plugins/add/schemas.ts +0 -35
- package/src/plugins/buildManifest/index.test.ts +0 -679
- package/src/plugins/buildManifest/index.ts +0 -131
- package/src/plugins/buildManifest/schemas.ts +0 -55
- package/src/plugins/bundleCode/index.ts +0 -128
- package/src/plugins/bundleCode/schemas.ts +0 -24
- package/src/plugins/generateAppTypes/index.test.ts +0 -679
- package/src/plugins/generateAppTypes/index.ts +0 -227
- package/src/plugins/generateAppTypes/schemas.ts +0 -61
- package/src/plugins/getLoginConfigPath/index.ts +0 -45
- package/src/plugins/getLoginConfigPath/schemas.ts +0 -10
- package/src/plugins/index.ts +0 -8
- package/src/plugins/login/index.ts +0 -135
- package/src/plugins/login/schemas.ts +0 -13
- package/src/plugins/logout/index.ts +0 -37
- package/src/plugins/logout/schemas.ts +0 -8
- package/src/plugins/mcp/index.ts +0 -43
- package/src/plugins/mcp/schemas.ts +0 -13
- package/src/sdk.ts +0 -45
- package/src/telemetry/builders.ts +0 -113
- package/src/telemetry/events.ts +0 -39
- package/src/types/sdk.ts +0 -8
- package/src/utils/api/client.ts +0 -44
- package/src/utils/auth/login.ts +0 -214
- package/src/utils/cli-generator-utils.ts +0 -169
- package/src/utils/cli-generator.test.ts +0 -347
- package/src/utils/cli-generator.ts +0 -807
- package/src/utils/constants.ts +0 -9
- package/src/utils/directory-detection.ts +0 -23
- package/src/utils/errors.ts +0 -26
- package/src/utils/getCallablePromise.ts +0 -21
- package/src/utils/log.ts +0 -23
- package/src/utils/manifest-helpers.ts +0 -25
- package/src/utils/package-manager-detector.ts +0 -83
- package/src/utils/parameter-resolver.ts +0 -1075
- package/src/utils/schema-formatter.ts +0 -153
- package/src/utils/serializeAsync.ts +0 -26
- package/src/utils/spinner.ts +0 -23
- package/src/utils/version-checker.test.ts +0 -239
- package/src/utils/version-checker.ts +0 -237
- package/tsconfig.build.json +0 -18
- package/tsconfig.json +0 -19
- package/tsup.config.ts +0 -23
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import type { z } from "zod";
|
|
3
|
-
import util from "util";
|
|
4
|
-
import type { FormattedItem, FormatMetadata } from "@zapier/zapier-sdk";
|
|
5
|
-
// These functions are internal to SDK, implementing basic formatting fallback
|
|
6
|
-
// TODO: Consider exposing these utilities or implementing proper CLI formatting
|
|
7
|
-
|
|
8
|
-
function getFormatMetadata(schema: unknown): FormatMetadata | undefined {
|
|
9
|
-
return (schema as { _zod?: { def?: { formatMeta?: FormatMetadata } } })?._zod
|
|
10
|
-
?.def?.formatMeta;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function getOutputSchema(schema: unknown): unknown {
|
|
14
|
-
return (schema as { _zod?: { def?: { outputSchema?: unknown } } })?._zod?.def
|
|
15
|
-
?.outputSchema;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// ============================================================================
|
|
19
|
-
// JSON Formatting
|
|
20
|
-
// ============================================================================
|
|
21
|
-
|
|
22
|
-
export function formatJsonOutput(data: unknown): void {
|
|
23
|
-
// Don't print anything for undefined results (commands that just perform actions)
|
|
24
|
-
if (data === undefined) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Use util.inspect for colored output
|
|
29
|
-
console.log(
|
|
30
|
-
util.inspect(data, { colors: true, depth: null, breakLength: 80 }),
|
|
31
|
-
);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// ============================================================================
|
|
35
|
-
// Generic Schema-Driven Formatter
|
|
36
|
-
// ============================================================================
|
|
37
|
-
|
|
38
|
-
export function formatItemsFromSchema(
|
|
39
|
-
functionInfo: { inputSchema: z.ZodType; outputSchema?: z.ZodType },
|
|
40
|
-
items: unknown[],
|
|
41
|
-
startingNumber: number = 0,
|
|
42
|
-
): void {
|
|
43
|
-
// Get the output schema from function info or fall back to input schema output schema
|
|
44
|
-
const outputSchema =
|
|
45
|
-
functionInfo.outputSchema || getOutputSchema(functionInfo.inputSchema);
|
|
46
|
-
if (!outputSchema) {
|
|
47
|
-
// Fallback to generic formatting if no output schema
|
|
48
|
-
formatItemsGeneric(items, startingNumber);
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const formatMeta = getFormatMetadata(outputSchema);
|
|
53
|
-
if (!formatMeta) {
|
|
54
|
-
// Fallback to generic formatting if no format metadata
|
|
55
|
-
formatItemsGeneric(items, startingNumber);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Format each item using the schema metadata
|
|
60
|
-
items.forEach((item, index) => {
|
|
61
|
-
const formatted = formatMeta.format(item);
|
|
62
|
-
formatSingleItem(formatted, startingNumber + index);
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function formatSingleItem(formatted: FormattedItem, itemNumber: number): void {
|
|
67
|
-
// Build the main title line with optional subtitle
|
|
68
|
-
let titleLine = `${chalk.gray(`${itemNumber + 1}.`)} ${chalk.cyan(formatted.title)}`;
|
|
69
|
-
|
|
70
|
-
// Generate subtitle - always show key if available, then ID if available
|
|
71
|
-
const subtitleParts = [];
|
|
72
|
-
if (formatted.keys) {
|
|
73
|
-
subtitleParts.push(...formatted.keys);
|
|
74
|
-
} else if (formatted.key) {
|
|
75
|
-
subtitleParts.push(formatted.key);
|
|
76
|
-
}
|
|
77
|
-
if (formatted.id) {
|
|
78
|
-
subtitleParts.push(formatted.id);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Remove duplicates while preserving order
|
|
82
|
-
const uniqueParts = [...new Set(subtitleParts)];
|
|
83
|
-
|
|
84
|
-
if (uniqueParts.length > 0) {
|
|
85
|
-
titleLine += ` ${chalk.gray(`(${uniqueParts.join(", ")})`)}`;
|
|
86
|
-
}
|
|
87
|
-
console.log(titleLine);
|
|
88
|
-
|
|
89
|
-
// Show description if available
|
|
90
|
-
if (formatted.description) {
|
|
91
|
-
console.log(` ${chalk.dim(formatted.description)}`);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// If data is provided, use JSON formatting instead of details
|
|
95
|
-
if (formatted.data !== undefined) {
|
|
96
|
-
formatJsonOutput(formatted.data);
|
|
97
|
-
console.log(); // Empty line between items
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Format detail lines
|
|
102
|
-
for (const detail of formatted.details) {
|
|
103
|
-
const styledText = applyStyle(detail.text, detail.style);
|
|
104
|
-
console.log(` ${styledText}`);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
console.log(); // Empty line between items
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function applyStyle(value: string, style: string): string {
|
|
111
|
-
switch (style) {
|
|
112
|
-
case "dim":
|
|
113
|
-
return chalk.dim(value);
|
|
114
|
-
case "accent":
|
|
115
|
-
return chalk.magenta(value);
|
|
116
|
-
case "warning":
|
|
117
|
-
return chalk.red(value);
|
|
118
|
-
case "success":
|
|
119
|
-
return chalk.green(value);
|
|
120
|
-
case "normal":
|
|
121
|
-
default:
|
|
122
|
-
return chalk.blue(value);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function convertGenericItemToFormattedItem(item: unknown): FormattedItem {
|
|
127
|
-
const itemObj = item as {
|
|
128
|
-
title?: string;
|
|
129
|
-
name?: string;
|
|
130
|
-
key?: string;
|
|
131
|
-
id?: string;
|
|
132
|
-
description?: string;
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
return {
|
|
136
|
-
title: itemObj.title || itemObj.name || itemObj.key || itemObj.id || "Item",
|
|
137
|
-
id: itemObj.id,
|
|
138
|
-
key: itemObj.key,
|
|
139
|
-
description: itemObj.description,
|
|
140
|
-
details: [],
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function formatItemsGeneric(
|
|
145
|
-
items: unknown[],
|
|
146
|
-
startingNumber: number = 0,
|
|
147
|
-
): void {
|
|
148
|
-
// Convert generic items to FormattedItem and use formatSingleItem
|
|
149
|
-
items.forEach((item, index) => {
|
|
150
|
-
const formatted = convertGenericItemToFormattedItem(item);
|
|
151
|
-
formatSingleItem(formatted, startingNumber + index);
|
|
152
|
-
});
|
|
153
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
|
-
|
|
3
|
-
const promises: Record<string, Promise<unknown>> = {};
|
|
4
|
-
|
|
5
|
-
const serializeAsync =
|
|
6
|
-
<R, A extends []>(
|
|
7
|
-
fn: (...args: A) => Promise<R>,
|
|
8
|
-
): ((...args: A) => Promise<R>) =>
|
|
9
|
-
async (...args: A): Promise<R> => {
|
|
10
|
-
const hash = createHash("sha256")
|
|
11
|
-
.update(fn.toString(), "utf8")
|
|
12
|
-
.digest()
|
|
13
|
-
.toString("hex");
|
|
14
|
-
|
|
15
|
-
const promise = promises[hash];
|
|
16
|
-
|
|
17
|
-
if (!promise) {
|
|
18
|
-
promises[hash] = fn(...args).finally(() => {
|
|
19
|
-
delete promises[hash];
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return promises[hash] as Promise<R>;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
export default serializeAsync;
|
package/src/utils/spinner.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import ora from "ora";
|
|
2
|
-
import { ZapierCliUserCancellationError } from "./errors";
|
|
3
|
-
|
|
4
|
-
export const spinPromise = async <T>(
|
|
5
|
-
promise: Promise<T>,
|
|
6
|
-
text: string,
|
|
7
|
-
): Promise<T> => {
|
|
8
|
-
const spinner = ora(text).start();
|
|
9
|
-
try {
|
|
10
|
-
const result = await promise;
|
|
11
|
-
spinner.succeed();
|
|
12
|
-
return result;
|
|
13
|
-
} catch (error) {
|
|
14
|
-
if (error instanceof ZapierCliUserCancellationError) {
|
|
15
|
-
// For user cancellation, just stop the spinner without showing failure
|
|
16
|
-
spinner.stop();
|
|
17
|
-
} else {
|
|
18
|
-
// For actual errors, show failure
|
|
19
|
-
spinner.fail();
|
|
20
|
-
}
|
|
21
|
-
throw error;
|
|
22
|
-
}
|
|
23
|
-
};
|
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
-
import { checkForUpdates, displayUpdateNotification } from "./version-checker";
|
|
3
|
-
|
|
4
|
-
// Mock package-json
|
|
5
|
-
vi.mock("package-json", () => ({
|
|
6
|
-
default: vi.fn(),
|
|
7
|
-
}));
|
|
8
|
-
|
|
9
|
-
// Mock chalk to make testing easier
|
|
10
|
-
vi.mock("chalk", () => ({
|
|
11
|
-
default: {
|
|
12
|
-
red: Object.assign((text: string) => text, {
|
|
13
|
-
bold: (text: string) => text,
|
|
14
|
-
}),
|
|
15
|
-
yellow: Object.assign((text: string) => text, {
|
|
16
|
-
bold: (text: string) => text,
|
|
17
|
-
}),
|
|
18
|
-
bold: (text: string) => text,
|
|
19
|
-
},
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
// Mock log module
|
|
23
|
-
vi.mock("./log", () => ({
|
|
24
|
-
default: {
|
|
25
|
-
debug: vi.fn(),
|
|
26
|
-
},
|
|
27
|
-
}));
|
|
28
|
-
|
|
29
|
-
// Mock conf module
|
|
30
|
-
const mockConf = {
|
|
31
|
-
get: vi.fn(),
|
|
32
|
-
set: vi.fn(),
|
|
33
|
-
};
|
|
34
|
-
vi.mock("conf", () => ({
|
|
35
|
-
default: vi.fn().mockImplementation(() => mockConf),
|
|
36
|
-
}));
|
|
37
|
-
|
|
38
|
-
const mockPackageJson = vi.mocked(await import("package-json")).default;
|
|
39
|
-
|
|
40
|
-
describe("version-checker", () => {
|
|
41
|
-
beforeEach(() => {
|
|
42
|
-
vi.clearAllMocks();
|
|
43
|
-
// Ensure cache is cleared between tests by returning undefined from get
|
|
44
|
-
mockConf.get.mockReturnValue(undefined);
|
|
45
|
-
// Suppress console output during tests
|
|
46
|
-
vi.spyOn(console, "log").mockImplementation(() => {});
|
|
47
|
-
vi.spyOn(console, "error").mockImplementation(() => {});
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
describe("checkForUpdates", () => {
|
|
51
|
-
it("should detect when an update is available", async () => {
|
|
52
|
-
mockPackageJson.mockResolvedValue({
|
|
53
|
-
version: "1.0.1",
|
|
54
|
-
deprecated: false,
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
const result = await checkForUpdates({
|
|
58
|
-
packageName: "test-package",
|
|
59
|
-
currentVersion: "1.0.0",
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
expect(result).toEqual({
|
|
63
|
-
hasUpdate: true,
|
|
64
|
-
latestVersion: "1.0.1",
|
|
65
|
-
currentVersion: "1.0.0",
|
|
66
|
-
isDeprecated: false,
|
|
67
|
-
deprecationMessage: undefined,
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it("should not suggest update when current version is newer than latest", async () => {
|
|
72
|
-
mockPackageJson.mockResolvedValue({
|
|
73
|
-
version: "1.0.0",
|
|
74
|
-
deprecated: false,
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
const result = await checkForUpdates({
|
|
78
|
-
packageName: "test-package",
|
|
79
|
-
currentVersion: "1.0.1",
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
expect(result).toEqual({
|
|
83
|
-
hasUpdate: false,
|
|
84
|
-
latestVersion: "1.0.0",
|
|
85
|
-
currentVersion: "1.0.1",
|
|
86
|
-
isDeprecated: false,
|
|
87
|
-
deprecationMessage: undefined,
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it("should handle pre-release versions correctly", async () => {
|
|
92
|
-
mockPackageJson.mockResolvedValue({
|
|
93
|
-
version: "1.0.0-beta.2",
|
|
94
|
-
deprecated: false,
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
const result = await checkForUpdates({
|
|
98
|
-
packageName: "test-package",
|
|
99
|
-
currentVersion: "1.0.0-beta.1",
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
expect(result).toEqual({
|
|
103
|
-
hasUpdate: true,
|
|
104
|
-
latestVersion: "1.0.0-beta.2",
|
|
105
|
-
currentVersion: "1.0.0-beta.1",
|
|
106
|
-
isDeprecated: false,
|
|
107
|
-
deprecationMessage: undefined,
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it("should detect when package is deprecated", async () => {
|
|
112
|
-
mockPackageJson.mockResolvedValue({
|
|
113
|
-
version: "1.0.0",
|
|
114
|
-
deprecated: "This package is no longer maintained",
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
const result = await checkForUpdates({
|
|
118
|
-
packageName: "test-package",
|
|
119
|
-
currentVersion: "1.0.0",
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
expect(result).toEqual({
|
|
123
|
-
hasUpdate: false,
|
|
124
|
-
latestVersion: "1.0.0",
|
|
125
|
-
currentVersion: "1.0.0",
|
|
126
|
-
isDeprecated: true,
|
|
127
|
-
deprecationMessage: "This package is no longer maintained",
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it("should handle when no update is available", async () => {
|
|
132
|
-
mockPackageJson.mockResolvedValue({
|
|
133
|
-
version: "1.0.0",
|
|
134
|
-
deprecated: false,
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
const result = await checkForUpdates({
|
|
138
|
-
packageName: "test-package",
|
|
139
|
-
currentVersion: "1.0.0",
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
expect(result).toEqual({
|
|
143
|
-
hasUpdate: false,
|
|
144
|
-
latestVersion: "1.0.0",
|
|
145
|
-
currentVersion: "1.0.0",
|
|
146
|
-
isDeprecated: false,
|
|
147
|
-
deprecationMessage: undefined,
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it("should handle network errors gracefully", async () => {
|
|
152
|
-
mockPackageJson.mockRejectedValue(new Error("Network error"));
|
|
153
|
-
|
|
154
|
-
const result = await checkForUpdates({
|
|
155
|
-
packageName: "test-package",
|
|
156
|
-
currentVersion: "1.0.0",
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
expect(result).toEqual({
|
|
160
|
-
hasUpdate: false,
|
|
161
|
-
currentVersion: "1.0.0",
|
|
162
|
-
isDeprecated: false,
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
describe("displayUpdateNotification", () => {
|
|
168
|
-
it("should display deprecation warning", () => {
|
|
169
|
-
const consoleSpy = vi
|
|
170
|
-
.spyOn(console, "error")
|
|
171
|
-
.mockImplementation(() => {});
|
|
172
|
-
|
|
173
|
-
displayUpdateNotification(
|
|
174
|
-
{
|
|
175
|
-
hasUpdate: false,
|
|
176
|
-
currentVersion: "1.0.0",
|
|
177
|
-
isDeprecated: true,
|
|
178
|
-
deprecationMessage: "This package is deprecated",
|
|
179
|
-
},
|
|
180
|
-
"test-package",
|
|
181
|
-
);
|
|
182
|
-
|
|
183
|
-
expect(consoleSpy).toHaveBeenCalledWith(
|
|
184
|
-
expect.stringContaining("DEPRECATION WARNING"),
|
|
185
|
-
);
|
|
186
|
-
expect(consoleSpy).toHaveBeenCalledWith(
|
|
187
|
-
expect.stringContaining("This package is deprecated"),
|
|
188
|
-
);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
it("should display update notification", () => {
|
|
192
|
-
const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
193
|
-
|
|
194
|
-
displayUpdateNotification(
|
|
195
|
-
{
|
|
196
|
-
hasUpdate: true,
|
|
197
|
-
currentVersion: "1.0.0",
|
|
198
|
-
latestVersion: "1.0.1",
|
|
199
|
-
isDeprecated: false,
|
|
200
|
-
},
|
|
201
|
-
"test-package",
|
|
202
|
-
);
|
|
203
|
-
|
|
204
|
-
expect(consoleSpy).toHaveBeenCalledWith(
|
|
205
|
-
expect.stringContaining("Update available!"),
|
|
206
|
-
);
|
|
207
|
-
expect(consoleSpy).toHaveBeenCalledWith(
|
|
208
|
-
expect.stringContaining("pnpm update test-package"),
|
|
209
|
-
);
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
it("should display both deprecation and update notifications", () => {
|
|
213
|
-
const consoleErrorSpy = vi
|
|
214
|
-
.spyOn(console, "error")
|
|
215
|
-
.mockImplementation(() => {});
|
|
216
|
-
const consoleLogSpy = vi
|
|
217
|
-
.spyOn(console, "log")
|
|
218
|
-
.mockImplementation(() => {});
|
|
219
|
-
|
|
220
|
-
displayUpdateNotification(
|
|
221
|
-
{
|
|
222
|
-
hasUpdate: true,
|
|
223
|
-
currentVersion: "1.0.0",
|
|
224
|
-
latestVersion: "1.0.1",
|
|
225
|
-
isDeprecated: true,
|
|
226
|
-
deprecationMessage: "This package is deprecated",
|
|
227
|
-
},
|
|
228
|
-
"test-package",
|
|
229
|
-
);
|
|
230
|
-
|
|
231
|
-
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
232
|
-
expect.stringContaining("DEPRECATION WARNING"),
|
|
233
|
-
);
|
|
234
|
-
expect(consoleLogSpy).toHaveBeenCalledWith(
|
|
235
|
-
expect.stringContaining("Update available!"),
|
|
236
|
-
);
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
});
|
|
@@ -1,237 +0,0 @@
|
|
|
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
|
-
import semver from "semver";
|
|
7
|
-
|
|
8
|
-
interface VersionInfo {
|
|
9
|
-
hasUpdate: boolean;
|
|
10
|
-
latestVersion?: string;
|
|
11
|
-
currentVersion: string;
|
|
12
|
-
isDeprecated: boolean;
|
|
13
|
-
deprecationMessage?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
interface CachedPackageInfo {
|
|
17
|
-
version: string;
|
|
18
|
-
deprecated?: string | boolean;
|
|
19
|
-
fetched_at: string; // ISO date string
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
interface VersionCache {
|
|
23
|
-
last_reset_timestamp: number; // Unix timestamp in milliseconds
|
|
24
|
-
packages: {
|
|
25
|
-
[packageName: string]: {
|
|
26
|
-
[version: string]: CachedPackageInfo;
|
|
27
|
-
};
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
let config: Conf | null = null;
|
|
32
|
-
|
|
33
|
-
function getConfig(): Conf {
|
|
34
|
-
if (!config) {
|
|
35
|
-
config = new Conf({ projectName: "zapier-sdk-cli" });
|
|
36
|
-
}
|
|
37
|
-
return config;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
|
|
41
|
-
|
|
42
|
-
const CACHE_RESET_INTERVAL_MS = (() => {
|
|
43
|
-
const { ZAPIER_SDK_UPDATE_CHECK_INTERVAL_MS = `${ONE_DAY_MS}` } = process.env;
|
|
44
|
-
const interval = parseInt(ZAPIER_SDK_UPDATE_CHECK_INTERVAL_MS);
|
|
45
|
-
if (isNaN(interval) || interval < 0) {
|
|
46
|
-
return -1;
|
|
47
|
-
}
|
|
48
|
-
return interval;
|
|
49
|
-
})();
|
|
50
|
-
|
|
51
|
-
function getVersionCache(): VersionCache {
|
|
52
|
-
try {
|
|
53
|
-
const cache = getConfig().get("version_cache") as VersionCache | undefined;
|
|
54
|
-
const now = Date.now();
|
|
55
|
-
|
|
56
|
-
// If no cache, missing timestamp, or it's been more than a day, reset the cache
|
|
57
|
-
if (
|
|
58
|
-
!cache ||
|
|
59
|
-
!cache.last_reset_timestamp ||
|
|
60
|
-
now - cache.last_reset_timestamp >= CACHE_RESET_INTERVAL_MS
|
|
61
|
-
) {
|
|
62
|
-
const newCache: VersionCache = {
|
|
63
|
-
last_reset_timestamp: now,
|
|
64
|
-
packages: {},
|
|
65
|
-
};
|
|
66
|
-
getConfig().set("version_cache", newCache);
|
|
67
|
-
return newCache;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return cache;
|
|
71
|
-
} catch (error) {
|
|
72
|
-
log.debug(`Failed to read version cache: ${error}`);
|
|
73
|
-
return {
|
|
74
|
-
last_reset_timestamp: Date.now(),
|
|
75
|
-
packages: {},
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function setCachedPackageInfo(
|
|
81
|
-
packageName: string,
|
|
82
|
-
version: string,
|
|
83
|
-
info: CachedPackageInfo,
|
|
84
|
-
): void {
|
|
85
|
-
try {
|
|
86
|
-
const cache = getVersionCache();
|
|
87
|
-
if (!cache.packages[packageName]) {
|
|
88
|
-
cache.packages[packageName] = {};
|
|
89
|
-
}
|
|
90
|
-
cache.packages[packageName][version] = info;
|
|
91
|
-
getConfig().set("version_cache", cache);
|
|
92
|
-
} catch (error) {
|
|
93
|
-
log.debug(`Failed to cache package info: ${error}`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function getCachedPackageInfo(
|
|
98
|
-
packageName: string,
|
|
99
|
-
version: string,
|
|
100
|
-
): CachedPackageInfo | undefined {
|
|
101
|
-
try {
|
|
102
|
-
const cache = getVersionCache();
|
|
103
|
-
return cache.packages[packageName]?.[version];
|
|
104
|
-
} catch (error) {
|
|
105
|
-
log.debug(`Failed to get cached package info: ${error}`);
|
|
106
|
-
return undefined;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async function fetchCachedPackageInfo(
|
|
111
|
-
packageName: string,
|
|
112
|
-
version?: string,
|
|
113
|
-
): Promise<CachedPackageInfo> {
|
|
114
|
-
const cacheKey = version || "latest";
|
|
115
|
-
|
|
116
|
-
// Try cache first
|
|
117
|
-
let cachedInfo = getCachedPackageInfo(packageName, cacheKey);
|
|
118
|
-
if (cachedInfo) {
|
|
119
|
-
return cachedInfo;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Not in cache, fetch from npm
|
|
123
|
-
const packageInfo = await packageJsonLib(packageName, {
|
|
124
|
-
version,
|
|
125
|
-
fullMetadata: true,
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
const info: CachedPackageInfo = {
|
|
129
|
-
version: packageInfo.version,
|
|
130
|
-
deprecated: packageInfo.deprecated,
|
|
131
|
-
fetched_at: new Date().toISOString(),
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
// Cache for next time
|
|
135
|
-
setCachedPackageInfo(packageName, cacheKey, info);
|
|
136
|
-
|
|
137
|
-
return info;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export async function checkForUpdates({
|
|
141
|
-
packageName,
|
|
142
|
-
currentVersion,
|
|
143
|
-
}: {
|
|
144
|
-
packageName: string;
|
|
145
|
-
currentVersion: string;
|
|
146
|
-
}): Promise<VersionInfo> {
|
|
147
|
-
try {
|
|
148
|
-
// Get latest version info (with caching)
|
|
149
|
-
const latestPackageInfo = await fetchCachedPackageInfo(packageName);
|
|
150
|
-
const latestVersion = latestPackageInfo.version;
|
|
151
|
-
const hasUpdate = semver.gt(latestVersion, currentVersion);
|
|
152
|
-
|
|
153
|
-
// Check deprecation status of the current version (with caching)
|
|
154
|
-
let currentPackageInfo: CachedPackageInfo;
|
|
155
|
-
try {
|
|
156
|
-
currentPackageInfo = await fetchCachedPackageInfo(
|
|
157
|
-
packageName,
|
|
158
|
-
currentVersion,
|
|
159
|
-
);
|
|
160
|
-
} catch (error) {
|
|
161
|
-
// If we can't fetch the current version info, use the latest version info
|
|
162
|
-
log.debug(`Failed to check deprecation for current version: ${error}`);
|
|
163
|
-
currentPackageInfo = latestPackageInfo;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const isDeprecated = Boolean(currentPackageInfo.deprecated);
|
|
167
|
-
const deprecationMessage = isDeprecated
|
|
168
|
-
? String(currentPackageInfo.deprecated)
|
|
169
|
-
: undefined;
|
|
170
|
-
|
|
171
|
-
return {
|
|
172
|
-
hasUpdate,
|
|
173
|
-
latestVersion,
|
|
174
|
-
currentVersion,
|
|
175
|
-
isDeprecated,
|
|
176
|
-
deprecationMessage,
|
|
177
|
-
};
|
|
178
|
-
} catch (error) {
|
|
179
|
-
// If we can't check for updates (network issues, etc.), fail silently
|
|
180
|
-
log.debug(`Failed to check for updates: ${error}`);
|
|
181
|
-
return {
|
|
182
|
-
hasUpdate: false,
|
|
183
|
-
currentVersion,
|
|
184
|
-
isDeprecated: false,
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
export function displayUpdateNotification(
|
|
190
|
-
versionInfo: VersionInfo,
|
|
191
|
-
packageName: string,
|
|
192
|
-
): void {
|
|
193
|
-
if (versionInfo.isDeprecated) {
|
|
194
|
-
console.error();
|
|
195
|
-
console.error(
|
|
196
|
-
chalk.red.bold("⚠️ DEPRECATION WARNING") +
|
|
197
|
-
chalk.red(
|
|
198
|
-
` - ${packageName} v${versionInfo.currentVersion} is deprecated.`,
|
|
199
|
-
),
|
|
200
|
-
);
|
|
201
|
-
if (versionInfo.deprecationMessage) {
|
|
202
|
-
console.error(chalk.red(` ${versionInfo.deprecationMessage}`));
|
|
203
|
-
}
|
|
204
|
-
console.error(chalk.red(` Please update to the latest version.`));
|
|
205
|
-
console.error();
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (versionInfo.hasUpdate) {
|
|
209
|
-
console.log();
|
|
210
|
-
console.log(
|
|
211
|
-
chalk.yellow.bold("📦 Update available!") +
|
|
212
|
-
chalk.yellow(
|
|
213
|
-
` ${packageName} v${versionInfo.currentVersion} → v${versionInfo.latestVersion}`,
|
|
214
|
-
),
|
|
215
|
-
);
|
|
216
|
-
console.log(
|
|
217
|
-
chalk.yellow(
|
|
218
|
-
` Run ${chalk.bold(getUpdateCommand(packageName))} to update.`,
|
|
219
|
-
),
|
|
220
|
-
);
|
|
221
|
-
console.log();
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
export async function checkAndNotifyUpdates({
|
|
226
|
-
packageName,
|
|
227
|
-
currentVersion,
|
|
228
|
-
}: {
|
|
229
|
-
packageName: string;
|
|
230
|
-
currentVersion: string;
|
|
231
|
-
}): Promise<void> {
|
|
232
|
-
if (CACHE_RESET_INTERVAL_MS < 0) {
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
const versionInfo = await checkForUpdates({ packageName, currentVersion });
|
|
236
|
-
displayUpdateNotification(versionInfo, packageName);
|
|
237
|
-
}
|
package/tsconfig.build.json
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "esnext",
|
|
5
|
-
"declaration": true,
|
|
6
|
-
"outDir": "./dist",
|
|
7
|
-
"rootDir": "./src",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"noUnusedLocals": true,
|
|
10
|
-
"noUnusedParameters": true,
|
|
11
|
-
"esModuleInterop": true,
|
|
12
|
-
"skipLibCheck": true,
|
|
13
|
-
"forceConsistentCasingInFileNames": true,
|
|
14
|
-
"moduleResolution": "bundler"
|
|
15
|
-
},
|
|
16
|
-
"include": ["src/**/*"],
|
|
17
|
-
"exclude": ["dist", "node_modules", "src/**/*.test.ts", "src/**/*.spec.ts"]
|
|
18
|
-
}
|