@zapier/zapier-sdk 0.18.1 → 0.18.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 +12 -0
- package/README.md +17 -17
- package/dist/api/router.d.ts.map +1 -1
- package/dist/api/router.js +1 -7
- package/dist/api/router.test.js +1 -7
- package/dist/api/schemas.d.ts +0 -49
- package/dist/api/schemas.d.ts.map +1 -1
- package/dist/api/schemas.js +0 -28
- package/dist/api/types.d.ts +2 -1
- package/dist/api/types.d.ts.map +1 -1
- package/dist/api/types.js +0 -10
- package/dist/index.cjs +38 -301
- package/dist/index.d.mts +114 -207
- package/dist/index.mjs +38 -301
- package/dist/plugins/findFirstAuthentication/index.test.js +2 -2
- package/dist/plugins/findUniqueAuthentication/index.test.js +2 -2
- package/dist/plugins/getAuthentication/index.d.ts +3 -3
- package/dist/plugins/getAuthentication/index.d.ts.map +1 -1
- package/dist/plugins/getAuthentication/index.js +3 -5
- package/dist/plugins/getAuthentication/index.test.js +4 -16
- package/dist/plugins/getAuthentication/schemas.d.ts +2 -4
- package/dist/plugins/getAuthentication/schemas.d.ts.map +1 -1
- package/dist/plugins/getAuthentication/schemas.js +1 -1
- package/dist/plugins/listAuthentications/index.d.ts +4 -10
- package/dist/plugins/listAuthentications/index.d.ts.map +1 -1
- package/dist/plugins/listAuthentications/index.js +19 -31
- package/dist/plugins/listAuthentications/index.test.js +347 -127
- package/dist/plugins/listAuthentications/schemas.d.ts +7 -7
- package/dist/plugins/listAuthentications/schemas.d.ts.map +1 -1
- package/dist/plugins/listAuthentications/schemas.js +10 -16
- package/dist/schemas/Auth.d.ts +11 -11
- package/dist/schemas/Auth.d.ts.map +1 -1
- package/dist/schemas/Auth.js +2 -12
- package/dist/sdk.d.ts +4 -2
- package/dist/sdk.d.ts.map +1 -1
- package/dist/temporary-internal-core/index.d.ts +0 -2
- package/dist/temporary-internal-core/index.d.ts.map +1 -1
- package/dist/temporary-internal-core/index.js +0 -2
- package/dist/temporary-internal-core/utils/transformations.d.ts +0 -14
- package/dist/temporary-internal-core/utils/transformations.d.ts.map +1 -1
- package/dist/temporary-internal-core/utils/transformations.js +0 -38
- package/dist/utils/domain-utils.d.ts +2 -15
- package/dist/utils/domain-utils.d.ts.map +1 -1
- package/dist/utils/domain-utils.js +0 -38
- package/dist/utils/function-utils.d.ts +1 -0
- package/dist/utils/function-utils.d.ts.map +1 -1
- package/dist/utils/function-utils.js +15 -3
- package/package.json +2 -1
- package/dist/temporary-internal-core/handlers/getAuthentication.d.ts +0 -94
- package/dist/temporary-internal-core/handlers/getAuthentication.d.ts.map +0 -1
- package/dist/temporary-internal-core/handlers/getAuthentication.js +0 -68
- package/dist/temporary-internal-core/handlers/getAuthentication.test.d.ts +0 -2
- package/dist/temporary-internal-core/handlers/getAuthentication.test.d.ts.map +0 -1
- package/dist/temporary-internal-core/handlers/getAuthentication.test.js +0 -248
- package/dist/temporary-internal-core/schemas/authentications/index.d.ts +0 -150
- package/dist/temporary-internal-core/schemas/authentications/index.d.ts.map +0 -1
- package/dist/temporary-internal-core/schemas/authentications/index.js +0 -97
|
@@ -4,37 +4,35 @@ import { listAuthenticationsPlugin } from "./index";
|
|
|
4
4
|
import { createSdk } from "../../sdk";
|
|
5
5
|
import { eventEmissionPlugin } from "../eventEmission";
|
|
6
6
|
const mockAuthenticationsResponse = {
|
|
7
|
-
|
|
7
|
+
data: [
|
|
8
8
|
{
|
|
9
|
-
id: 123,
|
|
9
|
+
id: "123",
|
|
10
10
|
date: "2021-01-01",
|
|
11
|
-
account_id: 456,
|
|
12
|
-
|
|
11
|
+
account_id: "456",
|
|
12
|
+
implementation_id: "SlackCLIAPI@1.21.1",
|
|
13
13
|
is_invite_only: false,
|
|
14
14
|
is_private: false,
|
|
15
15
|
shared_with_all: false,
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
is_expired: "false",
|
|
17
|
+
expired_at: null,
|
|
18
18
|
label: "My Slack Workspace",
|
|
19
19
|
title: "My Slack Workspace",
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
|
-
id: 789,
|
|
22
|
+
id: "789",
|
|
23
23
|
date: "2021-02-01",
|
|
24
|
-
account_id: 456,
|
|
25
|
-
|
|
24
|
+
account_id: "456",
|
|
25
|
+
implementation_id: "GitHubAPI@2.1.0",
|
|
26
26
|
is_invite_only: false,
|
|
27
27
|
is_private: false,
|
|
28
28
|
shared_with_all: true,
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
is_expired: "true",
|
|
30
|
+
expired_at: "2021-06-01",
|
|
31
31
|
label: "GitHub Integration",
|
|
32
32
|
title: "GitHub Integration",
|
|
33
33
|
},
|
|
34
34
|
],
|
|
35
|
-
|
|
36
|
-
next: null,
|
|
37
|
-
previous: null,
|
|
35
|
+
nextCursor: undefined,
|
|
38
36
|
};
|
|
39
37
|
describe("listAuthentications plugin", () => {
|
|
40
38
|
let mockApiClient;
|
|
@@ -205,7 +203,7 @@ describe("listAuthentications plugin", () => {
|
|
|
205
203
|
});
|
|
206
204
|
});
|
|
207
205
|
describe("data mapping", () => {
|
|
208
|
-
it("should
|
|
206
|
+
it("should pass through is_expired and expired_at fields", async () => {
|
|
209
207
|
const sdk = createTestSdk();
|
|
210
208
|
const result = await sdk.listAuthentications();
|
|
211
209
|
expect(result.data[0].is_expired).toBe("false");
|
|
@@ -213,12 +211,12 @@ describe("listAuthentications plugin", () => {
|
|
|
213
211
|
expect(result.data[1].is_expired).toBe("true");
|
|
214
212
|
expect(result.data[1].expired_at).toBe("2021-06-01");
|
|
215
213
|
});
|
|
216
|
-
it("should
|
|
214
|
+
it("should pass through label field when title is missing", async () => {
|
|
217
215
|
const responseWithoutTitle = {
|
|
218
216
|
...mockAuthenticationsResponse,
|
|
219
|
-
|
|
217
|
+
data: [
|
|
220
218
|
{
|
|
221
|
-
...mockAuthenticationsResponse.
|
|
219
|
+
...mockAuthenticationsResponse.data[0],
|
|
222
220
|
title: undefined,
|
|
223
221
|
label: "Label Only Auth",
|
|
224
222
|
},
|
|
@@ -227,14 +225,16 @@ describe("listAuthentications plugin", () => {
|
|
|
227
225
|
mockApiClient.get = vi.fn().mockResolvedValue(responseWithoutTitle);
|
|
228
226
|
const sdk = createTestSdk();
|
|
229
227
|
const result = await sdk.listAuthentications({});
|
|
230
|
-
|
|
228
|
+
// New API passes through fields directly - title coercion happens server-side
|
|
229
|
+
expect(result.data[0].title).toBeUndefined();
|
|
230
|
+
expect(result.data[0].label).toBe("Label Only Auth");
|
|
231
231
|
});
|
|
232
232
|
it("should handle authentications with neither title nor label", async () => {
|
|
233
233
|
const responseWithoutTitleOrLabel = {
|
|
234
234
|
...mockAuthenticationsResponse,
|
|
235
|
-
|
|
235
|
+
data: [
|
|
236
236
|
{
|
|
237
|
-
...mockAuthenticationsResponse.
|
|
237
|
+
...mockAuthenticationsResponse.data[0],
|
|
238
238
|
title: undefined,
|
|
239
239
|
label: undefined,
|
|
240
240
|
},
|
|
@@ -249,85 +249,90 @@ describe("listAuthentications plugin", () => {
|
|
|
249
249
|
});
|
|
250
250
|
});
|
|
251
251
|
describe("filtering", () => {
|
|
252
|
-
it("should
|
|
253
|
-
const sdk = createTestSdk();
|
|
254
|
-
const result = await sdk.listAuthentications({
|
|
255
|
-
title: "My Slack Workspace",
|
|
256
|
-
});
|
|
257
|
-
// Should filter to exact match
|
|
258
|
-
expect(result.data).toHaveLength(1);
|
|
259
|
-
expect(result.data[0].title).toBe("My Slack Workspace");
|
|
260
|
-
});
|
|
261
|
-
it("should use search parameter when provided", async () => {
|
|
252
|
+
it("should pass search parameter to API when provided", async () => {
|
|
262
253
|
const sdk = createTestSdk();
|
|
263
254
|
await sdk.listAuthentications({ search: "workspace" });
|
|
264
|
-
expect(mockApiClient.get).toHaveBeenCalledWith("/
|
|
255
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
265
256
|
searchParams: expect.objectContaining({
|
|
266
257
|
search: "workspace",
|
|
267
258
|
}),
|
|
268
259
|
}));
|
|
269
260
|
});
|
|
270
|
-
it("should
|
|
261
|
+
it("should pass title parameter separately to API", async () => {
|
|
271
262
|
const sdk = createTestSdk();
|
|
272
263
|
await sdk.listAuthentications({ title: "My Slack Workspace" });
|
|
273
|
-
expect(mockApiClient.get).toHaveBeenCalledWith("/
|
|
264
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
274
265
|
searchParams: expect.objectContaining({
|
|
275
|
-
|
|
266
|
+
title: "My Slack Workspace",
|
|
276
267
|
}),
|
|
277
268
|
}));
|
|
278
269
|
});
|
|
279
|
-
it("should
|
|
270
|
+
it("should pass both search and title when both provided", async () => {
|
|
280
271
|
const sdk = createTestSdk();
|
|
281
272
|
await sdk.listAuthentications({
|
|
282
273
|
search: "explicit search",
|
|
283
274
|
title: "My Title",
|
|
284
275
|
});
|
|
285
|
-
expect(mockApiClient.get).toHaveBeenCalledWith("/
|
|
276
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
286
277
|
searchParams: expect.objectContaining({
|
|
287
278
|
search: "explicit search",
|
|
279
|
+
title: "My Title",
|
|
288
280
|
}),
|
|
289
281
|
}));
|
|
290
282
|
});
|
|
291
283
|
it("should pass accountId filter to API", async () => {
|
|
292
284
|
const sdk = createTestSdk();
|
|
293
285
|
await sdk.listAuthentications({ accountId: "acc_123" });
|
|
294
|
-
expect(mockApiClient.get).toHaveBeenCalledWith("/
|
|
286
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
295
287
|
searchParams: expect.objectContaining({
|
|
296
|
-
|
|
288
|
+
accountId: "acc_123",
|
|
297
289
|
}),
|
|
298
290
|
}));
|
|
299
291
|
});
|
|
300
292
|
it("should pass owner filter to API", async () => {
|
|
301
293
|
const sdk = createTestSdk();
|
|
302
294
|
await sdk.listAuthentications({ owner: "me" });
|
|
303
|
-
expect(mockApiClient.get).toHaveBeenCalledWith("/
|
|
295
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
304
296
|
searchParams: expect.objectContaining({
|
|
305
297
|
owner: "me",
|
|
306
298
|
}),
|
|
307
299
|
}));
|
|
308
300
|
});
|
|
309
|
-
it("should pass authenticationIds as
|
|
301
|
+
it("should pass authenticationIds as comma-separated string to API", async () => {
|
|
310
302
|
const sdk = createTestSdk();
|
|
311
303
|
await sdk.listAuthentications({
|
|
312
304
|
authenticationIds: ["123", "456", "789"],
|
|
313
305
|
});
|
|
314
|
-
expect(mockApiClient.get).toHaveBeenCalledWith("/
|
|
306
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
315
307
|
searchParams: expect.objectContaining({
|
|
316
|
-
|
|
308
|
+
authenticationIds: "123,456,789",
|
|
317
309
|
}),
|
|
318
310
|
}));
|
|
319
311
|
});
|
|
320
|
-
it("should not include
|
|
312
|
+
it("should not include authenticationIds parameter when array is empty", async () => {
|
|
321
313
|
const sdk = createTestSdk();
|
|
322
314
|
await sdk.listAuthentications({
|
|
323
315
|
authenticationIds: [],
|
|
324
316
|
});
|
|
325
|
-
expect(mockApiClient.get).toHaveBeenCalledWith("/
|
|
317
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
326
318
|
searchParams: expect.not.objectContaining({
|
|
327
|
-
|
|
319
|
+
authenticationIds: expect.anything(),
|
|
328
320
|
}),
|
|
329
321
|
}));
|
|
330
322
|
});
|
|
323
|
+
it("should not include undefined optional parameters in searchParams", async () => {
|
|
324
|
+
const sdk = createTestSdk();
|
|
325
|
+
await sdk.listAuthentications({});
|
|
326
|
+
const callArgs = mockApiClient.get.mock.calls[0];
|
|
327
|
+
const searchParams = callArgs[1].searchParams;
|
|
328
|
+
// Should only have pageSize (default), not undefined params
|
|
329
|
+
expect(searchParams).not.toHaveProperty("search");
|
|
330
|
+
expect(searchParams).not.toHaveProperty("title");
|
|
331
|
+
expect(searchParams).not.toHaveProperty("accountId");
|
|
332
|
+
expect(searchParams).not.toHaveProperty("owner");
|
|
333
|
+
expect(searchParams).not.toHaveProperty("authenticationIds");
|
|
334
|
+
expect(searchParams).not.toHaveProperty("appKey");
|
|
335
|
+
});
|
|
331
336
|
});
|
|
332
337
|
describe("pagination", () => {
|
|
333
338
|
it("should handle pagination with maxItems by collecting all items", async () => {
|
|
@@ -335,27 +340,25 @@ describe("listAuthentications plugin", () => {
|
|
|
335
340
|
mockApiClient.get = vi
|
|
336
341
|
.fn()
|
|
337
342
|
.mockResolvedValueOnce({
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
next: "http://example.com/api/v4/authentications/?offset=2",
|
|
343
|
+
data: mockAuthenticationsResponse.data,
|
|
344
|
+
nextCursor: "2",
|
|
341
345
|
})
|
|
342
346
|
.mockResolvedValueOnce({
|
|
343
|
-
|
|
347
|
+
data: [
|
|
344
348
|
{
|
|
345
|
-
id: 999,
|
|
349
|
+
id: "999",
|
|
346
350
|
date: "2021-03-01",
|
|
347
|
-
account_id: 456,
|
|
348
|
-
|
|
351
|
+
account_id: "456",
|
|
352
|
+
implementation_id: "DropboxAPI@3.0.0",
|
|
349
353
|
is_invite_only: false,
|
|
350
354
|
is_private: false,
|
|
351
355
|
shared_with_all: false,
|
|
352
|
-
|
|
353
|
-
|
|
356
|
+
is_expired: "false",
|
|
357
|
+
expired_at: null,
|
|
354
358
|
title: "Dropbox Integration",
|
|
355
359
|
},
|
|
356
360
|
],
|
|
357
|
-
|
|
358
|
-
next: null,
|
|
361
|
+
nextCursor: undefined,
|
|
359
362
|
});
|
|
360
363
|
const sdk = createTestSdk();
|
|
361
364
|
// Collect all items using the items() iterator
|
|
@@ -370,9 +373,8 @@ describe("listAuthentications plugin", () => {
|
|
|
370
373
|
});
|
|
371
374
|
it("should return first page when awaited", async () => {
|
|
372
375
|
mockApiClient.get = vi.fn().mockResolvedValue({
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
next: null, // No more pages to prevent automatic fetching
|
|
376
|
+
data: mockAuthenticationsResponse.data,
|
|
377
|
+
nextCursor: undefined,
|
|
376
378
|
});
|
|
377
379
|
const sdk = createTestSdk();
|
|
378
380
|
const result = await sdk.listAuthentications({});
|
|
@@ -384,14 +386,12 @@ describe("listAuthentications plugin", () => {
|
|
|
384
386
|
mockApiClient.get = vi
|
|
385
387
|
.fn()
|
|
386
388
|
.mockResolvedValueOnce({
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
next: "http://example.com/api/v4/authentications/?offset=1",
|
|
389
|
+
data: mockAuthenticationsResponse.data.slice(0, 1),
|
|
390
|
+
nextCursor: "1",
|
|
390
391
|
})
|
|
391
392
|
.mockResolvedValueOnce({
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
next: null,
|
|
393
|
+
data: mockAuthenticationsResponse.data.slice(1, 2),
|
|
394
|
+
nextCursor: undefined,
|
|
395
395
|
});
|
|
396
396
|
const sdk = createTestSdk();
|
|
397
397
|
const pages = [];
|
|
@@ -418,43 +418,79 @@ describe("listAuthentications plugin", () => {
|
|
|
418
418
|
expect(items[0].id).toBe("123");
|
|
419
419
|
expect(items[1].id).toBe("789");
|
|
420
420
|
});
|
|
421
|
-
it("should set
|
|
421
|
+
it("should set pageSize in searchParams for API calls", async () => {
|
|
422
422
|
const sdk = createTestSdk();
|
|
423
|
-
await sdk.listAuthentications({ pageSize:
|
|
424
|
-
expect(mockApiClient.get).toHaveBeenCalledWith("/
|
|
423
|
+
await sdk.listAuthentications({ pageSize: 15 });
|
|
424
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
425
425
|
searchParams: expect.objectContaining({
|
|
426
|
-
|
|
426
|
+
pageSize: "15",
|
|
427
427
|
}),
|
|
428
428
|
}));
|
|
429
429
|
});
|
|
430
|
+
it("should pass cursor as offset parameter", async () => {
|
|
431
|
+
mockApiClient.get = vi
|
|
432
|
+
.fn()
|
|
433
|
+
.mockResolvedValueOnce({
|
|
434
|
+
data: mockAuthenticationsResponse.data.slice(0, 1),
|
|
435
|
+
nextCursor: "cursor-abc-123",
|
|
436
|
+
})
|
|
437
|
+
.mockResolvedValueOnce({
|
|
438
|
+
data: mockAuthenticationsResponse.data.slice(1, 2),
|
|
439
|
+
nextCursor: undefined,
|
|
440
|
+
});
|
|
441
|
+
const sdk = createTestSdk();
|
|
442
|
+
const pages = [];
|
|
443
|
+
for await (const page of sdk.listAuthentications({ pageSize: 1 })) {
|
|
444
|
+
pages.push(page);
|
|
445
|
+
if (pages.length >= 2)
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
// Second call should include the cursor as offset
|
|
449
|
+
expect(mockApiClient.get).toHaveBeenNthCalledWith(2, "/api/v0/authentications", expect.objectContaining({
|
|
450
|
+
searchParams: expect.objectContaining({
|
|
451
|
+
offset: "cursor-abc-123",
|
|
452
|
+
}),
|
|
453
|
+
}));
|
|
454
|
+
});
|
|
455
|
+
it("should stop pagination when nextCursor is undefined", async () => {
|
|
456
|
+
mockApiClient.get = vi.fn().mockResolvedValue({
|
|
457
|
+
data: mockAuthenticationsResponse.data,
|
|
458
|
+
nextCursor: undefined,
|
|
459
|
+
});
|
|
460
|
+
const sdk = createTestSdk();
|
|
461
|
+
const pages = [];
|
|
462
|
+
for await (const page of sdk.listAuthentications({})) {
|
|
463
|
+
pages.push(page);
|
|
464
|
+
}
|
|
465
|
+
expect(pages).toHaveLength(1);
|
|
466
|
+
expect(mockApiClient.get).toHaveBeenCalledTimes(1);
|
|
467
|
+
});
|
|
430
468
|
});
|
|
431
469
|
describe("API integration", () => {
|
|
432
470
|
it("should call the correct API endpoint", async () => {
|
|
433
471
|
const sdk = createTestSdk();
|
|
434
472
|
await sdk.listAuthentications({});
|
|
435
|
-
expect(mockApiClient.get).toHaveBeenCalledWith("/
|
|
473
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.any(Object));
|
|
436
474
|
});
|
|
437
|
-
it("should pass pageSize as
|
|
475
|
+
it("should pass pageSize as string in searchParams", async () => {
|
|
438
476
|
const sdk = createTestSdk();
|
|
439
477
|
await sdk.listAuthentications({ pageSize: 25 });
|
|
440
|
-
expect(mockApiClient.get).toHaveBeenCalledWith("/
|
|
478
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
441
479
|
searchParams: expect.objectContaining({
|
|
442
|
-
|
|
480
|
+
pageSize: "25",
|
|
443
481
|
}),
|
|
444
482
|
}));
|
|
445
483
|
});
|
|
446
|
-
it("should handle cursor-based pagination
|
|
484
|
+
it("should handle cursor-based pagination with nextCursor", async () => {
|
|
447
485
|
mockApiClient.get = vi
|
|
448
486
|
.fn()
|
|
449
487
|
.mockResolvedValueOnce({
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
next: "http://example.com/api/v4/authentications/?offset=1",
|
|
488
|
+
data: mockAuthenticationsResponse.data.slice(0, 1),
|
|
489
|
+
nextCursor: "offset-1",
|
|
453
490
|
})
|
|
454
491
|
.mockResolvedValueOnce({
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
next: null,
|
|
492
|
+
data: mockAuthenticationsResponse.data.slice(1, 2),
|
|
493
|
+
nextCursor: undefined,
|
|
458
494
|
});
|
|
459
495
|
const sdk = createTestSdk();
|
|
460
496
|
// Test that the function can handle multiple pages
|
|
@@ -466,42 +502,68 @@ describe("listAuthentications plugin", () => {
|
|
|
466
502
|
}
|
|
467
503
|
expect(pageCount).toBe(2);
|
|
468
504
|
expect(mockApiClient.get).toHaveBeenCalledTimes(2);
|
|
469
|
-
// The second call should include the offset from the
|
|
470
|
-
expect(mockApiClient.get).toHaveBeenNthCalledWith(2, "/
|
|
505
|
+
// The second call should include the offset from the nextCursor
|
|
506
|
+
expect(mockApiClient.get).toHaveBeenNthCalledWith(2, "/api/v0/authentications", expect.objectContaining({
|
|
471
507
|
searchParams: expect.objectContaining({
|
|
472
|
-
offset: "1",
|
|
508
|
+
offset: "offset-1",
|
|
473
509
|
}),
|
|
474
510
|
}));
|
|
475
511
|
});
|
|
512
|
+
it("should set authRequired to true in API call options", async () => {
|
|
513
|
+
const sdk = createTestSdk();
|
|
514
|
+
await sdk.listAuthentications({});
|
|
515
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
516
|
+
authRequired: true,
|
|
517
|
+
}));
|
|
518
|
+
});
|
|
519
|
+
it("should include customErrorHandler in API call options", async () => {
|
|
520
|
+
const sdk = createTestSdk();
|
|
521
|
+
await sdk.listAuthentications({});
|
|
522
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
523
|
+
customErrorHandler: expect.any(Function),
|
|
524
|
+
}));
|
|
525
|
+
});
|
|
476
526
|
});
|
|
477
527
|
describe("error handling", () => {
|
|
478
528
|
it("should throw ZapierAuthenticationError for 401 responses", async () => {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
throw error;
|
|
529
|
+
mockApiClient.get = vi.fn().mockImplementation((_url, options) => {
|
|
530
|
+
// Simulate the API client calling the customErrorHandler
|
|
531
|
+
const error = options.customErrorHandler({ status: 401 });
|
|
532
|
+
if (error)
|
|
533
|
+
throw error;
|
|
485
534
|
});
|
|
486
535
|
const sdk = createTestSdk();
|
|
487
536
|
await expect(sdk.listAuthentications({})).rejects.toThrow(ZapierAuthenticationError);
|
|
537
|
+
await expect(sdk.listAuthentications({})).rejects.toThrow(/Authentication failed.*HTTP 401/);
|
|
488
538
|
});
|
|
489
539
|
it("should throw ZapierAuthenticationError for 403 responses", async () => {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
throw error;
|
|
540
|
+
mockApiClient.get = vi.fn().mockImplementation((_url, options) => {
|
|
541
|
+
// Simulate the API client calling the customErrorHandler
|
|
542
|
+
const error = options.customErrorHandler({ status: 403 });
|
|
543
|
+
if (error)
|
|
544
|
+
throw error;
|
|
496
545
|
});
|
|
497
546
|
const sdk = createTestSdk();
|
|
498
547
|
await expect(sdk.listAuthentications({})).rejects.toThrow(ZapierAuthenticationError);
|
|
548
|
+
await expect(sdk.listAuthentications({})).rejects.toThrow(/Access forbidden.*HTTP 403/);
|
|
549
|
+
});
|
|
550
|
+
it("should return undefined from customErrorHandler for non-401/403 errors", async () => {
|
|
551
|
+
let customErrorHandlerResult;
|
|
552
|
+
mockApiClient.get = vi.fn().mockImplementation((_url, options) => {
|
|
553
|
+
// Capture the customErrorHandler result for 500
|
|
554
|
+
customErrorHandlerResult = options.customErrorHandler({ status: 500 });
|
|
555
|
+
// Return valid data since we're just testing the handler
|
|
556
|
+
return mockAuthenticationsResponse;
|
|
557
|
+
});
|
|
558
|
+
const sdk = createTestSdk();
|
|
559
|
+
await sdk.listAuthentications({});
|
|
560
|
+
// The customErrorHandler should return undefined for other status codes
|
|
561
|
+
expect(customErrorHandlerResult).toBeUndefined();
|
|
499
562
|
});
|
|
500
|
-
it("should handle empty
|
|
563
|
+
it("should handle empty data array", async () => {
|
|
501
564
|
const emptyResponse = {
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
next: null,
|
|
565
|
+
data: [],
|
|
566
|
+
nextCursor: undefined,
|
|
505
567
|
};
|
|
506
568
|
mockApiClient.get = vi.fn().mockResolvedValue(emptyResponse);
|
|
507
569
|
const sdk = createTestSdk();
|
|
@@ -509,59 +571,74 @@ describe("listAuthentications plugin", () => {
|
|
|
509
571
|
expect(result.data).toHaveLength(0);
|
|
510
572
|
expect(Array.isArray(result.data)).toBe(true);
|
|
511
573
|
});
|
|
512
|
-
it("should handle
|
|
513
|
-
const
|
|
514
|
-
|
|
515
|
-
next: null,
|
|
516
|
-
};
|
|
517
|
-
mockApiClient.get = vi.fn().mockResolvedValue(responseWithoutResults);
|
|
574
|
+
it("should handle API errors gracefully", async () => {
|
|
575
|
+
const networkError = new Error("Network error");
|
|
576
|
+
mockApiClient.get = vi.fn().mockRejectedValue(networkError);
|
|
518
577
|
const sdk = createTestSdk();
|
|
519
|
-
|
|
520
|
-
expect(result.data).toHaveLength(0);
|
|
521
|
-
expect(Array.isArray(result.data)).toBe(true);
|
|
578
|
+
await expect(sdk.listAuthentications({})).rejects.toThrow("Network error");
|
|
522
579
|
});
|
|
523
580
|
});
|
|
524
581
|
describe("app key integration", () => {
|
|
525
|
-
it("should
|
|
582
|
+
it("should not add appKey parameter when getVersionedImplementationId returns null", async () => {
|
|
526
583
|
mockGetVersionedImplementationId.mockResolvedValue(null);
|
|
527
584
|
const sdk = createTestSdk();
|
|
528
585
|
await sdk.listAuthentications({ appKey: "slack" });
|
|
529
|
-
// Should not add
|
|
530
|
-
expect(mockApiClient.get).toHaveBeenCalledWith("/
|
|
586
|
+
// Should not add appKey parameter when implementation can't be resolved
|
|
587
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
531
588
|
searchParams: expect.not.objectContaining({
|
|
532
|
-
|
|
589
|
+
appKey: expect.any(String),
|
|
533
590
|
}),
|
|
534
591
|
}));
|
|
535
592
|
});
|
|
536
|
-
it("should extract versionless
|
|
593
|
+
it("should extract versionless app key from versioned implementation ID", async () => {
|
|
537
594
|
mockGetVersionedImplementationId.mockResolvedValue("SlackCLIAPI@2.1.3");
|
|
538
595
|
const sdk = createTestSdk();
|
|
539
596
|
await sdk.listAuthentications({ appKey: "slack" });
|
|
540
|
-
expect(mockApiClient.get).toHaveBeenCalledWith("/
|
|
597
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
598
|
+
searchParams: expect.objectContaining({
|
|
599
|
+
appKey: "SlackCLIAPI",
|
|
600
|
+
}),
|
|
601
|
+
}));
|
|
602
|
+
});
|
|
603
|
+
it("should handle implementation ID without version", async () => {
|
|
604
|
+
mockGetVersionedImplementationId.mockResolvedValue("SlackCLIAPI");
|
|
605
|
+
const sdk = createTestSdk();
|
|
606
|
+
await sdk.listAuthentications({ appKey: "slack" });
|
|
607
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
541
608
|
searchParams: expect.objectContaining({
|
|
542
|
-
|
|
609
|
+
appKey: "SlackCLIAPI",
|
|
543
610
|
}),
|
|
544
611
|
}));
|
|
545
612
|
});
|
|
613
|
+
it("should call getVersionedImplementationId with the provided appKey", async () => {
|
|
614
|
+
const sdk = createTestSdk();
|
|
615
|
+
await sdk.listAuthentications({ appKey: "my-custom-app" });
|
|
616
|
+
expect(mockGetVersionedImplementationId).toHaveBeenCalledWith("my-custom-app");
|
|
617
|
+
});
|
|
618
|
+
it("should not call getVersionedImplementationId when appKey is not provided", async () => {
|
|
619
|
+
const sdk = createTestSdk();
|
|
620
|
+
await sdk.listAuthentications({});
|
|
621
|
+
expect(mockGetVersionedImplementationId).not.toHaveBeenCalled();
|
|
622
|
+
});
|
|
546
623
|
});
|
|
547
624
|
describe("response transformation", () => {
|
|
548
|
-
it("should preserve all
|
|
625
|
+
it("should preserve all authentication fields from new API response", async () => {
|
|
549
626
|
const authWithAllFields = {
|
|
550
|
-
|
|
627
|
+
data: [
|
|
551
628
|
{
|
|
552
|
-
id: 123,
|
|
629
|
+
id: "123",
|
|
553
630
|
date: "2021-01-01",
|
|
554
631
|
lastchanged: "2021-01-02",
|
|
555
|
-
account_id: 456,
|
|
556
|
-
|
|
557
|
-
|
|
632
|
+
account_id: "456",
|
|
633
|
+
profile_id: "789",
|
|
634
|
+
implementation_id: "SlackCLIAPI@1.21.1",
|
|
558
635
|
destination_selected_api: "SlackDestAPI@1.0.0",
|
|
559
636
|
is_invite_only: true,
|
|
560
637
|
is_private: true,
|
|
561
638
|
shared_with_all: false,
|
|
562
|
-
|
|
639
|
+
is_expired: "true",
|
|
563
640
|
is_shared: "false",
|
|
564
|
-
|
|
641
|
+
expired_at: "2021-06-01",
|
|
565
642
|
label: "Auth Label",
|
|
566
643
|
title: "Auth Title",
|
|
567
644
|
identifier: "auth-identifier",
|
|
@@ -569,15 +646,17 @@ describe("listAuthentications plugin", () => {
|
|
|
569
646
|
groups: "group1,group2",
|
|
570
647
|
members: "user1,user2",
|
|
571
648
|
permissions: { read: true, write: false },
|
|
649
|
+
app_key: "SlackCLIAPI",
|
|
650
|
+
app_version: "1.21.1",
|
|
572
651
|
},
|
|
573
652
|
],
|
|
574
|
-
|
|
653
|
+
nextCursor: undefined,
|
|
575
654
|
};
|
|
576
655
|
mockApiClient.get = vi.fn().mockResolvedValue(authWithAllFields);
|
|
577
656
|
const sdk = createTestSdk();
|
|
578
657
|
const result = await sdk.listAuthentications({});
|
|
579
658
|
const auth = result.data[0];
|
|
580
|
-
// Verify
|
|
659
|
+
// Verify all fields are passed through from the new API
|
|
581
660
|
expect(auth.id).toBe("123");
|
|
582
661
|
expect(auth.date).toBe("2021-01-01");
|
|
583
662
|
expect(auth.lastchanged).toBe("2021-01-02");
|
|
@@ -596,9 +675,29 @@ describe("listAuthentications plugin", () => {
|
|
|
596
675
|
expect(auth.groups).toBe("group1,group2");
|
|
597
676
|
expect(auth.members).toBe("user1,user2");
|
|
598
677
|
expect(auth.permissions).toEqual({ read: true, write: false });
|
|
599
|
-
// Verify mapped fields
|
|
600
678
|
expect(auth.is_expired).toBe("true");
|
|
601
679
|
expect(auth.expired_at).toBe("2021-06-01");
|
|
680
|
+
expect(auth.app_key).toBe("SlackCLIAPI");
|
|
681
|
+
expect(auth.app_version).toBe("1.21.1");
|
|
682
|
+
});
|
|
683
|
+
it("should handle authentications with minimal fields", async () => {
|
|
684
|
+
const minimalAuth = {
|
|
685
|
+
data: [
|
|
686
|
+
{
|
|
687
|
+
id: "100",
|
|
688
|
+
account_id: "200",
|
|
689
|
+
implementation_id: "TestAPI@1.0.0",
|
|
690
|
+
},
|
|
691
|
+
],
|
|
692
|
+
nextCursor: undefined,
|
|
693
|
+
};
|
|
694
|
+
mockApiClient.get = vi.fn().mockResolvedValue(minimalAuth);
|
|
695
|
+
const sdk = createTestSdk();
|
|
696
|
+
const result = await sdk.listAuthentications({});
|
|
697
|
+
const auth = result.data[0];
|
|
698
|
+
expect(auth.id).toBe("100");
|
|
699
|
+
expect(auth.account_id).toBe("200");
|
|
700
|
+
expect(auth.implementation_id).toBe("TestAPI@1.0.0");
|
|
602
701
|
});
|
|
603
702
|
});
|
|
604
703
|
describe("context and metadata", () => {
|
|
@@ -608,5 +707,126 @@ describe("listAuthentications plugin", () => {
|
|
|
608
707
|
expect(context.meta.listAuthentications).toBeDefined();
|
|
609
708
|
expect(context.meta.listAuthentications.inputSchema).toBeDefined();
|
|
610
709
|
});
|
|
710
|
+
it("should include all required metadata properties", () => {
|
|
711
|
+
const sdk = createTestSdk();
|
|
712
|
+
const context = sdk.getContext();
|
|
713
|
+
const meta = context.meta.listAuthentications;
|
|
714
|
+
expect(meta.categories).toContain("authentication");
|
|
715
|
+
expect(meta.type).toBe("list");
|
|
716
|
+
expect(meta.itemType).toBe("Authentication");
|
|
717
|
+
expect(meta.inputSchema).toBeDefined();
|
|
718
|
+
expect(meta.outputSchema).toBeDefined();
|
|
719
|
+
expect(meta.resolvers).toBeDefined();
|
|
720
|
+
expect(meta.resolvers.appKey).toBeDefined();
|
|
721
|
+
});
|
|
722
|
+
});
|
|
723
|
+
describe("edge cases", () => {
|
|
724
|
+
it("should handle special characters in search parameter", async () => {
|
|
725
|
+
const sdk = createTestSdk();
|
|
726
|
+
await sdk.listAuthentications({ search: "test@email.com" });
|
|
727
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
728
|
+
searchParams: expect.objectContaining({
|
|
729
|
+
search: "test@email.com",
|
|
730
|
+
}),
|
|
731
|
+
}));
|
|
732
|
+
});
|
|
733
|
+
it("should handle special characters in title parameter", async () => {
|
|
734
|
+
const sdk = createTestSdk();
|
|
735
|
+
await sdk.listAuthentications({ title: "My Auth (Test) #1" });
|
|
736
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
737
|
+
searchParams: expect.objectContaining({
|
|
738
|
+
title: "My Auth (Test) #1",
|
|
739
|
+
}),
|
|
740
|
+
}));
|
|
741
|
+
});
|
|
742
|
+
it("should handle single authenticationId in array", async () => {
|
|
743
|
+
const sdk = createTestSdk();
|
|
744
|
+
await sdk.listAuthentications({ authenticationIds: ["single-id"] });
|
|
745
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
746
|
+
searchParams: expect.objectContaining({
|
|
747
|
+
authenticationIds: "single-id",
|
|
748
|
+
}),
|
|
749
|
+
}));
|
|
750
|
+
});
|
|
751
|
+
it("should handle multiple filters combined", async () => {
|
|
752
|
+
const sdk = createTestSdk();
|
|
753
|
+
await sdk.listAuthentications({
|
|
754
|
+
appKey: "slack",
|
|
755
|
+
search: "workspace",
|
|
756
|
+
title: "My Workspace",
|
|
757
|
+
accountId: "acc_123",
|
|
758
|
+
owner: "me",
|
|
759
|
+
authenticationIds: ["id1", "id2"],
|
|
760
|
+
pageSize: 10,
|
|
761
|
+
});
|
|
762
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
763
|
+
searchParams: expect.objectContaining({
|
|
764
|
+
appKey: "SlackCLIAPI",
|
|
765
|
+
search: "workspace",
|
|
766
|
+
title: "My Workspace",
|
|
767
|
+
accountId: "acc_123",
|
|
768
|
+
owner: "me",
|
|
769
|
+
authenticationIds: "id1,id2",
|
|
770
|
+
pageSize: "10",
|
|
771
|
+
}),
|
|
772
|
+
}));
|
|
773
|
+
});
|
|
774
|
+
it("should handle maxItems less than pageSize", async () => {
|
|
775
|
+
mockApiClient.get = vi.fn().mockResolvedValue({
|
|
776
|
+
data: mockAuthenticationsResponse.data,
|
|
777
|
+
nextCursor: "next-page",
|
|
778
|
+
});
|
|
779
|
+
const sdk = createTestSdk();
|
|
780
|
+
const items = [];
|
|
781
|
+
for await (const item of sdk
|
|
782
|
+
.listAuthentications({ pageSize: 10, maxItems: 1 })
|
|
783
|
+
.items()) {
|
|
784
|
+
items.push(item);
|
|
785
|
+
}
|
|
786
|
+
expect(items).toHaveLength(1);
|
|
787
|
+
// Should only make one API call even though there's a next page
|
|
788
|
+
expect(mockApiClient.get).toHaveBeenCalledTimes(1);
|
|
789
|
+
});
|
|
790
|
+
it("should handle owner filter with user ID instead of 'me'", async () => {
|
|
791
|
+
const sdk = createTestSdk();
|
|
792
|
+
await sdk.listAuthentications({ owner: "user_12345" });
|
|
793
|
+
expect(mockApiClient.get).toHaveBeenCalledWith("/api/v0/authentications", expect.objectContaining({
|
|
794
|
+
searchParams: expect.objectContaining({
|
|
795
|
+
owner: "user_12345",
|
|
796
|
+
}),
|
|
797
|
+
}));
|
|
798
|
+
});
|
|
799
|
+
it("should pass through nextCursor in response", async () => {
|
|
800
|
+
mockApiClient.get = vi.fn().mockResolvedValue({
|
|
801
|
+
data: mockAuthenticationsResponse.data,
|
|
802
|
+
nextCursor: "cursor-for-next-page",
|
|
803
|
+
});
|
|
804
|
+
const sdk = createTestSdk();
|
|
805
|
+
const result = await sdk.listAuthentications({});
|
|
806
|
+
expect(result.nextCursor).toBe("cursor-for-next-page");
|
|
807
|
+
});
|
|
808
|
+
it("should handle undefined nextCursor in response", async () => {
|
|
809
|
+
mockApiClient.get = vi.fn().mockResolvedValue({
|
|
810
|
+
data: mockAuthenticationsResponse.data,
|
|
811
|
+
nextCursor: undefined,
|
|
812
|
+
});
|
|
813
|
+
const sdk = createTestSdk();
|
|
814
|
+
const result = await sdk.listAuthentications({});
|
|
815
|
+
expect(result.nextCursor).toBeUndefined();
|
|
816
|
+
});
|
|
817
|
+
});
|
|
818
|
+
describe("concurrent requests", () => {
|
|
819
|
+
it("should handle multiple concurrent listAuthentications calls", async () => {
|
|
820
|
+
const sdk = createTestSdk();
|
|
821
|
+
const [result1, result2, result3] = await Promise.all([
|
|
822
|
+
sdk.listAuthentications({ search: "first" }),
|
|
823
|
+
sdk.listAuthentications({ search: "second" }),
|
|
824
|
+
sdk.listAuthentications({ search: "third" }),
|
|
825
|
+
]);
|
|
826
|
+
expect(result1.data).toHaveLength(2);
|
|
827
|
+
expect(result2.data).toHaveLength(2);
|
|
828
|
+
expect(result3.data).toHaveLength(2);
|
|
829
|
+
expect(mockApiClient.get).toHaveBeenCalledTimes(3);
|
|
830
|
+
});
|
|
611
831
|
});
|
|
612
832
|
});
|