@zapier/zapier-sdk 0.33.0 → 0.33.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.
Files changed (128) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/index.cjs +2 -1
  3. package/dist/index.d.mts +9 -1
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.mjs +2 -1
  7. package/dist/plugins/registry/index.d.ts.map +1 -1
  8. package/dist/plugins/registry/index.js +1 -0
  9. package/dist/types/sdk.d.ts +8 -0
  10. package/dist/types/sdk.d.ts.map +1 -1
  11. package/package.json +2 -2
  12. package/dist/api/auth.test.d.ts +0 -2
  13. package/dist/api/auth.test.d.ts.map +0 -1
  14. package/dist/api/auth.test.js +0 -220
  15. package/dist/api/client.test.d.ts +0 -2
  16. package/dist/api/client.test.d.ts.map +0 -1
  17. package/dist/api/client.test.js +0 -611
  18. package/dist/api/debug.test.d.ts +0 -2
  19. package/dist/api/debug.test.d.ts.map +0 -1
  20. package/dist/api/debug.test.js +0 -59
  21. package/dist/api/polling.test.d.ts +0 -2
  22. package/dist/api/polling.test.d.ts.map +0 -1
  23. package/dist/api/polling.test.js +0 -360
  24. package/dist/auth.test.d.ts +0 -2
  25. package/dist/auth.test.d.ts.map +0 -1
  26. package/dist/auth.test.js +0 -480
  27. package/dist/plugins/eventEmission/builders.test.d.ts +0 -2
  28. package/dist/plugins/eventEmission/builders.test.d.ts.map +0 -1
  29. package/dist/plugins/eventEmission/builders.test.js +0 -138
  30. package/dist/plugins/eventEmission/index.test.d.ts +0 -5
  31. package/dist/plugins/eventEmission/index.test.d.ts.map +0 -1
  32. package/dist/plugins/eventEmission/index.test.js +0 -712
  33. package/dist/plugins/eventEmission/transport.test.d.ts +0 -5
  34. package/dist/plugins/eventEmission/transport.test.d.ts.map +0 -1
  35. package/dist/plugins/eventEmission/transport.test.js +0 -164
  36. package/dist/plugins/fetch/index.test.d.ts +0 -2
  37. package/dist/plugins/fetch/index.test.d.ts.map +0 -1
  38. package/dist/plugins/fetch/index.test.js +0 -428
  39. package/dist/plugins/findFirstConnection/index.test.d.ts +0 -2
  40. package/dist/plugins/findFirstConnection/index.test.d.ts.map +0 -1
  41. package/dist/plugins/findFirstConnection/index.test.js +0 -177
  42. package/dist/plugins/findUniqueConnection/index.test.d.ts +0 -2
  43. package/dist/plugins/findUniqueConnection/index.test.d.ts.map +0 -1
  44. package/dist/plugins/findUniqueConnection/index.test.js +0 -159
  45. package/dist/plugins/getAction/index.test.d.ts +0 -2
  46. package/dist/plugins/getAction/index.test.d.ts.map +0 -1
  47. package/dist/plugins/getAction/index.test.js +0 -211
  48. package/dist/plugins/getApp/index.test.d.ts +0 -2
  49. package/dist/plugins/getApp/index.test.d.ts.map +0 -1
  50. package/dist/plugins/getApp/index.test.js +0 -157
  51. package/dist/plugins/getConnection/index.test.d.ts +0 -2
  52. package/dist/plugins/getConnection/index.test.d.ts.map +0 -1
  53. package/dist/plugins/getConnection/index.test.js +0 -124
  54. package/dist/plugins/getInputFieldsSchema/index.test.d.ts +0 -2
  55. package/dist/plugins/getInputFieldsSchema/index.test.d.ts.map +0 -1
  56. package/dist/plugins/getInputFieldsSchema/index.test.js +0 -291
  57. package/dist/plugins/listActions/index.test.d.ts +0 -2
  58. package/dist/plugins/listActions/index.test.d.ts.map +0 -1
  59. package/dist/plugins/listActions/index.test.js +0 -454
  60. package/dist/plugins/listApps/index.test.d.ts +0 -2
  61. package/dist/plugins/listApps/index.test.d.ts.map +0 -1
  62. package/dist/plugins/listApps/index.test.js +0 -124
  63. package/dist/plugins/listConnections/index.test.d.ts +0 -2
  64. package/dist/plugins/listConnections/index.test.d.ts.map +0 -1
  65. package/dist/plugins/listConnections/index.test.js +0 -920
  66. package/dist/plugins/listInputFieldChoices/index.test.d.ts +0 -2
  67. package/dist/plugins/listInputFieldChoices/index.test.d.ts.map +0 -1
  68. package/dist/plugins/listInputFieldChoices/index.test.js +0 -717
  69. package/dist/plugins/listInputFields/index.test.d.ts +0 -2
  70. package/dist/plugins/listInputFields/index.test.d.ts.map +0 -1
  71. package/dist/plugins/listInputFields/index.test.js +0 -359
  72. package/dist/plugins/manifest/index.test.d.ts +0 -2
  73. package/dist/plugins/manifest/index.test.d.ts.map +0 -1
  74. package/dist/plugins/manifest/index.test.js +0 -1179
  75. package/dist/plugins/request/index.test.d.ts +0 -2
  76. package/dist/plugins/request/index.test.d.ts.map +0 -1
  77. package/dist/plugins/request/index.test.js +0 -458
  78. package/dist/plugins/runAction/index.test.d.ts +0 -2
  79. package/dist/plugins/runAction/index.test.d.ts.map +0 -1
  80. package/dist/plugins/runAction/index.test.js +0 -350
  81. package/dist/resolvers/connectionId.test.d.ts +0 -2
  82. package/dist/resolvers/connectionId.test.d.ts.map +0 -1
  83. package/dist/resolvers/connectionId.test.js +0 -61
  84. package/dist/sdk.test.d.ts +0 -2
  85. package/dist/sdk.test.d.ts.map +0 -1
  86. package/dist/sdk.test.js +0 -260
  87. package/dist/types/domain.test.d.ts +0 -2
  88. package/dist/types/domain.test.d.ts.map +0 -1
  89. package/dist/types/domain.test.js +0 -39
  90. package/dist/utils/array-utils.test.d.ts +0 -2
  91. package/dist/utils/array-utils.test.d.ts.map +0 -1
  92. package/dist/utils/array-utils.test.js +0 -107
  93. package/dist/utils/batch-utils.test.d.ts +0 -2
  94. package/dist/utils/batch-utils.test.d.ts.map +0 -1
  95. package/dist/utils/batch-utils.test.js +0 -476
  96. package/dist/utils/domain-utils.test.d.ts +0 -2
  97. package/dist/utils/domain-utils.test.d.ts.map +0 -1
  98. package/dist/utils/domain-utils.test.js +0 -346
  99. package/dist/utils/file-utils.test.d.ts +0 -2
  100. package/dist/utils/file-utils.test.d.ts.map +0 -1
  101. package/dist/utils/file-utils.test.js +0 -51
  102. package/dist/utils/function-utils.test.d.ts +0 -2
  103. package/dist/utils/function-utils.test.d.ts.map +0 -1
  104. package/dist/utils/function-utils.test.js +0 -188
  105. package/dist/utils/id-utils.test.d.ts +0 -2
  106. package/dist/utils/id-utils.test.d.ts.map +0 -1
  107. package/dist/utils/id-utils.test.js +0 -22
  108. package/dist/utils/pagination-utils.test.d.ts +0 -17
  109. package/dist/utils/pagination-utils.test.d.ts.map +0 -1
  110. package/dist/utils/pagination-utils.test.js +0 -461
  111. package/dist/utils/retry-utils.test.d.ts +0 -2
  112. package/dist/utils/retry-utils.test.d.ts.map +0 -1
  113. package/dist/utils/retry-utils.test.js +0 -90
  114. package/dist/utils/string-utils.test.d.ts +0 -2
  115. package/dist/utils/string-utils.test.d.ts.map +0 -1
  116. package/dist/utils/string-utils.test.js +0 -59
  117. package/dist/utils/telemetry-context.test.d.ts +0 -2
  118. package/dist/utils/telemetry-context.test.d.ts.map +0 -1
  119. package/dist/utils/telemetry-context.test.js +0 -154
  120. package/dist/utils/telemetry-utils.test.d.ts +0 -2
  121. package/dist/utils/telemetry-utils.test.d.ts.map +0 -1
  122. package/dist/utils/telemetry-utils.test.js +0 -155
  123. package/dist/utils/url-utils.test.d.ts +0 -2
  124. package/dist/utils/url-utils.test.d.ts.map +0 -1
  125. package/dist/utils/url-utils.test.js +0 -103
  126. package/dist/utils/validation.test.d.ts +0 -2
  127. package/dist/utils/validation.test.d.ts.map +0 -1
  128. package/dist/utils/validation.test.js +0 -44
@@ -1,5 +0,0 @@
1
- /**
2
- * Tests for Event Transport Layer
3
- */
4
- export {};
5
- //# sourceMappingURL=transport.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"transport.test.d.ts","sourceRoot":"","sources":["../../../src/plugins/eventEmission/transport.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -1,164 +0,0 @@
1
- /**
2
- * Tests for Event Transport Layer
3
- */
4
- import { describe, it, expect, vi, beforeEach } from "vitest";
5
- import { createHttpTransport, createConsoleTransport, createNoopTransport, createTransport, } from "./transport";
6
- // Mock fetch globally
7
- const mockFetch = vi.fn();
8
- global.fetch = mockFetch;
9
- // Mock console.log
10
- const mockConsoleLog = vi.spyOn(console, "log").mockImplementation(() => { });
11
- describe("Transport Layer", () => {
12
- const sampleEvent = {
13
- event_id: "test-123",
14
- timestamp_ms: Date.now(),
15
- release_id: "test-release",
16
- error_message: "Test error",
17
- is_user_facing: false,
18
- };
19
- const sampleSubject = "platform.sdk.ErrorOccurredEvent";
20
- beforeEach(() => {
21
- vi.clearAllMocks();
22
- });
23
- describe("createHttpTransport", () => {
24
- it("should emit events via HTTP successfully", async () => {
25
- mockFetch.mockResolvedValueOnce({
26
- ok: true,
27
- status: 200,
28
- });
29
- const transport = createHttpTransport({
30
- endpoint: "https://telemetry.example.com/events",
31
- headers: { "x-api-key": "test-key" },
32
- });
33
- await transport.emit(sampleSubject, sampleEvent);
34
- expect(mockFetch).toHaveBeenCalledWith("https://telemetry.example.com/events", {
35
- method: "POST",
36
- headers: {
37
- "Content-Type": "application/json",
38
- "x-api-key": "test-key",
39
- },
40
- body: JSON.stringify({
41
- subject: sampleSubject,
42
- properties: sampleEvent,
43
- }),
44
- });
45
- });
46
- it("should retry on HTTP failures", async () => {
47
- // Fail twice, then succeed
48
- mockFetch
49
- .mockResolvedValueOnce({ ok: false, status: 500 })
50
- .mockResolvedValueOnce({ ok: false, status: 500 })
51
- .mockResolvedValueOnce({ ok: true, status: 200 });
52
- const transport = createHttpTransport({
53
- endpoint: "https://telemetry.example.com/events",
54
- retryAttempts: 3,
55
- retryDelayMs: 10, // Short delay for testing
56
- });
57
- await transport.emit(sampleSubject, sampleEvent);
58
- expect(mockFetch).toHaveBeenCalledTimes(3);
59
- });
60
- it("should handle network errors silently", async () => {
61
- mockFetch.mockRejectedValue(new Error("Network error"));
62
- const transport = createHttpTransport({
63
- endpoint: "https://telemetry.example.com/events",
64
- retryAttempts: 1,
65
- retryDelayMs: 1,
66
- });
67
- // Should not throw despite network error
68
- await expect(transport.emit(sampleSubject, sampleEvent)).resolves.toBeUndefined();
69
- });
70
- it("should stop retrying after max attempts", async () => {
71
- mockFetch.mockResolvedValue({ ok: false, status: 500 });
72
- const transport = createHttpTransport({
73
- endpoint: "https://telemetry.example.com/events",
74
- retryAttempts: 2,
75
- retryDelayMs: 1,
76
- });
77
- await transport.emit(sampleSubject, sampleEvent);
78
- expect(mockFetch).toHaveBeenCalledTimes(2);
79
- });
80
- });
81
- describe("createConsoleTransport", () => {
82
- it("should log events to console", async () => {
83
- const transport = createConsoleTransport();
84
- await transport.emit(sampleSubject, sampleEvent);
85
- expect(mockConsoleLog).toHaveBeenCalledWith("[SDK Telemetry]", JSON.stringify({ subject: sampleSubject, properties: sampleEvent }, null, 2));
86
- });
87
- it("should handle console errors silently", async () => {
88
- mockConsoleLog.mockImplementation(() => {
89
- throw new Error("Console error");
90
- });
91
- const transport = createConsoleTransport();
92
- // Should not throw despite console error
93
- await expect(transport.emit(sampleSubject, sampleEvent)).resolves.toBeUndefined();
94
- });
95
- });
96
- describe("createNoopTransport", () => {
97
- it("should do nothing when emitting events", async () => {
98
- const transport = createNoopTransport();
99
- await transport.emit(sampleSubject, sampleEvent);
100
- // Verify no side effects
101
- expect(mockFetch).not.toHaveBeenCalled();
102
- expect(mockConsoleLog).not.toHaveBeenCalled();
103
- });
104
- });
105
- describe("createTransport", () => {
106
- it("should create HTTP transport with valid config", async () => {
107
- mockFetch.mockResolvedValueOnce({ ok: true, status: 200 });
108
- const transport = createTransport({
109
- type: "http",
110
- endpoint: "https://example.com",
111
- headers: { "x-key": "value" },
112
- retryAttempts: 5,
113
- retryDelayMs: 2000,
114
- });
115
- expect(transport.emit).toBeTypeOf("function");
116
- await transport.emit(sampleSubject, sampleEvent);
117
- expect(mockFetch).toHaveBeenCalledWith("https://example.com", expect.any(Object));
118
- });
119
- it("should create console transport", async () => {
120
- const transport = createTransport({
121
- type: "console",
122
- });
123
- expect(transport.emit).toBeTypeOf("function");
124
- await transport.emit(sampleSubject, sampleEvent);
125
- expect(mockConsoleLog).toHaveBeenCalled();
126
- });
127
- it("should create noop transport by default", async () => {
128
- const transport = createTransport({
129
- type: "noop",
130
- });
131
- expect(transport.emit).toBeTypeOf("function");
132
- await transport.emit(sampleSubject, sampleEvent);
133
- expect(mockFetch).not.toHaveBeenCalled();
134
- expect(mockConsoleLog).not.toHaveBeenCalled();
135
- });
136
- it("should fallback to noop transport on invalid HTTP config", async () => {
137
- const transport = createTransport({
138
- type: "http",
139
- // Missing endpoint
140
- });
141
- expect(transport.emit).toBeTypeOf("function");
142
- await transport.emit(sampleSubject, sampleEvent);
143
- expect(mockFetch).not.toHaveBeenCalled();
144
- });
145
- it("should fallback to noop transport on unknown type", async () => {
146
- const transport = createTransport({
147
- type: "unknown",
148
- });
149
- expect(transport.emit).toBeTypeOf("function");
150
- await transport.emit(sampleSubject, sampleEvent);
151
- expect(mockFetch).not.toHaveBeenCalled();
152
- expect(mockConsoleLog).not.toHaveBeenCalled();
153
- });
154
- it("should handle transport creation errors gracefully", async () => {
155
- expect(() => {
156
- const transport = createTransport({
157
- type: "http",
158
- // Missing required endpoint - should fallback to noop
159
- });
160
- expect(transport.emit).toBeTypeOf("function");
161
- }).not.toThrow();
162
- });
163
- });
164
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=index.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../src/plugins/fetch/index.test.ts"],"names":[],"mappings":""}
@@ -1,428 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest";
2
- import { fetchPlugin } from "./index";
3
- import { createSdk } from "../../sdk";
4
- import { eventEmissionPlugin } from "../eventEmission";
5
- import { ZapierRelayError } from "../../types/errors";
6
- describe("fetch plugin", () => {
7
- let mockApiClient;
8
- let mockFetch;
9
- beforeEach(() => {
10
- vi.clearAllMocks();
11
- mockFetch = vi.fn().mockResolvedValue(new Response('{"success": true}', {
12
- status: 200,
13
- headers: { "Content-Type": "application/json" },
14
- }));
15
- mockApiClient = {
16
- fetch: mockFetch,
17
- };
18
- });
19
- const apiPlugin = () => ({
20
- context: {
21
- api: mockApiClient,
22
- },
23
- });
24
- function createTestSdk() {
25
- return createSdk()
26
- .addPlugin(() => ({
27
- context: {
28
- options: {},
29
- },
30
- }))
31
- .addPlugin(apiPlugin)
32
- .addPlugin(eventEmissionPlugin)
33
- .addPlugin(fetchPlugin);
34
- }
35
- describe("URL transformation", () => {
36
- it("should transform full URLs to relay path format", async () => {
37
- const sdk = createTestSdk();
38
- await sdk.fetch("https://api.github.com/user");
39
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.github.com/user", expect.any(Object));
40
- });
41
- it("should preserve query parameters and fragments", async () => {
42
- const sdk = createTestSdk();
43
- await sdk.fetch("https://api.example.com/search?q=test&limit=10#section");
44
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/search?q=test&limit=10#section", expect.any(Object));
45
- });
46
- it("should handle URLs with ports", async () => {
47
- const sdk = createTestSdk();
48
- await sdk.fetch("https://api.example.com:8443/data");
49
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com:8443/data", expect.any(Object));
50
- });
51
- it("should handle URL objects", async () => {
52
- const sdk = createTestSdk();
53
- await sdk.fetch(new URL("https://api.example.com/data"));
54
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", expect.any(Object));
55
- });
56
- });
57
- describe("headers handling", () => {
58
- it("should pass through regular headers", async () => {
59
- const sdk = createTestSdk();
60
- const headers = {
61
- "Content-Type": "application/json",
62
- "X-Custom-Header": "test-value",
63
- };
64
- await sdk.fetch("https://api.example.com/data", {
65
- method: "POST",
66
- headers,
67
- });
68
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
69
- method: "POST",
70
- body: undefined,
71
- headers: {
72
- "Content-Type": "application/json",
73
- "X-Custom-Header": "test-value",
74
- },
75
- authRequired: true,
76
- });
77
- });
78
- it("should add relay-specific headers when provided", async () => {
79
- const sdk = createTestSdk();
80
- await sdk.fetch("https://api.example.com/data", {
81
- method: "POST",
82
- authenticationId: 123,
83
- callbackUrl: "https://webhook.example.com/callback",
84
- });
85
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
86
- method: "POST",
87
- body: undefined,
88
- headers: {
89
- "X-Relay-Authentication-Id": "123",
90
- "X-Relay-Callback-Url": "https://webhook.example.com/callback",
91
- },
92
- authRequired: true,
93
- });
94
- });
95
- it("should handle Headers object", async () => {
96
- const sdk = createTestSdk();
97
- const headers = new Headers();
98
- headers.set("Content-Type", "application/json");
99
- headers.set("Authorization", "Bearer token");
100
- await sdk.fetch("https://api.example.com/data", { headers });
101
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
102
- method: "GET",
103
- body: undefined,
104
- headers: {
105
- "content-type": "application/json",
106
- authorization: "Bearer token",
107
- },
108
- authRequired: true,
109
- });
110
- });
111
- it("should handle headers as array of tuples", async () => {
112
- const sdk = createTestSdk();
113
- const headers = [
114
- ["Content-Type", "application/json"],
115
- ["X-Api-Key", "secret"],
116
- ];
117
- await sdk.fetch("https://api.example.com/data", { headers });
118
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
119
- method: "GET",
120
- body: undefined,
121
- headers: {
122
- "Content-Type": "application/json",
123
- "X-Api-Key": "secret",
124
- },
125
- authRequired: true,
126
- });
127
- });
128
- });
129
- describe("HTTP methods", () => {
130
- const methods = [
131
- "GET",
132
- "POST",
133
- "PUT",
134
- "DELETE",
135
- "PATCH",
136
- "HEAD",
137
- "OPTIONS",
138
- ];
139
- methods.forEach((method) => {
140
- it(`should support ${method} method`, async () => {
141
- const sdk = createTestSdk();
142
- await sdk.fetch("https://api.example.com/data", { method });
143
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
144
- method,
145
- body: undefined,
146
- headers: {},
147
- authRequired: true,
148
- });
149
- });
150
- });
151
- it("should default to GET method", async () => {
152
- const sdk = createTestSdk();
153
- await sdk.fetch("https://api.example.com/data");
154
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
155
- method: "GET",
156
- body: undefined,
157
- headers: {},
158
- authRequired: true,
159
- });
160
- });
161
- });
162
- describe("request body", () => {
163
- it("should pass through request body", async () => {
164
- const sdk = createTestSdk();
165
- const body = '{"name": "test", "value": 42}';
166
- await sdk.fetch("https://api.example.com/data", {
167
- method: "POST",
168
- body,
169
- });
170
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
171
- method: "POST",
172
- body,
173
- headers: {
174
- "Content-Type": "application/json; charset=utf-8",
175
- },
176
- authRequired: true,
177
- });
178
- });
179
- it("should auto-set Content-Type for JSON object bodies", async () => {
180
- const sdk = createTestSdk();
181
- const body = '{"key": "value"}';
182
- await sdk.fetch("https://api.example.com/data", {
183
- method: "POST",
184
- body,
185
- });
186
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
187
- method: "POST",
188
- body,
189
- headers: {
190
- "Content-Type": "application/json; charset=utf-8",
191
- },
192
- authRequired: true,
193
- });
194
- });
195
- it("should auto-set Content-Type for JSON array bodies", async () => {
196
- const sdk = createTestSdk();
197
- const body = '[{"id": 1}, {"id": 2}]';
198
- await sdk.fetch("https://api.example.com/data", {
199
- method: "POST",
200
- body,
201
- });
202
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
203
- method: "POST",
204
- body,
205
- headers: {
206
- "Content-Type": "application/json; charset=utf-8",
207
- },
208
- authRequired: true,
209
- });
210
- });
211
- it("should not override explicit Content-Type header", async () => {
212
- const sdk = createTestSdk();
213
- const body = '{"key": "value"}';
214
- await sdk.fetch("https://api.example.com/data", {
215
- method: "POST",
216
- body,
217
- headers: {
218
- "Content-Type": "text/plain",
219
- },
220
- });
221
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
222
- method: "POST",
223
- body,
224
- headers: {
225
- "Content-Type": "text/plain",
226
- },
227
- authRequired: true,
228
- });
229
- });
230
- it("should not set Content-Type for non-JSON bodies", async () => {
231
- const sdk = createTestSdk();
232
- const body = "plain text body";
233
- await sdk.fetch("https://api.example.com/data", {
234
- method: "POST",
235
- body,
236
- });
237
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
238
- method: "POST",
239
- body,
240
- headers: {},
241
- authRequired: true,
242
- });
243
- });
244
- it("should not set Content-Type for FormData bodies", async () => {
245
- const sdk = createTestSdk();
246
- const body = new FormData();
247
- body.append("file", "contents");
248
- await sdk.fetch("https://api.example.com/upload", {
249
- method: "POST",
250
- body,
251
- });
252
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/upload", {
253
- method: "POST",
254
- body,
255
- headers: {},
256
- authRequired: true,
257
- });
258
- });
259
- it("should set Content-Type for URLSearchParams bodies", async () => {
260
- const sdk = createTestSdk();
261
- const body = new URLSearchParams({ key: "value", foo: "bar" });
262
- await sdk.fetch("https://api.example.com/form", {
263
- method: "POST",
264
- body,
265
- });
266
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/form", {
267
- method: "POST",
268
- body,
269
- headers: {
270
- "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
271
- },
272
- authRequired: true,
273
- });
274
- });
275
- it("should not set Content-Type for invalid JSON-like strings", async () => {
276
- const sdk = createTestSdk();
277
- const body = "{ this is not json";
278
- await sdk.fetch("https://api.example.com/data", {
279
- method: "POST",
280
- body,
281
- });
282
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
283
- method: "POST",
284
- body,
285
- headers: {},
286
- authRequired: true,
287
- });
288
- });
289
- it("should auto-set Content-Type for plain object bodies", async () => {
290
- const sdk = createTestSdk();
291
- const body = { channel: "C0123456789", text: "Hello, world!" };
292
- await sdk.fetch("https://api.example.com/data", {
293
- method: "POST",
294
- body: body,
295
- });
296
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
297
- method: "POST",
298
- body,
299
- headers: {
300
- "Content-Type": "application/json; charset=utf-8",
301
- },
302
- authRequired: true,
303
- });
304
- });
305
- it("should auto-set Content-Type for plain array bodies", async () => {
306
- const sdk = createTestSdk();
307
- const body = [{ id: 1 }, { id: 2 }];
308
- await sdk.fetch("https://api.example.com/data", {
309
- method: "POST",
310
- body: body,
311
- });
312
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/data", {
313
- method: "POST",
314
- body,
315
- headers: {
316
- "Content-Type": "application/json; charset=utf-8",
317
- },
318
- authRequired: true,
319
- });
320
- });
321
- it("should not set Content-Type for Blob bodies", async () => {
322
- const sdk = createTestSdk();
323
- const body = new Blob(["binary data"], {
324
- type: "application/octet-stream",
325
- });
326
- await sdk.fetch("https://api.example.com/upload", {
327
- method: "POST",
328
- body,
329
- });
330
- expect(mockFetch).toHaveBeenCalledWith("/relay/api.example.com/upload", {
331
- method: "POST",
332
- body,
333
- headers: {},
334
- authRequired: true,
335
- });
336
- });
337
- });
338
- describe("authentication", () => {
339
- it("should set authRequired to true in API call options", async () => {
340
- const sdk = createTestSdk();
341
- await sdk.fetch("https://api.example.com/data");
342
- expect(mockFetch).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
343
- authRequired: true,
344
- }));
345
- });
346
- });
347
- describe("response handling", () => {
348
- it("should return the response from api.fetch", async () => {
349
- const mockResponse = new Response('{"result": "success"}', {
350
- status: 200,
351
- statusText: "OK",
352
- headers: { "Content-Type": "application/json" },
353
- });
354
- mockFetch.mockResolvedValue(mockResponse);
355
- const sdk = createTestSdk();
356
- const response = await sdk.fetch("https://api.example.com/data");
357
- expect(response).toBe(mockResponse);
358
- expect(response.status).toBe(200);
359
- });
360
- it("should handle API errors", async () => {
361
- const error = new Error("Network error");
362
- mockFetch.mockRejectedValue(error);
363
- const sdk = createTestSdk();
364
- await expect(sdk.fetch("https://api.example.com/data")).rejects.toThrow("Network error");
365
- });
366
- });
367
- describe("relay errors", () => {
368
- it("should throw ZapierRelayError with the x-relay-error header message", async () => {
369
- const friendlyMessage = "Ashby does not support direct HTTP requests. Use zapier.apps.{appKey} or zapier.runAction() to use Actions built for this app.";
370
- mockFetch.mockResolvedValue(new Response("", {
371
- status: 404,
372
- headers: { "x-relay-error": friendlyMessage },
373
- }));
374
- const sdk = createTestSdk();
375
- const error = await sdk
376
- .fetch("https://api.example.com/data")
377
- .catch((e) => e);
378
- expect(error).toBeInstanceOf(ZapierRelayError);
379
- expect(error.message).toBe(friendlyMessage);
380
- expect(error.statusCode).toBe(404);
381
- });
382
- it("should throw ZapierRelayError for non-matching x-relay-error", async () => {
383
- mockFetch.mockResolvedValue(new Response("", {
384
- status: 404,
385
- headers: { "x-relay-error": "Some other relay error" },
386
- }));
387
- const sdk = createTestSdk();
388
- const error = await sdk
389
- .fetch("https://api.example.com/data")
390
- .catch((e) => e);
391
- expect(error).toBeInstanceOf(ZapierRelayError);
392
- expect(error.message).toBe("Some other relay error");
393
- });
394
- it("should throw ZapierRelayError regardless of status code", async () => {
395
- mockFetch.mockResolvedValue(new Response("", {
396
- status: 502,
397
- headers: { "x-relay-error": "upstream timeout" },
398
- }));
399
- const sdk = createTestSdk();
400
- const error = await sdk
401
- .fetch("https://api.example.com/data")
402
- .catch((e) => e);
403
- expect(error).toBeInstanceOf(ZapierRelayError);
404
- expect(error.statusCode).toBe(502);
405
- });
406
- });
407
- describe("context and metadata", () => {
408
- it("should provide context with meta information", () => {
409
- const sdk = createTestSdk();
410
- const context = sdk.getContext();
411
- expect(context.meta.fetch).toBeDefined();
412
- expect(context.meta.fetch.inputParameters).toBeDefined();
413
- expect(context.meta.fetch.inputParameters).toHaveLength(2);
414
- });
415
- it("should include cli and mcp in packages", () => {
416
- const sdk = createTestSdk();
417
- const context = sdk.getContext();
418
- expect(context.meta.fetch.packages).toContain("cli");
419
- expect(context.meta.fetch.packages).toContain("mcp");
420
- expect(context.meta.fetch.packages).toContain("sdk");
421
- });
422
- it("should be in the http category", () => {
423
- const sdk = createTestSdk();
424
- const context = sdk.getContext();
425
- expect(context.meta.fetch.categories).toContain("http");
426
- });
427
- });
428
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=index.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../src/plugins/findFirstConnection/index.test.ts"],"names":[],"mappings":""}