@zapier/zapier-sdk 0.16.0 → 0.16.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @zapier/zapier-sdk
2
2
 
3
+ ## 0.16.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 93cbb3c: Fix search to prefer public app versions over private when user has access to both
8
+
9
+ ## 0.16.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 142c1ce: Fix CLI UX issues: stdout truncation when piped, nullable schema detection for Zod 4, error body display, and auto Content-Type for JSON bodies
14
+
3
15
  ## 0.16.0
4
16
 
5
17
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -2840,6 +2840,16 @@ var requestPlugin = ({ context }) => {
2840
2840
  headers[key] = value;
2841
2841
  }
2842
2842
  }
2843
+ const hasContentType = Object.keys(headers).some(
2844
+ (k) => k.toLowerCase() === "content-type"
2845
+ );
2846
+ if (body && !hasContentType) {
2847
+ const bodyStr = typeof body === "string" ? body : JSON.stringify(body);
2848
+ const trimmed = bodyStr.trimStart();
2849
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
2850
+ headers["Content-Type"] = "application/json; charset=utf-8";
2851
+ }
2852
+ }
2843
2853
  if (authenticationId) {
2844
2854
  headers["X-Relay-Authentication-Id"] = authenticationId.toString();
2845
2855
  }
@@ -3887,8 +3897,17 @@ async function augmentWithSearchResults({
3887
3897
  searchParams: { term: searchTerm }
3888
3898
  }
3889
3899
  );
3890
- const searchResults = searchResponse.results.map(
3891
- transformImplementationMetaToAppItem
3900
+ const byImplementationName = /* @__PURE__ */ new Map();
3901
+ for (const result of searchResponse.results) {
3902
+ const [implementationName] = splitVersionedKey2(result.id);
3903
+ const isPublic = result.visibility === "public";
3904
+ const existing = byImplementationName.get(implementationName);
3905
+ if (!existing || isPublic && !existing.isPublic) {
3906
+ byImplementationName.set(implementationName, { result, isPublic });
3907
+ }
3908
+ }
3909
+ const searchResults = Array.from(byImplementationName.values()).map(
3910
+ (entry) => transformImplementationMetaToAppItem(entry.result)
3892
3911
  );
3893
3912
  const implementationNameSet = new Set(
3894
3913
  implementationIds.map((id) => {
@@ -5008,7 +5027,7 @@ function getCpuTime() {
5008
5027
 
5009
5028
  // package.json
5010
5029
  var package_default = {
5011
- version: "0.16.0"};
5030
+ version: "0.16.2"};
5012
5031
 
5013
5032
  // src/plugins/eventEmission/builders.ts
5014
5033
  function createBaseEvent(context = {}) {
package/dist/index.mjs CHANGED
@@ -2818,6 +2818,16 @@ var requestPlugin = ({ context }) => {
2818
2818
  headers[key] = value;
2819
2819
  }
2820
2820
  }
2821
+ const hasContentType = Object.keys(headers).some(
2822
+ (k) => k.toLowerCase() === "content-type"
2823
+ );
2824
+ if (body && !hasContentType) {
2825
+ const bodyStr = typeof body === "string" ? body : JSON.stringify(body);
2826
+ const trimmed = bodyStr.trimStart();
2827
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
2828
+ headers["Content-Type"] = "application/json; charset=utf-8";
2829
+ }
2830
+ }
2821
2831
  if (authenticationId) {
2822
2832
  headers["X-Relay-Authentication-Id"] = authenticationId.toString();
2823
2833
  }
@@ -3865,8 +3875,17 @@ async function augmentWithSearchResults({
3865
3875
  searchParams: { term: searchTerm }
3866
3876
  }
3867
3877
  );
3868
- const searchResults = searchResponse.results.map(
3869
- transformImplementationMetaToAppItem
3878
+ const byImplementationName = /* @__PURE__ */ new Map();
3879
+ for (const result of searchResponse.results) {
3880
+ const [implementationName] = splitVersionedKey2(result.id);
3881
+ const isPublic = result.visibility === "public";
3882
+ const existing = byImplementationName.get(implementationName);
3883
+ if (!existing || isPublic && !existing.isPublic) {
3884
+ byImplementationName.set(implementationName, { result, isPublic });
3885
+ }
3886
+ }
3887
+ const searchResults = Array.from(byImplementationName.values()).map(
3888
+ (entry) => transformImplementationMetaToAppItem(entry.result)
3870
3889
  );
3871
3890
  const implementationNameSet = new Set(
3872
3891
  implementationIds.map((id) => {
@@ -4986,7 +5005,7 @@ function getCpuTime() {
4986
5005
 
4987
5006
  // package.json
4988
5007
  var package_default = {
4989
- version: "0.16.0"};
5008
+ version: "0.16.2"};
4990
5009
 
4991
5010
  // src/plugins/eventEmission/builders.ts
4992
5011
  function createBaseEvent(context = {}) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/request/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAmB7D,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7D,OAAO,EAAE;QACP,IAAI,EAAE;YACJ,OAAO,EAAE;gBACP,WAAW,EAAE,OAAO,kBAAkB,CAAC;aACxC,CAAC;SACH,CAAC;KACH,CAAC;CACH;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAChC,EAAE,EAAE,sBAAsB;AAC1B,AADI,sBAAsB;AAC1B;IAAE,GAAG,EAAE,SAAS,CAAA;CAAE,GAAG,oBAAoB,EAAE,0BAA0B;AACrE,qBAAqB,CA4EtB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/request/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEzE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAmB7D,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7D,OAAO,EAAE;QACP,IAAI,EAAE;YACJ,OAAO,EAAE;gBACP,WAAW,EAAE,OAAO,kBAAkB,CAAC;aACxC,CAAC;SACH,CAAC;KACH,CAAC;CACH;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAChC,EAAE,EAAE,sBAAsB;AAC1B,AADI,sBAAsB;AAC1B;IAAE,GAAG,EAAE,SAAS,CAAA;CAAE,GAAG,oBAAoB,EAAE,0BAA0B;AACrE,qBAAqB,CAwFtB,CAAC"}
@@ -33,6 +33,15 @@ export const requestPlugin = ({ context }) => {
33
33
  headers[key] = value;
34
34
  }
35
35
  }
36
+ // Auto-set Content-Type for JSON bodies if not already specified
37
+ const hasContentType = Object.keys(headers).some((k) => k.toLowerCase() === "content-type");
38
+ if (body && !hasContentType) {
39
+ const bodyStr = typeof body === "string" ? body : JSON.stringify(body);
40
+ const trimmed = bodyStr.trimStart();
41
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
42
+ headers["Content-Type"] = "application/json; charset=utf-8";
43
+ }
44
+ }
36
45
  // Add Relay-specific headers
37
46
  if (authenticationId) {
38
47
  headers["X-Relay-Authentication-Id"] = authenticationId.toString();
@@ -230,6 +230,73 @@ describe("request plugin", () => {
230
230
  method: "POST",
231
231
  body,
232
232
  });
233
+ expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
234
+ method: "POST",
235
+ body,
236
+ headers: {
237
+ "Content-Type": "application/json; charset=utf-8",
238
+ },
239
+ });
240
+ });
241
+ it("should auto-set Content-Type for JSON object bodies", async () => {
242
+ const sdk = createTestSdk();
243
+ const body = '{"key": "value"}';
244
+ await sdk.request({
245
+ url: "https://api.example.com/data",
246
+ method: "POST",
247
+ body,
248
+ });
249
+ expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
250
+ method: "POST",
251
+ body,
252
+ headers: {
253
+ "Content-Type": "application/json; charset=utf-8",
254
+ },
255
+ });
256
+ });
257
+ it("should auto-set Content-Type for JSON array bodies", async () => {
258
+ const sdk = createTestSdk();
259
+ const body = '[{"id": 1}, {"id": 2}]';
260
+ await sdk.request({
261
+ url: "https://api.example.com/data",
262
+ method: "POST",
263
+ body,
264
+ });
265
+ expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
266
+ method: "POST",
267
+ body,
268
+ headers: {
269
+ "Content-Type": "application/json; charset=utf-8",
270
+ },
271
+ });
272
+ });
273
+ it("should not override explicit Content-Type header", async () => {
274
+ const sdk = createTestSdk();
275
+ const body = '{"key": "value"}';
276
+ await sdk.request({
277
+ url: "https://api.example.com/data",
278
+ method: "POST",
279
+ body,
280
+ headers: {
281
+ "Content-Type": "text/plain",
282
+ },
283
+ });
284
+ expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
285
+ method: "POST",
286
+ body,
287
+ headers: {
288
+ "Content-Type": "text/plain",
289
+ },
290
+ });
291
+ });
292
+ it("should not set Content-Type for non-JSON bodies", async () => {
293
+ const sdk = createTestSdk();
294
+ const body = "plain text body";
295
+ await sdk.request({
296
+ url: "https://api.example.com/data",
297
+ method: "POST",
298
+ body,
299
+ });
233
300
  expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
234
301
  method: "POST",
235
302
  body,
@@ -1 +1 @@
1
- {"version":3,"file":"listApps.d.ts","sourceRoot":"","sources":["../../../src/temporary-internal-core/handlers/listApps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACrD,OAAO,EAEL,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACtB,MAAM,iBAAiB,CAAC;AAkBzB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,CAAC,GAAG,OAAO,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAClD,OAAO,CAAC,CAAC,CAAC,CAAC;CACf;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,UAAU,EAAE,UAAU,CAAC;CACxB;AAwDD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,EAAE,OAAO,CAClC,sBAAsB,EACtB,gBAAgB,EAChB,mBAAmB,CA+EpB,CAAC"}
1
+ {"version":3,"file":"listApps.d.ts","sourceRoot":"","sources":["../../../src/temporary-internal-core/handlers/listApps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACrD,OAAO,EAEL,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACtB,MAAM,iBAAiB,CAAC;AAkBzB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,CAAC,GAAG,OAAO,EACb,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,GAClD,OAAO,CAAC,CAAC,CAAC,CAAC;CACf;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,UAAU,EAAE,UAAU,CAAC;CACxB;AA2ED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,EAAE,OAAO,CAClC,sBAAsB,EACtB,gBAAgB,EAChB,mBAAmB,CA+EpB,CAAC"}
@@ -25,13 +25,26 @@ const DEFAULT_PAGE_SIZE = 20;
25
25
  * Augments implementation IDs with search results
26
26
  *
27
27
  * Calls the search endpoint and merges results with existing implementation IDs,
28
- * deduplicating by implementation name (without version).
28
+ * deduplicating by implementation name (without version) and preferring public versions.
29
29
  */
30
30
  async function augmentWithSearchResults({ searchTerm, implementationIds, httpClient, }) {
31
31
  const searchResponse = await httpClient.get("/zapier/api/v4/implementations-meta/search/", {
32
32
  searchParams: { term: searchTerm },
33
33
  });
34
- const searchResults = searchResponse.results.map(transformImplementationMetaToAppItem);
34
+ // Deduplicate by implementation name, preferring public versions
35
+ // This ensures that when a user has access to both a private version (e.g., 1.0.17)
36
+ // and a public version (e.g., 1.1.0), we use the public one for search results
37
+ const byImplementationName = new Map();
38
+ for (const result of searchResponse.results) {
39
+ const [implementationName] = splitVersionedKey(result.id);
40
+ const isPublic = result.visibility === "public";
41
+ const existing = byImplementationName.get(implementationName);
42
+ // Take this result if we don't have one yet, or if this one is public and existing is not
43
+ if (!existing || (isPublic && !existing.isPublic)) {
44
+ byImplementationName.set(implementationName, { result, isPublic });
45
+ }
46
+ }
47
+ const searchResults = Array.from(byImplementationName.values()).map((entry) => transformImplementationMetaToAppItem(entry.result));
35
48
  const implementationNameSet = new Set(implementationIds.map((id) => {
36
49
  const [name] = splitVersionedKey(id);
37
50
  return name;
@@ -2,13 +2,14 @@ import { describe, it, expect, vi } from "vitest";
2
2
  import { handleListApps, } from "./listApps";
3
3
  import { ListAppsResponseSchema, } from "../schemas/apps";
4
4
  describe("handleListApps", () => {
5
- const mockImplementation = (id, name) => ({
5
+ const mockImplementation = (id, name, visibility = "public") => ({
6
6
  id,
7
7
  name,
8
8
  slug: name.toLowerCase().replace(/\s+/g, "-"),
9
9
  description: `${name} description`,
10
10
  primary_color: "#000000",
11
11
  categories: [{ id: 1, name: "test", slug: "test" }],
12
+ visibility,
12
13
  });
13
14
  describe("pageSize handling", () => {
14
15
  it("should use default pageSize of 20 when not provided", async () => {
@@ -186,6 +187,44 @@ describe("handleListApps", () => {
186
187
  }),
187
188
  }));
188
189
  });
190
+ it("should prefer public version when search returns multiple versions of same app", async () => {
191
+ // Simulates a user having access to both private (1.0.17) and public (1.1.0) versions
192
+ const mockSearchResponse = {
193
+ count: 2,
194
+ results: [
195
+ mockImplementation("LumAppsCLIAPI@1.0.17", "LumApps (1.0.17)", "private"),
196
+ mockImplementation("LumAppsCLIAPI@1.1.0", "LumApps", "public"),
197
+ ],
198
+ };
199
+ const mockLookupResponse = {
200
+ count: 1,
201
+ results: [
202
+ mockImplementation("LumAppsCLIAPI@1.1.0", "LumApps", "public"),
203
+ ],
204
+ next: null,
205
+ };
206
+ const mockHttpClient = {
207
+ get: vi
208
+ .fn()
209
+ .mockResolvedValueOnce(mockSearchResponse)
210
+ .mockResolvedValueOnce(mockLookupResponse),
211
+ };
212
+ await handleListApps({
213
+ request: {
214
+ implementationIds: [],
215
+ search: "lumapps",
216
+ pageSize: undefined,
217
+ cursor: undefined,
218
+ },
219
+ deps: { httpClient: mockHttpClient },
220
+ });
221
+ // Should request the public version (1.1.0), not the private one (1.0.17)
222
+ expect(mockHttpClient.get).toHaveBeenNthCalledWith(2, "/zapier/api/v4/implementations-meta/lookup/", expect.objectContaining({
223
+ searchParams: expect.objectContaining({
224
+ selected_apis: "LumAppsCLIAPI@1.1.0",
225
+ }),
226
+ }));
227
+ });
189
228
  });
190
229
  describe("specific implementation IDs", () => {
191
230
  it("should fetch specific apps when implementationIds provided", async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zapier/zapier-sdk",
3
- "version": "0.16.0",
3
+ "version": "0.16.2",
4
4
  "description": "Complete Zapier SDK - combines all Zapier SDK packages",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
@@ -51,7 +51,7 @@
51
51
  "tsup": "^8.5.0",
52
52
  "typescript": "^5.8.3",
53
53
  "vitest": "^3.2.3",
54
- "@zapier/zapier-sdk-cli-login": "0.3.5"
54
+ "@zapier/zapier-sdk-cli-login": "0.3.6"
55
55
  },
56
56
  "scripts": {
57
57
  "build": "tsup",