@dereekb/zoho 11.0.12 → 11.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.cjs.js CHANGED
@@ -2911,6 +2911,43 @@ const ZOHO_DUPLICATE_DATA_ERROR_CODE = 'DUPLICATE_DATA';
2911
2911
  * Error when some passed data is invalid.
2912
2912
  */
2913
2913
  const ZOHO_INVALID_DATA_ERROR_CODE = 'INVALID_DATA';
2914
+ /**
2915
+ * Error when too many requests are made in a short period of time.
2916
+ */
2917
+ const ZOHO_TOO_MANY_REQUESTS_ERROR_CODE = 'TOO_MANY_REQUESTS';
2918
+ /**
2919
+ * The status code that Zoho uses to indicates that too many requests have been made in a short period of time.
2920
+ */
2921
+ const ZOHO_TOO_MANY_REQUESTS_HTTP_STATUS_CODE = 429;
2922
+ const ZOHO_RATE_LIMIT_LIMIT_HEADER = 'X-RATELIMIT-LIMIT';
2923
+ const ZOHO_RATE_LIMIT_REMAINING_HEADER = 'X-RATELIMIT-REMAINING';
2924
+ const ZOHO_RATE_LIMIT_RESET_HEADER = 'X-RATELIMIT-RESET';
2925
+ const DEFAULT_ZOHO_API_RATE_LIMIT = 100;
2926
+ const DEFAULT_ZOHO_API_RATE_LIMIT_RESET_PERIOD = util.MS_IN_MINUTE;
2927
+ function zohoRateLimitHeaderDetails(headers) {
2928
+ const limitHeader = headers.has(ZOHO_RATE_LIMIT_REMAINING_HEADER);
2929
+ const remainingHeader = headers.get(ZOHO_RATE_LIMIT_REMAINING_HEADER);
2930
+ const resetHeader = headers.get(ZOHO_RATE_LIMIT_RESET_HEADER);
2931
+ let result = null;
2932
+ if (limitHeader != null && remainingHeader != null && resetHeader != null) {
2933
+ const limit = Number(limitHeader);
2934
+ const remaining = Number(remainingHeader);
2935
+ const reset = Number(resetHeader);
2936
+ const resetAt = new Date(reset);
2937
+ result = {
2938
+ limit,
2939
+ remaining,
2940
+ reset,
2941
+ resetAt
2942
+ };
2943
+ }
2944
+ return result;
2945
+ }
2946
+ class ZohoTooManyRequestsError extends ZohoServerFetchResponseError {
2947
+ get headerDetails() {
2948
+ return zohoRateLimitHeaderDetails(this.responseError.response.headers);
2949
+ }
2950
+ }
2914
2951
  /**
2915
2952
  * Function that parses/transforms a ZohoServerErrorResponseData into a general ZohoServerError or other known error type.
2916
2953
  *
@@ -2933,6 +2970,9 @@ function parseZohoServerErrorResponseData(errorResponseData, responseError) {
2933
2970
  case ZOHO_INVALID_QUERY_ERROR_CODE:
2934
2971
  result = new ZohoInvalidQueryError(errorData, responseError);
2935
2972
  break;
2973
+ case ZOHO_TOO_MANY_REQUESTS_ERROR_CODE:
2974
+ result = new ZohoTooManyRequestsError(errorData, responseError);
2975
+ break;
2936
2976
  default:
2937
2977
  result = new ZohoServerFetchResponseError(errorData, responseError);
2938
2978
  break;
@@ -3370,6 +3410,52 @@ function zohoAccessTokenStringFactory(zohoAccessTokenFactory) {
3370
3410
  };
3371
3411
  }
3372
3412
 
3413
+ function zohoRateLimitedFetchHandler(config) {
3414
+ var _config$maxRateLimit, _config$resetPeriod;
3415
+ const defaultLimit = (_config$maxRateLimit = config == null ? void 0 : config.maxRateLimit) != null ? _config$maxRateLimit : DEFAULT_ZOHO_API_RATE_LIMIT;
3416
+ const defaultResetPeriod = (_config$resetPeriod = config == null ? void 0 : config.resetPeriod) != null ? _config$resetPeriod : DEFAULT_ZOHO_API_RATE_LIMIT_RESET_PERIOD;
3417
+ function configForLimit(limit, resetAt) {
3418
+ return {
3419
+ limit: defaultLimit,
3420
+ cooldownRate: limit / (defaultResetPeriod / util.MS_IN_SECOND),
3421
+ exponentRate: 1.12,
3422
+ maxWaitTime: util.MS_IN_SECOND * 10,
3423
+ resetPeriod: defaultResetPeriod
3424
+ };
3425
+ }
3426
+ const defaultConfig = configForLimit(defaultLimit);
3427
+ const rateLimiter = util.resetPeriodPromiseRateLimiter(defaultConfig);
3428
+ return fetch.rateLimitedFetchHandler({
3429
+ rateLimiter,
3430
+ updateWithResponse: function (response, fetchResponseError) {
3431
+ const hasLimitHeader = response.headers.has(ZOHO_RATE_LIMIT_REMAINING_HEADER);
3432
+ let shouldRetry = false;
3433
+ let enabled = false;
3434
+ if (hasLimitHeader) {
3435
+ const headerDetails = zohoRateLimitHeaderDetails(response.headers);
3436
+ if (headerDetails) {
3437
+ const {
3438
+ limit,
3439
+ resetAt,
3440
+ remaining
3441
+ } = headerDetails;
3442
+ if (limit !== defaultLimit) {
3443
+ const newConfig = configForLimit(limit);
3444
+ rateLimiter.setConfig(newConfig, false);
3445
+ }
3446
+ rateLimiter.setRemainingLimit(remaining);
3447
+ rateLimiter.setNextResetAt(resetAt);
3448
+ enabled = true;
3449
+ // only retry if it's a TOO MANY REQUESTS error
3450
+ shouldRetry = response.status === ZOHO_TOO_MANY_REQUESTS_HTTP_STATUS_CODE;
3451
+ }
3452
+ }
3453
+ rateLimiter.setEnabled(enabled);
3454
+ return shouldRetry;
3455
+ }
3456
+ });
3457
+ }
3458
+
3373
3459
  function _call$1(body, then, direct) {
3374
3460
  if (direct) {
3375
3461
  return then ? then(body()) : body();
@@ -3386,9 +3472,10 @@ function zohoRecruitFactory(factoryConfig) {
3386
3472
  accountsContext
3387
3473
  } = factoryConfig;
3388
3474
  const accessTokenStringFactory = zohoAccessTokenStringFactory(accountsContext.loadAccessToken);
3475
+ const fetchHandler = zohoRateLimitedFetchHandler(factoryConfig.rateLimiterConfig);
3389
3476
  const {
3390
3477
  logZohoServerErrorFunction,
3391
- fetchFactory = input => fetch.nodeFetchService.makeFetch({
3478
+ fetchFactory = input => fetch.fetchApiFetchService.makeFetch({
3392
3479
  baseUrl: input.apiUrl,
3393
3480
  baseRequest: function () {
3394
3481
  return _call$1(accessTokenStringFactory, function (_accessTokenStringFac) {
@@ -3400,6 +3487,7 @@ function zohoRecruitFactory(factoryConfig) {
3400
3487
  };
3401
3488
  });
3402
3489
  },
3490
+ fetchHandler,
3403
3491
  timeout: 20 * 1000,
3404
3492
  requireOkResponse: true,
3405
3493
  useTimeout: true // use timeout
@@ -3423,7 +3511,8 @@ function zohoRecruitFactory(factoryConfig) {
3423
3511
  fetchJson,
3424
3512
  config: Object.assign({}, config, {
3425
3513
  apiUrl
3426
- })
3514
+ }),
3515
+ zohoRateLimiter: fetchHandler._rateLimiter
3427
3516
  };
3428
3517
  const zohoRecruit = {
3429
3518
  recruitContext
@@ -3540,15 +3629,17 @@ function _invoke(body, then) {
3540
3629
  return then(result);
3541
3630
  }
3542
3631
  function zohoAccountsFactory(factoryConfig) {
3632
+ const fetchHandler = zohoRateLimitedFetchHandler();
3543
3633
  const {
3544
3634
  logZohoServerErrorFunction,
3545
- fetchFactory = input => fetch.nodeFetchService.makeFetch({
3635
+ fetchFactory = input => fetch.fetchApiFetchService.makeFetch({
3546
3636
  baseUrl: input.apiUrl,
3547
3637
  baseRequest: {
3548
3638
  headers: {
3549
3639
  'Content-Type': 'application/json'
3550
3640
  }
3551
3641
  },
3642
+ fetchHandler,
3552
3643
  timeout: 20 * 1000,
3553
3644
  requireOkResponse: true,
3554
3645
  useTimeout: true // use timeout
@@ -3664,6 +3755,8 @@ function zohoAccountsZohoAccessTokenFactory(config) {
3664
3755
  });
3665
3756
  }
3666
3757
 
3758
+ exports.DEFAULT_ZOHO_API_RATE_LIMIT = DEFAULT_ZOHO_API_RATE_LIMIT;
3759
+ exports.DEFAULT_ZOHO_API_RATE_LIMIT_RESET_PERIOD = DEFAULT_ZOHO_API_RATE_LIMIT_RESET_PERIOD;
3667
3760
  exports.ZOHO_ACCOUNTS_INVALID_CLIENT_ERROR_CODE = ZOHO_ACCOUNTS_INVALID_CLIENT_ERROR_CODE;
3668
3761
  exports.ZOHO_ACCOUNTS_INVALID_CODE_ERROR_CODE = ZOHO_ACCOUNTS_INVALID_CODE_ERROR_CODE;
3669
3762
  exports.ZOHO_ACCOUNTS_US_API_URL = ZOHO_ACCOUNTS_US_API_URL;
@@ -3673,9 +3766,14 @@ exports.ZOHO_INVALID_AUTHORIZATION_ERROR_CODE = ZOHO_INVALID_AUTHORIZATION_ERROR
3673
3766
  exports.ZOHO_INVALID_DATA_ERROR_CODE = ZOHO_INVALID_DATA_ERROR_CODE;
3674
3767
  exports.ZOHO_INVALID_QUERY_ERROR_CODE = ZOHO_INVALID_QUERY_ERROR_CODE;
3675
3768
  exports.ZOHO_MANDATORY_NOT_FOUND_ERROR_CODE = ZOHO_MANDATORY_NOT_FOUND_ERROR_CODE;
3769
+ exports.ZOHO_RATE_LIMIT_LIMIT_HEADER = ZOHO_RATE_LIMIT_LIMIT_HEADER;
3770
+ exports.ZOHO_RATE_LIMIT_REMAINING_HEADER = ZOHO_RATE_LIMIT_REMAINING_HEADER;
3771
+ exports.ZOHO_RATE_LIMIT_RESET_HEADER = ZOHO_RATE_LIMIT_RESET_HEADER;
3676
3772
  exports.ZOHO_RECRUIT_CANDIDATES_MODULE = ZOHO_RECRUIT_CANDIDATES_MODULE;
3677
3773
  exports.ZOHO_RECRUIT_SERVICE_NAME = ZOHO_RECRUIT_SERVICE_NAME;
3678
3774
  exports.ZOHO_SUCCESS_CODE = ZOHO_SUCCESS_CODE;
3775
+ exports.ZOHO_TOO_MANY_REQUESTS_ERROR_CODE = ZOHO_TOO_MANY_REQUESTS_ERROR_CODE;
3776
+ exports.ZOHO_TOO_MANY_REQUESTS_HTTP_STATUS_CODE = ZOHO_TOO_MANY_REQUESTS_HTTP_STATUS_CODE;
3679
3777
  exports.ZohoAccountsAccessTokenError = ZohoAccountsAccessTokenError;
3680
3778
  exports.ZohoAccountsAuthFailureError = ZohoAccountsAuthFailureError;
3681
3779
  exports.ZohoInternalError = ZohoInternalError;
@@ -3689,6 +3787,7 @@ exports.ZohoRecruitRecordCrudNoMatchingRecordError = ZohoRecruitRecordCrudNoMatc
3689
3787
  exports.ZohoRecruitRecordNoContentError = ZohoRecruitRecordNoContentError;
3690
3788
  exports.ZohoServerError = ZohoServerError;
3691
3789
  exports.ZohoServerFetchResponseError = ZohoServerFetchResponseError;
3790
+ exports.ZohoTooManyRequestsError = ZohoTooManyRequestsError;
3692
3791
  exports.accessToken = accessToken;
3693
3792
  exports.assertRecordDataArrayResultHasContent = assertRecordDataArrayResultHasContent;
3694
3793
  exports.createNotes = createNotes;
@@ -3726,6 +3825,8 @@ exports.zohoAccountsConfigApiUrl = zohoAccountsConfigApiUrl;
3726
3825
  exports.zohoAccountsFactory = zohoAccountsFactory;
3727
3826
  exports.zohoAccountsZohoAccessTokenFactory = zohoAccountsZohoAccessTokenFactory;
3728
3827
  exports.zohoFetchPageFactory = zohoFetchPageFactory;
3828
+ exports.zohoRateLimitHeaderDetails = zohoRateLimitHeaderDetails;
3829
+ exports.zohoRateLimitedFetchHandler = zohoRateLimitedFetchHandler;
3729
3830
  exports.zohoRecruitApiFetchJsonInput = zohoRecruitApiFetchJsonInput;
3730
3831
  exports.zohoRecruitConfigApiUrl = zohoRecruitConfigApiUrl;
3731
3832
  exports.zohoRecruitFactory = zohoRecruitFactory;
package/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
- import { getNextPageNumber, escapeStringCharactersFunction, isStandardInternetAccessibleWebsiteUrl, filterMaybeValues, asArray, MS_IN_MINUTE, MS_IN_SECOND } from '@dereekb/util';
2
- import { fetchPageFactory, FetchResponseError, makeUrlSearchParams, FetchRequestFactoryError, fetchJsonFunction, returnNullHandleFetchJsonParseErrorFunction, nodeFetchService } from '@dereekb/util/fetch';
1
+ import { getNextPageNumber, escapeStringCharactersFunction, isStandardInternetAccessibleWebsiteUrl, filterMaybeValues, asArray, MS_IN_MINUTE, resetPeriodPromiseRateLimiter, MS_IN_SECOND } from '@dereekb/util';
2
+ import { fetchPageFactory, FetchResponseError, makeUrlSearchParams, FetchRequestFactoryError, rateLimitedFetchHandler, fetchJsonFunction, returnNullHandleFetchJsonParseErrorFunction, fetchApiFetchService } from '@dereekb/util/fetch';
3
3
  import { BaseError } from 'make-error';
4
4
 
5
5
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
@@ -3005,6 +3005,45 @@ const ZOHO_DUPLICATE_DATA_ERROR_CODE = 'DUPLICATE_DATA';
3005
3005
  */
3006
3006
  const ZOHO_INVALID_DATA_ERROR_CODE = 'INVALID_DATA';
3007
3007
 
3008
+ /**
3009
+ * Error when too many requests are made in a short period of time.
3010
+ */
3011
+ const ZOHO_TOO_MANY_REQUESTS_ERROR_CODE = 'TOO_MANY_REQUESTS';
3012
+
3013
+ /**
3014
+ * The status code that Zoho uses to indicates that too many requests have been made in a short period of time.
3015
+ */
3016
+ const ZOHO_TOO_MANY_REQUESTS_HTTP_STATUS_CODE = 429;
3017
+ const ZOHO_RATE_LIMIT_LIMIT_HEADER = 'X-RATELIMIT-LIMIT';
3018
+ const ZOHO_RATE_LIMIT_REMAINING_HEADER = 'X-RATELIMIT-REMAINING';
3019
+ const ZOHO_RATE_LIMIT_RESET_HEADER = 'X-RATELIMIT-RESET';
3020
+ const DEFAULT_ZOHO_API_RATE_LIMIT = 100;
3021
+ const DEFAULT_ZOHO_API_RATE_LIMIT_RESET_PERIOD = MS_IN_MINUTE;
3022
+ function zohoRateLimitHeaderDetails(headers) {
3023
+ const limitHeader = headers.has(ZOHO_RATE_LIMIT_REMAINING_HEADER);
3024
+ const remainingHeader = headers.get(ZOHO_RATE_LIMIT_REMAINING_HEADER);
3025
+ const resetHeader = headers.get(ZOHO_RATE_LIMIT_RESET_HEADER);
3026
+ let result = null;
3027
+ if (limitHeader != null && remainingHeader != null && resetHeader != null) {
3028
+ const limit = Number(limitHeader);
3029
+ const remaining = Number(remainingHeader);
3030
+ const reset = Number(resetHeader);
3031
+ const resetAt = new Date(reset);
3032
+ result = {
3033
+ limit,
3034
+ remaining,
3035
+ reset,
3036
+ resetAt
3037
+ };
3038
+ }
3039
+ return result;
3040
+ }
3041
+ class ZohoTooManyRequestsError extends ZohoServerFetchResponseError {
3042
+ get headerDetails() {
3043
+ return zohoRateLimitHeaderDetails(this.responseError.response.headers);
3044
+ }
3045
+ }
3046
+
3008
3047
  /**
3009
3048
  * Function that parses/transforms a ZohoServerErrorResponseData into a general ZohoServerError or other known error type.
3010
3049
  *
@@ -3027,6 +3066,9 @@ function parseZohoServerErrorResponseData(errorResponseData, responseError) {
3027
3066
  case ZOHO_INVALID_QUERY_ERROR_CODE:
3028
3067
  result = new ZohoInvalidQueryError(errorData, responseError);
3029
3068
  break;
3069
+ case ZOHO_TOO_MANY_REQUESTS_ERROR_CODE:
3070
+ result = new ZohoTooManyRequestsError(errorData, responseError);
3071
+ break;
3030
3072
  default:
3031
3073
  result = new ZohoServerFetchResponseError(errorData, responseError);
3032
3074
  break;
@@ -3500,14 +3542,62 @@ function zohoAccessTokenStringFactory(zohoAccessTokenFactory) {
3500
3542
  };
3501
3543
  }
3502
3544
 
3545
+ function zohoRateLimitedFetchHandler(config) {
3546
+ var _config$maxRateLimit, _config$resetPeriod;
3547
+ const defaultLimit = (_config$maxRateLimit = config == null ? void 0 : config.maxRateLimit) != null ? _config$maxRateLimit : DEFAULT_ZOHO_API_RATE_LIMIT;
3548
+ const defaultResetPeriod = (_config$resetPeriod = config == null ? void 0 : config.resetPeriod) != null ? _config$resetPeriod : DEFAULT_ZOHO_API_RATE_LIMIT_RESET_PERIOD;
3549
+ function configForLimit(limit, resetAt) {
3550
+ return {
3551
+ limit: defaultLimit,
3552
+ cooldownRate: limit / (defaultResetPeriod / MS_IN_SECOND),
3553
+ exponentRate: 1.12,
3554
+ maxWaitTime: MS_IN_SECOND * 10,
3555
+ resetPeriod: defaultResetPeriod
3556
+ };
3557
+ }
3558
+ const defaultConfig = configForLimit(defaultLimit);
3559
+ const rateLimiter = resetPeriodPromiseRateLimiter(defaultConfig);
3560
+ return rateLimitedFetchHandler({
3561
+ rateLimiter,
3562
+ updateWithResponse: function (response, fetchResponseError) {
3563
+ const hasLimitHeader = response.headers.has(ZOHO_RATE_LIMIT_REMAINING_HEADER);
3564
+ let shouldRetry = false;
3565
+ let enabled = false;
3566
+ if (hasLimitHeader) {
3567
+ const headerDetails = zohoRateLimitHeaderDetails(response.headers);
3568
+ if (headerDetails) {
3569
+ const {
3570
+ limit,
3571
+ resetAt,
3572
+ remaining
3573
+ } = headerDetails;
3574
+ if (limit !== defaultLimit) {
3575
+ const newConfig = configForLimit(limit);
3576
+ rateLimiter.setConfig(newConfig, false);
3577
+ }
3578
+ rateLimiter.setRemainingLimit(remaining);
3579
+ rateLimiter.setNextResetAt(resetAt);
3580
+ enabled = true;
3581
+
3582
+ // only retry if it's a TOO MANY REQUESTS error
3583
+ shouldRetry = response.status === ZOHO_TOO_MANY_REQUESTS_HTTP_STATUS_CODE;
3584
+ }
3585
+ }
3586
+ rateLimiter.setEnabled(enabled);
3587
+ return shouldRetry;
3588
+ }
3589
+ });
3590
+ }
3591
+
3503
3592
  function zohoRecruitFactory(factoryConfig) {
3504
3593
  const {
3505
3594
  accountsContext
3506
3595
  } = factoryConfig;
3507
3596
  const accessTokenStringFactory = zohoAccessTokenStringFactory(accountsContext.loadAccessToken);
3597
+ const fetchHandler = zohoRateLimitedFetchHandler(factoryConfig.rateLimiterConfig);
3508
3598
  const {
3509
3599
  logZohoServerErrorFunction,
3510
- fetchFactory = input => nodeFetchService.makeFetch({
3600
+ fetchFactory = input => fetchApiFetchService.makeFetch({
3511
3601
  baseUrl: input.apiUrl,
3512
3602
  baseRequest: async () => ({
3513
3603
  headers: {
@@ -3515,6 +3605,7 @@ function zohoRecruitFactory(factoryConfig) {
3515
3605
  Authorization: `Bearer ${await accessTokenStringFactory()}`
3516
3606
  }
3517
3607
  }),
3608
+ fetchHandler,
3518
3609
  timeout: 20 * 1000,
3519
3610
  // 20 second timeout
3520
3611
  requireOkResponse: true,
@@ -3541,7 +3632,8 @@ function zohoRecruitFactory(factoryConfig) {
3541
3632
  fetchJson,
3542
3633
  config: Object.assign({}, config, {
3543
3634
  apiUrl
3544
- })
3635
+ }),
3636
+ zohoRateLimiter: fetchHandler._rateLimiter
3545
3637
  };
3546
3638
  const zohoRecruit = {
3547
3639
  recruitContext
@@ -3596,15 +3688,17 @@ function zohoAccountsConfigApiUrl(input) {
3596
3688
  */
3597
3689
 
3598
3690
  function zohoAccountsFactory(factoryConfig) {
3691
+ const fetchHandler = zohoRateLimitedFetchHandler();
3599
3692
  const {
3600
3693
  logZohoServerErrorFunction,
3601
- fetchFactory = input => nodeFetchService.makeFetch({
3694
+ fetchFactory = input => fetchApiFetchService.makeFetch({
3602
3695
  baseUrl: input.apiUrl,
3603
3696
  baseRequest: {
3604
3697
  headers: {
3605
3698
  'Content-Type': 'application/json'
3606
3699
  }
3607
3700
  },
3701
+ fetchHandler,
3608
3702
  timeout: 20 * 1000,
3609
3703
  // 20 second timeout
3610
3704
  requireOkResponse: true,
@@ -3721,4 +3815,4 @@ function zohoAccountsZohoAccessTokenFactory(config) {
3721
3815
  };
3722
3816
  }
3723
3817
 
3724
- export { ZOHO_ACCOUNTS_INVALID_CLIENT_ERROR_CODE, ZOHO_ACCOUNTS_INVALID_CODE_ERROR_CODE, ZOHO_ACCOUNTS_US_API_URL, ZOHO_DUPLICATE_DATA_ERROR_CODE, ZOHO_INTERNAL_ERROR_CODE, ZOHO_INVALID_AUTHORIZATION_ERROR_CODE, ZOHO_INVALID_DATA_ERROR_CODE, ZOHO_INVALID_QUERY_ERROR_CODE, ZOHO_MANDATORY_NOT_FOUND_ERROR_CODE, ZOHO_RECRUIT_CANDIDATES_MODULE, ZOHO_RECRUIT_SERVICE_NAME, ZOHO_SUCCESS_CODE, ZohoAccountsAccessTokenError, ZohoAccountsAuthFailureError, ZohoInternalError, ZohoInvalidAuthorizationError, ZohoInvalidQueryError, ZohoRecruitRecordCrudDuplicateDataError, ZohoRecruitRecordCrudError, ZohoRecruitRecordCrudInvalidDataError, ZohoRecruitRecordCrudMandatoryFieldNotFoundError, ZohoRecruitRecordCrudNoMatchingRecordError, ZohoRecruitRecordNoContentError, ZohoServerError, ZohoServerFetchResponseError, accessToken, assertRecordDataArrayResultHasContent, createNotes, createNotesForRecord, deleteNotes, escapeZohoFieldValueForCriteriaString, getNotesForRecord, getNotesForRecordPageFactory, getRecordById, getRecords, handleZohoAccountsErrorFetch, handleZohoErrorFetchFactory, handleZohoRecruitErrorFetch, insertRecord, interceptZohoAccountsErrorResponse, interceptZohoErrorResponseFactory, interceptZohoRecruitErrorResponse, isZohoRecruitValidUrl, logZohoAccountsErrorToConsole, logZohoRecruitErrorToConsole, logZohoServerErrorFunction, parseZohoAccountsError, parseZohoAccountsServerErrorResponseData, parseZohoRecruitError, parseZohoRecruitServerErrorResponseData, parseZohoServerErrorResponseData, searchRecords, searchRecordsPageFactory, tryFindZohoServerErrorData, updateRecord, upsertRecord, zohoAccessTokenStringFactory, zohoAccountsApiFetchJsonInput, zohoAccountsConfigApiUrl, zohoAccountsFactory, zohoAccountsZohoAccessTokenFactory, zohoFetchPageFactory, zohoRecruitApiFetchJsonInput, zohoRecruitConfigApiUrl, zohoRecruitFactory, zohoRecruitMultiRecordResult, zohoRecruitRecordCrudError, zohoRecruitSearchRecordsCriteriaEntryToCriteriaString, zohoRecruitSearchRecordsCriteriaString, zohoRecruitSearchRecordsCriteriaStringForTree, zohoRecruitUrlSearchParams, zohoRecruitUrlSearchParamsMinusIdAndModule, zohoRecruitUrlSearchParamsMinusModule, zohoServerErrorData };
3818
+ export { DEFAULT_ZOHO_API_RATE_LIMIT, DEFAULT_ZOHO_API_RATE_LIMIT_RESET_PERIOD, ZOHO_ACCOUNTS_INVALID_CLIENT_ERROR_CODE, ZOHO_ACCOUNTS_INVALID_CODE_ERROR_CODE, ZOHO_ACCOUNTS_US_API_URL, ZOHO_DUPLICATE_DATA_ERROR_CODE, ZOHO_INTERNAL_ERROR_CODE, ZOHO_INVALID_AUTHORIZATION_ERROR_CODE, ZOHO_INVALID_DATA_ERROR_CODE, ZOHO_INVALID_QUERY_ERROR_CODE, ZOHO_MANDATORY_NOT_FOUND_ERROR_CODE, ZOHO_RATE_LIMIT_LIMIT_HEADER, ZOHO_RATE_LIMIT_REMAINING_HEADER, ZOHO_RATE_LIMIT_RESET_HEADER, ZOHO_RECRUIT_CANDIDATES_MODULE, ZOHO_RECRUIT_SERVICE_NAME, ZOHO_SUCCESS_CODE, ZOHO_TOO_MANY_REQUESTS_ERROR_CODE, ZOHO_TOO_MANY_REQUESTS_HTTP_STATUS_CODE, ZohoAccountsAccessTokenError, ZohoAccountsAuthFailureError, ZohoInternalError, ZohoInvalidAuthorizationError, ZohoInvalidQueryError, ZohoRecruitRecordCrudDuplicateDataError, ZohoRecruitRecordCrudError, ZohoRecruitRecordCrudInvalidDataError, ZohoRecruitRecordCrudMandatoryFieldNotFoundError, ZohoRecruitRecordCrudNoMatchingRecordError, ZohoRecruitRecordNoContentError, ZohoServerError, ZohoServerFetchResponseError, ZohoTooManyRequestsError, accessToken, assertRecordDataArrayResultHasContent, createNotes, createNotesForRecord, deleteNotes, escapeZohoFieldValueForCriteriaString, getNotesForRecord, getNotesForRecordPageFactory, getRecordById, getRecords, handleZohoAccountsErrorFetch, handleZohoErrorFetchFactory, handleZohoRecruitErrorFetch, insertRecord, interceptZohoAccountsErrorResponse, interceptZohoErrorResponseFactory, interceptZohoRecruitErrorResponse, isZohoRecruitValidUrl, logZohoAccountsErrorToConsole, logZohoRecruitErrorToConsole, logZohoServerErrorFunction, parseZohoAccountsError, parseZohoAccountsServerErrorResponseData, parseZohoRecruitError, parseZohoRecruitServerErrorResponseData, parseZohoServerErrorResponseData, searchRecords, searchRecordsPageFactory, tryFindZohoServerErrorData, updateRecord, upsertRecord, zohoAccessTokenStringFactory, zohoAccountsApiFetchJsonInput, zohoAccountsConfigApiUrl, zohoAccountsFactory, zohoAccountsZohoAccessTokenFactory, zohoFetchPageFactory, zohoRateLimitHeaderDetails, zohoRateLimitedFetchHandler, zohoRecruitApiFetchJsonInput, zohoRecruitConfigApiUrl, zohoRecruitFactory, zohoRecruitMultiRecordResult, zohoRecruitRecordCrudError, zohoRecruitSearchRecordsCriteriaEntryToCriteriaString, zohoRecruitSearchRecordsCriteriaString, zohoRecruitSearchRecordsCriteriaStringForTree, zohoRecruitUrlSearchParams, zohoRecruitUrlSearchParamsMinusIdAndModule, zohoRecruitUrlSearchParamsMinusModule, zohoServerErrorData };
@@ -2,6 +2,10 @@
2
2
 
3
3
  This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
4
4
 
5
+ ## [11.0.13](https://github.com/dereekb/dbx-components/compare/v11.0.12-dev...v11.0.13) (2024-11-27)
6
+
7
+
8
+
5
9
  ## [11.0.12](https://github.com/dereekb/dbx-components/compare/v11.0.11-dev...v11.0.12) (2024-11-24)
6
10
 
7
11
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/zoho/nestjs",
3
- "version": "11.0.12",
3
+ "version": "11.0.13",
4
4
  "type": "commonjs",
5
5
  "main": "./src/index.js"
6
6
  }
@@ -6,6 +6,7 @@ export declare class ZohoRecruitApi {
6
6
  readonly zohoAccountsApi: ZohoAccountsApi;
7
7
  readonly zohoRecruit: ZohoRecruit;
8
8
  get recruitContext(): ZohoRecruitContext;
9
+ get zohoRateLimiter(): import("../../../../../../dist/packages/util/src").ResetPeriodPromiseRateLimiter;
9
10
  constructor(config: ZohoRecruitServiceConfig, zohoAccountsApi: ZohoAccountsApi);
10
11
  get insertRecord(): import("@dereekb/zoho").ZohoRecruitCreateRecordLikeFunction;
11
12
  get upsertRecord(): import("@dereekb/zoho").ZohoRecruitUpsertRecordLikeFunction;
@@ -13,6 +13,9 @@ let ZohoRecruitApi = exports.ZohoRecruitApi = class ZohoRecruitApi {
13
13
  get recruitContext() {
14
14
  return this.zohoRecruit.recruitContext;
15
15
  }
16
+ get zohoRateLimiter() {
17
+ return this.zohoRecruit.recruitContext.zohoRateLimiter;
18
+ }
16
19
  constructor(config, zohoAccountsApi) {
17
20
  this.config = config;
18
21
  this.zohoAccountsApi = zohoAccountsApi;
@@ -1 +1 @@
1
- {"version":3,"file":"recruit.api.js","sourceRoot":"","sources":["../../../../../../../packages/zoho/nestjs/src/lib/recruit/recruit.api.ts"],"names":[],"mappings":";;;;AAAA,2CAAoD;AACpD,wCAAqQ;AACrQ,qDAA4D;AAC5D,2DAA2D;AAGpD,IAAM,cAAc,4BAApB,MAAM,cAAc;IAO8B;IAAoE;IANlH,WAAW,CAAc;IAElC,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC;IACzC,CAAC;IAED,YAAuD,MAAgC,EAAoC,eAAgC;QAApG,WAAM,GAAN,MAAM,CAA0B;QAAoC,oBAAe,GAAf,eAAe,CAAiB;QACzJ,IAAI,CAAC,WAAW,GAAG,IAAA,yBAAkB,EAAC;YACpC,GAAG,MAAM,CAAC,aAAa;YACvB,eAAe,EAAE,eAAe,CAAC,eAAe;SACjD,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACzB,CAAC;IAED,kBAAkB;IAClB,IAAI,YAAY;QACd,OAAO,IAAA,mBAAY,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAA,mBAAY,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAA,mBAAY,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,aAAa;QACf,OAAO,IAAA,oBAAa,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAA,iBAAU,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,aAAa;QACf,OAAO,IAAA,oBAAa,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,wBAAwB;QAC1B,OAAO,IAAA,+BAAwB,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAA,kBAAW,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAA,kBAAW,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,oBAAoB;QACtB,OAAO,IAAA,2BAAoB,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,iBAAiB;QACnB,OAAO,IAAA,wBAAiB,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAChD,CAAC;CACF,CAAA;yBA1DY,cAAc;IAD1B,IAAA,mBAAU,GAAE;IAQE,mBAAA,IAAA,eAAM,EAAC,yCAAwB,CAAC,CAAA;IAA6C,mBAAA,IAAA,eAAM,EAAC,8BAAe,CAAC,CAAA;6CAAlD,yCAAwB,EAAqD,8BAAe;GAPhJ,cAAc,CA0D1B"}
1
+ {"version":3,"file":"recruit.api.js","sourceRoot":"","sources":["../../../../../../../packages/zoho/nestjs/src/lib/recruit/recruit.api.ts"],"names":[],"mappings":";;;;AAAA,2CAAoD;AACpD,wCAAqQ;AACrQ,qDAA4D;AAC5D,2DAA2D;AAGpD,IAAM,cAAc,4BAApB,MAAM,cAAc;IAW8B;IAAoE;IAVlH,WAAW,CAAc;IAElC,IAAI,cAAc;QAChB,OAAO,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC;IACzC,CAAC;IAED,IAAI,eAAe;QACjB,OAAO,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,eAAe,CAAC;IACzD,CAAC;IAED,YAAuD,MAAgC,EAAoC,eAAgC;QAApG,WAAM,GAAN,MAAM,CAA0B;QAAoC,oBAAe,GAAf,eAAe,CAAiB;QACzJ,IAAI,CAAC,WAAW,GAAG,IAAA,yBAAkB,EAAC;YACpC,GAAG,MAAM,CAAC,aAAa;YACvB,eAAe,EAAE,eAAe,CAAC,eAAe;SACjD,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IACzB,CAAC;IAED,kBAAkB;IAClB,IAAI,YAAY;QACd,OAAO,IAAA,mBAAY,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAA,mBAAY,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAA,mBAAY,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC3C,CAAC;IAED,IAAI,aAAa;QACf,OAAO,IAAA,oBAAa,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAA,iBAAU,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,aAAa;QACf,OAAO,IAAA,oBAAa,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC5C,CAAC;IAED,IAAI,wBAAwB;QAC1B,OAAO,IAAA,+BAAwB,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAA,kBAAW,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAA,kBAAW,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,oBAAoB;QACtB,OAAO,IAAA,2BAAoB,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACnD,CAAC;IAED,IAAI,iBAAiB;QACnB,OAAO,IAAA,wBAAiB,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAChD,CAAC;CACF,CAAA;yBA9DY,cAAc;IAD1B,IAAA,mBAAU,GAAE;IAYE,mBAAA,IAAA,eAAM,EAAC,yCAAwB,CAAC,CAAA;IAA6C,mBAAA,IAAA,eAAM,EAAC,8BAAe,CAAC,CAAA;6CAAlD,yCAAwB,EAAqD,8BAAe;GAXhJ,cAAc,CA8D1B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/zoho",
3
- "version": "11.0.12",
3
+ "version": "11.0.13",
4
4
  "exports": {
5
5
  ".": {
6
6
  "types": "./src/index.d.ts",
@@ -3,4 +3,5 @@ export * from './accounts';
3
3
  export * from './zoho.error.api';
4
4
  export * from './zoho.api.page';
5
5
  export * from './zoho.config';
6
+ export * from './zoho.limit';
6
7
  export * from './zoho.type';
@@ -2,6 +2,7 @@ import { FactoryWithRequiredInput } from '@dereekb/util';
2
2
  import { ConfiguredFetch, FetchJsonFunction } from '@dereekb/util/fetch';
3
3
  import { ZohoApiUrl, ZohoRefreshToken, ZohoApiUrlKey, ZohoConfig, ZohoApiServiceName } from '../zoho.config';
4
4
  import { ZohoServiceAccessTokenKey } from '../accounts';
5
+ import { ZohoRateLimiterRef } from '../zoho.limit';
5
6
  export declare const ZOHO_RECRUIT_SERVICE_NAME: ZohoApiServiceName | ZohoServiceAccessTokenKey;
6
7
  export type ZohoRecruitApiUrl = ZohoApiUrl;
7
8
  export type ZohoRecruitApiKey = ZohoRefreshToken;
@@ -13,7 +14,7 @@ export interface ZohoRecruitFetchFactoryInput {
13
14
  readonly apiUrl: ZohoRecruitApiUrl;
14
15
  }
15
16
  export type ZohoRecruitFetchFactory = FactoryWithRequiredInput<ConfiguredFetch, ZohoRecruitFetchFactoryInput>;
16
- export interface ZohoRecruitContext {
17
+ export interface ZohoRecruitContext extends ZohoRateLimiterRef {
17
18
  readonly fetch: ConfiguredFetch;
18
19
  readonly fetchJson: FetchJsonFunction;
19
20
  readonly config: ZohoRecruitConfig;
@@ -136,7 +136,7 @@ export interface ZohoRecruitSearchRecordsCriteriaTree<T = any> {
136
136
  */
137
137
  readonly or?: Maybe<ZohoRecruitSearchRecordsCriteriaTreeElement<T>[]>;
138
138
  }
139
- export type ZohoRecruitSearchRecordsCriteriaTreeElement<T = any> = ZohoRecruitSearchRecordsCriteriaEntryArray<T> | ZohoRecruitSearchRecordsCriteriaTree | ZohoRecruitSearchRecordsCriteriaString;
139
+ export type ZohoRecruitSearchRecordsCriteriaTreeElement<T = any> = ZohoRecruitSearchRecordsCriteriaEntryArray<T> | ZohoRecruitSearchRecordsCriteriaTree<T> | ZohoRecruitSearchRecordsCriteriaString;
140
140
  export type ZohoRecruitSearchRecordsCriteriaFilterType = 'starts_with' | 'equals' | 'contains';
141
141
  export type ZohoRecruitSearchRecordsCriteriaEntryArray<T = any> = ZohoRecruitSearchRecordsCriteriaEntry<T>[];
142
142
  export interface ZohoRecruitSearchRecordsCriteriaEntry<T = any> {
@@ -1,8 +1,14 @@
1
1
  import { ZohoRecruitConfig, ZohoRecruitContextRef, ZohoRecruitFetchFactory } from './recruit.config';
2
2
  import { LogZohoServerErrorFunction } from '../zoho.error.api';
3
3
  import { ZohoAccountsContextRef } from '../accounts/accounts.config';
4
+ import { ZohoRateLimitedFetchHandlerConfig } from '../zoho.limit';
5
+ import { Maybe } from '@dereekb/util';
4
6
  export type ZohoRecruit = ZohoRecruitContextRef;
5
7
  export interface ZohoRecruitFactoryConfig extends ZohoAccountsContextRef {
8
+ /**
9
+ * Custom ZohoRateLimitedFetchHandlerConfig
10
+ */
11
+ rateLimiterConfig?: Maybe<ZohoRateLimitedFetchHandlerConfig>;
6
12
  /**
7
13
  * Creates a new fetch instance to use when making calls.
8
14
  */
@@ -1,4 +1,4 @@
1
- import { Maybe } from '@dereekb/util';
1
+ import { Maybe, UnixDateTimeNumber } from '@dereekb/util';
2
2
  import { ConfiguredFetch, FetchJsonInterceptJsonResponseFunction, FetchRequestFactoryError, FetchResponseError } from '@dereekb/util/fetch';
3
3
  import { BaseError } from 'make-error';
4
4
  export type ZohoServerErrorResponseDataError = ZohoServerErrorData | ZohoServerErrorCode;
@@ -125,6 +125,41 @@ export declare const ZOHO_DUPLICATE_DATA_ERROR_CODE = "DUPLICATE_DATA";
125
125
  * Error when some passed data is invalid.
126
126
  */
127
127
  export declare const ZOHO_INVALID_DATA_ERROR_CODE = "INVALID_DATA";
128
+ /**
129
+ * Error when too many requests are made in a short period of time.
130
+ */
131
+ export declare const ZOHO_TOO_MANY_REQUESTS_ERROR_CODE = "TOO_MANY_REQUESTS";
132
+ /**
133
+ * The status code that Zoho uses to indicates that too many requests have been made in a short period of time.
134
+ */
135
+ export declare const ZOHO_TOO_MANY_REQUESTS_HTTP_STATUS_CODE = 429;
136
+ export declare const ZOHO_RATE_LIMIT_LIMIT_HEADER = "X-RATELIMIT-LIMIT";
137
+ export declare const ZOHO_RATE_LIMIT_REMAINING_HEADER = "X-RATELIMIT-REMAINING";
138
+ export declare const ZOHO_RATE_LIMIT_RESET_HEADER = "X-RATELIMIT-RESET";
139
+ export declare const DEFAULT_ZOHO_API_RATE_LIMIT = 100;
140
+ export declare const DEFAULT_ZOHO_API_RATE_LIMIT_RESET_PERIOD: number;
141
+ export interface ZohoRateLimitHeaderDetails {
142
+ /**
143
+ * Total limit in a given period.
144
+ */
145
+ readonly limit: number;
146
+ /**
147
+ * Total number of remaining allowed requests.
148
+ */
149
+ readonly remaining: number;
150
+ /**
151
+ * The time at which the rate limit will reset.
152
+ */
153
+ readonly reset: UnixDateTimeNumber;
154
+ /**
155
+ * The time at which the rate limit will reset.
156
+ */
157
+ readonly resetAt: Date;
158
+ }
159
+ export declare function zohoRateLimitHeaderDetails(headers: Headers): Maybe<ZohoRateLimitHeaderDetails>;
160
+ export declare class ZohoTooManyRequestsError extends ZohoServerFetchResponseError {
161
+ get headerDetails(): Maybe<ZohoRateLimitHeaderDetails>;
162
+ }
128
163
  /**
129
164
  * Function that parses/transforms a ZohoServerErrorResponseData into a general ZohoServerError or other known error type.
130
165
  *
@@ -0,0 +1,23 @@
1
+ import { Maybe, Milliseconds, ResetPeriodPromiseRateLimiter } from '@dereekb/util';
2
+ import { RateLimitedFetchHandler } from '@dereekb/util/fetch';
3
+ export interface ZohoRateLimiterRef {
4
+ readonly zohoRateLimiter: ResetPeriodPromiseRateLimiter;
5
+ }
6
+ export interface ZohoRateLimitedFetchHandlerConfig {
7
+ /**
8
+ * Custom max rate limit.
9
+ *
10
+ * Rate limits are different between account types and are described here:
11
+ *
12
+ * https://help.zoho.com/portal/en/community/topic/key-changes-in-api-limits-26-9-2018#:~:text=X%2DRATELIMIT%2DREMAINING%20%2D%20Represents,time%20of%20the%20current%20window.&text=Please%20note%20that%20these%20Rate,API%20limit%20changes%20are%20implemented.
13
+ */
14
+ readonly maxRateLimit?: number;
15
+ /**
16
+ * Custom reset period for the rate limiter.
17
+ *
18
+ * Defaults to 1 minute in milliseconds.
19
+ */
20
+ readonly resetPeriod?: Milliseconds;
21
+ }
22
+ export type ZohoRateLimitedFetchHandler = RateLimitedFetchHandler<ResetPeriodPromiseRateLimiter>;
23
+ export declare function zohoRateLimitedFetchHandler(config?: Maybe<ZohoRateLimitedFetchHandlerConfig>): ZohoRateLimitedFetchHandler;