@zapier/zapier-sdk 0.13.9 → 0.14.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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # @zapier/zapier-sdk
2
2
 
3
+ ## 0.14.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 3f2f104: - Introduce a `services` layer for reusability between plugins
8
+ - `listInputFieldChoices` now supports returning static choices if they exist
9
+
3
10
  ## 0.13.9
4
11
 
5
12
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -1812,6 +1812,64 @@ var RootFieldItemSchema = zod.z.union([
1812
1812
  FieldsetItemSchema
1813
1813
  ]);
1814
1814
 
1815
+ // src/services/implementations.ts
1816
+ async function fetchImplementationNeeds({
1817
+ api,
1818
+ selectedApi,
1819
+ action,
1820
+ actionType,
1821
+ authenticationId,
1822
+ inputs
1823
+ }) {
1824
+ const request = {
1825
+ selected_api: selectedApi,
1826
+ action,
1827
+ type_of: actionType,
1828
+ params: inputs || {}
1829
+ };
1830
+ if (authenticationId !== null) {
1831
+ request.authentication_id = authenticationId;
1832
+ }
1833
+ const response = await api.post(
1834
+ "/api/v4/implementations/needs/",
1835
+ request
1836
+ );
1837
+ if (!response.success) {
1838
+ throw new ZapierApiError(
1839
+ `Failed to get input fields: ${response.errors?.join(", ") || "Unknown error"}`
1840
+ );
1841
+ }
1842
+ return response;
1843
+ }
1844
+ async function fetchImplementationChoices({
1845
+ api,
1846
+ actionId,
1847
+ inputFieldId,
1848
+ authenticationId,
1849
+ inputs,
1850
+ page
1851
+ }) {
1852
+ const request = {
1853
+ action_id: actionId,
1854
+ input_field_id: inputFieldId,
1855
+ page,
1856
+ params: inputs || {}
1857
+ };
1858
+ if (authenticationId !== null) {
1859
+ request.authentication_id = authenticationId;
1860
+ }
1861
+ const response = await api.post(
1862
+ "/api/v4/implementations/choices/",
1863
+ request
1864
+ );
1865
+ if (!response.success) {
1866
+ throw new ZapierApiError(
1867
+ `Failed to get input field choices: ${response.errors?.join(", ") || "Unknown error"}`
1868
+ );
1869
+ }
1870
+ return response;
1871
+ }
1872
+
1815
1873
  // src/plugins/listInputFields/index.ts
1816
1874
  function getInputFieldTypeFromNeed(need) {
1817
1875
  if (need.list) {
@@ -1915,7 +1973,13 @@ var listInputFieldsPlugin = ({ sdk, context }) => {
1915
1973
  const listInputFields = createPaginatedFunction(
1916
1974
  async function listInputFieldsPage(options) {
1917
1975
  const { api, getVersionedImplementationId } = context;
1918
- const { appKey, actionKey, actionType, authenticationId, inputs } = options;
1976
+ const {
1977
+ appKey,
1978
+ actionKey,
1979
+ actionType,
1980
+ authenticationId = null,
1981
+ inputs
1982
+ } = options;
1919
1983
  const selectedApi = await getVersionedImplementationId(appKey);
1920
1984
  if (!selectedApi) {
1921
1985
  throw new ZapierConfigurationError(
@@ -1928,24 +1992,14 @@ var listInputFieldsPlugin = ({ sdk, context }) => {
1928
1992
  actionType,
1929
1993
  actionKey
1930
1994
  });
1931
- const needsRequest = {
1932
- selected_api: selectedApi,
1995
+ const needsData = await fetchImplementationNeeds({
1996
+ api,
1997
+ selectedApi,
1933
1998
  action: action.key,
1934
- type_of: actionType,
1935
- params: inputs || {}
1936
- };
1937
- if (authenticationId !== null) {
1938
- needsRequest.authentication_id = authenticationId;
1939
- }
1940
- const needsData = await api.post(
1941
- "/api/v4/implementations/needs/",
1942
- needsRequest
1943
- );
1944
- if (!needsData.success) {
1945
- throw new ZapierApiError(
1946
- `Failed to get action fields: ${needsData.errors?.join(", ") || "Unknown error"}`
1947
- );
1948
- }
1999
+ actionType,
2000
+ authenticationId,
2001
+ inputs
2002
+ });
1949
2003
  const rootFieldset = transformNeedsToFields(needsData.needs || []);
1950
2004
  return {
1951
2005
  data: rootFieldset,
@@ -3855,43 +3909,62 @@ function transformNeedChoicesToInputFieldChoiceItem(choice) {
3855
3909
  }
3856
3910
  var listInputFieldChoicesPlugin = ({ context, sdk }) => {
3857
3911
  const listInputFieldChoices = createPaginatedFunction(async function listInputFieldChoicesPage(options) {
3858
- const { api } = context;
3912
+ const { api, getVersionedImplementationId } = context;
3859
3913
  const {
3860
3914
  appKey,
3861
3915
  actionType,
3862
3916
  actionKey,
3863
3917
  inputFieldKey,
3864
- authenticationId,
3918
+ authenticationId = null,
3865
3919
  inputs,
3866
3920
  page,
3867
3921
  cursor
3868
3922
  } = options;
3869
- const actionResult = await sdk.getAction({ appKey, actionType, actionKey });
3870
- const actionId = actionResult.data.id;
3871
- if (!actionId) {
3872
- throw new ZapierApiError(
3873
- `Action ${actionKey} does not have an ID - cannot retrieve input field choices`
3923
+ const selectedApi = await getVersionedImplementationId(appKey);
3924
+ if (!selectedApi) {
3925
+ throw new ZapierConfigurationError(
3926
+ "No current_implementation_id found for app",
3927
+ { configType: "current_implementation_id" }
3874
3928
  );
3875
3929
  }
3876
- const requestPage = cursor ? parseInt(cursor, 10) : page ?? 0;
3877
- const choicesRequest = {
3878
- action_id: actionId,
3879
- input_field_id: inputFieldKey,
3880
- page: requestPage,
3881
- params: inputs || {}
3882
- };
3883
- if (authenticationId !== null) {
3884
- choicesRequest.authentication_id = authenticationId;
3885
- }
3886
- const choicesData = await api.post(
3887
- "/api/v4/implementations/choices/",
3888
- choicesRequest
3930
+ const { data: action } = await sdk.getAction({
3931
+ appKey,
3932
+ actionType,
3933
+ actionKey
3934
+ });
3935
+ const needsData = await fetchImplementationNeeds({
3936
+ api,
3937
+ selectedApi,
3938
+ action: action.key,
3939
+ actionType,
3940
+ authenticationId,
3941
+ inputs
3942
+ });
3943
+ const targetNeed = needsData.needs?.find(
3944
+ (need) => need.key === inputFieldKey
3889
3945
  );
3890
- if (!choicesData.success) {
3946
+ if (targetNeed?.choices && targetNeed.choices.length > 0) {
3947
+ return {
3948
+ data: targetNeed.choices.map(
3949
+ transformNeedChoicesToInputFieldChoiceItem
3950
+ ),
3951
+ nextCursor: void 0
3952
+ };
3953
+ }
3954
+ if (!action.id) {
3891
3955
  throw new ZapierApiError(
3892
- `Failed to get input field choices: ${choicesData.errors?.join(", ") || "Unknown error"}`
3956
+ `Action ${actionKey} does not have an ID - cannot retrieve input field choices`
3893
3957
  );
3894
3958
  }
3959
+ const requestPage = cursor ? parseInt(cursor, 10) : page ?? 0;
3960
+ const choicesData = await fetchImplementationChoices({
3961
+ api,
3962
+ actionId: action.id,
3963
+ inputFieldId: inputFieldKey,
3964
+ authenticationId,
3965
+ inputs,
3966
+ page: requestPage
3967
+ });
3895
3968
  const choices = (choicesData.choices || []).map(
3896
3969
  transformNeedChoicesToInputFieldChoiceItem
3897
3970
  );
@@ -4089,7 +4162,7 @@ function getCpuTime() {
4089
4162
 
4090
4163
  // package.json
4091
4164
  var package_default = {
4092
- version: "0.13.9"};
4165
+ version: "0.14.0"};
4093
4166
 
4094
4167
  // src/plugins/eventEmission/builders.ts
4095
4168
  function createBaseEvent(context = {}) {
package/dist/index.mjs CHANGED
@@ -1790,6 +1790,64 @@ var RootFieldItemSchema = z.union([
1790
1790
  FieldsetItemSchema
1791
1791
  ]);
1792
1792
 
1793
+ // src/services/implementations.ts
1794
+ async function fetchImplementationNeeds({
1795
+ api,
1796
+ selectedApi,
1797
+ action,
1798
+ actionType,
1799
+ authenticationId,
1800
+ inputs
1801
+ }) {
1802
+ const request = {
1803
+ selected_api: selectedApi,
1804
+ action,
1805
+ type_of: actionType,
1806
+ params: inputs || {}
1807
+ };
1808
+ if (authenticationId !== null) {
1809
+ request.authentication_id = authenticationId;
1810
+ }
1811
+ const response = await api.post(
1812
+ "/api/v4/implementations/needs/",
1813
+ request
1814
+ );
1815
+ if (!response.success) {
1816
+ throw new ZapierApiError(
1817
+ `Failed to get input fields: ${response.errors?.join(", ") || "Unknown error"}`
1818
+ );
1819
+ }
1820
+ return response;
1821
+ }
1822
+ async function fetchImplementationChoices({
1823
+ api,
1824
+ actionId,
1825
+ inputFieldId,
1826
+ authenticationId,
1827
+ inputs,
1828
+ page
1829
+ }) {
1830
+ const request = {
1831
+ action_id: actionId,
1832
+ input_field_id: inputFieldId,
1833
+ page,
1834
+ params: inputs || {}
1835
+ };
1836
+ if (authenticationId !== null) {
1837
+ request.authentication_id = authenticationId;
1838
+ }
1839
+ const response = await api.post(
1840
+ "/api/v4/implementations/choices/",
1841
+ request
1842
+ );
1843
+ if (!response.success) {
1844
+ throw new ZapierApiError(
1845
+ `Failed to get input field choices: ${response.errors?.join(", ") || "Unknown error"}`
1846
+ );
1847
+ }
1848
+ return response;
1849
+ }
1850
+
1793
1851
  // src/plugins/listInputFields/index.ts
1794
1852
  function getInputFieldTypeFromNeed(need) {
1795
1853
  if (need.list) {
@@ -1893,7 +1951,13 @@ var listInputFieldsPlugin = ({ sdk, context }) => {
1893
1951
  const listInputFields = createPaginatedFunction(
1894
1952
  async function listInputFieldsPage(options) {
1895
1953
  const { api, getVersionedImplementationId } = context;
1896
- const { appKey, actionKey, actionType, authenticationId, inputs } = options;
1954
+ const {
1955
+ appKey,
1956
+ actionKey,
1957
+ actionType,
1958
+ authenticationId = null,
1959
+ inputs
1960
+ } = options;
1897
1961
  const selectedApi = await getVersionedImplementationId(appKey);
1898
1962
  if (!selectedApi) {
1899
1963
  throw new ZapierConfigurationError(
@@ -1906,24 +1970,14 @@ var listInputFieldsPlugin = ({ sdk, context }) => {
1906
1970
  actionType,
1907
1971
  actionKey
1908
1972
  });
1909
- const needsRequest = {
1910
- selected_api: selectedApi,
1973
+ const needsData = await fetchImplementationNeeds({
1974
+ api,
1975
+ selectedApi,
1911
1976
  action: action.key,
1912
- type_of: actionType,
1913
- params: inputs || {}
1914
- };
1915
- if (authenticationId !== null) {
1916
- needsRequest.authentication_id = authenticationId;
1917
- }
1918
- const needsData = await api.post(
1919
- "/api/v4/implementations/needs/",
1920
- needsRequest
1921
- );
1922
- if (!needsData.success) {
1923
- throw new ZapierApiError(
1924
- `Failed to get action fields: ${needsData.errors?.join(", ") || "Unknown error"}`
1925
- );
1926
- }
1977
+ actionType,
1978
+ authenticationId,
1979
+ inputs
1980
+ });
1927
1981
  const rootFieldset = transformNeedsToFields(needsData.needs || []);
1928
1982
  return {
1929
1983
  data: rootFieldset,
@@ -3833,43 +3887,62 @@ function transformNeedChoicesToInputFieldChoiceItem(choice) {
3833
3887
  }
3834
3888
  var listInputFieldChoicesPlugin = ({ context, sdk }) => {
3835
3889
  const listInputFieldChoices = createPaginatedFunction(async function listInputFieldChoicesPage(options) {
3836
- const { api } = context;
3890
+ const { api, getVersionedImplementationId } = context;
3837
3891
  const {
3838
3892
  appKey,
3839
3893
  actionType,
3840
3894
  actionKey,
3841
3895
  inputFieldKey,
3842
- authenticationId,
3896
+ authenticationId = null,
3843
3897
  inputs,
3844
3898
  page,
3845
3899
  cursor
3846
3900
  } = options;
3847
- const actionResult = await sdk.getAction({ appKey, actionType, actionKey });
3848
- const actionId = actionResult.data.id;
3849
- if (!actionId) {
3850
- throw new ZapierApiError(
3851
- `Action ${actionKey} does not have an ID - cannot retrieve input field choices`
3901
+ const selectedApi = await getVersionedImplementationId(appKey);
3902
+ if (!selectedApi) {
3903
+ throw new ZapierConfigurationError(
3904
+ "No current_implementation_id found for app",
3905
+ { configType: "current_implementation_id" }
3852
3906
  );
3853
3907
  }
3854
- const requestPage = cursor ? parseInt(cursor, 10) : page ?? 0;
3855
- const choicesRequest = {
3856
- action_id: actionId,
3857
- input_field_id: inputFieldKey,
3858
- page: requestPage,
3859
- params: inputs || {}
3860
- };
3861
- if (authenticationId !== null) {
3862
- choicesRequest.authentication_id = authenticationId;
3863
- }
3864
- const choicesData = await api.post(
3865
- "/api/v4/implementations/choices/",
3866
- choicesRequest
3908
+ const { data: action } = await sdk.getAction({
3909
+ appKey,
3910
+ actionType,
3911
+ actionKey
3912
+ });
3913
+ const needsData = await fetchImplementationNeeds({
3914
+ api,
3915
+ selectedApi,
3916
+ action: action.key,
3917
+ actionType,
3918
+ authenticationId,
3919
+ inputs
3920
+ });
3921
+ const targetNeed = needsData.needs?.find(
3922
+ (need) => need.key === inputFieldKey
3867
3923
  );
3868
- if (!choicesData.success) {
3924
+ if (targetNeed?.choices && targetNeed.choices.length > 0) {
3925
+ return {
3926
+ data: targetNeed.choices.map(
3927
+ transformNeedChoicesToInputFieldChoiceItem
3928
+ ),
3929
+ nextCursor: void 0
3930
+ };
3931
+ }
3932
+ if (!action.id) {
3869
3933
  throw new ZapierApiError(
3870
- `Failed to get input field choices: ${choicesData.errors?.join(", ") || "Unknown error"}`
3934
+ `Action ${actionKey} does not have an ID - cannot retrieve input field choices`
3871
3935
  );
3872
3936
  }
3937
+ const requestPage = cursor ? parseInt(cursor, 10) : page ?? 0;
3938
+ const choicesData = await fetchImplementationChoices({
3939
+ api,
3940
+ actionId: action.id,
3941
+ inputFieldId: inputFieldKey,
3942
+ authenticationId,
3943
+ inputs,
3944
+ page: requestPage
3945
+ });
3873
3946
  const choices = (choicesData.choices || []).map(
3874
3947
  transformNeedChoicesToInputFieldChoiceItem
3875
3948
  );
@@ -4067,7 +4140,7 @@ function getCpuTime() {
4067
4140
 
4068
4141
  // package.json
4069
4142
  var package_default = {
4070
- version: "0.13.9"};
4143
+ version: "0.14.0"};
4071
4144
 
4072
4145
  // src/plugins/eventEmission/builders.ts
4073
4146
  function createBaseEvent(context = {}) {
@@ -3,6 +3,7 @@ import type { ApiClient } from "../../api";
3
3
  import type { InputFieldChoiceItem } from "./schemas";
4
4
  import { ListInputFieldChoicesSchema, type ListInputFieldChoicesOptions } from "./schemas";
5
5
  import type { GetActionPluginProvides } from "../getAction";
6
+ import type { GetVersionedImplementationId } from "../manifest/schemas";
6
7
  export interface ListInputFieldChoicesPluginProvides {
7
8
  listInputFieldChoices: (options: ListInputFieldChoicesOptions) => Promise<{
8
9
  data: InputFieldChoiceItem[];
@@ -24,6 +25,7 @@ export interface ListInputFieldChoicesPluginProvides {
24
25
  export declare const listInputFieldChoicesPlugin: Plugin<GetSdkType<GetActionPluginProvides>, // requires getAction in SDK
25
26
  {
26
27
  api: ApiClient;
27
- }, // requires api in context
28
+ getVersionedImplementationId: GetVersionedImplementationId;
29
+ }, // requires api and getVersionedImplementationId in context
28
30
  ListInputFieldChoicesPluginProvides>;
29
31
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/listInputFieldChoices/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAM3C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EACL,2BAA2B,EAC3B,KAAK,4BAA4B,EAGlC,MAAM,WAAW,CAAC;AAGnB,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAsB5D,MAAM,WAAW,mCAAmC;IAClD,qBAAqB,EAAE,CAAC,OAAO,EAAE,4BAA4B,KAAK,OAAO,CAAC;QACxE,IAAI,EAAE,oBAAoB,EAAE,CAAC;QAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC,GACA,aAAa,CAAC;QAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG;QACrE,KAAK,IAAI,aAAa,CAAC,oBAAoB,CAAC,CAAC;KAC9C,CAAC;IACJ,OAAO,EAAE;QACP,IAAI,EAAE;YACJ,qBAAqB,EAAE;gBACrB,WAAW,EAAE,OAAO,2BAA2B,CAAC;aACjD,CAAC;SACH,CAAC;KACH,CAAC;CACH;AAED,eAAO,MAAM,2BAA2B,EAAE,MAAM,CAC9C,UAAU,CAAC,uBAAuB,CAAC,EAAE,4BAA4B;AACjE;IAAE,GAAG,EAAE,SAAS,CAAA;CAAE,EAAE,0BAA0B;AAC9C,mCAAmC,CAkHpC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/listInputFieldChoices/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EACL,2BAA2B,EAC3B,KAAK,4BAA4B,EAGlC,MAAM,WAAW,CAAC;AAGnB,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AA0BxE,MAAM,WAAW,mCAAmC;IAClD,qBAAqB,EAAE,CAAC,OAAO,EAAE,4BAA4B,KAAK,OAAO,CAAC;QACxE,IAAI,EAAE,oBAAoB,EAAE,CAAC;QAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC,GACA,aAAa,CAAC;QAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG;QACrE,KAAK,IAAI,aAAa,CAAC,oBAAoB,CAAC,CAAC;KAC9C,CAAC;IACJ,OAAO,EAAE;QACP,IAAI,EAAE;YACJ,qBAAqB,EAAE;gBACrB,WAAW,EAAE,OAAO,2BAA2B,CAAC;aACjD,CAAC;SACH,CAAC;KACH,CAAC;CACH;AAED,eAAO,MAAM,2BAA2B,EAAE,MAAM,CAC9C,UAAU,CAAC,uBAAuB,CAAC,EAAE,4BAA4B;AACjE;IACE,GAAG,EAAE,SAAS,CAAC;IACf,4BAA4B,EAAE,4BAA4B,CAAC;CAC5D,EAAE,2DAA2D;AAC9D,mCAAmC,CAyIpC,CAAC"}
@@ -1,7 +1,8 @@
1
1
  import { ListInputFieldChoicesSchema, InputFieldChoiceItemSchema, } from "./schemas";
2
- import { ZapierApiError } from "../../types/errors";
2
+ import { ZapierApiError, ZapierConfigurationError } from "../../types/errors";
3
3
  import { createPaginatedFunction } from "../../utils/function-utils";
4
4
  import { appKeyResolver, actionTypeResolver, actionKeyResolver, authenticationIdResolver, inputFieldKeyResolver, inputsAllOptionalResolver, } from "../../resolvers";
5
+ import { fetchImplementationNeeds, fetchImplementationChoices, } from "../../services/implementations";
5
6
  // Transform NeedChoices to InputFieldChoiceItem
6
7
  function transformNeedChoicesToInputFieldChoiceItem(choice) {
7
8
  return {
@@ -13,32 +14,52 @@ function transformNeedChoicesToInputFieldChoiceItem(choice) {
13
14
  }
14
15
  export const listInputFieldChoicesPlugin = ({ context, sdk }) => {
15
16
  const listInputFieldChoices = createPaginatedFunction(async function listInputFieldChoicesPage(options) {
16
- const { api } = context;
17
+ const { api, getVersionedImplementationId } = context;
17
18
  // Extract parameters
18
- const { appKey, actionType, actionKey, inputFieldKey, authenticationId, inputs, page, cursor, } = options;
19
- // Use sdk.getAction to get the action ID
20
- const actionResult = await sdk.getAction({ appKey, actionType, actionKey });
21
- const actionId = actionResult.data.id;
22
- if (!actionId) {
19
+ const { appKey, actionType, actionKey, inputFieldKey, authenticationId = null, inputs, page, cursor, } = options;
20
+ // Get versioned implementation ID for the app
21
+ const selectedApi = await getVersionedImplementationId(appKey);
22
+ if (!selectedApi) {
23
+ throw new ZapierConfigurationError("No current_implementation_id found for app", { configType: "current_implementation_id" });
24
+ }
25
+ // Get action details
26
+ const { data: action } = await sdk.getAction({
27
+ appKey,
28
+ actionType,
29
+ actionKey,
30
+ });
31
+ // First, check for static choices by fetching implementation needs directly
32
+ const needsData = await fetchImplementationNeeds({
33
+ api,
34
+ selectedApi,
35
+ action: action.key,
36
+ actionType,
37
+ authenticationId,
38
+ inputs,
39
+ });
40
+ // Find the specific Need by key - search through raw needs array
41
+ const targetNeed = needsData.needs?.find((need) => need.key === inputFieldKey);
42
+ // If the need has static choices, return them
43
+ if (targetNeed?.choices && targetNeed.choices.length > 0) {
44
+ return {
45
+ data: targetNeed.choices.map(transformNeedChoicesToInputFieldChoiceItem),
46
+ nextCursor: undefined,
47
+ };
48
+ }
49
+ if (!action.id) {
23
50
  throw new ZapierApiError(`Action ${actionKey} does not have an ID - cannot retrieve input field choices`);
24
51
  }
25
- // Build choices request using action ID from getAction
26
52
  // Use cursor (from pagination) as page number if available, otherwise use explicit page or default to 0
27
53
  const requestPage = cursor ? parseInt(cursor, 10) : (page ?? 0);
28
- const choicesRequest = {
29
- action_id: actionId,
30
- input_field_id: inputFieldKey,
54
+ // Use service layer to fetch dynamic choices
55
+ const choicesData = await fetchImplementationChoices({
56
+ api,
57
+ actionId: action.id,
58
+ inputFieldId: inputFieldKey,
59
+ authenticationId,
60
+ inputs,
31
61
  page: requestPage,
32
- params: inputs || {},
33
- };
34
- // Only include authentication_id if it's not null (skip authentication when null)
35
- if (authenticationId !== null) {
36
- choicesRequest.authentication_id = authenticationId;
37
- }
38
- const choicesData = await api.post("/api/v4/implementations/choices/", choicesRequest);
39
- if (!choicesData.success) {
40
- throw new ZapierApiError(`Failed to get input field choices: ${choicesData.errors?.join(", ") || "Unknown error"}`);
41
- }
62
+ });
42
63
  // Transform NeedChoices objects to InputFieldChoiceItem objects
43
64
  const choices = (choicesData.choices || []).map(transformNeedChoicesToInputFieldChoiceItem);
44
65
  // Handle pagination
@@ -41,17 +41,73 @@ const mockExternalChoicesResponse = {
41
41
  prev: null,
42
42
  },
43
43
  };
44
+ // Mock needs data for static choices
45
+ const mockNeedsWithStaticChoices = [
46
+ {
47
+ key: "priority",
48
+ label: "Priority",
49
+ help_text: "Select priority",
50
+ required: true,
51
+ type: "string",
52
+ choices: [
53
+ {
54
+ key: "high",
55
+ sample: "high",
56
+ label: "High Priority",
57
+ value: "high",
58
+ },
59
+ {
60
+ key: "medium",
61
+ sample: "medium",
62
+ label: "Medium Priority",
63
+ value: "medium",
64
+ },
65
+ ],
66
+ },
67
+ ];
68
+ const mockNeedsWithoutChoices = [
69
+ {
70
+ key: "channel",
71
+ label: "Channel",
72
+ help_text: "Select a channel",
73
+ required: true,
74
+ type: "string",
75
+ choices: [], // Empty choices
76
+ },
77
+ ];
78
+ const mockNeedsResponse = {
79
+ success: true,
80
+ needs: mockNeedsWithoutChoices,
81
+ };
82
+ const mockNeedsResponseWithStaticChoices = {
83
+ success: true,
84
+ needs: mockNeedsWithStaticChoices,
85
+ };
44
86
  describe("listInputFieldChoices plugin", () => {
45
87
  let mockApiClient;
46
88
  let mockGetAction;
89
+ let mockGetVersionedImplementationId;
47
90
  beforeEach(() => {
48
91
  vi.clearAllMocks();
92
+ // Mock api.post to handle both endpoints
93
+ const mockPost = vi.fn().mockImplementation((path) => {
94
+ if (path === "/api/v4/implementations/needs/") {
95
+ return Promise.resolve(mockNeedsResponse);
96
+ }
97
+ else if (path === "/api/v4/implementations/choices/") {
98
+ return Promise.resolve(mockChoicesResponse);
99
+ }
100
+ return Promise.reject(new Error(`Unexpected endpoint: ${path}`));
101
+ });
49
102
  mockApiClient = {
50
- post: vi.fn().mockResolvedValue(mockChoicesResponse),
103
+ post: mockPost,
51
104
  };
52
105
  mockGetAction = vi.fn().mockResolvedValue({
53
106
  data: { id: "core:123", key: "send_message", action_type: "read" },
54
107
  });
108
+ mockGetVersionedImplementationId = vi
109
+ .fn()
110
+ .mockResolvedValue("SlackCLIAPI@1.21.1");
55
111
  });
56
112
  function createTestSdk() {
57
113
  // Create a mock getAction plugin
@@ -66,7 +122,11 @@ describe("listInputFieldChoices plugin", () => {
66
122
  },
67
123
  });
68
124
  // Build SDK with proper plugin composition
69
- return createSdk({}, {}, { api: mockApiClient, meta: {} })
125
+ return createSdk({}, {}, {
126
+ api: mockApiClient,
127
+ meta: {},
128
+ getVersionedImplementationId: mockGetVersionedImplementationId,
129
+ })
70
130
  .addPlugin(mockGetActionPlugin)
71
131
  .addPlugin(listInputFieldChoicesPlugin);
72
132
  }
@@ -155,6 +215,122 @@ describe("listInputFieldChoices plugin", () => {
155
215
  }
156
216
  });
157
217
  });
218
+ describe("static choices from needs endpoint", () => {
219
+ it("should return static choices when field has them", async () => {
220
+ // Mock api.post to return needs with static choices
221
+ const mockPost = vi.fn().mockImplementation((path) => {
222
+ if (path === "/api/v4/implementations/needs/") {
223
+ return Promise.resolve(mockNeedsResponseWithStaticChoices);
224
+ }
225
+ else if (path === "/api/v4/implementations/choices/") {
226
+ return Promise.resolve(mockChoicesResponse);
227
+ }
228
+ return Promise.reject(new Error(`Unexpected endpoint: ${path}`));
229
+ });
230
+ mockApiClient.post = mockPost;
231
+ const sdk = createTestSdk();
232
+ const result = await sdk.listInputFieldChoices({
233
+ appKey: "slack",
234
+ actionType: "read",
235
+ actionKey: "send_message",
236
+ inputFieldKey: "priority",
237
+ });
238
+ // Should return static choices
239
+ expect(result.data).toHaveLength(2);
240
+ expect(result.data[0]).toEqual({
241
+ key: "high",
242
+ label: "High Priority",
243
+ sample: "high",
244
+ value: "high",
245
+ });
246
+ expect(result.data[1]).toEqual({
247
+ key: "medium",
248
+ label: "Medium Priority",
249
+ sample: "medium",
250
+ value: "medium",
251
+ });
252
+ // Should have called needs endpoint to check for static choices
253
+ expect(mockApiClient.post).toHaveBeenCalledWith("/api/v4/implementations/needs/", {
254
+ selected_api: "SlackCLIAPI@1.21.1",
255
+ action: "send_message",
256
+ type_of: "read",
257
+ params: {},
258
+ });
259
+ // Should not call choices endpoint since static choices were found
260
+ expect(mockApiClient.post).not.toHaveBeenCalledWith("/api/v4/implementations/choices/", expect.anything());
261
+ });
262
+ it("should fall back to dynamic choices when field has empty choices array", async () => {
263
+ // Mock api.post - needs endpoint returns field with empty choices
264
+ const mockPost = vi.fn().mockImplementation((path) => {
265
+ if (path === "/api/v4/implementations/needs/") {
266
+ return Promise.resolve(mockNeedsResponse); // Has empty choices
267
+ }
268
+ else if (path === "/api/v4/implementations/choices/") {
269
+ return Promise.resolve(mockChoicesResponse);
270
+ }
271
+ return Promise.reject(new Error(`Unexpected endpoint: ${path}`));
272
+ });
273
+ mockApiClient.post = mockPost;
274
+ const sdk = createTestSdk();
275
+ const result = await sdk.listInputFieldChoices({
276
+ appKey: "slack",
277
+ actionType: "read",
278
+ actionKey: "send_message",
279
+ inputFieldKey: "channel",
280
+ });
281
+ // Should first call needs endpoint
282
+ expect(mockApiClient.post).toHaveBeenCalledWith("/api/v4/implementations/needs/", {
283
+ selected_api: "SlackCLIAPI@1.21.1",
284
+ action: "send_message",
285
+ type_of: "read",
286
+ params: {},
287
+ });
288
+ // Should then call choices endpoint for dynamic choices
289
+ expect(mockApiClient.post).toHaveBeenCalledWith("/api/v4/implementations/choices/", expect.objectContaining({
290
+ action_id: "core:123",
291
+ input_field_id: "channel",
292
+ }));
293
+ // Should return dynamic choices
294
+ expect(result.data).toHaveLength(3);
295
+ });
296
+ it("should fall back to dynamic choices when field is not found", async () => {
297
+ // Mock api.post - needs endpoint returns different field
298
+ const mockNeedsWithOtherField = {
299
+ success: true,
300
+ needs: [
301
+ {
302
+ key: "other_field",
303
+ label: "Other Field",
304
+ help_text: "Some other field",
305
+ required: false,
306
+ type: "string",
307
+ choices: [],
308
+ },
309
+ ],
310
+ };
311
+ const mockPost = vi.fn().mockImplementation((path) => {
312
+ if (path === "/api/v4/implementations/needs/") {
313
+ return Promise.resolve(mockNeedsWithOtherField);
314
+ }
315
+ else if (path === "/api/v4/implementations/choices/") {
316
+ return Promise.resolve(mockChoicesResponse);
317
+ }
318
+ return Promise.reject(new Error(`Unexpected endpoint: ${path}`));
319
+ });
320
+ mockApiClient.post = mockPost;
321
+ const sdk = createTestSdk();
322
+ await sdk.listInputFieldChoices({
323
+ appKey: "slack",
324
+ actionType: "read",
325
+ actionKey: "send_message",
326
+ inputFieldKey: "channel",
327
+ });
328
+ // Should call needs endpoint first
329
+ expect(mockApiClient.post).toHaveBeenCalledWith("/api/v4/implementations/needs/", expect.anything());
330
+ // Should call choices endpoint since field was not found in needs
331
+ expect(mockApiClient.post).toHaveBeenCalledWith("/api/v4/implementations/choices/", expect.anything());
332
+ });
333
+ });
158
334
  describe("API integration - action method", () => {
159
335
  it("should call the correct API endpoint with action method", async () => {
160
336
  const sdk = createTestSdk();
@@ -439,12 +615,13 @@ describe("listInputFieldChoices plugin", () => {
439
615
  actionKey: "send_message",
440
616
  inputFieldKey: "invalid_field",
441
617
  })).rejects.toThrow(ZapierApiError);
618
+ // Error comes from needs endpoint (first call) with user-friendly message
442
619
  await expect(sdk.listInputFieldChoices({
443
620
  appKey: "slack",
444
621
  actionType: "read",
445
622
  actionKey: "send_message",
446
623
  inputFieldKey: "invalid_field",
447
- })).rejects.toThrow("Failed to get input field choices: Invalid field, Missing authentication");
624
+ })).rejects.toThrow("Failed to get input fields: Invalid field, Missing authentication");
448
625
  });
449
626
  it("should handle API errors gracefully", async () => {
450
627
  mockApiClient.post = vi
@@ -497,7 +674,7 @@ describe("listInputFieldChoices plugin", () => {
497
674
  actionType: "read",
498
675
  actionKey: "send_message",
499
676
  inputFieldKey: "channel",
500
- })).rejects.toThrow("Failed to get input field choices: Unknown error");
677
+ })).rejects.toThrow("Failed to get input fields: Unknown error");
501
678
  });
502
679
  it("should handle API response with errors but no error messages", async () => {
503
680
  mockApiClient.post = vi.fn().mockResolvedValue({
@@ -510,7 +687,7 @@ describe("listInputFieldChoices plugin", () => {
510
687
  actionType: "read",
511
688
  actionKey: "send_message",
512
689
  inputFieldKey: "channel",
513
- })).rejects.toThrow("Failed to get input field choices: Unknown error");
690
+ })).rejects.toThrow("Failed to get input fields: Unknown error");
514
691
  });
515
692
  it("should handle API response with empty errors array", async () => {
516
693
  mockApiClient.post = vi.fn().mockResolvedValue({
@@ -523,7 +700,7 @@ describe("listInputFieldChoices plugin", () => {
523
700
  actionType: "read",
524
701
  actionKey: "send_message",
525
702
  inputFieldKey: "channel",
526
- })).rejects.toThrow("Failed to get input field choices: Unknown error");
703
+ })).rejects.toThrow("Failed to get input fields: Unknown error");
527
704
  });
528
705
  });
529
706
  describe("context and metadata", () => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/listInputFields/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,qBAAqB,EACrB,KAAK,sBAAsB,EAE5B,MAAM,WAAW,CAAC;AAGnB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AAmKxE,MAAM,WAAW,6BAA6B;IAC5C,eAAe,EAAE,CAAC,OAAO,CAAC,EAAE,sBAAsB,KAAK,OAAO,CAAC;QAC7D,IAAI,EAAE,aAAa,EAAE,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC,GACA,aAAa,CAAC;QAAE,IAAI,EAAE,aAAa,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG;QAC9D,KAAK,IAAI,aAAa,CAAC,cAAc,GAAG,aAAa,GAAG,YAAY,CAAC,CAAC;KACvE,CAAC;IACJ,OAAO,EAAE;QACP,IAAI,EAAE;YACJ,eAAe,EAAE;gBACf,WAAW,EAAE,OAAO,qBAAqB,CAAC;aAC3C,CAAC;SACH,CAAC;KACH,CAAC;CACH;AAED,eAAO,MAAM,qBAAqB,EAAE,MAAM,CACxC,UAAU,CAAC,oBAAoB,GAAG,uBAAuB,CAAC,EAAE,uCAAuC;AACnG;IACE,GAAG,EAAE,SAAS,CAAC;IACf,4BAA4B,EAAE,4BAA4B,CAAC;CAC5D,EAAE,2DAA2D;AAC9D,6BAA6B,CAyF9B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/listInputFields/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,qBAAqB,EACrB,KAAK,sBAAsB,EAE5B,MAAM,WAAW,CAAC;AAGnB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAC;AAoKxE,MAAM,WAAW,6BAA6B;IAC5C,eAAe,EAAE,CAAC,OAAO,CAAC,EAAE,sBAAsB,KAAK,OAAO,CAAC;QAC7D,IAAI,EAAE,aAAa,EAAE,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC,GACA,aAAa,CAAC;QAAE,IAAI,EAAE,aAAa,EAAE,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG;QAC9D,KAAK,IAAI,aAAa,CAAC,cAAc,GAAG,aAAa,GAAG,YAAY,CAAC,CAAC;KACvE,CAAC;IACJ,OAAO,EAAE;QACP,IAAI,EAAE;YACJ,eAAe,EAAE;gBACf,WAAW,EAAE,OAAO,qBAAqB,CAAC;aAC3C,CAAC;SACH,CAAC;KACH,CAAC;CACH;AAED,eAAO,MAAM,qBAAqB,EAAE,MAAM,CACxC,UAAU,CAAC,oBAAoB,GAAG,uBAAuB,CAAC,EAAE,uCAAuC;AACnG;IACE,GAAG,EAAE,SAAS,CAAC;IACf,4BAA4B,EAAE,4BAA4B,CAAC;CAC5D,EAAE,2DAA2D;AAC9D,6BAA6B,CA8E9B,CAAC"}
@@ -1,9 +1,10 @@
1
1
  import { ListInputFieldsSchema, } from "./schemas";
2
- import { ZapierConfigurationError, ZapierApiError } from "../../types/errors";
2
+ import { ZapierConfigurationError } from "../../types/errors";
3
3
  import { createPaginatedFunction } from "../../utils/function-utils";
4
4
  import { appKeyResolver, actionTypeResolver, actionKeyResolver, authenticationIdResolver, inputsAllOptionalResolver, } from "../../resolvers";
5
5
  import { RootFieldItemSchema } from "../../schemas/Field";
6
6
  import { toTitleCase } from "../../utils/string-utils";
7
+ import { fetchImplementationNeeds } from "../../services/implementations";
7
8
  // Enums for input field transformation
8
9
  var InputFieldType;
9
10
  (function (InputFieldType) {
@@ -147,7 +148,7 @@ export const listInputFieldsPlugin = ({ sdk, context }) => {
147
148
  // Note: This function ignores pageSize and cursor since it's not actually paginated internally
148
149
  const { api, getVersionedImplementationId } = context;
149
150
  // Extract parameters
150
- const { appKey, actionKey, actionType, authenticationId, inputs } = options;
151
+ const { appKey, actionKey, actionType, authenticationId = null, inputs, } = options;
151
152
  // Use the manifest plugin
152
153
  const selectedApi = await getVersionedImplementationId(appKey);
153
154
  if (!selectedApi) {
@@ -158,21 +159,15 @@ export const listInputFieldsPlugin = ({ sdk, context }) => {
158
159
  actionType,
159
160
  actionKey,
160
161
  });
161
- // Build needs request
162
- const needsRequest = {
163
- selected_api: selectedApi,
162
+ // Use service layer to fetch implementation needs
163
+ const needsData = await fetchImplementationNeeds({
164
+ api,
165
+ selectedApi,
164
166
  action: action.key,
165
- type_of: actionType,
166
- params: inputs || {},
167
- };
168
- // Only include authentication_id if it's not null (skip authentication when null)
169
- if (authenticationId !== null) {
170
- needsRequest.authentication_id = authenticationId;
171
- }
172
- const needsData = await api.post("/api/v4/implementations/needs/", needsRequest);
173
- if (!needsData.success) {
174
- throw new ZapierApiError(`Failed to get action fields: ${needsData.errors?.join(", ") || "Unknown error"}`);
175
- }
167
+ actionType,
168
+ authenticationId,
169
+ inputs,
170
+ });
176
171
  // Transform Need objects to Root Fieldset with proper nesting
177
172
  const rootFieldset = transformNeedsToFields(needsData.needs || []);
178
173
  return {
@@ -208,7 +208,7 @@ describe("listInputFields plugin", () => {
208
208
  placeholder: "Enter your message",
209
209
  default_value: "",
210
210
  }));
211
- // Check channel field with SELECT format
211
+ // Check channel field with SELECT format (choices should NOT be exposed)
212
212
  expect(result.data[1]).toEqual(expect.objectContaining({
213
213
  key: "channel",
214
214
  title: "Channel",
@@ -217,6 +217,8 @@ describe("listInputFields plugin", () => {
217
217
  value_type: "STRING",
218
218
  format: "SELECT",
219
219
  }));
220
+ // Verify choices are NOT exposed in listInputFields output
221
+ expect(result.data[1]).not.toHaveProperty("choices");
220
222
  // Check array field
221
223
  expect(result.data[2]).toEqual(expect.objectContaining({
222
224
  key: "tags",
@@ -298,7 +300,7 @@ describe("listInputFields plugin", () => {
298
300
  appKey: "slack",
299
301
  actionType: "write",
300
302
  actionKey: "send_message", // Use valid action so we get to the POST call
301
- })).rejects.toThrow("Failed to get action fields: Authentication failed, Invalid credentials");
303
+ })).rejects.toThrow("Failed to get input fields: Authentication failed, Invalid credentials");
302
304
  });
303
305
  it("should handle API errors gracefully", async () => {
304
306
  mockApiClient.post = vi
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Implementation Services
3
+ *
4
+ * This module provides domain-specific service functions for interacting with
5
+ * the /api/v4/implementations/* endpoints. These services handle request building,
6
+ * validation, error handling, and authentication for implementation-related API calls.
7
+ *
8
+ * Services are consumed by plugins to avoid code duplication while maintaining
9
+ * separation between the generic HTTP client layer and business logic.
10
+ */
11
+ import type { ApiClient } from "../api";
12
+ import type { NeedsResponse, NeedChoicesResponse } from "../api/types";
13
+ /**
14
+ * Fetches implementation needs (input fields) for a specific action.
15
+ *
16
+ * This service calls the /api/v4/implementations/needs/ endpoint and returns
17
+ * the raw response after validating success. The response includes all field
18
+ * metadata including static choices, field types, and validation rules.
19
+ *
20
+ * @param params - Request parameters
21
+ * @param params.api - API client instance
22
+ * @param params.selectedApi - Versioned implementation ID (e.g., "SlackCLIAPI@1.21.1")
23
+ * @param params.action - Action key
24
+ * @param params.actionType - Action type (read, write, etc.)
25
+ * @param params.authenticationId - Authentication ID (null to skip authentication)
26
+ * @param params.inputs - Input values that may affect available fields
27
+ * @returns Promise resolving to NeedsResponse
28
+ * @throws {ZapierApiError} When the API request fails or returns success: false
29
+ */
30
+ export declare function fetchImplementationNeeds({ api, selectedApi, action, actionType, authenticationId, inputs, }: {
31
+ api: ApiClient;
32
+ selectedApi: string;
33
+ action: string;
34
+ actionType: string;
35
+ authenticationId: number | null;
36
+ inputs?: Record<string, unknown>;
37
+ }): Promise<NeedsResponse>;
38
+ /**
39
+ * Fetches dynamic choices for a specific input field.
40
+ *
41
+ * This service calls the /api/v4/implementations/choices/ endpoint and returns
42
+ * the raw response after validating success. The response includes available
43
+ * choices for dropdown fields with pagination support.
44
+ *
45
+ * @param params - Request parameters
46
+ * @param params.api - API client instance
47
+ * @param params.actionId - Action ID (e.g., "core:123")
48
+ * @param params.inputFieldId - Input field key
49
+ * @param params.authenticationId - Authentication ID (null to skip authentication)
50
+ * @param params.inputs - Input values that may affect available choices
51
+ * @param params.page - Page number for pagination (0-indexed)
52
+ * @returns Promise resolving to NeedChoicesResponse
53
+ * @throws {ZapierApiError} When the API request fails or returns success: false
54
+ */
55
+ export declare function fetchImplementationChoices({ api, actionId, inputFieldId, authenticationId, inputs, page, }: {
56
+ api: ApiClient;
57
+ actionId: string;
58
+ inputFieldId: string;
59
+ authenticationId: number | null;
60
+ inputs?: Record<string, unknown>;
61
+ page: number;
62
+ }): Promise<NeedChoicesResponse>;
63
+ //# sourceMappingURL=implementations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"implementations.d.ts","sourceRoot":"","sources":["../../src/services/implementations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAEV,aAAa,EAEb,mBAAmB,EACpB,MAAM,cAAc,CAAC;AAGtB;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,wBAAwB,CAAC,EAC7C,GAAG,EACH,WAAW,EACX,MAAM,EACN,UAAU,EACV,gBAAgB,EAChB,MAAM,GACP,EAAE;IACD,GAAG,EAAE,SAAS,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC,GAAG,OAAO,CAAC,aAAa,CAAC,CAyBzB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,0BAA0B,CAAC,EAC/C,GAAG,EACH,QAAQ,EACR,YAAY,EACZ,gBAAgB,EAChB,MAAM,EACN,IAAI,GACL,EAAE;IACD,GAAG,EAAE,SAAS,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAyB/B"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Implementation Services
3
+ *
4
+ * This module provides domain-specific service functions for interacting with
5
+ * the /api/v4/implementations/* endpoints. These services handle request building,
6
+ * validation, error handling, and authentication for implementation-related API calls.
7
+ *
8
+ * Services are consumed by plugins to avoid code duplication while maintaining
9
+ * separation between the generic HTTP client layer and business logic.
10
+ */
11
+ import { ZapierApiError } from "../types/errors";
12
+ /**
13
+ * Fetches implementation needs (input fields) for a specific action.
14
+ *
15
+ * This service calls the /api/v4/implementations/needs/ endpoint and returns
16
+ * the raw response after validating success. The response includes all field
17
+ * metadata including static choices, field types, and validation rules.
18
+ *
19
+ * @param params - Request parameters
20
+ * @param params.api - API client instance
21
+ * @param params.selectedApi - Versioned implementation ID (e.g., "SlackCLIAPI@1.21.1")
22
+ * @param params.action - Action key
23
+ * @param params.actionType - Action type (read, write, etc.)
24
+ * @param params.authenticationId - Authentication ID (null to skip authentication)
25
+ * @param params.inputs - Input values that may affect available fields
26
+ * @returns Promise resolving to NeedsResponse
27
+ * @throws {ZapierApiError} When the API request fails or returns success: false
28
+ */
29
+ export async function fetchImplementationNeeds({ api, selectedApi, action, actionType, authenticationId, inputs, }) {
30
+ const request = {
31
+ selected_api: selectedApi,
32
+ action,
33
+ type_of: actionType,
34
+ params: inputs || {},
35
+ };
36
+ // Only include authentication_id if it's not null (skip authentication when null)
37
+ if (authenticationId !== null) {
38
+ request.authentication_id = authenticationId;
39
+ }
40
+ const response = await api.post("/api/v4/implementations/needs/", request);
41
+ if (!response.success) {
42
+ throw new ZapierApiError(`Failed to get input fields: ${response.errors?.join(", ") || "Unknown error"}`);
43
+ }
44
+ return response;
45
+ }
46
+ /**
47
+ * Fetches dynamic choices for a specific input field.
48
+ *
49
+ * This service calls the /api/v4/implementations/choices/ endpoint and returns
50
+ * the raw response after validating success. The response includes available
51
+ * choices for dropdown fields with pagination support.
52
+ *
53
+ * @param params - Request parameters
54
+ * @param params.api - API client instance
55
+ * @param params.actionId - Action ID (e.g., "core:123")
56
+ * @param params.inputFieldId - Input field key
57
+ * @param params.authenticationId - Authentication ID (null to skip authentication)
58
+ * @param params.inputs - Input values that may affect available choices
59
+ * @param params.page - Page number for pagination (0-indexed)
60
+ * @returns Promise resolving to NeedChoicesResponse
61
+ * @throws {ZapierApiError} When the API request fails or returns success: false
62
+ */
63
+ export async function fetchImplementationChoices({ api, actionId, inputFieldId, authenticationId, inputs, page, }) {
64
+ const request = {
65
+ action_id: actionId,
66
+ input_field_id: inputFieldId,
67
+ page,
68
+ params: inputs || {},
69
+ };
70
+ // Only include authentication_id if it's not null (skip authentication when null)
71
+ if (authenticationId !== null) {
72
+ request.authentication_id = authenticationId;
73
+ }
74
+ const response = await api.post("/api/v4/implementations/choices/", request);
75
+ if (!response.success) {
76
+ throw new ZapierApiError(`Failed to get input field choices: ${response.errors?.join(", ") || "Unknown error"}`);
77
+ }
78
+ return response;
79
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zapier/zapier-sdk",
3
- "version": "0.13.9",
3
+ "version": "0.14.0",
4
4
  "description": "Complete Zapier SDK - combines all Zapier SDK packages",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",