@zapier/zapier-sdk 0.18.3 → 1.0.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 (112) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +1 -1
  3. package/dist/api/client.d.ts.map +1 -1
  4. package/dist/api/client.js +11 -24
  5. package/dist/api/client.test.js +82 -27
  6. package/dist/api/index.d.ts +3 -2
  7. package/dist/api/index.d.ts.map +1 -1
  8. package/dist/api/index.js +2 -3
  9. package/dist/api/schemas.d.ts +5 -114
  10. package/dist/api/schemas.d.ts.map +1 -1
  11. package/dist/api/schemas.js +0 -67
  12. package/dist/api/types.d.ts +10 -4
  13. package/dist/api/types.d.ts.map +1 -1
  14. package/dist/auth.d.ts +54 -26
  15. package/dist/auth.d.ts.map +1 -1
  16. package/dist/auth.js +211 -39
  17. package/dist/auth.test.js +338 -64
  18. package/dist/constants.d.ts +14 -0
  19. package/dist/constants.d.ts.map +1 -1
  20. package/dist/constants.js +14 -0
  21. package/dist/credentials.d.ts +57 -0
  22. package/dist/credentials.d.ts.map +1 -0
  23. package/dist/credentials.js +174 -0
  24. package/dist/index.cjs +644 -685
  25. package/dist/index.d.mts +265 -134
  26. package/dist/index.d.ts +3 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +5 -0
  29. package/dist/index.mjs +624 -684
  30. package/dist/plugins/api/index.d.ts +2 -0
  31. package/dist/plugins/api/index.d.ts.map +1 -1
  32. package/dist/plugins/api/index.js +8 -4
  33. package/dist/plugins/eventEmission/index.d.ts.map +1 -1
  34. package/dist/plugins/eventEmission/index.js +1 -3
  35. package/dist/plugins/eventEmission/index.test.js +14 -17
  36. package/dist/plugins/getAction/schemas.d.ts +1 -1
  37. package/dist/plugins/getInputFieldsSchema/schemas.d.ts +1 -1
  38. package/dist/plugins/listActions/index.test.js +1 -0
  39. package/dist/plugins/listActions/schemas.d.ts +1 -1
  40. package/dist/plugins/listApps/index.d.ts +2 -8
  41. package/dist/plugins/listApps/index.d.ts.map +1 -1
  42. package/dist/plugins/listApps/index.js +4 -6
  43. package/dist/plugins/listApps/index.test.js +62 -82
  44. package/dist/plugins/listApps/schemas.d.ts +35 -14
  45. package/dist/plugins/listApps/schemas.d.ts.map +1 -1
  46. package/dist/plugins/listApps/schemas.js +44 -14
  47. package/dist/plugins/listAuthentications/index.test.js +16 -0
  48. package/dist/plugins/listInputFieldChoices/schemas.d.ts +1 -1
  49. package/dist/plugins/listInputFields/schemas.d.ts +1 -1
  50. package/dist/plugins/runAction/schemas.d.ts +1 -1
  51. package/dist/schemas/Action.d.ts +1 -1
  52. package/dist/schemas/App.d.ts +28 -28
  53. package/dist/schemas/App.d.ts.map +1 -1
  54. package/dist/schemas/App.js +3 -8
  55. package/dist/sdk.d.ts +2 -1
  56. package/dist/sdk.d.ts.map +1 -1
  57. package/dist/sdk.test.js +17 -13
  58. package/dist/types/credentials.d.ts +65 -0
  59. package/dist/types/credentials.d.ts.map +1 -0
  60. package/dist/types/credentials.js +42 -0
  61. package/dist/types/properties.d.ts +1 -1
  62. package/dist/types/sdk.d.ts +12 -3
  63. package/dist/types/sdk.d.ts.map +1 -1
  64. package/dist/utils/logging.d.ts +13 -0
  65. package/dist/utils/logging.d.ts.map +1 -0
  66. package/dist/utils/logging.js +20 -0
  67. package/package.json +2 -2
  68. package/dist/api/client.integration.test.d.ts +0 -5
  69. package/dist/api/client.integration.test.d.ts.map +0 -1
  70. package/dist/api/client.integration.test.js +0 -318
  71. package/dist/api/client.methods.test.d.ts +0 -2
  72. package/dist/api/client.methods.test.d.ts.map +0 -1
  73. package/dist/api/client.methods.test.js +0 -158
  74. package/dist/api/router.d.ts +0 -16
  75. package/dist/api/router.d.ts.map +0 -1
  76. package/dist/api/router.js +0 -31
  77. package/dist/api/router.test.d.ts +0 -2
  78. package/dist/api/router.test.d.ts.map +0 -1
  79. package/dist/api/router.test.js +0 -103
  80. package/dist/temporary-internal-core/handlers/listApps.d.ts +0 -67
  81. package/dist/temporary-internal-core/handlers/listApps.d.ts.map +0 -1
  82. package/dist/temporary-internal-core/handlers/listApps.js +0 -134
  83. package/dist/temporary-internal-core/handlers/listApps.test.d.ts +0 -2
  84. package/dist/temporary-internal-core/handlers/listApps.test.d.ts.map +0 -1
  85. package/dist/temporary-internal-core/handlers/listApps.test.js +0 -367
  86. package/dist/temporary-internal-core/index.d.ts +0 -18
  87. package/dist/temporary-internal-core/index.d.ts.map +0 -1
  88. package/dist/temporary-internal-core/index.js +0 -18
  89. package/dist/temporary-internal-core/schemas/apps/index.d.ts +0 -175
  90. package/dist/temporary-internal-core/schemas/apps/index.d.ts.map +0 -1
  91. package/dist/temporary-internal-core/schemas/apps/index.js +0 -97
  92. package/dist/temporary-internal-core/schemas/errors/index.d.ts +0 -139
  93. package/dist/temporary-internal-core/schemas/errors/index.d.ts.map +0 -1
  94. package/dist/temporary-internal-core/schemas/errors/index.js +0 -129
  95. package/dist/temporary-internal-core/schemas/implementations/index.d.ts +0 -127
  96. package/dist/temporary-internal-core/schemas/implementations/index.d.ts.map +0 -1
  97. package/dist/temporary-internal-core/schemas/implementations/index.js +0 -79
  98. package/dist/temporary-internal-core/types/handler.d.ts +0 -51
  99. package/dist/temporary-internal-core/types/handler.d.ts.map +0 -1
  100. package/dist/temporary-internal-core/types/handler.js +0 -8
  101. package/dist/temporary-internal-core/types/index.d.ts +0 -5
  102. package/dist/temporary-internal-core/types/index.d.ts.map +0 -1
  103. package/dist/temporary-internal-core/types/index.js +0 -4
  104. package/dist/temporary-internal-core/utils/app-locators.d.ts +0 -34
  105. package/dist/temporary-internal-core/utils/app-locators.d.ts.map +0 -1
  106. package/dist/temporary-internal-core/utils/app-locators.js +0 -39
  107. package/dist/temporary-internal-core/utils/string-utils.d.ts +0 -28
  108. package/dist/temporary-internal-core/utils/string-utils.d.ts.map +0 -1
  109. package/dist/temporary-internal-core/utils/string-utils.js +0 -52
  110. package/dist/temporary-internal-core/utils/transformations.d.ts +0 -18
  111. package/dist/temporary-internal-core/utils/transformations.d.ts.map +0 -1
  112. package/dist/temporary-internal-core/utils/transformations.js +0 -36
@@ -1,67 +0,0 @@
1
- /**
2
- * Handler for listApps operation
3
- *
4
- * This handler will become an SDK API endpoint handler.
5
- * It encapsulates the business logic for listing apps, including:
6
- * - Search augmentation (merging search results with specified apps)
7
- * - API calls to internal services
8
- * - Response transformation
9
- * - Pagination with latest_only support
10
- *
11
- * Note: App key resolution (slugs → implementation IDs) happens in the SDK plugin.
12
- * The handler receives pre-resolved implementation IDs and performs search augmentation.
13
- */
14
- import type { Handler, HandlerDeps } from "../types";
15
- import { type ListAppsHandlerRequest, type ListAppsResponse } from "../schemas/apps";
16
- /**
17
- * Simple HTTP client interface for calling internal APIs
18
- *
19
- * Why pass this as a dependency instead of importing directly?
20
- *
21
- * 1. **Different implementations in different contexts:**
22
- * - In the SDK: Uses the ApiClient wrapper (adds auth, error handling, etc.)
23
- * - In the SDK API: Would use internal HTTP client or direct service calls
24
- *
25
- * 2. **Testability:**
26
- * - Can mock httpClient in tests without complex setup
27
- * - Can verify API calls and responses in isolation
28
- *
29
- * 3. **No hard coupling:**
30
- * - Handler doesn't know/care how HTTP calls are made
31
- * - Makes migration to SDK API easier (just swap implementation)
32
- */
33
- export interface HttpClient {
34
- get<T = unknown>(path: string, options?: {
35
- searchParams?: Record<string, string>;
36
- }): Promise<T>;
37
- }
38
- /**
39
- * Dependencies required by the listApps handler
40
- *
41
- * Passed as a parameter (dependency injection) rather than imported directly
42
- * to allow different implementations in different environments:
43
- * - SDK plugin injects: { httpClient: api } (SDK's ApiClient)
44
- * - SDK API would inject: { httpClient: internalHttpClient } (direct internal calls)
45
- * - Tests inject: { httpClient: mockHttpClient } (mocked responses)
46
- *
47
- * Extends HandlerDeps to ensure compatibility with the Handler interface.
48
- */
49
- export interface ListAppsHandlerDeps extends HandlerDeps {
50
- httpClient: HttpClient;
51
- }
52
- /**
53
- * Handles listApps operation
54
- *
55
- * Conforms to the Handler<TRequest, TResponse, TDeps> interface contract.
56
- * Validates and normalizes the request at the handler boundary before processing.
57
- *
58
- * Accepts flexible input types (via schema):
59
- * - implementationIds: string (comma-separated) or string[]
60
- * - pageSize: string or number
61
- *
62
- * @param request - The request with pre-resolved implementation IDs (handler performs search augmentation)
63
- * @param deps - Dependencies injected by the caller (see ListAppsHandlerDeps for why we use DI)
64
- * @returns Paginated list of apps with normalized data
65
- */
66
- export declare const handleListApps: Handler<ListAppsHandlerRequest, ListAppsResponse, ListAppsHandlerDeps>;
67
- //# sourceMappingURL=listApps.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"listApps.d.ts","sourceRoot":"","sources":["../../../src/temporary-internal-core/handlers/listApps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACrD,OAAO,EAEL,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACtB,MAAM,iBAAiB,CAAC;AAkBzB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,CAAC,GAAG,OAAO,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAClD,OAAO,CAAC,CAAC,CAAC,CAAC;CACf;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,UAAU,EAAE,UAAU,CAAC;CACxB;AA2ED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,EAAE,OAAO,CAClC,sBAAsB,EACtB,gBAAgB,EAChB,mBAAmB,CA+EpB,CAAC"}
@@ -1,134 +0,0 @@
1
- /**
2
- * Handler for listApps operation
3
- *
4
- * This handler will become an SDK API endpoint handler.
5
- * It encapsulates the business logic for listing apps, including:
6
- * - Search augmentation (merging search results with specified apps)
7
- * - API calls to internal services
8
- * - Response transformation
9
- * - Pagination with latest_only support
10
- *
11
- * Note: App key resolution (slugs → implementation IDs) happens in the SDK plugin.
12
- * The handler receives pre-resolved implementation IDs and performs search augmentation.
13
- */
14
- import { ListAppsHandlerRequestSchema, } from "../schemas/apps";
15
- import { splitVersionedKey } from "../utils/string-utils";
16
- import { transformImplementationMetaToAppItem, extractPaginationCursor, } from "../utils/transformations";
17
- // ============================================================================
18
- // Constants
19
- // ============================================================================
20
- const DEFAULT_PAGE_SIZE = 20;
21
- // ============================================================================
22
- // Business Logic Helpers
23
- // ============================================================================
24
- /**
25
- * Augments implementation IDs with search results
26
- *
27
- * Calls the search endpoint and merges results with existing implementation IDs,
28
- * deduplicating by implementation name (without version) and preferring public versions.
29
- */
30
- async function augmentWithSearchResults({ searchTerm, implementationIds, httpClient, }) {
31
- const searchResponse = await httpClient.get("/zapier/api/v4/implementations-meta/search/", {
32
- searchParams: { term: searchTerm },
33
- });
34
- // Deduplicate by implementation name, preferring public versions
35
- // This ensures that when a user has access to both a private version (e.g., 1.0.17)
36
- // and a public version (e.g., 1.1.0), we use the public one for search results
37
- const byImplementationName = new Map();
38
- for (const result of searchResponse.results) {
39
- const [implementationName] = splitVersionedKey(result.id);
40
- const isPublic = result.visibility === "public";
41
- const existing = byImplementationName.get(implementationName);
42
- // Take this result if we don't have one yet, or if this one is public and existing is not
43
- if (!existing || (isPublic && !existing.isPublic)) {
44
- byImplementationName.set(implementationName, { result, isPublic });
45
- }
46
- }
47
- const searchResults = Array.from(byImplementationName.values()).map((entry) => transformImplementationMetaToAppItem(entry.result));
48
- const implementationNameSet = new Set(implementationIds.map((id) => {
49
- const [name] = splitVersionedKey(id);
50
- return name;
51
- }));
52
- const additionalIds = [];
53
- for (const result of searchResults) {
54
- const [implementationName] = splitVersionedKey(result.key);
55
- if (!implementationNameSet.has(implementationName)) {
56
- implementationNameSet.add(implementationName);
57
- // Use the full implementation_id from the result
58
- additionalIds.push(result.implementation_id);
59
- }
60
- }
61
- return [...implementationIds, ...additionalIds];
62
- }
63
- // ============================================================================
64
- // Main Handler
65
- // ============================================================================
66
- /**
67
- * Handles listApps operation
68
- *
69
- * Conforms to the Handler<TRequest, TResponse, TDeps> interface contract.
70
- * Validates and normalizes the request at the handler boundary before processing.
71
- *
72
- * Accepts flexible input types (via schema):
73
- * - implementationIds: string (comma-separated) or string[]
74
- * - pageSize: string or number
75
- *
76
- * @param request - The request with pre-resolved implementation IDs (handler performs search augmentation)
77
- * @param deps - Dependencies injected by the caller (see ListAppsHandlerDeps for why we use DI)
78
- * @returns Paginated list of apps with normalized data
79
- */
80
- export const handleListApps = async ({ request, deps }) => {
81
- // Validate and normalize request at handler boundary
82
- // Schema automatically normalizes:
83
- // - implementationIds: string → string[]
84
- // - pageSize: string → number
85
- const validatedRequest = ListAppsHandlerRequestSchema.parse(request);
86
- const { httpClient } = deps;
87
- let { implementationIds } = validatedRequest;
88
- const pageSize = validatedRequest.pageSize ?? DEFAULT_PAGE_SIZE;
89
- if (validatedRequest.search) {
90
- implementationIds = await augmentWithSearchResults({
91
- searchTerm: validatedRequest.search,
92
- implementationIds,
93
- httpClient,
94
- });
95
- }
96
- if (implementationIds.length === 0) {
97
- // If search was provided but found nothing, return empty (bug fix)
98
- if (validatedRequest.search) {
99
- return {
100
- data: [],
101
- nextCursor: undefined,
102
- };
103
- }
104
- const searchParams = {
105
- latest_only: "true",
106
- selected_apis: "",
107
- limit: pageSize.toString(),
108
- };
109
- if (validatedRequest.cursor) {
110
- searchParams.offset = validatedRequest.cursor;
111
- }
112
- const implementationsResponse = await httpClient.get("/zapier/api/v4/implementations-meta/lookup/", {
113
- searchParams,
114
- });
115
- return {
116
- data: implementationsResponse.results.map(transformImplementationMetaToAppItem),
117
- nextCursor: extractPaginationCursor(implementationsResponse),
118
- };
119
- }
120
- const searchParams = {
121
- selected_apis: implementationIds.join(","),
122
- limit: pageSize.toString(),
123
- };
124
- if (validatedRequest.cursor) {
125
- searchParams.offset = validatedRequest.cursor;
126
- }
127
- const implementationsResponse = await httpClient.get("/zapier/api/v4/implementations-meta/lookup/", {
128
- searchParams,
129
- });
130
- return {
131
- data: implementationsResponse.results.map(transformImplementationMetaToAppItem),
132
- nextCursor: extractPaginationCursor(implementationsResponse),
133
- };
134
- };
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=listApps.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"listApps.test.d.ts","sourceRoot":"","sources":["../../../src/temporary-internal-core/handlers/listApps.test.ts"],"names":[],"mappings":""}
@@ -1,367 +0,0 @@
1
- import { describe, it, expect, vi } from "vitest";
2
- import { handleListApps, } from "./listApps";
3
- import { ListAppsResponseSchema, } from "../schemas/apps";
4
- describe("handleListApps", () => {
5
- const mockImplementation = (id, name, visibility = "public") => ({
6
- id,
7
- name,
8
- slug: name.toLowerCase().replace(/\s+/g, "-"),
9
- description: `${name} description`,
10
- primary_color: "#000000",
11
- categories: [{ id: 1, name: "test", slug: "test" }],
12
- visibility,
13
- });
14
- describe("pageSize handling", () => {
15
- it("should use default pageSize of 20 when not provided", async () => {
16
- const mockHttpClient = {
17
- get: vi.fn().mockResolvedValue({
18
- count: 0,
19
- results: [],
20
- }),
21
- };
22
- await handleListApps({
23
- request: {
24
- implementationIds: [],
25
- search: undefined,
26
- pageSize: undefined,
27
- cursor: undefined,
28
- },
29
- deps: { httpClient: mockHttpClient },
30
- });
31
- expect(mockHttpClient.get).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
32
- searchParams: expect.objectContaining({
33
- limit: "20",
34
- }),
35
- }));
36
- });
37
- it("should use custom pageSize when provided", async () => {
38
- const mockHttpClient = {
39
- get: vi.fn().mockResolvedValue({
40
- count: 0,
41
- results: [],
42
- }),
43
- };
44
- await handleListApps({
45
- request: {
46
- implementationIds: [],
47
- search: undefined,
48
- pageSize: 50,
49
- cursor: undefined,
50
- },
51
- deps: { httpClient: mockHttpClient },
52
- });
53
- expect(mockHttpClient.get).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
54
- searchParams: expect.objectContaining({
55
- limit: "50",
56
- }),
57
- }));
58
- });
59
- });
60
- describe("empty implementation IDs handling", () => {
61
- it("should fetch all apps when no implementationIds and no search", async () => {
62
- const mockResponse = {
63
- count: 2,
64
- results: [
65
- mockImplementation("SlackCLIAPI@1.0.0", "Slack"),
66
- mockImplementation("GitHubCLIAPI@1.0.0", "GitHub"),
67
- ],
68
- };
69
- const mockHttpClient = {
70
- get: vi.fn().mockResolvedValue(mockResponse),
71
- };
72
- const result = await handleListApps({
73
- request: {
74
- implementationIds: [],
75
- search: undefined,
76
- pageSize: undefined,
77
- cursor: undefined,
78
- },
79
- deps: { httpClient: mockHttpClient },
80
- });
81
- expect(result.data).toHaveLength(2);
82
- expect(mockHttpClient.get).toHaveBeenCalledWith("/zapier/api/v4/implementations-meta/lookup/", expect.objectContaining({
83
- searchParams: expect.objectContaining({
84
- latest_only: "true",
85
- selected_apis: "",
86
- }),
87
- }));
88
- });
89
- it("should return empty when search finds nothing (bug fix)", async () => {
90
- const mockSearchResponse = {
91
- count: 0,
92
- results: [],
93
- };
94
- const mockHttpClient = {
95
- get: vi.fn().mockResolvedValue(mockSearchResponse),
96
- };
97
- const result = await handleListApps({
98
- request: {
99
- implementationIds: [],
100
- search: "NonexistentApp",
101
- pageSize: undefined,
102
- cursor: undefined,
103
- },
104
- deps: { httpClient: mockHttpClient },
105
- });
106
- // Should only call search endpoint
107
- expect(mockHttpClient.get).toHaveBeenCalledTimes(1);
108
- expect(mockHttpClient.get).toHaveBeenCalledWith("/zapier/api/v4/implementations-meta/search/", expect.objectContaining({
109
- searchParams: { term: "NonexistentApp" },
110
- }));
111
- // Should return empty (bug fix - not all apps)
112
- expect(result.data).toHaveLength(0);
113
- expect(result.nextCursor).toBeUndefined();
114
- });
115
- });
116
- describe("search augmentation", () => {
117
- it("should augment results with search when search term provided", async () => {
118
- const mockSearchResponse = {
119
- count: 1,
120
- results: [mockImplementation("SlackCLIAPI@1.0.0", "Slack")],
121
- };
122
- const mockLookupResponse = {
123
- count: 2,
124
- results: [
125
- mockImplementation("GitHubCLIAPI@1.0.0", "GitHub"),
126
- mockImplementation("SlackCLIAPI@1.0.0", "Slack"),
127
- ],
128
- next: null,
129
- };
130
- const mockHttpClient = {
131
- get: vi
132
- .fn()
133
- .mockResolvedValueOnce(mockSearchResponse) // First call: search
134
- .mockResolvedValueOnce(mockLookupResponse), // Second call: lookup
135
- };
136
- const result = await handleListApps({
137
- request: {
138
- implementationIds: ["GitHubCLIAPI@1.0.0"],
139
- search: "Slack",
140
- pageSize: undefined,
141
- cursor: undefined,
142
- },
143
- deps: { httpClient: mockHttpClient },
144
- });
145
- // Should call both search and lookup
146
- expect(mockHttpClient.get).toHaveBeenCalledTimes(2);
147
- expect(mockHttpClient.get).toHaveBeenNthCalledWith(1, "/zapier/api/v4/implementations-meta/search/", expect.objectContaining({
148
- searchParams: { term: "Slack" },
149
- }));
150
- expect(mockHttpClient.get).toHaveBeenNthCalledWith(2, "/zapier/api/v4/implementations-meta/lookup/", expect.objectContaining({
151
- searchParams: expect.objectContaining({
152
- selected_apis: "GitHubCLIAPI@1.0.0,SlackCLIAPI@1.0.0",
153
- }),
154
- }));
155
- expect(result.data).toHaveLength(2);
156
- });
157
- it("should not duplicate apps when search returns apps already in implementationIds", async () => {
158
- const mockSearchResponse = {
159
- count: 1,
160
- results: [mockImplementation("SlackCLIAPI@1.0.0", "Slack")],
161
- };
162
- const mockLookupResponse = {
163
- count: 1,
164
- results: [mockImplementation("SlackCLIAPI@1.0.0", "Slack")],
165
- next: null,
166
- };
167
- const mockHttpClient = {
168
- get: vi
169
- .fn()
170
- .mockResolvedValueOnce(mockSearchResponse)
171
- .mockResolvedValueOnce(mockLookupResponse),
172
- };
173
- await handleListApps({
174
- request: {
175
- implementationIds: ["SlackCLIAPI@1.0.0"],
176
- search: "Slack",
177
- pageSize: undefined,
178
- cursor: undefined,
179
- },
180
- deps: { httpClient: mockHttpClient },
181
- });
182
- // Should call search and lookup but deduplicate IDs
183
- expect(mockHttpClient.get).toHaveBeenCalledTimes(2);
184
- expect(mockHttpClient.get).toHaveBeenNthCalledWith(2, "/zapier/api/v4/implementations-meta/lookup/", expect.objectContaining({
185
- searchParams: expect.objectContaining({
186
- selected_apis: "SlackCLIAPI@1.0.0",
187
- }),
188
- }));
189
- });
190
- it("should prefer public version when search returns multiple versions of same app", async () => {
191
- // Simulates a user having access to both private (1.0.17) and public (1.1.0) versions
192
- const mockSearchResponse = {
193
- count: 2,
194
- results: [
195
- mockImplementation("LumAppsCLIAPI@1.0.17", "LumApps (1.0.17)", "private"),
196
- mockImplementation("LumAppsCLIAPI@1.1.0", "LumApps", "public"),
197
- ],
198
- };
199
- const mockLookupResponse = {
200
- count: 1,
201
- results: [
202
- mockImplementation("LumAppsCLIAPI@1.1.0", "LumApps", "public"),
203
- ],
204
- next: null,
205
- };
206
- const mockHttpClient = {
207
- get: vi
208
- .fn()
209
- .mockResolvedValueOnce(mockSearchResponse)
210
- .mockResolvedValueOnce(mockLookupResponse),
211
- };
212
- await handleListApps({
213
- request: {
214
- implementationIds: [],
215
- search: "lumapps",
216
- pageSize: undefined,
217
- cursor: undefined,
218
- },
219
- deps: { httpClient: mockHttpClient },
220
- });
221
- // Should request the public version (1.1.0), not the private one (1.0.17)
222
- expect(mockHttpClient.get).toHaveBeenNthCalledWith(2, "/zapier/api/v4/implementations-meta/lookup/", expect.objectContaining({
223
- searchParams: expect.objectContaining({
224
- selected_apis: "LumAppsCLIAPI@1.1.0",
225
- }),
226
- }));
227
- });
228
- });
229
- describe("specific implementation IDs", () => {
230
- it("should fetch specific apps when implementationIds provided", async () => {
231
- const mockResponse = {
232
- count: 2,
233
- results: [
234
- mockImplementation("SlackCLIAPI@1.0.0", "Slack"),
235
- mockImplementation("GitHubCLIAPI@1.0.0", "GitHub"),
236
- ],
237
- };
238
- const mockHttpClient = {
239
- get: vi.fn().mockResolvedValue(mockResponse),
240
- };
241
- const result = await handleListApps({
242
- request: {
243
- implementationIds: ["SlackCLIAPI@1.0.0", "GitHubCLIAPI@1.0.0"],
244
- search: undefined,
245
- pageSize: undefined,
246
- cursor: undefined,
247
- },
248
- deps: { httpClient: mockHttpClient },
249
- });
250
- expect(result.data).toHaveLength(2);
251
- expect(mockHttpClient.get).toHaveBeenCalledWith("/zapier/api/v4/implementations-meta/lookup/", expect.objectContaining({
252
- searchParams: expect.objectContaining({
253
- selected_apis: "SlackCLIAPI@1.0.0,GitHubCLIAPI@1.0.0",
254
- }),
255
- }));
256
- });
257
- });
258
- describe("pagination", () => {
259
- it("should pass cursor to API when provided", async () => {
260
- const mockResponse = {
261
- count: 0,
262
- results: [],
263
- };
264
- const mockHttpClient = {
265
- get: vi.fn().mockResolvedValue(mockResponse),
266
- };
267
- await handleListApps({
268
- request: {
269
- implementationIds: ["SlackCLIAPI@1.0.0"],
270
- search: undefined,
271
- pageSize: undefined,
272
- cursor: "page-2-cursor",
273
- },
274
- deps: { httpClient: mockHttpClient },
275
- });
276
- expect(mockHttpClient.get).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
277
- searchParams: expect.objectContaining({
278
- offset: "page-2-cursor",
279
- }),
280
- }));
281
- });
282
- it("should extract nextCursor from response", async () => {
283
- const mockResponse = {
284
- count: 1,
285
- results: [mockImplementation("SlackCLIAPI@1.0.0", "Slack")],
286
- next: "https://api.zapier.com/v4/implementations-meta/lookup/?offset=next-page",
287
- };
288
- const mockHttpClient = {
289
- get: vi.fn().mockResolvedValue(mockResponse),
290
- };
291
- const result = await handleListApps({
292
- request: {
293
- implementationIds: [],
294
- search: undefined,
295
- pageSize: undefined,
296
- cursor: undefined,
297
- },
298
- deps: { httpClient: mockHttpClient },
299
- });
300
- expect(result.nextCursor).toBe("next-page");
301
- });
302
- });
303
- describe("request validation", () => {
304
- it("should reject request with invalid implementationIds type", async () => {
305
- const mockHttpClient = {
306
- get: vi.fn(),
307
- };
308
- const invalidRequest = {
309
- implementationIds: "not-an-array",
310
- search: undefined,
311
- pageSize: undefined,
312
- cursor: undefined,
313
- };
314
- const deps = {
315
- httpClient: mockHttpClient,
316
- };
317
- await expect(handleListApps({ request: invalidRequest, deps })).rejects.toThrow();
318
- });
319
- it("should reject request with negative pageSize", async () => {
320
- const mockHttpClient = {
321
- get: vi.fn(),
322
- };
323
- const invalidRequest = {
324
- implementationIds: [],
325
- search: undefined,
326
- pageSize: -1,
327
- cursor: undefined,
328
- };
329
- const deps = {
330
- httpClient: mockHttpClient,
331
- };
332
- await expect(handleListApps({ request: invalidRequest, deps })).rejects.toThrow();
333
- });
334
- });
335
- describe("response validation", () => {
336
- it("should return response matching ListAppsResponseSchema", async () => {
337
- const mockHttpClient = {
338
- get: vi.fn().mockResolvedValue({
339
- count: 1,
340
- results: [
341
- {
342
- id: "SlackCLIAPI@1.0.0",
343
- name: "SlackCLIAPI",
344
- slug: "slack",
345
- description: "Slack app",
346
- primary_color: "#000000",
347
- },
348
- ],
349
- }),
350
- };
351
- const request = {
352
- implementationIds: [],
353
- search: undefined,
354
- pageSize: 20,
355
- cursor: undefined,
356
- };
357
- const deps = {
358
- httpClient: mockHttpClient,
359
- };
360
- const result = await handleListApps({ request, deps });
361
- expect(() => ListAppsResponseSchema.parse(result)).not.toThrow();
362
- expect(result).toHaveProperty("data");
363
- expect(Array.isArray(result.data)).toBe(true);
364
- expect(result).toHaveProperty("nextCursor");
365
- });
366
- });
367
- });
@@ -1,18 +0,0 @@
1
- /**
2
- * temporary-internal-core
3
- *
4
- * Temporary internal directory for SDK core API extraction.
5
- * This will be extracted and moved to @sdkapi/ as @zapier/zapier-sdk-core.
6
- *
7
- * Purpose:
8
- * - Single source of truth for SDK API schemas
9
- * - Zod schemas for request/response shapes
10
- * - API endpoint contracts
11
- * - Lives inside zapier-sdk during extraction/migration (bundles when published)
12
- * - Will be extracted to separate package
13
- */
14
- export type { HandlerDeps, Handler, ValidatedHandler } from "./types";
15
- export * from "./schemas/apps";
16
- export * from "./schemas/implementations";
17
- export { handleListApps, type ListAppsHandlerDeps } from "./handlers/listApps";
18
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/temporary-internal-core/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,YAAY,EAAE,WAAW,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAGtE,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAG1C,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -1,18 +0,0 @@
1
- /**
2
- * temporary-internal-core
3
- *
4
- * Temporary internal directory for SDK core API extraction.
5
- * This will be extracted and moved to @sdkapi/ as @zapier/zapier-sdk-core.
6
- *
7
- * Purpose:
8
- * - Single source of truth for SDK API schemas
9
- * - Zod schemas for request/response shapes
10
- * - API endpoint contracts
11
- * - Lives inside zapier-sdk during extraction/migration (bundles when published)
12
- * - Will be extracted to separate package
13
- */
14
- // Schemas
15
- export * from "./schemas/apps";
16
- export * from "./schemas/implementations";
17
- // Handlers
18
- export { handleListApps } from "./handlers/listApps";