@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 +12 -0
- package/dist/index.cjs +22 -3
- package/dist/index.mjs +22 -3
- package/dist/plugins/request/index.d.ts.map +1 -1
- package/dist/plugins/request/index.js +9 -0
- package/dist/plugins/request/index.test.js +67 -0
- package/dist/temporary-internal-core/handlers/listApps.d.ts.map +1 -1
- package/dist/temporary-internal-core/handlers/listApps.js +15 -2
- package/dist/temporary-internal-core/handlers/listApps.test.js +40 -1
- package/package.json +2 -2
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
|
|
3891
|
-
|
|
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.
|
|
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
|
|
3869
|
-
|
|
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.
|
|
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,
|
|
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;
|
|
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
|
-
|
|
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.
|
|
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.
|
|
54
|
+
"@zapier/zapier-sdk-cli-login": "0.3.6"
|
|
55
55
|
},
|
|
56
56
|
"scripts": {
|
|
57
57
|
"build": "tsup",
|