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

mongodb-js / mongodb-mcp-server / 19262689096

11 Nov 2025 10:28AM UTC coverage: 80.145% (-0.006%) from 80.151%
19262689096

Pull #717

github

web-flow
Merge 2e10e748e into 2a8f602c5
Pull Request #717: chore: adds field embeddings validation for quantization "none" and warn when vectorSearch is not configured correctly

1367 of 1817 branches covered (75.23%)

Branch coverage included in aggregate %.

68 of 78 new or added lines in 7 files covered. (87.18%)

37 existing lines in 2 files now uncovered.

6484 of 7979 relevant lines covered (81.26%)

69.78 hits per line

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

71.36
/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
    // createFetch assumes that the first parameter of fetch is always a string
42
    // with the URL. However, fetch can also receive a Request object. While
43
    // the typechecking complains, createFetch does passthrough the parameters
44
    // so it works fine.
45
    private static customFetch: typeof fetch = createFetch({
3✔
46
        useEnvironmentVariableProxies: true,
3✔
47
    }) as unknown as typeof fetch;
3✔
48

49
    private client: Client<paths>;
50

51
    private oauth2Client?: oauth.Client;
52
    private oauth2Issuer?: oauth.AuthorizationServer;
53
    private accessToken?: AccessToken;
54

55
    public hasCredentials(): boolean {
3✔
56
        return !!this.oauth2Client && !!this.oauth2Issuer;
168✔
57
    }
168✔
58

59
    private isAccessTokenValid(): boolean {
3✔
60
        return !!(
131✔
61
            this.accessToken &&
131✔
62
            this.accessToken.expires_at !== undefined &&
107✔
63
            this.accessToken.expires_at > Date.now()
107✔
64
        );
65
    }
131✔
66

67
    private getAccessToken = async (): Promise<string | undefined> => {
3✔
68
        if (!this.hasCredentials()) {
131!
69
            return undefined;
×
70
        }
×
71

72
        if (!this.isAccessTokenValid()) {
131✔
73
            this.accessToken = await this.getNewAccessToken();
25✔
74
        }
25✔
75

76
        return this.accessToken?.access_token;
131✔
77
    };
131✔
78

79
    private authMiddleware: Middleware = {
3✔
80
        onRequest: async ({ request, schemaPath }) => {
3✔
81
            if (schemaPath.startsWith("/api/private/unauth") || schemaPath.startsWith("/api/oauth")) {
77!
82
                return undefined;
×
83
            }
×
84

85
            try {
77✔
86
                const accessToken = await this.getAccessToken();
77✔
87
                if (accessToken) {
77✔
88
                    request.headers.set("Authorization", `Bearer ${accessToken}`);
76✔
89
                }
76✔
90
                return request;
77✔
91
            } catch {
77!
92
                // ignore not availble tokens, API will return 401
93
                return undefined;
×
94
            }
×
95
        },
77✔
96
    };
3✔
97

98
    constructor(
3✔
99
        options: ApiClientOptions,
125✔
100
        public readonly logger: LoggerBase
125✔
101
    ) {
125✔
102
        this.options = {
125✔
103
            ...options,
125✔
104
            userAgent:
125✔
105
                options.userAgent ||
125✔
106
                `AtlasMCP/${packageInfo.version} (${process.platform}; ${process.arch}; ${process.env.HOSTNAME || "unknown"})`,
113✔
107
        };
125✔
108

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

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

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

136
            this.client.use(this.authMiddleware);
25✔
137
        }
25✔
138
    }
125✔
139

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

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

156
        return { client: undefined, clientAuth: undefined };
87✔
157
    }
130✔
158

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

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

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

196
        return undefined;
×
197
    }
25✔
198

199
    public async validateAccessToken(): Promise<void> {
3✔
200
        await this.getAccessToken();
19✔
201
    }
19✔
202

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

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

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

236
        if (!response.ok) {
22!
237
            throw await ApiClientError.fromResponse(response);
2✔
238
        }
2!
239

240
        return (await response.json()) as Promise<{
20✔
241
            currentIpv4Address: string;
242
        }>;
243
    }
22✔
244

245
    public async sendEvents(events: TelemetryEvent<CommonProperties>[]): Promise<void> {
3✔
246
        if (!this.options.credentials) {
109!
247
            await this.sendUnauthEvents(events);
91✔
248
            return;
91✔
249
        }
91!
250

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

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

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

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

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

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

303
        if (!response.ok) {
102!
304
            throw await ApiClientError.fromResponse(response);
1✔
305
        }
1✔
306
    }
102✔
307

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

581
    // DO NOT EDIT. This is auto-generated code.
582
}
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