@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zapier/zapier-sdk-cli",
3
- "version": "0.16.0",
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
- const result: unknown = await sdkObj[functionInfo.name](resolvedParams);
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;