• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mongodb-js / mongodb-mcp-server / 20916758679

12 Jan 2026 10:54AM UTC coverage: 79.476% (-0.06%) from 79.54%
20916758679

push

github

web-flow
chore: defer usage of node-specific API calls (#839)

1492 of 1953 branches covered (76.4%)

Branch coverage included in aggregate %.

51 of 61 new or added lines in 21 files covered. (83.61%)

6 existing lines in 2 files now uncovered.

6911 of 8620 relevant lines covered (80.17%)

88.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.84
/src/common/atlas/apiClient.ts
1
import createClient from "openapi-fetch";
3✔
2
import type { ClientOptions, FetchOptions, Client, Middleware } from "openapi-fetch";
3
import { ApiClientError } from "./apiClientError.js";
3✔
4
import type { paths, operations } from "./openapi.js";
5
import type { CommonProperties, TelemetryEvent } from "../../telemetry/types.js";
6
import { packageInfo } from "../packageInfo.js";
3✔
7
import type { LoggerBase } from "../logger.js";
8
import { LogId } from "../logger.js";
3✔
9
import { createFetch } from "@mongodb-js/devtools-proxy-support";
3✔
10
import * as oauth from "oauth4webapi";
3✔
11
import { Request as NodeFetchRequest } from "node-fetch";
3✔
12

13
const ATLAS_API_VERSION = "2025-03-12";
3✔
14

15
export interface ApiClientCredentials {
16
    clientId: string;
17
    clientSecret: string;
18
}
19

20
export interface ApiClientOptions {
21
    credentials?: ApiClientCredentials;
22
    baseUrl: string;
23
    userAgent?: string;
24
}
25

26
export interface AccessToken {
27
    access_token: string;
28
    expires_at?: number;
29
}
30

31
export class ApiClient {
3✔
32
    private readonly options: {
33
        baseUrl: string;
34
        userAgent: string;
35
        credentials?: {
36
            clientId: string;
37
            clientSecret: string;
38
        };
39
    };
40

41
    private customFetch: typeof fetch;
42

43
    private client: Client<paths>;
44

45
    private oauth2Client?: oauth.Client;
46
    private oauth2Issuer?: oauth.AuthorizationServer;
47
    private accessToken?: AccessToken;
48

49
    public hasCredentials(): boolean {
3✔
50
        return !!this.oauth2Client && !!this.oauth2Issuer;
3✔
51
    }
3✔
52

53
    private isAccessTokenValid(): boolean {
3✔
54
        return !!(
157✔
55
            this.accessToken &&
157✔
56
            this.accessToken.expires_at !== undefined &&
133✔
57
            this.accessToken.expires_at > Date.now()
133✔
58
        );
59
    }
157✔
60

61
    private getAccessToken = async (): Promise<string | undefined> => {
3✔
62
        if (!this.hasCredentials()) {
158!
63
            return undefined;
1✔
64
        }
1✔
65

66
        if (!this.isAccessTokenValid()) {
158✔
67
            this.accessToken = await this.getNewAccessToken();
26✔
68
        }
26✔
69

70
        return this.accessToken?.access_token;
158✔
71
    };
158✔
72

73
    private authMiddleware: Middleware = {
3✔
74
        onRequest: async ({ request, schemaPath }) => {
3✔
75
            if (schemaPath.startsWith("/api/private/unauth") || schemaPath.startsWith("/api/oauth")) {
99!
76
                return undefined;
1✔
77
            }
1✔
78

79
            try {
99✔
80
                const accessToken = await this.getAccessToken();
99✔
81
                if (accessToken) {
99✔
82
                    request.headers.set("Authorization", `Bearer ${accessToken}`);
98✔
83
                }
98✔
84
                return request;
99✔
85
            } catch {
99!
86
                // ignore not availble tokens, API will return 401
87
                return undefined;
1✔
88
            }
1✔
89
        },
99✔
90
    };
3✔
91

92
    constructor(
3✔
93
        options: ApiClientOptions,
25✔
94
        public readonly logger: LoggerBase
25✔
95
    ) {
25✔
96
        // createFetch assumes that the first parameter of fetch is always a string
97
        // with the URL. However, fetch can also receive a Request object. While
98
        // the typechecking complains, createFetch does passthrough the parameters
99
        // so it works fine. That said, node-fetch has incompatibilities with the web version
100
        // of fetch and can lead to genuine issues so we would like to move away of node-fetch dependency.
101
        this.customFetch = createFetch({
25✔
102
            useEnvironmentVariableProxies: true,
25✔
103
        }) as unknown as typeof fetch;
25✔
104
        this.options = {
25✔
105
            ...options,
25✔
106
            userAgent:
25✔
107
                options.userAgent ||
25✔
108
                `AtlasMCP/${packageInfo.version} (${process.platform}; ${process.arch}; ${process.env.HOSTNAME || "unknown"})`,
13✔
109
        };
25✔
110

111
        this.client = createClient<paths>({
25✔
112
            baseUrl: this.options.baseUrl,
25✔
113
            headers: {
25✔
114
                "User-Agent": this.options.userAgent,
25✔
115
                Accept: `application/vnd.atlas.${ATLAS_API_VERSION}+json`,
25✔
116
            },
25✔
117
            fetch: this.customFetch,
25✔
118
            // NodeFetchRequest has more overloadings than the native Request
119
            // so it complains here. However, the interfaces are actually compatible
120
            // so it's not a real problem, just a type checking problem.
121
            Request: NodeFetchRequest as unknown as ClientOptions["Request"],
25✔
122
        });
25✔
123

124
        if (this.options.credentials?.clientId && this.options.credentials?.clientSecret) {
25✔
125
            this.oauth2Issuer = {
25✔
126
                issuer: this.options.baseUrl,
25✔
127
                token_endpoint: new URL("/api/oauth/token", this.options.baseUrl).toString(),
25✔
128
                revocation_endpoint: new URL("/api/oauth/revoke", this.options.baseUrl).toString(),
25✔
129
                token_endpoint_auth_methods_supported: ["client_secret_basic"],
25✔
130
                grant_types_supported: ["client_credentials"],
25✔
131
            };
25✔
132

133
            this.oauth2Client = {
25✔
134
                client_id: this.options.credentials.clientId,
25✔
135
                client_secret: this.options.credentials.clientSecret,
25✔
136
            };
25✔
137

138
            this.client.use(this.authMiddleware);
25✔
139
        }
25✔
140
    }
25✔
141

142
    private getOauthClientAuth(): { client: oauth.Client | undefined; clientAuth: oauth.ClientAuth | undefined } {
3✔
143
        if (this.options.credentials?.clientId && this.options.credentials.clientSecret) {
43✔
144
            const clientSecret = this.options.credentials.clientSecret;
43✔
145
            const clientId = this.options.credentials.clientId;
43✔
146

147
            // We are using our own ClientAuth because ClientSecretBasic URL encodes wrongly
148
            // the username and password (for example, encodes `_` to %5F, which is wrong).
149
            return {
43✔
150
                client: { client_id: clientId },
43✔
151
                clientAuth: (_as, client, _body, headers): void => {
43✔
152
                    const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
34✔
153
                    headers.set("Authorization", `Basic ${credentials}`);
34✔
154
                },
34✔
155
            };
43✔
156
        }
43!
157

UNCOV
158
        return { client: undefined, clientAuth: undefined };
×
159
    }
43✔
160

161
    private async getNewAccessToken(): Promise<AccessToken | undefined> {
3✔
162
        if (!this.hasCredentials() || !this.oauth2Issuer) {
25!
163
            return undefined;
×
164
        }
×
165

166
        const { client, clientAuth } = this.getOauthClientAuth();
25✔
167
        if (client && clientAuth) {
25✔
168
            try {
25✔
169
                const response = await oauth.clientCredentialsGrantRequest(
25✔
170
                    this.oauth2Issuer,
25✔
171
                    client,
25✔
172
                    clientAuth,
25✔
173
                    new URLSearchParams(),
25✔
174
                    {
25✔
175
                        [oauth.customFetch]: this.customFetch,
25✔
176
                        headers: {
25✔
177
                            "User-Agent": this.options.userAgent,
25✔
178
                        },
25✔
179
                    }
25✔
180
                );
25✔
181

182
                const result = await oauth.processClientCredentialsResponse(this.oauth2Issuer, client, response);
25!
183
                this.accessToken = {
6✔
184
                    access_token: result.access_token,
6✔
185
                    expires_at: Date.now() + (result.expires_in ?? 0) * 1000,
25!
186
                };
25✔
187
            } catch (error: unknown) {
25!
188
                const err = error instanceof Error ? error : new Error(String(error));
19!
189
                this.logger.error({
19✔
190
                    id: LogId.atlasConnectFailure,
19✔
191
                    context: "apiClient",
19✔
192
                    message: `Failed to request access token: ${err.message}`,
19✔
193
                });
19✔
194
            }
19✔
195
            return this.accessToken;
25✔
196
        }
25!
197

198
        return undefined;
×
199
    }
25✔
200

201
    public async validateAccessToken(): Promise<void> {
3✔
202
        await this.getAccessToken();
20✔
203
    }
20✔
204

205
    public async close(): Promise<void> {
3✔
206
        const { client, clientAuth } = this.getOauthClientAuth();
18✔
207
        try {
18✔
208
            if (this.oauth2Issuer && this.accessToken && client && clientAuth) {
18✔
209
                await oauth.revocationRequest(this.oauth2Issuer, client, clientAuth, this.accessToken.access_token);
9✔
210
            }
7✔
211
        } catch (error: unknown) {
18!
212
            const err = error instanceof Error ? error : new Error(String(error));
2!
213
            this.logger.error({
2✔
214
                id: LogId.atlasApiRevokeFailure,
2✔
215
                context: "apiClient",
2✔
216
                message: `Failed to revoke access token: ${err.message}`,
2✔
217
            });
2✔
218
        }
2✔
219
        this.accessToken = undefined;
18✔
220
    }
18✔
221

222
    public async getIpInfo(): Promise<{
3✔
223
        currentIpv4Address: string;
224
    }> {
26✔
225
        const accessToken = await this.getAccessToken();
26✔
226

227
        const endpoint = "api/private/ipinfo";
26✔
228
        const url = new URL(endpoint, this.options.baseUrl);
26✔
229
        const response = await fetch(url, {
26✔
230
            method: "GET",
26✔
231
            headers: {
26✔
232
                Accept: "application/json",
26✔
233
                Authorization: `Bearer ${accessToken}`,
26✔
234
                "User-Agent": this.options.userAgent,
26✔
235
            },
26✔
236
        });
26✔
237

238
        if (!response.ok) {
26!
239
            throw await ApiClientError.fromResponse(response);
2✔
240
        }
2!
241

242
        return (await response.json()) as Promise<{
24✔
243
            currentIpv4Address: string;
244
        }>;
245
    }
26✔
246

247
    public async sendEvents(events: TelemetryEvent<CommonProperties>[]): Promise<void> {
3✔
248
        if (!this.options.credentials) {
18!
UNCOV
249
            await this.sendUnauthEvents(events);
×
UNCOV
250
            return;
×
UNCOV
251
        }
×
252

253
        try {
18✔
254
            await this.sendAuthEvents(events);
18✔
255
        } catch (error) {
18!
256
            if (error instanceof ApiClientError) {
11✔
257
                if (error.response.status !== 401) {
2!
258
                    throw error;
×
259
                }
×
260
            }
2✔
261

262
            // send unauth events if any of the following are true:
263
            // 1: the token is not valid (not ApiClientError)
264
            // 2: if the api responded with 401 (ApiClientError with status 401)
265
            await this.sendUnauthEvents(events);
11✔
266
        }
10✔
267
    }
18✔
268

269
    private async sendAuthEvents(events: TelemetryEvent<CommonProperties>[]): Promise<void> {
3✔
270
        const accessToken = await this.getAccessToken();
18✔
271
        if (!accessToken) {
18!
272
            throw new Error("No access token available");
8✔
273
        }
8✔
274
        const authUrl = new URL("api/private/v1.0/telemetry/events", this.options.baseUrl);
9✔
275
        const response = await fetch(authUrl, {
9✔
276
            method: "POST",
9✔
277
            headers: {
9✔
278
                Accept: "application/json",
9✔
279
                "Content-Type": "application/json",
9✔
280
                "User-Agent": this.options.userAgent,
9✔
281
                Authorization: `Bearer ${accessToken}`,
9✔
282
            },
9✔
283
            body: JSON.stringify(events),
9✔
284
        });
9✔
285

286
        if (!response.ok) {
11!
287
            throw await ApiClientError.fromResponse(response);
2✔
288
        }
2✔
289
    }
18✔
290

291
    private async sendUnauthEvents(events: TelemetryEvent<CommonProperties>[]): Promise<void> {
3✔
292
        const headers: Record<string, string> = {
11✔
293
            Accept: "application/json",
11✔
294
            "Content-Type": "application/json",
11✔
295
            "User-Agent": this.options.userAgent,
11✔
296
        };
11✔
297

298
        const unauthUrl = new URL("api/private/unauth/telemetry/events", this.options.baseUrl);
11✔
299
        const response = await fetch(unauthUrl, {
11✔
300
            method: "POST",
11✔
301
            headers,
11✔
302
            body: JSON.stringify(events),
11✔
303
        });
11✔
304

305
        if (!response.ok) {
11✔
306
            throw await ApiClientError.fromResponse(response);
1✔
307
        }
1✔
308
    }
11✔
309

310
    // DO NOT EDIT. This is auto-generated code.
311
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
312
    async listClusterDetails(options?: FetchOptions<operations["listClusterDetails"]>) {
3✔
313
        const { data, error, response } = await this.client.GET("/api/atlas/v2/clusters", options);
×
314
        if (error) {
×
315
            throw ApiClientError.fromError(response, error);
×
316
        }
×
317
        return data;
×
318
    }
×
319

320
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
321
    async listGroups(options?: FetchOptions<operations["listGroups"]>) {
3✔
322
        const { data, error, response } = await this.client.GET("/api/atlas/v2/groups", options);
4✔
323
        if (error) {
4!
324
            throw ApiClientError.fromError(response, error);
1✔
325
        }
1✔
326
        return data;
3✔
327
    }
4✔
328

329
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
330
    async createGroup(options: FetchOptions<operations["createGroup"]>) {
3✔
331
        const { data, error, response } = await this.client.POST("/api/atlas/v2/groups", options);
7✔
332
        if (error) {
7!
333
            throw ApiClientError.fromError(response, error);
×
334
        }
×
335
        return data;
7✔
336
    }
7✔
337

338
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
339
    async deleteGroup(options: FetchOptions<operations["deleteGroup"]>) {
3✔
340
        const { error, response } = await this.client.DELETE("/api/atlas/v2/groups/{groupId}", options);
7✔
341
        if (error) {
7✔
342
            throw ApiClientError.fromError(response, error);
2✔
343
        }
2✔
344
    }
7✔
345

346
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
347
    async getGroup(options: FetchOptions<operations["getGroup"]>) {
3✔
348
        const { data, error, response } = await this.client.GET("/api/atlas/v2/groups/{groupId}", options);
1✔
349
        if (error) {
1!
350
            throw ApiClientError.fromError(response, error);
×
351
        }
×
352
        return data;
1✔
353
    }
1✔
354

355
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
356
    async listAccessListEntries(options: FetchOptions<operations["listGroupAccessListEntries"]>) {
3✔
357
        const { data, error, response } = await this.client.GET("/api/atlas/v2/groups/{groupId}/accessList", options);
4✔
358
        if (error) {
4!
359
            throw ApiClientError.fromError(response, error);
×
360
        }
×
361
        return data;
4✔
362
    }
4✔
363

364
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
365
    async createAccessListEntry(options: FetchOptions<operations["createGroupAccessListEntry"]>) {
3✔
366
        const { data, error, response } = await this.client.POST("/api/atlas/v2/groups/{groupId}/accessList", options);
18✔
367
        if (error) {
18!
368
            throw ApiClientError.fromError(response, error);
1✔
369
        }
1!
370
        return data;
17✔
371
    }
18✔
372

373
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
374
    async deleteAccessListEntry(options: FetchOptions<operations["deleteGroupAccessListEntry"]>) {
3✔
375
        const { error, response } = await this.client.DELETE(
5✔
376
            "/api/atlas/v2/groups/{groupId}/accessList/{entryValue}",
5✔
377
            options
5✔
378
        );
5✔
379
        if (error) {
5!
380
            throw ApiClientError.fromError(response, error);
×
381
        }
×
382
    }
5✔
383

384
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
385
    async listAlerts(options: FetchOptions<operations["listGroupAlerts"]>) {
3✔
386
        const { data, error, response } = await this.client.GET("/api/atlas/v2/groups/{groupId}/alerts", options);
1✔
387
        if (error) {
1!
388
            throw ApiClientError.fromError(response, error);
×
389
        }
×
390
        return data;
1✔
391
    }
1✔
392

393
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
394
    async listClusters(options: FetchOptions<operations["listGroupClusters"]>) {
3✔
395
        const { data, error, response } = await this.client.GET("/api/atlas/v2/groups/{groupId}/clusters", options);
1✔
396
        if (error) {
1!
397
            throw ApiClientError.fromError(response, error);
×
398
        }
×
399
        return data;
1✔
400
    }
1✔
401

402
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
403
    async createCluster(options: FetchOptions<operations["createGroupCluster"]>) {
3✔
404
        const { data, error, response } = await this.client.POST("/api/atlas/v2/groups/{groupId}/clusters", options);
2✔
405
        if (error) {
2!
406
            throw ApiClientError.fromError(response, error);
×
407
        }
×
408
        return data;
2✔
409
    }
2✔
410

411
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
412
    async deleteCluster(options: FetchOptions<operations["deleteGroupCluster"]>) {
3✔
413
        const { error, response } = await this.client.DELETE(
2✔
414
            "/api/atlas/v2/groups/{groupId}/clusters/{clusterName}",
2✔
415
            options
2✔
416
        );
2✔
417
        if (error) {
2!
418
            throw ApiClientError.fromError(response, error);
×
419
        }
×
420
    }
2✔
421

422
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
423
    async getCluster(options: FetchOptions<operations["getGroupCluster"]>) {
3✔
424
        const { data, error, response } = await this.client.GET(
18✔
425
            "/api/atlas/v2/groups/{groupId}/clusters/{clusterName}",
18✔
426
            options
18✔
427
        );
18✔
428
        if (error) {
18!
429
            throw ApiClientError.fromError(response, error);
×
430
        }
×
431
        return data;
18✔
432
    }
18✔
433

434
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
435
    async listDropIndexSuggestions(
3✔
436
        options: FetchOptions<operations["listGroupClusterPerformanceAdvisorDropIndexSuggestions"]>
×
437
    ) {
×
438
        const { data, error, response } = await this.client.GET(
×
439
            "/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/performanceAdvisor/dropIndexSuggestions",
×
440
            options
×
441
        );
×
442
        if (error) {
×
443
            throw ApiClientError.fromError(response, error);
×
444
        }
×
445
        return data;
×
446
    }
×
447

448
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
449
    async listSchemaAdvice(options: FetchOptions<operations["listGroupClusterPerformanceAdvisorSchemaAdvice"]>) {
3✔
450
        const { data, error, response } = await this.client.GET(
×
451
            "/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/performanceAdvisor/schemaAdvice",
×
452
            options
×
453
        );
×
454
        if (error) {
×
455
            throw ApiClientError.fromError(response, error);
×
456
        }
×
457
        return data;
×
458
    }
×
459

460
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
461
    async listClusterSuggestedIndexes(
3✔
462
        options: FetchOptions<operations["listGroupClusterPerformanceAdvisorSuggestedIndexes"]>
×
463
    ) {
×
464
        const { data, error, response } = await this.client.GET(
×
465
            "/api/atlas/v2/groups/{groupId}/clusters/{clusterName}/performanceAdvisor/suggestedIndexes",
×
466
            options
×
467
        );
×
468
        if (error) {
×
469
            throw ApiClientError.fromError(response, error);
×
470
        }
×
471
        return data;
×
472
    }
×
473

474
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
475
    async listDatabaseUsers(options: FetchOptions<operations["listGroupDatabaseUsers"]>) {
3✔
476
        const { data, error, response } = await this.client.GET(
1✔
477
            "/api/atlas/v2/groups/{groupId}/databaseUsers",
1✔
478
            options
1✔
479
        );
1✔
480
        if (error) {
1!
481
            throw ApiClientError.fromError(response, error);
×
482
        }
×
483
        return data;
1✔
484
    }
1✔
485

486
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
487
    async createDatabaseUser(options: FetchOptions<operations["createGroupDatabaseUser"]>) {
3✔
488
        const { data, error, response } = await this.client.POST(
7✔
489
            "/api/atlas/v2/groups/{groupId}/databaseUsers",
7✔
490
            options
7✔
491
        );
7✔
492
        if (error) {
7!
493
            throw ApiClientError.fromError(response, error);
×
494
        }
×
495
        return data;
7✔
496
    }
7✔
497

498
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
499
    async deleteDatabaseUser(options: FetchOptions<operations["deleteGroupDatabaseUser"]>) {
3✔
500
        const { error, response } = await this.client.DELETE(
9✔
501
            "/api/atlas/v2/groups/{groupId}/databaseUsers/{databaseName}/{username}",
9✔
502
            options
9✔
503
        );
9✔
504
        if (error) {
9✔
505
            throw ApiClientError.fromError(response, error);
2✔
506
        }
2✔
507
    }
9✔
508

509
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
510
    async listFlexClusters(options: FetchOptions<operations["listGroupFlexClusters"]>) {
3✔
511
        const { data, error, response } = await this.client.GET("/api/atlas/v2/groups/{groupId}/flexClusters", options);
×
512
        if (error) {
×
513
            throw ApiClientError.fromError(response, error);
×
514
        }
×
515
        return data;
×
516
    }
×
517

518
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
519
    async createFlexCluster(options: FetchOptions<operations["createGroupFlexCluster"]>) {
3✔
520
        const { data, error, response } = await this.client.POST(
×
521
            "/api/atlas/v2/groups/{groupId}/flexClusters",
×
522
            options
×
523
        );
×
524
        if (error) {
×
525
            throw ApiClientError.fromError(response, error);
×
526
        }
×
527
        return data;
×
528
    }
×
529

530
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
531
    async deleteFlexCluster(options: FetchOptions<operations["deleteGroupFlexCluster"]>) {
3✔
532
        const { error, response } = await this.client.DELETE(
×
533
            "/api/atlas/v2/groups/{groupId}/flexClusters/{name}",
×
534
            options
×
535
        );
×
536
        if (error) {
×
537
            throw ApiClientError.fromError(response, error);
×
538
        }
×
539
    }
×
540

541
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
542
    async getFlexCluster(options: FetchOptions<operations["getGroupFlexCluster"]>) {
3✔
543
        const { data, error, response } = await this.client.GET(
×
544
            "/api/atlas/v2/groups/{groupId}/flexClusters/{name}",
×
545
            options
×
546
        );
×
547
        if (error) {
×
548
            throw ApiClientError.fromError(response, error);
×
549
        }
×
550
        return data;
×
551
    }
×
552

553
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
554
    async listSlowQueryLogs(options: FetchOptions<operations["listGroupProcessPerformanceAdvisorSlowQueryLogs"]>) {
3✔
555
        const { data, error, response } = await this.client.GET(
×
556
            "/api/atlas/v2/groups/{groupId}/processes/{processId}/performanceAdvisor/slowQueryLogs",
×
557
            options
×
558
        );
×
559
        if (error) {
×
560
            throw ApiClientError.fromError(response, error);
×
561
        }
×
562
        return data;
×
563
    }
×
564

565
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
566
    async listOrgs(options?: FetchOptions<operations["listOrgs"]>) {
3✔
567
        const { data, error, response } = await this.client.GET("/api/atlas/v2/orgs", options);
12!
568
        if (error) {
10!
569
            throw ApiClientError.fromError(response, error);
×
570
        }
×
571
        return data;
10✔
572
    }
12✔
573

574
    // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
575
    async getOrgGroups(options: FetchOptions<operations["getOrgGroups"]>) {
3✔
576
        const { data, error, response } = await this.client.GET("/api/atlas/v2/orgs/{orgId}/groups", options);
1✔
577
        if (error) {
1!
578
            throw ApiClientError.fromError(response, error);
×
579
        }
×
580
        return data;
1✔
581
    }
1✔
582

583
    // DO NOT EDIT. This is auto-generated code.
584
}
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc