@zapier/zapier-sdk-cli 0.16.1 → 0.16.3
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 +18 -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,679 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
-
import { buildManifestPlugin } from "./index";
|
|
3
|
-
import { BuildManifestSchema } from "./schemas";
|
|
4
|
-
import type {
|
|
5
|
-
AppItem,
|
|
6
|
-
Manifest,
|
|
7
|
-
UpdateManifestEntryOptions,
|
|
8
|
-
} from "@zapier/zapier-sdk";
|
|
9
|
-
import {
|
|
10
|
-
createSdk,
|
|
11
|
-
ZapierUnknownError,
|
|
12
|
-
ZapierValidationError,
|
|
13
|
-
} from "@zapier/zapier-sdk";
|
|
14
|
-
|
|
15
|
-
const mockSlackApp: AppItem = {
|
|
16
|
-
key: "SlackCLIAPI",
|
|
17
|
-
slug: "slack",
|
|
18
|
-
title: "Slack",
|
|
19
|
-
description: "Slack is a collaboration hub",
|
|
20
|
-
version: "1.30.0",
|
|
21
|
-
implementation_id: "SlackCLIAPI@1.30.0",
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const mockGmailApp: AppItem = {
|
|
25
|
-
key: "GmailCLIAPI",
|
|
26
|
-
slug: "gmail",
|
|
27
|
-
title: "Gmail",
|
|
28
|
-
description: "Gmail is an email service",
|
|
29
|
-
version: "2.5.0",
|
|
30
|
-
implementation_id: "GmailCLIAPI@2.5.0",
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const mockAppWithoutVersion: AppItem = {
|
|
34
|
-
key: "BrokenAPI",
|
|
35
|
-
slug: "broken",
|
|
36
|
-
title: "Broken App",
|
|
37
|
-
description: "An app without version",
|
|
38
|
-
version: undefined,
|
|
39
|
-
implementation_id: "BrokenAPI",
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
describe("buildManifest plugin", () => {
|
|
43
|
-
let mockUpdateManifestEntry: unknown;
|
|
44
|
-
let mockListAppsItems: unknown;
|
|
45
|
-
|
|
46
|
-
beforeEach(() => {
|
|
47
|
-
vi.clearAllMocks();
|
|
48
|
-
|
|
49
|
-
mockUpdateManifestEntry = vi
|
|
50
|
-
.fn()
|
|
51
|
-
.mockImplementation(async (options: UpdateManifestEntryOptions) => {
|
|
52
|
-
const manifestKey = options.entry.implementationName;
|
|
53
|
-
const updatedManifest: Manifest = {
|
|
54
|
-
apps: {
|
|
55
|
-
...options.manifest?.apps,
|
|
56
|
-
[manifestKey]: options.entry,
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
return {
|
|
60
|
-
key: manifestKey,
|
|
61
|
-
entry: options.entry,
|
|
62
|
-
manifest: updatedManifest,
|
|
63
|
-
};
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
mockListAppsItems = vi.fn();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
function createTestSdk(apps: AppItem[] = [mockSlackApp, mockGmailApp]) {
|
|
70
|
-
// Mock async iterator for listApps
|
|
71
|
-
mockListAppsItems.mockReturnValue({
|
|
72
|
-
async *[Symbol.asyncIterator]() {
|
|
73
|
-
for (const app of apps) {
|
|
74
|
-
yield app;
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
return createSdk()
|
|
80
|
-
.addPlugin(() => ({
|
|
81
|
-
context: {
|
|
82
|
-
updateManifestEntry: mockUpdateManifestEntry,
|
|
83
|
-
addActionEntry: vi
|
|
84
|
-
.fn()
|
|
85
|
-
.mockResolvedValue(["test-key", {}, { apps: {} }]),
|
|
86
|
-
findActionEntry: vi.fn().mockResolvedValue({
|
|
87
|
-
key: "test-key",
|
|
88
|
-
entry: {},
|
|
89
|
-
manifest: { apps: {} },
|
|
90
|
-
}),
|
|
91
|
-
hasActionEntry: vi.fn().mockResolvedValue(true),
|
|
92
|
-
listActionEntries: vi
|
|
93
|
-
.fn()
|
|
94
|
-
.mockResolvedValue([
|
|
95
|
-
[
|
|
96
|
-
"test-key",
|
|
97
|
-
{ key: "test-key", entry: {}, manifest: { apps: {} } },
|
|
98
|
-
],
|
|
99
|
-
]),
|
|
100
|
-
deleteActionEntry: vi.fn().mockResolvedValue({ apps: {} }),
|
|
101
|
-
findManifestEntry: vi
|
|
102
|
-
.fn()
|
|
103
|
-
.mockResolvedValue([
|
|
104
|
-
"test-key",
|
|
105
|
-
{ key: "test-key", entry: {}, manifest: { apps: {} } },
|
|
106
|
-
]),
|
|
107
|
-
readManifestFromFile: vi.fn().mockResolvedValue({ apps: {} }),
|
|
108
|
-
},
|
|
109
|
-
}))
|
|
110
|
-
.addPlugin(() => ({
|
|
111
|
-
listApps: vi.fn().mockReturnValue({
|
|
112
|
-
items: mockListAppsItems,
|
|
113
|
-
}),
|
|
114
|
-
}))
|
|
115
|
-
.addPlugin(buildManifestPlugin);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
describe("schema validation", () => {
|
|
119
|
-
it("should accept valid options with skipWrite true", () => {
|
|
120
|
-
const result = BuildManifestSchema.safeParse({
|
|
121
|
-
appKeys: ["slack", "gmail"],
|
|
122
|
-
skipWrite: true,
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
expect(result.success).toBe(true);
|
|
126
|
-
if (result.success) {
|
|
127
|
-
expect(result.data.skipWrite).toBe(true);
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it("should accept valid options with skipWrite false and configPath", () => {
|
|
132
|
-
const result = BuildManifestSchema.safeParse({
|
|
133
|
-
appKeys: ["slack"],
|
|
134
|
-
skipWrite: false,
|
|
135
|
-
configPath: "/path/to/.zapierrc",
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
expect(result.success).toBe(true);
|
|
139
|
-
if (result.success) {
|
|
140
|
-
expect(result.data.skipWrite).toBe(false);
|
|
141
|
-
expect(result.data.configPath).toBe("/path/to/.zapierrc");
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it("should accept options without skipWrite (defaults to false)", () => {
|
|
146
|
-
const result = BuildManifestSchema.safeParse({
|
|
147
|
-
appKeys: ["slack"],
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
expect(result.success).toBe(true);
|
|
151
|
-
if (result.success) {
|
|
152
|
-
expect(result.data.skipWrite).toBeUndefined();
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it("should require at least one appKey", () => {
|
|
157
|
-
const result = BuildManifestSchema.safeParse({
|
|
158
|
-
appKeys: [],
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
expect(result.success).toBe(false);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it("should reject empty string appKeys", () => {
|
|
165
|
-
const result = BuildManifestSchema.safeParse({
|
|
166
|
-
appKeys: ["slack", ""],
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
expect(result.success).toBe(false);
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
it("should reject non-array appKeys", () => {
|
|
173
|
-
const result = BuildManifestSchema.safeParse({
|
|
174
|
-
appKeys: "slack",
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
expect(result.success).toBe(false);
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
describe("manifest building with skipWrite: true", () => {
|
|
182
|
-
it("should build manifest entries without writing to disk", async () => {
|
|
183
|
-
const sdk = createTestSdk();
|
|
184
|
-
|
|
185
|
-
const result = await sdk.buildManifest({
|
|
186
|
-
appKeys: ["slack", "gmail"],
|
|
187
|
-
skipWrite: true,
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
// Should still call updateManifestEntry with skipWrite: true
|
|
191
|
-
expect(mockUpdateManifestEntry).toHaveBeenCalledTimes(2);
|
|
192
|
-
expect(mockUpdateManifestEntry).toHaveBeenCalledWith(
|
|
193
|
-
expect.objectContaining({
|
|
194
|
-
skipWrite: true,
|
|
195
|
-
}),
|
|
196
|
-
);
|
|
197
|
-
|
|
198
|
-
// Should return manifest with entries
|
|
199
|
-
expect(result.manifest).toBeDefined();
|
|
200
|
-
expect(result.manifest?.apps).toBeDefined();
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
it("should process apps and create manifest entries", async () => {
|
|
204
|
-
const sdk = createTestSdk();
|
|
205
|
-
|
|
206
|
-
const result = await sdk.buildManifest({
|
|
207
|
-
appKeys: ["slack"],
|
|
208
|
-
skipWrite: true,
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
expect(result.manifest?.apps).toBeDefined();
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
it("should return empty result when no apps found", async () => {
|
|
215
|
-
const sdk = createTestSdk([]);
|
|
216
|
-
|
|
217
|
-
const result = await sdk.buildManifest({
|
|
218
|
-
appKeys: ["nonexistent"],
|
|
219
|
-
skipWrite: true,
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
expect(result.manifest).toBeUndefined();
|
|
223
|
-
});
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
describe("manifest building with skipWrite: false", () => {
|
|
227
|
-
it("should build manifest and write to disk", async () => {
|
|
228
|
-
const sdk = createTestSdk();
|
|
229
|
-
|
|
230
|
-
const result = await sdk.buildManifest({
|
|
231
|
-
appKeys: ["slack", "gmail"],
|
|
232
|
-
skipWrite: false,
|
|
233
|
-
configPath: "/path/to/.zapierrc",
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
// Should call updateManifestEntry for each app
|
|
237
|
-
expect(mockUpdateManifestEntry).toHaveBeenCalledTimes(2);
|
|
238
|
-
|
|
239
|
-
// First call for slack
|
|
240
|
-
expect(mockUpdateManifestEntry).toHaveBeenNthCalledWith(1, {
|
|
241
|
-
appKey: "SlackCLIAPI",
|
|
242
|
-
entry: {
|
|
243
|
-
implementationName: "SlackCLIAPI",
|
|
244
|
-
version: "1.30.0",
|
|
245
|
-
},
|
|
246
|
-
configPath: "/path/to/.zapierrc",
|
|
247
|
-
skipWrite: false,
|
|
248
|
-
manifest: undefined,
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
// Second call for gmail (with manifest from first call)
|
|
252
|
-
expect(mockUpdateManifestEntry).toHaveBeenNthCalledWith(2, {
|
|
253
|
-
appKey: "GmailCLIAPI",
|
|
254
|
-
entry: {
|
|
255
|
-
implementationName: "GmailCLIAPI",
|
|
256
|
-
version: "2.5.0",
|
|
257
|
-
},
|
|
258
|
-
configPath: "/path/to/.zapierrc",
|
|
259
|
-
skipWrite: false,
|
|
260
|
-
manifest: {
|
|
261
|
-
apps: {
|
|
262
|
-
SlackCLIAPI: {
|
|
263
|
-
implementationName: "SlackCLIAPI",
|
|
264
|
-
version: "1.30.0",
|
|
265
|
-
},
|
|
266
|
-
},
|
|
267
|
-
},
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
// Should return updated manifest
|
|
271
|
-
expect(result.manifest).toBeDefined();
|
|
272
|
-
expect(result.manifest?.apps?.SlackCLIAPI).toEqual({
|
|
273
|
-
implementationName: "SlackCLIAPI",
|
|
274
|
-
version: "1.30.0",
|
|
275
|
-
});
|
|
276
|
-
expect(result.manifest?.apps?.GmailCLIAPI).toEqual({
|
|
277
|
-
implementationName: "GmailCLIAPI",
|
|
278
|
-
version: "2.5.0",
|
|
279
|
-
});
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
it("should accumulate manifest entries across multiple apps", async () => {
|
|
283
|
-
const sdk = createTestSdk();
|
|
284
|
-
|
|
285
|
-
const result = await sdk.buildManifest({
|
|
286
|
-
appKeys: ["slack", "gmail"],
|
|
287
|
-
skipWrite: false,
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
// Verify that the second call received the manifest from the first call
|
|
291
|
-
const secondCallArgs = mockUpdateManifestEntry.mock.calls[1][0];
|
|
292
|
-
expect(secondCallArgs.manifest).toEqual({
|
|
293
|
-
apps: {
|
|
294
|
-
SlackCLIAPI: {
|
|
295
|
-
implementationName: "SlackCLIAPI",
|
|
296
|
-
version: "1.30.0",
|
|
297
|
-
},
|
|
298
|
-
},
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
// Final result should have both apps
|
|
302
|
-
expect(Object.keys(result.manifest?.apps || {})).toHaveLength(2);
|
|
303
|
-
});
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
describe("progress events", () => {
|
|
307
|
-
it("should emit apps_lookup_start event", async () => {
|
|
308
|
-
const sdk = createTestSdk();
|
|
309
|
-
const onProgress = vi.fn();
|
|
310
|
-
|
|
311
|
-
await sdk.buildManifest({
|
|
312
|
-
appKeys: ["slack", "gmail"],
|
|
313
|
-
skipWrite: true,
|
|
314
|
-
onProgress,
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
expect(onProgress).toHaveBeenCalledWith({
|
|
318
|
-
type: "apps_lookup_start",
|
|
319
|
-
count: 2,
|
|
320
|
-
});
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
it("should emit app_found event for each app", async () => {
|
|
324
|
-
const sdk = createTestSdk();
|
|
325
|
-
const onProgress = vi.fn();
|
|
326
|
-
|
|
327
|
-
await sdk.buildManifest({
|
|
328
|
-
appKeys: ["slack", "gmail"],
|
|
329
|
-
skipWrite: true,
|
|
330
|
-
onProgress,
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
expect(onProgress).toHaveBeenCalledWith({
|
|
334
|
-
type: "app_found",
|
|
335
|
-
app: mockSlackApp,
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
expect(onProgress).toHaveBeenCalledWith({
|
|
339
|
-
type: "app_found",
|
|
340
|
-
app: mockGmailApp,
|
|
341
|
-
});
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
it("should emit apps_lookup_complete event", async () => {
|
|
345
|
-
const sdk = createTestSdk();
|
|
346
|
-
const onProgress = vi.fn();
|
|
347
|
-
|
|
348
|
-
await sdk.buildManifest({
|
|
349
|
-
appKeys: ["slack", "gmail"],
|
|
350
|
-
skipWrite: true,
|
|
351
|
-
onProgress,
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
expect(onProgress).toHaveBeenCalledWith({
|
|
355
|
-
type: "apps_lookup_complete",
|
|
356
|
-
count: 2,
|
|
357
|
-
});
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
it("should emit app_processing_start event for each app", async () => {
|
|
361
|
-
const sdk = createTestSdk();
|
|
362
|
-
const onProgress = vi.fn();
|
|
363
|
-
|
|
364
|
-
await sdk.buildManifest({
|
|
365
|
-
appKeys: ["slack"],
|
|
366
|
-
skipWrite: true,
|
|
367
|
-
onProgress,
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
expect(onProgress).toHaveBeenCalledWith({
|
|
371
|
-
type: "app_processing_start",
|
|
372
|
-
appKey: "SlackCLIAPI",
|
|
373
|
-
slug: "slack",
|
|
374
|
-
});
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
it("should emit manifest_entry_built event", async () => {
|
|
378
|
-
const sdk = createTestSdk();
|
|
379
|
-
const onProgress = vi.fn();
|
|
380
|
-
|
|
381
|
-
await sdk.buildManifest({
|
|
382
|
-
appKeys: ["slack"],
|
|
383
|
-
skipWrite: true,
|
|
384
|
-
onProgress,
|
|
385
|
-
});
|
|
386
|
-
|
|
387
|
-
expect(onProgress).toHaveBeenCalledWith({
|
|
388
|
-
type: "manifest_entry_built",
|
|
389
|
-
appKey: "SlackCLIAPI",
|
|
390
|
-
manifestKey: "SlackCLIAPI",
|
|
391
|
-
version: "1.30.0",
|
|
392
|
-
});
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
it("should emit manifest_updated event when skipWrite is false", async () => {
|
|
396
|
-
const sdk = createTestSdk();
|
|
397
|
-
const onProgress = vi.fn();
|
|
398
|
-
|
|
399
|
-
await sdk.buildManifest({
|
|
400
|
-
appKeys: ["slack"],
|
|
401
|
-
skipWrite: false,
|
|
402
|
-
onProgress,
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
expect(onProgress).toHaveBeenCalledWith({
|
|
406
|
-
type: "manifest_updated",
|
|
407
|
-
appKey: "SlackCLIAPI",
|
|
408
|
-
manifestKey: "SlackCLIAPI",
|
|
409
|
-
version: "1.30.0",
|
|
410
|
-
});
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
it("should emit app_processing_complete event", async () => {
|
|
414
|
-
const sdk = createTestSdk();
|
|
415
|
-
const onProgress = vi.fn();
|
|
416
|
-
|
|
417
|
-
await sdk.buildManifest({
|
|
418
|
-
appKeys: ["slack"],
|
|
419
|
-
skipWrite: true,
|
|
420
|
-
onProgress,
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
expect(onProgress).toHaveBeenCalledWith({
|
|
424
|
-
type: "app_processing_complete",
|
|
425
|
-
appKey: "SlackCLIAPI",
|
|
426
|
-
});
|
|
427
|
-
});
|
|
428
|
-
|
|
429
|
-
it("should emit events in correct order", async () => {
|
|
430
|
-
const sdk = createTestSdk([mockSlackApp]);
|
|
431
|
-
const onProgress = vi.fn();
|
|
432
|
-
|
|
433
|
-
await sdk.buildManifest({
|
|
434
|
-
appKeys: ["slack"],
|
|
435
|
-
skipWrite: false,
|
|
436
|
-
onProgress,
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
const eventTypes = onProgress.mock.calls.map((call) => call[0].type);
|
|
440
|
-
expect(eventTypes).toEqual([
|
|
441
|
-
"apps_lookup_start",
|
|
442
|
-
"app_found",
|
|
443
|
-
"apps_lookup_complete",
|
|
444
|
-
"app_processing_start",
|
|
445
|
-
"manifest_entry_built",
|
|
446
|
-
"manifest_updated",
|
|
447
|
-
"app_processing_complete",
|
|
448
|
-
]);
|
|
449
|
-
});
|
|
450
|
-
});
|
|
451
|
-
|
|
452
|
-
describe("error handling", () => {
|
|
453
|
-
it("should throw ZapierUnknownError when createManifestEntry fails", async () => {
|
|
454
|
-
const sdk = createTestSdk([mockAppWithoutVersion]);
|
|
455
|
-
|
|
456
|
-
await expect(
|
|
457
|
-
sdk.buildManifest({
|
|
458
|
-
appKeys: ["broken"],
|
|
459
|
-
skipWrite: true,
|
|
460
|
-
}),
|
|
461
|
-
).rejects.toThrow(ZapierUnknownError);
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
it("should include app key in error message when processing fails", async () => {
|
|
465
|
-
const sdk = createTestSdk([mockAppWithoutVersion]);
|
|
466
|
-
|
|
467
|
-
await expect(
|
|
468
|
-
sdk.buildManifest({
|
|
469
|
-
appKeys: ["broken"],
|
|
470
|
-
skipWrite: true,
|
|
471
|
-
}),
|
|
472
|
-
).rejects.toThrow(/Failed to process app BrokenAPI/);
|
|
473
|
-
});
|
|
474
|
-
|
|
475
|
-
it("should emit app_processing_error event before throwing", async () => {
|
|
476
|
-
const sdk = createTestSdk([mockAppWithoutVersion]);
|
|
477
|
-
const onProgress = vi.fn();
|
|
478
|
-
|
|
479
|
-
await expect(
|
|
480
|
-
sdk.buildManifest({
|
|
481
|
-
appKeys: ["broken"],
|
|
482
|
-
skipWrite: true,
|
|
483
|
-
onProgress,
|
|
484
|
-
}),
|
|
485
|
-
).rejects.toThrow();
|
|
486
|
-
|
|
487
|
-
expect(onProgress).toHaveBeenCalledWith({
|
|
488
|
-
type: "app_processing_error",
|
|
489
|
-
appKey: "BrokenAPI",
|
|
490
|
-
error: expect.stringContaining("Failed to process app BrokenAPI"),
|
|
491
|
-
});
|
|
492
|
-
});
|
|
493
|
-
|
|
494
|
-
it("should throw immediately on first error and not continue processing", async () => {
|
|
495
|
-
const sdk = createTestSdk([mockAppWithoutVersion, mockSlackApp]);
|
|
496
|
-
|
|
497
|
-
await expect(
|
|
498
|
-
sdk.buildManifest({
|
|
499
|
-
appKeys: ["broken", "slack"],
|
|
500
|
-
skipWrite: true,
|
|
501
|
-
}),
|
|
502
|
-
).rejects.toThrow(ZapierUnknownError);
|
|
503
|
-
|
|
504
|
-
// updateManifestEntry should not be called since first app failed
|
|
505
|
-
expect(mockUpdateManifestEntry).not.toHaveBeenCalled();
|
|
506
|
-
});
|
|
507
|
-
|
|
508
|
-
it("should throw ZapierUnknownError when updateManifestEntry fails", async () => {
|
|
509
|
-
mockUpdateManifestEntry.mockRejectedValueOnce(new Error("Write failed"));
|
|
510
|
-
const sdk = createTestSdk();
|
|
511
|
-
|
|
512
|
-
await expect(
|
|
513
|
-
sdk.buildManifest({
|
|
514
|
-
appKeys: ["slack"],
|
|
515
|
-
skipWrite: false,
|
|
516
|
-
}),
|
|
517
|
-
).rejects.toThrow(ZapierUnknownError);
|
|
518
|
-
});
|
|
519
|
-
|
|
520
|
-
it("should include original error as cause", async () => {
|
|
521
|
-
const originalError = new Error("Write failed");
|
|
522
|
-
mockUpdateManifestEntry.mockRejectedValueOnce(originalError);
|
|
523
|
-
const sdk = createTestSdk();
|
|
524
|
-
|
|
525
|
-
try {
|
|
526
|
-
await sdk.buildManifest({
|
|
527
|
-
appKeys: ["slack"],
|
|
528
|
-
skipWrite: false,
|
|
529
|
-
});
|
|
530
|
-
expect.fail("Should have thrown");
|
|
531
|
-
} catch (error) {
|
|
532
|
-
expect(error).toBeInstanceOf(ZapierUnknownError);
|
|
533
|
-
if (error instanceof ZapierUnknownError) {
|
|
534
|
-
expect(error.cause).toBe(originalError);
|
|
535
|
-
expect(error.message).toContain("Failed to process app SlackCLIAPI");
|
|
536
|
-
expect(error.message).toContain("Write failed");
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
});
|
|
540
|
-
|
|
541
|
-
it("should preserve ZapierValidationError if thrown from underlying code", async () => {
|
|
542
|
-
const validationError = new ZapierValidationError(
|
|
543
|
-
"Invalid manifest entry",
|
|
544
|
-
);
|
|
545
|
-
mockUpdateManifestEntry.mockRejectedValueOnce(validationError);
|
|
546
|
-
const sdk = createTestSdk();
|
|
547
|
-
|
|
548
|
-
await expect(
|
|
549
|
-
sdk.buildManifest({
|
|
550
|
-
appKeys: ["slack"],
|
|
551
|
-
skipWrite: false,
|
|
552
|
-
}),
|
|
553
|
-
).rejects.toThrow(ZapierValidationError);
|
|
554
|
-
});
|
|
555
|
-
|
|
556
|
-
it("should stop processing after first app error", async () => {
|
|
557
|
-
mockUpdateManifestEntry
|
|
558
|
-
.mockRejectedValueOnce(new Error("First error"))
|
|
559
|
-
.mockResolvedValueOnce([
|
|
560
|
-
"GmailCLIAPI",
|
|
561
|
-
{ implementationName: "GmailCLIAPI", version: "2.5.0" },
|
|
562
|
-
{ apps: {} },
|
|
563
|
-
]);
|
|
564
|
-
|
|
565
|
-
const sdk = createTestSdk();
|
|
566
|
-
|
|
567
|
-
await expect(
|
|
568
|
-
sdk.buildManifest({
|
|
569
|
-
appKeys: ["slack", "gmail"],
|
|
570
|
-
skipWrite: false,
|
|
571
|
-
}),
|
|
572
|
-
).rejects.toThrow(ZapierUnknownError);
|
|
573
|
-
|
|
574
|
-
// Should only call once (for first app that fails)
|
|
575
|
-
expect(mockUpdateManifestEntry).toHaveBeenCalledTimes(1);
|
|
576
|
-
});
|
|
577
|
-
});
|
|
578
|
-
|
|
579
|
-
describe("manifest entry creation", () => {
|
|
580
|
-
it("should create correct manifest entry structure", async () => {
|
|
581
|
-
const sdk = createTestSdk([mockSlackApp]);
|
|
582
|
-
|
|
583
|
-
await sdk.buildManifest({
|
|
584
|
-
appKeys: ["slack"],
|
|
585
|
-
skipWrite: false,
|
|
586
|
-
});
|
|
587
|
-
|
|
588
|
-
expect(mockUpdateManifestEntry).toHaveBeenCalledWith(
|
|
589
|
-
expect.objectContaining({
|
|
590
|
-
entry: {
|
|
591
|
-
implementationName: "SlackCLIAPI",
|
|
592
|
-
version: "1.30.0",
|
|
593
|
-
},
|
|
594
|
-
}),
|
|
595
|
-
);
|
|
596
|
-
});
|
|
597
|
-
|
|
598
|
-
it("should use app.key as implementationName", async () => {
|
|
599
|
-
const sdk = createTestSdk([mockGmailApp]);
|
|
600
|
-
|
|
601
|
-
await sdk.buildManifest({
|
|
602
|
-
appKeys: ["gmail"],
|
|
603
|
-
skipWrite: false,
|
|
604
|
-
});
|
|
605
|
-
|
|
606
|
-
expect(mockUpdateManifestEntry).toHaveBeenCalledWith(
|
|
607
|
-
expect.objectContaining({
|
|
608
|
-
entry: {
|
|
609
|
-
implementationName: "GmailCLIAPI",
|
|
610
|
-
version: "2.5.0",
|
|
611
|
-
},
|
|
612
|
-
}),
|
|
613
|
-
);
|
|
614
|
-
});
|
|
615
|
-
});
|
|
616
|
-
|
|
617
|
-
describe("context and metadata", () => {
|
|
618
|
-
it("should provide context with meta information", () => {
|
|
619
|
-
const sdk = createTestSdk();
|
|
620
|
-
const context = sdk.getContext();
|
|
621
|
-
|
|
622
|
-
expect(context.meta.buildManifest).toBeDefined();
|
|
623
|
-
expect(context.meta.buildManifest.inputSchema).toBeDefined();
|
|
624
|
-
expect(context.meta.buildManifest.categories).toEqual(["utility"]);
|
|
625
|
-
});
|
|
626
|
-
|
|
627
|
-
it("should expose BuildManifestSchema in metadata", () => {
|
|
628
|
-
const sdk = createTestSdk();
|
|
629
|
-
const context = sdk.getContext();
|
|
630
|
-
|
|
631
|
-
expect(context.meta.buildManifest.inputSchema).toBe(BuildManifestSchema);
|
|
632
|
-
});
|
|
633
|
-
});
|
|
634
|
-
|
|
635
|
-
describe("edge cases", () => {
|
|
636
|
-
it("should handle empty apps array when no apps are found", async () => {
|
|
637
|
-
const sdk = createTestSdk([]);
|
|
638
|
-
|
|
639
|
-
const result = await sdk.buildManifest({
|
|
640
|
-
appKeys: ["nonexistent"],
|
|
641
|
-
skipWrite: true,
|
|
642
|
-
});
|
|
643
|
-
|
|
644
|
-
expect(result.manifest).toBeUndefined();
|
|
645
|
-
});
|
|
646
|
-
|
|
647
|
-
it("should not call updateManifestEntry when no apps found", async () => {
|
|
648
|
-
const sdk = createTestSdk([]);
|
|
649
|
-
|
|
650
|
-
await sdk.buildManifest({
|
|
651
|
-
appKeys: ["nonexistent"],
|
|
652
|
-
skipWrite: false,
|
|
653
|
-
});
|
|
654
|
-
|
|
655
|
-
expect(mockUpdateManifestEntry).not.toHaveBeenCalled();
|
|
656
|
-
});
|
|
657
|
-
|
|
658
|
-
it("should handle apps without slug", async () => {
|
|
659
|
-
const appWithoutSlug: AppItem = {
|
|
660
|
-
...mockSlackApp,
|
|
661
|
-
slug: undefined as unknown as string,
|
|
662
|
-
};
|
|
663
|
-
const sdk = createTestSdk([appWithoutSlug]);
|
|
664
|
-
const onProgress = vi.fn();
|
|
665
|
-
|
|
666
|
-
await sdk.buildManifest({
|
|
667
|
-
appKeys: ["slack"],
|
|
668
|
-
skipWrite: true,
|
|
669
|
-
onProgress,
|
|
670
|
-
});
|
|
671
|
-
|
|
672
|
-
expect(onProgress).toHaveBeenCalledWith({
|
|
673
|
-
type: "app_processing_start",
|
|
674
|
-
appKey: "SlackCLIAPI",
|
|
675
|
-
slug: undefined,
|
|
676
|
-
});
|
|
677
|
-
});
|
|
678
|
-
});
|
|
679
|
-
});
|