@zapier/zapier-sdk 0.13.5 → 0.13.7
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 +15 -0
- package/dist/api/schemas.d.ts +38 -38
- package/dist/index.cjs +1 -1
- package/dist/index.d.mts +170 -177
- package/dist/index.mjs +1 -1
- package/dist/plugins/fetch/schemas.d.ts +4 -4
- package/dist/plugins/getAction/schemas.d.ts +2 -2
- package/dist/plugins/listActions/schemas.d.ts +6 -6
- package/dist/plugins/listApps/schemas.d.ts +6 -6
- package/dist/plugins/listAuthentications/schemas.d.ts +4 -4
- package/dist/plugins/listInputFieldChoices/schemas.d.ts +8 -8
- package/dist/plugins/listInputFields/schemas.d.ts +8 -8
- package/dist/plugins/request/schemas.d.ts +8 -8
- package/dist/plugins/runAction/schemas.d.ts +8 -8
- package/dist/schemas/Action.d.ts +2 -2
- package/dist/schemas/App.d.ts +8 -8
- package/dist/types/sdk.d.ts +2 -8
- package/dist/types/sdk.d.ts.map +1 -1
- package/package.json +8 -3
- package/src/api/auth.ts +0 -28
- package/src/api/client.ts +0 -491
- package/src/api/debug.test.ts +0 -76
- package/src/api/debug.ts +0 -154
- package/src/api/index.ts +0 -90
- package/src/api/polling.test.ts +0 -405
- package/src/api/polling.ts +0 -253
- package/src/api/schemas.ts +0 -465
- package/src/api/types.ts +0 -152
- package/src/auth.ts +0 -72
- package/src/constants.ts +0 -16
- package/src/index.ts +0 -111
- package/src/plugins/api/index.ts +0 -43
- package/src/plugins/apps/index.ts +0 -203
- package/src/plugins/apps/schemas.ts +0 -64
- package/src/plugins/eventEmission/builders.ts +0 -115
- package/src/plugins/eventEmission/index.test.ts +0 -169
- package/src/plugins/eventEmission/index.ts +0 -294
- package/src/plugins/eventEmission/transport.test.ts +0 -214
- package/src/plugins/eventEmission/transport.ts +0 -135
- package/src/plugins/eventEmission/types.ts +0 -58
- package/src/plugins/eventEmission/utils.ts +0 -121
- package/src/plugins/fetch/index.ts +0 -83
- package/src/plugins/fetch/schemas.ts +0 -37
- package/src/plugins/findFirstAuthentication/index.test.ts +0 -209
- package/src/plugins/findFirstAuthentication/index.ts +0 -68
- package/src/plugins/findFirstAuthentication/schemas.ts +0 -47
- package/src/plugins/findUniqueAuthentication/index.test.ts +0 -197
- package/src/plugins/findUniqueAuthentication/index.ts +0 -77
- package/src/plugins/findUniqueAuthentication/schemas.ts +0 -49
- package/src/plugins/getAction/index.test.ts +0 -239
- package/src/plugins/getAction/index.ts +0 -75
- package/src/plugins/getAction/schemas.ts +0 -41
- package/src/plugins/getApp/index.test.ts +0 -181
- package/src/plugins/getApp/index.ts +0 -60
- package/src/plugins/getApp/schemas.ts +0 -33
- package/src/plugins/getAuthentication/index.test.ts +0 -294
- package/src/plugins/getAuthentication/index.ts +0 -95
- package/src/plugins/getAuthentication/schemas.ts +0 -38
- package/src/plugins/getProfile/index.ts +0 -60
- package/src/plugins/getProfile/schemas.ts +0 -24
- package/src/plugins/listActions/index.test.ts +0 -526
- package/src/plugins/listActions/index.ts +0 -132
- package/src/plugins/listActions/schemas.ts +0 -55
- package/src/plugins/listApps/index.test.ts +0 -378
- package/src/plugins/listApps/index.ts +0 -159
- package/src/plugins/listApps/schemas.ts +0 -41
- package/src/plugins/listAuthentications/index.test.ts +0 -739
- package/src/plugins/listAuthentications/index.ts +0 -152
- package/src/plugins/listAuthentications/schemas.ts +0 -77
- package/src/plugins/listInputFieldChoices/index.test.ts +0 -653
- package/src/plugins/listInputFieldChoices/index.ts +0 -173
- package/src/plugins/listInputFieldChoices/schemas.ts +0 -125
- package/src/plugins/listInputFields/index.test.ts +0 -439
- package/src/plugins/listInputFields/index.ts +0 -294
- package/src/plugins/listInputFields/schemas.ts +0 -68
- package/src/plugins/manifest/index.test.ts +0 -776
- package/src/plugins/manifest/index.ts +0 -461
- package/src/plugins/manifest/schemas.ts +0 -60
- package/src/plugins/registry/index.ts +0 -160
- package/src/plugins/request/index.test.ts +0 -333
- package/src/plugins/request/index.ts +0 -105
- package/src/plugins/request/schemas.ts +0 -69
- package/src/plugins/runAction/index.test.ts +0 -388
- package/src/plugins/runAction/index.ts +0 -215
- package/src/plugins/runAction/schemas.ts +0 -60
- package/src/resolvers/actionKey.ts +0 -37
- package/src/resolvers/actionType.ts +0 -34
- package/src/resolvers/appKey.ts +0 -7
- package/src/resolvers/authenticationId.ts +0 -54
- package/src/resolvers/index.ts +0 -11
- package/src/resolvers/inputFieldKey.ts +0 -70
- package/src/resolvers/inputs.ts +0 -69
- package/src/schemas/Action.ts +0 -52
- package/src/schemas/App.ts +0 -45
- package/src/schemas/Auth.ts +0 -59
- package/src/schemas/Field.ts +0 -169
- package/src/schemas/Run.ts +0 -40
- package/src/schemas/UserProfile.ts +0 -60
- package/src/sdk.test.ts +0 -212
- package/src/sdk.ts +0 -178
- package/src/types/domain.test.ts +0 -50
- package/src/types/domain.ts +0 -66
- package/src/types/errors.ts +0 -278
- package/src/types/events.ts +0 -43
- package/src/types/functions.ts +0 -28
- package/src/types/optional-zapier-sdk-cli-login.d.ts +0 -37
- package/src/types/plugin.ts +0 -125
- package/src/types/properties.ts +0 -80
- package/src/types/sdk.ts +0 -117
- package/src/types/telemetry-events.ts +0 -85
- package/src/utils/array-utils.test.ts +0 -131
- package/src/utils/array-utils.ts +0 -41
- package/src/utils/domain-utils.test.ts +0 -433
- package/src/utils/domain-utils.ts +0 -267
- package/src/utils/file-utils.test.ts +0 -73
- package/src/utils/file-utils.ts +0 -94
- package/src/utils/function-utils.test.ts +0 -141
- package/src/utils/function-utils.ts +0 -245
- package/src/utils/pagination-utils.test.ts +0 -620
- package/src/utils/pagination-utils.ts +0 -242
- package/src/utils/schema-utils.ts +0 -207
- package/src/utils/string-utils.test.ts +0 -45
- package/src/utils/string-utils.ts +0 -54
- package/src/utils/validation.test.ts +0 -51
- package/src/utils/validation.ts +0 -44
- package/tsconfig.build.json +0 -18
- package/tsconfig.json +0 -20
- package/tsconfig.tsbuildinfo +0 -1
- package/tsup.config.ts +0 -23
|
@@ -1,776 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
manifestPlugin,
|
|
4
|
-
readManifestFromFile,
|
|
5
|
-
findManifestEntry,
|
|
6
|
-
getPreferredManifestEntryKey,
|
|
7
|
-
} from "./index";
|
|
8
|
-
import { createSdk } from "../../sdk";
|
|
9
|
-
import type { Manifest } from "./schemas";
|
|
10
|
-
|
|
11
|
-
// Mock file-utils module
|
|
12
|
-
vi.mock("../../utils/file-utils", () => ({
|
|
13
|
-
readFile: vi.fn(),
|
|
14
|
-
writeFile: vi.fn(),
|
|
15
|
-
resolve: vi.fn((path) => Promise.resolve(`/resolved/${path}`)),
|
|
16
|
-
}));
|
|
17
|
-
|
|
18
|
-
import { readFile, resolve } from "../../utils/file-utils";
|
|
19
|
-
import type { ApiClient } from "../../api";
|
|
20
|
-
|
|
21
|
-
const mockReadFile = vi.mocked(readFile);
|
|
22
|
-
const mockResolve = vi.mocked(resolve);
|
|
23
|
-
const mockResolveAppKeys = vi.fn();
|
|
24
|
-
|
|
25
|
-
describe("manifestPlugin", () => {
|
|
26
|
-
const mockManifest = {
|
|
27
|
-
apps: {
|
|
28
|
-
slack: {
|
|
29
|
-
implementationName: "SlackCLIAPI",
|
|
30
|
-
version: "1.21.1",
|
|
31
|
-
},
|
|
32
|
-
"google-sheets": {
|
|
33
|
-
implementationName: "GoogleSheetsCLIAPI",
|
|
34
|
-
version: "2.0.0",
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const mockManifestContent = JSON.stringify(mockManifest);
|
|
40
|
-
|
|
41
|
-
let mockApiClient: ApiClient;
|
|
42
|
-
let mockSdk: any;
|
|
43
|
-
|
|
44
|
-
beforeEach(() => {
|
|
45
|
-
vi.clearAllMocks();
|
|
46
|
-
vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
47
|
-
|
|
48
|
-
mockApiClient = {
|
|
49
|
-
get: vi.fn().mockImplementation((url: string, options?: any) => {
|
|
50
|
-
if (url === "/api/v4/implementations/") {
|
|
51
|
-
// Mock for manifest entries (versioned)
|
|
52
|
-
return Promise.resolve({
|
|
53
|
-
count: 1,
|
|
54
|
-
next: null,
|
|
55
|
-
previous: null,
|
|
56
|
-
results: [
|
|
57
|
-
{
|
|
58
|
-
selected_api: "SlackCLIAPI@1.29.0",
|
|
59
|
-
app_id: null,
|
|
60
|
-
service_id: null,
|
|
61
|
-
auth_type: "oauth",
|
|
62
|
-
auth_fields: [
|
|
63
|
-
{
|
|
64
|
-
key: "access_token",
|
|
65
|
-
required: true,
|
|
66
|
-
type: "unicode",
|
|
67
|
-
computed: true,
|
|
68
|
-
},
|
|
69
|
-
],
|
|
70
|
-
is_deprecated: false,
|
|
71
|
-
is_private_only: false,
|
|
72
|
-
is_invite_only: false,
|
|
73
|
-
is_beta: false,
|
|
74
|
-
is_premium: false,
|
|
75
|
-
is_hidden: false,
|
|
76
|
-
name: "Slack (1.29.0)",
|
|
77
|
-
name_clean: "Slack",
|
|
78
|
-
version: "1.29.0",
|
|
79
|
-
slug: null,
|
|
80
|
-
images: {
|
|
81
|
-
url_16x16:
|
|
82
|
-
"https://zapier-images.imgix.net/storage/services/6cf3f5a461feadfba7abc93c4c395b33_2.png?auto=format%2Ccompress&fit=crop&h=16&ixlib=python-3.0.0&q=50&w=16",
|
|
83
|
-
url_32x32:
|
|
84
|
-
"https://zapier-images.imgix.net/storage/services/6cf3f5a461feadfba7abc93c4c395b33_2.png?auto=format%2Ccompress&fit=crop&h=32&ixlib=python-3.0.0&q=50&w=32",
|
|
85
|
-
url_64x64:
|
|
86
|
-
"https://zapier-images.imgix.net/storage/services/6cf3f5a461feadfba7abc93c4c395b33_2.png?auto=format%2Ccompress&fit=crop&h=64&ixlib=python-3.0.0&q=50&w=64",
|
|
87
|
-
url_128x128:
|
|
88
|
-
"https://zapier-images.imgix.net/storage/services/6cf3f5a461feadfba7abc93c4c395b33_2.png?auto=format%2Ccompress&fit=crop&h=128&ixlib=python-3.0.0&q=50&w=128",
|
|
89
|
-
},
|
|
90
|
-
primary_color: null,
|
|
91
|
-
secondary_color: null,
|
|
92
|
-
classification: "third-party",
|
|
93
|
-
current_implementation: "SlackCLIAPI@1.30.0",
|
|
94
|
-
is_adoptable: true,
|
|
95
|
-
is_usable: true,
|
|
96
|
-
update_cta_level: "info",
|
|
97
|
-
update_cta_message:
|
|
98
|
-
"This version is legacy. Consider updating to the latest version for better support.",
|
|
99
|
-
badges: [
|
|
100
|
-
{
|
|
101
|
-
label: "Legacy",
|
|
102
|
-
color: "primary",
|
|
103
|
-
tooltip_markdown:
|
|
104
|
-
"This version is legacy. Consider updating to the latest version for better support.",
|
|
105
|
-
},
|
|
106
|
-
],
|
|
107
|
-
},
|
|
108
|
-
],
|
|
109
|
-
});
|
|
110
|
-
} else if (url === "/api/v4/implementations-meta/lookup/") {
|
|
111
|
-
// Mock for implementations-meta/lookup fallback
|
|
112
|
-
const searchParams = options?.searchParams || {};
|
|
113
|
-
|
|
114
|
-
// Check if we're looking for a nonexistent app
|
|
115
|
-
if (
|
|
116
|
-
searchParams.slugs?.includes("nonexistent") ||
|
|
117
|
-
searchParams.selected_apis?.includes("nonexistent")
|
|
118
|
-
) {
|
|
119
|
-
return Promise.resolve({
|
|
120
|
-
count: 0,
|
|
121
|
-
next: null,
|
|
122
|
-
previous: null,
|
|
123
|
-
results: [],
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Return successful response for known apps (like slack)
|
|
128
|
-
return Promise.resolve({
|
|
129
|
-
count: 1,
|
|
130
|
-
next: null,
|
|
131
|
-
previous: null,
|
|
132
|
-
results: [
|
|
133
|
-
{
|
|
134
|
-
id: "SlackCLIAPI@1.30.0",
|
|
135
|
-
name: "Slack",
|
|
136
|
-
slug: "slack",
|
|
137
|
-
images: {},
|
|
138
|
-
},
|
|
139
|
-
],
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
return Promise.resolve({ count: 0, results: [] });
|
|
143
|
-
}),
|
|
144
|
-
} as Partial<ApiClient> as ApiClient;
|
|
145
|
-
|
|
146
|
-
mockSdk = {
|
|
147
|
-
listApps: vi.fn().mockReturnValue({
|
|
148
|
-
items: vi.fn().mockReturnValue(
|
|
149
|
-
[
|
|
150
|
-
{
|
|
151
|
-
title: "Slack",
|
|
152
|
-
key: "slack",
|
|
153
|
-
current_implementation_id: "SlackCLIAPI@1.30.0",
|
|
154
|
-
description: "Team communication platform",
|
|
155
|
-
},
|
|
156
|
-
][Symbol.iterator](),
|
|
157
|
-
),
|
|
158
|
-
}),
|
|
159
|
-
};
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
afterEach(() => {
|
|
163
|
-
vi.restoreAllMocks();
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
const apiPlugin = () => ({
|
|
167
|
-
context: {
|
|
168
|
-
api: mockApiClient,
|
|
169
|
-
},
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
const listAppsMockPlugin = () => ({
|
|
173
|
-
listApps: mockSdk.listApps,
|
|
174
|
-
context: {
|
|
175
|
-
meta: {
|
|
176
|
-
listApps: {
|
|
177
|
-
inputSchema: {} as any,
|
|
178
|
-
},
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
function createTestSdk(options: any = {}) {
|
|
184
|
-
return createSdk(options).addPlugin(apiPlugin).addPlugin(manifestPlugin);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
describe("plugin initialization", () => {
|
|
188
|
-
it("should provide helper functions with direct manifest", () => {
|
|
189
|
-
const sdk = createTestSdk({ manifest: mockManifest });
|
|
190
|
-
const context = sdk.getContext();
|
|
191
|
-
|
|
192
|
-
expect(context.getVersionedImplementationId).toBeInstanceOf(Function);
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
it("should provide helper functions with manifestPath", async () => {
|
|
196
|
-
mockReadFile.mockResolvedValue(mockManifestContent);
|
|
197
|
-
|
|
198
|
-
const sdk = createTestSdk({ manifestPath: "manifest.json" });
|
|
199
|
-
const context = sdk.getContext();
|
|
200
|
-
|
|
201
|
-
expect(context.getVersionedImplementationId).toBeInstanceOf(Function);
|
|
202
|
-
|
|
203
|
-
// Verify file operations happen when functions are called
|
|
204
|
-
await context.getVersionedImplementationId("slack");
|
|
205
|
-
expect(mockResolve).toHaveBeenCalledWith("manifest.json");
|
|
206
|
-
expect(mockReadFile).toHaveBeenCalledWith("/resolved/manifest.json");
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it("should provide helper functions when no manifest or path provided", () => {
|
|
210
|
-
const sdk = createTestSdk();
|
|
211
|
-
const context = sdk.getContext();
|
|
212
|
-
|
|
213
|
-
expect(context.getVersionedImplementationId).toBeInstanceOf(Function);
|
|
214
|
-
|
|
215
|
-
// Manifest functions are available even when no manifest is provided
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
it("should prioritize direct manifest over manifestPath", () => {
|
|
219
|
-
mockReadFile.mockResolvedValue(
|
|
220
|
-
'{"apps": {"other": {"implementationName": "Other", "version": "1.0.0"}}}',
|
|
221
|
-
);
|
|
222
|
-
|
|
223
|
-
createTestSdk({
|
|
224
|
-
manifest: mockManifest,
|
|
225
|
-
manifestPath: "manifest.json",
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
// Verify that direct manifest is used and file loading is not needed
|
|
229
|
-
expect(mockReadFile).not.toHaveBeenCalled();
|
|
230
|
-
});
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
describe("getVersionedImplementationId function", () => {
|
|
234
|
-
it("should return versioned implementation ID when app exists in manifest", async () => {
|
|
235
|
-
const sdk = createTestSdk({ manifest: mockManifest });
|
|
236
|
-
const context = sdk.getContext();
|
|
237
|
-
|
|
238
|
-
const result = await context.getVersionedImplementationId("slack");
|
|
239
|
-
expect(result).toBe("SlackCLIAPI@1.21.1");
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
it("should fetch and return versioned implementation ID when app not in manifest", async () => {
|
|
243
|
-
const sdk = createTestSdk();
|
|
244
|
-
const context = sdk.getContext();
|
|
245
|
-
|
|
246
|
-
const result = await context.getVersionedImplementationId("slack");
|
|
247
|
-
expect(result).toBe("SlackCLIAPI@1.30.0");
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
it("should return null when app does not exist", async () => {
|
|
251
|
-
mockSdk.listApps = vi.fn().mockReturnValue({
|
|
252
|
-
items: vi.fn().mockReturnValue([][Symbol.iterator]()),
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
const sdk = createTestSdk();
|
|
256
|
-
const context = sdk.getContext();
|
|
257
|
-
|
|
258
|
-
const result = await context.getVersionedImplementationId("nonexistent");
|
|
259
|
-
expect(result).toBeNull();
|
|
260
|
-
});
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
describe("manifest parsing", () => {
|
|
264
|
-
it("should parse valid manifest content", () => {
|
|
265
|
-
createTestSdk({ manifest: mockManifest });
|
|
266
|
-
|
|
267
|
-
// Verify manifest is parsed correctly for other functions to use
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
it("should handle manifest with missing version", () => {
|
|
271
|
-
const manifestWithoutVersion: Manifest = {
|
|
272
|
-
apps: {
|
|
273
|
-
slack: {
|
|
274
|
-
implementationName: "SlackCLIAPI",
|
|
275
|
-
},
|
|
276
|
-
},
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
createTestSdk({ manifest: manifestWithoutVersion });
|
|
280
|
-
|
|
281
|
-
// Verify manifest with missing version is handled correctly
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it("should handle empty manifest", () => {
|
|
285
|
-
createTestSdk({ manifest: {} });
|
|
286
|
-
|
|
287
|
-
// Verify empty manifest is handled correctly
|
|
288
|
-
});
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
describe("file loading", () => {
|
|
292
|
-
it("should load manifest from file successfully", async () => {
|
|
293
|
-
mockReadFile.mockResolvedValue(mockManifestContent);
|
|
294
|
-
|
|
295
|
-
const sdk = createTestSdk({ manifestPath: "manifest.json" });
|
|
296
|
-
const context = sdk.getContext();
|
|
297
|
-
|
|
298
|
-
// Verify that file operations happen when functions are called
|
|
299
|
-
await context.getVersionedImplementationId("slack");
|
|
300
|
-
expect(mockResolve).toHaveBeenCalledWith("manifest.json");
|
|
301
|
-
expect(mockReadFile).toHaveBeenCalledWith("/resolved/manifest.json");
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
it("should handle file read errors gracefully", async () => {
|
|
305
|
-
mockReadFile.mockRejectedValue(new Error("File not found"));
|
|
306
|
-
|
|
307
|
-
const sdk = createTestSdk({ manifestPath: "nonexistent.json" });
|
|
308
|
-
const context = sdk.getContext();
|
|
309
|
-
|
|
310
|
-
// Trigger file loading by calling a function
|
|
311
|
-
await context.getVersionedImplementationId("slack");
|
|
312
|
-
|
|
313
|
-
// Verify file loading errors are handled gracefully
|
|
314
|
-
expect(console.warn).toHaveBeenCalledWith(
|
|
315
|
-
expect.stringContaining(
|
|
316
|
-
"Failed to read manifest from nonexistent.json",
|
|
317
|
-
),
|
|
318
|
-
);
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
it("should handle invalid JSON gracefully", async () => {
|
|
322
|
-
mockReadFile.mockResolvedValue("invalid json content");
|
|
323
|
-
|
|
324
|
-
const sdk = createTestSdk({ manifestPath: "invalid.json" });
|
|
325
|
-
const context = sdk.getContext();
|
|
326
|
-
|
|
327
|
-
// Trigger file loading by calling a function
|
|
328
|
-
await context.getVersionedImplementationId("slack");
|
|
329
|
-
|
|
330
|
-
// Verify JSON parsing errors are handled gracefully
|
|
331
|
-
expect(console.warn).toHaveBeenCalledWith(
|
|
332
|
-
expect.stringContaining(
|
|
333
|
-
"Failed to parse manifest from /resolved/invalid.json",
|
|
334
|
-
),
|
|
335
|
-
expect.any(SyntaxError),
|
|
336
|
-
);
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
it("should handle JSON without apps property", () => {
|
|
340
|
-
mockReadFile.mockResolvedValue('{"other": "data"}');
|
|
341
|
-
|
|
342
|
-
createTestSdk({ manifestPath: "no-apps.json" });
|
|
343
|
-
|
|
344
|
-
// Verify missing apps property is handled correctly
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
it("should handle JSON with invalid apps format", () => {
|
|
348
|
-
mockReadFile.mockResolvedValue('{"apps": "not an object"}');
|
|
349
|
-
|
|
350
|
-
createTestSdk({ manifestPath: "invalid-apps.json" });
|
|
351
|
-
|
|
352
|
-
// Verify invalid apps format is handled correctly
|
|
353
|
-
});
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
describe("integration with SDK", () => {
|
|
357
|
-
it("should work with createSdk", async () => {
|
|
358
|
-
const sdk = createSdk({ manifest: mockManifest })
|
|
359
|
-
.addPlugin(apiPlugin)
|
|
360
|
-
.addPlugin(listAppsMockPlugin)
|
|
361
|
-
.addPlugin(manifestPlugin);
|
|
362
|
-
const context = sdk.getContext();
|
|
363
|
-
|
|
364
|
-
// Verify that the manifest data is used correctly by other functions
|
|
365
|
-
|
|
366
|
-
const versionedId = await context.getVersionedImplementationId("slack");
|
|
367
|
-
expect(versionedId).toBe("SlackCLIAPI@1.21.1");
|
|
368
|
-
});
|
|
369
|
-
});
|
|
370
|
-
|
|
371
|
-
describe("findManifestEntry function", () => {
|
|
372
|
-
it("should find entry by direct key match", () => {
|
|
373
|
-
const manifest = {
|
|
374
|
-
apps: {
|
|
375
|
-
slack: { implementationName: "SlackCLIAPI", version: "1.21.1" },
|
|
376
|
-
gmail: { implementationName: "GmailCLIAPI", version: "2.0.0" },
|
|
377
|
-
},
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
const result = findManifestEntry({ appKey: "slack", manifest });
|
|
381
|
-
|
|
382
|
-
expect(result).toEqual([
|
|
383
|
-
"slack",
|
|
384
|
-
{ implementationName: "SlackCLIAPI", version: "1.21.1" },
|
|
385
|
-
]);
|
|
386
|
-
});
|
|
387
|
-
|
|
388
|
-
it("should find entry by implementation name match", () => {
|
|
389
|
-
const manifest = {
|
|
390
|
-
apps: {
|
|
391
|
-
SlackCLIAPI: { implementationName: "SlackCLIAPI", version: "1.21.1" },
|
|
392
|
-
GmailCLIAPI: { implementationName: "GmailCLIAPI", version: "2.0.0" },
|
|
393
|
-
},
|
|
394
|
-
};
|
|
395
|
-
|
|
396
|
-
const result = findManifestEntry({ appKey: "SlackCLIAPI", manifest });
|
|
397
|
-
|
|
398
|
-
expect(result).toEqual([
|
|
399
|
-
"SlackCLIAPI",
|
|
400
|
-
{ implementationName: "SlackCLIAPI", version: "1.21.1" },
|
|
401
|
-
]);
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
it("should find existing key when searching by implementation name", () => {
|
|
405
|
-
const manifest = {
|
|
406
|
-
apps: {
|
|
407
|
-
SlackCLIAPI: { implementationName: "SlackCLIAPI", version: "1.21.1" },
|
|
408
|
-
},
|
|
409
|
-
};
|
|
410
|
-
|
|
411
|
-
// This is the key test: searching by implementation name should find existing entry
|
|
412
|
-
const result = findManifestEntry({ appKey: "SlackCLIAPI", manifest });
|
|
413
|
-
|
|
414
|
-
expect(result).toEqual([
|
|
415
|
-
"SlackCLIAPI",
|
|
416
|
-
{ implementationName: "SlackCLIAPI", version: "1.21.1" },
|
|
417
|
-
]);
|
|
418
|
-
});
|
|
419
|
-
|
|
420
|
-
it("should return null when no match found", () => {
|
|
421
|
-
const manifest = {
|
|
422
|
-
apps: {
|
|
423
|
-
gmail: { implementationName: "GmailCLIAPI", version: "2.0.0" },
|
|
424
|
-
},
|
|
425
|
-
};
|
|
426
|
-
|
|
427
|
-
const result = findManifestEntry({ appKey: "slack", manifest });
|
|
428
|
-
|
|
429
|
-
expect(result).toBeNull();
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
it("should handle snake-cased slugs", () => {
|
|
433
|
-
const manifest = {
|
|
434
|
-
apps: {
|
|
435
|
-
"google-sheets": {
|
|
436
|
-
implementationName: "GoogleSheetsCLIAPI",
|
|
437
|
-
version: "1.0.0",
|
|
438
|
-
},
|
|
439
|
-
},
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
const result = findManifestEntry({ appKey: "google_sheets", manifest });
|
|
443
|
-
|
|
444
|
-
expect(result).toEqual([
|
|
445
|
-
"google-sheets",
|
|
446
|
-
{ implementationName: "GoogleSheetsCLIAPI", version: "1.0.0" },
|
|
447
|
-
]);
|
|
448
|
-
});
|
|
449
|
-
|
|
450
|
-
it("should NOT find entry when searching slug against implementation name key (current limitation)", () => {
|
|
451
|
-
const manifest = {
|
|
452
|
-
apps: {
|
|
453
|
-
SlackCLIAPI: { implementationName: "SlackCLIAPI", version: "1.21.1" },
|
|
454
|
-
},
|
|
455
|
-
};
|
|
456
|
-
|
|
457
|
-
// This will fail - we search by "slack" but can't find "SlackCLIAPI" entry
|
|
458
|
-
// This is the core issue we need to solve
|
|
459
|
-
const result = findManifestEntry({ appKey: "slack", manifest });
|
|
460
|
-
|
|
461
|
-
expect(result).toBeNull(); // Current behavior - doesn't find it
|
|
462
|
-
// We need to fix this so it CAN find existing implementation name entries
|
|
463
|
-
});
|
|
464
|
-
});
|
|
465
|
-
|
|
466
|
-
describe("updateManifestEntry with slug-to-implementation matching", () => {
|
|
467
|
-
it("should find existing implementation name entry when input is slug", async () => {
|
|
468
|
-
// Mock existing manifest with implementation name as key
|
|
469
|
-
mockReadFile.mockResolvedValue(
|
|
470
|
-
JSON.stringify({
|
|
471
|
-
apps: {
|
|
472
|
-
SlackCLIAPI: {
|
|
473
|
-
implementationName: "SlackCLIAPI",
|
|
474
|
-
version: "1.21.1",
|
|
475
|
-
},
|
|
476
|
-
},
|
|
477
|
-
}),
|
|
478
|
-
);
|
|
479
|
-
|
|
480
|
-
// Mock resolveAppKeys to resolve "slack" to "SlackCLIAPI"
|
|
481
|
-
mockResolveAppKeys.mockResolvedValue([
|
|
482
|
-
{
|
|
483
|
-
slug: "slack",
|
|
484
|
-
implementationName: "SlackCLIAPI",
|
|
485
|
-
version: "1.30.0",
|
|
486
|
-
lookupAppKey: "slack",
|
|
487
|
-
},
|
|
488
|
-
]);
|
|
489
|
-
|
|
490
|
-
const sdk = createTestSdk();
|
|
491
|
-
const context = sdk.getContext();
|
|
492
|
-
|
|
493
|
-
// This should now find the existing "SlackCLIAPI" entry
|
|
494
|
-
const [manifestKey] = await context.updateManifestEntry({
|
|
495
|
-
appKey: "slack", // Input is slug
|
|
496
|
-
entry: { implementationName: "SlackCLIAPI", version: "1.30.0" },
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
// Should return the existing key, not create a new one
|
|
500
|
-
expect(manifestKey).toBe("SlackCLIAPI");
|
|
501
|
-
});
|
|
502
|
-
});
|
|
503
|
-
|
|
504
|
-
describe("resolveAppKeys function", () => {
|
|
505
|
-
it("should resolve slug to manifest entry even when manifest uses implementation name as key", async () => {
|
|
506
|
-
const manifest = {
|
|
507
|
-
apps: {
|
|
508
|
-
SlackCLIAPI: { implementationName: "SlackCLIAPI", version: "1.21.1" },
|
|
509
|
-
},
|
|
510
|
-
};
|
|
511
|
-
|
|
512
|
-
// Mock API to return slack app data when looking up "slack"
|
|
513
|
-
mockApiClient.get = vi.fn().mockResolvedValue({
|
|
514
|
-
count: 1,
|
|
515
|
-
next: null,
|
|
516
|
-
previous: null,
|
|
517
|
-
results: [
|
|
518
|
-
{
|
|
519
|
-
id: "SlackCLIAPI@1.30.0",
|
|
520
|
-
name: "Slack",
|
|
521
|
-
slug: "slack",
|
|
522
|
-
key: "SlackCLIAPI", // This is the implementation name
|
|
523
|
-
version: "1.30.0",
|
|
524
|
-
},
|
|
525
|
-
],
|
|
526
|
-
});
|
|
527
|
-
|
|
528
|
-
// Test resolveAppKeys directly using the manifest plugin
|
|
529
|
-
const sdk = createSdk({ manifest })
|
|
530
|
-
.addPlugin(apiPlugin)
|
|
531
|
-
.addPlugin(manifestPlugin);
|
|
532
|
-
const context = sdk.getContext();
|
|
533
|
-
|
|
534
|
-
const resolved = await context.resolveAppKeys({ appKeys: ["slack"] });
|
|
535
|
-
|
|
536
|
-
// Should find the manifest entry and use its version (1.21.1) instead of latest (1.30.0)
|
|
537
|
-
expect(resolved).toHaveLength(1);
|
|
538
|
-
expect(resolved[0]).toEqual({
|
|
539
|
-
slug: "slack",
|
|
540
|
-
implementationName: "SlackCLIAPI",
|
|
541
|
-
version: "1.21.1", // Should use manifest version, not API version
|
|
542
|
-
lookupAppKey: "slack",
|
|
543
|
-
});
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
it("should fall back to API version when no manifest entry found", async () => {
|
|
547
|
-
const manifest = { apps: {} }; // Empty manifest
|
|
548
|
-
|
|
549
|
-
// Mock API to return slack app data
|
|
550
|
-
mockApiClient.get = vi.fn().mockResolvedValue({
|
|
551
|
-
count: 1,
|
|
552
|
-
next: null,
|
|
553
|
-
previous: null,
|
|
554
|
-
results: [
|
|
555
|
-
{
|
|
556
|
-
id: "SlackCLIAPI@1.30.0",
|
|
557
|
-
name: "Slack",
|
|
558
|
-
slug: "slack",
|
|
559
|
-
key: "SlackCLIAPI",
|
|
560
|
-
version: "1.30.0",
|
|
561
|
-
},
|
|
562
|
-
],
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
const sdk = createSdk({ manifest })
|
|
566
|
-
.addPlugin(apiPlugin)
|
|
567
|
-
.addPlugin(manifestPlugin);
|
|
568
|
-
const context = sdk.getContext();
|
|
569
|
-
|
|
570
|
-
const resolved = await context.resolveAppKeys({ appKeys: ["slack"] });
|
|
571
|
-
|
|
572
|
-
// Should use API version since no manifest entry found
|
|
573
|
-
expect(resolved).toHaveLength(1);
|
|
574
|
-
expect(resolved[0]).toEqual({
|
|
575
|
-
slug: "slack",
|
|
576
|
-
implementationName: "SlackCLIAPI",
|
|
577
|
-
version: "1.30.0", // Should use API version
|
|
578
|
-
lookupAppKey: "slack",
|
|
579
|
-
});
|
|
580
|
-
});
|
|
581
|
-
|
|
582
|
-
it("should always use version from input when specified (slug@version)", async () => {
|
|
583
|
-
const manifest = {
|
|
584
|
-
apps: {
|
|
585
|
-
SlackCLIAPI: { implementationName: "SlackCLIAPI", version: "1.21.1" },
|
|
586
|
-
},
|
|
587
|
-
};
|
|
588
|
-
|
|
589
|
-
// Mock API to return slack app data
|
|
590
|
-
mockApiClient.get = vi.fn().mockResolvedValue({
|
|
591
|
-
count: 1,
|
|
592
|
-
next: null,
|
|
593
|
-
previous: null,
|
|
594
|
-
results: [
|
|
595
|
-
{
|
|
596
|
-
id: "SlackCLIAPI@1.30.0",
|
|
597
|
-
name: "Slack",
|
|
598
|
-
slug: "slack",
|
|
599
|
-
key: "SlackCLIAPI",
|
|
600
|
-
version: "1.30.0",
|
|
601
|
-
},
|
|
602
|
-
],
|
|
603
|
-
});
|
|
604
|
-
|
|
605
|
-
const sdk = createSdk({ manifest })
|
|
606
|
-
.addPlugin(apiPlugin)
|
|
607
|
-
.addPlugin(manifestPlugin);
|
|
608
|
-
const context = sdk.getContext();
|
|
609
|
-
|
|
610
|
-
// Input version should take precedence over both manifest (1.21.1) and API (1.30.0)
|
|
611
|
-
const resolved = await context.resolveAppKeys({
|
|
612
|
-
appKeys: ["slack@1.2.3"],
|
|
613
|
-
});
|
|
614
|
-
|
|
615
|
-
expect(resolved).toHaveLength(1);
|
|
616
|
-
expect(resolved[0]).toEqual({
|
|
617
|
-
slug: "slack",
|
|
618
|
-
implementationName: "SlackCLIAPI",
|
|
619
|
-
version: "1.2.3", // Should use input version, not manifest or API
|
|
620
|
-
lookupAppKey: "slack",
|
|
621
|
-
});
|
|
622
|
-
});
|
|
623
|
-
|
|
624
|
-
it("should always use version from input when specified (implementationName@version)", async () => {
|
|
625
|
-
const manifest = {
|
|
626
|
-
apps: {
|
|
627
|
-
SlackCLIAPI: { implementationName: "SlackCLIAPI", version: "1.21.1" },
|
|
628
|
-
},
|
|
629
|
-
};
|
|
630
|
-
|
|
631
|
-
const sdk = createSdk({ manifest })
|
|
632
|
-
.addPlugin(apiPlugin)
|
|
633
|
-
.addPlugin(manifestPlugin);
|
|
634
|
-
const context = sdk.getContext();
|
|
635
|
-
|
|
636
|
-
// Input version should take precedence over manifest version
|
|
637
|
-
const resolved = await context.resolveAppKeys({
|
|
638
|
-
appKeys: ["SlackCLIAPI@1.2.3"],
|
|
639
|
-
});
|
|
640
|
-
|
|
641
|
-
expect(resolved).toHaveLength(1);
|
|
642
|
-
expect(resolved[0]).toEqual({
|
|
643
|
-
implementationName: "SlackCLIAPI",
|
|
644
|
-
version: "1.2.3", // Should use input version, not manifest version
|
|
645
|
-
lookupAppKey: "SlackCLIAPI",
|
|
646
|
-
});
|
|
647
|
-
});
|
|
648
|
-
});
|
|
649
|
-
});
|
|
650
|
-
|
|
651
|
-
describe("readManifestFromFile", () => {
|
|
652
|
-
const mockManifestContent = JSON.stringify({
|
|
653
|
-
apps: {
|
|
654
|
-
slack: {
|
|
655
|
-
implementationName: "SlackCLIAPI",
|
|
656
|
-
version: "1.21.1",
|
|
657
|
-
},
|
|
658
|
-
"google-sheets": {
|
|
659
|
-
implementationName: "GoogleSheetsCLIAPI",
|
|
660
|
-
version: "2.0.0",
|
|
661
|
-
},
|
|
662
|
-
},
|
|
663
|
-
});
|
|
664
|
-
|
|
665
|
-
beforeEach(() => {
|
|
666
|
-
vi.clearAllMocks();
|
|
667
|
-
});
|
|
668
|
-
|
|
669
|
-
it("should read and parse manifest from file", async () => {
|
|
670
|
-
mockReadFile.mockResolvedValue(mockManifestContent);
|
|
671
|
-
|
|
672
|
-
const result = await readManifestFromFile("manifest.json");
|
|
673
|
-
|
|
674
|
-
expect(mockResolve).toHaveBeenCalledWith("manifest.json");
|
|
675
|
-
expect(mockReadFile).toHaveBeenCalledWith("/resolved/manifest.json");
|
|
676
|
-
expect(result).toEqual({
|
|
677
|
-
apps: {
|
|
678
|
-
slack: {
|
|
679
|
-
implementationName: "SlackCLIAPI",
|
|
680
|
-
version: "1.21.1",
|
|
681
|
-
},
|
|
682
|
-
"google-sheets": {
|
|
683
|
-
implementationName: "GoogleSheetsCLIAPI",
|
|
684
|
-
version: "2.0.0",
|
|
685
|
-
},
|
|
686
|
-
},
|
|
687
|
-
});
|
|
688
|
-
});
|
|
689
|
-
|
|
690
|
-
it("should handle file read errors", async () => {
|
|
691
|
-
mockReadFile.mockRejectedValue(new Error("File not found"));
|
|
692
|
-
|
|
693
|
-
const result = await readManifestFromFile("nonexistent.json");
|
|
694
|
-
|
|
695
|
-
expect(result).toBeNull();
|
|
696
|
-
});
|
|
697
|
-
|
|
698
|
-
it("should handle invalid JSON content", async () => {
|
|
699
|
-
mockReadFile.mockResolvedValue("invalid json");
|
|
700
|
-
|
|
701
|
-
const result = await readManifestFromFile("invalid.json");
|
|
702
|
-
|
|
703
|
-
expect(result).toBeNull();
|
|
704
|
-
});
|
|
705
|
-
|
|
706
|
-
describe("getPreferredManifestEntryKey", () => {
|
|
707
|
-
let mockApi: ApiClient;
|
|
708
|
-
|
|
709
|
-
beforeEach(() => {
|
|
710
|
-
mockApi = {
|
|
711
|
-
get: vi.fn(),
|
|
712
|
-
} as any;
|
|
713
|
-
});
|
|
714
|
-
|
|
715
|
-
it("should prefer slug when available", async () => {
|
|
716
|
-
const result = await getPreferredManifestEntryKey({
|
|
717
|
-
appKey: "slack",
|
|
718
|
-
api: mockApi,
|
|
719
|
-
});
|
|
720
|
-
|
|
721
|
-
expect(result).toBe("slack");
|
|
722
|
-
});
|
|
723
|
-
|
|
724
|
-
it("should look up slug for implementation name", async () => {
|
|
725
|
-
// Mock API response for implementation name lookup
|
|
726
|
-
mockApi.get = vi.fn().mockResolvedValueOnce({
|
|
727
|
-
results: [
|
|
728
|
-
{
|
|
729
|
-
key: "SlackCLIAPI",
|
|
730
|
-
slug: "slack",
|
|
731
|
-
version: "1.0.0",
|
|
732
|
-
current_implementation_id: "SlackCLIAPI@1.0.0",
|
|
733
|
-
},
|
|
734
|
-
],
|
|
735
|
-
next: null,
|
|
736
|
-
});
|
|
737
|
-
|
|
738
|
-
const result = await getPreferredManifestEntryKey({
|
|
739
|
-
appKey: "SlackCLIAPI",
|
|
740
|
-
api: mockApi,
|
|
741
|
-
});
|
|
742
|
-
|
|
743
|
-
expect(result).toBe("slack");
|
|
744
|
-
expect(mockApi.get).toHaveBeenCalledWith(
|
|
745
|
-
"/api/v4/implementations-meta/lookup/",
|
|
746
|
-
{
|
|
747
|
-
searchParams: { selected_apis: "SlackCLIAPI" },
|
|
748
|
-
},
|
|
749
|
-
);
|
|
750
|
-
});
|
|
751
|
-
|
|
752
|
-
it("should fall back to implementation name if slug lookup fails", async () => {
|
|
753
|
-
// Mock API to return empty results
|
|
754
|
-
mockApi.get = vi.fn().mockResolvedValueOnce({
|
|
755
|
-
results: [],
|
|
756
|
-
next: null,
|
|
757
|
-
});
|
|
758
|
-
|
|
759
|
-
const result = await getPreferredManifestEntryKey({
|
|
760
|
-
appKey: "SlackCLIAPI",
|
|
761
|
-
api: mockApi,
|
|
762
|
-
});
|
|
763
|
-
|
|
764
|
-
expect(result).toBe("SlackCLIAPI");
|
|
765
|
-
});
|
|
766
|
-
|
|
767
|
-
it("should fall back to original key if no slug or implementation name", async () => {
|
|
768
|
-
const result = await getPreferredManifestEntryKey({
|
|
769
|
-
appKey: "some-random-key",
|
|
770
|
-
api: mockApi,
|
|
771
|
-
});
|
|
772
|
-
|
|
773
|
-
expect(result).toBe("some-random-key");
|
|
774
|
-
});
|
|
775
|
-
});
|
|
776
|
-
});
|