@zapier/zapier-sdk 0.5.1 → 0.6.0

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.
Files changed (137) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +107 -83
  3. package/dist/api/index.d.ts +1 -1
  4. package/dist/api/index.d.ts.map +1 -1
  5. package/dist/api/schemas.d.ts +6 -6
  6. package/dist/api/types.d.ts +7 -7
  7. package/dist/api/types.d.ts.map +1 -1
  8. package/dist/index.cjs +343 -67
  9. package/dist/index.d.mts +416 -347
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +0 -1
  12. package/dist/index.mjs +343 -67
  13. package/dist/plugins/api/index.js +1 -1
  14. package/dist/plugins/apps/types.d.ts +1 -1
  15. package/dist/plugins/apps/types.d.ts.map +1 -1
  16. package/dist/plugins/findFirstAuthentication/index.d.ts.map +1 -1
  17. package/dist/plugins/findFirstAuthentication/index.js +1 -0
  18. package/dist/plugins/findUniqueAuthentication/index.d.ts.map +1 -1
  19. package/dist/plugins/findUniqueAuthentication/index.js +1 -0
  20. package/dist/plugins/getAction/index.d.ts.map +1 -1
  21. package/dist/plugins/getAction/index.js +1 -0
  22. package/dist/plugins/getAction/index.test.js +1 -1
  23. package/dist/plugins/getApp/index.d.ts +6 -3
  24. package/dist/plugins/getApp/index.d.ts.map +1 -1
  25. package/dist/plugins/getApp/index.js +8 -18
  26. package/dist/plugins/getApp/index.test.js +2 -0
  27. package/dist/plugins/getAuthentication/index.d.ts.map +1 -1
  28. package/dist/plugins/getAuthentication/index.js +1 -0
  29. package/dist/plugins/getAuthentication/index.test.js +12 -1
  30. package/dist/plugins/getProfile/index.d.ts.map +1 -1
  31. package/dist/plugins/getProfile/index.js +1 -0
  32. package/dist/plugins/listActions/index.d.ts +5 -3
  33. package/dist/plugins/listActions/index.d.ts.map +1 -1
  34. package/dist/plugins/listActions/index.js +6 -6
  35. package/dist/plugins/listActions/index.test.js +26 -74
  36. package/dist/plugins/listActions/schemas.d.ts +4 -4
  37. package/dist/plugins/listApps/index.d.ts.map +1 -1
  38. package/dist/plugins/listApps/index.js +1 -0
  39. package/dist/plugins/listApps/schemas.d.ts +2 -2
  40. package/dist/plugins/listAuthentications/index.d.ts +4 -2
  41. package/dist/plugins/listAuthentications/index.d.ts.map +1 -1
  42. package/dist/plugins/listAuthentications/index.js +9 -12
  43. package/dist/plugins/listAuthentications/index.test.js +33 -40
  44. package/dist/plugins/listAuthentications/schemas.d.ts +4 -4
  45. package/dist/plugins/listInputFields/index.d.ts +3 -1
  46. package/dist/plugins/listInputFields/index.d.ts.map +1 -1
  47. package/dist/plugins/listInputFields/index.js +5 -5
  48. package/dist/plugins/listInputFields/index.test.js +10 -8
  49. package/dist/plugins/listInputFields/schemas.d.ts +4 -4
  50. package/dist/plugins/lockVersion/index.d.ts +24 -0
  51. package/dist/plugins/lockVersion/index.d.ts.map +1 -0
  52. package/dist/plugins/lockVersion/index.js +72 -0
  53. package/dist/plugins/lockVersion/index.test.d.ts +2 -0
  54. package/dist/plugins/lockVersion/index.test.d.ts.map +1 -0
  55. package/dist/plugins/lockVersion/index.test.js +129 -0
  56. package/dist/plugins/lockVersion/schemas.d.ts +10 -0
  57. package/dist/plugins/lockVersion/schemas.d.ts.map +1 -0
  58. package/dist/plugins/lockVersion/schemas.js +6 -0
  59. package/dist/plugins/manifest/index.d.ts +24 -0
  60. package/dist/plugins/manifest/index.d.ts.map +1 -0
  61. package/dist/plugins/manifest/index.js +119 -0
  62. package/dist/plugins/manifest/index.test.d.ts +2 -0
  63. package/dist/plugins/manifest/index.test.d.ts.map +1 -0
  64. package/dist/plugins/manifest/index.test.js +331 -0
  65. package/dist/plugins/manifest/schemas.d.ts +64 -0
  66. package/dist/plugins/manifest/schemas.d.ts.map +1 -0
  67. package/dist/plugins/manifest/schemas.js +25 -0
  68. package/dist/plugins/registry/index.d.ts +9 -1
  69. package/dist/plugins/registry/index.d.ts.map +1 -1
  70. package/dist/plugins/registry/index.js +68 -3
  71. package/dist/plugins/request/index.d.ts.map +1 -1
  72. package/dist/plugins/request/index.js +1 -0
  73. package/dist/plugins/request/index.test.js +6 -1
  74. package/dist/plugins/request/schemas.d.ts +4 -4
  75. package/dist/plugins/runAction/index.d.ts +2 -0
  76. package/dist/plugins/runAction/index.d.ts.map +1 -1
  77. package/dist/plugins/runAction/index.js +5 -5
  78. package/dist/plugins/runAction/index.test.js +9 -8
  79. package/dist/plugins/runAction/schemas.d.ts +4 -4
  80. package/dist/schemas/Auth.d.ts +4 -4
  81. package/dist/schemas/Field.d.ts.map +1 -1
  82. package/dist/sdk.d.ts +3 -3
  83. package/dist/sdk.d.ts.map +1 -1
  84. package/dist/sdk.js +18 -7
  85. package/dist/sdk.test.js +1 -1
  86. package/dist/types/errors.d.ts +6 -6
  87. package/dist/types/errors.d.ts.map +1 -1
  88. package/dist/types/events.d.ts +1 -1
  89. package/dist/types/events.d.ts.map +1 -1
  90. package/dist/types/plugin.d.ts +10 -2
  91. package/dist/types/plugin.d.ts.map +1 -1
  92. package/dist/types/sdk.d.ts +13 -2
  93. package/dist/types/sdk.d.ts.map +1 -1
  94. package/dist/utils/validation.test.js +2 -1
  95. package/package.json +2 -2
  96. package/src/api/client.ts +3 -3
  97. package/src/api/index.ts +2 -0
  98. package/src/api/types.ts +15 -7
  99. package/src/index.ts +0 -2
  100. package/src/plugins/api/index.ts +1 -1
  101. package/src/plugins/apps/types.ts +1 -1
  102. package/src/plugins/findFirstAuthentication/index.ts +1 -0
  103. package/src/plugins/findUniqueAuthentication/index.ts +1 -0
  104. package/src/plugins/getAction/index.test.ts +1 -1
  105. package/src/plugins/getAction/index.ts +1 -0
  106. package/src/plugins/getApp/index.test.ts +2 -0
  107. package/src/plugins/getApp/index.ts +12 -24
  108. package/src/plugins/getAuthentication/index.test.ts +13 -3
  109. package/src/plugins/getAuthentication/index.ts +1 -0
  110. package/src/plugins/getProfile/index.ts +1 -0
  111. package/src/plugins/listActions/index.test.ts +30 -89
  112. package/src/plugins/listActions/index.ts +34 -27
  113. package/src/plugins/listApps/index.ts +1 -0
  114. package/src/plugins/listAuthentications/index.test.ts +38 -47
  115. package/src/plugins/listAuthentications/index.ts +21 -18
  116. package/src/plugins/listInputFields/index.test.ts +12 -9
  117. package/src/plugins/listInputFields/index.ts +10 -6
  118. package/src/plugins/lockVersion/index.test.ts +176 -0
  119. package/src/plugins/lockVersion/index.ts +112 -0
  120. package/src/plugins/lockVersion/schemas.ts +9 -0
  121. package/src/plugins/manifest/index.test.ts +439 -0
  122. package/src/plugins/manifest/index.ts +171 -0
  123. package/src/plugins/manifest/schemas.ts +53 -0
  124. package/src/plugins/registry/index.ts +89 -8
  125. package/src/plugins/request/index.test.ts +8 -4
  126. package/src/plugins/request/index.ts +1 -0
  127. package/src/plugins/runAction/index.test.ts +9 -8
  128. package/src/plugins/runAction/index.ts +18 -9
  129. package/src/schemas/Field.ts +5 -2
  130. package/src/sdk.test.ts +1 -1
  131. package/src/sdk.ts +22 -7
  132. package/src/types/errors.ts +9 -6
  133. package/src/types/events.ts +1 -1
  134. package/src/types/plugin.ts +14 -2
  135. package/src/types/sdk.ts +15 -1
  136. package/src/utils/validation.test.ts +2 -1
  137. package/tsconfig.tsbuildinfo +1 -1
@@ -4,8 +4,9 @@ import { GetAppSchema } from "./schemas";
4
4
  import type { GetAppOptions } from "./schemas";
5
5
  import type { AppItem } from "../../types/domain";
6
6
  import { ZapierAppNotFoundError } from "../../types/errors";
7
- import type { ListAppsPluginProvides } from "../listApps";
8
7
  import type { GetSdkType } from "../../types/plugin";
8
+ import { GetImplementation } from "../manifest/schemas";
9
+ import { ManifestPluginProvides } from "../manifest";
9
10
 
10
11
  // GetApp plugin provides interface - getApp goes directly to SDK root
11
12
  export interface GetAppPluginProvides {
@@ -21,34 +22,20 @@ export interface GetAppPluginProvides {
21
22
 
22
23
  // GetApp plugin depends on listApps SDK function
23
24
  export const getAppPlugin: Plugin<
24
- GetSdkType<ListAppsPluginProvides>, // depends on listApps
25
- {}, // no additional context dependencies
25
+ GetSdkType<ManifestPluginProvides>, // depends on manifest plugin with getImplementation in context
26
+ { getImplementation: GetImplementation }, //
26
27
  GetAppPluginProvides
27
- > = ({ sdk }) => {
28
+ > = ({ context }) => {
28
29
  const getApp = createFunction(async function getApp(options: GetAppOptions) {
29
- const { appKey } = options;
30
-
31
- // Use listApps to get the app by key
32
- const appsIterator = sdk
33
- .listApps({
34
- ...options,
35
- appKeys: [appKey],
36
- })
37
- .items();
38
-
39
- // Get the first (and should be only) result
40
- const apps = [];
41
- for await (const app of appsIterator) {
42
- apps.push(app);
43
- break; // Only need the first result
44
- }
45
-
46
- if (apps.length === 0) {
47
- throw new ZapierAppNotFoundError(appKey);
30
+ const app = await context.getImplementation(options.appKey);
31
+ if (!app) {
32
+ throw new ZapierAppNotFoundError("App not found", {
33
+ appKey: options.appKey,
34
+ });
48
35
  }
49
36
 
50
37
  return {
51
- data: apps[0],
38
+ data: app,
52
39
  };
53
40
  }, GetAppSchema);
54
41
 
@@ -58,6 +45,7 @@ export const getAppPlugin: Plugin<
58
45
  context: {
59
46
  meta: {
60
47
  getApp: {
48
+ categories: ["app"],
61
49
  inputSchema: GetAppSchema,
62
50
  },
63
51
  },
@@ -9,6 +9,8 @@ import { createSdk } from "../../sdk";
9
9
  import type { ApiClient } from "../../api";
10
10
  import type { GetAuthenticationOptions } from "./schemas";
11
11
  import type { Authentication } from "../../api/types";
12
+ import { manifestPlugin } from "../manifest";
13
+ import { listAppsPlugin } from "../listApps";
12
14
 
13
15
  const mockAuthenticationResponse: Authentication = {
14
16
  id: 123,
@@ -34,10 +36,18 @@ describe("getAuthentication plugin", () => {
34
36
  } as Partial<ApiClient> as ApiClient;
35
37
  });
36
38
 
39
+ const apiPlugin = () => ({
40
+ context: {
41
+ api: mockApiClient,
42
+ },
43
+ });
44
+
37
45
  function createTestSdk() {
38
- return createSdk({}, { api: mockApiClient, meta: {} }).addPlugin(
39
- getAuthenticationPlugin,
40
- );
46
+ return createSdk()
47
+ .addPlugin(apiPlugin)
48
+ .addPlugin(listAppsPlugin)
49
+ .addPlugin(manifestPlugin)
50
+ .addPlugin(getAuthenticationPlugin);
41
51
  }
42
52
 
43
53
  describe("schema validation", () => {
@@ -78,6 +78,7 @@ export const getAuthenticationPlugin: Plugin<
78
78
  context: {
79
79
  meta: {
80
80
  getAuthentication: {
81
+ categories: ["authentication"],
81
82
  inputSchema: GetAuthenticationSchema,
82
83
  },
83
84
  },
@@ -47,6 +47,7 @@ export const getProfilePlugin: Plugin<
47
47
  context: {
48
48
  meta: {
49
49
  getProfile: {
50
+ categories: ["user"],
50
51
  inputSchema: GetProfileSchema,
51
52
  },
52
53
  },
@@ -8,19 +8,8 @@ import { listActionsPlugin } from "./index";
8
8
  import { createSdk } from "../../sdk";
9
9
  import type { ApiClient } from "../../api";
10
10
  import type { ListActionsOptions } from "./schemas";
11
- import { App } from "../../api/types";
12
- import { GetAppSchema } from "../getApp/schemas";
13
-
14
- const mockAppResponse = {
15
- data: {
16
- slug: "slack",
17
- name: "Slack",
18
- current_implementation_id: "SlackCLIAPI@1.20.0",
19
- key: "slack",
20
- title: "Slack",
21
- hex_color: "#4A154B",
22
- } as Partial<App> as App & { key: string; title: string; hex_color: string },
23
- };
11
+
12
+ import { listAppsPlugin } from "../listApps";
24
13
 
25
14
  const mockImplementationsResponse = {
26
15
  results: [
@@ -66,7 +55,7 @@ const mockEmptyImplementationsResponse = {
66
55
 
67
56
  describe("listActions plugin", () => {
68
57
  let mockApiClient: ApiClient;
69
- let mockGetApp: any;
58
+ let mockGetVersionedImplementationId: any;
70
59
 
71
60
  beforeEach(() => {
72
61
  vi.clearAllMocks();
@@ -74,25 +63,31 @@ describe("listActions plugin", () => {
74
63
  get: vi.fn().mockResolvedValue(mockImplementationsResponse),
75
64
  } as Partial<ApiClient> as ApiClient;
76
65
 
77
- mockGetApp = vi.fn().mockResolvedValue(mockAppResponse);
66
+ mockGetVersionedImplementationId = vi
67
+ .fn()
68
+ .mockResolvedValue("SlackCLIAPI@1.21.1");
78
69
  });
79
70
 
80
71
  function createTestSdk() {
81
72
  // Create a proper plugin chain with context dependencies
82
- const mockGetAppPlugin = () => ({
83
- getApp: mockGetApp,
84
- context: {
85
- meta: {
86
- getApp: {
87
- inputSchema: GetAppSchema,
88
- },
89
- },
90
- },
91
- });
92
73
 
93
74
  // Build SDK with proper plugin composition, providing API in initial context
94
- return createSdk({}, { api: mockApiClient, meta: {} })
95
- .addPlugin(mockGetAppPlugin)
75
+ return createSdk()
76
+ .addPlugin(() => ({
77
+ context: {
78
+ api: mockApiClient,
79
+ getVersionedImplementationId: mockGetVersionedImplementationId,
80
+ },
81
+ }))
82
+ .addPlugin(listAppsPlugin)
83
+ .addPlugin(() => ({
84
+ context: {
85
+ manifest: null,
86
+ getManifestEntry: () => null,
87
+ getVersionedImplementationId: mockGetVersionedImplementationId,
88
+ getImplementation: () => Promise.resolve(null),
89
+ },
90
+ }))
96
91
  .addPlugin(listActionsPlugin);
97
92
  }
98
93
 
@@ -401,9 +396,7 @@ describe("listActions plugin", () => {
401
396
  const sdk = createTestSdk();
402
397
  await sdk.listActions({ appKey: "slack" });
403
398
 
404
- expect(mockGetApp).toHaveBeenCalledWith({
405
- appKey: "slack",
406
- });
399
+ expect(mockGetVersionedImplementationId).toHaveBeenCalledWith("slack");
407
400
  });
408
401
 
409
402
  it("should pass correct search parameters to implementations API", async () => {
@@ -416,7 +409,7 @@ describe("listActions plugin", () => {
416
409
  searchParams: expect.objectContaining({
417
410
  global: "true",
418
411
  public_only: "true",
419
- selected_apis: "SlackCLIAPI", // Extracted from current_implementation_id
412
+ selected_apis: "SlackCLIAPI@1.21.1",
420
413
  }),
421
414
  }),
422
415
  );
@@ -425,12 +418,7 @@ describe("listActions plugin", () => {
425
418
 
426
419
  describe("error handling", () => {
427
420
  it("should throw ZapierConfigurationError when app has no current_implementation_id", async () => {
428
- mockGetApp.mockResolvedValue({
429
- data: {
430
- ...mockAppResponse.data,
431
- current_implementation_id: undefined, // Missing implementation ID
432
- },
433
- });
421
+ mockGetVersionedImplementationId.mockResolvedValue(null);
434
422
 
435
423
  const sdk = createTestSdk();
436
424
  await expect(sdk.listActions({ appKey: "slack" })).rejects.toThrow(
@@ -439,12 +427,7 @@ describe("listActions plugin", () => {
439
427
  });
440
428
 
441
429
  it("should throw ZapierConfigurationError when current_implementation_id is empty", async () => {
442
- mockGetApp.mockResolvedValue({
443
- data: {
444
- ...mockAppResponse.data,
445
- current_implementation_id: "", // Empty implementation ID
446
- },
447
- });
430
+ mockGetVersionedImplementationId.mockResolvedValue("");
448
431
 
449
432
  const sdk = createTestSdk();
450
433
  await expect(sdk.listActions({ appKey: "slack" })).rejects.toThrow(
@@ -516,8 +499,10 @@ describe("listActions plugin", () => {
516
499
  expect(result.data).toHaveLength(0);
517
500
  });
518
501
 
519
- it("should propagate getApp errors", async () => {
520
- mockGetApp.mockRejectedValue(new Error("App not found"));
502
+ it("should propagate getVersionedImplementationId errors", async () => {
503
+ mockGetVersionedImplementationId.mockRejectedValue(
504
+ new Error("App not found"),
505
+ );
521
506
 
522
507
  const sdk = createTestSdk();
523
508
  await expect(sdk.listActions({ appKey: "nonexistent" })).rejects.toThrow(
@@ -526,50 +511,6 @@ describe("listActions plugin", () => {
526
511
  });
527
512
  });
528
513
 
529
- describe("implementation ID extraction", () => {
530
- it("should extract implementation name from versioned ID", async () => {
531
- mockGetApp.mockResolvedValue({
532
- data: {
533
- ...mockAppResponse.data,
534
- current_implementation_id: "CustomAPIName@2.5.0",
535
- },
536
- });
537
-
538
- const sdk = createTestSdk();
539
- await sdk.listActions({ appKey: "slack" });
540
-
541
- expect(mockApiClient.get).toHaveBeenCalledWith(
542
- "/api/v4/implementations/",
543
- expect.objectContaining({
544
- searchParams: expect.objectContaining({
545
- selected_apis: "CustomAPIName", // Extracted name without version
546
- }),
547
- }),
548
- );
549
- });
550
-
551
- it("should handle implementation ID without version", async () => {
552
- mockGetApp.mockResolvedValue({
553
- data: {
554
- ...mockAppResponse.data,
555
- current_implementation_id: "PlainAPIName",
556
- },
557
- });
558
-
559
- const sdk = createTestSdk();
560
- await sdk.listActions({ appKey: "slack" });
561
-
562
- expect(mockApiClient.get).toHaveBeenCalledWith(
563
- "/api/v4/implementations/",
564
- expect.objectContaining({
565
- searchParams: expect.objectContaining({
566
- selected_apis: "PlainAPIName", // Used as-is
567
- }),
568
- }),
569
- );
570
- });
571
- });
572
-
573
514
  describe("context and metadata", () => {
574
515
  it("should provide context with meta information", () => {
575
516
  const sdk = createTestSdk();
@@ -1,5 +1,5 @@
1
1
  import type { Plugin, GetSdkType } from "../../types/plugin";
2
- import type { ApiClient } from "../../api";
2
+ import type { ApiClient, Implementation } from "../../api";
3
3
  import type { ActionItem } from "../../types/domain";
4
4
  import { normalizeActionItem } from "../../utils/domain-utils";
5
5
  import {
@@ -12,7 +12,8 @@ import {
12
12
  ZapierAuthenticationError,
13
13
  } from "../../types/errors";
14
14
  import { createPaginatedFunction } from "../../utils/function-utils";
15
- import type { GetAppPluginProvides } from "../getApp";
15
+ import { ManifestPluginProvides } from "../manifest";
16
+ import { GetVersionedImplementationId } from "../manifest/schemas";
16
17
 
17
18
  export interface ListActionsPluginProvides {
18
19
  listActions: (options?: ListActionsOptions) => Promise<{
@@ -31,20 +32,22 @@ export interface ListActionsPluginProvides {
31
32
  }
32
33
 
33
34
  export const listActionsPlugin: Plugin<
34
- GetSdkType<GetAppPluginProvides>, // requires getApp in SDK
35
- { api: ApiClient }, // requires api in context
35
+ GetSdkType<ManifestPluginProvides>, // requires getApp in SDK
36
+ {
37
+ api: ApiClient;
38
+ getVersionedImplementationId: GetVersionedImplementationId;
39
+ }, // requires api and getVersionedImplementationId in context
36
40
  ListActionsPluginProvides
37
- > = ({ sdk, context }) => {
41
+ > = ({ context }) => {
38
42
  const listActions = createPaginatedFunction(async function listActionsPage(
39
43
  options: ListActionsOptions & { cursor?: string } & { pageSize: number },
40
44
  ): Promise<ListActionsPage> {
41
- const { api } = context;
45
+ const { api, getVersionedImplementationId } = context;
42
46
 
43
47
  // Use the getApp function from the SDK (dependency injection)
44
- const app = await sdk.getApp({ appKey: options.appKey });
48
+ const selectedApi = await getVersionedImplementationId(options.appKey);
45
49
 
46
- const implementationId = app.data.current_implementation_id?.split("@")[0];
47
- if (!implementationId) {
50
+ if (!selectedApi) {
48
51
  throw new ZapierConfigurationError(
49
52
  "No current_implementation_id found for app",
50
53
  { configType: "current_implementation_id" },
@@ -54,27 +57,30 @@ export const listActionsPlugin: Plugin<
54
57
  const searchParams: Record<string, string> = {
55
58
  global: "true",
56
59
  public_only: "true",
57
- selected_apis: implementationId,
60
+ selected_apis: selectedApi,
58
61
  };
59
62
 
60
- const data = await api.get("/api/v4/implementations/", {
61
- searchParams,
62
- customErrorHandler: ({ status }) => {
63
- if (status === 401) {
64
- return new ZapierAuthenticationError(
65
- `Authentication failed. Your token may not have permission to access implementations or may be expired. (HTTP ${status})`,
66
- { statusCode: status },
67
- );
68
- }
69
- if (status === 403) {
70
- return new ZapierAuthenticationError(
71
- `Access forbidden. Your token may not have the required scopes to list implementations. (HTTP ${status})`,
72
- { statusCode: status },
73
- );
74
- }
75
- return undefined;
63
+ const data = await api.get<{ results: Implementation[] }>(
64
+ "/api/v4/implementations/",
65
+ {
66
+ searchParams,
67
+ customErrorHandler: ({ status }) => {
68
+ if (status === 401) {
69
+ return new ZapierAuthenticationError(
70
+ `Authentication failed. Your token may not have permission to access implementations or may be expired. (HTTP ${status})`,
71
+ { statusCode: status },
72
+ );
73
+ }
74
+ if (status === 403) {
75
+ return new ZapierAuthenticationError(
76
+ `Access forbidden. Your token may not have the required scopes to list implementations. (HTTP ${status})`,
77
+ { statusCode: status },
78
+ );
79
+ }
80
+ return undefined;
81
+ },
76
82
  },
77
- });
83
+ );
78
84
 
79
85
  let allActions: ActionItem[] = [];
80
86
 
@@ -107,6 +113,7 @@ export const listActionsPlugin: Plugin<
107
113
  context: {
108
114
  meta: {
109
115
  listActions: {
116
+ categories: ["action"],
110
117
  inputSchema: ListActionsSchema,
111
118
  },
112
119
  },
@@ -113,6 +113,7 @@ export const listAppsPlugin: Plugin<
113
113
  context: {
114
114
  meta: {
115
115
  listApps: {
116
+ categories: ["app"],
116
117
  inputSchema: ListAppsSchema,
117
118
  },
118
119
  },
@@ -6,7 +6,7 @@ import {
6
6
  import { listAuthenticationsPlugin } from "./index";
7
7
  import { createSdk } from "../../sdk";
8
8
  import type { ApiClient } from "../../api";
9
- import type { App } from "../../api/types";
9
+ import type { AppItem } from "../../types/domain";
10
10
 
11
11
  const mockAuthenticationsResponse = {
12
12
  results: [
@@ -42,29 +42,18 @@ const mockAuthenticationsResponse = {
42
42
  previous: null,
43
43
  };
44
44
 
45
- const mockSlackApp = {
46
- data: {
47
- id: 1,
48
- key: "slack",
49
- title: "Slack",
50
- hex_color: "#000000",
51
- age_in_days: "100",
52
- api_docs_url: "https://slack.com/api-docs",
53
- app_profile_url: "https://slack.com",
54
- banner: "https://slack.com/banner.png",
55
- categories: [],
56
- canonical_id: "slack",
57
- zap_usage_count: 100,
58
- zap_usage_count_last_updated: "2021-01-01",
59
- zap_usage_count_last_updated_by: "user1",
60
- zap_usage_count_last_updated_by_id: 123,
61
- current_implementation_id: "SlackCLIAPI@1.21.1",
62
- } as Partial<App> as App,
45
+ const mockSlackApp: AppItem = {
46
+ title: "Slack",
47
+ key: "SlackCLIAPI",
48
+ current_implementation_id: "SlackCLIAPI@1.21.1",
49
+ version: "1.21.1",
50
+ description: "Team communication platform",
51
+ slug: "slack",
63
52
  };
64
53
 
65
54
  describe("listAuthentications plugin", () => {
66
55
  let mockApiClient: ApiClient;
67
- let mockGetApp: any;
56
+ let mockGetVersionedImplementationId: any;
68
57
 
69
58
  beforeEach(() => {
70
59
  vi.clearAllMocks();
@@ -72,14 +61,34 @@ describe("listAuthentications plugin", () => {
72
61
  get: vi.fn().mockResolvedValue(mockAuthenticationsResponse),
73
62
  } as Partial<ApiClient> as ApiClient;
74
63
 
75
- mockGetApp = vi.fn().mockResolvedValue(mockSlackApp);
64
+ mockGetVersionedImplementationId = vi
65
+ .fn()
66
+ .mockResolvedValue("SlackCLIAPI@1.21.1");
67
+ });
68
+
69
+ const apiPlugin = () => ({
70
+ context: {
71
+ api: mockApiClient,
72
+ },
73
+ });
74
+
75
+ const manifestPlugin = () => ({
76
+ context: {
77
+ manifest: null,
78
+ getVersionedImplementationId: mockGetVersionedImplementationId,
79
+ getManifestEntry: () => ({
80
+ implementationName: "SlackCLIAPI",
81
+ version: "1.21.1",
82
+ }),
83
+ getImplementation: vi.fn().mockResolvedValue(mockSlackApp),
84
+ },
76
85
  });
77
86
 
78
87
  function createTestSdk() {
79
- return createSdk(
80
- { getApp: mockGetApp }, // Provide getApp in SDK
81
- { api: mockApiClient, meta: {} },
82
- ).addPlugin(listAuthenticationsPlugin as any);
88
+ return createSdk()
89
+ .addPlugin(apiPlugin)
90
+ .addPlugin(manifestPlugin)
91
+ .addPlugin(listAuthenticationsPlugin);
83
92
  }
84
93
 
85
94
  describe("schema validation", () => {
@@ -129,7 +138,7 @@ describe("listAuthentications plugin", () => {
129
138
  const sdk = createTestSdk();
130
139
  expect(() => {
131
140
  sdk.listAuthentications({
132
- account_id: 123,
141
+ account_id: 123 as any,
133
142
  });
134
143
  }).toThrow(ZapierValidationError);
135
144
  });
@@ -192,7 +201,7 @@ describe("listAuthentications plugin", () => {
192
201
  describe("data mapping", () => {
193
202
  it("should map is_stale to is_expired and marked_stale_at to expired_at", async () => {
194
203
  const sdk = createTestSdk();
195
- const result = await sdk.listAuthentications({});
204
+ const result = await sdk.listAuthentications();
196
205
 
197
206
  expect(result.data[0].is_expired).toBe("false");
198
207
  expect(result.data[0].expired_at).toBe(null);
@@ -582,16 +591,7 @@ describe("listAuthentications plugin", () => {
582
591
 
583
592
  describe("app key integration", () => {
584
593
  it("should handle app without current_implementation_id", async () => {
585
- const appWithoutImplementation = {
586
- data: {
587
- id: 123,
588
- key: "slack",
589
- title: "Slack",
590
- current_implementation_id: undefined,
591
- } as Partial<App> as App,
592
- };
593
-
594
- mockGetApp.mockResolvedValue(appWithoutImplementation);
594
+ mockGetVersionedImplementationId.mockResolvedValue(null);
595
595
 
596
596
  const sdk = createTestSdk();
597
597
  await sdk.listAuthentications({ appKey: "slack" });
@@ -608,16 +608,7 @@ describe("listAuthentications plugin", () => {
608
608
  });
609
609
 
610
610
  it("should extract versionless API from versioned implementation ID", async () => {
611
- const appWithVersionedApi = {
612
- data: {
613
- id: 123,
614
- key: "slack",
615
- title: "Slack",
616
- current_implementation_id: "SlackCLIAPI@2.1.3",
617
- } as Partial<App> as App,
618
- };
619
-
620
- mockGetApp.mockResolvedValue(appWithVersionedApi);
611
+ mockGetVersionedImplementationId.mockResolvedValue("SlackCLIAPI@2.1.3");
621
612
 
622
613
  const sdk = createTestSdk();
623
614
  await sdk.listAuthentications({ appKey: "slack" });
@@ -7,13 +7,17 @@ import {
7
7
  type ListAuthenticationsOptions,
8
8
  type ListAuthenticationsPage,
9
9
  } from "./schemas";
10
- import { normalizeAuthenticationItem } from "../../utils/domain-utils";
10
+ import {
11
+ normalizeAuthenticationItem,
12
+ splitVersionedKey,
13
+ } from "../../utils/domain-utils";
11
14
  import { ZapierAuthenticationError } from "../../types/errors";
12
15
  import {
13
16
  createPaginatedFunction,
14
17
  extractCursor,
15
18
  } from "../../utils/function-utils";
16
- import type { GetAppPluginProvides } from "../getApp";
19
+ import { GetVersionedImplementationId } from "../manifest/schemas";
20
+ import { ManifestPluginProvides } from "../manifest";
17
21
 
18
22
  export interface ListAuthenticationsPluginProvides {
19
23
  listAuthentications: (options?: ListAuthenticationsOptions) => Promise<{
@@ -32,33 +36,31 @@ export interface ListAuthenticationsPluginProvides {
32
36
  }
33
37
 
34
38
  export const listAuthenticationsPlugin: Plugin<
35
- GetSdkType<GetAppPluginProvides>, // requires getApp in SDK
36
- { api: ApiClient }, // requires api in context
39
+ GetSdkType<ManifestPluginProvides>, // requires getApp in SDK
40
+ {
41
+ api: ApiClient;
42
+ getVersionedImplementationId: GetVersionedImplementationId;
43
+ }, // requires api in context
37
44
  ListAuthenticationsPluginProvides
38
- > = ({ sdk, context }) => {
45
+ > = ({ context }) => {
39
46
  const listAuthentications = createPaginatedFunction(
40
47
  async function listAuthenticationsPage(
41
48
  options: ListAuthenticationsOptions & { cursor?: string } & {
42
49
  pageSize: number;
43
50
  },
44
51
  ): Promise<ListAuthenticationsPage> {
45
- const { api } = context;
46
-
52
+ const { api, getVersionedImplementationId } = context;
47
53
  // Build search parameters
48
54
  const searchParams: Record<string, string> = {};
49
55
 
50
56
  // Handle appKey filtering by getting the selected_api first
51
57
  if (options.appKey) {
52
- const app = await sdk.getApp({
53
- appKey: options.appKey,
54
- });
55
-
56
- const selectedApi = app.data.current_implementation_id;
57
- if (selectedApi) {
58
- // Use versionless_selected_api to find auths across all app versions
59
- // Extract the base name without the version (e.g., "SlackCLIAPI" from "SlackCLIAPI@1.21.1")
60
- const versionlessApi = selectedApi.split("@")[0];
61
- searchParams.versionless_selected_api = versionlessApi;
58
+ const implementationId = await getVersionedImplementationId(
59
+ options.appKey,
60
+ );
61
+ if (implementationId) {
62
+ const [versionlessSelectedApi] = splitVersionedKey(implementationId);
63
+ searchParams.versionless_selected_api = versionlessSelectedApi;
62
64
  }
63
65
  }
64
66
 
@@ -81,7 +83,7 @@ export const listAuthenticationsPlugin: Plugin<
81
83
  // Convert cursor back to offset for the API
82
84
  searchParams.offset = options.cursor;
83
85
  }
84
-
86
+ console.log({ searchParams });
85
87
  const data: AuthenticationsResponse = await api.get(
86
88
  "/api/v4/authentications/",
87
89
  {
@@ -128,6 +130,7 @@ export const listAuthenticationsPlugin: Plugin<
128
130
  context: {
129
131
  meta: {
130
132
  listAuthentications: {
133
+ categories: ["authentication"],
131
134
  inputSchema: ListAuthenticationsSchema,
132
135
  },
133
136
  },
@@ -47,7 +47,7 @@ const mockNeedsResponse: NeedsResponse = {
47
47
 
48
48
  describe("listInputFields plugin", () => {
49
49
  let mockApiClient: ApiClient;
50
- let mockGetApp: any;
50
+ let mockGetVersionedImplementationId: any;
51
51
 
52
52
  beforeEach(() => {
53
53
  vi.clearAllMocks();
@@ -55,15 +55,20 @@ describe("listInputFields plugin", () => {
55
55
  post: vi.fn().mockResolvedValue(mockNeedsResponse),
56
56
  } as Partial<ApiClient> as ApiClient;
57
57
 
58
- mockGetApp = vi.fn().mockResolvedValue({
59
- data: { current_implementation_id: "SlackCLIAPI@1.21.1" },
60
- });
58
+ mockGetVersionedImplementationId = vi
59
+ .fn()
60
+ .mockResolvedValue("SlackCLIAPI@1.21.1");
61
61
  });
62
62
 
63
63
  function createTestSdk() {
64
64
  return createSdk(
65
- { getApp: mockGetApp },
66
- { api: mockApiClient, meta: {} },
65
+ {},
66
+ {},
67
+ {
68
+ api: mockApiClient,
69
+ meta: {},
70
+ getVersionedImplementationId: mockGetVersionedImplementationId,
71
+ },
67
72
  ).addPlugin(listInputFieldsPlugin as any);
68
73
  }
69
74
 
@@ -303,9 +308,7 @@ describe("listInputFields plugin", () => {
303
308
 
304
309
  describe("error handling", () => {
305
310
  it("should throw ZapierConfigurationError when app has no current_implementation_id", async () => {
306
- mockGetApp.mockResolvedValue({
307
- data: { current_implementation_id: undefined },
308
- });
311
+ mockGetVersionedImplementationId.mockResolvedValue(null);
309
312
 
310
313
  const sdk = createTestSdk();
311
314
  await expect(