@zapier/zapier-sdk-cli 0.16.0 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/cli.cjs +20 -3
- package/dist/cli.mjs +20 -3
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/package.json +1 -1
- package/dist/src/utils/cli-generator.js +21 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/utils/cli-generator.test.ts +152 -0
- package/src/utils/cli-generator.ts +24 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zapier/zapier-sdk-cli",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.1",
|
|
4
4
|
"description": "Command line interface for Zapier SDK",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"semver": "^7.7.3",
|
|
48
48
|
"typescript": "^5.8.3",
|
|
49
49
|
"zod": "4.2.1",
|
|
50
|
-
"@zapier/zapier-sdk-mcp": "0.4.0",
|
|
51
50
|
"@zapier/zapier-sdk-cli-login": "0.3.5",
|
|
51
|
+
"@zapier/zapier-sdk-mcp": "0.4.0",
|
|
52
52
|
"@zapier/zapier-sdk": "0.16.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
@@ -119,6 +119,158 @@ const mockSdk = {
|
|
|
119
119
|
listApps: vi.fn().mockResolvedValue({ data: [] }),
|
|
120
120
|
} as unknown as ZapierSdk;
|
|
121
121
|
|
|
122
|
+
// Schema for request command testing
|
|
123
|
+
const requestSchema = z
|
|
124
|
+
.object({
|
|
125
|
+
url: z.string().describe("The URL to request"),
|
|
126
|
+
method: z.string().optional().describe("HTTP method"),
|
|
127
|
+
authenticationId: z.number().optional(),
|
|
128
|
+
})
|
|
129
|
+
.describe("Make authenticated HTTP requests");
|
|
130
|
+
|
|
131
|
+
describe("CLI Response Body Handling", () => {
|
|
132
|
+
let consoleSpy: ReturnType<typeof vi.spyOn>;
|
|
133
|
+
|
|
134
|
+
beforeEach(() => {
|
|
135
|
+
vi.clearAllMocks();
|
|
136
|
+
consoleSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
afterEach(() => {
|
|
140
|
+
consoleSpy.mockRestore();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("should wrap Response objects in structured envelope with statusCode, headers, body", async () => {
|
|
144
|
+
const bodyData = { ok: true, users: [{ id: 1, name: "Test User" }] };
|
|
145
|
+
|
|
146
|
+
// Create a mock Response object
|
|
147
|
+
const mockResponse = new Response(JSON.stringify(bodyData), {
|
|
148
|
+
status: 200,
|
|
149
|
+
headers: { "Content-Type": "application/json" },
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const mockSdkWithRequest = {
|
|
153
|
+
getRegistry: vi.fn(() => ({
|
|
154
|
+
functions: [
|
|
155
|
+
{
|
|
156
|
+
name: "request",
|
|
157
|
+
type: "single",
|
|
158
|
+
inputSchema: requestSchema,
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
categories: [],
|
|
162
|
+
})),
|
|
163
|
+
request: vi.fn().mockResolvedValue(mockResponse),
|
|
164
|
+
} as unknown as ZapierSdk;
|
|
165
|
+
|
|
166
|
+
const program = new Command();
|
|
167
|
+
program.exitOverride();
|
|
168
|
+
|
|
169
|
+
generateCliCommands(program, mockSdkWithRequest);
|
|
170
|
+
|
|
171
|
+
await program.parseAsync([
|
|
172
|
+
"node",
|
|
173
|
+
"test",
|
|
174
|
+
"request",
|
|
175
|
+
"https://api.example.com/users",
|
|
176
|
+
"--json",
|
|
177
|
+
]);
|
|
178
|
+
|
|
179
|
+
// Verify the SDK method was called
|
|
180
|
+
expect(mockSdkWithRequest.request).toHaveBeenCalled();
|
|
181
|
+
|
|
182
|
+
// Verify output includes the structured envelope with statusCode, headers, and body
|
|
183
|
+
const expectedEnvelope = {
|
|
184
|
+
statusCode: 200,
|
|
185
|
+
headers: { "content-type": "application/json" },
|
|
186
|
+
body: bodyData,
|
|
187
|
+
};
|
|
188
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
189
|
+
JSON.stringify(expectedEnvelope, null, 2),
|
|
190
|
+
);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it("should handle invalid JSON in Response with helpful error", async () => {
|
|
194
|
+
// Create a mock Response with invalid JSON
|
|
195
|
+
const mockResponse = new Response("not valid json {", {
|
|
196
|
+
status: 200,
|
|
197
|
+
headers: { "Content-Type": "application/json" },
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const mockSdkWithBadResponse = {
|
|
201
|
+
getRegistry: vi.fn(() => ({
|
|
202
|
+
functions: [
|
|
203
|
+
{
|
|
204
|
+
name: "request",
|
|
205
|
+
type: "single",
|
|
206
|
+
inputSchema: requestSchema,
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
categories: [],
|
|
210
|
+
})),
|
|
211
|
+
request: vi.fn().mockResolvedValue(mockResponse),
|
|
212
|
+
} as unknown as ZapierSdk;
|
|
213
|
+
|
|
214
|
+
const program = new Command();
|
|
215
|
+
program.exitOverride();
|
|
216
|
+
const consoleErrorSpy = vi
|
|
217
|
+
.spyOn(console, "error")
|
|
218
|
+
.mockImplementation(() => {});
|
|
219
|
+
|
|
220
|
+
generateCliCommands(program, mockSdkWithBadResponse);
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
await program.parseAsync([
|
|
224
|
+
"node",
|
|
225
|
+
"test",
|
|
226
|
+
"request",
|
|
227
|
+
"https://api.example.com/users",
|
|
228
|
+
"--json",
|
|
229
|
+
]);
|
|
230
|
+
} catch {
|
|
231
|
+
// Expected to throw
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Verify error message includes helpful context
|
|
235
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
236
|
+
expect.stringContaining("❌"),
|
|
237
|
+
expect.stringContaining("Failed to parse response as JSON"),
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
consoleErrorSpy.mockRestore();
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it("should handle non-Response objects normally", async () => {
|
|
244
|
+
const regularData = { apps: [{ id: 1, name: "Test App" }] };
|
|
245
|
+
|
|
246
|
+
const mockSdkRegular = {
|
|
247
|
+
getRegistry: vi.fn(() => ({
|
|
248
|
+
functions: [
|
|
249
|
+
{
|
|
250
|
+
name: "getApp",
|
|
251
|
+
type: "single",
|
|
252
|
+
inputSchema: z.object({ appKey: z.string() }).describe("Get app"),
|
|
253
|
+
},
|
|
254
|
+
],
|
|
255
|
+
categories: [],
|
|
256
|
+
})),
|
|
257
|
+
getApp: vi.fn().mockResolvedValue(regularData),
|
|
258
|
+
} as unknown as ZapierSdk;
|
|
259
|
+
|
|
260
|
+
const program = new Command();
|
|
261
|
+
program.exitOverride();
|
|
262
|
+
|
|
263
|
+
generateCliCommands(program, mockSdkRegular);
|
|
264
|
+
|
|
265
|
+
await program.parseAsync(["node", "test", "get-app", "test-app", "--json"]);
|
|
266
|
+
|
|
267
|
+
expect(mockSdkRegular.getApp).toHaveBeenCalled();
|
|
268
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
269
|
+
JSON.stringify(regularData, null, 2),
|
|
270
|
+
);
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
|
|
122
274
|
describe("CLI Command Generation", () => {
|
|
123
275
|
beforeEach(() => {
|
|
124
276
|
vi.clearAllMocks();
|
|
@@ -350,7 +350,30 @@ function createCommandConfig(
|
|
|
350
350
|
string,
|
|
351
351
|
(params: unknown) => Promise<unknown>
|
|
352
352
|
>;
|
|
353
|
-
|
|
353
|
+
let result: unknown = await sdkObj[functionInfo.name](resolvedParams);
|
|
354
|
+
|
|
355
|
+
// Handle Response objects by wrapping in a structured envelope
|
|
356
|
+
if (result instanceof Response) {
|
|
357
|
+
const response = result;
|
|
358
|
+
let body: unknown;
|
|
359
|
+
try {
|
|
360
|
+
body = await response.json();
|
|
361
|
+
} catch {
|
|
362
|
+
// If JSON parsing fails, try to get text for error context
|
|
363
|
+
const text = response.bodyUsed
|
|
364
|
+
? "[body already consumed]"
|
|
365
|
+
: await response.text().catch(() => "[unable to read body]");
|
|
366
|
+
throw new Error(
|
|
367
|
+
`Failed to parse response as JSON (status: ${response.status}). Body: ${text.slice(0, 200)}`,
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
result = {
|
|
371
|
+
statusCode: response.status,
|
|
372
|
+
headers: Object.fromEntries(response.headers.entries()),
|
|
373
|
+
body,
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
354
377
|
const items = (result as { data?: unknown })?.data
|
|
355
378
|
? (result as { data: unknown }).data
|
|
356
379
|
: result;
|