@gitbeaker/requester-utils 39.33.0 → 39.33.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitbeaker/requester-utils",
3
- "version": "39.33.0",
3
+ "version": "39.33.1",
4
4
  "description": "Utility functions for requester implementatons used in @gitbeaker",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -43,17 +43,8 @@
43
43
  "test:types": "tsc",
44
44
  "test:integration": "jest --maxWorkers=50% test/integration",
45
45
  "test:unit": "jest --maxWorkers=50% test/unit",
46
- "format:docs": "prettier '**/(*.json|.yml|.js|.md)' --ignore-path ../../.prettierignore",
47
- "format:docs:fix": "yarn format:docs --write",
48
- "format:src": "prettier '{src,test}/**/*.ts' --ignore-path ../../.prettierignore",
49
- "format:src:fix": "yarn format:src --write",
50
- "format": "yarn format:src && yarn format:docs",
51
- "format:fix": "yarn format:src:fix && yarn format:docs:fix",
52
- "lint": "eslint '{src,test}/**/*.ts'",
53
- "lint:fix": "yarn lint --fix",
54
- "release:rc": "auto next",
55
- "release:canary": "auto canary",
56
- "release": "auto shipit"
46
+ "lint": "eslint '**/{src,test,scripts}/**/*.ts'",
47
+ "lint:fix": "yarn lint --fix"
57
48
  },
58
49
  "dependencies": {
59
50
  "picomatch-browser": "^2.2.6",
@@ -66,5 +57,5 @@
66
57
  "tsup": "^8.0.1",
67
58
  "typescript": "^5.3.3"
68
59
  },
69
- "gitHead": "e76b91bdab64ea71a8819e15d5edcb066586121d"
60
+ "gitHead": "f34db265145f4914f79bf338db3cca0aa6cef0aa"
70
61
  }
package/dist/index.d.mts DELETED
@@ -1,125 +0,0 @@
1
- type RateLimiterFn = () => Promise<number>;
2
- type RateLimiters = Record<string, RateLimiterFn | {
3
- method: string;
4
- limit: RateLimiterFn;
5
- }>;
6
- type RateLimitOptions = Record<string, number | {
7
- method: string;
8
- limit: number;
9
- }>;
10
- type ResponseBodyTypes = Record<string, unknown> | Record<string, unknown>[] | ReadableStream | Blob | string | string[] | number | void | null;
11
- interface FormattedResponse<T extends ResponseBodyTypes = ResponseBodyTypes> {
12
- body: T;
13
- headers: Record<string, string>;
14
- status: number;
15
- }
16
- interface Constructable<T = any> {
17
- new (...args: any[]): T;
18
- }
19
- type ResourceOptions = {
20
- headers: {
21
- [header: string]: string;
22
- };
23
- authHeaders: {
24
- [authHeader: string]: () => Promise<string>;
25
- };
26
- url: string;
27
- rejectUnauthorized: boolean;
28
- rateLimits?: RateLimitOptions;
29
- };
30
- type DefaultRequestOptions = {
31
- body?: FormData | Record<string, unknown>;
32
- searchParams?: Record<string, unknown>;
33
- sudo?: string | number;
34
- method?: string;
35
- asStream?: boolean;
36
- signal?: AbortSignal;
37
- };
38
- type RequestOptions = {
39
- headers?: Record<string, string>;
40
- timeout?: number;
41
- method?: string;
42
- searchParams?: string;
43
- prefixUrl?: string;
44
- body?: string | FormData;
45
- asStream?: boolean;
46
- signal?: AbortSignal;
47
- rateLimiters?: Record<string, RateLimiterFn>;
48
- };
49
- interface RequesterType {
50
- get<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
51
- post<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
52
- put<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
53
- patch<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
54
- delete<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
55
- }
56
- type RequestHandlerFn<T extends ResponseBodyTypes = ResponseBodyTypes> = (endpoint: string, options?: Record<string, unknown>) => Promise<FormattedResponse<T>>;
57
- declare function generateRateLimiterFn(limit: number, interval: number): () => Promise<number>;
58
- declare function formatQuery(params?: Record<string, unknown>): string;
59
- type OptionsHandlerFn = (serviceOptions: ResourceOptions, requestOptions: RequestOptions) => Promise<RequestOptions>;
60
- declare function defaultOptionsHandler(resourceOptions: ResourceOptions, { body, searchParams, sudo, signal, asStream, method, }?: DefaultRequestOptions): Promise<RequestOptions>;
61
- declare function createRateLimiters(rateLimitOptions?: RateLimitOptions): RateLimiters;
62
- declare function createRequesterFn(optionsHandler: OptionsHandlerFn, requestHandler: RequestHandlerFn): (serviceOptions: ResourceOptions) => RequesterType;
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): RateLimiterFn;
65
-
66
- interface RootResourceOptions<C> {
67
- requesterFn?: (resourceOptions: ResourceOptions) => RequesterType;
68
- host?: string;
69
- prefixUrl?: string;
70
- rejectUnauthorized?: boolean;
71
- camelize?: C;
72
- queryTimeout?: number | null;
73
- sudo?: string | number;
74
- profileToken?: string;
75
- profileMode?: 'execution' | 'memory';
76
- rateLimits?: RateLimitOptions;
77
- }
78
- type GitlabToken = string | (() => Promise<string>);
79
- interface BaseRequestOptionsWithOAuthToken<C> extends RootResourceOptions<C> {
80
- oauthToken: GitlabToken;
81
- }
82
- interface BaseRequestOptionsWithAccessToken<C> extends RootResourceOptions<C> {
83
- token: GitlabToken;
84
- }
85
- interface BaseRequestOptionsWithJobToken<C> extends RootResourceOptions<C> {
86
- jobToken: GitlabToken;
87
- }
88
- type BaseResourceOptions<C> = BaseRequestOptionsWithOAuthToken<C> | BaseRequestOptionsWithAccessToken<C> | BaseRequestOptionsWithJobToken<C>;
89
- declare class BaseResource<C extends boolean = false> {
90
- readonly url: string;
91
- readonly requester: RequesterType;
92
- readonly queryTimeout: number | null;
93
- readonly headers: {
94
- [header: string]: string;
95
- };
96
- readonly authHeaders: {
97
- [authHeader: string]: () => Promise<string>;
98
- };
99
- readonly camelize: C | undefined;
100
- readonly rejectUnauthorized: boolean;
101
- constructor({ sudo, profileToken, camelize, requesterFn, profileMode, host, prefixUrl, rejectUnauthorized, queryTimeout, rateLimits, ...tokens }: BaseResourceOptions<C>);
102
- }
103
-
104
- declare class GitbeakerRequestError extends Error {
105
- readonly cause?: {
106
- description: string;
107
- request: Request;
108
- response: Response;
109
- };
110
- constructor(message: string, options?: {
111
- cause?: {
112
- description: string;
113
- request: Request;
114
- response: Response;
115
- };
116
- });
117
- }
118
- declare class GitbeakerTimeoutError extends Error {
119
- constructor(message: string, options?: ErrorOptions);
120
- }
121
- declare class GitbeakerRetryError extends Error {
122
- constructor(message: string, options?: ErrorOptions);
123
- }
124
-
125
- export { type BaseRequestOptionsWithAccessToken, type BaseRequestOptionsWithJobToken, type BaseRequestOptionsWithOAuthToken, BaseResource, type BaseResourceOptions, type Constructable, type DefaultRequestOptions, type FormattedResponse, GitbeakerRequestError, GitbeakerRetryError, GitbeakerTimeoutError, type GitlabToken, type OptionsHandlerFn, type RateLimitOptions, type RateLimiterFn, type RateLimiters, type RequestHandlerFn, type RequestOptions, type RequesterType, type ResourceOptions, type ResponseBodyTypes, type RootResourceOptions, createRateLimiters, createRequesterFn, defaultOptionsHandler, formatQuery, generateRateLimiterFn, getMatchingRateLimiter, presetResourceArguments };
package/dist/index.d.ts DELETED
@@ -1,125 +0,0 @@
1
- type RateLimiterFn = () => Promise<number>;
2
- type RateLimiters = Record<string, RateLimiterFn | {
3
- method: string;
4
- limit: RateLimiterFn;
5
- }>;
6
- type RateLimitOptions = Record<string, number | {
7
- method: string;
8
- limit: number;
9
- }>;
10
- type ResponseBodyTypes = Record<string, unknown> | Record<string, unknown>[] | ReadableStream | Blob | string | string[] | number | void | null;
11
- interface FormattedResponse<T extends ResponseBodyTypes = ResponseBodyTypes> {
12
- body: T;
13
- headers: Record<string, string>;
14
- status: number;
15
- }
16
- interface Constructable<T = any> {
17
- new (...args: any[]): T;
18
- }
19
- type ResourceOptions = {
20
- headers: {
21
- [header: string]: string;
22
- };
23
- authHeaders: {
24
- [authHeader: string]: () => Promise<string>;
25
- };
26
- url: string;
27
- rejectUnauthorized: boolean;
28
- rateLimits?: RateLimitOptions;
29
- };
30
- type DefaultRequestOptions = {
31
- body?: FormData | Record<string, unknown>;
32
- searchParams?: Record<string, unknown>;
33
- sudo?: string | number;
34
- method?: string;
35
- asStream?: boolean;
36
- signal?: AbortSignal;
37
- };
38
- type RequestOptions = {
39
- headers?: Record<string, string>;
40
- timeout?: number;
41
- method?: string;
42
- searchParams?: string;
43
- prefixUrl?: string;
44
- body?: string | FormData;
45
- asStream?: boolean;
46
- signal?: AbortSignal;
47
- rateLimiters?: Record<string, RateLimiterFn>;
48
- };
49
- interface RequesterType {
50
- get<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
51
- post<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
52
- put<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
53
- patch<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
54
- delete<T extends ResponseBodyTypes>(endpoint: string, options?: DefaultRequestOptions): Promise<FormattedResponse<T>>;
55
- }
56
- type RequestHandlerFn<T extends ResponseBodyTypes = ResponseBodyTypes> = (endpoint: string, options?: Record<string, unknown>) => Promise<FormattedResponse<T>>;
57
- declare function generateRateLimiterFn(limit: number, interval: number): () => Promise<number>;
58
- declare function formatQuery(params?: Record<string, unknown>): string;
59
- type OptionsHandlerFn = (serviceOptions: ResourceOptions, requestOptions: RequestOptions) => Promise<RequestOptions>;
60
- declare function defaultOptionsHandler(resourceOptions: ResourceOptions, { body, searchParams, sudo, signal, asStream, method, }?: DefaultRequestOptions): Promise<RequestOptions>;
61
- declare function createRateLimiters(rateLimitOptions?: RateLimitOptions): RateLimiters;
62
- declare function createRequesterFn(optionsHandler: OptionsHandlerFn, requestHandler: RequestHandlerFn): (serviceOptions: ResourceOptions) => RequesterType;
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): RateLimiterFn;
65
-
66
- interface RootResourceOptions<C> {
67
- requesterFn?: (resourceOptions: ResourceOptions) => RequesterType;
68
- host?: string;
69
- prefixUrl?: string;
70
- rejectUnauthorized?: boolean;
71
- camelize?: C;
72
- queryTimeout?: number | null;
73
- sudo?: string | number;
74
- profileToken?: string;
75
- profileMode?: 'execution' | 'memory';
76
- rateLimits?: RateLimitOptions;
77
- }
78
- type GitlabToken = string | (() => Promise<string>);
79
- interface BaseRequestOptionsWithOAuthToken<C> extends RootResourceOptions<C> {
80
- oauthToken: GitlabToken;
81
- }
82
- interface BaseRequestOptionsWithAccessToken<C> extends RootResourceOptions<C> {
83
- token: GitlabToken;
84
- }
85
- interface BaseRequestOptionsWithJobToken<C> extends RootResourceOptions<C> {
86
- jobToken: GitlabToken;
87
- }
88
- type BaseResourceOptions<C> = BaseRequestOptionsWithOAuthToken<C> | BaseRequestOptionsWithAccessToken<C> | BaseRequestOptionsWithJobToken<C>;
89
- declare class BaseResource<C extends boolean = false> {
90
- readonly url: string;
91
- readonly requester: RequesterType;
92
- readonly queryTimeout: number | null;
93
- readonly headers: {
94
- [header: string]: string;
95
- };
96
- readonly authHeaders: {
97
- [authHeader: string]: () => Promise<string>;
98
- };
99
- readonly camelize: C | undefined;
100
- readonly rejectUnauthorized: boolean;
101
- constructor({ sudo, profileToken, camelize, requesterFn, profileMode, host, prefixUrl, rejectUnauthorized, queryTimeout, rateLimits, ...tokens }: BaseResourceOptions<C>);
102
- }
103
-
104
- declare class GitbeakerRequestError extends Error {
105
- readonly cause?: {
106
- description: string;
107
- request: Request;
108
- response: Response;
109
- };
110
- constructor(message: string, options?: {
111
- cause?: {
112
- description: string;
113
- request: Request;
114
- response: Response;
115
- };
116
- });
117
- }
118
- declare class GitbeakerTimeoutError extends Error {
119
- constructor(message: string, options?: ErrorOptions);
120
- }
121
- declare class GitbeakerRetryError extends Error {
122
- constructor(message: string, options?: ErrorOptions);
123
- }
124
-
125
- export { type BaseRequestOptionsWithAccessToken, type BaseRequestOptionsWithJobToken, type BaseRequestOptionsWithOAuthToken, BaseResource, type BaseResourceOptions, type Constructable, type DefaultRequestOptions, type FormattedResponse, GitbeakerRequestError, GitbeakerRetryError, GitbeakerTimeoutError, type GitlabToken, type OptionsHandlerFn, type RateLimitOptions, type RateLimiterFn, type RateLimiters, type RequestHandlerFn, type RequestOptions, type RequesterType, type ResourceOptions, type ResponseBodyTypes, type RootResourceOptions, createRateLimiters, createRequesterFn, defaultOptionsHandler, formatQuery, generateRateLimiterFn, getMatchingRateLimiter, presetResourceArguments };
package/dist/index.js DELETED
@@ -1,238 +0,0 @@
1
- 'use strict';
2
-
3
- var qs = require('qs');
4
- var xcase = require('xcase');
5
- var rateLimiterFlexible = require('rate-limiter-flexible');
6
- var Picomatch = require('picomatch-browser');
7
-
8
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
-
10
- var Picomatch__default = /*#__PURE__*/_interopDefault(Picomatch);
11
-
12
- // src/RequesterUtils.ts
13
- var { isMatch: isGlobMatch } = Picomatch__default.default;
14
- function generateRateLimiterFn(limit, interval) {
15
- const limiter = new rateLimiterFlexible.RateLimiterQueue(
16
- new rateLimiterFlexible.RateLimiterMemory({ points: limit, duration: interval })
17
- );
18
- return () => limiter.removeTokens(1);
19
- }
20
- function formatQuery(params = {}) {
21
- const decamelized = xcase.decamelizeKeys(params);
22
- return qs.stringify(decamelized, { arrayFormat: "brackets" });
23
- }
24
- async function defaultOptionsHandler(resourceOptions, {
25
- body,
26
- searchParams,
27
- sudo,
28
- signal,
29
- asStream = false,
30
- method = "GET"
31
- } = {}) {
32
- const { headers: preconfiguredHeaders, authHeaders, url } = resourceOptions;
33
- const headers = { ...preconfiguredHeaders };
34
- const defaultOptions = {
35
- method,
36
- asStream,
37
- signal,
38
- prefixUrl: url
39
- };
40
- defaultOptions.headers = headers;
41
- if (sudo)
42
- defaultOptions.headers.sudo = `${sudo}`;
43
- if (body) {
44
- if (body instanceof FormData) {
45
- defaultOptions.body = body;
46
- } else {
47
- defaultOptions.body = JSON.stringify(xcase.decamelizeKeys(body));
48
- defaultOptions.headers["content-type"] = "application/json";
49
- }
50
- }
51
- const [authHeaderKey, authHeaderFn] = Object.entries(authHeaders)[0];
52
- defaultOptions.headers[authHeaderKey] = await authHeaderFn();
53
- const q = formatQuery(searchParams);
54
- if (q)
55
- defaultOptions.searchParams = q;
56
- return Promise.resolve(defaultOptions);
57
- }
58
- function createRateLimiters(rateLimitOptions = {}) {
59
- const rateLimiters = {};
60
- Object.entries(rateLimitOptions).forEach(([key, config]) => {
61
- if (typeof config === "number")
62
- rateLimiters[key] = generateRateLimiterFn(config, 60);
63
- else
64
- rateLimiters[key] = {
65
- method: config.method.toUpperCase(),
66
- limit: generateRateLimiterFn(config.limit, 60)
67
- };
68
- });
69
- return rateLimiters;
70
- }
71
- function createRequesterFn(optionsHandler, requestHandler) {
72
- const methods = ["get", "post", "put", "patch", "delete"];
73
- return (serviceOptions) => {
74
- const requester = {};
75
- const rateLimiters = createRateLimiters(serviceOptions.rateLimits);
76
- methods.forEach((m) => {
77
- requester[m] = async (endpoint, options) => {
78
- const defaultRequestOptions = await defaultOptionsHandler(serviceOptions, {
79
- ...options,
80
- method: m.toUpperCase()
81
- });
82
- const requestOptions = await optionsHandler(serviceOptions, defaultRequestOptions);
83
- return requestHandler(endpoint, { ...requestOptions, rateLimiters });
84
- };
85
- });
86
- return requester;
87
- };
88
- }
89
- function extendClass(Base, customConfig) {
90
- return class extends Base {
91
- constructor(...options) {
92
- const [config, ...opts] = options;
93
- super({ ...customConfig, ...config }, ...opts);
94
- }
95
- };
96
- }
97
- function presetResourceArguments(resources, customConfig = {}) {
98
- const updated = {};
99
- Object.entries(resources).filter(([, s]) => typeof s === "function").forEach(([k, r]) => {
100
- updated[k] = extendClass(r, customConfig);
101
- });
102
- return updated;
103
- }
104
- function getMatchingRateLimiter(endpoint, rateLimiters = {}, method = "GET") {
105
- const sortedEndpoints = Object.keys(rateLimiters).sort().reverse();
106
- const match = sortedEndpoints.find((ep) => isGlobMatch(endpoint, ep));
107
- const rateLimitConfig = match && rateLimiters[match];
108
- if (typeof rateLimitConfig === "function")
109
- return rateLimitConfig;
110
- if (rateLimitConfig && rateLimitConfig?.method?.toUpperCase() === method.toUpperCase()) {
111
- return rateLimitConfig.limit;
112
- }
113
- return generateRateLimiterFn(3e3, 60);
114
- }
115
-
116
- // src/BaseResource.ts
117
- function getDynamicToken(tokenArgument) {
118
- return tokenArgument instanceof Function ? tokenArgument() : Promise.resolve(tokenArgument);
119
- }
120
- var DEFAULT_RATE_LIMITS = Object.freeze({
121
- // Default rate limit
122
- "**": 3e3,
123
- // Import/Export
124
- "projects/import": 6,
125
- "projects/*/export": 6,
126
- "projects/*/download": 1,
127
- "groups/import": 6,
128
- "groups/*/export": 6,
129
- "groups/*/download": 1,
130
- // Note creation
131
- "projects/*/issues/*/notes": {
132
- method: "post",
133
- limit: 300
134
- },
135
- "projects/*/snippets/*/notes": {
136
- method: "post",
137
- limit: 300
138
- },
139
- "projects/*/merge_requests/*/notes": {
140
- method: "post",
141
- limit: 300
142
- },
143
- "groups/*/epics/*/notes": {
144
- method: "post",
145
- limit: 300
146
- },
147
- // Repositories - get file archive
148
- "projects/*/repository/archive*": 5,
149
- // Project Jobs
150
- "projects/*/jobs": 600,
151
- // Member deletion
152
- "projects/*/members": 60,
153
- "groups/*/members": 60
154
- });
155
- var BaseResource = class {
156
- url;
157
- requester;
158
- queryTimeout;
159
- headers;
160
- authHeaders;
161
- camelize;
162
- rejectUnauthorized;
163
- constructor({
164
- sudo,
165
- profileToken,
166
- camelize,
167
- requesterFn,
168
- profileMode = "execution",
169
- host = "https://gitlab.com",
170
- prefixUrl = "",
171
- rejectUnauthorized = true,
172
- queryTimeout = 3e5,
173
- rateLimits = DEFAULT_RATE_LIMITS,
174
- ...tokens
175
- }) {
176
- if (!requesterFn)
177
- throw new ReferenceError("requesterFn must be passed");
178
- this.url = [host, "api", "v4", prefixUrl].join("/");
179
- this.headers = {};
180
- this.authHeaders = {};
181
- this.rejectUnauthorized = rejectUnauthorized;
182
- this.camelize = camelize;
183
- this.queryTimeout = queryTimeout;
184
- if ("oauthToken" in tokens)
185
- this.authHeaders.authorization = async () => {
186
- const token = await getDynamicToken(tokens.oauthToken);
187
- return `Bearer ${token}`;
188
- };
189
- else if ("jobToken" in tokens)
190
- this.authHeaders["job-token"] = async () => getDynamicToken(tokens.jobToken);
191
- else if ("token" in tokens)
192
- this.authHeaders["private-token"] = async () => getDynamicToken(tokens.token);
193
- else {
194
- throw new ReferenceError("A token, oauthToken or jobToken must be passed");
195
- }
196
- if (profileToken) {
197
- this.headers["X-Profile-Token"] = profileToken;
198
- this.headers["X-Profile-Mode"] = profileMode;
199
- }
200
- if (sudo)
201
- this.headers.Sudo = `${sudo}`;
202
- this.requester = requesterFn({ ...this, rateLimits });
203
- }
204
- };
205
-
206
- // src/GitbeakerError.ts
207
- var GitbeakerRequestError = class extends Error {
208
- cause;
209
- constructor(message, options) {
210
- super(message, options);
211
- this.cause = options?.cause;
212
- this.name = "GitbeakerRequestError";
213
- }
214
- };
215
- var GitbeakerTimeoutError = class extends Error {
216
- constructor(message, options) {
217
- super(message, options);
218
- this.name = "GitbeakerTimeoutError";
219
- }
220
- };
221
- var GitbeakerRetryError = class extends Error {
222
- constructor(message, options) {
223
- super(message, options);
224
- this.name = "GitbeakerRetryError";
225
- }
226
- };
227
-
228
- exports.BaseResource = BaseResource;
229
- exports.GitbeakerRequestError = GitbeakerRequestError;
230
- exports.GitbeakerRetryError = GitbeakerRetryError;
231
- exports.GitbeakerTimeoutError = GitbeakerTimeoutError;
232
- exports.createRateLimiters = createRateLimiters;
233
- exports.createRequesterFn = createRequesterFn;
234
- exports.defaultOptionsHandler = defaultOptionsHandler;
235
- exports.formatQuery = formatQuery;
236
- exports.generateRateLimiterFn = generateRateLimiterFn;
237
- exports.getMatchingRateLimiter = getMatchingRateLimiter;
238
- exports.presetResourceArguments = presetResourceArguments;
package/dist/index.mjs DELETED
@@ -1,222 +0,0 @@
1
- import { stringify } from 'qs';
2
- import { decamelizeKeys } from 'xcase';
3
- import { RateLimiterQueue, RateLimiterMemory } from 'rate-limiter-flexible';
4
- import Picomatch from 'picomatch-browser';
5
-
6
- // src/RequesterUtils.ts
7
- var { isMatch: isGlobMatch } = Picomatch;
8
- function generateRateLimiterFn(limit, interval) {
9
- const limiter = new RateLimiterQueue(
10
- new RateLimiterMemory({ points: limit, duration: interval })
11
- );
12
- return () => limiter.removeTokens(1);
13
- }
14
- function formatQuery(params = {}) {
15
- const decamelized = decamelizeKeys(params);
16
- return stringify(decamelized, { arrayFormat: "brackets" });
17
- }
18
- async function defaultOptionsHandler(resourceOptions, {
19
- body,
20
- searchParams,
21
- sudo,
22
- signal,
23
- asStream = false,
24
- method = "GET"
25
- } = {}) {
26
- const { headers: preconfiguredHeaders, authHeaders, url } = resourceOptions;
27
- const headers = { ...preconfiguredHeaders };
28
- const defaultOptions = {
29
- method,
30
- asStream,
31
- signal,
32
- prefixUrl: url
33
- };
34
- defaultOptions.headers = headers;
35
- if (sudo)
36
- defaultOptions.headers.sudo = `${sudo}`;
37
- if (body) {
38
- if (body instanceof FormData) {
39
- defaultOptions.body = body;
40
- } else {
41
- defaultOptions.body = JSON.stringify(decamelizeKeys(body));
42
- defaultOptions.headers["content-type"] = "application/json";
43
- }
44
- }
45
- const [authHeaderKey, authHeaderFn] = Object.entries(authHeaders)[0];
46
- defaultOptions.headers[authHeaderKey] = await authHeaderFn();
47
- const q = formatQuery(searchParams);
48
- if (q)
49
- defaultOptions.searchParams = q;
50
- return Promise.resolve(defaultOptions);
51
- }
52
- function createRateLimiters(rateLimitOptions = {}) {
53
- const rateLimiters = {};
54
- Object.entries(rateLimitOptions).forEach(([key, config]) => {
55
- if (typeof config === "number")
56
- rateLimiters[key] = generateRateLimiterFn(config, 60);
57
- else
58
- rateLimiters[key] = {
59
- method: config.method.toUpperCase(),
60
- limit: generateRateLimiterFn(config.limit, 60)
61
- };
62
- });
63
- return rateLimiters;
64
- }
65
- function createRequesterFn(optionsHandler, requestHandler) {
66
- const methods = ["get", "post", "put", "patch", "delete"];
67
- return (serviceOptions) => {
68
- const requester = {};
69
- const rateLimiters = createRateLimiters(serviceOptions.rateLimits);
70
- methods.forEach((m) => {
71
- requester[m] = async (endpoint, options) => {
72
- const defaultRequestOptions = await defaultOptionsHandler(serviceOptions, {
73
- ...options,
74
- method: m.toUpperCase()
75
- });
76
- const requestOptions = await optionsHandler(serviceOptions, defaultRequestOptions);
77
- return requestHandler(endpoint, { ...requestOptions, rateLimiters });
78
- };
79
- });
80
- return requester;
81
- };
82
- }
83
- function extendClass(Base, customConfig) {
84
- return class extends Base {
85
- constructor(...options) {
86
- const [config, ...opts] = options;
87
- super({ ...customConfig, ...config }, ...opts);
88
- }
89
- };
90
- }
91
- function presetResourceArguments(resources, customConfig = {}) {
92
- const updated = {};
93
- Object.entries(resources).filter(([, s]) => typeof s === "function").forEach(([k, r]) => {
94
- updated[k] = extendClass(r, customConfig);
95
- });
96
- return updated;
97
- }
98
- function getMatchingRateLimiter(endpoint, rateLimiters = {}, method = "GET") {
99
- const sortedEndpoints = Object.keys(rateLimiters).sort().reverse();
100
- const match = sortedEndpoints.find((ep) => isGlobMatch(endpoint, ep));
101
- const rateLimitConfig = match && rateLimiters[match];
102
- if (typeof rateLimitConfig === "function")
103
- return rateLimitConfig;
104
- if (rateLimitConfig && rateLimitConfig?.method?.toUpperCase() === method.toUpperCase()) {
105
- return rateLimitConfig.limit;
106
- }
107
- return generateRateLimiterFn(3e3, 60);
108
- }
109
-
110
- // src/BaseResource.ts
111
- function getDynamicToken(tokenArgument) {
112
- return tokenArgument instanceof Function ? tokenArgument() : Promise.resolve(tokenArgument);
113
- }
114
- var DEFAULT_RATE_LIMITS = Object.freeze({
115
- // Default rate limit
116
- "**": 3e3,
117
- // Import/Export
118
- "projects/import": 6,
119
- "projects/*/export": 6,
120
- "projects/*/download": 1,
121
- "groups/import": 6,
122
- "groups/*/export": 6,
123
- "groups/*/download": 1,
124
- // Note creation
125
- "projects/*/issues/*/notes": {
126
- method: "post",
127
- limit: 300
128
- },
129
- "projects/*/snippets/*/notes": {
130
- method: "post",
131
- limit: 300
132
- },
133
- "projects/*/merge_requests/*/notes": {
134
- method: "post",
135
- limit: 300
136
- },
137
- "groups/*/epics/*/notes": {
138
- method: "post",
139
- limit: 300
140
- },
141
- // Repositories - get file archive
142
- "projects/*/repository/archive*": 5,
143
- // Project Jobs
144
- "projects/*/jobs": 600,
145
- // Member deletion
146
- "projects/*/members": 60,
147
- "groups/*/members": 60
148
- });
149
- var BaseResource = class {
150
- url;
151
- requester;
152
- queryTimeout;
153
- headers;
154
- authHeaders;
155
- camelize;
156
- rejectUnauthorized;
157
- constructor({
158
- sudo,
159
- profileToken,
160
- camelize,
161
- requesterFn,
162
- profileMode = "execution",
163
- host = "https://gitlab.com",
164
- prefixUrl = "",
165
- rejectUnauthorized = true,
166
- queryTimeout = 3e5,
167
- rateLimits = DEFAULT_RATE_LIMITS,
168
- ...tokens
169
- }) {
170
- if (!requesterFn)
171
- throw new ReferenceError("requesterFn must be passed");
172
- this.url = [host, "api", "v4", prefixUrl].join("/");
173
- this.headers = {};
174
- this.authHeaders = {};
175
- this.rejectUnauthorized = rejectUnauthorized;
176
- this.camelize = camelize;
177
- this.queryTimeout = queryTimeout;
178
- if ("oauthToken" in tokens)
179
- this.authHeaders.authorization = async () => {
180
- const token = await getDynamicToken(tokens.oauthToken);
181
- return `Bearer ${token}`;
182
- };
183
- else if ("jobToken" in tokens)
184
- this.authHeaders["job-token"] = async () => getDynamicToken(tokens.jobToken);
185
- else if ("token" in tokens)
186
- this.authHeaders["private-token"] = async () => getDynamicToken(tokens.token);
187
- else {
188
- throw new ReferenceError("A token, oauthToken or jobToken must be passed");
189
- }
190
- if (profileToken) {
191
- this.headers["X-Profile-Token"] = profileToken;
192
- this.headers["X-Profile-Mode"] = profileMode;
193
- }
194
- if (sudo)
195
- this.headers.Sudo = `${sudo}`;
196
- this.requester = requesterFn({ ...this, rateLimits });
197
- }
198
- };
199
-
200
- // src/GitbeakerError.ts
201
- var GitbeakerRequestError = class extends Error {
202
- cause;
203
- constructor(message, options) {
204
- super(message, options);
205
- this.cause = options?.cause;
206
- this.name = "GitbeakerRequestError";
207
- }
208
- };
209
- var GitbeakerTimeoutError = class extends Error {
210
- constructor(message, options) {
211
- super(message, options);
212
- this.name = "GitbeakerTimeoutError";
213
- }
214
- };
215
- var GitbeakerRetryError = class extends Error {
216
- constructor(message, options) {
217
- super(message, options);
218
- this.name = "GitbeakerRetryError";
219
- }
220
- };
221
-
222
- export { BaseResource, GitbeakerRequestError, GitbeakerRetryError, GitbeakerTimeoutError, createRateLimiters, createRequesterFn, defaultOptionsHandler, formatQuery, generateRateLimiterFn, getMatchingRateLimiter, presetResourceArguments };