@gitbeaker/requester-utils 39.17.0 → 39.19.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.
package/README.md CHANGED
@@ -73,7 +73,7 @@
73
73
 
74
74
  - [Usage](#usage)
75
75
  - [Testing](../../docs/TESTING.md)
76
- - [FAQ](../../FAQ.md)
76
+ - [FAQ](../../docs/FAQ.md)
77
77
  - [Contributors](#contributors)
78
78
  - [Changelog](./CHANGELOG.md)
79
79
 
@@ -230,6 +230,7 @@ import { RequesterUtils, BaseResource } from '@gitbeaker/requester-utils';
230
230
  <td align="center" valign="top" width="3.84%"><a href="https://github.com/demedos"><img src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/16702156?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt="Alessandro Diez"/></td>
231
231
  <td align="center" valign="top" width="3.84%"><a href="https://github.com/artlist-scottambrose"><img src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/124692101?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt="artlist-scottambrose"/></td>
232
232
  <td align="center" valign="top" width="3.84%"><a href="https://github.com/mercutiodesign"><img src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/1114120?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt="Martin Dreher"/></td>
233
+ <td align="center" valign="top" width="3.84%"><a href="https://github.com/glensc"><img src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/199095?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt="Elan Ruusamäe"/></td>
233
234
  </tr>
234
235
  </p>
235
236
 
package/dist/index.d.mts CHANGED
@@ -1,3 +1,13 @@
1
+ import { RateLimit } from 'async-sema';
2
+
3
+ type RateLimiters = Record<string, ReturnType<typeof RateLimit> | {
4
+ method: string;
5
+ limit: ReturnType<typeof RateLimit>;
6
+ }>;
7
+ type RateLimitOptions = Record<string, number | {
8
+ method: string;
9
+ limit: number;
10
+ }>;
1
11
  type ResponseBodyTypes = Record<string, unknown> | Record<string, unknown>[] | ReadableStream | Blob | string | string[] | number | void | null;
2
12
  interface FormattedResponse<T extends ResponseBodyTypes = ResponseBodyTypes> {
3
13
  body: T;
@@ -16,6 +26,7 @@ type ResourceOptions = {
16
26
  };
17
27
  url: string;
18
28
  rejectUnauthorized: boolean;
29
+ rateLimits?: RateLimitOptions;
19
30
  };
20
31
  type DefaultRequestOptions = {
21
32
  body?: FormData | Record<string, unknown>;
@@ -34,6 +45,7 @@ type RequestOptions = {
34
45
  body?: string | FormData;
35
46
  asStream?: boolean;
36
47
  signal?: AbortSignal;
48
+ rateLimiters?: Record<string, ReturnType<typeof RateLimit>>;
37
49
  };
38
50
  interface RequesterType {
39
51
  get<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
@@ -42,12 +54,14 @@ interface RequesterType {
42
54
  patch<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
43
55
  delete<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
44
56
  }
57
+ type RequestHandlerFn<T extends ResponseBodyTypes = ResponseBodyTypes> = (endpoint: string, options?: Record<string, unknown>) => Promise<FormattedResponse<T>>;
45
58
  declare function formatQuery(params?: Record<string, unknown>): string;
46
59
  type OptionsHandlerFn = (serviceOptions: ResourceOptions, requestOptions: RequestOptions) => Promise<RequestOptions>;
47
60
  declare function defaultOptionsHandler(resourceOptions: ResourceOptions, { body, searchParams, sudo, signal, asStream, method, }?: DefaultRequestOptions): Promise<RequestOptions>;
48
- type RequestHandlerFn<T extends ResponseBodyTypes = ResponseBodyTypes> = (endpoint: string, options?: Record<string, unknown>) => Promise<FormattedResponse<T>>;
61
+ declare function createRateLimiters(rateLimitOptions?: RateLimitOptions): RateLimiters;
49
62
  declare function createRequesterFn(optionsHandler: OptionsHandlerFn, requestHandler: RequestHandlerFn): (serviceOptions: ResourceOptions) => RequesterType;
50
63
  declare function presetResourceArguments<T extends Record<string, Constructable>>(resources: T, customConfig?: Record<string, unknown>): T;
64
+ declare function getMatchingRateLimiter(endpoint: string, rateLimiters?: RateLimiters, method?: string): () => Promise<void>;
51
65
 
52
66
  interface RootResourceOptions<C> {
53
67
  requesterFn?: (resourceOptions: ResourceOptions) => RequesterType;
@@ -59,6 +73,7 @@ interface RootResourceOptions<C> {
59
73
  sudo?: string | number;
60
74
  profileToken?: string;
61
75
  profileMode?: 'execution' | 'memory';
76
+ rateLimits?: RateLimitOptions;
62
77
  }
63
78
  type GitlabToken = string | (() => Promise<string>);
64
79
  interface BaseRequestOptionsWithOAuthToken<C> extends RootResourceOptions<C> {
@@ -83,7 +98,7 @@ declare class BaseResource<C extends boolean = false> {
83
98
  };
84
99
  readonly camelize: C | undefined;
85
100
  readonly rejectUnauthorized: boolean;
86
- constructor({ sudo, profileToken, camelize, requesterFn, profileMode, host, prefixUrl, rejectUnauthorized, queryTimeout, ...tokens }: BaseResourceOptions<C>);
101
+ constructor({ sudo, profileToken, camelize, requesterFn, profileMode, host, prefixUrl, rejectUnauthorized, queryTimeout, rateLimits, ...tokens }: BaseResourceOptions<C>);
87
102
  }
88
103
 
89
- export { BaseRequestOptionsWithAccessToken, BaseRequestOptionsWithJobToken, BaseRequestOptionsWithOAuthToken, BaseResource, BaseResourceOptions, Constructable, DefaultRequestOptions, FormattedResponse, GitlabToken, OptionsHandlerFn, RequestHandlerFn, RequestOptions, RequesterType, ResourceOptions, ResponseBodyTypes, RootResourceOptions, createRequesterFn, defaultOptionsHandler, formatQuery, presetResourceArguments };
104
+ export { BaseRequestOptionsWithAccessToken, BaseRequestOptionsWithJobToken, BaseRequestOptionsWithOAuthToken, BaseResource, BaseResourceOptions, Constructable, DefaultRequestOptions, FormattedResponse, GitlabToken, OptionsHandlerFn, RateLimitOptions, RateLimiters, RequestHandlerFn, RequestOptions, RequesterType, ResourceOptions, ResponseBodyTypes, RootResourceOptions, createRateLimiters, createRequesterFn, defaultOptionsHandler, formatQuery, getMatchingRateLimiter, presetResourceArguments };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,13 @@
1
+ import { RateLimit } from 'async-sema';
2
+
3
+ type RateLimiters = Record<string, ReturnType<typeof RateLimit> | {
4
+ method: string;
5
+ limit: ReturnType<typeof RateLimit>;
6
+ }>;
7
+ type RateLimitOptions = Record<string, number | {
8
+ method: string;
9
+ limit: number;
10
+ }>;
1
11
  type ResponseBodyTypes = Record<string, unknown> | Record<string, unknown>[] | ReadableStream | Blob | string | string[] | number | void | null;
2
12
  interface FormattedResponse<T extends ResponseBodyTypes = ResponseBodyTypes> {
3
13
  body: T;
@@ -16,6 +26,7 @@ type ResourceOptions = {
16
26
  };
17
27
  url: string;
18
28
  rejectUnauthorized: boolean;
29
+ rateLimits?: RateLimitOptions;
19
30
  };
20
31
  type DefaultRequestOptions = {
21
32
  body?: FormData | Record<string, unknown>;
@@ -34,6 +45,7 @@ type RequestOptions = {
34
45
  body?: string | FormData;
35
46
  asStream?: boolean;
36
47
  signal?: AbortSignal;
48
+ rateLimiters?: Record<string, ReturnType<typeof RateLimit>>;
37
49
  };
38
50
  interface RequesterType {
39
51
  get<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
@@ -42,12 +54,14 @@ interface RequesterType {
42
54
  patch<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
43
55
  delete<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
44
56
  }
57
+ type RequestHandlerFn<T extends ResponseBodyTypes = ResponseBodyTypes> = (endpoint: string, options?: Record<string, unknown>) => Promise<FormattedResponse<T>>;
45
58
  declare function formatQuery(params?: Record<string, unknown>): string;
46
59
  type OptionsHandlerFn = (serviceOptions: ResourceOptions, requestOptions: RequestOptions) => Promise<RequestOptions>;
47
60
  declare function defaultOptionsHandler(resourceOptions: ResourceOptions, { body, searchParams, sudo, signal, asStream, method, }?: DefaultRequestOptions): Promise<RequestOptions>;
48
- type RequestHandlerFn<T extends ResponseBodyTypes = ResponseBodyTypes> = (endpoint: string, options?: Record<string, unknown>) => Promise<FormattedResponse<T>>;
61
+ declare function createRateLimiters(rateLimitOptions?: RateLimitOptions): RateLimiters;
49
62
  declare function createRequesterFn(optionsHandler: OptionsHandlerFn, requestHandler: RequestHandlerFn): (serviceOptions: ResourceOptions) => RequesterType;
50
63
  declare function presetResourceArguments<T extends Record<string, Constructable>>(resources: T, customConfig?: Record<string, unknown>): T;
64
+ declare function getMatchingRateLimiter(endpoint: string, rateLimiters?: RateLimiters, method?: string): () => Promise<void>;
51
65
 
52
66
  interface RootResourceOptions<C> {
53
67
  requesterFn?: (resourceOptions: ResourceOptions) => RequesterType;
@@ -59,6 +73,7 @@ interface RootResourceOptions<C> {
59
73
  sudo?: string | number;
60
74
  profileToken?: string;
61
75
  profileMode?: 'execution' | 'memory';
76
+ rateLimits?: RateLimitOptions;
62
77
  }
63
78
  type GitlabToken = string | (() => Promise<string>);
64
79
  interface BaseRequestOptionsWithOAuthToken<C> extends RootResourceOptions<C> {
@@ -83,7 +98,7 @@ declare class BaseResource<C extends boolean = false> {
83
98
  };
84
99
  readonly camelize: C | undefined;
85
100
  readonly rejectUnauthorized: boolean;
86
- constructor({ sudo, profileToken, camelize, requesterFn, profileMode, host, prefixUrl, rejectUnauthorized, queryTimeout, ...tokens }: BaseResourceOptions<C>);
101
+ constructor({ sudo, profileToken, camelize, requesterFn, profileMode, host, prefixUrl, rejectUnauthorized, queryTimeout, rateLimits, ...tokens }: BaseResourceOptions<C>);
87
102
  }
88
103
 
89
- export { BaseRequestOptionsWithAccessToken, BaseRequestOptionsWithJobToken, BaseRequestOptionsWithOAuthToken, BaseResource, BaseResourceOptions, Constructable, DefaultRequestOptions, FormattedResponse, GitlabToken, OptionsHandlerFn, RequestHandlerFn, RequestOptions, RequesterType, ResourceOptions, ResponseBodyTypes, RootResourceOptions, createRequesterFn, defaultOptionsHandler, formatQuery, presetResourceArguments };
104
+ export { BaseRequestOptionsWithAccessToken, BaseRequestOptionsWithJobToken, BaseRequestOptionsWithOAuthToken, BaseResource, BaseResourceOptions, Constructable, DefaultRequestOptions, FormattedResponse, GitlabToken, OptionsHandlerFn, RateLimitOptions, RateLimiters, RequestHandlerFn, RequestOptions, RequesterType, ResourceOptions, ResponseBodyTypes, RootResourceOptions, createRateLimiters, createRequesterFn, defaultOptionsHandler, formatQuery, getMatchingRateLimiter, presetResourceArguments };
package/dist/index.js CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  var qs = require('qs');
4
4
  var xcase = require('xcase');
5
+ var asyncSema = require('async-sema');
6
+ var micromatch = require('micromatch');
7
+
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ var micromatch__default = /*#__PURE__*/_interopDefault(micromatch);
5
11
 
6
12
  // src/RequesterUtils.ts
7
13
  function formatQuery(params = {}) {
@@ -45,10 +51,24 @@ async function defaultOptionsHandler(resourceOptions, {
45
51
  defaultOptions.searchParams = q;
46
52
  return Promise.resolve(defaultOptions);
47
53
  }
54
+ function createRateLimiters(rateLimitOptions = {}) {
55
+ const rateLimiters = {};
56
+ Object.entries(rateLimitOptions).forEach(([key, config]) => {
57
+ if (typeof config === "number")
58
+ rateLimiters[key] = asyncSema.RateLimit(config, { timeUnit: 6e4 });
59
+ else
60
+ rateLimiters[key] = {
61
+ method: config.method.toUpperCase(),
62
+ limit: asyncSema.RateLimit(config.limit, { timeUnit: 6e4 })
63
+ };
64
+ });
65
+ return rateLimiters;
66
+ }
48
67
  function createRequesterFn(optionsHandler, requestHandler) {
49
68
  const methods = ["get", "post", "put", "patch", "delete"];
50
69
  return (serviceOptions) => {
51
70
  const requester = {};
71
+ const rateLimiters = createRateLimiters(serviceOptions.rateLimits);
52
72
  methods.forEach((m) => {
53
73
  requester[m] = async (endpoint, options) => {
54
74
  const defaultRequestOptions = await defaultOptionsHandler(serviceOptions, {
@@ -56,13 +76,13 @@ function createRequesterFn(optionsHandler, requestHandler) {
56
76
  method: m.toUpperCase()
57
77
  });
58
78
  const requestOptions = await optionsHandler(serviceOptions, defaultRequestOptions);
59
- return requestHandler(endpoint, requestOptions);
79
+ return requestHandler(endpoint, { ...requestOptions, rateLimiters });
60
80
  };
61
81
  });
62
82
  return requester;
63
83
  };
64
84
  }
65
- function extendClass(Base, customConfig = {}) {
85
+ function extendClass(Base, customConfig) {
66
86
  return class extends Base {
67
87
  constructor(...options) {
68
88
  const [config, ...opts] = options;
@@ -77,11 +97,58 @@ function presetResourceArguments(resources, customConfig = {}) {
77
97
  });
78
98
  return updated;
79
99
  }
100
+ function getMatchingRateLimiter(endpoint, rateLimiters = {}, method = "GET") {
101
+ const sortedEndpoints = Object.keys(rateLimiters).sort().reverse();
102
+ const match = sortedEndpoints.find((ep) => micromatch__default.default.isMatch(endpoint, ep));
103
+ const rateLimitConfig = match && rateLimiters[match];
104
+ if (rateLimitConfig && typeof rateLimitConfig !== "object") {
105
+ return rateLimitConfig;
106
+ }
107
+ if (rateLimitConfig && rateLimitConfig.method.toUpperCase() === method.toUpperCase()) {
108
+ return rateLimitConfig.limit;
109
+ }
110
+ return asyncSema.RateLimit(3e3, { timeUnit: 6e4 });
111
+ }
80
112
 
81
113
  // src/BaseResource.ts
82
114
  function getDynamicToken(tokenArgument) {
83
115
  return tokenArgument instanceof Function ? tokenArgument() : Promise.resolve(tokenArgument);
84
116
  }
117
+ var DEFAULT_RATE_LIMITS = Object.freeze({
118
+ // Default rate limit
119
+ "**": 3e3,
120
+ // Import/Export
121
+ "projects/import": 6,
122
+ "projects/*/export": 6,
123
+ "projects/*/download": 1,
124
+ "groups/import": 6,
125
+ "groups/*/export": 6,
126
+ "groups/*/download": 1,
127
+ // Note creation
128
+ "projects/*/issues/*/notes": {
129
+ method: "post",
130
+ limit: 300
131
+ },
132
+ "projects/*/snippets/*/notes": {
133
+ method: "post",
134
+ limit: 300
135
+ },
136
+ "projects/*/merge_requests/*/notes": {
137
+ method: "post",
138
+ limit: 300
139
+ },
140
+ "groups/*/epics/*/notes": {
141
+ method: "post",
142
+ limit: 300
143
+ },
144
+ // Repositories - get file archive
145
+ "projects/*/repository/archive*": 5,
146
+ // Project Jobs
147
+ "projects/*/jobs": 600,
148
+ // Member deletion
149
+ "projects/*/members": 60,
150
+ "groups/*/members": 60
151
+ });
85
152
  var BaseResource = class {
86
153
  url;
87
154
  requester;
@@ -100,6 +167,7 @@ var BaseResource = class {
100
167
  prefixUrl = "",
101
168
  rejectUnauthorized = true,
102
169
  queryTimeout = 3e5,
170
+ rateLimits = DEFAULT_RATE_LIMITS,
103
171
  ...tokens
104
172
  }) {
105
173
  if (!requesterFn)
@@ -128,12 +196,14 @@ var BaseResource = class {
128
196
  }
129
197
  if (sudo)
130
198
  this.headers.Sudo = `${sudo}`;
131
- this.requester = requesterFn({ ...this });
199
+ this.requester = requesterFn({ ...this, rateLimits });
132
200
  }
133
201
  };
134
202
 
135
203
  exports.BaseResource = BaseResource;
204
+ exports.createRateLimiters = createRateLimiters;
136
205
  exports.createRequesterFn = createRequesterFn;
137
206
  exports.defaultOptionsHandler = defaultOptionsHandler;
138
207
  exports.formatQuery = formatQuery;
208
+ exports.getMatchingRateLimiter = getMatchingRateLimiter;
139
209
  exports.presetResourceArguments = presetResourceArguments;
package/dist/index.mjs CHANGED
@@ -1,5 +1,7 @@
1
1
  import { stringify } from 'qs';
2
2
  import { decamelizeKeys } from 'xcase';
3
+ import { RateLimit } from 'async-sema';
4
+ import micromatch from 'micromatch';
3
5
 
4
6
  // src/RequesterUtils.ts
5
7
  function formatQuery(params = {}) {
@@ -43,10 +45,24 @@ async function defaultOptionsHandler(resourceOptions, {
43
45
  defaultOptions.searchParams = q;
44
46
  return Promise.resolve(defaultOptions);
45
47
  }
48
+ function createRateLimiters(rateLimitOptions = {}) {
49
+ const rateLimiters = {};
50
+ Object.entries(rateLimitOptions).forEach(([key, config]) => {
51
+ if (typeof config === "number")
52
+ rateLimiters[key] = RateLimit(config, { timeUnit: 6e4 });
53
+ else
54
+ rateLimiters[key] = {
55
+ method: config.method.toUpperCase(),
56
+ limit: RateLimit(config.limit, { timeUnit: 6e4 })
57
+ };
58
+ });
59
+ return rateLimiters;
60
+ }
46
61
  function createRequesterFn(optionsHandler, requestHandler) {
47
62
  const methods = ["get", "post", "put", "patch", "delete"];
48
63
  return (serviceOptions) => {
49
64
  const requester = {};
65
+ const rateLimiters = createRateLimiters(serviceOptions.rateLimits);
50
66
  methods.forEach((m) => {
51
67
  requester[m] = async (endpoint, options) => {
52
68
  const defaultRequestOptions = await defaultOptionsHandler(serviceOptions, {
@@ -54,13 +70,13 @@ function createRequesterFn(optionsHandler, requestHandler) {
54
70
  method: m.toUpperCase()
55
71
  });
56
72
  const requestOptions = await optionsHandler(serviceOptions, defaultRequestOptions);
57
- return requestHandler(endpoint, requestOptions);
73
+ return requestHandler(endpoint, { ...requestOptions, rateLimiters });
58
74
  };
59
75
  });
60
76
  return requester;
61
77
  };
62
78
  }
63
- function extendClass(Base, customConfig = {}) {
79
+ function extendClass(Base, customConfig) {
64
80
  return class extends Base {
65
81
  constructor(...options) {
66
82
  const [config, ...opts] = options;
@@ -75,11 +91,58 @@ function presetResourceArguments(resources, customConfig = {}) {
75
91
  });
76
92
  return updated;
77
93
  }
94
+ function getMatchingRateLimiter(endpoint, rateLimiters = {}, method = "GET") {
95
+ const sortedEndpoints = Object.keys(rateLimiters).sort().reverse();
96
+ const match = sortedEndpoints.find((ep) => micromatch.isMatch(endpoint, ep));
97
+ const rateLimitConfig = match && rateLimiters[match];
98
+ if (rateLimitConfig && typeof rateLimitConfig !== "object") {
99
+ return rateLimitConfig;
100
+ }
101
+ if (rateLimitConfig && rateLimitConfig.method.toUpperCase() === method.toUpperCase()) {
102
+ return rateLimitConfig.limit;
103
+ }
104
+ return RateLimit(3e3, { timeUnit: 6e4 });
105
+ }
78
106
 
79
107
  // src/BaseResource.ts
80
108
  function getDynamicToken(tokenArgument) {
81
109
  return tokenArgument instanceof Function ? tokenArgument() : Promise.resolve(tokenArgument);
82
110
  }
111
+ var DEFAULT_RATE_LIMITS = Object.freeze({
112
+ // Default rate limit
113
+ "**": 3e3,
114
+ // Import/Export
115
+ "projects/import": 6,
116
+ "projects/*/export": 6,
117
+ "projects/*/download": 1,
118
+ "groups/import": 6,
119
+ "groups/*/export": 6,
120
+ "groups/*/download": 1,
121
+ // Note creation
122
+ "projects/*/issues/*/notes": {
123
+ method: "post",
124
+ limit: 300
125
+ },
126
+ "projects/*/snippets/*/notes": {
127
+ method: "post",
128
+ limit: 300
129
+ },
130
+ "projects/*/merge_requests/*/notes": {
131
+ method: "post",
132
+ limit: 300
133
+ },
134
+ "groups/*/epics/*/notes": {
135
+ method: "post",
136
+ limit: 300
137
+ },
138
+ // Repositories - get file archive
139
+ "projects/*/repository/archive*": 5,
140
+ // Project Jobs
141
+ "projects/*/jobs": 600,
142
+ // Member deletion
143
+ "projects/*/members": 60,
144
+ "groups/*/members": 60
145
+ });
83
146
  var BaseResource = class {
84
147
  url;
85
148
  requester;
@@ -98,6 +161,7 @@ var BaseResource = class {
98
161
  prefixUrl = "",
99
162
  rejectUnauthorized = true,
100
163
  queryTimeout = 3e5,
164
+ rateLimits = DEFAULT_RATE_LIMITS,
101
165
  ...tokens
102
166
  }) {
103
167
  if (!requesterFn)
@@ -126,8 +190,8 @@ var BaseResource = class {
126
190
  }
127
191
  if (sudo)
128
192
  this.headers.Sudo = `${sudo}`;
129
- this.requester = requesterFn({ ...this });
193
+ this.requester = requesterFn({ ...this, rateLimits });
130
194
  }
131
195
  };
132
196
 
133
- export { BaseResource, createRequesterFn, defaultOptionsHandler, formatQuery, presetResourceArguments };
197
+ export { BaseResource, createRateLimiters, createRequesterFn, defaultOptionsHandler, formatQuery, getMatchingRateLimiter, presetResourceArguments };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitbeaker/requester-utils",
3
- "version": "39.17.0",
3
+ "version": "39.19.0",
4
4
  "description": "Utility functions for requester implementatons used in @gitbeaker",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -51,6 +51,8 @@
51
51
  "release": "auto shipit"
52
52
  },
53
53
  "dependencies": {
54
+ "async-sema": "^3.1.1",
55
+ "micromatch": "^4.0.5",
54
56
  "qs": "^6.11.2",
55
57
  "xcase": "^2.0.1"
56
58
  },
@@ -59,5 +61,5 @@
59
61
  "tsup": "^7.1.0",
60
62
  "typescript": "^5.1.6"
61
63
  },
62
- "gitHead": "604085015c962cdcbe542b96d717d64d2051ca3c"
64
+ "gitHead": "b6ac7ead7ee50ced0f99f66ea0c212d2afcba3c2"
63
65
  }