├── .nvmrc ├── .eslintignore ├── commitlint.config.js ├── .eslintrc ├── .huskyrc ├── jest.config.js ├── jest.config.unit.js ├── jest.config.shared.js ├── jest.config.integration.js ├── src ├── range.js ├── translateQueryParameters.js ├── translateQueryParameters.unit.test.js ├── index.js └── index.integration.test.js ├── .npmignore ├── .babelrc ├── LICENSE ├── .gitignore ├── rollup.config.js ├── .github └── workflows │ └── workflows.yaml ├── package.json └── README.md /.nvmrc: -------------------------------------------------------------------------------- 1 | 12.14.1 2 | 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | coverage/* 2 | build 3 | node_modules 4 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-angular'] }; 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb-base", 3 | "env": { 4 | "jest": true 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /.huskyrc: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "pre-commit": "npm run lint", 4 | "commit-msg": "npm run commitmsg", 5 | "pre-push": "npm run test" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | collectCoverage: true, 3 | testEnvironment: 'node', 4 | testPathIgnorePatterns: [ 5 | '/build/', 6 | '/node_modules/', 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /jest.config.unit.js: -------------------------------------------------------------------------------- 1 | const sharedConfig = require('./jest.config.shared'); 2 | 3 | const config = { 4 | testMatch: ['**/**.unit.test.js'], 5 | ...sharedConfig, 6 | }; 7 | 8 | module.exports = config; 9 | -------------------------------------------------------------------------------- /jest.config.shared.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | collectCoverage: true, 3 | testEnvironment: 'node', 4 | testPathIgnorePatterns: [ 5 | '/build/', 6 | '/node_modules/', 7 | ], 8 | }; 9 | -------------------------------------------------------------------------------- /jest.config.integration.js: -------------------------------------------------------------------------------- 1 | const sharedConfig = require('./jest.config.shared'); 2 | 3 | const config = { 4 | testMatch: ['**/**.integration.test.js'], 5 | ...sharedConfig, 6 | }; 7 | 8 | module.exports = config; 9 | -------------------------------------------------------------------------------- /src/range.js: -------------------------------------------------------------------------------- 1 | const RANGE = Object.freeze({ 2 | LAST_7_DAYS: 'LAST_7_DAYS', 3 | LAST_30_DAYS: 'LAST_30_DAYS', 4 | LAST_6_MONTHS: 'LAST_6_MONTHS', 5 | LAST_YEAR: 'LAST_YEAR', 6 | }); 7 | 8 | export default RANGE; 9 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/** 2 | 3 | src/** 4 | test/** 5 | coverage/** 6 | 7 | npm-debug.log 8 | commitlint.config.js 9 | *.test.js 10 | 11 | .DS_Store 12 | .eslintcache 13 | .travis.yml 14 | .babelrc 15 | .eslintignore 16 | .eslintrc 17 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "test": { 4 | "presets": [ 5 | [ 6 | "@babel/preset-env", 7 | { "modules": "umd" } 8 | ] 9 | ], 10 | "plugins": [ 11 | "@babel/plugin-transform-runtime", 12 | "@babel/plugin-transform-regenerator" 13 | ], 14 | }, 15 | "production": { 16 | "presets": [ 17 | [ 18 | "@babel/preset-env", 19 | { "modules": false } 20 | ] 21 | ] 22 | } 23 | }, 24 | "plugins": [ 25 | "@babel/plugin-proposal-object-rest-spread" 26 | ], 27 | "ignore": [ 28 | "node_modules/**" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jae Bradley 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 | -------------------------------------------------------------------------------- /src/translateQueryParameters.js: -------------------------------------------------------------------------------- 1 | const translateSummaryParameters = ({ 2 | dateRange, 3 | projectName = null, 4 | branchNames = [], 5 | }) => { 6 | const { startDate, endDate } = dateRange; 7 | return { 8 | start: startDate, 9 | end: endDate, 10 | project: projectName, 11 | branches: branchNames.join(','), 12 | }; 13 | }; 14 | 15 | const translateStatsParameters = ({ 16 | timeout = null, 17 | useWritesOnly = null, 18 | projectName = null, 19 | } = {}) => ( 20 | { 21 | timeout, 22 | writes_only: useWritesOnly, 23 | project: projectName, 24 | } 25 | ); 26 | 27 | const translateDurationParameters = ({ date, projectName = null, branchNames = [] }) => ( 28 | { 29 | date, 30 | project: projectName, 31 | branches: branchNames.join(','), 32 | } 33 | ); 34 | 35 | const translateCommitsParameters = ({ authorUsername = null, pageNumber = null } = {}) => ( 36 | { 37 | author: authorUsername, 38 | page: pageNumber, 39 | } 40 | ); 41 | 42 | export { 43 | translateSummaryParameters, 44 | translateStatsParameters, 45 | translateDurationParameters, 46 | translateCommitsParameters, 47 | }; 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | build 61 | .DS_Store 62 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from '@rollup/plugin-babel'; 2 | import commonjs from '@rollup/plugin-commonjs'; 3 | import resolve from '@rollup/plugin-node-resolve'; 4 | import localResolve from 'rollup-plugin-local-resolve'; 5 | import filesize from 'rollup-plugin-filesize'; 6 | import minify from 'rollup-plugin-babel-minify'; 7 | import { terser } from 'rollup-plugin-terser'; 8 | 9 | import pkg from './package.json'; 10 | 11 | const config = { 12 | external: ['axios'], 13 | input: 'src/index.js', 14 | output: [ 15 | { 16 | file: pkg.browser, 17 | format: 'umd', 18 | name: pkg.name, 19 | globals: { 20 | axios: 'axios', 21 | }, 22 | }, 23 | { 24 | file: pkg.main, 25 | format: 'cjs', 26 | name: pkg.name, 27 | globals: { 28 | axios: 'axios', 29 | }, 30 | }, 31 | { 32 | file: pkg.module, 33 | format: 'es', 34 | name: pkg.name, 35 | globals: { 36 | axios: 'axios', 37 | }, 38 | }, 39 | ], 40 | plugins: [ 41 | babel({ exclude: 'node_modules/**', babelHelpers: 'bundled' }), 42 | localResolve(), 43 | resolve({ 44 | preferBuiltins: true, 45 | browser: true, 46 | modulesOnly: true, 47 | mainFields: 'browser', 48 | }), 49 | minify(), 50 | terser(), 51 | commonjs(), 52 | filesize(), 53 | ], 54 | }; 55 | 56 | export default config; 57 | -------------------------------------------------------------------------------- /.github/workflows/workflows.yaml: -------------------------------------------------------------------------------- 1 | name: Wakatime Client 2 | 3 | on: 4 | release: 5 | types: [published] 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | schedule: 11 | - cron: '0 12 * * *' 12 | 13 | jobs: 14 | build: 15 | name: Build 16 | runs-on: ${{ matrix.os }} 17 | strategy: 18 | matrix: 19 | os: [ubuntu-latest, macos-latest] 20 | node: [10, 12, 14] 21 | steps: 22 | - uses: actions/checkout@v2 23 | with: 24 | ref: ${{ github.ref }} 25 | - name: Setup Node 26 | uses: actions/setup-node@v1 27 | with: 28 | node-version: ${{ matrix.node }} 29 | - name: Cache dependencies 30 | uses: actions/cache@v2 31 | with: 32 | path: ~/.npm 33 | key: ${{ runner.OS }}-node-${{ hashFiles('**/package-lock.json') }} 34 | restore-keys: | 35 | ${{ runner.OS }}-node- 36 | ${{ runner.OS }}- 37 | - name: Install dependencies 38 | run: npm ci 39 | - name: Run Linting 40 | run: npm run lint 41 | - name: Run Build 42 | run: npm run build 43 | - name: Check Build Is ES5 Compatible 44 | run: npm run is-build-es5 45 | test: 46 | name: Test & Code Coverage 47 | runs-on: ubuntu-latest 48 | needs: build 49 | steps: 50 | - uses: actions/checkout@v2 51 | with: 52 | ref: ${{ github.ref }} 53 | - name: Setup Node 54 | uses: actions/setup-node@v1 55 | - name: Install dependencies 56 | run: npm ci 57 | - name: Run Tests 58 | run: npm run test 59 | env: 60 | ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }} 61 | DASHBOARD_ID: ${{ secrets.DASHBOARD_ID }} 62 | ORGANIZATION_ID: ${{ secrets.ORGANIZATION_ID }} 63 | USER_ID: ${{ secrets.USER_ID }} 64 | - name: Codecov 65 | uses: codecov/codecov-action@v1 66 | release: 67 | name: Release 68 | runs-on: ubuntu-latest 69 | if: ${{ github.ref == 'refs/heads/master' }} 70 | needs: test 71 | steps: 72 | - uses: actions/checkout@v2 73 | with: 74 | ref: ${{ github.ref }} 75 | - name: Setup Node 76 | uses: actions/setup-node@v1 77 | - name: Install dependencies 78 | run: npm ci 79 | - name: Run Build 80 | run: npm run build 81 | - name: Semantic Release 82 | uses: cycjimmy/semantic-release-action@v2 83 | with: 84 | semantic_version: 16 85 | env: 86 | GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} 87 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 88 | -------------------------------------------------------------------------------- /src/translateQueryParameters.unit.test.js: -------------------------------------------------------------------------------- 1 | import { 2 | translateSummaryParameters, 3 | translateStatsParameters, 4 | translateDurationParameters, 5 | translateCommitsParameters, 6 | } from './translateQueryParameters'; 7 | 8 | describe('translateQueryParameters', () => { 9 | const projectName = 'projectName'; 10 | const branchNames = ['jae', 'bae', 'bae']; 11 | 12 | describe('translateSummaryParameters', () => { 13 | const startDate = 'startDate'; 14 | const endDate = 'endDate'; 15 | const dateRange = { startDate, endDate }; 16 | 17 | it('gets only required parameters', () => { 18 | expect(translateSummaryParameters({ dateRange })).toEqual({ 19 | start: startDate, 20 | end: endDate, 21 | project: null, 22 | branches: '', 23 | }); 24 | }); 25 | 26 | it('gets all parameters', () => { 27 | expect(translateSummaryParameters({ dateRange, projectName, branchNames })).toEqual({ 28 | start: startDate, 29 | end: endDate, 30 | project: projectName, 31 | branches: 'jae,bae,bae', 32 | }); 33 | }); 34 | }); 35 | 36 | describe('translateStatsParameters', () => { 37 | it('gets only required parameters', () => { 38 | expect(translateStatsParameters()).toEqual({ 39 | timeout: null, 40 | writes_only: null, 41 | project: null, 42 | }); 43 | }); 44 | 45 | it('gets all parameters', () => { 46 | expect(translateStatsParameters({ 47 | timeout: 'timeout', 48 | useWritesOnly: 'useWritesOnly', 49 | projectName: 'projectName', 50 | })).toEqual({ 51 | timeout: 'timeout', 52 | writes_only: 'useWritesOnly', 53 | project: 'projectName', 54 | }); 55 | }); 56 | }); 57 | 58 | describe('translateDurationParameters', () => { 59 | const date = 'date'; 60 | 61 | it('gets only required parameters', () => { 62 | expect(translateDurationParameters({ date })).toEqual({ 63 | date, 64 | project: null, 65 | branches: '', 66 | }); 67 | }); 68 | 69 | it('gets all parameters', () => { 70 | expect(translateDurationParameters({ date, projectName, branchNames })).toEqual({ 71 | date, 72 | project: projectName, 73 | branches: 'jae,bae,bae', 74 | }); 75 | }); 76 | }); 77 | 78 | describe('translateCommitsParameters', () => { 79 | it('gets only required parameters', () => { 80 | expect(translateCommitsParameters()).toEqual({ author: null, page: null }); 81 | }); 82 | 83 | it('gets all parameters', () => { 84 | const authorUsername = 'authorUsername'; 85 | const pageNumber = 'pageNumber'; 86 | 87 | expect(translateCommitsParameters({ authorUsername, pageNumber })).toEqual({ 88 | author: authorUsername, 89 | page: pageNumber, 90 | }); 91 | }); 92 | }); 93 | }); 94 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wakatime-client", 3 | "version": "0.0.0-development", 4 | "description": "NodeJS Client for the Wakatime API", 5 | "keywords": [ 6 | "wakatime", 7 | "wakatime client" 8 | ], 9 | "homepage": "https://github.com/jaebradley/wakatime-client/#readme", 10 | "readme": "https://github.com/jaebradley/wakatime-client/#readme", 11 | "bugs": { 12 | "url": "https://github.com/jaebradley/wakatime-client/issues" 13 | }, 14 | "license": "MIT", 15 | "author": { 16 | "name": "jae.b.bradley@gmail.com" 17 | }, 18 | "files": [ 19 | "build" 20 | ], 21 | "browser": "build/index.js", 22 | "main": "build/index.cjs.js", 23 | "module": "build/index.esm.js", 24 | "repository": { 25 | "type": "git", 26 | "url": "https://github.com/jaebradley/wakatime-client" 27 | }, 28 | "global": false, 29 | "scripts": { 30 | "build": "BABEL_ENV=production npx rollup -c", 31 | "codecov": "npx codecov", 32 | "commitmsg": "npx commitlint -E HUSKY_GIT_PARAMS", 33 | "deploy": "npm run semantic-release'", 34 | "gc": "commit", 35 | "is-build-es5": "npx es-check es5 './build/**/*.!(esm).js'", 36 | "lint": "npx eslint --ext .js .", 37 | "prepare": "npm run build", 38 | "semantic-release": "npx semantic-release", 39 | "test": "BABEL_ENV=test jest src/ -c jest.config.shared.js", 40 | "unit-test": "BABEL_ENV=test jest src/ -c jest.config.unit.js", 41 | "integration-test": "BABEL_ENV=test jest src/ -c jest.config.integration.js" 42 | }, 43 | "dependencies": {}, 44 | "peerDependencies": { 45 | "axios": "^0.19.0" 46 | }, 47 | "devDependencies": { 48 | "@babel/cli": "^7.13.10", 49 | "@babel/core": "^7.13.10", 50 | "@babel/plugin-proposal-object-rest-spread": "^7.13.8", 51 | "@babel/plugin-transform-regenerator": "^7.12.13", 52 | "@babel/plugin-transform-runtime": "^7.13.10", 53 | "@babel/preset-env": "^7.13.12", 54 | "@babel/runtime": "^7.13.10", 55 | "@commitlint/cli": "^12.1.0", 56 | "@commitlint/config-angular": "^12.0.1", 57 | "@commitlint/prompt": "^12.1.0", 58 | "@commitlint/prompt-cli": "^12.1.0", 59 | "@rollup/plugin-babel": "^5.3.0", 60 | "@rollup/plugin-commonjs": "^18.0.0-1", 61 | "@rollup/plugin-node-resolve": "^11.2.0", 62 | "axios": "^0.21.1", 63 | "babel-core": "^7.0.0-bridge.0", 64 | "babel-jest": "^27.0.0-next.5", 65 | "codecov": "^3.8.1", 66 | "dotenv": "^8.2.0", 67 | "es-check": "^5.2.3", 68 | "eslint": "^7.22.0", 69 | "eslint-config-airbnb-base": "^14.2.1", 70 | "eslint-plugin-import": "^2.22.1", 71 | "husky": "^5.2.0", 72 | "jest": "^27.0.0-next.5", 73 | "marked": "^2.0.1", 74 | "rollup": "^2.42.3", 75 | "rollup-plugin-babel-minify": "^10.0.0", 76 | "rollup-plugin-filesize": "^9.1.1", 77 | "rollup-plugin-local-resolve": "^1.0.7", 78 | "rollup-plugin-terser": "^7.0.2", 79 | "semantic-release": "^17.4.2" 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import RANGE from './range'; 3 | import { 4 | translateSummaryParameters, 5 | translateStatsParameters, 6 | translateDurationParameters, 7 | translateCommitsParameters, 8 | } from './translateQueryParameters'; 9 | 10 | const rangeQueryParameters = Object.freeze({ 11 | [RANGE.LAST_7_DAYS]: 'last_7_days', 12 | [RANGE.LAST_30_DAYS]: 'last_30_days', 13 | [RANGE.LAST_6_MONTHS]: 'last_6_months', 14 | [RANGE.LAST_YEAR]: 'last_year', 15 | }); 16 | 17 | class WakaTimeClient { 18 | constructor(apiKey, baseURL = 'https://wakatime.com/api/v1/') { 19 | this.apiKey = apiKey; 20 | this.axiosConfiguration = axios.create({ 21 | baseURL, 22 | // Base-64 encode the API Key 23 | // https://wakatime.com/developers#introduction 24 | headers: { Authorization: `Basic ${Buffer.from(this.apiKey).toString('base64')}` }, 25 | }); 26 | } 27 | 28 | getUser(userId) { 29 | return this.axiosConfiguration.get(`users/${userId}`).then((response) => response.data); 30 | } 31 | 32 | getMe() { 33 | return this.axiosConfiguration.get('users/current').then((response) => response.data); 34 | } 35 | 36 | getTeams(userId) { 37 | return this.axiosConfiguration.get(`users/${userId}/teams`).then((response) => response.data); 38 | } 39 | 40 | getMyTeams() { 41 | return this.axiosConfiguration.get('users/current/teams').then((response) => response.data); 42 | } 43 | 44 | getUserAgents(userId) { 45 | return this.axiosConfiguration.get(`users/${userId}/user_agents`).then((response) => response.data); 46 | } 47 | 48 | getMyUserAgents() { 49 | return this.axiosConfiguration.get('users/current/user_agents').then((response) => response.data); 50 | } 51 | 52 | getTeamMembers({ userId, teamId }) { 53 | return this.axiosConfiguration.get(`users/${userId}/teams/${teamId}/members`).then((response) => response.data); 54 | } 55 | 56 | getMyTeamMembers(teamId) { 57 | return this.axiosConfiguration.get(`users/current/teams/${teamId}/members`).then((response) => response.data); 58 | } 59 | 60 | getTeamMemberSummary({ 61 | userId, 62 | teamId, 63 | teamMemberId, 64 | ...parameters 65 | }) { 66 | return this.axiosConfiguration.get( 67 | `users/${userId}/teams/${teamId}/members/${teamMemberId}/summaries`, 68 | { params: translateSummaryParameters(parameters) }, 69 | ).then((response) => response.data); 70 | } 71 | 72 | getMyTeamMemberSummary({ teamId, teamMemberId, ...parameters }) { 73 | return this.axiosConfiguration.get( 74 | `users/current/teams/${teamId}/members/${teamMemberId}/summaries`, 75 | { params: translateSummaryParameters(parameters) }, 76 | ).then((response) => response.data); 77 | } 78 | 79 | getUserSummary({ userId, ...parameters }) { 80 | return this.axiosConfiguration.get( 81 | `users/${userId}/summaries`, 82 | { params: translateSummaryParameters(parameters) }, 83 | ).then((response) => response.data); 84 | } 85 | 86 | getMySummary({ ...parameters }) { 87 | return this.axiosConfiguration.get( 88 | 'users/current/summaries', 89 | { params: translateSummaryParameters(parameters) }, 90 | ).then((response) => response.data); 91 | } 92 | 93 | getUserStats({ 94 | userId, 95 | range, 96 | ...parameters 97 | }) { 98 | return this.axiosConfiguration.get( 99 | `users/${userId}/stats/${rangeQueryParameters[range]}`, 100 | { params: translateStatsParameters(parameters) }, 101 | ).then((response) => response.data); 102 | } 103 | 104 | getMyStats({ range, ...parameters }) { 105 | return this.axiosConfiguration.get( 106 | `users/current/stats/${rangeQueryParameters[range]}`, 107 | { params: translateStatsParameters(parameters) }, 108 | ).then((response) => response.data); 109 | } 110 | 111 | getProjects(userId) { 112 | return this.axiosConfiguration.get(`users/${userId}/projects`).then((response) => response.data); 113 | } 114 | 115 | getMyProjects() { 116 | return this.axiosConfiguration.get('users/current/projects').then((response) => response.data); 117 | } 118 | 119 | getLeaders({ language = null, pageNumber = null } = {}) { 120 | return this.axiosConfiguration.get('leaders', { params: { language, page: pageNumber } }).then((response) => response.data); 121 | } 122 | 123 | getHeartbeats({ userId, date }) { 124 | return this.axiosConfiguration.get(`users/${userId}/heartbeats`, { params: { date } }).then((response) => response.data); 125 | } 126 | 127 | getMyHeartbeats(date) { 128 | return this.axiosConfiguration.get('users/current/heartbeats', { params: { date } }).then((response) => response.data); 129 | } 130 | 131 | getGoals(userId) { 132 | return this.axiosConfiguration.get(`users/${userId}/goals`).then((response) => response.data); 133 | } 134 | 135 | getMyGoals() { 136 | return this.axiosConfiguration.get('users/current/goals').then((response) => response.data); 137 | } 138 | 139 | getDurations({ userId, ...parameters }) { 140 | return this.axiosConfiguration.get( 141 | `users/${userId}/durations`, 142 | { params: translateDurationParameters(parameters) }, 143 | ).then((response) => response.data); 144 | } 145 | 146 | getMyDurations({ ...parameters }) { 147 | return this.axiosConfiguration.get('users/current/durations', { params: translateDurationParameters(parameters) }).then((response) => response.data); 148 | } 149 | 150 | getCommits({ userId, projectName, ...parameters }) { 151 | return this.axiosConfiguration.get( 152 | `users/${userId}/projects/${projectName}/commits`, 153 | { params: translateCommitsParameters(parameters) }, 154 | ).then((response) => response.data); 155 | } 156 | 157 | getMyCommits({ projectName, ...parameters }) { 158 | return this.axiosConfiguration.get( 159 | `users/current/projects/${projectName}/commits`, 160 | { params: translateCommitsParameters(parameters) }, 161 | ).then((response) => response.data); 162 | } 163 | 164 | getMetadata() { 165 | return this.axiosConfiguration.get('meta'); 166 | } 167 | 168 | getOrganizations(userId) { 169 | return this.axiosConfiguration.get(`users/${userId}/orgs`).then((response) => response.data); 170 | } 171 | 172 | getMyOrganizations() { 173 | return this.axiosConfiguration.get('users/current/orgs').then((response) => response.data); 174 | } 175 | 176 | getOrganizationDashboards({ userId, organizationId }) { 177 | return this.axiosConfiguration.get(`users/${userId}/orgs/${organizationId}`).then((response) => response.data); 178 | } 179 | 180 | getMyOrganizationDashboards(organizationId) { 181 | return this.getOrganizationDashboards({ userId: 'current', organizationId }); 182 | } 183 | 184 | getOrganizationDashboardMembers({ userId, organizationId, dashboardId }) { 185 | return this.axiosConfiguration.get(`users/${userId}/orgs/${organizationId}/dashboards/${dashboardId}/members`).then((response) => response.data); 186 | } 187 | 188 | getMyOrganizationDashboardMembers({ organizationId, dashboardId }) { 189 | return this.getOrganizationDashboardMembers({ userId: 'current', organizationId, dashboardId }); 190 | } 191 | 192 | getOrganizationDashboardMemberSummaries({ 193 | userId, 194 | organizationId, 195 | dashboardId, 196 | memberId, 197 | }) { 198 | return this.axiosConfiguration 199 | .get(`users/${userId}/orgs/${organizationId}/dashboards/${dashboardId}/members/${memberId}/summaries`) 200 | .then((response) => response.data); 201 | } 202 | 203 | getMyOrganizationDashboardMemberSummaries({ organizationId, dashboardId, memberId }) { 204 | return this.getOrganizationDashboardMemberSummaries({ 205 | userId: 'current', 206 | organizationId, 207 | dashboardId, 208 | memberId, 209 | }); 210 | } 211 | 212 | getOrganizationDashboardMemberDurations({ 213 | userId, 214 | organizationId, 215 | dashboardId, 216 | memberId, 217 | }) { 218 | return this.axiosConfiguration 219 | .get(`users/${userId}/orgs/${organizationId}/dashboards/${dashboardId}/members/${memberId}/durations`) 220 | .then((response) => response.data); 221 | } 222 | 223 | getMyOrganizationDashboardMemberDurations({ organizationId, dashboardId, memberId }) { 224 | return this.getOrganizationDashboardMemberDurations({ 225 | userId: 'current', 226 | organizationId, 227 | dashboardId, 228 | memberId, 229 | }); 230 | } 231 | } 232 | 233 | export { 234 | WakaTimeClient, 235 | RANGE, 236 | }; 237 | -------------------------------------------------------------------------------- /src/index.integration.test.js: -------------------------------------------------------------------------------- 1 | import dotenv from 'dotenv'; 2 | 3 | import { WakaTimeClient, RANGE } from '.'; 4 | 5 | dotenv.config(); 6 | 7 | jest.setTimeout(60000); 8 | 9 | describe('WakaTimeClient Integration Test', () => { 10 | let client; 11 | const userId = process.env.USER_ID; 12 | const startDate = new Date(new Date().setDate(new Date().getDate() - 6)); 13 | const endDate = new Date(); 14 | const formattedStartDate = startDate.toISOString().split('T')[0]; 15 | const formattedEndDate = endDate.toISOString().split('T')[0]; 16 | const date = startDate.toISOString().split('T')[0]; 17 | const dateRange = { 18 | startDate: formattedStartDate, 19 | endDate: formattedEndDate, 20 | }; 21 | const range = RANGE.LAST_7_DAYS; 22 | const projectName = 'jae-bradley-cli-creator'; 23 | const branchNames = ['master']; 24 | const organizationId = process.env.ORGANIZATION_ID; 25 | const dashboardId = process.env.DASHBOARD_ID; 26 | 27 | beforeEach(() => { 28 | client = new WakaTimeClient(process.env.ACCESS_TOKEN); 29 | }); 30 | 31 | describe('getUser', () => { 32 | it('gets user details', async () => { 33 | const response = await client.getUser(userId); 34 | const { data } = response; 35 | expect(data).toBeDefined(); 36 | expect(data).toMatchObject(expect.objectContaining({ 37 | created_at: '2017-02-18T07:50:22Z', 38 | id: userId, 39 | })); 40 | }); 41 | }); 42 | describe('getMe', () => { 43 | it('gets my user details', async () => { 44 | const response = await client.getMe(); 45 | const { data } = response; 46 | expect(data).toBeDefined(); 47 | expect(data).toMatchObject(expect.objectContaining({ 48 | created_at: '2017-02-18T07:50:22Z', 49 | id: userId, 50 | })); 51 | }); 52 | }); 53 | describe('getTeams', () => { 54 | it('gets teams', async () => { 55 | const response = await client.getTeams(userId); 56 | expect(response).toBeDefined(); 57 | }); 58 | }); 59 | describe('getMyTeams', () => { 60 | it('gets my teams', async () => { 61 | const response = await client.getMyTeams(); 62 | expect(response).toBeDefined(); 63 | }); 64 | }); 65 | describe('getUserAgents', () => { 66 | it('gets user agents', async () => { 67 | const response = await client.getUserAgents(userId); 68 | expect(response).toBeDefined(); 69 | }); 70 | }); 71 | 72 | describe('getMyUserAgents', () => { 73 | it('gets my user agents', async () => { 74 | const response = await client.getMyUserAgents(); 75 | expect(response).toBeDefined(); 76 | }); 77 | }); 78 | 79 | describe('getTeamMembers', () => { 80 | it('gets team members', async () => { 81 | // Test this when I have a test teams 82 | // const response = await client.getTeamMembers({ userId, teamId }); 83 | // const { data } = response; 84 | // const { data: teamMemberData } = data; 85 | // expect(teamMemberData).toBeDefined(); 86 | }); 87 | }); 88 | 89 | describe('getUserSummary', () => { 90 | it('gets user summary with default parameters', async () => { 91 | const response = await client.getUserSummary({ userId, dateRange }); 92 | expect(response).toBeDefined(); 93 | }); 94 | 95 | it('gets user summary with parameters', async () => { 96 | const response = await client.getUserSummary({ 97 | userId, 98 | dateRange, 99 | projectName, 100 | branchNames, 101 | }); 102 | expect(response).toBeDefined(); 103 | }); 104 | }); 105 | 106 | describe('getMySummary', () => { 107 | it('gets my summary with default parameters', async () => { 108 | const response = await client.getMySummary({ dateRange }); 109 | expect(response).toBeDefined(); 110 | }); 111 | 112 | it('gets my summary with parameters', async () => { 113 | const response = await client.getMySummary({ 114 | dateRange, 115 | projectName, 116 | branchNames, 117 | }); 118 | expect(response).toBeDefined(); 119 | }); 120 | }); 121 | 122 | describe('getUserStats', () => { 123 | it('gets user stats with default parameters', async () => { 124 | const response = await client.getUserStats({ userId, range }); 125 | expect(response).toBeDefined(); 126 | }); 127 | }); 128 | 129 | describe('getMyStats', () => { 130 | it('gets my stats with default parameters', async () => { 131 | const response = await client.getMyStats({ range }); 132 | expect(response).toBeDefined(); 133 | }); 134 | }); 135 | 136 | describe('getProjects', () => { 137 | it('gets projects', async () => { 138 | const response = await client.getProjects(userId); 139 | expect(response).toBeDefined(); 140 | }); 141 | }); 142 | 143 | describe('getMyProjects', () => { 144 | it('gets my projects', async () => { 145 | const response = await client.getMyProjects(); 146 | expect(response).toBeDefined(); 147 | }); 148 | }); 149 | 150 | describe('getLeaders', () => { 151 | it('gets leaders with default parameters', async () => { 152 | const response = await client.getLeaders(); 153 | expect(response).toBeDefined(); 154 | }); 155 | 156 | it('gets JavaScript leaders on page 2', async () => { 157 | const response = await client.getLeaders({ language: 'JavaScript', pageNumber: 2 }); 158 | expect(response).toBeDefined(); 159 | }); 160 | }); 161 | 162 | describe('getHeartbeats', () => { 163 | it('gets heartbeats for date', async () => { 164 | const response = await client.getHeartbeats({ userId, date }); 165 | expect(response).toBeDefined(); 166 | }); 167 | }); 168 | 169 | describe('getMyHeartbeats', () => { 170 | it('gets my heartbeats for date', async () => { 171 | const response = await client.getMyHeartbeats(date); 172 | expect(response).toBeDefined(); 173 | }); 174 | }); 175 | 176 | describe('getGoals', () => { 177 | it('gets goals', async () => { 178 | const response = await client.getGoals(userId); 179 | expect(response).toBeDefined(); 180 | }); 181 | }); 182 | 183 | describe('getMyGoals', () => { 184 | it('gets my goals', async () => { 185 | const response = await client.getMyGoals(); 186 | expect(response).toBeDefined(); 187 | }); 188 | }); 189 | 190 | describe('getDurations', () => { 191 | it('gets durations for date', async () => { 192 | const response = await client.getDurations({ userId, date }); 193 | expect(response).toBeDefined(); 194 | }); 195 | 196 | it('gets durations for date, project, and branches', async () => { 197 | const response = await client.getDurations({ 198 | userId, 199 | date, 200 | projectName, 201 | branchNames, 202 | }); 203 | expect(response).toBeDefined(); 204 | }); 205 | }); 206 | 207 | describe('getMyDurations', () => { 208 | it('gets my durations for date', async () => { 209 | const response = await client.getMyDurations({ date }); 210 | expect(response).toBeDefined(); 211 | }); 212 | 213 | it('gets my durations for date, project, and branches', async () => { 214 | const response = await client.getMyDurations({ date, projectName, branchNames }); 215 | expect(response).toBeDefined(); 216 | }); 217 | }); 218 | 219 | // describe('getCommits', () => { 220 | // it('gets commits with default parameters', async () => { 221 | // const response = await client.getCommits({ userId, projectName }); 222 | // const { data } = response; 223 | // const { data: commits } = data; 224 | // expect(commits).toBeDefined(); 225 | // }); 226 | // }); 227 | 228 | // describe('getMyCommits', () => { 229 | // it('gets my commits with default parameters', async () => { 230 | // const response = await client.getMyCommits({ projectName }); 231 | // const { data } = response; 232 | // const { data: myCommits } = data; 233 | // expect(myCommits).toBeDefined(); 234 | // }); 235 | // }); 236 | 237 | describe('getMetadata', () => { 238 | it('gets metadata about WakaTime', async () => { 239 | const response = await client.getMetadata(); 240 | expect(response).toBeDefined(); 241 | }); 242 | 243 | it('WakaTime metadata response has data property', async () => { 244 | const response = await client.getMetadata(); 245 | expect(response.data).toBeDefined(); 246 | }); 247 | }); 248 | 249 | describe('getOrganizations', () => { 250 | it('gets organizations for specified user', async () => { 251 | const response = await client.getOrganizations(userId); 252 | expect(response).toBeDefined(); 253 | }); 254 | }); 255 | 256 | describe('getMyOrganizations', () => { 257 | it('gets organizations for current user', async () => { 258 | const response = await client.getMyOrganizations(); 259 | expect(response).toBeDefined(); 260 | }); 261 | }); 262 | 263 | describe('getOrganizationDashboards', () => { 264 | it('gets organization dashboards for specified user and organization', async () => { 265 | const response = await client.getOrganizationDashboards({ userId, organizationId }); 266 | expect(response).toBeDefined(); 267 | }); 268 | }); 269 | 270 | describe('getMyOrganizationDashboards', () => { 271 | it('gets organization dashboards for current user and organization', async () => { 272 | const response = await client.getMyOrganizationDashboards(organizationId); 273 | expect(response).toBeDefined(); 274 | }); 275 | }); 276 | 277 | describe('getOrganizationDashboardMembers', () => { 278 | it('gets organization dashboard members for specified user, organization, and dashboard', async () => { 279 | const response = await client.getOrganizationDashboardMembers({ 280 | userId, 281 | organizationId, 282 | dashboardId, 283 | }); 284 | expect(response).toBeDefined(); 285 | }); 286 | }); 287 | 288 | describe('getMyOrganizationDashboardMembers', () => { 289 | it('gets organization dashboard members for specified user, organization, and dashboard', async () => { 290 | const response = await client.getMyOrganizationDashboardMembers({ 291 | organizationId, 292 | dashboardId, 293 | }); 294 | expect(response).toBeDefined(); 295 | }); 296 | 297 | // TODO: @jaebradley can run these integration tests when have dashboard with members 298 | // describe('getOrganizationDashboardMemberSummaries', () => { 299 | // eslint-disable-next-line max-len 300 | // it('gets organization dashboard members for specified user, organization, dashboard, and member', async () => { 301 | // const response = await client.getOrganizationDashboardMemberSummaries({ 302 | // userId, 303 | // organizationId, 304 | // dashboardId, 305 | // memberId: userId, 306 | // }); 307 | // expect(response).toBeDefined(); 308 | // }); 309 | // }); 310 | // 311 | // describe('getMyOrganizationDashboardMemberSummaries', () => { 312 | // eslint-disable-next-line max-len 313 | // it('gets organization dashboard members for specified user, organization, dashboard, and member', async () => { 314 | // const response = await client.getMyOrganizationDashboardMemberSummaries({ 315 | // organizationId, 316 | // dashboardId, 317 | // memberId: userId, 318 | // }); 319 | // expect(response).toBeDefined(); 320 | // }); 321 | // }); 322 | }); 323 | }); 324 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Wakatime Client](https://github.com/jaebradley/wakatime-client/workflows/Wakatime%20Client/badge.svg) 2 | [![npm](https://img.shields.io/npm/v/wakatime-client.svg)](https://www.npmjs.com/package/wakatime-client) 3 | [![npm-total-downloads](https://img.shields.io/npm/dt/wakatime-client.svg)](https://www.npmjs.com/package/wakatime-client) 4 | ![npm bundle size](https://img.shields.io/bundlephobia/minzip/wakatime-client) 5 | ![Codecov branch](https://img.shields.io/codecov/c/gh/jaebradley/wakatime-client/master) 6 | ![GitHub](https://img.shields.io/github/license/jaebradley/wakatime-client) 7 | 8 | # wakatime-client 9 | 10 | A `NodeJS` client for [the `WakaTime` API](https://wakatime.com/developers). 11 | 12 | - [WakaTime Client](#wakatime-client) 13 | - [Installation](#installation) 14 | - [API](#api) 15 | - [Local Development](#local-development) 16 | 17 | ## Installation 18 | 19 | ```bash 20 | npm install wakatime-client --save 21 | ``` 22 | 23 | ## API 24 | 25 | * [Create Instance Using API Key](#create-instance-using-api-key) 26 | * [Custom Base URLs](#custom-base-urls) 27 | * [`getUser`](#getuser) 28 | * [`getMe`](#getme) 29 | * [`getTeams`](#getteams) 30 | * [`getMyTeams`](#getmyteams) 31 | * [`getUserAgents`](#getuseragents) 32 | * [`getMyUserAgents`](#getmyuseragents) 33 | * [`getTeamMembers`](#getteammembers) 34 | * [`getMyTeamMembers`](#getmyteammembers) 35 | * [`getTeamMemberSummary`](#getteammembersummary) 36 | * [`getMyTeamMemberSummary`](#getmyteammembersummary) 37 | * [`getUserSummary`](#getusersummary) 38 | * [`getMySummary`](#getmysummary) 39 | * [`getUserStats`](#getuserstats) 40 | * [`getMyStats`](#getmystats) 41 | * [`getProjects`](#getprojects) 42 | * [`getMyProjects`](#getmyprojects) 43 | * [`getLeaders`](#getleaders) 44 | * [`getHeartbeats`](#getheartbeats) 45 | * [`getMyHeartbeats`](#getmyheartbeats) 46 | * [`getGoals`](#getgoals) 47 | * [`getMyGoals`](#getmygoals) 48 | * [`getDurations`](#getdurations) 49 | * [`getMyDurations`](#getmydurations) 50 | * [`getCommits`](#getcommits) 51 | * [`getMyCommits`](#getmycommits) 52 | * [`getMetadata`](#getmetadata) 53 | * [`getOrganizations`](#getorganizations) 54 | * [`getMyOrganizations`](#getmyorganizations) 55 | * [`getOrganizationDashboards`](#getorganizationdashboards) 56 | * [`getMyOrganizationDashboards`](#getmyorganizationdashboards) 57 | * [`getOrganizationDashboardMembers`](#getorganizationdashboardmembers) 58 | * [`getMyOrganizationDashboardMembers`](#getmyorganizationdashboardmembers) 59 | * [`getOrganizationDashboardMemberSummaries`](#getorganizationdashboardmembersummaries) 60 | * [`getMyOrganizationDashboardMemberSummaries`](#getmyorganizationdashboardmembersummaries) 61 | * [`getOrganizationDashboardMemberDurations`](#getorganizationdashboardmemberdurations) 62 | * [`getMyOrganizationDashboardMemberDurations`](#getmyorganizationdashboardmemberdurations) 63 | 64 | ### Create Instance Using API Key 65 | 66 | ```javascript 67 | import { WakaTimeClient } from 'wakatime-client'; 68 | 69 | const client = new WakaTimeClient('some api key'); 70 | ``` 71 | 72 | #### Custom Base URLs 73 | ```javascript 74 | import { WakaTimeClient } from 'wakatime-client'; 75 | 76 | const client = new WakaTimeClient('some api key', 'https://wakapi.dev/api/v1'); 77 | ``` 78 | 79 | ### `getUser` 80 | 81 | Get details for user 82 | 83 | ```javascript 84 | const userDetails = await client.getUser('some user id'); 85 | ``` 86 | 87 | ### `getMe` 88 | 89 | Get details for user associated with API key 90 | 91 | ```javascript 92 | const myUserDetails = await client.getMe(); 93 | ``` 94 | 95 | ### `getTeams` 96 | 97 | Get teams for user 98 | 99 | ```javascript 100 | const teams = await client.getTeams('some user id'); 101 | ``` 102 | 103 | ### `getMyTeams` 104 | 105 | Get teams for user associated with API key 106 | 107 | ```javascript 108 | const myTeams = await client.getMyTeams(); 109 | ``` 110 | 111 | ### `getUserAgents` 112 | 113 | Get `User Agents` (or plugins) for user 114 | 115 | ```javascript 116 | const userAgents = await client.getUserAgents('some user id'); 117 | ``` 118 | 119 | ### `getMyUserAgents` 120 | 121 | Get `User Agents` (or plugins) for user associated with API key 122 | 123 | ```javascript 124 | const myUserAgents = await client.getMyUserAgents(); 125 | ``` 126 | 127 | ### `getTeamMembers` 128 | 129 | Get team members for specified user and team 130 | 131 | ```javascript 132 | const teamMembers = await client.getTeamMembers({ userId: 'some user id', teamId: 'some team id' }); 133 | ``` 134 | 135 | ### `getMyTeamMembers` 136 | 137 | Get team members for user associated with API key and specified team 138 | 139 | ```javascript 140 | const myTeamMembers = await client.getMyTeamMembers('some team id'); 141 | ``` 142 | 143 | ### `getTeamMemberSummary` 144 | 145 | Get summary for team member 146 | 147 | #### Required Parameters 148 | 149 | ```javascript 150 | const teamMemberSummary = await client.getTeamMemberSummary({ 151 | userId: 'some user id', 152 | teamId: 'some team id', 153 | teamMemberId: 'some team member id', 154 | dateRange: { 155 | startDate: 'some start date', 156 | endDate: 'some end date', 157 | }, 158 | }); 159 | ``` 160 | 161 | #### With Optional Parameters 162 | 163 | ```javascript 164 | const teamMemberSummary = await client.getTeamMemberSummary({ 165 | userId: 'some user id', 166 | teamId: 'some team id', 167 | teamMemberId: 'some team member id', 168 | dateRange: { 169 | startDate: 'some start date', 170 | endDate: 'some end date', 171 | }, 172 | projectName: 'some project name', 173 | branchNames: ['some branch', 'some other branch', 'some other other branch'], 174 | }); 175 | ``` 176 | 177 | ### `getMyTeamMemberSummary` 178 | 179 | Get summary for team member for user associated with API key 180 | 181 | #### Required Parameters 182 | 183 | ```javascript 184 | const myTeamMemberSummary = await client.getMyTeamMemberSummary({ 185 | teamId: 'some team id', 186 | teamMemberId: 'some team member id', 187 | dateRange: { 188 | startDate: 'some start date', 189 | endDate: 'some end date', 190 | }, 191 | }); 192 | ``` 193 | 194 | #### With Optional Parameters 195 | 196 | ```javascript 197 | const myTeamMemberSummary = await client.getMyTeamMemberSummary({ 198 | teamId: 'some team id', 199 | teamMemberId: 'some team member id', 200 | dateRange: { 201 | startDate: 'some start date', 202 | endDate: 'some end date', 203 | }, 204 | projectName: 'some project name', 205 | branchNames: ['some branch', 'some other branch', 'some other other branch'], 206 | }); 207 | ``` 208 | 209 | ### `getUserSummary` 210 | 211 | Get summary for user 212 | 213 | #### Required Parameters 214 | 215 | ```javascript 216 | const summary = await client.getUserSummary({ 217 | userId: 'some user id', 218 | dateRange: { 219 | startDate: 'some start date', 220 | endDate: 'some end date', 221 | }, 222 | }) 223 | ``` 224 | 225 | #### With Optional Parameters 226 | 227 | ```javascript 228 | const summary = await client.getUserSummary({ 229 | userId: 'some user id', 230 | dateRange: { 231 | startDate: 'some start date', 232 | endDate: 'some end date', 233 | }, 234 | projectName: 'some project name', 235 | branchNames: ['some branch', 'some other branch', 'some other other branch'], 236 | }) 237 | ``` 238 | 239 | ### `getMySummary` 240 | 241 | Get summary for user associated with API key 242 | 243 | #### Required Parameters 244 | 245 | ```javascript 246 | const summary = await client.getMySummary({ 247 | dateRange: { 248 | startDate: 'some start date', 249 | endDate: 'some end date', 250 | }, 251 | }) 252 | ``` 253 | 254 | #### With Optional Parameters 255 | 256 | ```javascript 257 | const summary = await client.getMySummary({ 258 | dateRange: { 259 | startDate: 'some start date', 260 | endDate: 'some end date', 261 | }, 262 | projectName: 'some project name', 263 | branchNames: ['some branch', 'some other branch', 'some other other branch'], 264 | }) 265 | ``` 266 | 267 | ### `getUserStats` 268 | 269 | Get stats for user 270 | 271 | #### Required Parameters 272 | 273 | ```javascript 274 | import { RANGE } from 'wakatime-client'; 275 | 276 | // I assume you have instantiated the client 277 | 278 | const stats = await client.getUserStats({ 279 | userId: 'some user id', 280 | range: RANGE.PAST_7_DAYS, 281 | }); 282 | ``` 283 | 284 | #### With Optional Parameters 285 | 286 | ```javascript 287 | import { RANGE } from 'wakatime-client'; 288 | 289 | // I assume you have instantiated the client 290 | 291 | const stats = await client.getUserStats({ 292 | userId: 'some user id', 293 | range: RANGE.PAST_7_DAYS, 294 | timeout: 'some timeout', 295 | useWritesOnly: true, 296 | projectName: 'some project name', 297 | }); 298 | ``` 299 | 300 | ### `getMyStats` 301 | 302 | Get stats for user associated with API key 303 | 304 | #### Required Parameters 305 | 306 | ```javascript 307 | import { RANGE } from 'wakatime-client'; 308 | 309 | // I assume you have instantiated the client 310 | 311 | const myStats = await client.getMyStats({ range: RANGE.PAST_7_DAYS }); 312 | ``` 313 | 314 | #### With Optional Parameters 315 | 316 | ```javascript 317 | import { RANGE } from 'wakatime-client'; 318 | 319 | // I assume you have instantiated the client 320 | 321 | const myStats = await client.getMyStats({ 322 | range: RANGE.PAST_7_DAYS, 323 | timeout: 'some timeout', 324 | useWritesOnly: true, 325 | projectName: 'some project name', 326 | }); 327 | ``` 328 | 329 | ### `getProjects` 330 | 331 | Get projects for user 332 | 333 | ```javascript 334 | const projects = await client.getProjects('some user id'); 335 | ``` 336 | 337 | ### `getMyProjects` 338 | 339 | Get projects for user associated with API key 340 | 341 | ```javascript 342 | const myProjects = await client.getMyProjects(); 343 | ``` 344 | 345 | ### `getLeaders` 346 | 347 | Get Leaders 348 | 349 | #### Leaders, regardless of language 350 | 351 | ```javascript 352 | const leaders = await client.getLeaders(); 353 | ``` 354 | 355 | #### JavaScript Leaders on Page 2 356 | 357 | ```javascript 358 | const leaders = await client.getLeaders({ language: 'JavaScript', pageNumber: 2 }); 359 | ``` 360 | 361 | ### `getHeartbeats` 362 | 363 | Get heartbeats for user on a specified date 364 | 365 | ```javascript 366 | const heartbeats = await client.getHeartbeats({ userId: 'some user id', date: 'some date' }); 367 | ``` 368 | 369 | ### `getMyHeartbeats` 370 | 371 | Get heartbeats for user associated with API key on a specified date 372 | 373 | ```javascript 374 | const myHeartbeats = await client.getMyHeartbeats('some date'); 375 | ``` 376 | 377 | ### `getGoals` 378 | 379 | Get goals for user 380 | 381 | ```javascript 382 | const goals = await client.getGoals('some user id'); 383 | ``` 384 | 385 | ### `getMyGoals` 386 | 387 | Get goals for user associated with API key 388 | 389 | ```javascript 390 | const myGoals = await client.getMyGoals(); 391 | ``` 392 | 393 | ### `getDurations` 394 | 395 | Get durations for user 396 | 397 | #### Required Parameters 398 | 399 | ```javascript 400 | const durations = await client.getDurations({ userId: 'some user id', date: 'some date' }); 401 | ``` 402 | 403 | #### With Optional Parameters 404 | 405 | ```javascript 406 | const durations = await client.getDurations({ 407 | userId: 'some user id', 408 | date: 'some date', 409 | projectName: 'some project name', 410 | branchNames: ['some branch', 'some other branch', 'some other other branch'], 411 | }); 412 | ``` 413 | 414 | ### `getMyDurations` 415 | 416 | Get durations for user associated with API key 417 | 418 | #### Required Parameters 419 | 420 | ```javascript 421 | const myDurations = await client.getMyDurations({ date: 'some date' }); 422 | ``` 423 | 424 | #### With Optional Parameters 425 | 426 | ```javascript 427 | const myDurations = await client.getMyDurations({ 428 | date: 'some date', 429 | projectName: 'some project name', 430 | branchNames: ['some branch', 'some other branch', 'some other other branch'], 431 | }); 432 | ``` 433 | 434 | ### `getCommits` 435 | 436 | Get commits for user 437 | 438 | #### Required Parameters 439 | 440 | ```javascript 441 | const commits = await client.getCommits({ 442 | userId: 'some user id', 443 | projectName: 'some project name', 444 | }); 445 | ``` 446 | 447 | #### With Optional Parameters 448 | 449 | ```javascript 450 | const commits = await client.getCommits({ 451 | userId: 'some user id', 452 | projectName: 'some project name', 453 | authorName: 'jaebaebae', 454 | pageNumber: 2, 455 | }); 456 | ``` 457 | 458 | ### `getMyCommits` 459 | 460 | Get commits for user associated with API key 461 | 462 | #### Required Parameters 463 | 464 | ```javascript 465 | const myCommits = await client.getMyCommits({ projectName: 'some project name' }); 466 | ``` 467 | 468 | #### With Optional Parameters 469 | 470 | ```javascript 471 | const myCommits = await client.getMyCommits({ 472 | projectName: 'some project name', 473 | authorName: 'jaebaebae', 474 | pageNumber: 2, 475 | }); 476 | ``` 477 | 478 | ### `getMetadata` 479 | 480 | Get metadata associated with WakaTime service (like IP addresses) 481 | 482 | ```javascript 483 | const metadata = await client.getMetadata(); 484 | ``` 485 | 486 | ### `getOrganizations` 487 | 488 | Get list of organizations for the specified user 489 | 490 | ```javascript 491 | const organizations = await client.getOrganizations('some user id'); 492 | ``` 493 | 494 | ### `getMyOrganizations` 495 | 496 | Get list of organizations for user associated with API key 497 | 498 | ```javascript 499 | const myOrganizations = await client.getMyOrganizations(); 500 | ``` 501 | 502 | ### `getOrganizationDashboards` 503 | 504 | Get list of dashboards for the specified user and organization 505 | 506 | ```javascript 507 | const dashboards = await client.getOrganizationDashboards({ 508 | userId: 'some user id', 509 | organizationId: 'some organization id', 510 | }); 511 | ``` 512 | 513 | ### `getMyOrganizationDashboards` 514 | 515 | Get list of dashboards for the current user and the specified organization 516 | 517 | ```javascript 518 | const dashboards = await client.getMyOrganizationDashboards('some organization id'); 519 | ``` 520 | 521 | ### `getOrganizationDashboardMembers` 522 | 523 | Get list of dashboard members for the specified user, organization, and dashboard 524 | 525 | ```javascript 526 | const members = await client.getOrganizationDashboardMembers({ 527 | userId: 'some user id', 528 | organizationId: 'some organization id', 529 | dashboardId: 'some dashboard id', 530 | }) 531 | ``` 532 | 533 | ### `getMyOrganizationDashboardMembers` 534 | 535 | Get list of dashboard members for the current user and specified organization and dashboard 536 | 537 | ```javascript 538 | const members = await client.getMyOrganizationDashboardMembers({ 539 | organizationId: 'some organization id', 540 | dashboardId: 'some dashboard id', 541 | }) 542 | ``` 543 | 544 | ### `getOrganizationDashboardMemberSummaries` 545 | 546 | Get list of dashboard member summaries for the specified user, organization, dashboard, and member 547 | 548 | ```javascript 549 | const summaries = await client.getOrganizationDashboardMemberSummaries({ 550 | userId: 'some user id', 551 | organizationId: 'some organization id', 552 | dashboardId: 'some dashboard id', 553 | memberId: 'some member id', 554 | }) 555 | ``` 556 | 557 | ### `getMyOrganizationDashboardMemberSummaries` 558 | 559 | Get list of dashboard member summaries for the current user and specified organization, dashboard, and member 560 | 561 | ```javascript 562 | const summaries = await client.getMyOrganizationDashboardMemberSummaries({ 563 | organizationId: 'some organization id', 564 | dashboardId: 'some dashboard id', 565 | memberId: 'some member id', 566 | }) 567 | ``` 568 | 569 | ### `getOrganizationDashboardMemberDurations` 570 | 571 | Get list of dashboard member durations for the specified user, organization, dashboard, and member 572 | 573 | ```javascript 574 | const summaries = await client.getOrganizationDashboardMemberDurations({ 575 | userId: 'some user id', 576 | organizationId: 'some organization id', 577 | dashboardId: 'some dashboard id', 578 | memberId: 'some member id', 579 | }) 580 | ``` 581 | 582 | ### `getMyOrganizationDashboardMemberDurations` 583 | 584 | Get list of dashboard member durations for the current user and specified organization, dashboard, and member 585 | 586 | ```javascript 587 | const summaries = await client.getMyOrganizationDashboardMemberDurations({ 588 | organizationId: 'some organization id', 589 | dashboardId: 'some dashboard id', 590 | memberId: 'some member id', 591 | }) 592 | ``` 593 | 594 | ## Local Development 595 | 596 | After cloning the repository, use `nvm` / `npm` to install dependencies. 597 | 598 | To run tests, execute `npm run test`. This will run both unit and integration tests. 599 | 600 | In order to execute local integration tests successfully, you'll need to specify the following environment variables in the `.env` file as well as in the `Secrets` section of your fork's `Settings` page. 601 | 602 | - `ACCESS_TOKEN` (A WakaTime Access Token) 603 | - `USER_ID` (A WakaTime User ID) 604 | - `ORGANIZATION_ID` ( A WakaTime Organization ID) 605 | - `DASHBOARD_ID` (A WakaTime Dashboard ID) 606 | 607 | To build the production bundle, execute `npm run build`. 608 | 609 | ### Git Hooks 610 | 611 | This project uses [`husky`](https://github.com/typicode/husky) to maintain git hooks. 612 | 613 | - `pre-commit` - run `eslint` 614 | - `commit-msg` - run commit message linting 615 | - `pre-push` - run tests 616 | 617 | ### Commit Linting 618 | 619 | This project uses [`semantic-release`](https://github.com/semantic-release/semantic-release) and [`commitlint`](https://github.com/conventional-changelog/commitlint) (specifically the [Angular commit convention](https://gist.github.com/stephenparish/9941e89d80e2bc58a153)) to automatically enforce semantic versioning. 620 | --------------------------------------------------------------------------------