@zapier/zapier-sdk 0.0.3 → 0.1.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.
Files changed (171) hide show
  1. package/dist/api/auth.d.ts +8 -0
  2. package/dist/api/auth.js +29 -0
  3. package/dist/api/client.d.ts +8 -0
  4. package/dist/api/client.js +102 -0
  5. package/dist/api/debug.d.ts +12 -0
  6. package/dist/api/debug.js +50 -0
  7. package/dist/api/index.d.ts +26 -0
  8. package/dist/api/index.js +51 -0
  9. package/dist/api/polling.d.ts +17 -0
  10. package/dist/api/polling.js +34 -0
  11. package/dist/{types.d.ts → api/types.d.ts} +37 -88
  12. package/dist/api/types.js +9 -0
  13. package/dist/functions/{bundleCode.d.ts → bundleCode/index.d.ts} +1 -8
  14. package/dist/functions/bundleCode/info.d.ts +27 -0
  15. package/dist/functions/bundleCode/info.js +11 -0
  16. package/dist/functions/bundleCode/schemas.d.ts +27 -0
  17. package/dist/functions/bundleCode/schemas.js +22 -0
  18. package/dist/functions/{generateTypes.d.ts → generateTypes/index.d.ts} +2 -7
  19. package/dist/functions/{generateTypes.js → generateTypes/index.js} +58 -24
  20. package/dist/functions/generateTypes/info.d.ts +21 -0
  21. package/dist/functions/generateTypes/info.js +11 -0
  22. package/dist/functions/generateTypes/schemas.d.ts +30 -0
  23. package/dist/functions/generateTypes/schemas.js +14 -0
  24. package/dist/functions/{getAction.d.ts → getAction/index.d.ts} +2 -6
  25. package/dist/functions/{getAction.js → getAction/index.js} +6 -5
  26. package/dist/functions/getAction/info.d.ts +18 -0
  27. package/dist/functions/getAction/info.js +11 -0
  28. package/dist/functions/getAction/schemas.d.ts +30 -0
  29. package/dist/functions/getAction/schemas.js +13 -0
  30. package/dist/functions/{getApp.d.ts → getApp/index.d.ts} +2 -4
  31. package/dist/functions/{getApp.js → getApp/index.js} +6 -10
  32. package/dist/functions/getApp/info.d.ts +12 -0
  33. package/dist/functions/getApp/info.js +11 -0
  34. package/dist/functions/getApp/schemas.d.ts +24 -0
  35. package/dist/functions/getApp/schemas.js +11 -0
  36. package/dist/functions/{listActions.d.ts → listActions/index.d.ts} +3 -6
  37. package/dist/functions/{listActions.js → listActions/index.js} +4 -3
  38. package/dist/functions/listActions/info.d.ts +15 -0
  39. package/dist/functions/listActions/info.js +11 -0
  40. package/dist/functions/listActions/schemas.d.ts +27 -0
  41. package/dist/functions/listActions/schemas.js +14 -0
  42. package/dist/functions/{listApps.d.ts → listApps/index.d.ts} +2 -6
  43. package/dist/functions/{listApps.js → listApps/index.js} +1 -1
  44. package/dist/functions/listApps/info.d.ts +18 -0
  45. package/dist/functions/listApps/info.js +11 -0
  46. package/dist/functions/listApps/schemas.d.ts +30 -0
  47. package/dist/functions/listApps/schemas.js +15 -0
  48. package/dist/functions/{listAuths.d.ts → listAuths/index.d.ts} +3 -9
  49. package/dist/functions/{listAuths.js → listAuths/index.js} +5 -5
  50. package/dist/functions/listAuths/info.d.ts +24 -0
  51. package/dist/functions/listAuths/info.js +11 -0
  52. package/dist/functions/listAuths/schemas.d.ts +36 -0
  53. package/dist/functions/listAuths/schemas.js +17 -0
  54. package/dist/functions/{listFields.d.ts → listFields/index.d.ts} +3 -9
  55. package/dist/functions/{listFields.js → listFields/index.js} +8 -10
  56. package/dist/functions/listFields/info.d.ts +24 -0
  57. package/dist/functions/listFields/info.js +11 -0
  58. package/dist/functions/listFields/schemas.d.ts +36 -0
  59. package/dist/functions/listFields/schemas.js +17 -0
  60. package/dist/functions/{runAction.d.ts → runAction/index.d.ts} +2 -8
  61. package/dist/functions/{runAction.js → runAction/index.js} +15 -14
  62. package/dist/functions/runAction/info.d.ts +24 -0
  63. package/dist/functions/runAction/info.js +11 -0
  64. package/dist/functions/runAction/schemas.d.ts +36 -0
  65. package/dist/functions/runAction/schemas.js +15 -0
  66. package/dist/index.d.ts +6 -3
  67. package/dist/index.js +7 -3
  68. package/dist/plugins/apps/index.d.ts +8 -0
  69. package/dist/plugins/apps/index.js +77 -0
  70. package/dist/plugins/apps/info.d.ts +6 -0
  71. package/dist/plugins/apps/info.js +13 -0
  72. package/dist/plugins/apps/types.d.ts +21 -0
  73. package/dist/plugins/apps/types.js +2 -0
  74. package/dist/resolvers/actionKey.d.ts +8 -0
  75. package/dist/resolvers/actionKey.js +20 -0
  76. package/dist/resolvers/actionType.d.ts +8 -0
  77. package/dist/resolvers/actionType.js +21 -0
  78. package/dist/resolvers/appKey.d.ts +6 -0
  79. package/dist/resolvers/appKey.js +8 -0
  80. package/dist/resolvers/authenticationId.d.ts +8 -0
  81. package/dist/resolvers/authenticationId.js +29 -0
  82. package/dist/resolvers/index.d.ts +39 -0
  83. package/dist/resolvers/index.js +105 -0
  84. package/dist/resolvers/inputs.d.ts +7 -0
  85. package/dist/resolvers/inputs.js +15 -0
  86. package/dist/schema-utils.d.ts +39 -0
  87. package/dist/schema-utils.js +52 -0
  88. package/dist/schemas/Action.d.ts +21 -0
  89. package/dist/schemas/Action.js +31 -0
  90. package/dist/schemas/App.d.ts +19 -0
  91. package/dist/schemas/App.js +32 -0
  92. package/dist/schemas/Auth.d.ts +30 -0
  93. package/dist/schemas/Auth.js +49 -0
  94. package/dist/schemas/Field.d.ts +15 -0
  95. package/dist/schemas/Field.js +25 -0
  96. package/dist/sdk.d.ts +3 -4
  97. package/dist/sdk.js +96 -11
  98. package/dist/types/domain.d.ts +22 -0
  99. package/dist/types/domain.js +21 -0
  100. package/dist/types/properties.d.ts +21 -0
  101. package/dist/types/properties.js +45 -0
  102. package/dist/types/sdk.d.ts +21 -0
  103. package/dist/types/sdk.js +2 -0
  104. package/package.json +4 -2
  105. package/src/api/auth.ts +28 -0
  106. package/src/api/client.ts +148 -0
  107. package/src/api/debug.ts +58 -0
  108. package/src/api/index.ts +83 -0
  109. package/src/api/polling.ts +56 -0
  110. package/src/api/types.ts +177 -0
  111. package/src/functions/{bundleCode.ts → bundleCode/index.ts} +1 -8
  112. package/src/functions/bundleCode/info.ts +9 -0
  113. package/src/functions/bundleCode/schemas.ts +30 -0
  114. package/src/functions/{generateTypes.ts → generateTypes/index.ts} +70 -31
  115. package/src/functions/generateTypes/info.ts +9 -0
  116. package/src/functions/generateTypes/schemas.ts +38 -0
  117. package/src/functions/{getAction.ts → getAction/index.ts} +11 -12
  118. package/src/functions/getAction/info.ts +9 -0
  119. package/src/functions/getAction/schemas.ts +35 -0
  120. package/src/functions/{getApp.ts → getApp/index.ts} +9 -15
  121. package/src/functions/getApp/info.ts +9 -0
  122. package/src/functions/getApp/schemas.ts +31 -0
  123. package/src/functions/{listActions.ts → listActions/index.ts} +8 -10
  124. package/src/functions/listActions/info.ts +9 -0
  125. package/src/functions/listActions/schemas.ts +40 -0
  126. package/src/functions/{listApps.ts → listApps/index.ts} +3 -8
  127. package/src/functions/listApps/info.ts +9 -0
  128. package/src/functions/listApps/schemas.ts +43 -0
  129. package/src/functions/{listAuths.ts → listAuths/index.ts} +8 -16
  130. package/src/functions/listAuths/info.ts +9 -0
  131. package/src/functions/listAuths/schemas.ts +48 -0
  132. package/src/functions/{listFields.ts → listFields/index.ts} +11 -20
  133. package/src/functions/listFields/info.ts +9 -0
  134. package/src/functions/listFields/schemas.ts +46 -0
  135. package/src/functions/{runAction.ts → runAction/index.ts} +25 -23
  136. package/src/functions/runAction/info.ts +9 -0
  137. package/src/functions/runAction/schemas.ts +41 -0
  138. package/src/index.ts +13 -4
  139. package/src/plugins/apps/index.ts +144 -0
  140. package/src/plugins/apps/info.ts +12 -0
  141. package/src/plugins/apps/types.ts +34 -0
  142. package/src/resolvers/actionKey.ts +33 -0
  143. package/src/resolvers/actionType.ts +30 -0
  144. package/src/resolvers/appKey.ts +11 -0
  145. package/src/resolvers/authenticationId.ts +38 -0
  146. package/src/resolvers/index.ts +117 -0
  147. package/src/resolvers/inputs.ts +23 -0
  148. package/src/schema-utils.ts +119 -0
  149. package/src/schemas/Action.ts +40 -0
  150. package/src/schemas/App.ts +43 -0
  151. package/src/schemas/Auth.ts +62 -0
  152. package/src/schemas/Field.ts +34 -0
  153. package/src/sdk.ts +153 -19
  154. package/src/types/domain.ts +54 -0
  155. package/src/types/properties.ts +67 -0
  156. package/src/types/sdk.ts +42 -0
  157. package/dist/actions-sdk.d.ts +0 -47
  158. package/dist/actions-sdk.js +0 -208
  159. package/dist/api.d.ts +0 -62
  160. package/dist/api.js +0 -227
  161. package/dist/output-schemas.d.ts +0 -95
  162. package/dist/output-schemas.js +0 -138
  163. package/dist/schemas.d.ts +0 -338
  164. package/dist/schemas.js +0 -336
  165. package/dist/types.js +0 -41
  166. package/src/actions-sdk.ts +0 -356
  167. package/src/api.ts +0 -361
  168. package/src/output-schemas.ts +0 -196
  169. package/src/schemas.ts +0 -467
  170. package/src/types.ts +0 -257
  171. /package/dist/functions/{bundleCode.js → bundleCode/index.js} +0 -0
@@ -1,356 +0,0 @@
1
- import {
2
- Integration,
3
- Action,
4
- ActionExecutionOptions,
5
- ActionExecutionResult,
6
- ActionField,
7
- Authentication,
8
- BaseSdkOptions,
9
- } from "./types";
10
- import { createZapierApi, type ApiClient } from "./api";
11
- import { listAuths } from "./functions/listAuths";
12
- import { listApps } from "./functions/listApps";
13
- import { getApp } from "./functions/getApp";
14
- import { listActions } from "./functions/listActions";
15
- import { getAction } from "./functions/getAction";
16
- import { runAction } from "./functions/runAction";
17
- import { listFields } from "./functions/listFields";
18
- import { generateTypes as generateTypesFunction } from "./functions/generateTypes";
19
- import { bundleCode as bundleCodeFunction } from "./functions/bundleCode";
20
- import {
21
- AppsListOptions,
22
- AppsGetOptions,
23
- ActionsListOptions,
24
- ActionsGetOptions,
25
- ActionsRunOptions,
26
- AuthsListOptions,
27
- AuthsFindOptions,
28
- FieldsListOptions,
29
- GenerateOptions,
30
- BundleOptions,
31
- } from "./schemas";
32
- export * from "./schemas";
33
- export * from "./output-schemas";
34
-
35
- export interface ActionsSdk {
36
- // Resource namespaces
37
- apps: AppsService;
38
- actions: ActionsService;
39
- auths: AuthsService;
40
- fields: FieldsService;
41
-
42
- // Root namespace tools
43
- generate: GenerateFunction;
44
- bundle: BundleFunction;
45
- }
46
-
47
- export interface AppsService {
48
- list(options?: AppsListOptions): Promise<Integration[]>;
49
- get(options: AppsGetOptions): Promise<Integration>;
50
- }
51
-
52
- interface ActionRunner {
53
- (params: ActionsRunOptions): Promise<ActionExecutionResult>;
54
- }
55
-
56
- interface ActionProxy {
57
- [app: string]: {
58
- [type: string]: {
59
- [action: string]: (
60
- options?: ActionExecutionOptions,
61
- ) => Promise<ActionExecutionResult>;
62
- };
63
- };
64
- }
65
-
66
- export interface GenerateFunction {
67
- (options: GenerateOptions): Promise<string>;
68
- }
69
-
70
- export interface BundleFunction {
71
- (options: BundleOptions): Promise<string>;
72
- }
73
-
74
- export interface ActionsService {
75
- list(options?: ActionsListOptions): Promise<Action[]>;
76
- get(options: ActionsGetOptions): Promise<Action>;
77
- run: ActionRunner & ActionProxy;
78
- }
79
-
80
- export interface AuthsService {
81
- list(options?: AuthsListOptions): Promise<Authentication[]>;
82
- find(options: AuthsFindOptions): number;
83
- }
84
-
85
- export interface FieldsService {
86
- list(options: FieldsListOptions): Promise<ActionField[]>;
87
- }
88
-
89
- export interface ActionsSdkOptions extends BaseSdkOptions {}
90
-
91
- export function createActionsSdk(options: ActionsSdkOptions = {}): ActionsSdk {
92
- // Auto-load .env files (searches up directory tree)
93
- try {
94
- const { findUpSync } = require("find-up");
95
- const envPath = findUpSync(".env");
96
- if (envPath) {
97
- require("dotenv").config({ path: envPath, quiet: true });
98
- }
99
- } catch {
100
- // Silently fail if dotenv/find-up not available or .env not found
101
- }
102
-
103
- const {
104
- fetch: customFetch = globalThis.fetch,
105
- baseUrl = "https://zapier.com",
106
- token,
107
- authentications = {},
108
- debug = false,
109
- } = options;
110
-
111
- // If no token provided, try to get it from environment variable
112
- const finalToken = token || process.env.ZAPIER_TOKEN;
113
-
114
- // Create the API client
115
- const api = createZapierApi({
116
- baseUrl,
117
- token: finalToken,
118
- debug,
119
- fetch: customFetch,
120
- });
121
-
122
- // Create SDK object - we'll populate services after creation to avoid circular dependency
123
- const sdk: ActionsSdk = {} as ActionsSdk;
124
-
125
- const appsService = createAppsService({
126
- api,
127
- token: finalToken,
128
- authentications,
129
- sdk,
130
- });
131
-
132
- const actionsService = createActionsService({
133
- api,
134
- token: finalToken,
135
- authentications,
136
- sdk,
137
- });
138
-
139
- const authsService = createAuthsService({
140
- api,
141
- token: finalToken,
142
- authentications,
143
- sdk,
144
- });
145
-
146
- const fieldsService = createFieldsService({
147
- api,
148
- token: finalToken,
149
- authentications,
150
- sdk,
151
- });
152
-
153
- // Create root namespace tools
154
- const generateFunction: GenerateFunction = async (
155
- options: GenerateOptions,
156
- ) => {
157
- return generateTypesFunction({ ...options, api, token: finalToken });
158
- };
159
-
160
- const bundleFunction: BundleFunction = async (options: BundleOptions) => {
161
- return bundleCodeFunction(options);
162
- };
163
-
164
- // Populate the SDK object
165
- sdk.apps = appsService;
166
- sdk.actions = actionsService;
167
- sdk.auths = authsService;
168
- sdk.fields = fieldsService;
169
- sdk.generate = generateFunction;
170
- sdk.bundle = bundleFunction;
171
-
172
- // Note: Debug logging for SDK initialization is now handled by the API client
173
-
174
- return sdk;
175
- }
176
-
177
- interface AppsServiceOptions {
178
- api: ApiClient;
179
- token?: string;
180
- authentications?: { [appKey: string]: { id: number }[] };
181
- sdk: ActionsSdk;
182
- }
183
-
184
- interface AuthsServiceOptions {
185
- api: ApiClient;
186
- token?: string;
187
- authentications?: { [appKey: string]: { id: number }[] };
188
- sdk: ActionsSdk;
189
- }
190
-
191
- interface ActionsServiceOptions {
192
- api: ApiClient;
193
- token?: string;
194
- authentications?: { [appKey: string]: { id: number }[] };
195
- sdk: ActionsSdk;
196
- }
197
-
198
- interface FieldsServiceOptions {
199
- api: ApiClient;
200
- token?: string;
201
- authentications?: { [appKey: string]: { id: number }[] };
202
- sdk: ActionsSdk;
203
- }
204
-
205
- function createAppsService(options: AppsServiceOptions): AppsService {
206
- const { api, token } = options;
207
-
208
- return {
209
- async list(options?: AppsListOptions): Promise<Integration[]> {
210
- return listApps({ ...options, api, token });
211
- },
212
-
213
- async get(options: AppsGetOptions): Promise<Integration> {
214
- return getApp({ ...options, api, token });
215
- },
216
- };
217
- }
218
-
219
- function createAuthsService(options: AuthsServiceOptions): AuthsService {
220
- const { api, token, authentications } = options;
221
-
222
- return {
223
- async list(options?: AuthsListOptions): Promise<Authentication[]> {
224
- return listAuths({ ...options, api, token });
225
- },
226
-
227
- find(options: { appKey: string }): number {
228
- if (!authentications) {
229
- throw new Error(`No authentication configured`);
230
- }
231
-
232
- const auths = authentications[options.appKey] || [];
233
-
234
- if (auths.length === 0) {
235
- throw new Error(
236
- `No authentication configured for app "${options.appKey}"`,
237
- );
238
- }
239
-
240
- if (auths.length > 1) {
241
- throw new Error(
242
- `Multiple authentications found for app "${options.appKey}". Please specify which one to use.`,
243
- );
244
- }
245
-
246
- return auths[0].id;
247
- },
248
- };
249
- }
250
-
251
- function createFieldsService(options: FieldsServiceOptions): FieldsService {
252
- const { api, token } = options;
253
-
254
- return {
255
- async list(options: FieldsListOptions): Promise<ActionField[]> {
256
- return listFields({ ...options, api, token });
257
- },
258
- };
259
- }
260
-
261
- function createActionsService(options: ActionsServiceOptions): ActionsService {
262
- const { api, token, authentications } = options;
263
-
264
- // Create the base service with named methods
265
- const baseService: ActionsService = {
266
- async list(options?: ActionsListOptions): Promise<Action[]> {
267
- return listActions({ ...options, api, token });
268
- },
269
-
270
- async get(options: ActionsGetOptions): Promise<Action> {
271
- return getAction({ ...options, api, token });
272
- },
273
-
274
- // run will be replaced with function/proxy pattern below
275
- } as ActionsService;
276
-
277
- // Create the run function with proxy capabilities
278
- const runFunction = async (
279
- params: ActionsRunOptions,
280
- ): Promise<ActionExecutionResult> => {
281
- const { app, type, action, inputs, authId: providedAuthId } = params;
282
-
283
- // Resolve auth ID for this specific app
284
- let authId: number | undefined = providedAuthId;
285
-
286
- if (!authId && authentications) {
287
- const auths = authentications[app] || [];
288
- if (auths.length === 0) {
289
- throw new Error(`No authentication configured for app "${app}"`);
290
- }
291
- if (auths.length > 1) {
292
- throw new Error(
293
- `Multiple authentications found for app "${app}". Please specify which one to use.`,
294
- );
295
- }
296
- authId = auths[0].id;
297
- }
298
-
299
- // Delegate to standalone runAction function
300
- return runAction({
301
- app,
302
- type,
303
- action,
304
- inputs,
305
- authId,
306
- api,
307
- token,
308
- });
309
- };
310
-
311
- // Create proxy wrapper for the run function
312
- const runWithProxy = new Proxy(runFunction, {
313
- get(target, prop: string) {
314
- if (typeof prop === "string") {
315
- // Return app-level proxy
316
- return new Proxy(
317
- {},
318
- {
319
- get(_target, actionType: string) {
320
- if (typeof actionType !== "string") return undefined;
321
-
322
- return new Proxy(
323
- {},
324
- {
325
- get(_target, actionKey: string) {
326
- if (typeof actionKey !== "string") return undefined;
327
-
328
- // Return function that calls the main run function
329
- return async (
330
- options: ActionExecutionOptions = {},
331
- ): Promise<ActionExecutionResult> => {
332
- return await runFunction({
333
- app: prop,
334
- type: actionType as any, // Cast because proxy string can't be typed as enum
335
- action: actionKey,
336
- inputs: options.inputs,
337
- authId: options.authId,
338
- });
339
- };
340
- },
341
- },
342
- );
343
- },
344
- },
345
- );
346
- }
347
- return target[prop];
348
- },
349
- });
350
-
351
- // Add the run function/proxy to the base service
352
- baseService.run = runWithProxy as ActionRunner & ActionProxy;
353
-
354
- // Return the service with the new run function/proxy
355
- return baseService;
356
- }
package/src/api.ts DELETED
@@ -1,361 +0,0 @@
1
- /**
2
- * Zapier API Client Module
3
- *
4
- * This module provides a centralized API layer for all HTTP interactions
5
- * with Zapier's various APIs. It handles authentication, error handling,
6
- * polling, and provides consistent patterns across all services.
7
- */
8
-
9
- // ============================================================================
10
- // Types
11
- // ============================================================================
12
-
13
- export interface ApiClientOptions {
14
- baseUrl: string;
15
- token?: string;
16
- debug?: boolean;
17
- fetch?: typeof globalThis.fetch;
18
- }
19
-
20
- export interface ApiClient {
21
- get: (path: string, options?: RequestOptions) => Promise<any>;
22
- post: (path: string, data?: any, options?: RequestOptions) => Promise<any>;
23
- put: (path: string, data?: any, options?: RequestOptions) => Promise<any>;
24
- delete: (path: string, options?: RequestOptions) => Promise<any>;
25
- poll: (path: string, options?: PollOptions) => Promise<any>;
26
- }
27
-
28
- export interface RequestOptions {
29
- headers?: Record<string, string>;
30
- searchParams?: Record<string, string>;
31
- authRequired?: boolean;
32
- customErrorHandler?: (response: Response) => Error | undefined;
33
- }
34
-
35
- export interface PollOptions extends RequestOptions {
36
- maxAttempts?: number;
37
- initialDelay?: number;
38
- maxDelay?: number;
39
- successStatus?: number;
40
- pendingStatus?: number;
41
- resultExtractor?: (response: any) => any;
42
- }
43
-
44
- interface DebugLogger {
45
- (message: string, data?: any): void;
46
- }
47
-
48
- // ============================================================================
49
- // Authentication Utilities
50
- // ============================================================================
51
-
52
- export function isJwt(token: string): boolean {
53
- // JWT tokens have exactly 3 parts separated by dots
54
- const parts = token.split(".");
55
- if (parts.length !== 3) {
56
- return false;
57
- }
58
-
59
- // Each part should be base64url encoded (no padding)
60
- // Basic validation - each part should be non-empty and contain valid base64url characters
61
- const base64UrlPattern = /^[A-Za-z0-9_-]+$/;
62
- return parts.every((part) => part.length > 0 && base64UrlPattern.test(part));
63
- }
64
-
65
- export function getAuthorizationHeader(token: string): string {
66
- // Check if token is a JWT (has 3 parts separated by dots)
67
- if (isJwt(token)) {
68
- return `JWT ${token}`;
69
- }
70
- // Default to Bearer for other token types
71
- return `Bearer ${token}`;
72
- }
73
-
74
- // ============================================================================
75
- // Debug Logging
76
- // ============================================================================
77
-
78
- function createDebugLogger(enabled: boolean): DebugLogger {
79
- if (!enabled) {
80
- return () => {}; // No-op function when debug is disabled
81
- }
82
-
83
- return (message: string, data?: any) => {
84
- console.log(`[Zapier SDK] ${message}`, data || "");
85
- };
86
- }
87
-
88
- function createDebugFetch(options: {
89
- originalFetch: typeof globalThis.fetch;
90
- debugLog: DebugLogger;
91
- }) {
92
- const { originalFetch, debugLog } = options;
93
- return async (input: RequestInfo | URL, options?: RequestInit) => {
94
- const startTime = Date.now();
95
-
96
- // Convert input to URL string for logging
97
- const url = typeof input === "string" ? input : input.toString();
98
- const method = options?.method || "GET";
99
-
100
- debugLog(`→ ${method} ${url}`, {
101
- headers: options?.headers,
102
- body: options?.body ? JSON.parse(options.body as string) : undefined,
103
- });
104
-
105
- try {
106
- const response = await originalFetch(input, options);
107
- const duration = Date.now() - startTime;
108
-
109
- debugLog(`← ${response.status} ${response.statusText} (${duration}ms)`, {
110
- url,
111
- method,
112
- status: response.status,
113
- });
114
-
115
- return response;
116
- } catch (error) {
117
- const duration = Date.now() - startTime;
118
- debugLog(`✖ Request failed (${duration}ms)`, {
119
- url,
120
- method,
121
- error: error instanceof Error ? error.message : error,
122
- });
123
- throw error;
124
- }
125
- };
126
- }
127
-
128
- // ============================================================================
129
- // Polling Utilities
130
- // ============================================================================
131
-
132
- export async function pollUntilComplete(options: {
133
- fetch: typeof globalThis.fetch;
134
- url: string;
135
- headers?: Record<string, string>;
136
- maxAttempts?: number;
137
- initialDelay?: number;
138
- maxDelay?: number;
139
- successStatus?: number;
140
- pendingStatus?: number;
141
- resultExtractor?: (response: any) => any;
142
- }): Promise<any> {
143
- const {
144
- fetch,
145
- url,
146
- headers = {},
147
- maxAttempts = 30,
148
- initialDelay = 50,
149
- maxDelay = 1000,
150
- successStatus = 200,
151
- pendingStatus = 202,
152
- resultExtractor = (response) => response,
153
- } = options;
154
-
155
- let delay = initialDelay;
156
-
157
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
158
- const response = await fetch(url, { headers });
159
-
160
- if (response.status === successStatus) {
161
- // Success - extract and return results
162
- const result = await response.json();
163
- return resultExtractor(result);
164
- } else if (response.status === pendingStatus) {
165
- // Still processing - wait and retry
166
- if (attempt < maxAttempts - 1) {
167
- await new Promise((resolve) => setTimeout(resolve, delay));
168
- delay = Math.min(delay * 2, maxDelay); // Exponential backoff
169
- continue;
170
- }
171
- } else {
172
- // Error occurred
173
- throw new Error(
174
- `Request failed: GET ${url} - ${response.status} ${response.statusText}`,
175
- );
176
- }
177
- }
178
-
179
- throw new Error(`Operation timed out after ${maxAttempts} attempts`);
180
- }
181
-
182
- // ============================================================================
183
- // API Client Factory
184
- // ============================================================================
185
-
186
- export function createZapierApi(options: ApiClientOptions): ApiClient {
187
- const {
188
- baseUrl,
189
- token,
190
- debug = false,
191
- fetch: originalFetch = globalThis.fetch,
192
- } = options;
193
-
194
- const debugLog = createDebugLogger(debug);
195
- const fetch = createDebugFetch({ originalFetch, debugLog });
196
-
197
- // Helper to build full URLs
198
- function buildUrl(
199
- path: string,
200
- searchParams?: Record<string, string>,
201
- ): string {
202
- const url = new URL(path, baseUrl);
203
- if (searchParams) {
204
- Object.entries(searchParams).forEach(([key, value]) => {
205
- url.searchParams.set(key, value);
206
- });
207
- }
208
- return url.toString();
209
- }
210
-
211
- // Helper to build headers
212
- function buildHeaders(options: RequestOptions = {}): Record<string, string> {
213
- const headers: Record<string, string> = {
214
- ...options.headers,
215
- };
216
-
217
- // Add auth header if token provided and not explicitly disabled
218
- if (token && options.authRequired !== false) {
219
- headers.Authorization = getAuthorizationHeader(token);
220
- }
221
-
222
- return headers;
223
- }
224
-
225
- // Helper to handle responses
226
- async function handleResponse(
227
- response: Response,
228
- customErrorHandler?: (response: Response) => Error | undefined,
229
- ): Promise<any> {
230
- if (!response.ok) {
231
- // Check for custom error handling first
232
- if (customErrorHandler) {
233
- const customError = customErrorHandler(response);
234
- if (customError) {
235
- throw customError;
236
- }
237
- }
238
-
239
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
240
- }
241
-
242
- // Try to parse JSON, fall back to text if that fails
243
- try {
244
- return await response.json();
245
- } catch {
246
- return await response.text();
247
- }
248
- }
249
-
250
- // Helper to perform HTTP requests with JSON handling
251
- async function fetchJson(
252
- method: string,
253
- path: string,
254
- data?: any,
255
- options: RequestOptions = {},
256
- ): Promise<any> {
257
- const url = buildUrl(path, options.searchParams);
258
- const headers = buildHeaders(options);
259
-
260
- // Add Content-Type for JSON requests with body data
261
- if (data && typeof data === "object") {
262
- headers["Content-Type"] = "application/json";
263
- }
264
-
265
- const response = await fetch(url, {
266
- method,
267
- headers,
268
- body: data ? JSON.stringify(data) : undefined,
269
- });
270
-
271
- return handleResponse(response, options.customErrorHandler);
272
- }
273
-
274
- return {
275
- async get(path: string, options: RequestOptions = {}): Promise<any> {
276
- return fetchJson("GET", path, undefined, options);
277
- },
278
-
279
- async post(
280
- path: string,
281
- data?: any,
282
- options: RequestOptions = {},
283
- ): Promise<any> {
284
- return fetchJson("POST", path, data, options);
285
- },
286
-
287
- async put(
288
- path: string,
289
- data?: any,
290
- options: RequestOptions = {},
291
- ): Promise<any> {
292
- return fetchJson("PUT", path, data, options);
293
- },
294
-
295
- async delete(path: string, options: RequestOptions = {}): Promise<any> {
296
- return fetchJson("DELETE", path, undefined, options);
297
- },
298
-
299
- async poll(path: string, options: PollOptions = {}): Promise<any> {
300
- const url = buildUrl(path, options.searchParams);
301
- const headers = buildHeaders(options);
302
-
303
- return pollUntilComplete({
304
- fetch,
305
- url,
306
- headers,
307
- maxAttempts: options.maxAttempts,
308
- initialDelay: options.initialDelay,
309
- maxDelay: options.maxDelay,
310
- successStatus: options.successStatus,
311
- pendingStatus: options.pendingStatus,
312
- resultExtractor: options.resultExtractor,
313
- });
314
- },
315
- };
316
- }
317
-
318
- // ============================================================================
319
- // Utility Functions
320
- // ============================================================================
321
-
322
- export function generateRequestId(): string {
323
- return Math.random().toString(36).substring(2) + Date.now().toString(36);
324
- }
325
-
326
- // ============================================================================
327
- // Utility Functions for Standalone Functions
328
- // ============================================================================
329
-
330
- /**
331
- * Utility function to get or create an API client for standalone functions
332
- *
333
- * @param config - Configuration that may include an existing API client
334
- * @returns ApiClient instance
335
- */
336
- export function getOrCreateApiClient(config: {
337
- baseUrl?: string;
338
- token?: string;
339
- api?: ApiClient;
340
- debug?: boolean;
341
- fetch?: typeof globalThis.fetch;
342
- }): ApiClient {
343
- const {
344
- baseUrl = "https://zapier.com",
345
- token = process.env.ZAPIER_TOKEN,
346
- api: providedApi,
347
- debug = false,
348
- fetch: customFetch,
349
- } = config;
350
-
351
- // Use provided API client or create a new one
352
- return (
353
- providedApi ||
354
- createZapierApi({
355
- baseUrl,
356
- token,
357
- debug,
358
- fetch: customFetch,
359
- })
360
- );
361
- }