@zapier/zapier-sdk 0.6.4 → 0.8.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.
- package/CHANGELOG.md +12 -0
- package/README.md +55 -23
- package/dist/api/schemas.d.ts +114 -0
- package/dist/api/schemas.d.ts.map +1 -1
- package/dist/api/schemas.js +45 -0
- package/dist/api/types.d.ts +5 -1
- package/dist/api/types.d.ts.map +1 -1
- package/dist/index.cjs +171 -7
- package/dist/index.d.mts +84 -10
- package/dist/index.mjs +171 -7
- package/dist/plugins/findFirstAuthentication/index.test.js +3 -3
- package/dist/plugins/findFirstAuthentication/schemas.d.ts +3 -3
- package/dist/plugins/findFirstAuthentication/schemas.js +1 -1
- package/dist/plugins/findUniqueAuthentication/index.test.js +3 -3
- package/dist/plugins/findUniqueAuthentication/schemas.d.ts +3 -3
- package/dist/plugins/findUniqueAuthentication/schemas.js +1 -1
- package/dist/plugins/listAuthentications/index.d.ts.map +1 -1
- package/dist/plugins/listAuthentications/index.js +2 -3
- package/dist/plugins/listAuthentications/index.test.js +5 -5
- package/dist/plugins/listAuthentications/schemas.d.ts +3 -3
- package/dist/plugins/listAuthentications/schemas.js +1 -1
- package/dist/plugins/listInputFieldChoices/index.d.ts +28 -0
- package/dist/plugins/listInputFieldChoices/index.d.ts.map +1 -0
- package/dist/plugins/listInputFieldChoices/index.js +78 -0
- package/dist/plugins/listInputFieldChoices/index.test.d.ts +2 -0
- package/dist/plugins/listInputFieldChoices/index.test.d.ts.map +1 -0
- package/dist/plugins/listInputFieldChoices/index.test.js +537 -0
- package/dist/plugins/listInputFieldChoices/schemas.d.ts +61 -0
- package/dist/plugins/listInputFieldChoices/schemas.d.ts.map +1 -0
- package/dist/plugins/listInputFieldChoices/schemas.js +73 -0
- package/dist/sdk.d.ts +7 -1
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +2 -0
- package/package.json +1 -1
- package/src/api/schemas.ts +62 -0
- package/src/api/types.ts +14 -0
- package/src/plugins/findFirstAuthentication/index.test.ts +3 -3
- package/src/plugins/findFirstAuthentication/schemas.ts +1 -1
- package/src/plugins/findUniqueAuthentication/index.test.ts +3 -3
- package/src/plugins/findUniqueAuthentication/schemas.ts +1 -1
- package/src/plugins/listAuthentications/index.test.ts +5 -5
- package/src/plugins/listAuthentications/index.ts +2 -3
- package/src/plugins/listAuthentications/schemas.ts +1 -1
- package/src/plugins/listInputFieldChoices/index.test.ts +653 -0
- package/src/plugins/listInputFieldChoices/index.ts +152 -0
- package/src/plugins/listInputFieldChoices/schemas.ts +139 -0
- package/src/sdk.ts +2 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { ListInputFieldChoicesSchema, } from "./schemas";
|
|
2
|
+
import { ZapierApiError } from "../../types/errors";
|
|
3
|
+
import { createPaginatedFunction } from "../../utils/function-utils";
|
|
4
|
+
// Transform NeedChoices to InputFieldChoiceItem
|
|
5
|
+
function transformNeedChoicesToInputFieldChoiceItem(choice) {
|
|
6
|
+
return {
|
|
7
|
+
key: choice.key,
|
|
8
|
+
label: choice.label,
|
|
9
|
+
sample: choice.sample,
|
|
10
|
+
value: choice.value,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export const listInputFieldChoicesPlugin = ({ context, sdk }) => {
|
|
14
|
+
const listInputFieldChoices = createPaginatedFunction(async function listInputFieldChoicesPage(options) {
|
|
15
|
+
const { api } = context;
|
|
16
|
+
// Extract parameters
|
|
17
|
+
const { appKey, actionType, actionKey, inputFieldKey, authenticationId, inputs, page, cursor, } = options;
|
|
18
|
+
// Use sdk.getAction to get the action ID
|
|
19
|
+
const actionResult = await sdk.getAction({ appKey, actionType, actionKey });
|
|
20
|
+
const actionId = actionResult.data.id;
|
|
21
|
+
if (!actionId) {
|
|
22
|
+
throw new ZapierApiError(`Action ${actionKey} does not have an ID - cannot retrieve input field choices`);
|
|
23
|
+
}
|
|
24
|
+
// Build choices request using action ID from getAction
|
|
25
|
+
// Use cursor (from pagination) as page number if available, otherwise use explicit page or default to 0
|
|
26
|
+
const requestPage = cursor ? parseInt(cursor, 10) : (page ?? 0);
|
|
27
|
+
const choicesRequest = {
|
|
28
|
+
action_id: actionId,
|
|
29
|
+
input_field_id: inputFieldKey,
|
|
30
|
+
page: requestPage,
|
|
31
|
+
params: inputs || {},
|
|
32
|
+
};
|
|
33
|
+
// Only include authentication_id if it's not null (skip authentication when null)
|
|
34
|
+
if (authenticationId !== null) {
|
|
35
|
+
choicesRequest.authentication_id = authenticationId;
|
|
36
|
+
}
|
|
37
|
+
const choicesData = await api.post("/api/v4/implementations/choices/", choicesRequest);
|
|
38
|
+
if (!choicesData.success) {
|
|
39
|
+
throw new ZapierApiError(`Failed to get input field choices: ${choicesData.errors?.join(", ") || "Unknown error"}`);
|
|
40
|
+
}
|
|
41
|
+
// Transform NeedChoices objects to InputFieldChoiceItem objects
|
|
42
|
+
const choices = (choicesData.choices || []).map(transformNeedChoicesToInputFieldChoiceItem);
|
|
43
|
+
// Handle pagination
|
|
44
|
+
let nextCursor;
|
|
45
|
+
if (choicesData.next_page !== undefined) {
|
|
46
|
+
nextCursor = choicesData.next_page.toString();
|
|
47
|
+
}
|
|
48
|
+
else if (choicesData.links?.next) {
|
|
49
|
+
// Extract page from next URL for external actions
|
|
50
|
+
try {
|
|
51
|
+
const nextUrl = new URL(choicesData.links.next);
|
|
52
|
+
const nextPage = nextUrl.searchParams.get("page");
|
|
53
|
+
if (nextPage) {
|
|
54
|
+
nextCursor = nextPage;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Handle malformed URLs gracefully by not setting nextCursor
|
|
59
|
+
nextCursor = undefined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
data: choices,
|
|
64
|
+
nextCursor,
|
|
65
|
+
};
|
|
66
|
+
}, ListInputFieldChoicesSchema);
|
|
67
|
+
return {
|
|
68
|
+
listInputFieldChoices,
|
|
69
|
+
context: {
|
|
70
|
+
meta: {
|
|
71
|
+
listInputFieldChoices: {
|
|
72
|
+
categories: ["action"],
|
|
73
|
+
inputSchema: ListInputFieldChoicesSchema,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../src/plugins/listInputFieldChoices/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,537 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { ZapierValidationError, ZapierApiError } from "../../types/errors";
|
|
3
|
+
import { listInputFieldChoicesPlugin } from "./index";
|
|
4
|
+
import { createSdk } from "../../sdk";
|
|
5
|
+
import { GetActionSchema } from "../getAction/schemas";
|
|
6
|
+
const mockChoices = [
|
|
7
|
+
{
|
|
8
|
+
key: "general",
|
|
9
|
+
label: "General Channel",
|
|
10
|
+
sample: "#general",
|
|
11
|
+
value: "general",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
key: "random",
|
|
15
|
+
label: "Random Channel",
|
|
16
|
+
sample: "#random",
|
|
17
|
+
value: "random",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
key: "dev",
|
|
21
|
+
label: "Development Channel",
|
|
22
|
+
sample: "#dev",
|
|
23
|
+
value: "dev",
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
const mockChoicesResponse = {
|
|
27
|
+
success: true,
|
|
28
|
+
choices: mockChoices,
|
|
29
|
+
};
|
|
30
|
+
const mockPaginatedChoicesResponse = {
|
|
31
|
+
success: true,
|
|
32
|
+
choices: mockChoices.slice(0, 2),
|
|
33
|
+
next_page: 1,
|
|
34
|
+
};
|
|
35
|
+
const mockExternalChoicesResponse = {
|
|
36
|
+
success: true,
|
|
37
|
+
choices: mockChoices,
|
|
38
|
+
meta: { page: "0" },
|
|
39
|
+
links: {
|
|
40
|
+
next: "https://api.zapier.com/api/v4/implementations/choices/?page=1",
|
|
41
|
+
prev: null,
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
describe("listInputFieldChoices plugin", () => {
|
|
45
|
+
let mockApiClient;
|
|
46
|
+
let mockGetAction;
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
vi.clearAllMocks();
|
|
49
|
+
mockApiClient = {
|
|
50
|
+
post: vi.fn().mockResolvedValue(mockChoicesResponse),
|
|
51
|
+
};
|
|
52
|
+
mockGetAction = vi.fn().mockResolvedValue({
|
|
53
|
+
data: { id: "core:123", key: "send_message", action_type: "read" },
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
function createTestSdk() {
|
|
57
|
+
// Create a mock getAction plugin
|
|
58
|
+
const mockGetActionPlugin = () => ({
|
|
59
|
+
getAction: mockGetAction,
|
|
60
|
+
context: {
|
|
61
|
+
meta: {
|
|
62
|
+
getAction: {
|
|
63
|
+
inputSchema: GetActionSchema,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
// Build SDK with proper plugin composition
|
|
69
|
+
return createSdk({}, {}, { api: mockApiClient, meta: {} })
|
|
70
|
+
.addPlugin(mockGetActionPlugin)
|
|
71
|
+
.addPlugin(listInputFieldChoicesPlugin);
|
|
72
|
+
}
|
|
73
|
+
describe("schema validation", () => {
|
|
74
|
+
it("should throw validation error for missing inputFieldKey", async () => {
|
|
75
|
+
const sdk = createTestSdk();
|
|
76
|
+
try {
|
|
77
|
+
await sdk.listInputFieldChoices({
|
|
78
|
+
appKey: "slack",
|
|
79
|
+
actionType: "read",
|
|
80
|
+
actionKey: "send_message",
|
|
81
|
+
// Missing inputFieldKey
|
|
82
|
+
});
|
|
83
|
+
expect.fail("Expected ZapierValidationError to be thrown");
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
expect(error).toBeInstanceOf(ZapierValidationError);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
it("should throw validation error for missing actionKey", async () => {
|
|
90
|
+
const sdk = createTestSdk();
|
|
91
|
+
try {
|
|
92
|
+
await sdk.listInputFieldChoices({
|
|
93
|
+
appKey: "slack",
|
|
94
|
+
actionType: "read",
|
|
95
|
+
inputFieldKey: "channel",
|
|
96
|
+
// Missing actionKey
|
|
97
|
+
});
|
|
98
|
+
expect.fail("Expected ZapierValidationError to be thrown");
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
expect(error).toBeInstanceOf(ZapierValidationError);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
it("should pass validation with action method", async () => {
|
|
105
|
+
const sdk = createTestSdk();
|
|
106
|
+
const result = await sdk.listInputFieldChoices({
|
|
107
|
+
appKey: "slack",
|
|
108
|
+
actionType: "read",
|
|
109
|
+
actionKey: "send_message",
|
|
110
|
+
inputFieldKey: "channel",
|
|
111
|
+
});
|
|
112
|
+
expect(result.data).toBeDefined();
|
|
113
|
+
});
|
|
114
|
+
it("should pass validation with optional fields", async () => {
|
|
115
|
+
const sdk = createTestSdk();
|
|
116
|
+
const result = await sdk.listInputFieldChoices({
|
|
117
|
+
appKey: "slack",
|
|
118
|
+
actionType: "read",
|
|
119
|
+
actionKey: "send_message",
|
|
120
|
+
inputFieldKey: "channel",
|
|
121
|
+
authenticationId: 456,
|
|
122
|
+
inputs: { workspace: "my-team" },
|
|
123
|
+
page: 0,
|
|
124
|
+
});
|
|
125
|
+
expect(result.data).toBeDefined();
|
|
126
|
+
});
|
|
127
|
+
it("should throw validation error for empty string actionKey", async () => {
|
|
128
|
+
const sdk = createTestSdk();
|
|
129
|
+
try {
|
|
130
|
+
await sdk.listInputFieldChoices({
|
|
131
|
+
appKey: "slack",
|
|
132
|
+
actionType: "read",
|
|
133
|
+
actionKey: "", // Empty string
|
|
134
|
+
inputFieldKey: "channel",
|
|
135
|
+
});
|
|
136
|
+
expect.fail("Expected ZapierValidationError to be thrown");
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
expect(error).toBeInstanceOf(ZapierValidationError);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
it("should throw validation error for empty string inputFieldKey", async () => {
|
|
143
|
+
const sdk = createTestSdk();
|
|
144
|
+
try {
|
|
145
|
+
await sdk.listInputFieldChoices({
|
|
146
|
+
appKey: "slack",
|
|
147
|
+
actionType: "read",
|
|
148
|
+
actionKey: "send_message",
|
|
149
|
+
inputFieldKey: "", // Empty string
|
|
150
|
+
});
|
|
151
|
+
expect.fail("Expected ZapierValidationError to be thrown");
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
expect(error).toBeInstanceOf(ZapierValidationError);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
describe("API integration - action method", () => {
|
|
159
|
+
it("should call the correct API endpoint with action method", async () => {
|
|
160
|
+
const sdk = createTestSdk();
|
|
161
|
+
await sdk.listInputFieldChoices({
|
|
162
|
+
appKey: "slack",
|
|
163
|
+
actionType: "read",
|
|
164
|
+
actionKey: "send_message",
|
|
165
|
+
inputFieldKey: "channel",
|
|
166
|
+
});
|
|
167
|
+
expect(mockGetAction).toHaveBeenCalledWith({
|
|
168
|
+
appKey: "slack",
|
|
169
|
+
actionType: "read",
|
|
170
|
+
actionKey: "send_message",
|
|
171
|
+
});
|
|
172
|
+
expect(mockApiClient.post).toHaveBeenCalledWith("/api/v4/implementations/choices/", {
|
|
173
|
+
action_id: "core:123",
|
|
174
|
+
input_field_id: "channel",
|
|
175
|
+
page: 0,
|
|
176
|
+
params: {},
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
it("should include authentication_id when provided", async () => {
|
|
180
|
+
const sdk = createTestSdk();
|
|
181
|
+
await sdk.listInputFieldChoices({
|
|
182
|
+
appKey: "slack",
|
|
183
|
+
actionType: "read",
|
|
184
|
+
actionKey: "send_message",
|
|
185
|
+
inputFieldKey: "channel",
|
|
186
|
+
authenticationId: 456,
|
|
187
|
+
});
|
|
188
|
+
expect(mockApiClient.post).toHaveBeenCalledWith("/api/v4/implementations/choices/", {
|
|
189
|
+
action_id: "core:123",
|
|
190
|
+
input_field_id: "channel",
|
|
191
|
+
authentication_id: 456,
|
|
192
|
+
page: 0,
|
|
193
|
+
params: {},
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
it("should exclude authentication_id when null", async () => {
|
|
197
|
+
const sdk = createTestSdk();
|
|
198
|
+
await sdk.listInputFieldChoices({
|
|
199
|
+
appKey: "slack",
|
|
200
|
+
actionType: "read",
|
|
201
|
+
actionKey: "send_message",
|
|
202
|
+
inputFieldKey: "channel",
|
|
203
|
+
authenticationId: null,
|
|
204
|
+
});
|
|
205
|
+
expect(mockApiClient.post).toHaveBeenCalledWith("/api/v4/implementations/choices/", {
|
|
206
|
+
action_id: "core:123",
|
|
207
|
+
input_field_id: "channel",
|
|
208
|
+
page: 0,
|
|
209
|
+
params: {},
|
|
210
|
+
// No authentication_id
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
it("should include inputs when provided", async () => {
|
|
214
|
+
const sdk = createTestSdk();
|
|
215
|
+
const inputs = { workspace: "my-team", board: "project" };
|
|
216
|
+
await sdk.listInputFieldChoices({
|
|
217
|
+
appKey: "slack",
|
|
218
|
+
actionType: "read",
|
|
219
|
+
actionKey: "send_message",
|
|
220
|
+
inputFieldKey: "channel",
|
|
221
|
+
inputs,
|
|
222
|
+
});
|
|
223
|
+
expect(mockApiClient.post).toHaveBeenCalledWith("/api/v4/implementations/choices/", {
|
|
224
|
+
action_id: "core:123",
|
|
225
|
+
input_field_id: "channel",
|
|
226
|
+
page: 0,
|
|
227
|
+
params: inputs,
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
it("should include page when provided", async () => {
|
|
231
|
+
const sdk = createTestSdk();
|
|
232
|
+
await sdk.listInputFieldChoices({
|
|
233
|
+
appKey: "slack",
|
|
234
|
+
actionType: "read",
|
|
235
|
+
actionKey: "send_message",
|
|
236
|
+
inputFieldKey: "channel",
|
|
237
|
+
page: 2,
|
|
238
|
+
});
|
|
239
|
+
expect(mockApiClient.post).toHaveBeenCalledWith("/api/v4/implementations/choices/", {
|
|
240
|
+
action_id: "core:123",
|
|
241
|
+
input_field_id: "channel",
|
|
242
|
+
page: 2,
|
|
243
|
+
params: {},
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
describe("data transformation", () => {
|
|
248
|
+
it("should transform choices to input field choice items correctly", async () => {
|
|
249
|
+
const sdk = createTestSdk();
|
|
250
|
+
const result = await sdk.listInputFieldChoices({
|
|
251
|
+
appKey: "slack",
|
|
252
|
+
actionType: "read",
|
|
253
|
+
actionKey: "send_message",
|
|
254
|
+
inputFieldKey: "channel",
|
|
255
|
+
});
|
|
256
|
+
expect(result.data).toHaveLength(3);
|
|
257
|
+
// Check first choice transformation
|
|
258
|
+
expect(result.data[0]).toEqual({
|
|
259
|
+
key: "general",
|
|
260
|
+
label: "General Channel",
|
|
261
|
+
sample: "#general",
|
|
262
|
+
value: "general",
|
|
263
|
+
});
|
|
264
|
+
// Check second choice transformation
|
|
265
|
+
expect(result.data[1]).toEqual({
|
|
266
|
+
key: "random",
|
|
267
|
+
label: "Random Channel",
|
|
268
|
+
sample: "#random",
|
|
269
|
+
value: "random",
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
it("should handle choices with missing fields gracefully", async () => {
|
|
273
|
+
const sparseChoices = [
|
|
274
|
+
{ key: "item1", label: "Item 1" },
|
|
275
|
+
{ value: "item2", sample: "item2" },
|
|
276
|
+
{ label: "Item 3" },
|
|
277
|
+
];
|
|
278
|
+
mockApiClient.post = vi.fn().mockResolvedValue({
|
|
279
|
+
success: true,
|
|
280
|
+
choices: sparseChoices,
|
|
281
|
+
});
|
|
282
|
+
const sdk = createTestSdk();
|
|
283
|
+
const result = await sdk.listInputFieldChoices({
|
|
284
|
+
appKey: "slack",
|
|
285
|
+
actionType: "read",
|
|
286
|
+
actionKey: "send_message",
|
|
287
|
+
inputFieldKey: "item",
|
|
288
|
+
});
|
|
289
|
+
expect(result.data).toHaveLength(3);
|
|
290
|
+
expect(result.data[0]).toEqual({
|
|
291
|
+
key: "item1",
|
|
292
|
+
label: "Item 1",
|
|
293
|
+
sample: undefined,
|
|
294
|
+
value: undefined,
|
|
295
|
+
});
|
|
296
|
+
expect(result.data[1]).toEqual({
|
|
297
|
+
key: undefined,
|
|
298
|
+
label: undefined,
|
|
299
|
+
sample: "item2",
|
|
300
|
+
value: "item2",
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
describe("pagination handling", () => {
|
|
305
|
+
it("should handle next_page pagination correctly in the plugin", async () => {
|
|
306
|
+
mockApiClient.post = vi
|
|
307
|
+
.fn()
|
|
308
|
+
.mockResolvedValue(mockPaginatedChoicesResponse);
|
|
309
|
+
const sdk = createTestSdk();
|
|
310
|
+
// Test that the plugin correctly sets nextCursor when next_page is present
|
|
311
|
+
const listChoicesResult = sdk.listInputFieldChoices({
|
|
312
|
+
appKey: "slack",
|
|
313
|
+
actionType: "read",
|
|
314
|
+
actionKey: "send_message",
|
|
315
|
+
inputFieldKey: "channel",
|
|
316
|
+
pageSize: 2, // Set a small page size to test pagination behavior
|
|
317
|
+
});
|
|
318
|
+
const pages = [];
|
|
319
|
+
for await (const page of listChoicesResult) {
|
|
320
|
+
pages.push(page);
|
|
321
|
+
break; // Just get first page for testing
|
|
322
|
+
}
|
|
323
|
+
expect(pages).toHaveLength(1);
|
|
324
|
+
expect(pages[0].nextCursor).toBe("1");
|
|
325
|
+
});
|
|
326
|
+
it("should handle external action link-based pagination correctly in the plugin", async () => {
|
|
327
|
+
mockApiClient.post = vi
|
|
328
|
+
.fn()
|
|
329
|
+
.mockResolvedValue(mockExternalChoicesResponse);
|
|
330
|
+
const sdk = createTestSdk();
|
|
331
|
+
// Test that the plugin correctly extracts cursor from links.next
|
|
332
|
+
const listChoicesResult = sdk.listInputFieldChoices({
|
|
333
|
+
appKey: "slack",
|
|
334
|
+
actionType: "read",
|
|
335
|
+
actionKey: "send_message",
|
|
336
|
+
inputFieldKey: "option",
|
|
337
|
+
pageSize: 3, // Set a small page size to test pagination behavior
|
|
338
|
+
});
|
|
339
|
+
const pages = [];
|
|
340
|
+
for await (const page of listChoicesResult) {
|
|
341
|
+
pages.push(page);
|
|
342
|
+
break; // Just get first page for testing
|
|
343
|
+
}
|
|
344
|
+
expect(pages).toHaveLength(1);
|
|
345
|
+
expect(pages[0].nextCursor).toBe("1"); // Extracted from links.next URL
|
|
346
|
+
});
|
|
347
|
+
it("should handle no pagination", async () => {
|
|
348
|
+
const sdk = createTestSdk();
|
|
349
|
+
const listChoicesResult = sdk.listInputFieldChoices({
|
|
350
|
+
appKey: "slack",
|
|
351
|
+
actionType: "read",
|
|
352
|
+
actionKey: "send_message",
|
|
353
|
+
inputFieldKey: "channel",
|
|
354
|
+
});
|
|
355
|
+
const pages = [];
|
|
356
|
+
for await (const page of listChoicesResult) {
|
|
357
|
+
pages.push(page);
|
|
358
|
+
break; // Just get first page for testing
|
|
359
|
+
}
|
|
360
|
+
expect(pages).toHaveLength(1);
|
|
361
|
+
expect(pages[0].nextCursor).toBeUndefined();
|
|
362
|
+
});
|
|
363
|
+
it("should support async iteration over individual items", async () => {
|
|
364
|
+
const sdk = createTestSdk();
|
|
365
|
+
const listChoicesResult = sdk.listInputFieldChoices({
|
|
366
|
+
appKey: "slack",
|
|
367
|
+
actionType: "read",
|
|
368
|
+
actionKey: "send_message",
|
|
369
|
+
inputFieldKey: "channel",
|
|
370
|
+
});
|
|
371
|
+
const items = [];
|
|
372
|
+
for await (const item of listChoicesResult.items()) {
|
|
373
|
+
items.push(item);
|
|
374
|
+
}
|
|
375
|
+
expect(items).toHaveLength(3);
|
|
376
|
+
expect(items[0].key).toBe("general");
|
|
377
|
+
});
|
|
378
|
+
it("should handle malformed links.next URL gracefully", async () => {
|
|
379
|
+
const malformedExternalResponse = {
|
|
380
|
+
success: true,
|
|
381
|
+
choices: mockChoices,
|
|
382
|
+
links: {
|
|
383
|
+
next: "invalid-url-format", // Malformed URL
|
|
384
|
+
prev: null,
|
|
385
|
+
},
|
|
386
|
+
};
|
|
387
|
+
mockApiClient.post = vi.fn().mockResolvedValue(malformedExternalResponse);
|
|
388
|
+
const sdk = createTestSdk();
|
|
389
|
+
const listChoicesResult = sdk.listInputFieldChoices({
|
|
390
|
+
appKey: "slack",
|
|
391
|
+
actionType: "read",
|
|
392
|
+
actionKey: "send_message",
|
|
393
|
+
inputFieldKey: "option",
|
|
394
|
+
});
|
|
395
|
+
const pages = [];
|
|
396
|
+
for await (const page of listChoicesResult) {
|
|
397
|
+
pages.push(page);
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
expect(pages).toHaveLength(1);
|
|
401
|
+
expect(pages[0].nextCursor).toBeUndefined(); // Should handle gracefully
|
|
402
|
+
});
|
|
403
|
+
it("should handle links.next URL without page parameter", async () => {
|
|
404
|
+
const noPageResponse = {
|
|
405
|
+
success: true,
|
|
406
|
+
choices: mockChoices,
|
|
407
|
+
links: {
|
|
408
|
+
next: "https://api.zapier.com/api/v4/implementations/choices/", // No page param
|
|
409
|
+
prev: null,
|
|
410
|
+
},
|
|
411
|
+
};
|
|
412
|
+
mockApiClient.post = vi.fn().mockResolvedValue(noPageResponse);
|
|
413
|
+
const sdk = createTestSdk();
|
|
414
|
+
const listChoicesResult = sdk.listInputFieldChoices({
|
|
415
|
+
appKey: "slack",
|
|
416
|
+
actionType: "read",
|
|
417
|
+
actionKey: "send_message",
|
|
418
|
+
inputFieldKey: "option",
|
|
419
|
+
});
|
|
420
|
+
const pages = [];
|
|
421
|
+
for await (const page of listChoicesResult) {
|
|
422
|
+
pages.push(page);
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
expect(pages).toHaveLength(1);
|
|
426
|
+
expect(pages[0].nextCursor).toBeUndefined();
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
describe("error handling", () => {
|
|
430
|
+
it("should throw ZapierApiError when API response indicates failure", async () => {
|
|
431
|
+
mockApiClient.post = vi.fn().mockResolvedValue({
|
|
432
|
+
success: false,
|
|
433
|
+
errors: ["Invalid field", "Missing authentication"],
|
|
434
|
+
});
|
|
435
|
+
const sdk = createTestSdk();
|
|
436
|
+
await expect(sdk.listInputFieldChoices({
|
|
437
|
+
appKey: "slack",
|
|
438
|
+
actionType: "read",
|
|
439
|
+
actionKey: "send_message",
|
|
440
|
+
inputFieldKey: "invalid_field",
|
|
441
|
+
})).rejects.toThrow(ZapierApiError);
|
|
442
|
+
await expect(sdk.listInputFieldChoices({
|
|
443
|
+
appKey: "slack",
|
|
444
|
+
actionType: "read",
|
|
445
|
+
actionKey: "send_message",
|
|
446
|
+
inputFieldKey: "invalid_field",
|
|
447
|
+
})).rejects.toThrow("Failed to get input field choices: Invalid field, Missing authentication");
|
|
448
|
+
});
|
|
449
|
+
it("should handle API errors gracefully", async () => {
|
|
450
|
+
mockApiClient.post = vi
|
|
451
|
+
.fn()
|
|
452
|
+
.mockRejectedValue(new Error("Network error"));
|
|
453
|
+
const sdk = createTestSdk();
|
|
454
|
+
await expect(sdk.listInputFieldChoices({
|
|
455
|
+
appKey: "slack",
|
|
456
|
+
actionType: "read",
|
|
457
|
+
actionKey: "send_message",
|
|
458
|
+
inputFieldKey: "channel",
|
|
459
|
+
})).rejects.toThrow("Network error");
|
|
460
|
+
});
|
|
461
|
+
it("should handle empty choices array response", async () => {
|
|
462
|
+
mockApiClient.post = vi.fn().mockResolvedValue({
|
|
463
|
+
success: true,
|
|
464
|
+
choices: [], // Empty choices
|
|
465
|
+
});
|
|
466
|
+
const sdk = createTestSdk();
|
|
467
|
+
const result = await sdk.listInputFieldChoices({
|
|
468
|
+
appKey: "slack",
|
|
469
|
+
actionType: "read",
|
|
470
|
+
actionKey: "send_message",
|
|
471
|
+
inputFieldKey: "channel",
|
|
472
|
+
});
|
|
473
|
+
expect(result.data).toEqual([]);
|
|
474
|
+
});
|
|
475
|
+
it("should handle missing choices field in response", async () => {
|
|
476
|
+
mockApiClient.post = vi.fn().mockResolvedValue({
|
|
477
|
+
success: true,
|
|
478
|
+
// Missing choices field
|
|
479
|
+
});
|
|
480
|
+
const sdk = createTestSdk();
|
|
481
|
+
const result = await sdk.listInputFieldChoices({
|
|
482
|
+
appKey: "slack",
|
|
483
|
+
actionType: "read",
|
|
484
|
+
actionKey: "send_message",
|
|
485
|
+
inputFieldKey: "channel",
|
|
486
|
+
});
|
|
487
|
+
expect(result.data).toEqual([]);
|
|
488
|
+
});
|
|
489
|
+
it("should treat missing success field as failure", async () => {
|
|
490
|
+
mockApiClient.post = vi.fn().mockResolvedValue({
|
|
491
|
+
// Missing success field (undefined)
|
|
492
|
+
choices: mockChoices,
|
|
493
|
+
});
|
|
494
|
+
const sdk = createTestSdk();
|
|
495
|
+
await expect(sdk.listInputFieldChoices({
|
|
496
|
+
appKey: "slack",
|
|
497
|
+
actionType: "read",
|
|
498
|
+
actionKey: "send_message",
|
|
499
|
+
inputFieldKey: "channel",
|
|
500
|
+
})).rejects.toThrow("Failed to get input field choices: Unknown error");
|
|
501
|
+
});
|
|
502
|
+
it("should handle API response with errors but no error messages", async () => {
|
|
503
|
+
mockApiClient.post = vi.fn().mockResolvedValue({
|
|
504
|
+
success: false,
|
|
505
|
+
// Missing errors field
|
|
506
|
+
});
|
|
507
|
+
const sdk = createTestSdk();
|
|
508
|
+
await expect(sdk.listInputFieldChoices({
|
|
509
|
+
appKey: "slack",
|
|
510
|
+
actionType: "read",
|
|
511
|
+
actionKey: "send_message",
|
|
512
|
+
inputFieldKey: "channel",
|
|
513
|
+
})).rejects.toThrow("Failed to get input field choices: Unknown error");
|
|
514
|
+
});
|
|
515
|
+
it("should handle API response with empty errors array", async () => {
|
|
516
|
+
mockApiClient.post = vi.fn().mockResolvedValue({
|
|
517
|
+
success: false,
|
|
518
|
+
errors: [], // Empty errors array
|
|
519
|
+
});
|
|
520
|
+
const sdk = createTestSdk();
|
|
521
|
+
await expect(sdk.listInputFieldChoices({
|
|
522
|
+
appKey: "slack",
|
|
523
|
+
actionType: "read",
|
|
524
|
+
actionKey: "send_message",
|
|
525
|
+
inputFieldKey: "channel",
|
|
526
|
+
})).rejects.toThrow("Failed to get input field choices: Unknown error");
|
|
527
|
+
});
|
|
528
|
+
});
|
|
529
|
+
describe("context and metadata", () => {
|
|
530
|
+
it("should provide context with meta information", () => {
|
|
531
|
+
const sdk = createTestSdk();
|
|
532
|
+
const context = sdk.getContext();
|
|
533
|
+
expect(context.meta.listInputFieldChoices).toBeDefined();
|
|
534
|
+
expect(context.meta.listInputFieldChoices.inputSchema).toBeDefined();
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { PaginatedSdkFunction } from "../../types/functions";
|
|
3
|
+
import type { ZapierConfigurationError, ZapierApiError, ZapierAuthenticationError, ZapierAppNotFoundError, ZapierValidationError, ZapierUnknownError } from "../../types/errors";
|
|
4
|
+
export declare const InputFieldChoiceItemSchema: z.ZodObject<{
|
|
5
|
+
key: z.ZodOptional<z.ZodString>;
|
|
6
|
+
label: z.ZodOptional<z.ZodString>;
|
|
7
|
+
sample: z.ZodOptional<z.ZodString>;
|
|
8
|
+
value: z.ZodOptional<z.ZodString>;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
value?: string | undefined;
|
|
11
|
+
key?: string | undefined;
|
|
12
|
+
label?: string | undefined;
|
|
13
|
+
sample?: string | undefined;
|
|
14
|
+
}, {
|
|
15
|
+
value?: string | undefined;
|
|
16
|
+
key?: string | undefined;
|
|
17
|
+
label?: string | undefined;
|
|
18
|
+
sample?: string | undefined;
|
|
19
|
+
}>;
|
|
20
|
+
export type InputFieldChoiceItem = z.infer<typeof InputFieldChoiceItemSchema>;
|
|
21
|
+
export declare const ListInputFieldChoicesSchema: z.ZodObject<{
|
|
22
|
+
appKey: z.ZodString;
|
|
23
|
+
actionType: z.ZodEnum<["read", "read_bulk", "write", "run", "search", "search_or_write", "search_and_write", "filter"]>;
|
|
24
|
+
actionKey: z.ZodString;
|
|
25
|
+
inputFieldKey: z.ZodString;
|
|
26
|
+
authenticationId: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
27
|
+
inputs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
28
|
+
page: z.ZodOptional<z.ZodNumber>;
|
|
29
|
+
pageSize: z.ZodOptional<z.ZodNumber>;
|
|
30
|
+
maxItems: z.ZodOptional<z.ZodNumber>;
|
|
31
|
+
}, "strip", z.ZodTypeAny, {
|
|
32
|
+
appKey: string;
|
|
33
|
+
actionType: "filter" | "read" | "read_bulk" | "run" | "search" | "search_and_write" | "search_or_write" | "write";
|
|
34
|
+
actionKey: string;
|
|
35
|
+
inputFieldKey: string;
|
|
36
|
+
page?: number | undefined;
|
|
37
|
+
authenticationId?: number | null | undefined;
|
|
38
|
+
inputs?: Record<string, any> | undefined;
|
|
39
|
+
pageSize?: number | undefined;
|
|
40
|
+
maxItems?: number | undefined;
|
|
41
|
+
}, {
|
|
42
|
+
appKey: string;
|
|
43
|
+
actionType: "filter" | "read" | "read_bulk" | "run" | "search" | "search_and_write" | "search_or_write" | "write";
|
|
44
|
+
actionKey: string;
|
|
45
|
+
inputFieldKey: string;
|
|
46
|
+
page?: number | undefined;
|
|
47
|
+
authenticationId?: number | null | undefined;
|
|
48
|
+
inputs?: Record<string, any> | undefined;
|
|
49
|
+
pageSize?: number | undefined;
|
|
50
|
+
maxItems?: number | undefined;
|
|
51
|
+
}>;
|
|
52
|
+
export type ListInputFieldChoicesOptions = z.infer<typeof ListInputFieldChoicesSchema>;
|
|
53
|
+
export type ListInputFieldChoicesError = ZapierConfigurationError | ZapierApiError | ZapierAuthenticationError | ZapierAppNotFoundError | ZapierValidationError | ZapierUnknownError;
|
|
54
|
+
export interface ListInputFieldChoicesPage {
|
|
55
|
+
data: InputFieldChoiceItem[];
|
|
56
|
+
nextCursor?: string;
|
|
57
|
+
}
|
|
58
|
+
export interface ListInputFieldChoicesSdkFunction {
|
|
59
|
+
listInputFieldChoices: PaginatedSdkFunction<ListInputFieldChoicesOptions, InputFieldChoiceItem>;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=schemas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../../src/plugins/listInputFieldChoices/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EACV,wBAAwB,EACxB,cAAc,EACd,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,oBAAoB,CAAC;AAM5B,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;EAuCtC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAM9E,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwCvC,CAAC;AAGF,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAChD,OAAO,2BAA2B,CACnC,CAAC;AAGF,MAAM,MAAM,0BAA0B,GAClC,wBAAwB,GACxB,cAAc,GACd,yBAAyB,GACzB,sBAAsB,GACtB,qBAAqB,GACrB,kBAAkB,CAAC;AAGvB,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,oBAAoB,EAAE,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAGD,MAAM,WAAW,gCAAgC;IAC/C,qBAAqB,EAAE,oBAAoB,CACzC,4BAA4B,EAC5B,oBAAoB,CACrB,CAAC;CACH"}
|