├── .gitignore ├── src ├── helper.js ├── alert.d.ts ├── cloudProviderAccess.d.ts ├── httpClient.js ├── dataLake.d.ts ├── atlasSearch.d.ts ├── alert.js ├── event.d.ts ├── event.js ├── projectWhitelist.d.ts ├── projectAccesslist.d.ts ├── atlasUser.d.ts ├── customDbRole.d.ts ├── cloudBackup.js ├── cloudProviderAccess.js ├── project.d.ts ├── user.d.ts ├── atlasUser.js ├── organization.d.ts ├── projectWhitelist.js ├── user.js ├── projectAccesslist.js ├── customDbRole.js ├── cloudBackup.d.ts ├── dataLake.js ├── index.d.ts ├── organization.js ├── index.js ├── project.js ├── atlasSearch.js ├── cluster.js └── cluster.d.ts ├── .github ├── workflows │ ├── pull_request.yml │ ├── test_npm.yml │ ├── testcoverage.yml │ ├── npmpublish.yml │ └── codeql-analysis.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── copilot-instructions.md ├── LICENSE ├── test ├── helper.test.js ├── event.test.js ├── cloudProviderAccess.test.js ├── cloudbackup.test.js ├── user.test.js ├── customDbRole.test.js ├── projectWhitelist.test.js ├── projectAccesslist.test.js ├── dataLake.test.js ├── alert.test.js ├── organization.test.js ├── project.test.js ├── cluster.test.js ├── atlasUser.test.js └── atlasSearch.test.js ├── package.json └── eslint.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | integration 2 | integ 3 | node_modules 4 | .tmp 5 | .idea 6 | .sass-cache 7 | .eslintcache 8 | npm-debug.log 9 | coverage.html 10 | .vscode 11 | .history 12 | .npmrc 13 | coverage 14 | .coveralls.yml 15 | test-results -------------------------------------------------------------------------------- /src/helper.js: -------------------------------------------------------------------------------- 1 | function getQueryStringFromOptions(options = {}) { 2 | /* eslint-disable no-unused-vars */ 3 | const {httpOptions, ...mongoQueryStringOptions} = options; 4 | const urlparams = new URLSearchParams(mongoQueryStringOptions); 5 | const queryString = urlparams.toString(); 6 | return queryString; 7 | } 8 | 9 | module.exports = { 10 | getQueryStringFromOptions 11 | }; 12 | -------------------------------------------------------------------------------- /src/alert.d.ts: -------------------------------------------------------------------------------- 1 | import {AtlasClientOptions, AtlasError} from '.'; 2 | 3 | // AlertClient 4 | export type AlertId = string; 5 | export interface Alert { 6 | get(alertId: AlertId, options?: AtlasClientOptions): Promise; 7 | getAll(options?: AtlasClientOptions): Promise; 8 | acknowledge(alertId: AlertId, options?: AtlasClientOptions): Promise; 9 | } -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | name: Run tests on pull request create/update 2 | 3 | on: 4 | pull_request: 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | node: [ 18, 20, 22 ] 12 | name: Node ${{ matrix.node }} sample 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Setup node 16 | uses: actions/setup-node@v3 17 | with: 18 | node-version: ${{ matrix.node }} 19 | - run: npm install 20 | - run: npm test -------------------------------------------------------------------------------- /src/cloudProviderAccess.d.ts: -------------------------------------------------------------------------------- 1 | import {AtlasClientOptions, AtlasError} from '.'; 2 | 3 | // DataLakeClient 4 | export type RoleId = string; 5 | export interface CloudProviderAccess { 6 | getAll(options?: AtlasClientOptions): Promise; 7 | delete(cloudProvider: string, roleId: RoleId, options?: AtlasClientOptions): Promise; 8 | update(roleId: RoleId, body: object, options?: AtlasClientOptions): Promise; 9 | create(body: object, options?: AtlasClientOptions): Promise; 10 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /src/httpClient.js: -------------------------------------------------------------------------------- 1 | class HttpClient { 2 | constructor(client, publicKey, privateKey) { 3 | this.client_ = client; 4 | this.digestAuth_ = `${publicKey}:${privateKey}`; 5 | } 6 | 7 | async fetch(url, options) { 8 | const response = await this.client_.request(url, { 9 | "digestAuth": this.digestAuth_, 10 | "dataType": "json", 11 | ...options 12 | }); 13 | 14 | return response.data; 15 | } 16 | 17 | async fetchStream(url, options) { 18 | const response = await this.client_.request(url, { 19 | "digestAuth": this.digestAuth_, 20 | "streaming": true, 21 | ...options 22 | }); 23 | 24 | return response.res; 25 | } 26 | } 27 | 28 | module.exports = HttpClient; 29 | -------------------------------------------------------------------------------- /src/dataLake.d.ts: -------------------------------------------------------------------------------- 1 | import {AtlasClientOptions, AtlasError} from '.'; 2 | 3 | // DataLakeClient 4 | export type DataLakeName = string; 5 | export interface DataLake { 6 | get(dataLakeName: DataLakeName, options?: AtlasClientOptions): Promise; 7 | getAll(options?: AtlasClientOptions): Promise; 8 | getLogsStream(dataLakeName: DataLakeName, options?: AtlasClientOptions): Promise; 9 | delete(dataLakeName: DataLakeName, options?: AtlasClientOptions): Promise; 10 | update(dataLakeName: DataLakeName, body: object, options?: AtlasClientOptions): Promise; 11 | create(body: object, options?: AtlasClientOptions): Promise; 12 | } -------------------------------------------------------------------------------- /.github/workflows/test_npm.yml: -------------------------------------------------------------------------------- 1 | name: test npm 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | publish-npm: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | with: 12 | persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token 13 | fetch-depth: 0 # otherwise, you will failed to push refs to dest repo: 14 | - uses: actions/checkout@v3 15 | with: 16 | node-version: 14 17 | registry-url: https://registry.npmjs.org/ 18 | - name: Authenticate with NPM 19 | run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc 20 | - run: npm whoami 21 | env: 22 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 23 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /src/atlasSearch.d.ts: -------------------------------------------------------------------------------- 1 | import {AtlasClientOptions, AtlasError} from '.'; 2 | 3 | // DataLakeClient 4 | export type ClusterName = string; 5 | export type IndexId = string; 6 | export type DatabaseName = string; 7 | export type CollectionName = string; 8 | 9 | export interface AtlasSearch { 10 | get(clusterName: ClusterName, indexId: IndexId, options?: AtlasClientOptions): Promise; 11 | getAll(clusterName: ClusterName, databaseName: DatabaseName, collectionName: CollectionName, options?: AtlasClientOptions): Promise; 12 | delete(clusterName: ClusterName, indexId: IndexId, options?: AtlasClientOptions): Promise; 13 | update(clusterName: ClusterName, indexId: IndexId, body: object, options?: AtlasClientOptions): Promise; 14 | create(clusterName: ClusterName, body: object, options?: AtlasClientOptions): Promise; 15 | getAllAnalyzers(clusterName: ClusterName, options?: AtlasClientOptions): Promise; 16 | upsertAnalyzer(clusterName: ClusterName, body: object, options?: AtlasClientOptions): Promise; 17 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ashish Modi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /test/helper.test.js: -------------------------------------------------------------------------------- 1 | const {describe, it} = exports.lab = require("@hapi/lab").script(); 2 | const {expect} = require('@hapi/code'); 3 | const {getQueryStringFromOptions} = require('../src/helper.js'); 4 | 5 | describe("Helper Methods", () => { 6 | 7 | describe("When getQueryStringFromOptions is called with emmpty object", () => { 8 | 9 | it("should return empty string", async () => { 10 | const result = getQueryStringFromOptions({}); 11 | expect(result).to.equal(""); 12 | }); 13 | }); 14 | 15 | describe("When getQueryStringFromOptions is called without httpOptions but other properties", () => { 16 | 17 | it("should return other properties as string", async () => { 18 | const result = getQueryStringFromOptions({"a": 1, "b": 23, "httpOptions": {"key": "value"}}); 19 | expect(result).to.equal("a=1&b=23"); 20 | }); 21 | }); 22 | 23 | describe("When getQueryStringFromOptions is called with only httpOptions", () => { 24 | 25 | it("should return empty string", async () => { 26 | const result = getQueryStringFromOptions({"httpOptions": {"key": "value"}}); 27 | expect(result).to.equal(""); 28 | }); 29 | }); 30 | 31 | describe("When getQueryStringFromOptions is called without any parameters", () => { 32 | 33 | it("should return empty string", async () => { 34 | const result = getQueryStringFromOptions(); 35 | expect(result).to.equal(""); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /src/alert.js: -------------------------------------------------------------------------------- 1 | const {getQueryStringFromOptions} = require("./helper"); 2 | 3 | class Alert { 4 | 5 | constructor(client, baseUrl, projectId) { 6 | this.client_ = client; 7 | this.baseUrl_ = baseUrl; 8 | this.projectId_ = projectId; 9 | } 10 | 11 | async getAll(options = {}) { 12 | const queryString = getQueryStringFromOptions(options); 13 | const httpOptions = options.httpOptions; 14 | const response = ( 15 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/alerts?${queryString}`, httpOptions) 16 | ); 17 | return response; 18 | } 19 | 20 | async get(alertId, options = {}) { 21 | const queryString = getQueryStringFromOptions(options); 22 | const httpOptions = options.httpOptions; 23 | const response = ( 24 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/alerts/${alertId}?${queryString}`, httpOptions) 25 | ); 26 | return response; 27 | } 28 | 29 | async acknowledge(alertId, body, options = {}) { 30 | const queryString = getQueryStringFromOptions(options); 31 | const httpOptions = options.httpOptions; 32 | const response = ( 33 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/alerts/${alertId}?${queryString}`, { 34 | "method": "PATCH", 35 | "data": body, 36 | "headers": {"Content-Type": "application/json"}, 37 | ...httpOptions 38 | }) 39 | ); 40 | return response; 41 | } 42 | } 43 | 44 | module.exports = Alert; 45 | 46 | -------------------------------------------------------------------------------- /src/event.d.ts: -------------------------------------------------------------------------------- 1 | import {Links, AtlasResultsResponse, AtlasClientOptions, AtlasError} from "."; 2 | import {OrganizationId} from "./organization"; 3 | 4 | // EventClient 5 | export type EventId = string; 6 | export interface GetEventResponse { 7 | alertId: string; 8 | alertConfigId: string; 9 | apiKeyId: string; 10 | collection: string; 11 | created: string; 12 | currentValue: { 13 | number: number; 14 | units: string; 15 | }; 16 | database: string; 17 | eventTypeName: string; 18 | groupId: string; 19 | hostname: string; 20 | id: string; 21 | invoiceId: string; 22 | isGlobalAdmin: boolean; 23 | links: Links; 24 | metricName: string; 25 | opType: string; 26 | orgId: string; 27 | paymentId: string; 28 | port: number; 29 | publicKey: string; 30 | remoteAddress: string; 31 | replicaSetName: string; 32 | shardName: string; 33 | targetPublicKey: string; 34 | targetUsername: string; 35 | teamId: string; 36 | userId: string; 37 | username: string; 38 | whitelistentry: string; 39 | } 40 | export type GetAllEventsResponse = AtlasResultsResponse; 41 | export interface Event { 42 | get(eventId: EventId, options?: AtlasClientOptions): Promise; 43 | getAll(options?: AtlasClientOptions): Promise; 44 | getByOrganizationId(organizationId: OrganizationId, eventId: EventId, options?: AtlasClientOptions): Promise; 45 | getAllByOrganizationId(organizationId: OrganizationId, options?: AtlasClientOptions): Promise; 46 | } -------------------------------------------------------------------------------- /.github/workflows/testcoverage.yml: -------------------------------------------------------------------------------- 1 | name: Test Coverage 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | jobs: 8 | run-tests: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v1 12 | with: 13 | persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token 14 | fetch-depth: 0 # otherwise, you will failed to push refs to dest repo: 15 | - uses: actions/setup-node@v1 16 | with: 17 | node-version: 20 18 | registry-url: https://registry.npmjs.org/ 19 | - run: npm install 20 | - run: npm test 21 | - name: get specified property 22 | id: repository_type 23 | uses: zoexx/github-action-json-file-properties@release 24 | with: 25 | file_path: "test-results/result.json" 26 | prop_path: "coverage.percent" 27 | 28 | - run: | 29 | echo ${{steps.repository_type.outputs.value}} 30 | 31 | - name: Create badge 32 | uses: emibcn/badge-action@d6f51ff11b5c3382b3b88689ae2d6db22d9737d1 33 | with: 34 | label: Tests 35 | status: 'Tests Coverage: ${{steps.repository_type.outputs.value}}%' 36 | color: '31c653' 37 | path: badge.svg 38 | 39 | - name: Upload badge to Gist 40 | # Upload only for master branch 41 | if: github.ref == 'refs/heads/master' 42 | uses: andymckay/append-gist-action@1fbfbbce708a39bd45846f0955ed5521f2099c6d 43 | with: 44 | token: ${{ secrets.GIST_TOKEN }} 45 | gistURL: https://gist.github.com/montumodi/4863975b3d11c22536fcf9fcc8d237dd 46 | file: badge.svg 47 | -------------------------------------------------------------------------------- /src/event.js: -------------------------------------------------------------------------------- 1 | const {getQueryStringFromOptions} = require("./helper"); 2 | 3 | class Event { 4 | 5 | constructor(client, baseUrl, projectId) { 6 | this.client_ = client; 7 | this.baseUrl_ = baseUrl; 8 | this.projectId_ = projectId; 9 | } 10 | 11 | async get(eventId, options = {}) { 12 | const queryString = getQueryStringFromOptions(options); 13 | const httpOptions = options.httpOptions; 14 | const response = ( 15 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/events/${eventId}?${queryString}`, httpOptions) 16 | ); 17 | return response; 18 | } 19 | 20 | async getAll(options = {}) { 21 | const queryString = getQueryStringFromOptions(options); 22 | const httpOptions = options.httpOptions; 23 | const response = ( 24 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/events?${queryString}`, httpOptions) 25 | ); 26 | return response; 27 | } 28 | 29 | async getByOrganizationId(organizationId, eventId, options = {}) { 30 | const queryString = getQueryStringFromOptions(options); 31 | const httpOptions = options.httpOptions; 32 | const response = ( 33 | await this.client_.fetch(`${this.baseUrl_}/orgs/${organizationId}/events/${eventId}?${queryString}`, httpOptions) 34 | ); 35 | return response; 36 | } 37 | 38 | async getAllByOrganizationId(organizationId, options = {}) { 39 | const queryString = getQueryStringFromOptions(options); 40 | const httpOptions = options.httpOptions; 41 | const response = ( 42 | await this.client_.fetch(`${this.baseUrl_}/orgs/${organizationId}/events?${queryString}`, httpOptions) 43 | ); 44 | return response; 45 | } 46 | 47 | } 48 | 49 | module.exports = Event; 50 | 51 | -------------------------------------------------------------------------------- /src/projectWhitelist.d.ts: -------------------------------------------------------------------------------- 1 | import {Links, AtlasResultsResponse, AtlasClientOptions, AtlasError} from "."; 2 | 3 | // ProjectwhiltelistClient 4 | export type WhitelistEntryName = string; 5 | export interface GetWhitelistEntryResponse { 6 | awsSecurityGroup: string; 7 | cidrBlock: string; 8 | ipAddress: string; 9 | groupId: string; 10 | comment: string; 11 | deleteAftetrDate: string; 12 | links: Links; 13 | } 14 | export type GetAllWhitelistEntriesResponse = AtlasResultsResponse; 15 | export interface CreateWhitelistEntryRequest { 16 | awsSecurityGroup: string; 17 | cidrBlock: string; 18 | ipAddress: string; 19 | comment?: string; 20 | deleteAftetrDate?: string; 21 | } 22 | export type CreateWhitelistEntryResponse = GetWhitelistEntryResponse; 23 | export interface UpdateWhitelistEntryRequest { 24 | awsSecurityGroup: string; 25 | cidrBlock: string; 26 | ipAddress: string; 27 | comment?: string; 28 | deleteAftetrDate?: string; 29 | } 30 | export type UpdateWhitelistEntryResponse = GetWhitelistEntryResponse; 31 | export interface ProjectWhitelist { 32 | get(whitelistentryname: WhitelistEntryName, options?: AtlasClientOptions): Promise; 33 | getAll(options?: AtlasClientOptions): Promise; 34 | delete(whitelistentryname: WhitelistEntryName, options?: AtlasClientOptions): Promise; 35 | create(whitelistentry: CreateWhitelistEntryRequest, options?: AtlasClientOptions): Promise; 36 | update(whitelistentryname: WhitelistEntryName, whitelistentry: UpdateWhitelistEntryRequest, options?: AtlasClientOptions): Promise; 37 | } 38 | -------------------------------------------------------------------------------- /src/projectAccesslist.d.ts: -------------------------------------------------------------------------------- 1 | import {Links, AtlasResultsResponse, AtlasClientOptions, AtlasError} from "."; 2 | 3 | // ProjectaccesslistClient 4 | export type AccesslistEntryName = string; 5 | export interface GetAccesslistEntryResponse { 6 | awsSecurityGroup: string; 7 | cidrBlock: string; 8 | ipAddress: string; 9 | groupId: string; 10 | comment: string; 11 | deleteAfterDate: string; 12 | links: Links; 13 | } 14 | export type GetAllAccesslistEntriesResponse = AtlasResultsResponse; 15 | export interface CreateAccesslistEntryRequest { 16 | awsSecurityGroup: string; 17 | cidrBlock: string; 18 | ipAddress: string; 19 | comment?: string; 20 | deleteAfterDate?: string; 21 | } 22 | export type CreateAccesslistEntryResponse = GetAccesslistEntryResponse; 23 | export interface UpdateAccesslistEntryRequest { 24 | awsSecurityGroup: string; 25 | cidrBlock: string; 26 | ipAddress: string; 27 | comment?: string; 28 | deleteAfterDate?: string; 29 | } 30 | export type UpdateAccesslistEntryResponse = GetAccesslistEntryResponse; 31 | export interface ProjectAccesslist { 32 | get(accesslistentryname: AccesslistEntryName, options?: AtlasClientOptions): Promise; 33 | getAll(options?: AtlasClientOptions): Promise; 34 | delete(accesslistentryname: AccesslistEntryName, options?: AtlasClientOptions): Promise; 35 | create(accesslistentry: CreateAccesslistEntryRequest, options?: AtlasClientOptions): Promise; 36 | update(accesslistentryname: AccesslistEntryName, accesslistentry: UpdateAccesslistEntryRequest, options?: AtlasClientOptions): Promise; 37 | } 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mongodb-atlas-api-client", 3 | "version": "4.12.0", 4 | "description": "A mongodb atlas api client for nodejs.", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "pretest": "npm run depcheck && eslint --cache \"src/**/*.js\" \"test/**/*.js\"", 8 | "depcheck": "depcheck", 9 | "test": "./node_modules/@hapi/lab/bin/lab -I '@@any-promise/REGISTRATION,Symbol(undici.globalDispatcher.1),File' ./test/ -v -S --assert @hapi/code --threshold 100 -p 1 -o test-results/result.json -r json -r console -o stdout", 10 | "lint": "./node_modules/.bin/eslint ./src --fix", 11 | "premajor": "npm run test", 12 | "major": "npm version major -m \"published to npm as v%s\" && git push --follow-tags && npm publish", 13 | "preminor": "npm run test", 14 | "minor": "npm version minor -m \"published to npm as v%s\" && git push --follow-tags && npm publish", 15 | "prepatch": "npm run test", 16 | "patch": "npm version patch -m \"published to npm as v%s\" && git push --follow-tags && npm publish" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/montumodi/mongodb-atlas-api-client.git" 21 | }, 22 | "keywords": [ 23 | "mongo", 24 | "mongodb", 25 | "atlas", 26 | "api", 27 | "client", 28 | "driver", 29 | "nodejs", 30 | "node" 31 | ], 32 | "author": "Ashish Modi", 33 | "license": "ISC", 34 | "bugs": { 35 | "url": "https://github.com/montumodi/mongodb-atlas-api-client/issues" 36 | }, 37 | "homepage": "https://github.com/montumodi/mongodb-atlas-api-client#readme", 38 | "devDependencies": { 39 | "@eslint/js": "^9.38.0", 40 | "@hapi/code": "^9.0.3", 41 | "@hapi/lab": "^25.3.2", 42 | "depcheck": "^1.4.7", 43 | "eslint": "^9.38.0", 44 | "sinon": "^21.0.0" 45 | }, 46 | "dependencies": { 47 | "urllib": "^4.8.2" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/atlasUser.d.ts: -------------------------------------------------------------------------------- 1 | import {OrganizationRoleName} from "./organization"; 2 | import {ProjectRoleName} from "./project"; 3 | import {AtlasResultsResponse, AtlasClientOptions, AtlasError, Links} from "."; 4 | 5 | // AtlasUserclient 6 | export type AtlasUserId = string; 7 | export type AtlasUserName = string; 8 | export interface AtlasUserOrgRole { 9 | orgId: string; 10 | roleName: OrganizationRoleName; 11 | } 12 | export interface AtlasUserGroupRole { 13 | groupId: string; 14 | roleName: ProjectRoleName; 15 | } 16 | export type AtlasUserRole = AtlasUserOrgRole | AtlasUserGroupRole; 17 | export interface GetAtlasUserResponse { 18 | emailAddress: string; 19 | firstName: string; 20 | id: string; 21 | lastName: string; 22 | links: Links; 23 | mobileNumber: string; 24 | roles: AtlasUserRole[]; 25 | teamIds: string[]; 26 | username: string; 27 | } 28 | export type GetAllAtlasUsersResponse = AtlasResultsResponse; 29 | export interface CreateAtlasUserRequest { 30 | emailAddress: string; 31 | firstName: string; 32 | id: string; 33 | lastName: string; 34 | links: Links; 35 | mobileNumber: string; 36 | roles: AtlasUserRole[]; 37 | teamIds: string[]; 38 | username: string; 39 | } 40 | export type CreateAtlasUserResponse = GetAtlasUserResponse; 41 | export interface UpdateAtlasUserRequest {} 42 | export type UpdateAtlasUserResponse = GetAtlasUserResponse; 43 | export interface AtlasUser { 44 | getById(userId: AtlasUserId, options?: AtlasClientOptions): Promise; 45 | getByName(username: AtlasUserName, options?: AtlasClientOptions): Promise; 46 | getAll(options?: AtlasClientOptions): Promise; 47 | create(atlasuser: CreateAtlasUserRequest, options?: AtlasClientOptions): Promise; 48 | update(userId: AtlasUserId, atlasuser: UpdateAtlasUserRequest, options?: AtlasClientOptions): Promise; 49 | } -------------------------------------------------------------------------------- /src/customDbRole.d.ts: -------------------------------------------------------------------------------- 1 | import {AtlasResultsResponse, AtlasClientOptions, AtlasError} from "."; 2 | 3 | // CustomDbRoleClient 4 | export type RoleName = string; 5 | export interface GetCustomDbRoleResponse { 6 | actions: { 7 | action: string; 8 | resources: { 9 | collection: string; 10 | db: string; 11 | cluster: boolean; 12 | }[]; 13 | }[]; 14 | inheritedRoles: { 15 | db: string; 16 | role: string; 17 | }[]; 18 | roleName: string; 19 | } 20 | export type GetAllCustomDbRolesResponse = AtlasResultsResponse; 21 | export interface CreateCustomDbRoleRequest { 22 | actions: { 23 | action: string; 24 | resources: { 25 | collection: string; 26 | db: string; 27 | cluster: boolean; 28 | }[]; 29 | }[]; 30 | inheritedRoles: { 31 | db: string; 32 | role: string; 33 | }[]; 34 | roleName: string; 35 | } 36 | export type CreateCustomDbRoleResponse = GetCustomDbRoleResponse; 37 | export interface UpdateCustomDbRoleRequest { 38 | actions: { 39 | action: string; 40 | resources: { 41 | collection: string; 42 | db: string; 43 | cluster: boolean; 44 | }[]; 45 | }[]; 46 | inheritedRoles: { 47 | db: string; 48 | role: string; 49 | }[]; 50 | roleName: string; 51 | } 52 | export type UpdateCustomDbRoleResponse = GetCustomDbRoleResponse; 53 | export interface CustomDbRole { 54 | get(rolename: RoleName, options?: AtlasClientOptions): Promise; 55 | getAll(options?: AtlasClientOptions): Promise; 56 | delete(rolename: RoleName, options?: AtlasClientOptions): Promise; 57 | create(role: CreateCustomDbRoleRequest, options?: AtlasClientOptions): Promise; 58 | update(rolename: RoleName, role: UpdateCustomDbRoleRequest, options?: AtlasClientOptions): Promise; 59 | } 60 | -------------------------------------------------------------------------------- /src/cloudBackup.js: -------------------------------------------------------------------------------- 1 | const {getQueryStringFromOptions} = require("./helper"); 2 | 3 | class CloudBackup { 4 | 5 | constructor(client, baseUrl, projectId) { 6 | this.client_ = client; 7 | this.baseUrl_ = baseUrl; 8 | this.projectId_ = projectId; 9 | } 10 | 11 | async getReplicaSetCloudBackup(clustername, snapshotId, options = {}) { 12 | const queryString = getQueryStringFromOptions(options); 13 | const httpOptions = options.httpOptions; 14 | const response = ( 15 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clustername}/backup/snapshots/${snapshotId}?${queryString}`, httpOptions) 16 | ); 17 | return response; 18 | } 19 | 20 | async getAllReplicaSetCloudBackups(clustername, options = {}) { 21 | const queryString = getQueryStringFromOptions(options); 22 | const httpOptions = options.httpOptions; 23 | const response = ( 24 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clustername}/backup/snapshots?${queryString}`, httpOptions) 25 | ); 26 | return response; 27 | } 28 | 29 | async getSnapshotRestoreJob(clustername, restoreJobId, options = {}) { 30 | const queryString = getQueryStringFromOptions(options); 31 | const httpOptions = options.httpOptions; 32 | const response = ( 33 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clustername}/backup/restoreJobs/${restoreJobId}?${queryString}`, httpOptions) 34 | ); 35 | return response; 36 | } 37 | 38 | async createSnapshotRestoreJob(clustername, body, options = {}) { 39 | const queryString = getQueryStringFromOptions(options); 40 | const httpOptions = options.httpOptions; 41 | const response = ( 42 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clustername}/backup/restoreJobs?${queryString}`, { 43 | "method": "POST", 44 | "data": body, 45 | "headers": {"Content-Type": "application/json"}, 46 | ...httpOptions 47 | }) 48 | ); 49 | return response; 50 | } 51 | } 52 | 53 | module.exports = CloudBackup; 54 | -------------------------------------------------------------------------------- /src/cloudProviderAccess.js: -------------------------------------------------------------------------------- 1 | const {getQueryStringFromOptions} = require("./helper"); 2 | 3 | class CloudProviderAccess { 4 | 5 | constructor(client, baseUrl, projectId) { 6 | this.client_ = client; 7 | this.baseUrl_ = baseUrl; 8 | this.projectId_ = projectId; 9 | } 10 | 11 | async getAll(options = {}) { 12 | const queryString = getQueryStringFromOptions(options); 13 | const httpOptions = options.httpOptions; 14 | const response = ( 15 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/cloudProviderAccess?${queryString}`, httpOptions) 16 | ); 17 | return response; 18 | } 19 | 20 | async delete(cloudProvider, roleId, options = {}) { 21 | const queryString = getQueryStringFromOptions(options); 22 | const httpOptions = options.httpOptions; 23 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/cloudProviderAccess/${cloudProvider}/${roleId}?${queryString}`, { 24 | "method": "DELETE", 25 | ...httpOptions 26 | }); 27 | return true; 28 | } 29 | 30 | async update(roleId, body, options = {}) { 31 | const queryString = getQueryStringFromOptions(options); 32 | const httpOptions = options.httpOptions; 33 | const response = ( 34 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/cloudProviderAccess/${roleId}?${queryString}`, { 35 | "method": "PATCH", 36 | "data": body, 37 | "headers": {"Content-Type": "application/json"}, 38 | ...httpOptions 39 | }) 40 | ); 41 | return response; 42 | } 43 | 44 | async create(body, options = {}) { 45 | const queryString = getQueryStringFromOptions(options); 46 | const httpOptions = options.httpOptions; 47 | const response = ( 48 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/cloudProviderAccess?${queryString}`, { 49 | "method": "POST", 50 | "data": body, 51 | "headers": {"Content-Type": "application/json"}, 52 | ...httpOptions 53 | }) 54 | ); 55 | return response; 56 | } 57 | } 58 | 59 | module.exports = CloudProviderAccess; 60 | 61 | -------------------------------------------------------------------------------- /src/project.d.ts: -------------------------------------------------------------------------------- 1 | import {Links, AtlasResultsResponse, AtlasClientOptions, AtlasError} from "."; 2 | import {AtlasUserId} from "./atlasUser"; 3 | 4 | // ProjectClient 5 | export type ProjectId = string; 6 | export type ProjectName = string; 7 | export interface GetProjectResponse { 8 | clusterCount: number; 9 | created: string; 10 | id: string; 11 | links: Links; 12 | name: string; 13 | orgId: string; 14 | } 15 | export type GetAllProjectsResponse = AtlasResultsResponse; 16 | export interface CreateProjectRequest { 17 | name: string; 18 | orgId: string; 19 | } 20 | export type CreateProjectResponse = GetProjectResponse; 21 | export interface GetTeamsByProjectResponse { 22 | links: Links; 23 | roleNames: string[]; 24 | teamId: string; 25 | } 26 | export type ProjectRoleName = 'GROUP_OWNER' | 'GROUP_READ_ONLY' | 'GROUP_DATA_ACCESS_ADMIN' | 'GROUP_DATA_ACCESS_READ_WRITE' | 'GROUP_DATA_ACCESS_READ_ONLY'; 27 | export interface AssignTeamsRequest { 28 | teamId: string; 29 | roleNames: ProjectRoleName[] 30 | } 31 | export interface AssignTeamsResponse { 32 | links: Links; 33 | roleNames: string[]; 34 | teamId: string; 35 | } 36 | export interface Project { 37 | getById(projectId: ProjectId, options?: AtlasClientOptions): Promise; 38 | getByName(projectName: ProjectName, options?: AtlasClientOptions): Promise; 39 | getTeamsByProjectId(projectId: ProjectId, options?: AtlasClientOptions): Promise; 40 | getAll(options?: AtlasClientOptions): Promise; 41 | delete(projectId: ProjectId, options?: AtlasClientOptions): Promise; 42 | removeUserFromProject(projectId: ProjectId, userId: AtlasUserId, options?: AtlasClientOptions): Promise; 43 | create(project: CreateProjectRequest, options?: AtlasClientOptions): Promise; 44 | assignTeams(projectId: ProjectId, teams: AssignTeamsRequest[], options?: AtlasClientOptions): Promise; 45 | } -------------------------------------------------------------------------------- /.github/workflows/npmpublish.yml: -------------------------------------------------------------------------------- 1 | name: Node.js Package 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | npm_otp: 7 | description: enter npm otp 8 | required: true 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | strategy: 13 | matrix: 14 | node: [ 18, 20, 22 ] 15 | name: Node ${{ matrix.node }} sample 16 | steps: 17 | - uses: actions/checkout@v3 18 | - name: Setup node 19 | uses: actions/setup-node@v3 20 | with: 21 | node-version: ${{ matrix.node }} 22 | - run: npm install 23 | - run: npm test 24 | publish-npm: 25 | runs-on: ubuntu-latest 26 | needs: build 27 | steps: 28 | - uses: actions/checkout@v3 29 | with: 30 | persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token 31 | fetch-depth: 0 # otherwise, you will failed to push refs to dest repo: 32 | - uses: actions/checkout@v3 33 | with: 34 | node-version: 14 35 | registry-url: https://registry.npmjs.org/ 36 | - run: npm update 37 | - run: npm install 38 | - run: npm audit fix 39 | - run: npm test 40 | - run: git config --global user.email "montumodi@gmail.com" 41 | - run: git config --global user.name "Ashish Modi" 42 | - run: git commit -m "Add changes" -a 43 | env: 44 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 45 | - name: Push changes 46 | uses: ad-m/github-push-action@master 47 | with: 48 | github_token: ${{ secrets.GITHUB_TOKEN }} 49 | branch: ${{ github.ref }} 50 | - run: npm version minor 51 | - name: Authenticate with NPM 52 | run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc 53 | - name: Push changes 54 | uses: ad-m/github-push-action@master 55 | with: 56 | github_token: ${{ secrets.GITHUB_TOKEN }} 57 | branch: ${{ github.ref }} 58 | - run: npm publish --otp ${{github.event.inputs.npm_otp}} 59 | env: 60 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 61 | -------------------------------------------------------------------------------- /src/user.d.ts: -------------------------------------------------------------------------------- 1 | import {KeyValuePairDocumentArray, AtlasResultsResponse, AtlasClientOptions, AtlasError} from "."; 2 | 3 | // UserClient 4 | export type Username = string; 5 | export interface GetUserResponse { 6 | databaseName: string; 7 | deleteAfterDate: string; 8 | labels: KeyValuePairDocumentArray; 9 | ladapAuthType: string; 10 | x509Type: string; 11 | groupId: string; 12 | roles: UserRoleConfig[]; 13 | scopes: UserScopeConfig[]; 14 | password: string; 15 | username: string; 16 | } 17 | export type GetAllUsersResponse = AtlasResultsResponse; 18 | export interface CreateUserRequest { 19 | databaseName: string; 20 | deleteAfterDate?: string; 21 | labels?: KeyValuePairDocumentArray; 22 | ladapAuthType?: string; 23 | x509Type?: string; 24 | groupId: string; 25 | roles: UserRoleConfig[]; 26 | password: string; 27 | username: string; 28 | scopes?: UserScopeConfig[]; 29 | } 30 | export type CreateUserResponse = GetUserResponse; 31 | export interface UserRoleConfig { 32 | collectionName?: string; 33 | databaseName: string; 34 | roleName: string; 35 | } 36 | export interface UserScopeConfig { 37 | name: string; 38 | type: string; 39 | } 40 | export interface UpdateUserRequest { 41 | /** 42 | * ISO 8601 Date 43 | * ex: `new Date(string).toISOString();` 44 | */ 45 | deleteAfterDate?: string; 46 | labels?: KeyValuePairDocumentArray; 47 | roles?: UserRoleConfig[]; 48 | password?: string; 49 | scopes?: UserScopeConfig[]; 50 | } 51 | export type UpdateUserResponse = GetUserResponse; 52 | export interface User { 53 | get(username: Username, options?: AtlasClientOptions): Promise; 54 | getAll(options?: AtlasClientOptions): Promise; 55 | delete(username: Username, options?: AtlasClientOptions): Promise; 56 | create(user: CreateUserRequest, options?: AtlasClientOptions): Promise; 57 | update(username: Username, user: UpdateUserRequest, options?: AtlasClientOptions): Promise; 58 | } 59 | -------------------------------------------------------------------------------- /src/atlasUser.js: -------------------------------------------------------------------------------- 1 | const {getQueryStringFromOptions} = require("./helper"); 2 | 3 | class AtlasUser { 4 | 5 | constructor(client, baseUrl, projectId) { 6 | this.client_ = client; 7 | this.baseUrl_ = baseUrl; 8 | this.projectId_ = projectId; 9 | } 10 | 11 | async getByName(username, options = {}) { 12 | const queryString = getQueryStringFromOptions(options); 13 | const httpOptions = options.httpOptions; 14 | const response = ( 15 | await this.client_.fetch(`${this.baseUrl_}/users/byName/${username}?${queryString}`, httpOptions) 16 | ); 17 | return response; 18 | } 19 | 20 | async getById(userId, options = {}) { 21 | const queryString = getQueryStringFromOptions(options); 22 | const httpOptions = options.httpOptions; 23 | const response = ( 24 | await this.client_.fetch(`${this.baseUrl_}/users/${userId}?${queryString}`, httpOptions) 25 | ); 26 | return response; 27 | } 28 | 29 | async getAll(options = {}) { 30 | const queryString = getQueryStringFromOptions(options); 31 | const httpOptions = options.httpOptions; 32 | const response = ( 33 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/users?${queryString}`, httpOptions) 34 | ); 35 | return response; 36 | } 37 | 38 | async update(userId, body, options = {}) { 39 | const queryString = getQueryStringFromOptions(options); 40 | const httpOptions = options.httpOptions; 41 | const response = ( 42 | await this.client_.fetch(`${this.baseUrl_}/users/${userId}?${queryString}`, { 43 | "method": "PATCH", 44 | "data": body, 45 | "headers": {"Content-Type": "application/json"}, 46 | ...httpOptions 47 | }) 48 | ); 49 | return response; 50 | } 51 | 52 | async create(body, options = {}) { 53 | const queryString = getQueryStringFromOptions(options); 54 | const httpOptions = options.httpOptions; 55 | const response = ( 56 | await this.client_.fetch(`${this.baseUrl_}/users?${queryString}`, { 57 | "method": "POST", 58 | "data": body, 59 | "headers": {"Content-Type": "application/json"}, 60 | ...httpOptions 61 | }) 62 | ); 63 | return response; 64 | } 65 | } 66 | 67 | module.exports = AtlasUser; 68 | 69 | -------------------------------------------------------------------------------- /src/organization.d.ts: -------------------------------------------------------------------------------- 1 | import {Links, AtlasResultsResponse, AtlasClientOptions, AtlasError} from "."; 2 | import {GetAtlasUserResponse} from "./atlasUser"; 3 | import {GetAllProjectsResponse} from "./project"; 4 | 5 | // OrganizationClient 6 | export type OrganizationId = string; 7 | export type OrganizationRoleName = 'ORG_OWNER' | 'ORG_GROUP_CREATOR' | 'ORG_BILLING_ADMIN' | 'ORG_READ_ONLY' | 'ORG_MEMBER'; 8 | export interface GetOrganizationResponse { 9 | id: string; 10 | name: string; 11 | links: Links; 12 | } 13 | export type GetAllOrganizationsResponse = AtlasResultsResponse; 14 | export interface RenameOrganizationRequest { 15 | /** 16 | * The new name for the organization. 17 | */ 18 | name: string; 19 | } 20 | 21 | export interface InviteOneToOrganizationRequest { 22 | roles: string[], 23 | teamIds?: string[], 24 | username: string, 25 | } 26 | 27 | export interface InviteOneToOrganizationResponse { 28 | createdAt: string, 29 | expiresAt: string, 30 | id: string, 31 | inviterUsername: string, 32 | orgId: string, 33 | orgName: string, 34 | roles: string[], 35 | teamIds: string[], 36 | username: string, 37 | } 38 | export type RenameOrganizationResponse = GetOrganizationResponse; 39 | export interface Organization { 40 | getById(organizationId: OrganizationId, options?: AtlasClientOptions): Promise; 41 | getAllUsersForOrganization(organizationId: OrganizationId, options?: AtlasClientOptions): Promise | AtlasError>; 42 | getAllProjectsForOrganization(organizationId: OrganizationId, options?: AtlasClientOptions): Promise; 43 | getAll(options?: AtlasClientOptions): Promise; 44 | delete(organizationId: OrganizationId, options?: AtlasClientOptions): Promise; 45 | rename(organizationId: OrganizationId, organization: RenameOrganizationRequest, options?: AtlasClientOptions): Promise; 46 | invite(organizationId: OrganizationId, organization: InviteOneToOrganizationRequest, options?: AtlasClientOptions): Promise; 47 | } 48 | -------------------------------------------------------------------------------- /src/projectWhitelist.js: -------------------------------------------------------------------------------- 1 | const {getQueryStringFromOptions} = require("./helper"); 2 | 3 | class ProjectWhitelist { 4 | 5 | constructor(client, baseUrl, projectId) { 6 | this.client_ = client; 7 | this.baseUrl_ = baseUrl; 8 | this.projectId_ = projectId; 9 | } 10 | 11 | async get(whitelistentry, options = {}) { 12 | const queryString = getQueryStringFromOptions(options); 13 | const httpOptions = options.httpOptions; 14 | const response = ( 15 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/whitelist/${whitelistentry}?${queryString}`, httpOptions) 16 | ); 17 | return response; 18 | } 19 | 20 | async getAll(options = {}) { 21 | const queryString = getQueryStringFromOptions(options); 22 | const httpOptions = options.httpOptions; 23 | const response = ( 24 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/whitelist?${queryString}`, httpOptions) 25 | ); 26 | return response; 27 | } 28 | 29 | async delete(whitelistentry, options = {}) { 30 | const queryString = getQueryStringFromOptions(options); 31 | const httpOptions = options.httpOptions; 32 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/whitelist/${whitelistentry}?${queryString}`, { 33 | "method": "DELETE", 34 | ...httpOptions 35 | }); 36 | return true; 37 | } 38 | 39 | async update(body, options = {}) { 40 | const queryString = getQueryStringFromOptions(options); 41 | const httpOptions = options.httpOptions; 42 | const response = ( 43 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/whitelist?${queryString}`, { 44 | "method": "POST", 45 | "data": body, 46 | "headers": {"Content-Type": "application/json"}, 47 | ...httpOptions 48 | }) 49 | ); 50 | return response; 51 | } 52 | 53 | async create(body, options = {}) { 54 | const queryString = getQueryStringFromOptions(options); 55 | const httpOptions = options.httpOptions; 56 | const response = ( 57 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/whitelist?${queryString}`, { 58 | "method": "POST", 59 | "data": body, 60 | "headers": {"Content-Type": "application/json"}, 61 | ...httpOptions 62 | }) 63 | ); 64 | return response; 65 | } 66 | } 67 | 68 | module.exports = ProjectWhitelist; 69 | 70 | -------------------------------------------------------------------------------- /src/user.js: -------------------------------------------------------------------------------- 1 | const {getQueryStringFromOptions} = require("./helper"); 2 | 3 | class User { 4 | 5 | constructor(client, baseUrl, projectId) { 6 | this.client_ = client; 7 | this.baseUrl_ = baseUrl; 8 | this.projectId_ = projectId; 9 | } 10 | 11 | async get(username, options = {}) { 12 | const queryString = getQueryStringFromOptions(options); 13 | const httpOptions = options.httpOptions; 14 | const response = ( 15 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/databaseUsers/admin/${username}?${queryString}`, httpOptions) 16 | ); 17 | return response; 18 | } 19 | 20 | async getAll(options = {}) { 21 | const queryString = getQueryStringFromOptions(options); 22 | const httpOptions = options.httpOptions; 23 | const response = ( 24 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/databaseUsers?${queryString}`, httpOptions) 25 | ); 26 | return response; 27 | } 28 | 29 | async delete(username, options = {}) { 30 | const queryString = getQueryStringFromOptions(options); 31 | const httpOptions = options.httpOptions; 32 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/databaseUsers/admin/${username}?${queryString}`, { 33 | "method": "DELETE", 34 | ...httpOptions 35 | }); 36 | return true; 37 | } 38 | 39 | async update(username, body, options = {}) { 40 | const queryString = getQueryStringFromOptions(options); 41 | const httpOptions = options.httpOptions; 42 | const response = ( 43 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/databaseUsers/admin/${username}?${queryString}`, { 44 | "method": "PATCH", 45 | "data": body, 46 | "headers": {"Content-Type": "application/json"}, 47 | ...httpOptions 48 | }) 49 | ); 50 | return response; 51 | } 52 | 53 | async create(body, options = {}) { 54 | const queryString = getQueryStringFromOptions(options); 55 | const httpOptions = options.httpOptions; 56 | const response = ( 57 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/databaseUsers?${queryString}`, { 58 | "method": "POST", 59 | "data": body, 60 | "headers": {"Content-Type": "application/json"}, 61 | ...httpOptions 62 | }) 63 | ); 64 | return response; 65 | } 66 | } 67 | 68 | module.exports = User; 69 | 70 | -------------------------------------------------------------------------------- /src/projectAccesslist.js: -------------------------------------------------------------------------------- 1 | const {getQueryStringFromOptions} = require("./helper"); 2 | 3 | class ProjectAccesslist { 4 | 5 | constructor(client, baseUrl, projectId) { 6 | this.client_ = client; 7 | this.baseUrl_ = baseUrl; 8 | this.projectId_ = projectId; 9 | } 10 | 11 | async get(accesslistentry, options = {}) { 12 | const queryString = getQueryStringFromOptions(options); 13 | const httpOptions = options.httpOptions; 14 | const response = ( 15 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/accessList/${accesslistentry}?${queryString}`, httpOptions) 16 | ); 17 | return response; 18 | } 19 | 20 | async getAll(options = {}) { 21 | const queryString = getQueryStringFromOptions(options); 22 | const httpOptions = options.httpOptions; 23 | const response = ( 24 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/accessList?${queryString}`, httpOptions) 25 | ); 26 | return response; 27 | } 28 | 29 | async delete(accesslistentry, options = {}) { 30 | const queryString = getQueryStringFromOptions(options); 31 | const httpOptions = options.httpOptions; 32 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/accessList/${accesslistentry}?${queryString}`, { 33 | "method": "DELETE", 34 | ...httpOptions 35 | }); 36 | return true; 37 | } 38 | 39 | async update(body, options = {}) { 40 | const queryString = getQueryStringFromOptions(options); 41 | const httpOptions = options.httpOptions; 42 | const response = ( 43 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/accessList?${queryString}`, { 44 | "method": "POST", 45 | "data": body, 46 | "headers": {"Content-Type": "application/json"}, 47 | ...httpOptions 48 | }) 49 | ); 50 | return response; 51 | } 52 | 53 | async create(body, options = {}) { 54 | const queryString = getQueryStringFromOptions(options); 55 | const httpOptions = options.httpOptions; 56 | const response = ( 57 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/accessList?${queryString}`, { 58 | "method": "POST", 59 | "data": body, 60 | "headers": {"Content-Type": "application/json"}, 61 | ...httpOptions 62 | }) 63 | ); 64 | return response; 65 | } 66 | } 67 | 68 | module.exports = ProjectAccesslist; 69 | 70 | -------------------------------------------------------------------------------- /src/customDbRole.js: -------------------------------------------------------------------------------- 1 | const {getQueryStringFromOptions} = require("./helper"); 2 | 3 | class CustomDbRole { 4 | 5 | constructor(client, baseUrl, projectId) { 6 | this.client_ = client; 7 | this.baseUrl_ = baseUrl; 8 | this.projectId_ = projectId; 9 | } 10 | 11 | async get(rolename, options = {}) { 12 | const queryString = getQueryStringFromOptions(options); 13 | const httpOptions = options.httpOptions; 14 | const response = ( 15 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/customDBRoles/roles/${rolename}?${queryString}`, httpOptions) 16 | ); 17 | return response; 18 | } 19 | 20 | async getAll(options = {}) { 21 | const queryString = getQueryStringFromOptions(options); 22 | const httpOptions = options.httpOptions; 23 | const response = ( 24 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/customDBRoles/roles?${queryString}`, httpOptions) 25 | ); 26 | return response; 27 | } 28 | 29 | async delete(rolename, options = {}) { 30 | const queryString = getQueryStringFromOptions(options); 31 | const httpOptions = options.httpOptions; 32 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/customDBRoles/roles/${rolename}?${queryString}`, { 33 | "method": "DELETE", 34 | ...httpOptions 35 | }); 36 | return true; 37 | } 38 | 39 | async update(rolename, body, options = {}) { 40 | const queryString = getQueryStringFromOptions(options); 41 | const httpOptions = options.httpOptions; 42 | const response = ( 43 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/customDBRoles/roles/${rolename}?${queryString}`, { 44 | "method": "PATCH", 45 | "data": body, 46 | "headers": {"Content-Type": "application/json"}, 47 | ...httpOptions 48 | }) 49 | ); 50 | return response; 51 | } 52 | 53 | async create(body, options = {}) { 54 | const queryString = getQueryStringFromOptions(options); 55 | const httpOptions = options.httpOptions; 56 | const response = ( 57 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/customDBRoles/roles?${queryString}`, { 58 | "method": "POST", 59 | "data": body, 60 | "headers": {"Content-Type": "application/json"}, 61 | ...httpOptions 62 | }) 63 | ); 64 | return response; 65 | } 66 | } 67 | 68 | module.exports = CustomDbRole; 69 | 70 | -------------------------------------------------------------------------------- /src/cloudBackup.d.ts: -------------------------------------------------------------------------------- 1 | import {ClusterName, Links, AtlasResultsResponse, AtlasClientOptions, AtlasError} from "."; 2 | 3 | export interface GetReplicaSetCloudBackup { 4 | cloudProvider: 'AWS' | 'GCP' | 'AZURE' | 'TENANT'; 5 | copyRegions: string[]; 6 | createdAt: string; 7 | description?: string; 8 | expiresAt: string; 9 | frequencyType: 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly'; 10 | id: string; 11 | links: Links; 12 | masterKeyUUID?: string; 13 | mongodVersion: string; 14 | policyItems: Array; 15 | replicaSetName: string; 16 | snapshotType: 'onDemand' | 'scheduled'; 17 | status: 'queued' | 'inProgress' | 'completed' | 'failed'; 18 | storageSizeBytes: number; 19 | type: string 20 | } 21 | 22 | export type GetAllReplicaSetCloudBackups = AtlasResultsResponse; 23 | 24 | export interface SnapshotRestoreJobComponent { 25 | replicaSetName: string 26 | } 27 | 28 | export type SnapshotRestoreJobComponents = SnapshotRestoreJobComponent[] 29 | 30 | export interface GetSnapshotRestoreJob { 31 | cancelled?: boolean; 32 | components?: SnapshotRestoreJobComponents; 33 | deliveryType: 'automated' | 'download' | 'pointInTime'; 34 | deliveryUrl?: string[]; 35 | desiredTimestamp?: { 36 | date: string; 37 | increment: number 38 | }; 39 | expired?: boolean; 40 | expiresAt?: string; 41 | failed?: boolean; 42 | finishedAt?: string; 43 | id?: string; 44 | links?: Links; 45 | oplogInc?: number; 46 | oplogTs?: number; 47 | pointInTimeUTCSeconds?: number; 48 | snapshotId?: string; 49 | targetClusterName?: string; 50 | targetGroupId?: string; 51 | timestamp?: string 52 | } 53 | 54 | export interface SnapshotRestoreJobRequest { 55 | deliveryType: 'automated' | 'download' | 'pointInTime'; 56 | oplogInc?: number; 57 | oplogTs?: number; 58 | pointInTimeUTCSeconds?: number; 59 | snapshotId?: string; 60 | targetClusterName?: string; 61 | targetGroupId?: string 62 | } 63 | export type CreateSnapshotRestoreJobResponse = GetSnapshotRestoreJob; 64 | 65 | export interface CloudBackup { 66 | getReplicaSetCloudBackup(clustername: ClusterName, snapshotId: string, options?: AtlasClientOptions): Promise; 67 | getAllReplicaSetCloudBackups(clustername: ClusterName, options?: AtlasClientOptions): Promise; 68 | getSnapshotRestoreJob(clustername: ClusterName, restoreJobId: string, options?: AtlasClientOptions): Promise 69 | createSnapshotRestoreJob(clustername: ClusterName, body: SnapshotRestoreJobRequest, options?: AtlasClientOptions): Promise 70 | } -------------------------------------------------------------------------------- /src/dataLake.js: -------------------------------------------------------------------------------- 1 | const {getQueryStringFromOptions} = require("./helper"); 2 | 3 | class DataLake { 4 | 5 | constructor(client, baseUrl, projectId) { 6 | this.client_ = client; 7 | this.baseUrl_ = baseUrl; 8 | this.projectId_ = projectId; 9 | } 10 | 11 | async get(dataLakeName, options = {}) { 12 | const queryString = getQueryStringFromOptions(options); 13 | const httpOptions = options.httpOptions; 14 | const response = ( 15 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/dataLakes/${dataLakeName}?${queryString}`, httpOptions) 16 | ); 17 | return response; 18 | } 19 | 20 | async getLogsStream(dataLakeName, options = {}) { 21 | const queryString = getQueryStringFromOptions(options); 22 | const httpOptions = options.httpOptions; 23 | const response = await this.client_.fetchStream(`${this.baseUrl_}/groups/${this.projectId_}/dataLakes/${dataLakeName}/queryLogs.gz?${queryString}`, { 24 | "gzip": true, 25 | ...httpOptions 26 | }); 27 | return response; 28 | } 29 | 30 | async getAll(options = {}) { 31 | const queryString = getQueryStringFromOptions(options); 32 | const httpOptions = options.httpOptions; 33 | const response = ( 34 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/dataLakes?${queryString}`, httpOptions) 35 | ); 36 | return response; 37 | } 38 | 39 | async delete(dataLakeName, options = {}) { 40 | const queryString = getQueryStringFromOptions(options); 41 | const httpOptions = options.httpOptions; 42 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/dataLakes/${dataLakeName}?${queryString}`, { 43 | "method": "DELETE", 44 | ...httpOptions 45 | }); 46 | return true; 47 | } 48 | 49 | async update(dataLakeName, body, options = {}) { 50 | const queryString = getQueryStringFromOptions(options); 51 | const httpOptions = options.httpOptions; 52 | const response = ( 53 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/dataLakes/${dataLakeName}?${queryString}`, { 54 | "method": "PATCH", 55 | "data": body, 56 | "headers": {"Content-Type": "application/json"}, 57 | ...httpOptions 58 | }) 59 | ); 60 | return response; 61 | } 62 | 63 | async create(body, options = {}) { 64 | const queryString = getQueryStringFromOptions(options); 65 | const httpOptions = options.httpOptions; 66 | const response = ( 67 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/dataLakes?${queryString}`, { 68 | "method": "POST", 69 | "data": body, 70 | "headers": {"Content-Type": "application/json"}, 71 | ...httpOptions 72 | }) 73 | ); 74 | return response; 75 | } 76 | } 77 | 78 | module.exports = DataLake; 79 | 80 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ master ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ master ] 20 | schedule: 21 | - cron: '39 7 * * 2' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | -------------------------------------------------------------------------------- /src/index.d.ts: -------------------------------------------------------------------------------- 1 | import {Alert} from './alert' 2 | import {AtlasUser} from './atlasUser'; 3 | import {Cluster} from './cluster'; 4 | import {CloudBackup} from './cloudBackup'; 5 | import {CustomDbRole} from './customDbRole'; 6 | import {Event} from './event'; 7 | import {Organization} from './organization'; 8 | import {Project} from './project'; 9 | import {ProjectWhitelist} from './projectWhitelist'; 10 | import {ProjectAccesslist} from './projectAccesslist'; 11 | import {User} from './user'; 12 | import {DataLake} from './dataLake'; 13 | import {CloudProviderAccess} from './cloudProviderAccess'; 14 | import {AtlasSearch} from './atlasSearch'; 15 | 16 | export * from './alert' 17 | export * from './atlasUser'; 18 | export * from './cluster'; 19 | export * from './cloudBackup'; 20 | export * from './customDbRole'; 21 | export * from './event'; 22 | export * from './organization'; 23 | export * from './project'; 24 | export * from './projectWhitelist'; 25 | export * from './projectAccesslist'; 26 | export * from './user'; 27 | export * from './dataLake' 28 | export * from './cloudProviderAccess'; 29 | export * from './atlasSearch'; 30 | 31 | export interface KeyValuePairDocument { 32 | key: string; 33 | value: string; 34 | } 35 | 36 | export type KeyValuePairDocumentArray = KeyValuePairDocument[]; 37 | 38 | export interface AtlasResultsResponse { 39 | results: T[]; 40 | links: Links; 41 | totalCount: number; 42 | } 43 | 44 | export interface Link { 45 | href: string; 46 | rel: string; 47 | } 48 | 49 | export type Links = Link[]; 50 | 51 | export interface AtlasError { 52 | details: string; 53 | error: number; 54 | errorCode: string; 55 | reason: string; 56 | } 57 | 58 | export type ResponseOrError = T | AtlasError; 59 | 60 | // Atlas Client 61 | export interface AtlasClient { 62 | user: User; 63 | alert: Alert; 64 | atlasUser: AtlasUser; 65 | organization: Organization; 66 | project: Project; 67 | projectWhitelist: ProjectWhitelist; 68 | projectAccesslist: ProjectAccesslist; 69 | customDbRole: CustomDbRole; 70 | cluster: Cluster; 71 | cloudBackup: CloudBackup; 72 | event: Event; 73 | dataLake: DataLake; 74 | cloudProviderAccess: CloudProviderAccess; 75 | atlasSearch: AtlasSearch 76 | } 77 | 78 | export interface AtlasClientConfig { 79 | /** 80 | * API Access Public Key 81 | */ 82 | publicKey: string; 83 | /** 84 | * API Access Private Key 85 | */ 86 | privateKey: string; 87 | /** 88 | * Base URL for Atlas API 89 | */ 90 | baseUrl: string; 91 | /** 92 | * Target Project ID in Atlas account 93 | */ 94 | projectId?: String; 95 | } 96 | 97 | export interface AtlasClientOptions { 98 | envelope?: boolean; 99 | itemsPerPage?: number; 100 | pretty?: boolean; 101 | } 102 | 103 | export default function getMongodbAtlasApiClient(config: AtlasClientConfig): AtlasClient; 104 | -------------------------------------------------------------------------------- /src/organization.js: -------------------------------------------------------------------------------- 1 | const {getQueryStringFromOptions} = require("./helper"); 2 | 3 | class Organization { 4 | 5 | constructor(client, baseUrl) { 6 | this.client_ = client; 7 | this.baseUrl_ = baseUrl; 8 | } 9 | 10 | async getById(organizationId, options = {}) { 11 | const queryString = getQueryStringFromOptions(options); 12 | const httpOptions = options.httpOptions; 13 | const response = ( 14 | await this.client_.fetch(`${this.baseUrl_}/orgs/${organizationId}?${queryString}`, httpOptions) 15 | ); 16 | return response; 17 | } 18 | 19 | async getAllUsersForOrganization(organizationId, options = {}) { 20 | const queryString = getQueryStringFromOptions(options); 21 | const httpOptions = options.httpOptions; 22 | const response = ( 23 | await this.client_.fetch(`${this.baseUrl_}/orgs/${organizationId}/users?${queryString}`, httpOptions) 24 | ); 25 | return response; 26 | } 27 | 28 | async getAllProjectsForOrganization(organizationId, options = {}) { 29 | const queryString = getQueryStringFromOptions(options); 30 | const httpOptions = options.httpOptions; 31 | const response = ( 32 | await this.client_.fetch(`${this.baseUrl_}/orgs/${organizationId}/groups?${queryString}`, httpOptions) 33 | ); 34 | return response; 35 | } 36 | 37 | async getAll(options = {}) { 38 | const queryString = getQueryStringFromOptions(options); 39 | const httpOptions = options.httpOptions; 40 | const response = ( 41 | await this.client_.fetch(`${this.baseUrl_}/orgs?${queryString}`, httpOptions) 42 | ); 43 | return response; 44 | } 45 | 46 | async delete(organizationId, options = {}) { 47 | const queryString = getQueryStringFromOptions(options); 48 | const httpOptions = options.httpOptions; 49 | await this.client_.fetch(`${this.baseUrl_}/orgs/${organizationId}?${queryString}`, { 50 | "method": "DELETE", 51 | ...httpOptions 52 | }); 53 | return true; 54 | } 55 | 56 | async rename(organizationId, body, options = {}) { 57 | const queryString = getQueryStringFromOptions(options); 58 | const httpOptions = options.httpOptions; 59 | const response = ( 60 | await this.client_.fetch(`${this.baseUrl_}/orgs/${organizationId}?${queryString}`, { 61 | "method": "PATCH", 62 | "data": body, 63 | "headers": {"Content-Type": "application/json"}, 64 | ...httpOptions 65 | }) 66 | ); 67 | return response; 68 | } 69 | 70 | async invite(organizationId, body, options = {}) { 71 | const queryString = getQueryStringFromOptions(options); 72 | const httpOptions = options.httpOptions; 73 | const response = ( 74 | await this.client_.fetch(`${this.baseUrl_}/orgs/${organizationId}/invites?${queryString}`, { 75 | "method": "POST", 76 | "data": body, 77 | "headers": {"Content-Type": "application/json"}, 78 | ...httpOptions 79 | }) 80 | ); 81 | return response; 82 | } 83 | } 84 | 85 | module.exports = Organization; 86 | 87 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const User = require("./user"); 2 | const CloudBackup = require("./cloudBackup"); 3 | const Cluster = require("./cluster"); 4 | const CustomDbRole = require("./customDbRole"); 5 | const ProjectWhitelist = require("./projectWhitelist"); 6 | const ProjectAccesslist = require("./projectAccesslist"); 7 | const Project = require("./project"); 8 | const Organization = require("./organization"); 9 | const AtlasUser = require("./atlasUser"); 10 | const Event = require("./event"); 11 | const Alert = require("./alert"); 12 | const DataLake = require("./dataLake"); 13 | const CloudProviderAccess = require("./cloudProviderAccess"); 14 | const AtlasSearch = require("./atlasSearch"); 15 | const urllibClient = require("urllib"); 16 | const HttpClient = require("./httpClient"); 17 | 18 | function getFunctions(instance) { 19 | const functions = {}; 20 | Object.getOwnPropertyNames(Object.getPrototypeOf(instance)) 21 | .filter(name => name !== "constructor") 22 | .forEach(functionName => { 23 | functions[functionName] = instance[functionName].bind(instance); 24 | }); 25 | return functions; 26 | } 27 | 28 | 29 | function getMongodbAtlasApiClient(options) { 30 | 31 | const client = new HttpClient(urllibClient, options.publicKey, options.privateKey); 32 | const user = new User(client, options.baseUrl, options.projectId); 33 | const cluster = new Cluster(client, options.baseUrl, options.projectId); 34 | const cloudBackup = new CloudBackup(client, options.baseUrl, options.projectId); 35 | const customDbRole = new CustomDbRole(client, options.baseUrl, options.projectId); 36 | const projectWhitelist = new ProjectWhitelist(client, options.baseUrl, options.projectId); 37 | const projectAccesslist = new ProjectAccesslist(client, options.baseUrl, options.projectId); 38 | const project = new Project(client, options.baseUrl); 39 | const organization = new Organization(client, options.baseUrl); 40 | const atlasUser = new AtlasUser(client, options.baseUrl, options.projectId); 41 | const event = new Event(client, options.baseUrl, options.projectId); 42 | const alert = new Alert(client, options.baseUrl, options.projectId); 43 | const dataLake = new DataLake(client, options.baseUrl, options.projectId); 44 | const cloudProviderAccess = new CloudProviderAccess(client, options.baseUrl, options.projectId); 45 | const atlasSearch = new AtlasSearch(client, options.baseUrl, options.projectId); 46 | 47 | const functions = {}; 48 | functions.user = getFunctions(user); 49 | functions.cluster = getFunctions(cluster); 50 | functions.cloudBackup = getFunctions(cloudBackup); 51 | functions.customDbRole = getFunctions(customDbRole); 52 | functions.projectWhitelist = getFunctions(projectWhitelist); 53 | functions.projectAccesslist = getFunctions(projectAccesslist); 54 | functions.project = getFunctions(project); 55 | functions.organization = getFunctions(organization); 56 | functions.atlasUser = getFunctions(atlasUser); 57 | functions.event = getFunctions(event); 58 | functions.alert = getFunctions(alert); 59 | functions.dataLake = getFunctions(dataLake); 60 | functions.cloudProviderAccess = getFunctions(cloudProviderAccess); 61 | functions.atlasSearch = getFunctions(atlasSearch); 62 | 63 | return functions; 64 | } 65 | 66 | module.exports = getMongodbAtlasApiClient; 67 | 68 | -------------------------------------------------------------------------------- /src/project.js: -------------------------------------------------------------------------------- 1 | const {getQueryStringFromOptions} = require("./helper"); 2 | 3 | class Project { 4 | 5 | constructor(client, baseUrl) { 6 | this.client_ = client; 7 | this.baseUrl_ = baseUrl; 8 | } 9 | 10 | async getById(projectId, options = {}) { 11 | const queryString = getQueryStringFromOptions(options); 12 | const httpOptions = options.httpOptions; 13 | const response = ( 14 | await this.client_.fetch(`${this.baseUrl_}/groups/${projectId}?${queryString}`, httpOptions) 15 | ); 16 | return response; 17 | } 18 | 19 | async getByName(projectName, options = {}) { 20 | const queryString = getQueryStringFromOptions(options); 21 | const httpOptions = options.httpOptions; 22 | const response = ( 23 | await this.client_.fetch(`${this.baseUrl_}/groups/byName/${projectName}?${queryString}`, httpOptions) 24 | ); 25 | return response; 26 | } 27 | 28 | async getTeamsByProjectId(projectId, options = {}) { 29 | const queryString = getQueryStringFromOptions(options); 30 | const httpOptions = options.httpOptions; 31 | const response = ( 32 | await this.client_.fetch(`${this.baseUrl_}/groups/${projectId}/teams?${queryString}`, httpOptions) 33 | ); 34 | return response; 35 | } 36 | 37 | async getAll(options = {}) { 38 | const queryString = getQueryStringFromOptions(options); 39 | const httpOptions = options.httpOptions; 40 | const response = ( 41 | await this.client_.fetch(`${this.baseUrl_}/groups?${queryString}`, httpOptions) 42 | ); 43 | return response; 44 | } 45 | 46 | async delete(projectId, options = {}) { 47 | const queryString = getQueryStringFromOptions(options); 48 | const httpOptions = options.httpOptions; 49 | await this.client_.fetch(`${this.baseUrl_}/groups/${projectId}?${queryString}`, { 50 | "method": "DELETE", 51 | ...httpOptions 52 | }); 53 | return true; 54 | } 55 | 56 | async removeUserFromProject(projectId, userId, options = {}) { 57 | const queryString = getQueryStringFromOptions(options); 58 | const httpOptions = options.httpOptions; 59 | await this.client_.fetch(`${this.baseUrl_}/groups/${projectId}/users/${userId}?${queryString}`, { 60 | "method": "DELETE", 61 | ...httpOptions 62 | }); 63 | return true; 64 | } 65 | 66 | async assignTeams(projectId, body, options = {}) { 67 | const queryString = getQueryStringFromOptions(options); 68 | const httpOptions = options.httpOptions; 69 | const response = ( 70 | await this.client_.fetch(`${this.baseUrl_}/groups/${projectId}/teams?${queryString}`, { 71 | "method": "POST", 72 | "data": body, 73 | "headers": {"Content-Type": "application/json"}, 74 | ...httpOptions 75 | }) 76 | ); 77 | return response; 78 | } 79 | 80 | async create(body, options = {}) { 81 | const queryString = getQueryStringFromOptions(options); 82 | const httpOptions = options.httpOptions; 83 | const response = ( 84 | await this.client_.fetch(`${this.baseUrl_}/groups?${queryString}`, { 85 | "method": "POST", 86 | "data": body, 87 | "headers": {"Content-Type": "application/json"}, 88 | ...httpOptions 89 | }) 90 | ); 91 | return response; 92 | } 93 | } 94 | 95 | module.exports = Project; 96 | 97 | -------------------------------------------------------------------------------- /test/event.test.js: -------------------------------------------------------------------------------- 1 | const {describe, it, afterEach, before, beforeEach} = exports.lab = require("@hapi/lab").script(); 2 | const {expect} = require('@hapi/code'); 3 | const getClient = require('../src/index.js'); 4 | const {MockAgent, setGlobalDispatcher} = require('urllib'); 5 | 6 | const baseUrl = "http://localhost:7001"; 7 | const projectId = "dummyProjectId"; 8 | 9 | const client = getClient({ 10 | "publicKey": "dummuyPublicKey", 11 | "privateKey": "dummyPrivateKey", 12 | "baseUrl": baseUrl, 13 | "projectId": projectId 14 | }); 15 | 16 | describe("Mongo Atlas Api Client - Event", () => { 17 | 18 | let mockAgent; 19 | let mockPool; 20 | before(() => { 21 | mockAgent = new MockAgent(); 22 | setGlobalDispatcher(mockAgent); 23 | }); 24 | 25 | beforeEach(() => { 26 | mockPool = mockAgent.get(baseUrl); 27 | }); 28 | 29 | afterEach(() => { 30 | mockAgent.assertNoPendingInterceptors(); 31 | }); 32 | 33 | describe("When event is exported from index", () => { 34 | it("should export event functions", async () => { 35 | expect(client.event.get).to.be.function(); 36 | expect(client.event.getAll).to.be.function(); 37 | expect(client.event.getAllByOrganizationId).to.be.function(); 38 | expect(client.event.getByOrganizationId).to.be.function(); 39 | }); 40 | }); 41 | 42 | describe("When get is called with querystring parameters", () => { 43 | it("should return response", async () => { 44 | mockPool.intercept({ 45 | "path": `/groups/${projectId}/events/myeventId?key1=value1&key2=value2`, 46 | "method": "get" 47 | }) 48 | .reply(200, {"event": "name"}); 49 | const result = await client.event.get("myeventId", {"key1": "value1", "key2": "value2"}); 50 | expect(result).to.equal({"event": "name"}); 51 | 52 | }); 53 | }); 54 | 55 | describe("When getAll is called with querystring parameters", () => { 56 | it("should return response", async () => { 57 | mockPool.intercept({ 58 | "path": `/groups/${projectId}/events?key1=value1&key2=value2`, 59 | "method": "get" 60 | }) 61 | .reply(200, [{"event": "name"}]); 62 | const result = await client.event.getAll({"key1": "value1", "key2": "value2"}); 63 | expect(result).to.equal([{"event": "name"}]); 64 | 65 | }); 66 | }); 67 | 68 | describe("When getByOrganizationId is called with querystring parameters", () => { 69 | it("should return response", async () => { 70 | mockPool.intercept({ 71 | "path": "/orgs/myOrgId/events/myeventId?key1=value1&key2=value2", 72 | "method": "get" 73 | }) 74 | .reply(200, {"event": "name"}); 75 | const result = await client.event.getByOrganizationId("myOrgId", "myeventId", {"key1": "value1", "key2": "value2"}); 76 | expect(result).to.equal({"event": "name"}); 77 | 78 | }); 79 | }); 80 | 81 | describe("When getAllByOrganizationId is called with querystring parameters", () => { 82 | it("should return response", async () => { 83 | mockPool.intercept({ 84 | "path": "/orgs/myOrgId/events?key1=value1&key2=value2", 85 | "method": "get" 86 | }) 87 | .reply(200, [{"event": "name"}]); 88 | const result = await client.event.getAllByOrganizationId("myOrgId", {"key1": "value1", "key2": "value2"}); 89 | expect(result).to.equal([{"event": "name"}]); 90 | 91 | }); 92 | }); 93 | }); 94 | -------------------------------------------------------------------------------- /src/atlasSearch.js: -------------------------------------------------------------------------------- 1 | const {getQueryStringFromOptions} = require("./helper"); 2 | 3 | class AtlasSearch { 4 | 5 | constructor(client, baseUrl, projectId) { 6 | this.client_ = client; 7 | this.baseUrl_ = baseUrl; 8 | this.projectId_ = projectId; 9 | } 10 | 11 | async get(clusterName, indexId, options = {}) { 12 | const queryString = getQueryStringFromOptions(options); 13 | const httpOptions = options.httpOptions; 14 | const response = ( 15 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clusterName}/fts/indexes/${indexId}?${queryString}`, httpOptions) 16 | ); 17 | return response; 18 | } 19 | 20 | async getAllAnalyzers(clusterName, options = {}) { 21 | const queryString = getQueryStringFromOptions(options); 22 | const httpOptions = options.httpOptions; 23 | const response = ( 24 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clusterName}/fts/analyzers?${queryString}`, httpOptions) 25 | ); 26 | return response; 27 | } 28 | 29 | async upsertAnalyzer(clusterName, body, options = {}) { 30 | const queryString = getQueryStringFromOptions(options); 31 | const httpOptions = options.httpOptions; 32 | const response = ( 33 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clusterName}/fts/analyzers?${queryString}`, { 34 | "method": "PUT", 35 | "data": body, 36 | "headers": {"Content-Type": "application/json"}, 37 | ...httpOptions 38 | }) 39 | ); 40 | return response; 41 | } 42 | 43 | async getAll(clusterName, databaseName, collectionName, options = {}) { 44 | const queryString = getQueryStringFromOptions(options); 45 | const httpOptions = options.httpOptions; 46 | const response = ( 47 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clusterName}/fts/indexes/${databaseName}/${collectionName}?${queryString}`, httpOptions) 48 | ); 49 | return response; 50 | } 51 | 52 | async delete(clusterName, indexId, options = {}) { 53 | const queryString = getQueryStringFromOptions(options); 54 | const httpOptions = options.httpOptions; 55 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clusterName}/fts/indexes/${indexId}?${queryString}`, { 56 | "method": "DELETE", 57 | ...httpOptions 58 | }); 59 | return true; 60 | } 61 | 62 | async update(clusterName, indexId, body, options = {}) { 63 | const queryString = getQueryStringFromOptions(options); 64 | const httpOptions = options.httpOptions; 65 | const response = ( 66 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clusterName}/fts/indexes/${indexId}?${queryString}`, { 67 | "method": "PATCH", 68 | "data": body, 69 | "headers": {"Content-Type": "application/json"}, 70 | ...httpOptions 71 | }) 72 | ); 73 | return response; 74 | } 75 | 76 | async create(clusterName, body, options = {}) { 77 | const queryString = getQueryStringFromOptions(options); 78 | const httpOptions = options.httpOptions; 79 | const response = ( 80 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clusterName}/fts/indexes?${queryString}`, { 81 | "method": "POST", 82 | "data": body, 83 | "headers": {"Content-Type": "application/json"}, 84 | ...httpOptions 85 | }) 86 | ); 87 | return response; 88 | } 89 | } 90 | 91 | module.exports = AtlasSearch; 92 | 93 | -------------------------------------------------------------------------------- /test/cloudProviderAccess.test.js: -------------------------------------------------------------------------------- 1 | const {describe, it, afterEach, before, beforeEach} = exports.lab = require("@hapi/lab").script(); 2 | const {expect} = require('@hapi/code'); 3 | const getClient = require('../src/index.js'); 4 | const {MockAgent, setGlobalDispatcher} = require('urllib'); 5 | 6 | const baseUrl = "http://localhost:7001"; 7 | const projectId = "dummyProjectId"; 8 | 9 | const client = getClient({ 10 | "publicKey": "dummuyPublicKey", 11 | "privateKey": "dummyPrivateKey", 12 | "baseUrl": baseUrl, 13 | "projectId": projectId 14 | }); 15 | 16 | describe("Mongo Atlas Api Client - cloudProviderAccess", () => { 17 | 18 | let mockAgent; 19 | let mockPool; 20 | before(() => { 21 | mockAgent = new MockAgent(); 22 | setGlobalDispatcher(mockAgent); 23 | }); 24 | 25 | beforeEach(() => { 26 | mockPool = mockAgent.get(baseUrl); 27 | }); 28 | 29 | afterEach(() => { 30 | mockAgent.assertNoPendingInterceptors(); 31 | }); 32 | 33 | describe("When cloudProviderAccess is exported from index", () => { 34 | it("should export cloudProviderAccess functions", async () => { 35 | expect(client.cloudProviderAccess.getAll).to.be.function(); 36 | expect(client.cloudProviderAccess.create).to.be.function(); 37 | expect(client.cloudProviderAccess.delete).to.be.function(); 38 | expect(client.cloudProviderAccess.update).to.be.function(); 39 | }); 40 | }); 41 | 42 | describe("When getAll is called with querystring parameters", () => { 43 | it("should return response", async () => { 44 | mockPool.intercept({ 45 | "path": `/groups/${projectId}/cloudProviderAccess?key1=value1&key2=value2`, 46 | "method": "GET" 47 | }) 48 | .reply(200, [{"cloudProviderAccess": "name"}]); 49 | const result = await client.cloudProviderAccess.getAll({"key1": "value1", "key2": "value2"}); 50 | expect(result).to.equal([{"cloudProviderAccess": "name"}]); 51 | 52 | }); 53 | }); 54 | 55 | describe("When update is called with querystring parameters", () => { 56 | it("should return response", async () => { 57 | mockPool.intercept({ 58 | "path": `/groups/${projectId}/cloudProviderAccess/roleId?key1=value1&key2=value2`, 59 | "method": "PATCH", 60 | "data": {"body": "value"} 61 | }) 62 | .reply(200, [{"cloudProviderAccess": "name"}]); 63 | const result = await client.cloudProviderAccess.update("roleId", {"body": "value"}, {"key1": "value1", "key2": "value2"}); 64 | expect(result).to.equal([{"cloudProviderAccess": "name"}]); 65 | 66 | }); 67 | }); 68 | 69 | describe("When create is called with querystring parameters", () => { 70 | it("should return response", async () => { 71 | mockPool.intercept({ 72 | "path": `/groups/${projectId}/cloudProviderAccess?key1=value1&key2=value2`, 73 | "method": "POST", 74 | "data": {"body": "value"} 75 | }) 76 | .reply(200, [{"cloudProviderAccess": "name"}]); 77 | const result = await client.cloudProviderAccess.create({"body": "value"}, {"key1": "value1", "key2": "value2"}); 78 | expect(result).to.equal([{"cloudProviderAccess": "name"}]); 79 | 80 | }); 81 | }); 82 | 83 | describe("When delete is called with querystring parameters", () => { 84 | it("should return response", async () => { 85 | mockPool.intercept({ 86 | "path": `/groups/${projectId}/cloudProviderAccess/aws/roleId?key1=value1&key2=value2`, 87 | "method": "DELETE" 88 | }) 89 | .reply(200, true); 90 | const result = await client.cloudProviderAccess.delete("aws", "roleId", {"key1": "value1", "key2": "value2"}); 91 | expect(result).to.be.true(); 92 | 93 | }); 94 | }); 95 | }); 96 | -------------------------------------------------------------------------------- /test/cloudbackup.test.js: -------------------------------------------------------------------------------- 1 | const {describe, it, afterEach, before, beforeEach} = exports.lab = require("@hapi/lab").script(); 2 | const {expect} = require('@hapi/code'); 3 | const getClient = require('../src/index.js'); 4 | const {MockAgent, setGlobalDispatcher} = require('urllib'); 5 | 6 | const baseUrl = "http://localhost:7001"; 7 | const projectId = "dummyProjectId"; 8 | 9 | const client = getClient({ 10 | "publicKey": "dummuyPublicKey", 11 | "privateKey": "dummyPrivateKey", 12 | "baseUrl": baseUrl, 13 | "projectId": projectId 14 | }); 15 | 16 | describe("Mongo Atlas Api Client - CloudBackup", () => { 17 | 18 | let mockAgent; 19 | let mockPool; 20 | before(() => { 21 | mockAgent = new MockAgent(); 22 | setGlobalDispatcher(mockAgent); 23 | }); 24 | 25 | beforeEach(() => { 26 | mockPool = mockAgent.get(baseUrl); 27 | }); 28 | 29 | afterEach(() => { 30 | mockAgent.assertNoPendingInterceptors(); 31 | }); 32 | 33 | describe("When cluster is exported from index", () => { 34 | it("should export cluster functions", async () => { 35 | expect(client.cloudBackup.getReplicaSetCloudBackup).to.be.function(); 36 | expect(client.cloudBackup.getAllReplicaSetCloudBackups).to.be.function(); 37 | expect(client.cloudBackup.getSnapshotRestoreJob).to.be.function(); 38 | expect(client.cloudBackup.createSnapshotRestoreJob).to.be.function(); 39 | }); 40 | }); 41 | 42 | describe("When getReplicaSetCloudBackup is called with querystring parameters", () => { 43 | it("should return response", async () => { 44 | mockPool.intercept({ 45 | "path": `/groups/${projectId}/clusters/mycluster/backup/snapshots/mysnapshot?key1=value1&key2=value2`, 46 | "method": "get" 47 | }) 48 | .reply(200, {"replicaSetName": "mycluster"}); 49 | const result = await client.cloudBackup.getReplicaSetCloudBackup("mycluster", "mysnapshot", {"key1": "value1", "key2": "value2"}); 50 | expect(result).to.equal({"replicaSetName": "mycluster"}); 51 | 52 | }); 53 | }); 54 | 55 | describe("When getAllReplicaSetCloudBackups is called with querystring parameters", () => { 56 | it("should return response", async () => { 57 | mockPool.intercept({ 58 | "path": `/groups/${projectId}/clusters/mycluster/backup/snapshots?key1=value1&key2=value2`, 59 | "method": "get" 60 | }) 61 | .reply(200, [{"replicaSetName": "mycluster"}]); 62 | const result = await client.cloudBackup.getAllReplicaSetCloudBackups("mycluster", {"key1": "value1", "key2": "value2"}); 63 | expect(result).to.equal([{"replicaSetName": "mycluster"}]); 64 | 65 | }); 66 | }); 67 | 68 | describe("When getSnapshotRestoreJob is called with querystring parameters", () => { 69 | it("should return response", async () => { 70 | mockPool.intercept({ 71 | "path": `/groups/${projectId}/clusters/mycluster/backup/restoreJobs/myrestorejob?key1=value1&key2=value2`, 72 | "method": "get" 73 | }) 74 | .reply(200, {"id": "myrestorejob"}); 75 | const result = await client.cloudBackup.getSnapshotRestoreJob("mycluster", "myrestorejob", {"key1": "value1", "key2": "value2"}); 76 | expect(result).to.equal({"id": "myrestorejob"}); 77 | 78 | }); 79 | }); 80 | 81 | describe("When createSnapshotRestoreJob is called with querystring parameters", () => { 82 | it("should return response", async () => { 83 | mockPool.intercept({ 84 | "path": `/groups/${projectId}/clusters/mycluster/backup/restoreJobs?key1=value1&key2=value2`, 85 | "method": "post", 86 | "data": {"body": "value"} 87 | }) 88 | .reply(200, {"id": "myrestorejob"}); 89 | const result = await client.cloudBackup.createSnapshotRestoreJob("mycluster", {"body": "value"}, {"key1": "value1", "key2": "value2"}); 90 | expect(result).to.equal({"id": "myrestorejob"}); 91 | 92 | }); 93 | }); 94 | }); 95 | -------------------------------------------------------------------------------- /src/cluster.js: -------------------------------------------------------------------------------- 1 | const {getQueryStringFromOptions} = require("./helper"); 2 | 3 | class Cluster { 4 | 5 | constructor(client, baseUrl, projectId) { 6 | this.client_ = client; 7 | this.baseUrl_ = baseUrl; 8 | this.projectId_ = projectId; 9 | } 10 | 11 | async get(clustername, options = {}) { 12 | const queryString = getQueryStringFromOptions(options); 13 | const httpOptions = options.httpOptions; 14 | const response = ( 15 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clustername}?${queryString}`, httpOptions) 16 | ); 17 | return response; 18 | } 19 | 20 | async getAdvanceConfiguration(clustername, options = {}) { 21 | const queryString = getQueryStringFromOptions(options); 22 | const httpOptions = options.httpOptions; 23 | const response = ( 24 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clustername}/processArgs?${queryString}`, httpOptions) 25 | ); 26 | return response; 27 | } 28 | 29 | async getAll(options = {}) { 30 | const queryString = getQueryStringFromOptions(options); 31 | const httpOptions = options.httpOptions; 32 | const response = ( 33 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters?${queryString}`, httpOptions) 34 | ); 35 | return response; 36 | } 37 | 38 | async delete(clustername, options = {}) { 39 | const queryString = getQueryStringFromOptions(options); 40 | const httpOptions = options.httpOptions; 41 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clustername}?${queryString}`, { 42 | "method": "DELETE", 43 | ...httpOptions 44 | }); 45 | return true; 46 | } 47 | 48 | async update(clustername, body, options = {}) { 49 | const queryString = getQueryStringFromOptions(options); 50 | const httpOptions = options.httpOptions; 51 | const response = ( 52 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clustername}?${queryString}`, { 53 | "method": "PATCH", 54 | "data": body, 55 | "headers": {"Content-Type": "application/json"}, 56 | ...httpOptions 57 | }) 58 | ); 59 | return response; 60 | } 61 | 62 | async updateAdvanceConfiguration(clustername, body, options = {}) { 63 | const queryString = getQueryStringFromOptions(options); 64 | const httpOptions = options.httpOptions; 65 | const response = ( 66 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clustername}/processArgs?${queryString}`, { 67 | "method": "PATCH", 68 | "data": body, 69 | "headers": {"Content-Type": "application/json"}, 70 | ...httpOptions 71 | }) 72 | ); 73 | return response; 74 | } 75 | 76 | async testPrimaryFailOver(clustername, options = {}) { 77 | const queryString = getQueryStringFromOptions(options); 78 | const httpOptions = options.httpOptions; 79 | const response = ( 80 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters/${clustername}/restartPrimaries?${queryString}`, { 81 | "method": "POST", 82 | ...httpOptions 83 | }) 84 | ); 85 | return response; 86 | } 87 | 88 | async create(body, options = {}) { 89 | const queryString = getQueryStringFromOptions(options); 90 | const httpOptions = options.httpOptions; 91 | const response = ( 92 | await this.client_.fetch(`${this.baseUrl_}/groups/${this.projectId_}/clusters?${queryString}`, { 93 | "method": "POST", 94 | "data": body, 95 | "headers": {"Content-Type": "application/json"}, 96 | ...httpOptions 97 | }) 98 | ); 99 | return response; 100 | } 101 | } 102 | 103 | module.exports = Cluster; 104 | 105 | -------------------------------------------------------------------------------- /test/user.test.js: -------------------------------------------------------------------------------- 1 | const {describe, it, afterEach, before, beforeEach} = exports.lab = require("@hapi/lab").script(); 2 | const {expect} = require('@hapi/code'); 3 | const getClient = require('../src/index.js'); 4 | const {MockAgent, setGlobalDispatcher} = require('urllib'); 5 | 6 | const baseUrl = "http://localhost:7001"; 7 | const projectId = "dummyProjectId"; 8 | 9 | const client = getClient({ 10 | "publicKey": "dummuyPublicKey", 11 | "privateKey": "dummyPrivateKey", 12 | "baseUrl": baseUrl, 13 | "projectId": projectId 14 | }); 15 | 16 | describe("Mongo Atlas Api Client - User", () => { 17 | 18 | let mockAgent; 19 | let mockPool; 20 | before(() => { 21 | mockAgent = new MockAgent(); 22 | setGlobalDispatcher(mockAgent); 23 | }); 24 | 25 | beforeEach(() => { 26 | mockPool = mockAgent.get(baseUrl); 27 | }); 28 | 29 | afterEach(() => { 30 | mockAgent.assertNoPendingInterceptors(); 31 | }); 32 | 33 | describe("When user is exported from index", () => { 34 | it("should export user functions", async () => { 35 | expect(client.user.get).to.be.function(); 36 | expect(client.user.getAll).to.be.function(); 37 | expect(client.user.create).to.be.function(); 38 | expect(client.user.delete).to.be.function(); 39 | expect(client.user.update).to.be.function(); 40 | }); 41 | }); 42 | 43 | describe("When get is called with querystring parameters", () => { 44 | it("should return response", async () => { 45 | mockPool.intercept({ 46 | "path": `/groups/${projectId}/databaseUsers/admin/myUsername?key1=value1&key2=value2`, 47 | "method": "get" 48 | }) 49 | .reply(200, {"projectWhitelist": "name"}); 50 | const result = await client.user.get("myUsername", {"key1": "value1", "key2": "value2"}); 51 | expect(result).to.equal({"projectWhitelist": "name"}); 52 | 53 | }); 54 | }); 55 | 56 | describe("When getAll is called with querystring parameters", () => { 57 | it("should return response", async () => { 58 | mockPool.intercept({ 59 | "path": `/groups/${projectId}/databaseUsers?key1=value1&key2=value2`, 60 | "method": "get" 61 | }) 62 | .reply(200, [{"projectWhitelist": "name"}]); 63 | const result = await client.user.getAll({"key1": "value1", "key2": "value2"}); 64 | expect(result).to.equal([{"projectWhitelist": "name"}]); 65 | 66 | }); 67 | }); 68 | 69 | describe("When update is called with querystring parameters", () => { 70 | it("should return response", async () => { 71 | mockPool.intercept({ 72 | "path": `/groups/${projectId}/databaseUsers/admin/myUsername?key1=value1&key2=value2`, 73 | "method": "PATCH", 74 | "data": {"body": "value"} 75 | }) 76 | .reply(200, [{"projectWhitelist": "name"}]); 77 | const result = await client.user.update("myUsername", {"body": "value"}, {"key1": "value1", "key2": "value2"}); 78 | expect(result).to.equal([{"projectWhitelist": "name"}]); 79 | 80 | }); 81 | }); 82 | 83 | describe("When create is called with querystring parameters", () => { 84 | it("should return response", async () => { 85 | mockPool.intercept({ 86 | "path": `/groups/${projectId}/databaseUsers?key1=value1&key2=value2`, 87 | "method": "POST", 88 | "data": {"body": "value"} 89 | }) 90 | .reply(200, [{"projectWhitelist": "name"}]); 91 | const result = await client.user.create({"body": "value"}, {"key1": "value1", "key2": "value2"}); 92 | expect(result).to.equal([{"projectWhitelist": "name"}]); 93 | 94 | }); 95 | }); 96 | 97 | describe("When delete is called with querystring parameters", () => { 98 | it("should return response", async () => { 99 | mockPool.intercept({ 100 | "path": `/groups/${projectId}/databaseUsers/admin/myUsername?key1=value1&key2=value2`, 101 | "method": "DELETE" 102 | }) 103 | .reply(200, true); 104 | const result = await client.user.delete("myUsername", {"key1": "value1", "key2": "value2"}); 105 | expect(result).to.be.true(); 106 | 107 | }); 108 | }); 109 | }); 110 | -------------------------------------------------------------------------------- /test/customDbRole.test.js: -------------------------------------------------------------------------------- 1 | const {describe, it, afterEach, before, beforeEach} = exports.lab = require("@hapi/lab").script(); 2 | const {expect} = require('@hapi/code'); 3 | const getClient = require('../src/index.js'); 4 | const {MockAgent, setGlobalDispatcher} = require('urllib'); 5 | 6 | const baseUrl = "http://localhost:7001"; 7 | const projectId = "dummyProjectId"; 8 | 9 | const client = getClient({ 10 | "publicKey": "dummuyPublicKey", 11 | "privateKey": "dummyPrivateKey", 12 | "baseUrl": baseUrl, 13 | "projectId": projectId 14 | }); 15 | 16 | describe("Mongo Atlas Api Client - Custom Db Role", () => { 17 | 18 | let mockAgent; 19 | let mockPool; 20 | before(() => { 21 | mockAgent = new MockAgent(); 22 | setGlobalDispatcher(mockAgent); 23 | }); 24 | 25 | beforeEach(() => { 26 | mockPool = mockAgent.get(baseUrl); 27 | }); 28 | 29 | afterEach(() => { 30 | mockAgent.assertNoPendingInterceptors(); 31 | }); 32 | 33 | describe("When customDbRole is exported from index", () => { 34 | it("should export customDbRole functions", async () => { 35 | expect(client.customDbRole.get).to.be.function(); 36 | expect(client.customDbRole.getAll).to.be.function(); 37 | expect(client.customDbRole.create).to.be.function(); 38 | expect(client.customDbRole.delete).to.be.function(); 39 | expect(client.customDbRole.update).to.be.function(); 40 | }); 41 | }); 42 | 43 | describe("When get is called with querystring parameters", () => { 44 | it("should return response", async () => { 45 | mockPool.intercept({ 46 | "path": `/groups/${projectId}/customDBRoles/roles/rolename?key1=value1&key2=value2`, 47 | "method": "get" 48 | }) 49 | .reply(200, {"customDbRole": "name"}); 50 | const result = await client.customDbRole.get("rolename", {"key1": "value1", "key2": "value2"}); 51 | expect(result).to.equal({"customDbRole": "name"}); 52 | 53 | }); 54 | }); 55 | 56 | describe("When getAll is called with querystring parameters", () => { 57 | it("should return response", async () => { 58 | mockPool.intercept({ 59 | "path": `/groups/${projectId}/customDBRoles/roles?key1=value1&key2=value2`, 60 | "method": "get" 61 | }) 62 | .reply(200, [{"customDbRole": "name"}]); 63 | const result = await client.customDbRole.getAll({"key1": "value1", "key2": "value2"}); 64 | expect(result).to.equal([{"customDbRole": "name"}]); 65 | 66 | }); 67 | }); 68 | 69 | describe("When update is called with querystring parameters", () => { 70 | it("should return response", async () => { 71 | mockPool.intercept({ 72 | "path": `/groups/${projectId}/customDBRoles/roles/rolename?key1=value1&key2=value2`, 73 | "method": "PATCH", 74 | "data": {"body": "value"} 75 | }) 76 | .reply(200, [{"customDbRole": "name"}]); 77 | const result = await client.customDbRole.update("rolename", {"body": "value"}, {"key1": "value1", "key2": "value2"}); 78 | expect(result).to.equal([{"customDbRole": "name"}]); 79 | 80 | }); 81 | }); 82 | 83 | describe("When delete is called with querystring parameters", () => { 84 | it("should return response", async () => { 85 | mockPool.intercept({ 86 | "path": `/groups/${projectId}/customDBRoles/roles/rolename?key1=value1&key2=value2`, 87 | "method": "delete" 88 | }) 89 | .reply(200, true); 90 | const result = await client.customDbRole.delete("rolename", {"key1": "value1", "key2": "value2"}); 91 | expect(result).to.be.true(); 92 | 93 | }); 94 | }); 95 | 96 | describe("When create is called with querystring parameters", () => { 97 | it("should return response", async () => { 98 | mockPool.intercept({ 99 | "path": `/groups/${projectId}/customDBRoles/roles?key1=value1&key2=value2`, 100 | "method": "post", 101 | "data": {"body": "value"} 102 | }) 103 | .reply(200, [{"customDbRole": "name"}]); 104 | const result = await client.customDbRole.create({"body": "value"}, {"key1": "value1", "key2": "value2"}); 105 | expect(result).to.equal([{"customDbRole": "name"}]); 106 | 107 | }); 108 | }); 109 | }); 110 | -------------------------------------------------------------------------------- /test/projectWhitelist.test.js: -------------------------------------------------------------------------------- 1 | const {describe, it, afterEach, before, beforeEach} = exports.lab = require("@hapi/lab").script(); 2 | const {expect} = require('@hapi/code'); 3 | const getClient = require('../src/index.js'); 4 | const {MockAgent, setGlobalDispatcher} = require('urllib'); 5 | 6 | const baseUrl = "http://localhost:7001"; 7 | const projectId = "dummyProjectId"; 8 | 9 | const client = getClient({ 10 | "publicKey": "dummuyPublicKey", 11 | "privateKey": "dummyPrivateKey", 12 | "baseUrl": baseUrl, 13 | "projectId": projectId 14 | }); 15 | 16 | describe("Mongo Atlas Api Client - Project Whitelist", () => { 17 | 18 | let mockAgent; 19 | let mockPool; 20 | before(() => { 21 | mockAgent = new MockAgent(); 22 | setGlobalDispatcher(mockAgent); 23 | }); 24 | 25 | beforeEach(() => { 26 | mockPool = mockAgent.get(baseUrl); 27 | }); 28 | 29 | afterEach(() => { 30 | mockAgent.assertNoPendingInterceptors(); 31 | }); 32 | 33 | describe("When projectWhitelist is exported from index", () => { 34 | it("should export projectWhitelist functions", async () => { 35 | expect(client.projectWhitelist.get).to.be.function(); 36 | expect(client.projectWhitelist.getAll).to.be.function(); 37 | expect(client.projectWhitelist.create).to.be.function(); 38 | expect(client.projectWhitelist.delete).to.be.function(); 39 | expect(client.projectWhitelist.update).to.be.function(); 40 | }); 41 | }); 42 | 43 | describe("When get is called with querystring parameters", () => { 44 | it("should return response", async () => { 45 | mockPool.intercept({ 46 | "path": `/groups/${projectId}/whitelist/myWhitelistEntry?key1=value1&key2=value2`, 47 | "method": "get" 48 | }) 49 | .reply(200, {"projectWhitelist": "name"}); 50 | const result = await client.projectWhitelist.get("myWhitelistEntry", {"key1": "value1", "key2": "value2"}); 51 | expect(result).to.equal({"projectWhitelist": "name"}); 52 | 53 | }); 54 | }); 55 | 56 | describe("When getAll is called with querystring parameters", () => { 57 | it("should return response", async () => { 58 | mockPool.intercept({ 59 | "path": `/groups/${projectId}/whitelist?key1=value1&key2=value2`, 60 | "method": "get" 61 | }) 62 | .reply(200, [{"projectWhitelist": "name"}]); 63 | const result = await client.projectWhitelist.getAll({"key1": "value1", "key2": "value2"}); 64 | expect(result).to.equal([{"projectWhitelist": "name"}]); 65 | 66 | }); 67 | }); 68 | 69 | describe("When update is called with querystring parameters", () => { 70 | it("should return response", async () => { 71 | mockPool.intercept({ 72 | "path": `/groups/${projectId}/whitelist?key1=value1&key2=value2`, 73 | "method": "POST", 74 | "data": {"body": "value"} 75 | }) 76 | .reply(200, [{"projectWhitelist": "name"}]); 77 | const result = await client.projectWhitelist.update({"body": "value"}, {"key1": "value1", "key2": "value2"}); 78 | expect(result).to.equal([{"projectWhitelist": "name"}]); 79 | 80 | }); 81 | }); 82 | 83 | describe("When create is called with querystring parameters", () => { 84 | it("should return response", async () => { 85 | mockPool.intercept({ 86 | "path": `/groups/${projectId}/whitelist?key1=value1&key2=value2`, 87 | "method": "POST", 88 | "data": {"body": "value"} 89 | }) 90 | .reply(200, [{"projectWhitelist": "name"}]); 91 | const result = await client.projectWhitelist.create({"body": "value"}, {"key1": "value1", "key2": "value2"}); 92 | expect(result).to.equal([{"projectWhitelist": "name"}]); 93 | 94 | }); 95 | }); 96 | 97 | describe("When delete is called with querystring parameters", () => { 98 | it("should return response", async () => { 99 | mockPool.intercept({ 100 | "path": `/groups/${projectId}/whitelist/myWhitelistEntry?key1=value1&key2=value2`, 101 | "method": "delete" 102 | }) 103 | .reply(200, true); 104 | const result = await client.projectWhitelist.delete("myWhitelistEntry", {"key1": "value1", "key2": "value2"}); 105 | expect(result).to.be.true(); 106 | 107 | }); 108 | }); 109 | }); 110 | -------------------------------------------------------------------------------- /test/projectAccesslist.test.js: -------------------------------------------------------------------------------- 1 | const {describe, it, afterEach, before, beforeEach} = exports.lab = require("@hapi/lab").script(); 2 | const {expect} = require('@hapi/code'); 3 | const getClient = require('../src/index.js'); 4 | const {MockAgent, setGlobalDispatcher} = require('urllib'); 5 | 6 | const baseUrl = "http://localhost:7001"; 7 | const projectId = "dummyProjectId"; 8 | 9 | const client = getClient({ 10 | "publicKey": "dummuyPublicKey", 11 | "privateKey": "dummyPrivateKey", 12 | "baseUrl": baseUrl, 13 | "projectId": projectId 14 | }); 15 | 16 | describe("Mongo Atlas Api Client - Project Accesslist", () => { 17 | 18 | let mockAgent; 19 | let mockPool; 20 | before(() => { 21 | mockAgent = new MockAgent(); 22 | setGlobalDispatcher(mockAgent); 23 | }); 24 | 25 | beforeEach(() => { 26 | mockPool = mockAgent.get(baseUrl); 27 | }); 28 | 29 | afterEach(() => { 30 | mockAgent.assertNoPendingInterceptors(); 31 | }); 32 | 33 | describe("When projectAccesslist is exported from index", () => { 34 | it("should export projectAccesslist functions", async () => { 35 | expect(client.projectAccesslist.get).to.be.function(); 36 | expect(client.projectAccesslist.getAll).to.be.function(); 37 | expect(client.projectAccesslist.create).to.be.function(); 38 | expect(client.projectAccesslist.delete).to.be.function(); 39 | expect(client.projectAccesslist.update).to.be.function(); 40 | }); 41 | }); 42 | 43 | describe("When get is called with querystring parameters", () => { 44 | it("should return response", async () => { 45 | mockPool.intercept({ 46 | "path": `/groups/${projectId}/accessList/myAccesslistEntry?key1=value1&key2=value2`, 47 | "method": "get" 48 | }) 49 | .reply(200, {"projectAccesslist": "name"}); 50 | const result = await client.projectAccesslist.get("myAccesslistEntry", {"key1": "value1", "key2": "value2"}); 51 | expect(result).to.equal({"projectAccesslist": "name"}); 52 | 53 | }); 54 | }); 55 | 56 | describe("When getAll is called with querystring parameters", () => { 57 | it("should return response", async () => { 58 | mockPool.intercept({ 59 | "path": `/groups/${projectId}/accessList?key1=value1&key2=value2`, 60 | "method": "get" 61 | }) 62 | .reply(200, [{"projectAccesslist": "name"}]); 63 | const result = await client.projectAccesslist.getAll({"key1": "value1", "key2": "value2"}); 64 | expect(result).to.equal([{"projectAccesslist": "name"}]); 65 | 66 | }); 67 | }); 68 | 69 | describe("When update is called with querystring parameters", () => { 70 | it("should return response", async () => { 71 | mockPool.intercept({ 72 | "path": `/groups/${projectId}/accessList?key1=value1&key2=value2`, 73 | "method": "POST", 74 | "data": {"body": "value"} 75 | }) 76 | .reply(200, [{"projectAccesslist": "name"}]); 77 | const result = await client.projectAccesslist.update({"body": "value"}, {"key1": "value1", "key2": "value2"}); 78 | expect(result).to.equal([{"projectAccesslist": "name"}]); 79 | 80 | }); 81 | }); 82 | 83 | describe("When create is called with querystring parameters", () => { 84 | it("should return response", async () => { 85 | mockPool.intercept({ 86 | "path": `/groups/${projectId}/accessList?key1=value1&key2=value2`, 87 | "method": "POST", 88 | "data": {"body": "value"} 89 | }) 90 | .reply(200, [{"projectAccesslist": "name"}]); 91 | const result = await client.projectAccesslist.create({"body": "value"}, {"key1": "value1", "key2": "value2"}); 92 | expect(result).to.equal([{"projectAccesslist": "name"}]); 93 | 94 | }); 95 | }); 96 | 97 | describe("When delete is called with querystring parameters", () => { 98 | it("should return response", async () => { 99 | mockPool.intercept({ 100 | "path": `/groups/${projectId}/accessList/myAccesslistEntry?key1=value1&key2=value2`, 101 | "method": "DELETE" 102 | }) 103 | .reply(200, true); 104 | const result = await client.projectAccesslist.delete("myAccesslistEntry", {"key1": "value1", "key2": "value2"}); 105 | expect(result).to.be.true(); 106 | 107 | }); 108 | }); 109 | }); 110 | -------------------------------------------------------------------------------- /test/dataLake.test.js: -------------------------------------------------------------------------------- 1 | const {describe, it, afterEach, before, beforeEach} = exports.lab = require("@hapi/lab").script(); 2 | const {expect} = require('@hapi/code'); 3 | const getClient = require('../src/index.js'); 4 | const {MockAgent, setGlobalDispatcher} = require('urllib'); 5 | 6 | const baseUrl = "http://localhost:7001"; 7 | const projectId = "dummyProjectId"; 8 | 9 | const client = getClient({ 10 | "publicKey": "dummuyPublicKey", 11 | "privateKey": "dummyPrivateKey", 12 | "baseUrl": baseUrl, 13 | "projectId": projectId 14 | }); 15 | 16 | describe("Mongo Atlas Api Client - dataLake", () => { 17 | 18 | let mockAgent; 19 | let mockPool; 20 | before(() => { 21 | mockAgent = new MockAgent(); 22 | setGlobalDispatcher(mockAgent); 23 | }); 24 | 25 | beforeEach(() => { 26 | mockPool = mockAgent.get(baseUrl); 27 | }); 28 | 29 | afterEach(() => { 30 | mockAgent.assertNoPendingInterceptors(); 31 | }); 32 | 33 | describe("When dataLake is exported from index", () => { 34 | it("should export dataLake functions", async () => { 35 | expect(client.dataLake.get).to.be.function(); 36 | expect(client.dataLake.getAll).to.be.function(); 37 | expect(client.dataLake.getLogsStream).to.be.function(); 38 | expect(client.dataLake.create).to.be.function(); 39 | expect(client.dataLake.delete).to.be.function(); 40 | expect(client.dataLake.update).to.be.function(); 41 | }); 42 | }); 43 | 44 | describe("When get is called with querystring parameters", () => { 45 | it("should return response", async () => { 46 | mockPool.intercept({ 47 | "path": `/groups/${projectId}/dataLakes/mydataLakename?key1=value1&key2=value2`, 48 | "method": "GET" 49 | }) 50 | .reply(200, {"datalake": "name"}); 51 | const result = await client.dataLake.get("mydataLakename", {"key1": "value1", "key2": "value2"}); 52 | expect(result).to.equal({"datalake": "name"}); 53 | 54 | }); 55 | }); 56 | 57 | describe("When getLogsStream is called with querystring parameters", () => { 58 | it("should return response", async () => { 59 | mockPool.intercept({ 60 | "path": `/groups/${projectId}/dataLakes/mydataLakename/queryLogs.gz?key1=value1&key2=value2`, 61 | "method": "GET" 62 | }) 63 | .reply(200, Buffer.from("Some test string", "utf8"), {"headers": {"accept": "application/gzip"}}); 64 | const result = await client.dataLake.getLogsStream("mydataLakename", {"key1": "value1", "key2": "value2"}); 65 | expect(result.pipe).to.exist(); 66 | 67 | }); 68 | }); 69 | 70 | describe("When getAll is called with querystring parameters", () => { 71 | it("should return response", async () => { 72 | mockPool.intercept({ 73 | "path": `/groups/${projectId}/dataLakes?key1=value1&key2=value2`, 74 | "method": "GET" 75 | }) 76 | .reply(200, [{"datalake": "name"}]); 77 | const result = await client.dataLake.getAll({"key1": "value1", "key2": "value2"}); 78 | expect(result).to.equal([{"datalake": "name"}]); 79 | 80 | }); 81 | }); 82 | 83 | describe("When update is called with querystring parameters", () => { 84 | it("should return response", async () => { 85 | mockPool.intercept({ 86 | "path": `/groups/${projectId}/dataLakes/mydataLakename?key1=value1&key2=value2`, 87 | "method": "PATCH", 88 | "data": {"body": "value"} 89 | }) 90 | .reply(200, [{"datalake": "name"}]); 91 | const result = await client.dataLake.update("mydataLakename", {"body": "value"}, {"key1": "value1", "key2": "value2"}); 92 | expect(result).to.equal([{"datalake": "name"}]); 93 | 94 | }); 95 | }); 96 | 97 | describe("When create is called with querystring parameters", () => { 98 | it("should return response", async () => { 99 | mockPool.intercept({ 100 | "path": `/groups/${projectId}/dataLakes?key1=value1&key2=value2`, 101 | "method": "POST", 102 | "data": {"body": "value"} 103 | }) 104 | .reply(200, [{"dataLakes": "name"}]); 105 | const result = await client.dataLake.create({"body": "value"}, {"key1": "value1", "key2": "value2"}); 106 | expect(result).to.equal([{"dataLakes": "name"}]); 107 | 108 | }); 109 | }); 110 | 111 | describe("When delete is called with querystring parameters", () => { 112 | it("should return response", async () => { 113 | mockPool.intercept({ 114 | "path": `/groups/${projectId}/dataLakes/mydataLakename?key1=value1&key2=value2`, 115 | "method": "DELETE" 116 | }) 117 | .reply(200, true); 118 | const result = await client.dataLake.delete("mydataLakename", {"key1": "value1", "key2": "value2"}); 119 | expect(result).to.be.true(); 120 | 121 | }); 122 | }); 123 | }); -------------------------------------------------------------------------------- /test/alert.test.js: -------------------------------------------------------------------------------- 1 | const {describe, it, afterEach, before, beforeEach} = exports.lab = require("@hapi/lab").script(); 2 | const {expect} = require('@hapi/code'); 3 | const getClient = require('../src/index.js'); 4 | const Alert = require('../src/alert.js'); 5 | const HttpClient = require('../src/httpClient.js'); 6 | const {stub} = require("sinon"); 7 | const {MockAgent, setGlobalDispatcher} = require('urllib'); 8 | 9 | const baseUrl = "http://localhost:7001"; 10 | const projectId = "dummyProjectId"; 11 | 12 | const client = getClient({ 13 | "publicKey": "dummuyPublicKey", 14 | "privateKey": "dummyPrivateKey", 15 | "baseUrl": baseUrl, 16 | "projectId": projectId 17 | }); 18 | 19 | describe("Mongo Atlas Api Client - Alert", () => { 20 | 21 | let mockAgent; 22 | let mockPool; 23 | before(() => { 24 | mockAgent = new MockAgent(); 25 | setGlobalDispatcher(mockAgent); 26 | }); 27 | 28 | beforeEach(() => { 29 | mockPool = mockAgent.get(baseUrl); 30 | }); 31 | 32 | afterEach(() => { 33 | mockAgent.assertNoPendingInterceptors(); 34 | }); 35 | 36 | describe("When alert is exported from index", () => { 37 | it("should export alert functions", async () => { 38 | expect(client.alert.get).to.be.function(); 39 | expect(client.alert.getAll).to.be.function(); 40 | expect(client.alert.acknowledge).to.be.function(); 41 | }); 42 | }); 43 | 44 | describe("When get is called with querystring parameters", () => { 45 | it("should return response", async () => { 46 | mockPool.intercept({ 47 | "path": `/groups/${projectId}/alerts/myAlertId?key1=value1&key2=value2`, 48 | "method": "get" 49 | }) 50 | .reply(200, {"alert": "name"}); 51 | const result = await client.alert.get("myAlertId", {"key1": "value1", "key2": "value2"}); 52 | expect(result).to.equal({"alert": "name"}); 53 | }); 54 | }); 55 | 56 | describe("When getAll is called with querystring parameters", () => { 57 | it("should return response", async () => { 58 | mockPool.intercept({ 59 | "path": `/groups/${projectId}/alerts?key1=value1&key2=value2`, 60 | "method": "get" 61 | }) 62 | .reply(200, [{"alert": "name"}]); 63 | const result = await client.alert.getAll({"key1": "value1", "key2": "value2"}); 64 | expect(result).to.equal([{"alert": "name"}]); 65 | }); 66 | }); 67 | 68 | describe("When acknowledge is called with querystring parameters", () => { 69 | it("should return response", async () => { 70 | mockPool.intercept({ 71 | "path": `/groups/${projectId}/alerts/myAlertId?key1=value1&key2=value2`, 72 | "method": "PATCH", 73 | "data": {"body": "value"} 74 | }) 75 | .reply(200, [{"alert": "name"}]); 76 | const result = await client.alert.acknowledge("myAlertId", {"body": "value"}, {"key1": "value1", "key2": "value2"}); 77 | expect(result).to.equal([{"alert": "name"}]); 78 | }); 79 | }); 80 | }); 81 | 82 | describe("Alert Class", () => { 83 | 84 | const mockRequest = { 85 | "request": stub().returns(new Promise(resolve => resolve({"data": "some test data"}))) 86 | }; 87 | const mockHttpClient = new HttpClient(mockRequest, "dummyPublicKey", "dummyPrivateKey"); 88 | 89 | const alert = new Alert(mockHttpClient, "dummyBaseUrl", "dummyProjectId"); 90 | 91 | describe("When GetAll method is called with querystring parameters and httpOptions", () => { 92 | it("Should send appropriate parameters to underlying request", async () => { 93 | const requestParams = {"digestAuth": "dummyPublicKey:dummyPrivateKey", "dataType": "json"}; 94 | await alert.getAll({"queryStringParam1": "value1", "httpOptions": {"options1": "value1"}}); 95 | expect(mockRequest.request.calledWith("dummyBaseUrl/groups/dummyProjectId/alerts?queryStringParam1=value1", {...requestParams, "options1": "value1"})).to.be.true(); 96 | }); 97 | }); 98 | 99 | describe("When Get method is called with querystring parameters and httpOptions", () => { 100 | it("Should send appropriate parameters to underlying request", async () => { 101 | const requestParams = {"digestAuth": "dummyPublicKey:dummyPrivateKey", "dataType": "json"}; 102 | await alert.get("alertId", {"queryStringParam1": "value1", "httpOptions": {"options1": "value1"}}); 103 | expect(mockRequest.request.calledWith("dummyBaseUrl/groups/dummyProjectId/alerts/alertId?queryStringParam1=value1", {...requestParams, "options1": "value1"})).to.be.true(); 104 | }); 105 | }); 106 | 107 | describe("When Acknowledge method is called with querystring parameters and httpOptions", () => { 108 | it("Should send appropriate parameters to underlying request", async () => { 109 | const requestParams = { 110 | "digestAuth": "dummyPublicKey:dummyPrivateKey", 111 | "dataType": "json", 112 | "method": "PATCH", 113 | "data": {"body": "text"}, 114 | "headers": {"Content-Type": "application/json"}}; 115 | await alert.acknowledge("alertId", {"body": "text"}, {"queryStringParam1": "value1", "httpOptions": {"options1": "value1"}}); 116 | expect(mockRequest.request.calledWith("dummyBaseUrl/groups/dummyProjectId/alerts/alertId?queryStringParam1=value1", {...requestParams, "options1": "value1"})).to.be.true(); 117 | }); 118 | }); 119 | 120 | }); -------------------------------------------------------------------------------- /test/organization.test.js: -------------------------------------------------------------------------------- 1 | const {describe, it, afterEach, before, beforeEach} = exports.lab = require("@hapi/lab").script(); 2 | const {expect} = require('@hapi/code'); 3 | const getClient = require('../src/index.js'); 4 | const {MockAgent, setGlobalDispatcher} = require('urllib'); 5 | 6 | const baseUrl = "http://localhost:7001"; 7 | 8 | const client = getClient({ 9 | "publicKey": "dummuyPublicKey", 10 | "privateKey": "dummyPrivateKey", 11 | "baseUrl": baseUrl 12 | }); 13 | 14 | describe("Mongo Atlas Api Client - Organization", () => { 15 | 16 | let mockAgent; 17 | let mockPool; 18 | before(() => { 19 | mockAgent = new MockAgent(); 20 | setGlobalDispatcher(mockAgent); 21 | }); 22 | 23 | beforeEach(() => { 24 | mockPool = mockAgent.get(baseUrl); 25 | }); 26 | 27 | afterEach(() => { 28 | mockAgent.assertNoPendingInterceptors(); 29 | }); 30 | 31 | describe("When organization is exported from index", () => { 32 | it("should export organization functions", async () => { 33 | expect(client.organization.getById).to.be.function(); 34 | expect(client.organization.getAll).to.be.function(); 35 | expect(client.organization.delete).to.be.function(); 36 | expect(client.organization.rename).to.be.function(); 37 | expect(client.organization.getAllUsersForOrganization).to.be.function(); 38 | expect(client.organization.getAllProjectsForOrganization).to.be.function(); 39 | expect(client.organization.invite).to.be.function(); 40 | }); 41 | }); 42 | 43 | describe("When getById is called with querystring parameters", () => { 44 | it("should return response", async () => { 45 | mockPool.intercept({ 46 | "path": "/orgs/orgName", 47 | "query": {"key1": "value1", "key2": "value2"}, 48 | "method": "GET" 49 | }).reply(200, {"organization": "name"}); 50 | const result = await client.organization.getById("orgName", {"key1": "value1", "key2": "value2"}); 51 | expect(result).to.equal({"organization": "name"}); 52 | 53 | }); 54 | }); 55 | 56 | describe("When getAllUsersForOrganization is called with querystring parameters", () => { 57 | it("should return response", async () => { 58 | mockPool.intercept({ 59 | "path": "/orgs/orgId/users?key1=value1&key2=value2", 60 | "method": "GET" 61 | }) 62 | .reply(200, {"organization": "name"}); 63 | const result = await client.organization.getAllUsersForOrganization("orgId", {"key1": "value1", "key2": "value2"}); 64 | expect(result).to.equal({"organization": "name"}); 65 | 66 | }); 67 | }); 68 | 69 | describe("When getAll is called with querystring parameters", () => { 70 | it("should return response", async () => { 71 | mockPool.intercept({ 72 | "path": "/orgs?key1=value1&key2=value2", 73 | "method": "GET" 74 | }) 75 | .reply(200, [{"organization": "name"}]); 76 | const result = await client.organization.getAll({"key1": "value1", "key2": "value2"}); 77 | expect(result).to.equal([{"organization": "name"}]); 78 | 79 | }); 80 | }); 81 | 82 | describe("When rename is called with querystring parameters", () => { 83 | it("should return response", async () => { 84 | mockPool.intercept({ 85 | "path": "/orgs/orgId?key1=value1&key2=value2", 86 | "method": "PATCH", 87 | "data": {"body": "value"} 88 | }) 89 | .reply(200, [{"organization": "name"}]); 90 | const result = await client.organization.rename("orgId", {"body": "value"}, {"key1": "value1", "key2": "value2"}); 91 | expect(result).to.equal([{"organization": "name"}]); 92 | 93 | }); 94 | }); 95 | 96 | describe("When getAllProjectsForOrganization is called with querystring parameters", () => { 97 | it("should return response", async () => { 98 | mockPool.intercept({ 99 | "path": "/orgs/orgId/groups?key1=value1&key2=value2", 100 | "method": "GET" 101 | }) 102 | .reply(200, [{"organization": "name"}]); 103 | const result = await client.organization.getAllProjectsForOrganization("orgId", {"key1": "value1", "key2": "value2"}); 104 | expect(result).to.equal([{"organization": "name"}]); 105 | 106 | }); 107 | }); 108 | 109 | describe("When delete is called with querystring parameters", () => { 110 | it("should return response", async () => { 111 | mockPool.intercept({ 112 | "path": "/orgs/orgId?key1=value1&key2=value2", 113 | "method": "DELETE" 114 | }) 115 | .reply(200, true); 116 | const result = await client.organization.delete("orgId", {"key1": "value1", "key2": "value2"}); 117 | expect(result).to.be.true(); 118 | 119 | }); 120 | }); 121 | 122 | describe("When invite is called with querystring parameters", () => { 123 | it("should return response", async () => { 124 | mockPool.intercept({ 125 | "path": "/orgs/orgId/invites?key1=value1&key2=value2", 126 | "method": "POST", 127 | "data": {"body": "value"} 128 | }) 129 | .reply(200, [{"organization": "name"}]); 130 | const result = await client.organization.invite("orgId", {"body": "value"}, {"key1": "value1", "key2": "value2"}); 131 | expect(result).to.equal([{"organization": "name"}]); 132 | 133 | }); 134 | }); 135 | }); 136 | -------------------------------------------------------------------------------- /test/project.test.js: -------------------------------------------------------------------------------- 1 | const {describe, it, afterEach, before, beforeEach} = exports.lab = require("@hapi/lab").script(); 2 | const {expect} = require('@hapi/code'); 3 | const getClient = require('../src/index.js'); 4 | const {MockAgent, setGlobalDispatcher} = require('urllib'); 5 | 6 | const baseUrl = "http://localhost:7001"; 7 | 8 | const client = getClient({ 9 | "publicKey": "dummuyPublicKey", 10 | "privateKey": "dummyPrivateKey", 11 | "baseUrl": baseUrl 12 | }); 13 | 14 | describe("Mongo Atlas Api Client - Project", () => { 15 | 16 | let mockAgent; 17 | let mockPool; 18 | before(() => { 19 | mockAgent = new MockAgent(); 20 | setGlobalDispatcher(mockAgent); 21 | }); 22 | 23 | beforeEach(() => { 24 | mockPool = mockAgent.get(baseUrl); 25 | }); 26 | 27 | afterEach(() => { 28 | mockAgent.assertNoPendingInterceptors(); 29 | }); 30 | 31 | describe("When project is exported from index", () => { 32 | it("should export project functions", async () => { 33 | expect(client.project.getById).to.be.function(); 34 | expect(client.project.getByName).to.be.function(); 35 | expect(client.project.getAll).to.be.function(); 36 | expect(client.project.getTeamsByProjectId).to.be.function(); 37 | expect(client.project.getByName).to.be.function(); 38 | expect(client.project.delete).to.be.function(); 39 | expect(client.project.removeUserFromProject).to.be.function(); 40 | expect(client.project.assignTeams).to.be.function(); 41 | }); 42 | }); 43 | 44 | describe("When getById is called with querystring parameters", () => { 45 | it("should return response", async () => { 46 | mockPool.intercept({ 47 | "path": "/groups/projectId?key1=value1&key2=value2", 48 | "method": "GET" 49 | }) 50 | .reply(200, {"project": "name"}); 51 | const result = await client.project.getById("projectId", {"key1": "value1", "key2": "value2"}); 52 | expect(result).to.equal({"project": "name"}); 53 | 54 | }); 55 | }); 56 | 57 | describe("When getByName is called with querystring parameters", () => { 58 | it("should return response", async () => { 59 | mockPool.intercept({ 60 | "path": "/groups/byName/projectName?key1=value1&key2=value2", 61 | "method": "GET" 62 | }) 63 | .reply(200, {"project": "name"}); 64 | const result = await client.project.getByName("projectName", {"key1": "value1", "key2": "value2"}); 65 | expect(result).to.equal({"project": "name"}); 66 | 67 | }); 68 | }); 69 | 70 | describe("When getTeamsByProjectId is called with querystring parameters", () => { 71 | it("should return response", async () => { 72 | mockPool.intercept({ 73 | "path": "/groups/projectId/teams?key1=value1&key2=value2", 74 | "method": "GET" 75 | }) 76 | .reply(200, {"project": "name"}); 77 | const result = await client.project.getTeamsByProjectId("projectId", {"key1": "value1", "key2": "value2"}); 78 | expect(result).to.equal({"project": "name"}); 79 | 80 | }); 81 | }); 82 | 83 | describe("When getAll is called with querystring parameters", () => { 84 | it("should return response", async () => { 85 | mockPool.intercept({ 86 | "path": "/groups?key1=value1&key2=value2", 87 | "method": "GET" 88 | }) 89 | .reply(200, [{"project": "name"}]); 90 | const result = await client.project.getAll({"key1": "value1", "key2": "value2"}); 91 | expect(result).to.equal([{"project": "name"}]); 92 | 93 | }); 94 | }); 95 | 96 | describe("When assignTeams is called with querystring parameters", () => { 97 | it("should return response", async () => { 98 | mockPool.intercept({ 99 | "path": "/groups/projectId/teams?key1=value1&key2=value2", 100 | "method": "POST", 101 | "data": {"body": "value"} 102 | }) 103 | .reply(200, [{"project": "name"}]); 104 | const result = await client.project.assignTeams("projectId", {"body": "value"}, {"key1": "value1", "key2": "value2"}); 105 | expect(result).to.equal([{"project": "name"}]); 106 | 107 | }); 108 | }); 109 | 110 | describe("When create is called with querystring parameters", () => { 111 | it("should return response", async () => { 112 | mockPool.intercept({ 113 | "path": "/groups?key1=value1&key2=value2", 114 | "method": "POST", 115 | "data": {"body": "value"} 116 | }) 117 | .reply(200, [{"project": "name"}]); 118 | const result = await client.project.create({"body": "value"}, {"key1": "value1", "key2": "value2"}); 119 | expect(result).to.equal([{"project": "name"}]); 120 | 121 | }); 122 | }); 123 | 124 | describe("When delete is called with querystring parameters", () => { 125 | it("should return response", async () => { 126 | mockPool.intercept({ 127 | "path": "/groups/projectId?key1=value1&key2=value2", 128 | "method": "DELETE" 129 | }) 130 | .reply(200, true); 131 | const result = await client.project.delete("projectId", {"key1": "value1", "key2": "value2"}); 132 | expect(result).to.be.true(); 133 | 134 | }); 135 | }); 136 | 137 | describe("When removeUserFromProject is called with querystring parameters", () => { 138 | it("should return response", async () => { 139 | mockPool.intercept({ 140 | "path": "/groups/projectId/users/userId?key1=value1&key2=value2", 141 | "method": "DELETE" 142 | }) 143 | .reply(200, true); 144 | const result = await client.project.removeUserFromProject("projectId", "userId", {"key1": "value1", "key2": "value2"}); 145 | expect(result).to.be.true(); 146 | 147 | }); 148 | }); 149 | }); 150 | -------------------------------------------------------------------------------- /test/cluster.test.js: -------------------------------------------------------------------------------- 1 | const {describe, it, afterEach, before, beforeEach} = exports.lab = require("@hapi/lab").script(); 2 | const {expect} = require('@hapi/code'); 3 | const getClient = require('../src/index.js'); 4 | const {MockAgent, setGlobalDispatcher} = require('urllib'); 5 | 6 | const baseUrl = "http://localhost:7001"; 7 | const projectId = "dummyProjectId"; 8 | 9 | const client = getClient({ 10 | "publicKey": "dummuyPublicKey", 11 | "privateKey": "dummyPrivateKey", 12 | "baseUrl": baseUrl, 13 | "projectId": projectId 14 | }); 15 | 16 | describe("Mongo Atlas Api Client - Cluster", () => { 17 | 18 | let mockAgent; 19 | let mockPool; 20 | before(() => { 21 | mockAgent = new MockAgent(); 22 | setGlobalDispatcher(mockAgent); 23 | }); 24 | 25 | beforeEach(() => { 26 | mockPool = mockAgent.get(baseUrl); 27 | }); 28 | 29 | afterEach(() => { 30 | mockAgent.assertNoPendingInterceptors(); 31 | }); 32 | 33 | describe("When cluster is exported from index", () => { 34 | it("should export cluster functions", async () => { 35 | expect(client.cluster.get).to.be.function(); 36 | expect(client.cluster.getAll).to.be.function(); 37 | expect(client.cluster.create).to.be.function(); 38 | expect(client.cluster.delete).to.be.function(); 39 | expect(client.cluster.update).to.be.function(); 40 | expect(client.cluster.updateAdvanceConfiguration).to.be.function(); 41 | expect(client.cluster.testPrimaryFailOver).to.be.function(); 42 | expect(client.cluster.getAdvanceConfiguration).to.be.function(); 43 | }); 44 | }); 45 | 46 | describe("When get is called with querystring parameters", () => { 47 | it("should return response", async () => { 48 | mockPool.intercept({ 49 | "path": `/groups/${projectId}/clusters/mycluster?key1=value1&key2=value2`, 50 | "method": "get" 51 | }) 52 | .reply(200, {"cluster": "name"}); 53 | const result = await client.cluster.get("mycluster", {"key1": "value1", "key2": "value2"}); 54 | expect(result).to.equal({"cluster": "name"}); 55 | 56 | }); 57 | }); 58 | 59 | describe("When getAdvanceConfiguration is called with querystring parameters", () => { 60 | it("should return response", async () => { 61 | mockPool.intercept({ 62 | "path": `/groups/${projectId}/clusters/mycluster/processArgs?key1=value1&key2=value2`, 63 | "method": "get" 64 | }) 65 | .reply(200, {"cluster": "name"}); 66 | const result = await client.cluster.getAdvanceConfiguration("mycluster", {"key1": "value1", "key2": "value2"}); 67 | expect(result).to.equal({"cluster": "name"}); 68 | 69 | }); 70 | }); 71 | 72 | describe("When getAll is called with querystring parameters", () => { 73 | it("should return response", async () => { 74 | mockPool.intercept({ 75 | "path": `/groups/${projectId}/clusters?key1=value1&key2=value2`, 76 | "method": "get" 77 | }) 78 | .reply(200, [{"cluster": "name"}]); 79 | const result = await client.cluster.getAll({"key1": "value1", "key2": "value2"}); 80 | expect(result).to.equal([{"cluster": "name"}]); 81 | 82 | }); 83 | }); 84 | 85 | describe("When update is called with querystring parameters", () => { 86 | it("should return response", async () => { 87 | mockPool.intercept({ 88 | "path": `/groups/${projectId}/clusters/myCluster?key1=value1&key2=value2`, 89 | "method": "patch", 90 | "data": {"body": "value"} 91 | }) 92 | .reply(200, [{"cluster": "name"}]); 93 | const result = await client.cluster.update("myCluster", {"body": "value"}, {"key1": "value1", "key2": "value2"}); 94 | expect(result).to.equal([{"cluster": "name"}]); 95 | 96 | }); 97 | }); 98 | 99 | describe("When updateAdvanceConfiguration is called with querystring parameters", () => { 100 | it("should return response", async () => { 101 | mockPool.intercept({ 102 | "path": `/groups/${projectId}/clusters/myCluster/processArgs?key1=value1&key2=value2`, 103 | "method": "patch", 104 | "data": {"body": "value"} 105 | }) 106 | .reply(200, [{"cluster": "name"}]); 107 | const result = await client.cluster.updateAdvanceConfiguration("myCluster", {"body": "value"}, {"key1": "value1", "key2": "value2"}); 108 | expect(result).to.equal([{"cluster": "name"}]); 109 | 110 | }); 111 | }); 112 | 113 | describe("When create is called with querystring parameters", () => { 114 | it("should return response", async () => { 115 | mockPool.intercept({ 116 | "path": `/groups/${projectId}/clusters?key1=value1&key2=value2`, 117 | "method": "post", 118 | "data": {"body": "value"} 119 | }) 120 | .reply(200, [{"cluster": "name"}]); 121 | const result = await client.cluster.create({"body": "value"}, {"key1": "value1", "key2": "value2"}); 122 | expect(result).to.equal([{"cluster": "name"}]); 123 | 124 | }); 125 | }); 126 | 127 | describe("When testPrimaryFailOver is called with querystring parameters", () => { 128 | it("should return response", async () => { 129 | mockPool.intercept({ 130 | "path": `/groups/${projectId}/clusters/mycluster/restartPrimaries?key1=value1&key2=value2`, 131 | "method": "post", 132 | "data": {"body": "value"} 133 | }) 134 | .reply(200, [{"cluster": "name"}]); 135 | const result = await client.cluster.testPrimaryFailOver("mycluster", {"key1": "value1", "key2": "value2"}); 136 | expect(result).to.equal([{"cluster": "name"}]); 137 | 138 | }); 139 | }); 140 | 141 | describe("When delete is called with querystring parameters", () => { 142 | it("should return response", async () => { 143 | mockPool.intercept({ 144 | "path": `/groups/${projectId}/clusters/mycluster?key1=value1&key2=value2`, 145 | "method": "delete" 146 | }) 147 | .reply(200, true); 148 | const result = await client.cluster.delete("mycluster", {"key1": "value1", "key2": "value2"}); 149 | expect(result).to.be.true(); 150 | 151 | }); 152 | }); 153 | }); 154 | -------------------------------------------------------------------------------- /src/cluster.d.ts: -------------------------------------------------------------------------------- 1 | import {KeyValuePairDocumentArray, AtlasResultsResponse, AtlasClientOptions, AtlasError} from "."; 2 | 3 | // Clusterclient 4 | export type ClusterName = string; 5 | export interface ClusterRegionConfig { 6 | [regionName: string]: { 7 | analyticsNodes: number; 8 | electableNodes: number; 9 | readOnlyNodes: number; 10 | priority: number; 11 | }; 12 | } 13 | export interface GetClusterResponse { 14 | autoScaling: { 15 | compute: { 16 | enabled: boolean; 17 | scaleDownEnabled: boolean; 18 | }; 19 | diskGBEnable: boolean; 20 | }; 21 | backupEnabled: boolean; 22 | biConnector: { 23 | enabled: boolean; 24 | readPreference: 'primary' | 'secondary' | 'analytics' 25 | }; 26 | clusterType: 'REPLICASET' | 'SHARDED' | 'GEOSHARDED'; 27 | diskSizeGB: number; 28 | encryptionAtRestProvider: string; 29 | groupId: string; 30 | id: string; 31 | labels: KeyValuePairDocumentArray; 32 | mongoDBVersion: string; 33 | mongoDBMajorVersion: string; 34 | mongoURI: string; 35 | mongoURIUpdated: string; 36 | mongoURIWithOptions: string; 37 | name: string; 38 | numShards: number; 39 | paused: boolean; 40 | pitEnabled: boolean; 41 | providerBackupEnabled: boolean; 42 | providerSettings: { 43 | autoScaling: { 44 | compute: { 45 | minInstanceSize: string; 46 | maxInstanceSize: string; 47 | }; 48 | }; 49 | providerName: 'AWS' | 'GCP' | 'AZURE' | 'TENANT'; 50 | backingProviderName: 'AWS' | 'GCP' | 'AZURE'; 51 | regionName: string; 52 | instanceSizeName: string; 53 | diskIOPS: number; 54 | diskTypeName: 'P4' | 'P6' | 'P10' | 'P20' | 'P30' | 'P40' | 'P50'; 55 | encryptEBSVolume: boolean; 56 | }; 57 | replicationFactor: number; 58 | replicationSpec: ClusterRegionConfig; 59 | replicationSpecs: { 60 | id: string; 61 | zoneName: string; 62 | numShards: number; 63 | regionsConfig: ClusterRegionConfig; 64 | }[]; 65 | srvAddress: string; 66 | stateName: string; 67 | } 68 | export type GetAllClustersResponse = AtlasResultsResponse; 69 | export interface CreateClusterRequest { 70 | autoScaling?: { 71 | compute?: { 72 | enabled?: boolean; 73 | scaleDownEnabled?: boolean; 74 | }; 75 | diskGBEnable?: boolean; 76 | }; 77 | backupEnabled?: boolean; 78 | biConnector?: { 79 | enabled?: boolean; 80 | readPreference?: 'primary' | 'secondary' | 'analytics' 81 | }; 82 | clusterType?: 'REPLICASET' | 'SHARDED' | 'GEOSHARDED'; 83 | diskSizeGB?: number; 84 | encryptionAtRestProvider?: string; 85 | labels?: KeyValuePairDocumentArray; 86 | name: string; 87 | mongoDBMajorVersion?: string; 88 | numShards?: number; 89 | pitEnabled?: boolean; 90 | providerBackupEnabled?: boolean; 91 | providerSettings: { 92 | autoScaling?: { 93 | compute?: { 94 | minInstanceSize?: string; 95 | maxInstanceSize?: string; 96 | }; 97 | }; 98 | backingProviderName?: 'AWS' | 'GCP' | 'AZURE'; 99 | diskIOPS?: number; 100 | diskTypeName?: 'P4' | 'P6' | 'P10' | 'P20' | 'P30' | 'P40' | 'P50'; 101 | encryptEBSVolume?: boolean; 102 | instanceSizeName?: string; 103 | providerName?: 'AWS' | 'GCP' | 'AZURE' | 'TENANT'; 104 | regionName?: string; 105 | volumeType?: string; 106 | }; 107 | replicationFactor?: number; 108 | replicationSpec?: ClusterRegionConfig; 109 | replicationSpecs?: { 110 | id?: string; 111 | zoneName: string; 112 | numShards: number; 113 | regionsConfig?: ClusterRegionConfig; 114 | }[]; 115 | } 116 | export interface GetClusterAdvancedConfigResponse { 117 | failIndexKeyTooLong: boolean; 118 | javascriptEnabled: boolean; 119 | minimumEnabledTlsProtocol: string; 120 | noTableScan: boolean; 121 | oplogSizeMB: number; 122 | sampleSizeBIConnector: number; 123 | sampleRefreshIntervalBIConnector: number; 124 | } 125 | export type CreateClusterResponse = GetClusterResponse; 126 | export interface UpdateClusterRequest { 127 | autoScaling?: { 128 | compute?: { 129 | enabled?: boolean; 130 | scaleDownEnabled?: boolean; 131 | }; 132 | diskGBEnable?: boolean; 133 | }; 134 | backupEnabled?: boolean; 135 | biConnector?: { 136 | enabled?: boolean; 137 | readPreference?: 'primary' | 'secondary' | 'analytics' 138 | }; 139 | clusterType?: 'REPLICASET' | 'SHARDED' | 'GEOSHARDED'; 140 | diskSizeGB?: number; 141 | encryptionAtRestProvider?: string; 142 | labels?: KeyValuePairDocumentArray; 143 | name: string; 144 | mongoDBMajorVersion?: string; 145 | numShards?: number; 146 | pitEnabled?: boolean; 147 | providerBackupEnabled?: boolean; 148 | providerSettings: { 149 | autoScaling?: { 150 | compute?: { 151 | minInstanceSize?: string; 152 | maxInstanceSize?: string; 153 | }; 154 | }; 155 | backingProviderName?: 'AWS' | 'GCP' | 'AZURE'; 156 | diskIOPS?: number; 157 | diskTypeName?: 'P4' | 'P6' | 'P10' | 'P20' | 'P30' | 'P40' | 'P50'; 158 | encryptEBSVolume?: boolean; 159 | instanceSizeName?: string; 160 | providerName?: 'AWS' | 'GCP' | 'AZURE' | 'TENANT'; 161 | regionName?: string; 162 | volumeType?: string; 163 | }; 164 | replicationFactor?: number; 165 | replicationSpec?: ClusterRegionConfig; 166 | replicationSpecs?: { 167 | id?: string; 168 | zoneName: string; 169 | numShards: number; 170 | regionsConfig?: ClusterRegionConfig; 171 | }[]; 172 | } 173 | export type UpdateClusterResponse = GetClusterResponse; 174 | export interface UpdateClusterAdvancedConfigurationRequest { 175 | failIndexKeyTooLong?: boolean; 176 | javascriptEnabled?: boolean; 177 | minimumEnabledTlsProtocol?: string; 178 | noTableScan?: boolean; 179 | oplogSizeMB?: number; 180 | sampleSizeBIConnector?: number; 181 | sampleRefreshIntervalBIConnector?: number; 182 | } 183 | export type UpdateClusterAdvancedConfigurationResponse = GetClusterAdvancedConfigResponse 184 | export interface Cluster { 185 | get(clustername: ClusterName, options?: AtlasClientOptions): Promise; 186 | getAdvanceConfiguration(clustername: ClusterName, options?: AtlasClientOptions): Promise; 187 | getAll(options?: AtlasClientOptions): Promise; 188 | delete(cluster: ClusterName, options?: AtlasClientOptions): Promise; 189 | create(cluster: CreateClusterRequest, options?: AtlasClientOptions): Promise; 190 | update(clustername: ClusterName, cluster: UpdateClusterRequest, options?: AtlasClientOptions): Promise; 191 | updateAdvanceConfiguration(clustername: ClusterName, cluster: UpdateClusterAdvancedConfigurationRequest, options?: AtlasClientOptions): Promise; 192 | testPrimaryFailOver(clustername: ClusterName, options?: AtlasClientOptions): Promise<{} | AtlasError>; 193 | } -------------------------------------------------------------------------------- /eslint.config.js: -------------------------------------------------------------------------------- 1 | // eslint.config.js 2 | const pluginJs = require("@eslint/js"); 3 | 4 | module.exports = [ 5 | pluginJs.configs.recommended, 6 | { 7 | languageOptions: { 8 | ecmaVersion: "latest", 9 | sourceType: "commonjs", 10 | globals: { 11 | process: "readonly", 12 | __dirname: "readonly", 13 | __filename: "readonly", 14 | require: "readonly", 15 | module: "readonly", 16 | exports: "writable", 17 | console: "readonly", 18 | Buffer: "readonly", 19 | URLSearchParams: "readonly" 20 | } 21 | }, 22 | rules: { 23 | // Possible Errors 24 | "comma-dangle": ["error", "never"], 25 | "getter-return": "error", 26 | "no-async-promise-executor": "error", 27 | "no-await-in-loop": "error", 28 | "no-compare-neg-zero": "error", 29 | "no-cond-assign": "error", 30 | "no-console": "error", 31 | "no-constant-condition": "error", 32 | "no-control-regex": "error", 33 | "no-debugger": "error", 34 | "no-dupe-args": "error", 35 | "no-dupe-keys": "error", 36 | "no-duplicate-case": "error", 37 | "no-empty-character-class": "error", 38 | "no-empty": "error", 39 | "no-ex-assign": "error", 40 | "no-extra-boolean-cast": "error", 41 | "no-extra-parens": "off", 42 | "no-extra-semi": "error", 43 | "no-func-assign": "error", 44 | "no-inner-declarations": ["error", "functions"], 45 | "no-invalid-regexp": "error", 46 | "no-irregular-whitespace": "error", 47 | "no-obj-calls": "error", 48 | "no-regex-spaces": "error", 49 | "no-sparse-arrays": "off", 50 | "no-unreachable": "error", 51 | "use-isnan": "error", 52 | "valid-typeof": "error", 53 | "no-unexpected-multiline": "error", 54 | 55 | // Best Practices 56 | "accessor-pairs": "error", 57 | "block-scoped-var": "off", 58 | "complexity": ["warn", 9], 59 | "consistent-return": "warn", 60 | "curly": ["error", "all"], 61 | "default-case": "off", 62 | "dot-notation": "error", 63 | "dot-location": ["error", "property"], 64 | "eqeqeq": "error", 65 | "guard-for-in": "error", 66 | "no-alert": "error", 67 | "no-caller": "error", 68 | "no-div-regex": "error", 69 | "no-else-return": "error", 70 | "no-eq-null": "error", 71 | "no-eval": "error", 72 | "no-extend-native": "error", 73 | "no-extra-bind": "error", 74 | "no-fallthrough": "error", 75 | "no-floating-decimal": "error", 76 | "no-implicit-coercion": "error", 77 | "no-implied-eval": "error", 78 | "no-invalid-this": "error", 79 | "no-iterator": "error", 80 | "no-labels": "error", 81 | "no-lone-blocks": "error", 82 | "no-loop-func": "error", 83 | "no-multi-spaces": ["error", { "ignoreEOLComments": true }], 84 | "no-multi-str": "error", 85 | "no-new-func": "error", 86 | "no-new-wrappers": "error", 87 | "no-new": "error", 88 | "no-octal-escape": "error", 89 | "no-octal": "error", 90 | "no-param-reassign": "error", 91 | "no-proto": "error", 92 | "no-redeclare": "error", 93 | "no-return-assign": "error", 94 | "no-return-await": "error", 95 | "no-script-url": "error", 96 | "no-self-assign": "error", 97 | "no-self-compare": "error", 98 | "no-sequences": "error", 99 | "no-throw-literal": "error", 100 | "no-unused-expressions": "off", 101 | "no-useless-call": "error", 102 | "no-void": "error", 103 | "no-warning-comments": "off", 104 | "no-with": "error", 105 | "radix": "error", 106 | "vars-on-top": "error", 107 | "wrap-iife": "error", 108 | "yoda": "error", 109 | 110 | // Variables 111 | "init-declarations": "off", 112 | "no-delete-var": "error", 113 | "no-label-var": "error", 114 | "no-shadow-restricted-names": "error", 115 | "no-shadow": "error", 116 | "no-undef-init": "error", 117 | "no-undef": "error", 118 | "no-undefined": "off", 119 | "no-unused-vars": "error", 120 | "no-use-before-define": "error", 121 | 122 | // Node.js (using stylistic rules where available in ESLint 9) 123 | "callback-return": "off", // Removed in ESLint 9 124 | "global-require": "off", // Removed in ESLint 9 125 | "handle-callback-err": "off", // Removed in ESLint 9 126 | "no-mixed-requires": "off", // Removed in ESLint 9 127 | "no-new-require": "off", // Removed in ESLint 9 128 | "no-path-concat": "off", // Removed in ESLint 9 129 | "no-process-env": "off", // Removed in ESLint 9 130 | "no-process-exit": "off", // Removed in ESLint 9 131 | "no-restricted-modules": "off", 132 | "no-sync": "off", // Removed in ESLint 9 133 | "no-buffer-constructor": "error", 134 | 135 | // Stylistic Issues (many moved to @stylistic/eslint-plugin in ESLint 9) 136 | "array-bracket-spacing": "off", 137 | "brace-style": "off", 138 | "camelcase": "error", 139 | "comma-spacing": "off", 140 | "comma-style": "off", 141 | "computed-property-spacing": "off", 142 | "consistent-this": "off", 143 | "eol-last": "off", 144 | "func-names": "off", 145 | "func-style": "off", 146 | "id-length": ["error", { "min": 2, "max": 70, "exceptions": ["i", "j", "k", "n", "Q", "_"] }], 147 | "id-match": "off", 148 | "indent": "off", 149 | "key-spacing": "off", 150 | "lines-around-comment": "off", 151 | "linebreak-style": "off", 152 | "max-nested-callbacks": ["error", 6], 153 | "max-statements-per-line": "off", 154 | "new-cap": "off", 155 | "new-parens": "off", 156 | "newline-after-var": "off", 157 | "no-array-constructor": "error", 158 | "no-continue": "error", 159 | "no-inline-comments": "off", 160 | "no-lonely-if": "error", 161 | "no-mixed-spaces-and-tabs": "error", 162 | "no-multiple-empty-lines": "off", 163 | "no-nested-ternary": "error", 164 | "no-new-object": "error", 165 | "no-spaced-func": "off", 166 | "no-ternary": "off", 167 | "no-trailing-spaces": "off", 168 | "no-underscore-dangle": "off", 169 | "no-unneeded-ternary": "error", 170 | "object-curly-spacing": "off", 171 | "one-var": ["warn", "never"], 172 | "operator-assignment": ["error", "always"], 173 | "operator-linebreak": "off", 174 | "padded-blocks": "off", 175 | "quote-props": "off", 176 | "quotes": "off", 177 | "semi-spacing": "off", 178 | "semi": "off", 179 | "sort-vars": "off", 180 | "keyword-spacing": "off", 181 | "space-before-blocks": "off", 182 | "space-before-function-paren": "off", 183 | "space-in-parens": "off", 184 | "space-infix-ops": "off", 185 | "space-unary-ops": "off", 186 | "spaced-comment": "off", 187 | "wrap-regex": "off", 188 | 189 | // ECMAScript 6 190 | "arrow-parens": "off", 191 | "arrow-spacing": "off", 192 | "constructor-super": "error", 193 | "generator-star-spacing": "off", 194 | "no-class-assign": "error", 195 | "no-const-assign": "error", 196 | "no-this-before-super": "error", 197 | "no-var": "error", 198 | "object-shorthand": ["error", "methods"], 199 | "prefer-const": "error", 200 | "prefer-spread": "error", 201 | "require-yield": "error", 202 | "prefer-template": "error" 203 | } 204 | } 205 | ]; -------------------------------------------------------------------------------- /test/atlasUser.test.js: -------------------------------------------------------------------------------- 1 | const {describe, it, afterEach, before, beforeEach} = exports.lab = require("@hapi/lab").script(); 2 | const {expect} = require('@hapi/code'); 3 | const getClient = require('../src/index.js'); 4 | const AtlasUser = require('../src/atlasUser.js'); 5 | const HttpClient = require('../src/httpClient.js'); 6 | const {stub} = require("sinon"); 7 | const {MockAgent, setGlobalDispatcher} = require('urllib'); 8 | 9 | const baseUrl = "http://localhost:7001"; 10 | const projectId = "dummyProjectId"; 11 | 12 | const client = getClient({ 13 | "publicKey": "dummuyPublicKey", 14 | "privateKey": "dummyPrivateKey", 15 | "baseUrl": baseUrl, 16 | "projectId": projectId 17 | }); 18 | 19 | describe("Mongo Atlas Api Client - Atlas User", () => { 20 | 21 | let mockAgent; 22 | let mockPool; 23 | before(() => { 24 | mockAgent = new MockAgent(); 25 | setGlobalDispatcher(mockAgent); 26 | }); 27 | 28 | beforeEach(() => { 29 | mockPool = mockAgent.get(baseUrl); 30 | }); 31 | 32 | afterEach(() => { 33 | mockAgent.assertNoPendingInterceptors(); 34 | }); 35 | 36 | describe("When atlasUser is exported from index", () => { 37 | it("should export atlasUser functions", async () => { 38 | expect(client.atlasUser.getById).to.be.function(); 39 | expect(client.atlasUser.getAll).to.be.function(); 40 | expect(client.atlasUser.create).to.be.function(); 41 | expect(client.atlasUser.getByName).to.be.function(); 42 | expect(client.atlasUser.update).to.be.function(); 43 | }); 44 | }); 45 | 46 | describe("When getByName is called with querystring parameters", () => { 47 | it("should return response", async () => { 48 | mockPool.intercept({ 49 | "path": "/users/byName/myuser?key1=value1&key2=value2", 50 | "method": "get" 51 | }) 52 | .reply(200, {"user": "name"}); 53 | const result = await client.atlasUser.getByName("myuser", {"key1": "value1", "key2": "value2"}); 54 | expect(result).to.equal({"user": "name"}); 55 | }); 56 | }); 57 | 58 | describe("When getById is called with querystring parameters", () => { 59 | it("should return response", async () => { 60 | mockPool.intercept({ 61 | "path": "/users/someid?key1=value1&key2=value2", 62 | "method": "get" 63 | }) 64 | .reply(200, {"user": "name"}); 65 | const result = await client.atlasUser.getById("someid", {"key1": "value1", "key2": "value2"}); 66 | expect(result).to.equal({"user": "name"}); 67 | }); 68 | }); 69 | 70 | describe("When getAll is called with querystring parameters", () => { 71 | it("should return response", async () => { 72 | mockPool.intercept({ 73 | "path": `/groups/${projectId}/users?key1=value1&key2=value2`, 74 | "method": "get" 75 | }) 76 | .reply(200, [{"user": "name"}]); 77 | const result = await client.atlasUser.getAll({"key1": "value1", "key2": "value2"}); 78 | expect(result).to.equal([{"user": "name"}]); 79 | }); 80 | }); 81 | 82 | describe("When update is called with querystring parameters", () => { 83 | it("should return response", async () => { 84 | mockPool.intercept({ 85 | "path": "/users/someId?key1=value1&key2=value2", 86 | "method": "PATCH", 87 | "data": {"body": "value"} 88 | }) 89 | .reply(200, [{"user": "name"}]); 90 | const result = await client.atlasUser.update("someId", {"body": "value"}, {"key1": "value1", "key2": "value2"}); 91 | expect(result).to.equal([{"user": "name"}]); 92 | }); 93 | }); 94 | 95 | describe("When create is called with querystring parameters", () => { 96 | it("should return response", async () => { 97 | mockPool.intercept({ 98 | "path": "/users?key1=value1&key2=value2", 99 | "method": "POST", 100 | "data": {"body": "value"} 101 | }) 102 | .reply(200, [{"user": "name"}]); 103 | const result = await client.atlasUser.create({"body": "value"}, {"key1": "value1", "key2": "value2"}); 104 | expect(result).to.equal([{"user": "name"}]); 105 | }); 106 | }); 107 | }); 108 | 109 | describe("AtlasUser Class", () => { 110 | 111 | const mockRequest = { 112 | "request": stub().returns(new Promise(resolve => resolve({"data": "some test data"}))) 113 | }; 114 | const mockHttpClient = new HttpClient(mockRequest, "dummyPublicKey", "dummyPrivateKey"); 115 | 116 | const atlasUser = new AtlasUser(mockHttpClient, "dummyBaseUrl", "dummyProjectId"); 117 | 118 | describe("When getByName method is called with querystring parameters and httpOptions", () => { 119 | it("Should send appropriate parameters to underlying request", async () => { 120 | const requestParams = {"digestAuth": "dummyPublicKey:dummyPrivateKey", "dataType": "json"}; 121 | await atlasUser.getByName("username", {"queryStringParam1": "value1", "httpOptions": {"options1": "value1"}}); 122 | expect(mockRequest.request.calledWith("dummyBaseUrl/users/byName/username?queryStringParam1=value1", {...requestParams, "options1": "value1"})).to.be.true(); 123 | }); 124 | }); 125 | 126 | describe("When getById method is called with querystring parameters and httpOptions", () => { 127 | it("Should send appropriate parameters to underlying request", async () => { 128 | const requestParams = {"digestAuth": "dummyPublicKey:dummyPrivateKey", "dataType": "json"}; 129 | await atlasUser.getById("userId", {"queryStringParam1": "value1", "httpOptions": {"options1": "value1"}}); 130 | expect(mockRequest.request.calledWith("dummyBaseUrl/users/userId?queryStringParam1=value1", {...requestParams, "options1": "value1"})).to.be.true(); 131 | }); 132 | }); 133 | 134 | describe("When getAll method is called with querystring parameters and httpOptions", () => { 135 | it("Should send appropriate parameters to underlying request", async () => { 136 | const requestParams = {"digestAuth": "dummyPublicKey:dummyPrivateKey", "dataType": "json"}; 137 | await atlasUser.getAll({"queryStringParam1": "value1", "httpOptions": {"options1": "value1"}}); 138 | expect(mockRequest.request.calledWith("dummyBaseUrl/groups/dummyProjectId/users?queryStringParam1=value1", {...requestParams, "options1": "value1"})).to.be.true(); 139 | }); 140 | }); 141 | 142 | describe("When update method is called with querystring parameters and httpOptions", () => { 143 | it("Should send appropriate parameters to underlying request", async () => { 144 | const requestParams = { 145 | "digestAuth": "dummyPublicKey:dummyPrivateKey", 146 | "dataType": "json", 147 | "method": "PATCH", 148 | "data": {"body": "text"}, 149 | "headers": {"Content-Type": "application/json"} 150 | }; 151 | await atlasUser.update("userId", {"body": "text"}, {"queryStringParam1": "value1", "httpOptions": {"options1": "value1"}}); 152 | expect(mockRequest.request.calledWith("dummyBaseUrl/users/userId?queryStringParam1=value1", {...requestParams, "options1": "value1"})).to.be.true(); 153 | }); 154 | }); 155 | 156 | describe("When create method is called with querystring parameters and httpOptions", () => { 157 | it("Should send appropriate parameters to underlying request", async () => { 158 | const requestParams = { 159 | "digestAuth": "dummyPublicKey:dummyPrivateKey", 160 | "dataType": "json", 161 | "method": "POST", 162 | "data": {"body": "text"}, 163 | "headers": {"Content-Type": "application/json"} 164 | }; 165 | await atlasUser.create({"body": "text"}, {"queryStringParam1": "value1", "httpOptions": {"options1": "value1"}}); 166 | expect(mockRequest.request.calledWith("dummyBaseUrl/users?queryStringParam1=value1", {...requestParams, "options1": "value1"})).to.be.true(); 167 | }); 168 | }); 169 | 170 | }); 171 | -------------------------------------------------------------------------------- /.github/copilot-instructions.md: -------------------------------------------------------------------------------- 1 | # MongoDB Atlas API Client - Copilot Instructions 2 | 3 | ## Project Overview 4 | 5 | This is a MongoDB Atlas API client library for Node.js that provides a programmatic interface to the MongoDB Atlas REST API. The library uses HTTP Digest Authentication and wraps the urllib HTTP client library. 6 | 7 | ## Architecture and Code Organization 8 | 9 | ### Module Structure 10 | - Each API resource (User, Cluster, Project, Organization, etc.) is implemented as a separate class in `src/` 11 | - Each class follows a consistent pattern: 12 | - Constructor receives: `client`, `baseUrl`, and optionally `projectId` 13 | - Methods return promises 14 | - All API methods accept an optional `options` parameter 15 | - The main entry point (`src/index.js`) exports a factory function that creates instances of all API resource classes 16 | - TypeScript definitions (`.d.ts` files) are provided alongside each JavaScript file 17 | 18 | ### Key Components 19 | - `httpClient.js`: HTTP client wrapper that handles digest authentication 20 | - `helper.js`: Utility functions for query string generation 21 | - `index.js`: Main entry point that instantiates and exports all API resource clients 22 | 23 | ## Code Patterns and Conventions 24 | 25 | ### API Method Pattern 26 | ```javascript 27 | async methodName(param1, param2, options = {}) { 28 | const queryString = getQueryStringFromOptions(options); 29 | const httpOptions = options.httpOptions; 30 | const response = await this.client_.fetch(`${this.baseUrl_}/path/${param1}?${queryString}`, { 31 | "method": "METHOD", 32 | "data": body, 33 | ...httpOptions 34 | }); 35 | return response; 36 | } 37 | ``` 38 | 39 | ### Class Pattern 40 | - Private properties use trailing underscore: `this.client_`, `this.baseUrl_`, `this.projectId_` 41 | - All methods are async and return promises 42 | - Methods should handle `options` parameter for query strings and HTTP options 43 | - The `httpOptions` parameter is extracted from options and passed separately (not included in query string) 44 | 45 | ### Naming Conventions 46 | - Use camelCase for variables and function names 47 | - Use PascalCase for class names 48 | - Use descriptive names (e.g., `getAll`, `getById`, `delete`, `create`, `update`) 49 | - Private instance variables end with underscore: `this.client_`, `this.baseUrl_` 50 | 51 | ## Testing Requirements 52 | 53 | ### Test Framework 54 | - Uses `@hapi/lab` for test execution 55 | - Uses `@hapi/code` for assertions 56 | - Uses `sinon` for stubbing/mocking when needed 57 | - Uses `urllib`'s MockAgent for HTTP mocking 58 | - **100% code coverage is required** - all tests must pass with full coverage 59 | 60 | ### Test Structure Pattern 61 | ```javascript 62 | const {describe, it, afterEach, before, beforeEach} = exports.lab = require("@hapi/lab").script(); 63 | const {expect} = require('@hapi/code'); 64 | const getClient = require('../src/index.js'); 65 | const {MockAgent, setGlobalDispatcher} = require('urllib'); 66 | 67 | const baseUrl = "http://localhost:7001"; 68 | const projectId = "dummyProjectId"; 69 | 70 | const client = getClient({ 71 | "publicKey": "dummyPublicKey", 72 | "privateKey": "dummyPrivateKey", 73 | "baseUrl": baseUrl, 74 | "projectId": projectId 75 | }); 76 | 77 | describe("Mongo Atlas Api Client - ResourceName", () => { 78 | let mockAgent; 79 | let mockPool; 80 | 81 | before(() => { 82 | mockAgent = new MockAgent(); 83 | setGlobalDispatcher(mockAgent); 84 | }); 85 | 86 | beforeEach(() => { 87 | mockPool = mockAgent.get(baseUrl); 88 | }); 89 | 90 | afterEach(() => { 91 | mockAgent.assertNoPendingInterceptors(); 92 | }); 93 | 94 | describe("When method is called", () => { 95 | it("should return expected result", async () => { 96 | mockPool.intercept({ 97 | "path": `/expected/path`, 98 | "method": "get" 99 | }).reply(200, {"response": "data"}); 100 | 101 | const result = await client.resource.method(); 102 | expect(result).to.equal({"response": "data"}); 103 | }); 104 | }); 105 | }); 106 | ``` 107 | 108 | ### Test Guidelines 109 | - Test file names match source files: `user.js` → `user.test.js` 110 | - Each resource should have tests for: 111 | - Verification that methods are exported from index 112 | - Each public method with various parameter combinations 113 | - Query string handling 114 | - HTTP options handling 115 | - Use MockAgent to intercept HTTP requests 116 | - Always call `mockAgent.assertNoPendingInterceptors()` in afterEach 117 | 118 | ## Linting and Code Style 119 | 120 | ### ESLint Configuration 121 | - Uses ESLint 9 with `@eslint/js` recommended config 122 | - ES2015+ (latest) JavaScript syntax 123 | - CommonJS module system (not ES modules) 124 | - Strict rules including: 125 | - No console logs (`no-console: error`) 126 | - No var declarations (`no-var: error`) 127 | - Prefer const (`prefer-const: error`) 128 | - Prefer template literals (`prefer-template: error`) 129 | - Complexity limit of 9 (`complexity: [warn, 9]`) 130 | - One variable declaration per statement (`one-var: [warn, never]`) 131 | - Variable name length: 2-70 characters (with exceptions for i, j, k, n, Q, _) 132 | 133 | ### Code Style Guidelines 134 | - Use double quotes for strings (no enforcement, but check existing code) 135 | - Use semicolons at end of statements (no enforcement, but check existing code) 136 | - No trailing commas in arrays/objects (`comma-dangle: [error, never]`) 137 | - Use arrow functions for callbacks where appropriate 138 | - Prefer object method shorthand 139 | 140 | ## Build and Development Commands 141 | 142 | ```bash 143 | # Install dependencies 144 | npm install 145 | 146 | # Run tests (includes linting and depcheck) 147 | npm test 148 | 149 | # Run linting only 150 | npm run lint 151 | 152 | # Run dependency check 153 | npm run depcheck 154 | 155 | # Version bumping and publishing 156 | npm run patch # Bump patch version 157 | npm run minor # Bump minor version 158 | npm run major # Bump major version 159 | ``` 160 | 161 | ### Pre-test Steps 162 | The `pretest` script automatically runs: 163 | 1. Dependency check with `depcheck` 164 | 2. ESLint on all source and test files 165 | 166 | ## TypeScript Definitions 167 | 168 | - All source files should have corresponding `.d.ts` TypeScript definition files 169 | - Type definitions should match the JavaScript implementation 170 | - Export types for all public classes and their methods 171 | - Method signatures should include parameter types and return types 172 | 173 | ## Dependencies 174 | 175 | ### Production 176 | - `urllib`: HTTP client library (version 4.x) 177 | 178 | ### Development 179 | - `@hapi/lab`: Test runner 180 | - `@hapi/code`: Assertion library 181 | - `eslint`: Linting 182 | - `depcheck`: Dependency checker 183 | - `sinon`: Test stubbing/mocking 184 | 185 | ## MongoDB Atlas API Specifics 186 | 187 | ### Authentication 188 | - Uses HTTP Digest Authentication 189 | - Requires public key (username) and private key (password) 190 | - Authentication is handled by HttpClient class 191 | 192 | ### Common Parameters 193 | - `baseUrl`: MongoDB Atlas API base URL (e.g., `https://cloud.mongodb.com/api/atlas/v1.0`) 194 | - `projectId`: MongoDB Atlas project/group ID 195 | - `options`: Object that can contain: 196 | - Query parameters (e.g., `envelope`, `itemsPerPage`, `pretty`) 197 | - `httpOptions`: Additional options passed to urllib (e.g., `timeout`) 198 | 199 | ### URL Structure 200 | - Groups and projects are synonymous in MongoDB Atlas API 201 | - URLs typically follow pattern: `/groups/{projectId}/resource/{identifier}` 202 | 203 | ## Best Practices for Contributing 204 | 205 | 1. **Minimal Changes**: Make the smallest possible changes to accomplish the goal 206 | 2. **Test Coverage**: Maintain 100% test coverage - add tests for all new code 207 | 3. **Consistency**: Follow existing patterns in the codebase 208 | 4. **No Breaking Changes**: Don't modify existing public APIs unless necessary 209 | 5. **Documentation**: Update README.md if adding new features 210 | 6. **Type Safety**: Update corresponding `.d.ts` files when modifying JavaScript 211 | 7. **Error Handling**: Follow existing error handling patterns (let errors propagate) 212 | 8. **Async/Await**: Use async/await for all asynchronous operations (not callbacks or raw promises) 213 | 214 | ## Common Tasks 215 | 216 | ### Adding a New API Resource 217 | 218 | 1. Create `src/resourceName.js` with class following the established pattern 219 | 2. Create `src/resourceName.d.ts` with TypeScript definitions 220 | 3. Add resource to `src/index.js` initialization and exports 221 | 4. Create `test/resourceName.test.js` with comprehensive tests 222 | 5. Ensure 100% coverage and all tests pass 223 | 6. Update README.md if the resource is a significant new feature 224 | 225 | ### Adding a Method to Existing Resource 226 | 227 | 1. Add method to the class in `src/` 228 | 2. Update corresponding `.d.ts` file 229 | 3. Add comprehensive tests in `test/` file 230 | 4. Ensure 100% coverage maintained 231 | 5. Run linter and fix any issues 232 | 233 | ## Important Notes 234 | 235 | - This library is production code used by many users - stability is critical 236 | - All changes must pass existing tests without modification 237 | - HTTP interactions are mocked in tests using urllib's MockAgent 238 | - The library uses MongoDB Atlas API v1.0 239 | - Digest authentication is required for all API calls 240 | -------------------------------------------------------------------------------- /test/atlasSearch.test.js: -------------------------------------------------------------------------------- 1 | const {describe, it, afterEach, before, beforeEach} = exports.lab = require("@hapi/lab").script(); 2 | const {expect} = require('@hapi/code'); 3 | const getClient = require('../src/index.js'); 4 | const AtlasSearch = require('../src/atlasSearch.js'); 5 | const HttpClient = require('../src/httpClient.js'); 6 | const {stub} = require("sinon"); 7 | const {MockAgent, setGlobalDispatcher} = require('urllib'); 8 | 9 | const baseUrl = "http://localhost:7001"; 10 | const projectId = "dummyProjectId"; 11 | 12 | const client = getClient({ 13 | "publicKey": "dummuyPublicKey", 14 | "privateKey": "dummyPrivateKey", 15 | "baseUrl": baseUrl, 16 | "projectId": projectId 17 | }); 18 | 19 | describe("Mongo Atlas Api Client - atlasSearch", () => { 20 | 21 | let mockAgent; 22 | let mockPool; 23 | before(() => { 24 | mockAgent = new MockAgent(); 25 | setGlobalDispatcher(mockAgent); 26 | }); 27 | 28 | beforeEach(() => { 29 | mockPool = mockAgent.get(baseUrl); 30 | }); 31 | 32 | afterEach(() => { 33 | mockAgent.assertNoPendingInterceptors(); 34 | }); 35 | 36 | describe("When atlasSearch is exported from index", () => { 37 | it("should export atlasSearch functions", async () => { 38 | expect(client.atlasSearch.get).to.be.function(); 39 | expect(client.atlasSearch.getAll).to.be.function(); 40 | expect(client.atlasSearch.create).to.be.function(); 41 | expect(client.atlasSearch.delete).to.be.function(); 42 | expect(client.atlasSearch.update).to.be.function(); 43 | expect(client.atlasSearch.getAllAnalyzers).to.be.function(); 44 | expect(client.atlasSearch.upsertAnalyzer).to.be.function(); 45 | }); 46 | }); 47 | 48 | describe("When get is called with querystring parameters", () => { 49 | it("should return response", async () => { 50 | mockPool.intercept({ 51 | "path": `/groups/${projectId}/clusters/mycluster/fts/indexes/myindexId?key1=value1&key2=value2`, 52 | "method": "GET" 53 | }).reply(200, {"atlasSearch": "name"}); 54 | const result = await client.atlasSearch.get("mycluster", "myindexId", {"key1": "value1", "key2": "value2"}); 55 | expect(result).to.equal({"atlasSearch": "name"}); 56 | }); 57 | }); 58 | 59 | describe("When getAll is called with querystring parameters", () => { 60 | it("should return response", async () => { 61 | mockPool.intercept({ 62 | "path": `/groups/${projectId}/clusters/mycluster/fts/indexes/mydatabasename/mycollectionname?key1=value1&key2=value2`, 63 | "method": "GET" 64 | }).reply(200, [{"atlasSearch": "name"}]); 65 | const result = await client.atlasSearch.getAll("mycluster", "mydatabasename", "mycollectionname", {"key1": "value1", "key2": "value2"}); 66 | expect(result).to.equal([{"atlasSearch": "name"}]); 67 | }); 68 | }); 69 | 70 | describe("When getAllAnalyzers is called with querystring parameters", () => { 71 | it("should return response", async () => { 72 | mockPool.intercept({ 73 | "path": `/groups/${projectId}/clusters/mycluster/fts/analyzers?key1=value1&key2=value2`, 74 | "method": "GET" 75 | }).reply(200, [{"atlasSearch": "name"}]); 76 | const result = await client.atlasSearch.getAllAnalyzers("mycluster", {"key1": "value1", "key2": "value2"}); 77 | expect(result).to.equal([{"atlasSearch": "name"}]); 78 | }); 79 | }); 80 | 81 | describe("When update is called with querystring parameters", () => { 82 | it("should return response", async () => { 83 | mockPool.intercept({ 84 | "path": `/groups/${projectId}/clusters/mycluster/fts/indexes/indexId?key1=value1&key2=value2`, 85 | "method": "PATCH", 86 | "data": {"body": "value"} 87 | }).reply(200, [{"atlasSearch": "name"}]); 88 | const result = await client.atlasSearch.update("mycluster", "indexId", {"body": "value"}, {"key1": "value1", "key2": "value2"}); 89 | expect(result).to.equal([{"atlasSearch": "name"}]); 90 | }); 91 | }); 92 | 93 | describe("When upsertAnalyzer is called with querystring parameters", () => { 94 | it("should return response", async () => { 95 | mockPool.intercept({ 96 | "path": `/groups/${projectId}/clusters/mycluster/fts/analyzers?key1=value1&key2=value2`, 97 | "method": "PUT", 98 | "data": {"body": "value"} 99 | }).reply(200, [{"atlasSearch": "name"}]); 100 | const result = await client.atlasSearch.upsertAnalyzer("mycluster", {"body": "value"}, {"key1": "value1", "key2": "value2"}); 101 | expect(result).to.equal([{"atlasSearch": "name"}]); 102 | }); 103 | }); 104 | 105 | describe("When create is called with querystring parameters", () => { 106 | it("should return response", async () => { 107 | mockPool.intercept({ 108 | "path": `/groups/${projectId}/clusters/mycluster/fts/indexes?key1=value1&key2=value2`, 109 | "method": "POST", 110 | "data": {"body": "value"} 111 | }).reply(200, [{"atlasSearch": "name"}]); 112 | const result = await client.atlasSearch.create("mycluster", {"body": "value"}, {"key1": "value1", "key2": "value2"}); 113 | expect(result).to.equal([{"atlasSearch": "name"}]); 114 | }); 115 | }); 116 | 117 | describe("When delete is called with querystring parameters", () => { 118 | it("should return response", async () => { 119 | mockPool.intercept({ 120 | "path": `/groups/${projectId}/clusters/mycluster/fts/indexes/indexId?key1=value1&key2=value2`, 121 | "method": "DELETE" 122 | }).reply(200, true); 123 | const result = await client.atlasSearch.delete("mycluster", "indexId", {"key1": "value1", "key2": "value2"}); 124 | expect(result).to.be.true(); 125 | }); 126 | }); 127 | }); 128 | 129 | describe("AtlasSearch Class", () => { 130 | 131 | const mockRequest = { 132 | "request": stub().returns(new Promise(resolve => resolve({"data": "some test data"}))) 133 | }; 134 | const mockHttpClient = new HttpClient(mockRequest, "dummyPublicKey", "dummyPrivateKey"); 135 | 136 | const atlasSearch = new AtlasSearch(mockHttpClient, "dummyBaseUrl", "dummyProjectId"); 137 | 138 | describe("When getAllAnalyzers method is called with querystring parameters and httpOptions", () => { 139 | it("Should send appropriate parameters to underlying request", async () => { 140 | const requestParams = {"digestAuth": "dummyPublicKey:dummyPrivateKey", "dataType": "json"}; 141 | await atlasSearch.getAllAnalyzers("clusterName", {"queryStringParam1": "value1", "httpOptions": {"options1": "value1"}}); 142 | expect(mockRequest.request.calledWith("dummyBaseUrl/groups/dummyProjectId/clusters/clusterName/fts/analyzers?queryStringParam1=value1", {...requestParams, "options1": "value1"})).to.be.true(); 143 | }); 144 | }); 145 | 146 | describe("When Get method is called with querystring parameters and httpOptions", () => { 147 | it("Should send appropriate parameters to underlying request", async () => { 148 | const requestParams = {"digestAuth": "dummyPublicKey:dummyPrivateKey", "dataType": "json"}; 149 | await atlasSearch.get("clusterName", "indexId", {"queryStringParam1": "value1", "httpOptions": {"options1": "value1"}}); 150 | expect(mockRequest.request.calledWith("dummyBaseUrl/groups/dummyProjectId/clusters/clusterName/fts/indexes/indexId?queryStringParam1=value1", {...requestParams, "options1": "value1"})).to.be.true(); 151 | }); 152 | }); 153 | 154 | describe("When upsertAnalyzer method is called with querystring parameters and httpOptions", () => { 155 | it("Should send appropriate parameters to underlying request", async () => { 156 | const requestParams = { 157 | "digestAuth": "dummyPublicKey:dummyPrivateKey", 158 | "dataType": "json", 159 | "method": "PUT", 160 | "data": {"body": "text"}, 161 | "headers": {"Content-Type": "application/json"}}; 162 | await atlasSearch.upsertAnalyzer("clusterName", {"body": "text"}, {"queryStringParam1": "value1", "httpOptions": {"options1": "value1"}}); 163 | expect(mockRequest.request.calledWith("dummyBaseUrl/groups/dummyProjectId/clusters/clusterName/fts/analyzers?queryStringParam1=value1", {...requestParams, "options1": "value1"})).to.be.true(); 164 | }); 165 | }); 166 | 167 | describe("When getAll method is called with querystring parameters and httpOptions", () => { 168 | it("Should send appropriate parameters to underlying request", async () => { 169 | const requestParams = {"digestAuth": "dummyPublicKey:dummyPrivateKey", "dataType": "json"}; 170 | await atlasSearch.getAll("clusterName", "databaseName", "collectionName", {"queryStringParam1": "value1", "httpOptions": {"options1": "value1"}}); 171 | expect(mockRequest.request.calledWith("dummyBaseUrl/groups/dummyProjectId/clusters/clusterName/fts/indexes/databaseName/collectionName?queryStringParam1=value1", {...requestParams, "options1": "value1"})).to.be.true(); 172 | }); 173 | }); 174 | 175 | describe("When delete method is called with querystring parameters and httpOptions", () => { 176 | it("Should send appropriate parameters to underlying request", async () => { 177 | const requestParams = { 178 | "digestAuth": "dummyPublicKey:dummyPrivateKey", 179 | "dataType": "json", 180 | "method": "DELETE" 181 | }; 182 | await atlasSearch.delete("clusterName", "indexId", {"queryStringParam1": "value1", "httpOptions": {"options1": "value1"}}); 183 | expect(mockRequest.request.calledWith("dummyBaseUrl/groups/dummyProjectId/clusters/clusterName/fts/indexes/indexId?queryStringParam1=value1", {...requestParams, "options1": "value1"})).to.be.true(); 184 | }); 185 | }); 186 | 187 | describe("When update method is called with querystring parameters and httpOptions", () => { 188 | it("Should send appropriate parameters to underlying request", async () => { 189 | const requestParams = { 190 | "digestAuth": "dummyPublicKey:dummyPrivateKey", 191 | "dataType": "json", 192 | "method": "PATCH", 193 | "data": {"body": "text"}, 194 | "headers": {"Content-Type": "application/json"} 195 | }; 196 | await atlasSearch.update("clusterName", "indexId", {"body": "text"}, {"queryStringParam1": "value1", "httpOptions": {"options1": "value1"}}); 197 | expect(mockRequest.request.calledWith("dummyBaseUrl/groups/dummyProjectId/clusters/clusterName/fts/indexes/indexId?queryStringParam1=value1", {...requestParams, "options1": "value1"})).to.be.true(); 198 | }); 199 | }); 200 | 201 | describe("When create method is called with querystring parameters and httpOptions", () => { 202 | it("Should send appropriate parameters to underlying request", async () => { 203 | const requestParams = { 204 | "digestAuth": "dummyPublicKey:dummyPrivateKey", 205 | "dataType": "json", 206 | "method": "POST", 207 | "data": {"body": "text"}, 208 | "headers": {"Content-Type": "application/json"} 209 | }; 210 | await atlasSearch.create("clusterName", {"body": "text"}, {"queryStringParam1": "value1", "httpOptions": {"options1": "value1"}}); 211 | expect(mockRequest.request.calledWith("dummyBaseUrl/groups/dummyProjectId/clusters/clusterName/fts/indexes?queryStringParam1=value1", {...requestParams, "options1": "value1"})).to.be.true(); 212 | }); 213 | }); 214 | 215 | }); 216 | --------------------------------------------------------------------------------