@gitbeaker/requester-utils 39.18.0 → 39.20.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/dist/index.d.mts +18 -3
- package/dist/index.d.ts +18 -3
- package/dist/index.js +73 -3
- package/dist/index.mjs +68 -4
- package/package.json +4 -2
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
|
-
|
|
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
|
-
|
|
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.
|
|
3
|
+
"version": "39.20.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": "
|
|
64
|
+
"gitHead": "ec94930b7b5fd79d6afe88af882725a6a7c3bfa5"
|
|
63
65
|
}
|