@zapier/zapier-sdk 0.13.7 → 0.13.9

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 (59) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/api/client.d.ts.map +1 -1
  3. package/dist/api/client.js +5 -5
  4. package/dist/api/client.test.d.ts +2 -0
  5. package/dist/api/client.test.d.ts.map +1 -0
  6. package/dist/api/client.test.js +80 -0
  7. package/dist/api/index.d.ts +1 -0
  8. package/dist/api/index.d.ts.map +1 -1
  9. package/dist/api/index.js +3 -1
  10. package/dist/api/polling.d.ts.map +1 -1
  11. package/dist/api/polling.js +1 -11
  12. package/dist/api/schemas.d.ts +20 -20
  13. package/dist/api/types.d.ts +2 -0
  14. package/dist/api/types.d.ts.map +1 -1
  15. package/dist/auth.d.ts +3 -0
  16. package/dist/auth.d.ts.map +1 -1
  17. package/dist/auth.test.d.ts +2 -0
  18. package/dist/auth.test.d.ts.map +1 -0
  19. package/dist/auth.test.js +102 -0
  20. package/dist/constants.d.ts +4 -4
  21. package/dist/constants.d.ts.map +1 -1
  22. package/dist/constants.js +4 -4
  23. package/dist/index.cjs +194 -33
  24. package/dist/index.d.mts +93 -1
  25. package/dist/index.d.ts +3 -0
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +4 -0
  28. package/dist/index.mjs +192 -34
  29. package/dist/plugins/api/index.d.ts.map +1 -1
  30. package/dist/plugins/api/index.js +4 -1
  31. package/dist/plugins/eventEmission/index.d.ts +2 -0
  32. package/dist/plugins/eventEmission/index.d.ts.map +1 -1
  33. package/dist/plugins/eventEmission/index.js +35 -9
  34. package/dist/plugins/eventEmission/index.test.js +100 -0
  35. package/dist/schemas/Action.d.ts +2 -2
  36. package/dist/schemas/Auth.d.ts +4 -4
  37. package/dist/schemas/Field.d.ts +10 -10
  38. package/dist/sdk.test.js +121 -1
  39. package/dist/types/sdk.d.ts +3 -0
  40. package/dist/types/sdk.d.ts.map +1 -1
  41. package/dist/utils/batch-utils.d.ts +72 -0
  42. package/dist/utils/batch-utils.d.ts.map +1 -0
  43. package/dist/utils/batch-utils.js +162 -0
  44. package/dist/utils/batch-utils.test.d.ts +2 -0
  45. package/dist/utils/batch-utils.test.d.ts.map +1 -0
  46. package/dist/utils/batch-utils.test.js +476 -0
  47. package/dist/utils/retry-utils.d.ts +45 -0
  48. package/dist/utils/retry-utils.d.ts.map +1 -0
  49. package/dist/utils/retry-utils.js +51 -0
  50. package/dist/utils/retry-utils.test.d.ts +2 -0
  51. package/dist/utils/retry-utils.test.d.ts.map +1 -0
  52. package/dist/utils/retry-utils.test.js +90 -0
  53. package/dist/utils/url-utils.d.ts +19 -0
  54. package/dist/utils/url-utils.d.ts.map +1 -0
  55. package/dist/utils/url-utils.js +62 -0
  56. package/dist/utils/url-utils.test.d.ts +2 -0
  57. package/dist/utils/url-utils.test.d.ts.map +1 -0
  58. package/dist/utils/url-utils.test.js +103 -0
  59. package/package.json +2 -2
package/dist/index.mjs CHANGED
@@ -32,8 +32,8 @@ function isPositional(schema) {
32
32
  }
33
33
 
34
34
  // src/constants.ts
35
+ var ZAPIER_BASE_URL = process.env.ZAPIER_BASE_URL || "https://zapier.com";
35
36
  var MAX_PAGE_LIMIT = 1e4;
36
- var TRACKING_API_ENDPOINT = "https://zapier.com/api/v4/tracking/event/";
37
37
 
38
38
  // src/types/properties.ts
39
39
  var AppKeyPropertySchema = withPositional(
@@ -3079,15 +3079,28 @@ function createDebugFetch(options) {
3079
3079
  }
3080
3080
  };
3081
3081
  }
3082
+
3083
+ // src/utils/retry-utils.ts
3084
+ var MAX_CONSECUTIVE_ERRORS = 3;
3085
+ var BASE_ERROR_BACKOFF_MS = 1e3;
3086
+ var JITTER_FACTOR = 0.5;
3087
+ function calculateWaitTime(baseInterval, errorCount) {
3088
+ const jitter = Math.random() * JITTER_FACTOR * baseInterval;
3089
+ const errorBackoff = Math.min(
3090
+ BASE_ERROR_BACKOFF_MS * (errorCount / 2),
3091
+ baseInterval * 2
3092
+ // Cap error backoff at 2x the base interval
3093
+ );
3094
+ return Math.floor(baseInterval + jitter + errorBackoff);
3095
+ }
3096
+
3097
+ // src/api/polling.ts
3082
3098
  var DEFAULT_TIMEOUT_MS = 18e4;
3083
3099
  var DEFAULT_SUCCESS_STATUS = 200;
3084
3100
  var DEFAULT_PENDING_STATUS = 202;
3085
3101
  var DEFAULT_INITIAL_DELAY_MS = 50;
3086
3102
  var DEFAULT_MAX_POLLING_INTERVAL_MS = 1e4;
3087
- var MAX_CONSECUTIVE_ERRORS = 3;
3088
3103
  var MAX_TIMEOUT_BUFFER_MS = 1e4;
3089
- var BASE_ERROR_BACKOFF_MS = 1e3;
3090
- var JITTER_FACTOR = 0.5;
3091
3104
  var DEFAULT_POLLING_STAGES = [
3092
3105
  [125, 125],
3093
3106
  // Up to 125ms: poll every 125ms
@@ -3102,15 +3115,6 @@ var DEFAULT_POLLING_STAGES = [
3102
3115
  [6e4, 5e3]
3103
3116
  // Up to 60s: poll every 5s
3104
3117
  ];
3105
- var calculateWaitTime = (baseInterval, errorCount) => {
3106
- const jitter = Math.random() * JITTER_FACTOR * baseInterval;
3107
- const errorBackoff = Math.min(
3108
- BASE_ERROR_BACKOFF_MS * (errorCount / 2),
3109
- baseInterval * 2
3110
- // Cap error backoff at 2x the base interval
3111
- );
3112
- return Math.floor(baseInterval + jitter + errorBackoff);
3113
- };
3114
3118
  var processResponse = async (response, successStatus, pendingStatus, resultExtractor, errorCount) => {
3115
3119
  if (!response.ok) {
3116
3120
  return {
@@ -3318,7 +3322,10 @@ var ZapierApiClient = class {
3318
3322
  }
3319
3323
  return getTokenFromEnvOrConfig({
3320
3324
  onEvent: this.options.onEvent,
3321
- fetch: this.options.fetch
3325
+ fetch: this.options.fetch,
3326
+ baseUrl: this.options.baseUrl,
3327
+ authBaseUrl: this.options.authBaseUrl,
3328
+ authClientId: this.options.authClientId
3322
3329
  });
3323
3330
  }
3324
3331
  // Helper to handle responses
@@ -3549,23 +3556,13 @@ var ZapierApiClient = class {
3549
3556
  }
3550
3557
  };
3551
3558
  var createZapierApi = (options) => {
3552
- const {
3553
- baseUrl,
3554
- token,
3555
- getToken,
3556
- debug = false,
3557
- fetch: originalFetch = globalThis.fetch,
3558
- onEvent
3559
- } = options;
3559
+ const { debug = false, fetch: originalFetch = globalThis.fetch } = options;
3560
3560
  const debugLog = createDebugLogger(debug);
3561
3561
  const debugFetch = createDebugFetch({ originalFetch, debugLog });
3562
3562
  return new ZapierApiClient({
3563
- baseUrl,
3564
- token,
3565
- getToken,
3563
+ ...options,
3566
3564
  debug,
3567
- fetch: debugFetch,
3568
- onEvent
3565
+ fetch: debugFetch
3569
3566
  });
3570
3567
  };
3571
3568
 
@@ -3573,7 +3570,9 @@ var createZapierApi = (options) => {
3573
3570
  var apiPlugin = (params) => {
3574
3571
  const {
3575
3572
  fetch: customFetch = globalThis.fetch,
3576
- baseUrl = "https://zapier.com",
3573
+ baseUrl = ZAPIER_BASE_URL,
3574
+ authBaseUrl,
3575
+ authClientId,
3577
3576
  token,
3578
3577
  getToken,
3579
3578
  onEvent,
@@ -3581,6 +3580,8 @@ var apiPlugin = (params) => {
3581
3580
  } = params.context.options;
3582
3581
  const api = createZapierApi({
3583
3582
  baseUrl,
3583
+ authBaseUrl,
3584
+ authClientId,
3584
3585
  token,
3585
3586
  getToken,
3586
3587
  debug,
@@ -3594,6 +3595,94 @@ var apiPlugin = (params) => {
3594
3595
  }
3595
3596
  };
3596
3597
  };
3598
+ var DEFAULT_CONCURRENCY = 10;
3599
+ var BATCH_START_DELAY_MS = 25;
3600
+ var DEFAULT_BATCH_TIMEOUT_MS = 18e4;
3601
+ async function batch(tasks, options = {}) {
3602
+ const {
3603
+ concurrency = DEFAULT_CONCURRENCY,
3604
+ retry = true,
3605
+ batchDelay = BATCH_START_DELAY_MS,
3606
+ timeoutMs = DEFAULT_BATCH_TIMEOUT_MS,
3607
+ taskTimeoutMs
3608
+ } = options;
3609
+ if (concurrency <= 0) {
3610
+ throw new Error("Concurrency must be greater than 0");
3611
+ }
3612
+ if (timeoutMs <= 0) {
3613
+ throw new Error("Timeout must be greater than 0");
3614
+ }
3615
+ if (taskTimeoutMs !== void 0 && taskTimeoutMs <= 0) {
3616
+ throw new Error("Task timeout must be greater than 0");
3617
+ }
3618
+ if (tasks.length === 0) {
3619
+ return [];
3620
+ }
3621
+ const startTime = Date.now();
3622
+ const results = new Array(tasks.length);
3623
+ const taskQueue = tasks.map((task, index) => ({
3624
+ index,
3625
+ task,
3626
+ errorCount: 0
3627
+ }));
3628
+ async function executeTask(taskState) {
3629
+ const { index, task, errorCount } = taskState;
3630
+ try {
3631
+ let result;
3632
+ if (taskTimeoutMs !== void 0) {
3633
+ const timeoutPromise = setTimeout$1(taskTimeoutMs).then(() => {
3634
+ throw new ZapierTimeoutError(
3635
+ `Task timed out after ${taskTimeoutMs}ms`
3636
+ );
3637
+ });
3638
+ result = await Promise.race([task(), timeoutPromise]);
3639
+ } else {
3640
+ result = await task();
3641
+ }
3642
+ results[index] = { status: "fulfilled", value: result };
3643
+ } catch (error) {
3644
+ const newErrorCount = errorCount + 1;
3645
+ const isTimeout = error instanceof ZapierTimeoutError;
3646
+ if (retry && !isTimeout && newErrorCount < MAX_CONSECUTIVE_ERRORS) {
3647
+ const waitTime = calculateWaitTime(1e3, newErrorCount);
3648
+ await setTimeout$1(waitTime);
3649
+ taskQueue.push({
3650
+ index,
3651
+ task,
3652
+ errorCount: newErrorCount
3653
+ });
3654
+ } else {
3655
+ results[index] = { status: "rejected", reason: error };
3656
+ }
3657
+ }
3658
+ }
3659
+ async function worker() {
3660
+ while (taskQueue.length > 0) {
3661
+ const elapsedTime = Date.now() - startTime;
3662
+ if (elapsedTime >= timeoutMs) {
3663
+ throw new ZapierTimeoutError(
3664
+ `Batch operation timed out after ${Math.floor(elapsedTime / 1e3)}s. ${taskQueue.length} task(s) not completed.`
3665
+ );
3666
+ }
3667
+ const taskState = taskQueue.shift();
3668
+ if (!taskState) break;
3669
+ await executeTask(taskState);
3670
+ if (taskQueue.length > 0 && batchDelay > 0) {
3671
+ await setTimeout$1(batchDelay);
3672
+ }
3673
+ }
3674
+ }
3675
+ const workerCount = Math.min(concurrency, tasks.length);
3676
+ const workers = [];
3677
+ for (let i = 0; i < workerCount; i++) {
3678
+ workers.push(worker());
3679
+ if (i < workerCount - 1 && batchDelay > 0) {
3680
+ await setTimeout$1(batchDelay / 10);
3681
+ }
3682
+ }
3683
+ await Promise.all(workers);
3684
+ return results;
3685
+ }
3597
3686
 
3598
3687
  // src/plugins/registry/index.ts
3599
3688
  var registryPlugin = ({ sdk, context }) => {
@@ -3978,7 +4067,7 @@ function getCpuTime() {
3978
4067
 
3979
4068
  // package.json
3980
4069
  var package_default = {
3981
- version: "0.13.7"};
4070
+ version: "0.13.9"};
3982
4071
 
3983
4072
  // src/plugins/eventEmission/builders.ts
3984
4073
  function createBaseEvent(context = {}) {
@@ -4048,17 +4137,80 @@ function buildErrorEventWithContext(data, context = {}) {
4048
4137
  };
4049
4138
  }
4050
4139
 
4140
+ // src/utils/url-utils.ts
4141
+ function getZapierBaseUrl(baseUrl) {
4142
+ if (!baseUrl) {
4143
+ return void 0;
4144
+ }
4145
+ try {
4146
+ const url = new URL(baseUrl);
4147
+ const hostname = url.hostname;
4148
+ const hostParts = hostname.split(".");
4149
+ if (hostParts.length < 2) {
4150
+ return void 0;
4151
+ }
4152
+ const hasZapierPart = hostParts.some(
4153
+ (part) => part === "zapier" || part.startsWith("zapier-")
4154
+ );
4155
+ if (!hasZapierPart) {
4156
+ return void 0;
4157
+ }
4158
+ const rootDomain = hostParts.slice(-2).join(".");
4159
+ return `${url.protocol}//${rootDomain}`;
4160
+ } catch {
4161
+ return void 0;
4162
+ }
4163
+ }
4164
+ function getTrackingBaseUrl({
4165
+ trackingBaseUrl,
4166
+ baseUrl
4167
+ }) {
4168
+ if (trackingBaseUrl) {
4169
+ return trackingBaseUrl;
4170
+ }
4171
+ if (process.env.ZAPIER_TRACKING_BASE_URL) {
4172
+ return process.env.ZAPIER_TRACKING_BASE_URL;
4173
+ }
4174
+ if (baseUrl) {
4175
+ const zapierBaseUrl = getZapierBaseUrl(baseUrl);
4176
+ if (zapierBaseUrl) {
4177
+ return zapierBaseUrl;
4178
+ }
4179
+ }
4180
+ if (baseUrl) {
4181
+ return baseUrl;
4182
+ }
4183
+ return ZAPIER_BASE_URL;
4184
+ }
4185
+
4051
4186
  // src/plugins/eventEmission/index.ts
4052
4187
  var APPLICATION_LIFECYCLE_EVENT_SUBJECT = "platform.sdk.ApplicationLifecycleEvent";
4053
4188
  var ERROR_OCCURRED_EVENT_SUBJECT = "platform.sdk.ErrorOccurredEvent";
4189
+ var transportStates = /* @__PURE__ */ new WeakMap();
4054
4190
  async function silentEmit(transport, subject, event) {
4055
4191
  try {
4056
- transport.emit(subject, event).catch(() => {
4192
+ let state = transportStates.get(transport);
4193
+ if (!state) {
4194
+ state = { hasWorked: false, hasLoggedFailure: false };
4195
+ transportStates.set(transport, state);
4196
+ }
4197
+ transport.emit(subject, event).then(() => {
4198
+ state.hasWorked = true;
4199
+ }).catch((error) => {
4200
+ if (!state.hasWorked && !state.hasLoggedFailure) {
4201
+ state.hasLoggedFailure = true;
4202
+ console.warn(
4203
+ `[zapier-sdk] Tracking failed: ${error.message || "Unknown error"}`
4204
+ );
4205
+ console.warn(
4206
+ `[zapier-sdk] Hint: Set trackingBaseUrl parameter or ZAPIER_TRACKING_BASE_URL environment variable if using custom domains`
4207
+ );
4208
+ }
4057
4209
  });
4058
4210
  } catch {
4059
4211
  }
4060
4212
  }
4061
- function getTransportConfig() {
4213
+ function getTransportConfig(options) {
4062
4214
  const envTransport = process?.env?.ZAPIER_SDK_TELEMETRY_TRANSPORT;
4063
4215
  if (envTransport === "noop" || envTransport === "disabled") {
4064
4216
  return { type: "noop" };
@@ -4066,14 +4218,20 @@ function getTransportConfig() {
4066
4218
  if (envTransport === "console") {
4067
4219
  return { type: "console" };
4068
4220
  }
4069
- const endpoint = process?.env?.ZAPIER_SDK_TELEMETRY_ENDPOINT || TRACKING_API_ENDPOINT;
4221
+ const endpoint = process?.env?.ZAPIER_SDK_TELEMETRY_ENDPOINT || `${getTrackingBaseUrl({
4222
+ trackingBaseUrl: options?.trackingBaseUrl,
4223
+ baseUrl: options?.baseUrl
4224
+ })}/api/v4/tracking/event/`;
4070
4225
  return {
4071
4226
  type: "http",
4072
4227
  endpoint
4073
4228
  };
4074
4229
  }
4075
4230
  var eventEmissionPlugin = ({ context }) => {
4076
- const defaultTransport = getTransportConfig();
4231
+ const defaultTransport = getTransportConfig({
4232
+ trackingBaseUrl: context.options.trackingBaseUrl,
4233
+ baseUrl: context.options.baseUrl
4234
+ });
4077
4235
  const config = {
4078
4236
  enabled: context.options.eventEmission?.enabled ?? true,
4079
4237
  transport: (
@@ -4277,4 +4435,4 @@ function createZapierSdk(options = {}) {
4277
4435
  return createZapierSdkWithoutRegistry(options).addPlugin(registryPlugin);
4278
4436
  }
4279
4437
 
4280
- export { ActionKeyPropertySchema, ActionTypePropertySchema, AppKeyPropertySchema, AuthenticationIdPropertySchema, DEFAULT_CONFIG_PATH, DebugPropertySchema, InputsPropertySchema, LimitPropertySchema, OffsetPropertySchema, OutputPropertySchema, ParamsPropertySchema, RelayFetchSchema, RelayRequestSchema, ZapierActionError, ZapierApiError, ZapierAppNotFoundError, ZapierAuthenticationError, ZapierBundleError, ZapierConfigurationError, ZapierError, ZapierNotFoundError, ZapierResourceNotFoundError, ZapierTimeoutError, ZapierUnknownError, ZapierValidationError, actionKeyResolver, actionTypeResolver, apiPlugin, appKeyResolver, appsPlugin, authenticationIdGenericResolver, authenticationIdResolver, buildApplicationLifecycleEvent, buildErrorEvent, buildErrorEventWithContext, createBaseEvent, createFunction, createSdk, createZapierSdk, createZapierSdkWithoutRegistry, fetchPlugin, findFirstAuthenticationPlugin, findManifestEntry, findUniqueAuthenticationPlugin, formatErrorMessage, generateEventId, getActionPlugin, getAppPlugin, getAuthenticationPlugin, getCiPlatform, getCpuTime, getCurrentTimestamp, getMemoryUsage, getOsInfo, getPlatformVersions, getPreferredManifestEntryKey, getProfilePlugin, getReleaseId, getTokenFromCliLogin, getTokenFromEnv, getTokenFromEnvOrConfig, inputFieldKeyResolver, inputsAllOptionalResolver, inputsResolver, isCi, isPositional, listActionsPlugin, listAppsPlugin, listAuthenticationsPlugin, listInputFieldsPlugin, manifestPlugin, readManifestFromFile, registryPlugin, requestPlugin, runActionPlugin, toSnakeCase, toTitleCase };
4438
+ export { ActionKeyPropertySchema, ActionTypePropertySchema, AppKeyPropertySchema, AuthenticationIdPropertySchema, DEFAULT_CONFIG_PATH, DebugPropertySchema, InputsPropertySchema, LimitPropertySchema, MAX_PAGE_LIMIT, OffsetPropertySchema, OutputPropertySchema, ParamsPropertySchema, RelayFetchSchema, RelayRequestSchema, ZAPIER_BASE_URL, ZapierActionError, ZapierApiError, ZapierAppNotFoundError, ZapierAuthenticationError, ZapierBundleError, ZapierConfigurationError, ZapierError, ZapierNotFoundError, ZapierResourceNotFoundError, ZapierTimeoutError, ZapierUnknownError, ZapierValidationError, actionKeyResolver, actionTypeResolver, apiPlugin, appKeyResolver, appsPlugin, authenticationIdGenericResolver, authenticationIdResolver, batch, buildApplicationLifecycleEvent, buildErrorEvent, buildErrorEventWithContext, createBaseEvent, createFunction, createSdk, createZapierSdk, createZapierSdkWithoutRegistry, fetchPlugin, findFirstAuthenticationPlugin, findManifestEntry, findUniqueAuthenticationPlugin, formatErrorMessage, generateEventId, getActionPlugin, getAppPlugin, getAuthenticationPlugin, getCiPlatform, getCpuTime, getCurrentTimestamp, getMemoryUsage, getOsInfo, getPlatformVersions, getPreferredManifestEntryKey, getProfilePlugin, getReleaseId, getTokenFromCliLogin, getTokenFromEnv, getTokenFromEnvOrConfig, inputFieldKeyResolver, inputsAllOptionalResolver, inputsResolver, isCi, isPositional, listActionsPlugin, listAppsPlugin, listAuthenticationsPlugin, listInputFieldsPlugin, manifestPlugin, readManifestFromFile, registryPlugin, requestPlugin, runActionPlugin, toSnakeCase, toTitleCase };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/api/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,WAAW,gBAAiB,SAAQ,cAAc;CAAG;AAG3D,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE;QACP,GAAG,EAAE,SAAS,CAAC;KAChB,CAAC;CACH;AAGD,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,iBAAiB,CA2BvD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/api/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAGjD,MAAM,WAAW,gBAAiB,SAAQ,cAAc;CAAG;AAG3D,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE;QACP,GAAG,EAAE,SAAS,CAAC;KAChB,CAAC;CACH;AAGD,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,iBAAiB,CA+BvD,CAAC"}
@@ -1,11 +1,14 @@
1
1
  import { createZapierApi } from "../../api";
2
+ import { ZAPIER_BASE_URL } from "../../constants";
2
3
  // API plugin requires no context and provides api in context
3
4
  export const apiPlugin = (params) => {
4
5
  // Extract all options - everything passed to the plugin
5
- const { fetch: customFetch = globalThis.fetch, baseUrl = "https://zapier.com", token, getToken, onEvent, debug = false, } = params.context.options;
6
+ const { fetch: customFetch = globalThis.fetch, baseUrl = ZAPIER_BASE_URL, authBaseUrl, authClientId, token, getToken, onEvent, debug = false, } = params.context.options;
6
7
  // Create the API client - it will handle token resolution internally
7
8
  const api = createZapierApi({
8
9
  baseUrl,
10
+ authBaseUrl,
11
+ authClientId,
9
12
  token,
10
13
  getToken,
11
14
  debug,
@@ -25,6 +25,8 @@ export interface EventEmissionProvides {
25
25
  export declare const eventEmissionPlugin: Plugin<{}, {
26
26
  options: {
27
27
  eventEmission?: EventEmissionConfig;
28
+ trackingBaseUrl?: string;
29
+ baseUrl?: string;
28
30
  };
29
31
  }, EventEmissionProvides>;
30
32
  export type { EventContext, ApplicationLifecycleEventData, EnhancedErrorEventData, } from "./types";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/eventEmission/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAUnE,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B;AAGD,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE;QACb,SAAS,EAAE,cAAc,CAAC;QAC1B,MAAM,EAAE,mBAAmB,CAAC;QAE5B,IAAI,CAAC,CAAC,SAAS,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;QAErD,eAAe,IAAI,SAAS,CAAC;KAC9B,CAAC;CACH;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,oBAAoB,CAAC;CAC/B;AA4CD,eAAO,MAAM,mBAAmB,EAAE,MAAM,CACtC,EAAE,EACF;IAAE,OAAO,EAAE;QAAE,aAAa,CAAC,EAAE,mBAAmB,CAAA;KAAE,CAAA;CAAE,EACpD,qBAAqB,CAiMtB,CAAC;AAGF,YAAY,EACV,YAAY,EACZ,6BAA6B,EAC7B,sBAAsB,GACvB,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,8BAA8B,EAC9B,0BAA0B,EAC1B,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/plugins/eventEmission/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAUnE,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,eAAe,CAAC;CAC7B;AAGD,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE;QACb,SAAS,EAAE,cAAc,CAAC;QAC1B,MAAM,EAAE,mBAAmB,CAAC;QAE5B,IAAI,CAAC,CAAC,SAAS,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;QAErD,eAAe,IAAI,SAAS,CAAC;KAC9B,CAAC;CACH;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,oBAAoB,CAAC;CAC/B;AA+ED,eAAO,MAAM,mBAAmB,EAAE,MAAM,CACtC,EAAE,EACF;IACE,OAAO,EAAE;QACP,aAAa,CAAC,EAAE,mBAAmB,CAAC;QACpC,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH,EACD,qBAAqB,CAoMtB,CAAC;AAGF,YAAY,EACV,YAAY,EACZ,6BAA6B,EAC7B,sBAAsB,GACvB,MAAM,SAAS,CAAC;AACjB,OAAO,EACL,8BAA8B,EAC9B,0BAA0B,EAC1B,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC9D,cAAc,SAAS,CAAC"}
@@ -7,23 +7,42 @@
7
7
  import { createTransport } from "./transport";
8
8
  import { generateEventId, getCurrentTimestamp, getReleaseId } from "./utils";
9
9
  import { buildApplicationLifecycleEvent, buildErrorEventWithContext, } from "./builders";
10
- import { TRACKING_API_ENDPOINT } from "../../constants";
10
+ import { getTrackingBaseUrl } from "../../utils/url-utils";
11
11
  const APPLICATION_LIFECYCLE_EVENT_SUBJECT = "platform.sdk.ApplicationLifecycleEvent";
12
12
  const ERROR_OCCURRED_EVENT_SUBJECT = "platform.sdk.ErrorOccurredEvent";
13
- // Silent emission wrapper - ensures events never disrupt SDK operation
13
+ // Track transport success/failure so we only log failure once.
14
+ const transportStates = new WeakMap();
15
+ // Silent emission wrapper with smart first-failure logging
14
16
  async function silentEmit(transport, subject, event) {
15
17
  try {
18
+ // Get or initialize state for this transport
19
+ let state = transportStates.get(transport);
20
+ if (!state) {
21
+ state = { hasWorked: false, hasLoggedFailure: false };
22
+ transportStates.set(transport, state);
23
+ }
16
24
  // Fire and forget - don't await the transport
17
- transport.emit(subject, event).catch(() => {
18
- // Silently ignore transport failures
25
+ transport
26
+ .emit(subject, event)
27
+ .then(() => {
28
+ // Mark as working if any emit succeeds
29
+ state.hasWorked = true;
30
+ })
31
+ .catch((error) => {
32
+ // Only log if we haven't seen it work and haven't logged yet
33
+ if (!state.hasWorked && !state.hasLoggedFailure) {
34
+ state.hasLoggedFailure = true;
35
+ console.warn(`[zapier-sdk] Tracking failed: ${error.message || "Unknown error"}`);
36
+ console.warn(`[zapier-sdk] Hint: Set trackingBaseUrl parameter or ZAPIER_TRACKING_BASE_URL environment variable if using custom domains`);
37
+ }
19
38
  });
20
39
  }
21
40
  catch {
22
41
  // Silently ignore all errors
23
42
  }
24
43
  }
25
- // Helper to get transport config from environment or defaults
26
- function getTransportConfig() {
44
+ // Helper to get transport config from environment or options
45
+ function getTransportConfig(options) {
27
46
  const envTransport = process?.env?.ZAPIER_SDK_TELEMETRY_TRANSPORT;
28
47
  if (envTransport === "noop" || envTransport === "disabled") {
29
48
  return { type: "noop" };
@@ -31,15 +50,22 @@ function getTransportConfig() {
31
50
  if (envTransport === "console") {
32
51
  return { type: "console" };
33
52
  }
34
- // Default to HTTP transport
35
- const endpoint = process?.env?.ZAPIER_SDK_TELEMETRY_ENDPOINT || TRACKING_API_ENDPOINT;
53
+ // Default to HTTP transport with resolved tracking URL
54
+ const endpoint = process?.env?.ZAPIER_SDK_TELEMETRY_ENDPOINT ||
55
+ `${getTrackingBaseUrl({
56
+ trackingBaseUrl: options?.trackingBaseUrl,
57
+ baseUrl: options?.baseUrl,
58
+ })}/api/v4/tracking/event/`;
36
59
  return {
37
60
  type: "http",
38
61
  endpoint,
39
62
  };
40
63
  }
41
64
  export const eventEmissionPlugin = ({ context }) => {
42
- const defaultTransport = getTransportConfig();
65
+ const defaultTransport = getTransportConfig({
66
+ trackingBaseUrl: context.options.trackingBaseUrl,
67
+ baseUrl: context.options.baseUrl,
68
+ });
43
69
  // Merge config: env var takes precedence over options, options take precedence over defaults
44
70
  const config = {
45
71
  enabled: context.options.eventEmission?.enabled ?? true,
@@ -119,6 +119,106 @@ describe("eventEmissionPlugin", () => {
119
119
  await new Promise((resolve) => setTimeout(resolve, 10));
120
120
  expect(failingTransport.emit).toHaveBeenCalled();
121
121
  });
122
+ it("should log tracking failure only on first occurrence", async () => {
123
+ // Mock console.warn to track logging calls
124
+ const mockConsoleWarn = vi
125
+ .spyOn(console, "warn")
126
+ .mockImplementation(() => { });
127
+ // Mock transport to throw error
128
+ const failingTransport = {
129
+ emit: vi.fn().mockRejectedValue(new Error("Network error")),
130
+ close: vi.fn().mockResolvedValue(undefined),
131
+ };
132
+ vi.mocked(createTransport).mockReturnValueOnce(failingTransport);
133
+ const plugin = eventEmissionPlugin({
134
+ sdk: {},
135
+ context: {
136
+ meta: {},
137
+ options: {
138
+ eventEmission: {
139
+ enabled: true,
140
+ transport: {
141
+ type: "http",
142
+ endpoint: "https://example.com",
143
+ },
144
+ },
145
+ },
146
+ },
147
+ });
148
+ // First event should trigger logging
149
+ plugin.context.eventEmission.emit("test.event.FirstEvent", {
150
+ data: "first",
151
+ });
152
+ await new Promise((resolve) => setTimeout(resolve, 10));
153
+ // Verify logging occurred
154
+ const initialLogCount = mockConsoleWarn.mock.calls.length;
155
+ expect(initialLogCount).toBeGreaterThan(0);
156
+ // Second and third events should not trigger additional logging
157
+ plugin.context.eventEmission.emit("test.event.SecondEvent", {
158
+ data: "second",
159
+ });
160
+ plugin.context.eventEmission.emit("test.event.ThirdEvent", {
161
+ data: "third",
162
+ });
163
+ await new Promise((resolve) => setTimeout(resolve, 10));
164
+ // Verify no additional logging occurred
165
+ expect(mockConsoleWarn).toHaveBeenCalledTimes(initialLogCount);
166
+ mockConsoleWarn.mockRestore();
167
+ });
168
+ it("should not log failures after a successful emit", async () => {
169
+ // Mock console.warn to track logging calls
170
+ const mockConsoleWarn = vi
171
+ .spyOn(console, "warn")
172
+ .mockImplementation(() => { });
173
+ // Mock transport that succeeds first, then fails
174
+ let callCount = 0;
175
+ const mixedTransport = {
176
+ emit: vi.fn().mockImplementation(() => {
177
+ callCount++;
178
+ if (callCount === 1) {
179
+ return Promise.resolve(); // First call succeeds
180
+ }
181
+ else {
182
+ return Promise.reject(new Error("Network error")); // Subsequent calls fail
183
+ }
184
+ }),
185
+ close: vi.fn().mockResolvedValue(undefined),
186
+ };
187
+ vi.mocked(createTransport).mockReturnValueOnce(mixedTransport);
188
+ const plugin = eventEmissionPlugin({
189
+ sdk: {},
190
+ context: {
191
+ meta: {},
192
+ options: {
193
+ eventEmission: {
194
+ enabled: true,
195
+ transport: {
196
+ type: "http",
197
+ endpoint: "https://example.com",
198
+ },
199
+ },
200
+ },
201
+ },
202
+ });
203
+ // First emit should succeed
204
+ plugin.context.eventEmission.emit("test.event.SuccessfulEvent", {
205
+ data: "success",
206
+ });
207
+ // Give time for success to be recorded
208
+ await new Promise((resolve) => setTimeout(resolve, 10));
209
+ // Subsequent emits should fail but not log
210
+ plugin.context.eventEmission.emit("test.event.FailingEvent1", {
211
+ data: "fail1",
212
+ });
213
+ plugin.context.eventEmission.emit("test.event.FailingEvent2", {
214
+ data: "fail2",
215
+ });
216
+ // Give async emissions time to complete
217
+ await new Promise((resolve) => setTimeout(resolve, 20));
218
+ // Should not have logged any warnings because tracking worked initially
219
+ expect(mockConsoleWarn).toHaveBeenCalledTimes(0);
220
+ mockConsoleWarn.mockRestore();
221
+ });
122
222
  it("should merge options with defaults", () => {
123
223
  const plugin = eventEmissionPlugin({
124
224
  sdk: {},
@@ -15,8 +15,8 @@ export declare const ActionItemSchema: z.ZodObject<Omit<{
15
15
  title: z.ZodString;
16
16
  type: z.ZodLiteral<"action">;
17
17
  }, "strip", z.ZodTypeAny, {
18
- type: "action";
19
18
  key: string;
19
+ type: "action";
20
20
  description: string;
21
21
  title: string;
22
22
  app_key: string;
@@ -26,8 +26,8 @@ export declare const ActionItemSchema: z.ZodObject<Omit<{
26
26
  is_hidden?: boolean | undefined;
27
27
  app_version?: string | undefined;
28
28
  }, {
29
- type: "action";
30
29
  key: string;
30
+ type: "action";
31
31
  description: string;
32
32
  title: string;
33
33
  app_key: string;
@@ -35,6 +35,7 @@ export declare const AuthenticationItemSchema: z.ZodObject<Omit<{
35
35
  is_private: boolean;
36
36
  shared_with_all: boolean;
37
37
  url?: string | undefined;
38
+ members?: string | undefined;
38
39
  label?: string | null | undefined;
39
40
  lastchanged?: string | undefined;
40
41
  destination_selected_api?: string | null | undefined;
@@ -44,7 +45,6 @@ export declare const AuthenticationItemSchema: z.ZodObject<Omit<{
44
45
  identifier?: string | null | undefined;
45
46
  title?: string | null | undefined;
46
47
  groups?: string | undefined;
47
- members?: string | undefined;
48
48
  permissions?: Record<string, boolean> | undefined;
49
49
  user_id?: number | undefined;
50
50
  implementation_id?: string | undefined;
@@ -60,6 +60,7 @@ export declare const AuthenticationItemSchema: z.ZodObject<Omit<{
60
60
  is_private: boolean;
61
61
  shared_with_all: boolean;
62
62
  url?: string | undefined;
63
+ members?: string | undefined;
63
64
  label?: string | null | undefined;
64
65
  lastchanged?: string | undefined;
65
66
  destination_selected_api?: string | null | undefined;
@@ -69,7 +70,6 @@ export declare const AuthenticationItemSchema: z.ZodObject<Omit<{
69
70
  identifier?: string | null | undefined;
70
71
  title?: string | null | undefined;
71
72
  groups?: string | undefined;
72
- members?: string | undefined;
73
73
  permissions?: Record<string, boolean> | undefined;
74
74
  user_id?: number | undefined;
75
75
  implementation_id?: string | undefined;
@@ -114,6 +114,7 @@ export declare const AuthItemSchema: z.ZodObject<Omit<{
114
114
  is_private: boolean;
115
115
  shared_with_all: boolean;
116
116
  url?: string | undefined;
117
+ members?: string | undefined;
117
118
  label?: string | null | undefined;
118
119
  lastchanged?: string | undefined;
119
120
  destination_selected_api?: string | null | undefined;
@@ -123,7 +124,6 @@ export declare const AuthItemSchema: z.ZodObject<Omit<{
123
124
  identifier?: string | null | undefined;
124
125
  title?: string | null | undefined;
125
126
  groups?: string | undefined;
126
- members?: string | undefined;
127
127
  permissions?: Record<string, boolean> | undefined;
128
128
  user_id?: number | undefined;
129
129
  implementation_id?: string | undefined;
@@ -139,6 +139,7 @@ export declare const AuthItemSchema: z.ZodObject<Omit<{
139
139
  is_private: boolean;
140
140
  shared_with_all: boolean;
141
141
  url?: string | undefined;
142
+ members?: string | undefined;
142
143
  label?: string | null | undefined;
143
144
  lastchanged?: string | undefined;
144
145
  destination_selected_api?: string | null | undefined;
@@ -148,7 +149,6 @@ export declare const AuthItemSchema: z.ZodObject<Omit<{
148
149
  identifier?: string | null | undefined;
149
150
  title?: string | null | undefined;
150
151
  groups?: string | undefined;
151
- members?: string | undefined;
152
152
  permissions?: Record<string, boolean> | undefined;
153
153
  user_id?: number | undefined;
154
154
  implementation_id?: string | undefined;