@zapier/zapier-sdk 0.13.0 → 0.13.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"domain-utils.d.ts","sourceRoot":"","sources":["../../src/utils/domain-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE/E;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,GACnB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAQ9B;AAED;;;;;GAKG;AACH,wBAAgB,oCAAoC,CAClD,kBAAkB,EAAE,kBAAkB,GACrC,OAAO,CAgBT;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,cAAc,EACpB,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACvD,kBAAkB,CAqCpB;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAsB9D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG;IAC9D,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAgCA;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG;IACrD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAUA;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5C;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOtD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAY1D;AAED,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAI9C;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAkBvD;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,UAAU,GACrB,UAAU,IAAI,kBAAkB,CAElC;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAEzE"}
1
+ {"version":3,"file":"domain-utils.d.ts","sourceRoot":"","sources":["../../src/utils/domain-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE/E;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,GACnB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAQ9B;AAED;;;;;GAKG;AACH,wBAAgB,oCAAoC,CAClD,kBAAkB,EAAE,kBAAkB,GACrC,OAAO,CAYT;AAED;;;;;;;;GAQG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,cAAc,EACpB,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACvD,kBAAkB,CAqCpB;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAsB9D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG;IAC9D,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAgCA;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG;IACrD,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAUA;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5C;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOtD;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAY1D;AAED,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAI9C;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAkBvD;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,UAAU,GACrB,UAAU,IAAI,kBAAkB,CAElC;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,kBAAkB,GAAG,MAAM,CAEzE"}
@@ -27,18 +27,14 @@ export function splitVersionedKey(versionedKey) {
27
27
  * @returns Normalized AppItem with essential fields only
28
28
  */
29
29
  export function normalizeImplementationMetaToAppItem(implementationMeta) {
30
- // Extract API name and version from the implementation ID
31
30
  const [selectedApi, appVersion] = splitVersionedKey(implementationMeta.id);
32
- // Destructure to exclude id and name before spreading
33
31
  const { id, name, ...restOfImplementationMeta } = implementationMeta;
34
32
  return {
35
- // Pass through all ImplementationMeta fields except id and name
36
33
  ...restOfImplementationMeta,
37
- // Transform key fields
38
34
  title: name,
39
35
  key: selectedApi,
40
- implementation_id: id, // Keep the full versioned ID
41
- version: appVersion, // Extract version separately
36
+ implementation_id: id,
37
+ version: appVersion,
42
38
  };
43
39
  }
44
40
  /**
@@ -9,4 +9,13 @@
9
9
  * - mixed formats: "first_name-value" → "First Name Value"
10
10
  */
11
11
  export declare function toTitleCase(input: string): string;
12
+ /**
13
+ * Converts a string to snake_case, handling various input formats:
14
+ * - camelCase: "firstName" → "first_name"
15
+ * - kebab-case: "first-name" → "first_name"
16
+ * - title case: "First Name" → "first_name"
17
+ * - mixed formats: "first-Name Value" → "first_name_value"
18
+ * - starts with number: "123abc" → "_123abc"
19
+ */
20
+ export declare function toSnakeCase(input: string): string;
12
21
  //# sourceMappingURL=string-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"string-utils.d.ts","sourceRoot":"","sources":["../../src/utils/string-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAcjD"}
1
+ {"version":3,"file":"string-utils.d.ts","sourceRoot":"","sources":["../../src/utils/string-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAcjD;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAkBjD"}
@@ -21,3 +21,28 @@ export function toTitleCase(input) {
21
21
  .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
22
22
  .join(" "));
23
23
  }
24
+ /**
25
+ * Converts a string to snake_case, handling various input formats:
26
+ * - camelCase: "firstName" → "first_name"
27
+ * - kebab-case: "first-name" → "first_name"
28
+ * - title case: "First Name" → "first_name"
29
+ * - mixed formats: "first-Name Value" → "first_name_value"
30
+ * - starts with number: "123abc" → "_123abc"
31
+ */
32
+ export function toSnakeCase(input) {
33
+ let result = input
34
+ // insert underscore before capital letters (handles camelCase)
35
+ .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
36
+ // replace spaces and dashes with underscores
37
+ .replace(/[\s\-]+/g, "_")
38
+ // replace multiple underscores with single underscore
39
+ .replace(/_+/g, "_")
40
+ // remove leading/trailing underscores and convert to lowercase
41
+ .replace(/^_|_$/g, "")
42
+ .toLowerCase();
43
+ // If the result starts with a number, prefix with underscore
44
+ if (/^[0-9]/.test(result)) {
45
+ result = "_" + result;
46
+ }
47
+ return result;
48
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zapier/zapier-sdk",
3
- "version": "0.13.0",
3
+ "version": "0.13.2",
4
4
  "description": "Complete Zapier SDK - combines all Zapier SDK packages",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
package/src/index.ts CHANGED
@@ -42,6 +42,9 @@ export { isPositional, PositionalMetadata } from "./utils/schema-utils";
42
42
  export { createFunction } from "./utils/function-utils";
43
43
  export type { FormattedItem, FormatMetadata } from "./utils/schema-utils";
44
44
 
45
+ // Export string utilities
46
+ export { toSnakeCase, toTitleCase } from "./utils/string-utils";
47
+
45
48
  // Export resolver utilities for CLI
46
49
  export * from "./resolvers";
47
50
 
@@ -52,19 +52,41 @@ describe("getApp plugin", () => {
52
52
  const sdk = createTestSdk();
53
53
  const context = sdk.getContext();
54
54
 
55
- // Mock the API client in context to respond to listApps implementation
56
- (context.api as any).get = vi.fn().mockResolvedValue({
57
- results: [
58
- {
59
- id: "SlackCLIAPI@1.0.0",
60
- name: "Slack",
61
- description: "Team communication",
62
- primary_color: "#4A154B",
63
- categories: ["communication"],
64
- },
65
- ],
66
- next: null,
67
- });
55
+ // Mock the API client to handle both resolveAppKeys and listApps calls
56
+ (context.api as any).get = vi
57
+ .fn()
58
+ // First call: resolveAppKeys may call to resolve slug to implementation name
59
+ .mockResolvedValueOnce({
60
+ results: [
61
+ {
62
+ id: "SlackCLIAPI@1.0.0",
63
+ name: "Slack",
64
+ description: "Team communication",
65
+ primary_color: "#4A154B",
66
+ categories: ["communication"],
67
+ slug: "slack",
68
+ key: "SlackCLIAPI",
69
+ version: "1.0.0",
70
+ },
71
+ ],
72
+ next: null,
73
+ })
74
+ // Second call: listApps main API call
75
+ .mockResolvedValueOnce({
76
+ results: [
77
+ {
78
+ id: "SlackCLIAPI@1.0.0",
79
+ name: "Slack",
80
+ description: "Team communication",
81
+ primary_color: "#4A154B",
82
+ categories: ["communication"],
83
+ slug: "slack",
84
+ key: "SlackCLIAPI",
85
+ version: "1.0.0",
86
+ },
87
+ ],
88
+ next: null,
89
+ });
68
90
 
69
91
  const result = await sdk.getApp({
70
92
  appKey: "slack",
@@ -82,11 +104,19 @@ describe("getApp plugin", () => {
82
104
  const sdk = createTestSdk();
83
105
  const context = sdk.getContext();
84
106
 
85
- // Mock API to return empty results (app not found)
86
- (context.api as any).get = vi.fn().mockResolvedValue({
87
- results: [],
88
- next: null,
89
- });
107
+ // Mock API to return empty results for both potential calls
108
+ (context.api as any).get = vi
109
+ .fn()
110
+ // First call: resolveAppKeys may call to resolve slug
111
+ .mockResolvedValueOnce({
112
+ results: [],
113
+ next: null,
114
+ })
115
+ // Second call: listApps main API call
116
+ .mockResolvedValueOnce({
117
+ results: [],
118
+ next: null,
119
+ });
90
120
 
91
121
  await expect(
92
122
  sdk.getApp({
@@ -101,19 +131,41 @@ describe("getApp plugin", () => {
101
131
  const sdk = createTestSdk();
102
132
  const context = sdk.getContext();
103
133
 
104
- // Mock the API client in context to respond to listApps implementation
105
- (context.api as any).get = vi.fn().mockResolvedValue({
106
- results: [
107
- {
108
- id: "TestCLIAPI@1.0.0",
109
- name: "Test App",
110
- description: "Test description",
111
- primary_color: "#FF0000",
112
- categories: ["testing"],
113
- },
114
- ],
115
- next: null,
116
- });
134
+ // Mock the API client to handle both resolveAppKeys and listApps calls
135
+ (context.api as any).get = vi
136
+ .fn()
137
+ // First call: resolveAppKeys may call to resolve slug to implementation name
138
+ .mockResolvedValueOnce({
139
+ results: [
140
+ {
141
+ id: "TestCLIAPI@1.0.0",
142
+ name: "Test App",
143
+ description: "Test description",
144
+ primary_color: "#FF0000",
145
+ categories: ["testing"],
146
+ slug: "test",
147
+ key: "TestCLIAPI",
148
+ version: "1.0.0",
149
+ },
150
+ ],
151
+ next: null,
152
+ })
153
+ // Second call: listApps main API call
154
+ .mockResolvedValueOnce({
155
+ results: [
156
+ {
157
+ id: "TestCLIAPI@1.0.0",
158
+ name: "Test App",
159
+ description: "Test description",
160
+ primary_color: "#FF0000",
161
+ categories: ["testing"],
162
+ slug: "test",
163
+ key: "TestCLIAPI",
164
+ version: "1.0.0",
165
+ },
166
+ ],
167
+ next: null,
168
+ });
117
169
 
118
170
  const result = await sdk.getApp({
119
171
  appKey: "test",
@@ -41,11 +41,11 @@ export const listAppsPlugin: Plugin<
41
41
  const listApps = createPaginatedFunction(async function listAppsPage(
42
42
  options: ListAppsOptions & { cursor?: string } & { pageSize: number },
43
43
  ): Promise<ListAppsPage> {
44
- const api = context.api;
45
- const opts = options;
44
+ const { api, resolveAppKeys } = context;
45
+ const appKeys = options.appKeys ?? [];
46
46
 
47
- const appLocators = await context.resolveAppKeys({
48
- appKeys: [...(opts.appKeys ?? [])],
47
+ const appLocators = await resolveAppKeys({
48
+ appKeys: [...appKeys],
49
49
  });
50
50
  const implementationNameToLocator: Record<string, ResolvedAppLocator[]> =
51
51
  {};
@@ -67,10 +67,10 @@ export const listAppsPlugin: Plugin<
67
67
  );
68
68
  }
69
69
 
70
- if (opts.search) {
70
+ if (options.search) {
71
71
  const searchParams: Record<string, string> = {};
72
72
 
73
- searchParams.term = opts.search;
73
+ searchParams.term = options.search;
74
74
 
75
75
  const searchEnvelope: ImplementationsMetaResponse = await api.get(
76
76
  "/api/v4/implementations-meta/search/",
@@ -101,22 +101,31 @@ export const listAppsPlugin: Plugin<
101
101
 
102
102
  const searchParams: Record<string, string> = {};
103
103
 
104
- if (opts.pageSize) {
105
- searchParams.limit = opts.pageSize.toString();
104
+ if (options.pageSize) {
105
+ searchParams.limit = options.pageSize.toString();
106
106
  }
107
107
 
108
108
  if (appLocators.length === 0) {
109
109
  searchParams.latest_only = "true";
110
110
  }
111
111
 
112
- if (opts.cursor) {
113
- searchParams.offset = opts.cursor;
112
+ if (options.cursor) {
113
+ searchParams.offset = options.cursor;
114
114
  }
115
115
 
116
116
  searchParams.selected_apis = appLocators
117
117
  .map((locator) => toImplementationId(locator))
118
118
  .join(",");
119
119
 
120
+ // If we have app keys, but they resolved to an empty list, then we need to short-circuit and return an empty list.
121
+ // Otherwise, the API will return all apps, since no selected_apis are provided.
122
+ if (appKeys.length > 0 && appLocators.length === 0) {
123
+ return {
124
+ data: [],
125
+ nextCursor: undefined,
126
+ };
127
+ }
128
+
120
129
  const implementationsEnvelope: ImplementationsMetaResponse = await api.get(
121
130
  "/api/v4/implementations-meta/lookup/",
122
131
  {
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { withFormatter } from "../utils/schema-utils";
3
3
  import { ImplementationMetaSchema } from "../api/schemas";
4
+ import { toSnakeCase } from "../utils/string-utils";
4
5
 
5
6
  export { FormattedItem, FormatMetadata } from "../utils/schema-utils";
6
7
 
@@ -16,10 +17,20 @@ export const AppItemSchema = withFormatter(
16
17
  }),
17
18
  {
18
19
  format: (item) => {
20
+ // Create additional keys if slug exists
21
+ const additionalKeys = [];
22
+ if (item.slug && item.slug !== item.key) {
23
+ additionalKeys.push(item.slug);
24
+ const snakeCaseSlug = toSnakeCase(item.slug);
25
+ if (snakeCaseSlug !== item.slug && snakeCaseSlug !== item.key) {
26
+ additionalKeys.push(snakeCaseSlug);
27
+ }
28
+ }
29
+
19
30
  return {
20
31
  title: item.title,
21
32
  key: item.key,
22
- keys: [item.slug, item.key].filter(Boolean),
33
+ keys: [item.key, ...additionalKeys],
23
34
  description: item.description,
24
35
  details: [],
25
36
  };
@@ -36,20 +36,16 @@ export function splitVersionedKey(
36
36
  export function normalizeImplementationMetaToAppItem(
37
37
  implementationMeta: ImplementationMeta,
38
38
  ): AppItem {
39
- // Extract API name and version from the implementation ID
40
39
  const [selectedApi, appVersion] = splitVersionedKey(implementationMeta.id);
41
40
 
42
- // Destructure to exclude id and name before spreading
43
41
  const { id, name, ...restOfImplementationMeta } = implementationMeta;
44
42
 
45
43
  return {
46
- // Pass through all ImplementationMeta fields except id and name
47
44
  ...restOfImplementationMeta,
48
- // Transform key fields
49
45
  title: name,
50
46
  key: selectedApi,
51
- implementation_id: id, // Keep the full versioned ID
52
- version: appVersion, // Extract version separately
47
+ implementation_id: id,
48
+ version: appVersion,
53
49
  };
54
50
  }
55
51
 
@@ -24,3 +24,31 @@ export function toTitleCase(input: string): string {
24
24
  .join(" ")
25
25
  );
26
26
  }
27
+
28
+ /**
29
+ * Converts a string to snake_case, handling various input formats:
30
+ * - camelCase: "firstName" → "first_name"
31
+ * - kebab-case: "first-name" → "first_name"
32
+ * - title case: "First Name" → "first_name"
33
+ * - mixed formats: "first-Name Value" → "first_name_value"
34
+ * - starts with number: "123abc" → "_123abc"
35
+ */
36
+ export function toSnakeCase(input: string): string {
37
+ let result = input
38
+ // insert underscore before capital letters (handles camelCase)
39
+ .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
40
+ // replace spaces and dashes with underscores
41
+ .replace(/[\s\-]+/g, "_")
42
+ // replace multiple underscores with single underscore
43
+ .replace(/_+/g, "_")
44
+ // remove leading/trailing underscores and convert to lowercase
45
+ .replace(/^_|_$/g, "")
46
+ .toLowerCase();
47
+
48
+ // If the result starts with a number, prefix with underscore
49
+ if (/^[0-9]/.test(result)) {
50
+ result = "_" + result;
51
+ }
52
+
53
+ return result;
54
+ }