├── .env.example ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .npmignore ├── .prettierrc.json ├── LICENSE ├── README.md ├── jest.config.js ├── package.json ├── pnpm-lock.yaml ├── rollup.config.js ├── src ├── UmamiApiClient.ts ├── client.ts ├── declaration.d.ts ├── index.ts └── types.ts ├── test.js ├── tsconfig.json └── tslint.json /.env.example: -------------------------------------------------------------------------------- 1 | UMAMI_API_CLIENT_USER_ID= 2 | UMAMI_API_CLIENT_SECRET= 3 | UMAMI_API_CLIENT_ENDPOINT=https://api.umami.is/v1 4 | UMAMI_API_KEY= 5 | UMAMI_WEBSITE_ID= 6 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "commonjs": true, 5 | "es6": true, 6 | "node": true, 7 | "jest": true 8 | }, 9 | 10 | "parser": "@typescript-eslint/parser", 11 | "parserOptions": { 12 | "ecmaVersion": 9 13 | }, 14 | "globals": { 15 | "JSX": true 16 | }, 17 | "extends": ["plugin:@typescript-eslint/recommended", "eslint:recommended", "prettier"], 18 | "plugins": ["@typescript-eslint", "prettier"], 19 | "rules": { 20 | "linebreak-style": ["error", "unix"], 21 | "max-len": [ 22 | "error", 23 | { 24 | "code": 100, 25 | "ignoreComments": true 26 | } 27 | ], 28 | "import/no-unresolved": "off", 29 | "no-empty-pattern": "off", 30 | "no-unused-vars": "off", 31 | "@typescript-eslint/no-explicit-any": "off", 32 | "@typescript-eslint/no-unused-vars": ["error"], 33 | "@typescript-eslint/no-var-requires": "off", 34 | "@typescript-eslint/no-empty-function": "off", 35 | "@typescript-eslint/no-empty-interface": "off" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | .env 4 | dist 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .env* 3 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "endOfLine": "lf", 4 | "printWidth": 100, 5 | "singleQuote": true, 6 | "trailingComma": "all" 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Umami Software, Inc. 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @umami/api-client 2 | 3 | API client for Umami Analytics 4 | 5 | ### Getting started 6 | 7 | More detailed usage information can be found at https://umami.is/docs/api/api-client 8 | 9 | ### Installation 10 | 11 | ```shell 12 | yarn add @umami/api-client 13 | ``` 14 | 15 | ### Usage 16 | 17 | ```javascript 18 | import { client } from '@umami/api-client'; 19 | 20 | const { ok, data, status, error } = await client.getWebsites(); 21 | ``` 22 | 23 | # License 24 | 25 | MIT 26 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testTimeout: 20000, 3 | verbose: true, 4 | /* testEnvironment: 'jsdom', */ 5 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'], 6 | moduleNameMapper: { 7 | '\\.(css|less|jpg|png|svg)$': '/test/mocks/emptyModule.js', 8 | '^(components|assets|hooks|styles)(.*)': '/src/$1/$2', 9 | '^(icons)': '/src/$1', 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@umami/api-client", 3 | "version": "0.79.0", 4 | "description": "API client for Umami Analytics", 5 | "main": "dist/cjs/index.js", 6 | "module": "dist/esm/index.js", 7 | "types": "dist/esm/index.d.ts", 8 | "files": [ 9 | "dist" 10 | ], 11 | "publishConfig": { 12 | "access": "public" 13 | }, 14 | "license": "MIT", 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/umami-software/api-client.git" 18 | }, 19 | "scripts": { 20 | "build": "rollup -c", 21 | "dev": "rollup -c -w" 22 | }, 23 | "dependencies": { 24 | "cross-fetch": "^3.1.5", 25 | "debug": "^4.3.4", 26 | "next-basics": "^0.36.0", 27 | "uuid": "^9.0.0" 28 | }, 29 | "devDependencies": { 30 | "@rollup/plugin-commonjs": "^22.0.2", 31 | "@rollup/plugin-node-resolve": "^13.3.0", 32 | "@types/next": "^9.0.0", 33 | "@types/node": "^18.7.13", 34 | "@typescript-eslint/eslint-plugin": "^5.17.0", 35 | "@typescript-eslint/parser": "^5.17.0", 36 | "dotenv": "^10.0.0", 37 | "eslint": "^7.23.0", 38 | "eslint-config-prettier": "^8.1.0", 39 | "eslint-plugin-import": "^2.22.1", 40 | "eslint-plugin-jest": "^24.3.4", 41 | "eslint-plugin-prettier": "^4.0.0", 42 | "eslint-plugin-promise": "^5.1.0", 43 | "husky": "^7.0.4", 44 | "jest": "^27.2.4", 45 | "lint-staged": "^11.1.2", 46 | "prettier": "^2.2.1", 47 | "prettier-eslint": "^13.0.0", 48 | "react": "^18.2.0", 49 | "rollup": "^2.78.1", 50 | "rollup-plugin-exclude-dependencies-from-bundle": "^1.1.23", 51 | "rollup-plugin-peer-deps-external": "^2.2.4", 52 | "rollup-plugin-terser": "^7.0.2", 53 | "rollup-plugin-ts": "^3.0.2", 54 | "source-map-loader": "^3.0.0", 55 | "ts-node": "^10.9.1", 56 | "tslib": "^2.4.1", 57 | "tslint": "^6.1.3", 58 | "tslint-config-prettier": "^1.18.0", 59 | "typescript": "^4.7.4" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from '@rollup/plugin-node-resolve'; 2 | import commonjs from '@rollup/plugin-commonjs'; 3 | import external from 'rollup-plugin-peer-deps-external'; 4 | import ts from 'rollup-plugin-ts'; 5 | 6 | export default [ 7 | { 8 | input: 'src/index.ts', 9 | output: [ 10 | { 11 | file: 'dist/cjs/index.js', 12 | format: 'cjs', 13 | }, 14 | { 15 | file: 'dist/esm/index.js', 16 | format: 'esm', 17 | }, 18 | ], 19 | plugins: [external({ includeDependencies: true }), resolve(), commonjs(), ts()], 20 | }, 21 | ]; 22 | -------------------------------------------------------------------------------- /src/UmamiApiClient.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createSecureToken, 3 | hash, 4 | httpGet, 5 | httpPost, 6 | httpPut, 7 | httpDelete, 8 | buildUrl, 9 | ApiResponse, 10 | } from 'next-basics'; 11 | import * as Umami from 'types'; 12 | import debug from 'debug'; 13 | import { SearchResult } from 'types'; 14 | 15 | export const log = debug('umami:api-client'); 16 | 17 | export const API_KEY_HEADER = 'x-umami-api-key'; 18 | 19 | export interface UmamiApiClientOptions { 20 | userId?: string; 21 | secret?: string; 22 | apiEndpoint?: string; 23 | apiKey?: string; 24 | } 25 | 26 | export class UmamiApiClient { 27 | apiEndpoint: string; 28 | secret: string; 29 | authToken?: string; 30 | apiKey?: string; 31 | 32 | constructor(options: UmamiApiClientOptions) { 33 | const { userId, secret, apiEndpoint = '', apiKey } = options; 34 | 35 | this.apiEndpoint = apiEndpoint; 36 | this.secret = hash(secret); 37 | this.apiKey = apiKey; 38 | 39 | if (userId) { 40 | this.setAuthToken({ userId }); 41 | } 42 | } 43 | 44 | setAuthToken(data: object) { 45 | this.authToken = createSecureToken(data, this.secret); 46 | } 47 | 48 | setSecret(secret: string) { 49 | this.secret = secret; 50 | } 51 | 52 | setApiEndPoint(url: string) { 53 | this.apiEndpoint = url; 54 | } 55 | 56 | getHeaders(headers: any = {}) { 57 | if (this.authToken) { 58 | headers.authorization = `Bearer ${this.authToken}`; 59 | } 60 | if (this.apiKey) { 61 | headers[API_KEY_HEADER] = this.apiKey; 62 | } 63 | 64 | return headers; 65 | } 66 | 67 | get(url: string, params?: object, headers?: object) { 68 | const dest = buildUrl(`${this.apiEndpoint}/${url}`, params); 69 | 70 | log(`GET ${dest}`, params, headers); 71 | 72 | return httpGet(dest, undefined, { 73 | ...this.getHeaders(headers), 74 | }); 75 | } 76 | 77 | post(url: string, data?: object, headers?: object) { 78 | const dest = `${this.apiEndpoint}/${url}`; 79 | 80 | log(`POST ${dest}`, data, headers); 81 | 82 | return httpPost(dest, data, this.getHeaders(headers)); 83 | } 84 | 85 | put(url: string, params?: object, headers?: object) { 86 | const dest = `${this.apiEndpoint}/${url}`; 87 | 88 | log(`PUT ${dest}`, params, headers); 89 | 90 | return httpPut(dest, params, this.getHeaders(headers)); 91 | } 92 | 93 | del(url: string, params?: object, headers?: object) { 94 | const dest = buildUrl(`${this.apiEndpoint}/${url}`, params); 95 | 96 | log(`DELETE ${dest}`, params, headers); 97 | 98 | return httpDelete(dest, undefined, this.getHeaders(headers)); 99 | } 100 | 101 | async createUser(data: { 102 | id?: string; 103 | username: string; 104 | password: string; 105 | role?: string; 106 | }): Promise> { 107 | return this.post(`users`, data); 108 | } 109 | 110 | async getUser(userId: string): Promise> { 111 | return this.get(`users/${userId}`); 112 | } 113 | 114 | async getUsers( 115 | params: Umami.UserSearchParams, 116 | ): Promise>> { 117 | return this.get(`users`, params); 118 | } 119 | 120 | async getUserUsage( 121 | userId: string, 122 | params: { 123 | startAt: number; 124 | endAt: number; 125 | }, 126 | ) { 127 | return this.get(`users/${userId}/usage`, params); 128 | } 129 | 130 | async getUserTeams( 131 | userId: string, 132 | params?: Umami.TeamSearchParams, 133 | ): Promise>> { 134 | return this.get(`users/${userId}/teams`, params); 135 | } 136 | 137 | async getUserWebsites( 138 | userId: string, 139 | params?: Umami.WebsiteSearchParams, 140 | ): Promise>> { 141 | return this.get(`users/${userId}/websites`, params); 142 | } 143 | 144 | async deleteUser(userId: string): Promise> { 145 | return this.del(`users/${userId}`); 146 | } 147 | 148 | async updateUser( 149 | userId: string, 150 | data: { username: string; password: string }, 151 | ): Promise> { 152 | return this.post(`users/${userId}`, data); 153 | } 154 | 155 | async getShare(shareId: string): Promise> { 156 | return this.get(`share/${shareId}`); 157 | } 158 | 159 | async getReport(reportId): Promise> { 160 | return this.get(`reports/${reportId}`); 161 | } 162 | 163 | async updateReport( 164 | reportId, 165 | data: { 166 | websiteId: string; 167 | type: string; 168 | name: string; 169 | description: string; 170 | parameters: string; 171 | }, 172 | ): Promise> { 173 | return this.post(`reports/${reportId}`, data); 174 | } 175 | 176 | async deleteReport(reportId): Promise> { 177 | return this.del(`reports/${reportId}`); 178 | } 179 | 180 | async getReports( 181 | params?: Umami.SearchParams, 182 | ): Promise>> { 183 | return this.get(`reports`, params); 184 | } 185 | 186 | async createReport(data: { 187 | websiteId: string; 188 | name: string; 189 | type: string; 190 | description: string; 191 | parameters: { 192 | [key: string]: any; 193 | }; 194 | }): Promise> { 195 | return this.post(`reports`, data); 196 | } 197 | 198 | async createWebsite(data: { name: string; domain: string }): Promise> { 199 | return this.post(`websites`, data); 200 | } 201 | 202 | async getWebsite(websiteId: string): Promise> { 203 | return this.get(`websites/${websiteId}`); 204 | } 205 | 206 | async updateWebsite( 207 | websiteId: string, 208 | params: { 209 | name: string; 210 | domain: string; 211 | shareId: string; 212 | }, 213 | ): Promise> { 214 | return this.post(`websites/${websiteId}`, params); 215 | } 216 | 217 | async deleteWebsite(websiteId: string): Promise> { 218 | return this.del(`websites/${websiteId}`); 219 | } 220 | 221 | async resetWebsite(websiteId: string): Promise> { 222 | return this.post(`websites/${websiteId}/reset`); 223 | } 224 | 225 | async getWebsites( 226 | params?: Umami.WebsiteSearchParams, 227 | ): Promise>> { 228 | return this.get(`websites`, params); 229 | } 230 | 231 | async getWebsiteActive(websiteId: string): Promise> { 232 | return this.get(`websites/${websiteId}/active`); 233 | } 234 | 235 | async getWebsiteReports(websiteId: string): Promise> { 236 | return this.get(`websites/${websiteId}/reports`); 237 | } 238 | 239 | async getWebsiteValues( 240 | websiteId: string, 241 | params: { startAt: number; endAt: number }, 242 | ): Promise> { 243 | return this.get(`websites/${websiteId}/values`, params); 244 | } 245 | 246 | async getWebsiteEvents( 247 | websiteId: string, 248 | params: { 249 | startAt: string; 250 | endAt: string; 251 | query?: string; 252 | }, 253 | ): Promise>> { 254 | return this.get(`websites/${websiteId}/events`, params); 255 | } 256 | 257 | async getWebsiteSessions( 258 | websiteId: string, 259 | params: { 260 | startAt: string; 261 | endAt: string; 262 | }, 263 | ): Promise>> { 264 | return this.get(`websites/${websiteId}/sessions`, params); 265 | } 266 | 267 | async getWebsiteSessionsWeekly( 268 | websiteId: string, 269 | params: { 270 | startAt: string; 271 | endAt: string; 272 | }, 273 | ): Promise> { 274 | return this.get(`websites/${websiteId}/sessions/weekly`, params); 275 | } 276 | 277 | async getWebsiteSessionStats( 278 | websiteId: string, 279 | params: { 280 | startAt: string; 281 | endAt: string; 282 | url?: string; 283 | referrer?: string; 284 | title?: string; 285 | query?: string; 286 | event?: string; 287 | host?: string; 288 | os?: string; 289 | browser?: string; 290 | device?: string; 291 | country?: string; 292 | region?: string; 293 | city?: string; 294 | }, 295 | ): Promise> { 296 | return this.get(`websites/${websiteId}/sessions/stats`, params); 297 | } 298 | 299 | async getWebsiteSession( 300 | websiteId: string, 301 | sessionId: string, 302 | ): Promise>> { 303 | return this.get(`websites/${websiteId}/sessions/${sessionId}`); 304 | } 305 | 306 | async getSessionActivity( 307 | websiteId: string, 308 | sessionId: string, 309 | params: { 310 | startAt: string; 311 | endAt: string; 312 | }, 313 | ): Promise>> { 314 | return this.get(`websites/${websiteId}/sessions/${sessionId}/activity`, params); 315 | } 316 | 317 | async getSessionData( 318 | websiteId: string, 319 | sessionId: string, 320 | ): Promise>> { 321 | return this.get(`websites/${websiteId}/sessions/${sessionId}/properties`); 322 | } 323 | 324 | async getEventMetrics( 325 | websiteId: string, 326 | params: { 327 | startAt: string; 328 | endAt: string; 329 | unit: string; 330 | timezone: string; 331 | url?: string; 332 | referrer?: string; 333 | title?: string; 334 | host?: string; 335 | os?: string; 336 | browser?: string; 337 | device?: string; 338 | country?: string; 339 | region?: string; 340 | city?: string; 341 | }, 342 | ): Promise> { 343 | return this.get(`websites/${websiteId}/events/series`, params); 344 | } 345 | 346 | async getWebsiteMetrics( 347 | websiteId: string, 348 | params: { 349 | type: string; 350 | startAt: number; 351 | endAt: number; 352 | url?: string; 353 | referrer?: string; 354 | title?: string; 355 | query?: string; 356 | event?: string; 357 | os?: string; 358 | browser?: string; 359 | device?: string; 360 | country?: string; 361 | region?: string; 362 | city?: string; 363 | limit?: number; 364 | tag?: string; 365 | }, 366 | ): Promise>> { 367 | return this.get(`websites/${websiteId}/metrics`, params); 368 | } 369 | 370 | async getWebsitePageviews( 371 | websiteId: string, 372 | params: { 373 | startAt: number; 374 | endAt: number; 375 | unit: string; 376 | timezone: string; 377 | url?: string; 378 | referrer?: string; 379 | title?: string; 380 | os?: string; 381 | browser?: string; 382 | device?: string; 383 | country?: string; 384 | region?: string; 385 | city?: string; 386 | tag?: string; 387 | }, 388 | ): Promise> { 389 | return this.get(`websites/${websiteId}/pageviews`, params); 390 | } 391 | 392 | async getWebsiteStats( 393 | websiteId: string, 394 | params: { 395 | startAt: number; 396 | endAt: number; 397 | url?: string; 398 | referrer?: string; 399 | title?: string; 400 | query?: string; 401 | event?: string; 402 | os?: string; 403 | browser?: string; 404 | device?: string; 405 | country?: string; 406 | region?: string; 407 | city?: string; 408 | tag?: string; 409 | }, 410 | ): Promise> { 411 | return this.get(`websites/${websiteId}/stats`, params); 412 | } 413 | 414 | async createTeam(data: { name: string; domain: string }): Promise> { 415 | return this.post(`teams`, data); 416 | } 417 | 418 | async getTeam(teamId: string): Promise> { 419 | return this.get(`teams/${teamId}`); 420 | } 421 | 422 | async getTeams( 423 | params?: Umami.TeamSearchParams, 424 | ): Promise>> { 425 | return this.get(`teams`, params); 426 | } 427 | 428 | async joinTeam(data: { accessCode: string }): Promise> { 429 | return this.post(`teams/join`, data); 430 | } 431 | 432 | async getTeamUsers( 433 | teamId: string, 434 | params?: Umami.UserSearchParams, 435 | ): Promise>> { 436 | return this.get(`teams/${teamId}/users`, params); 437 | } 438 | 439 | async getTeamUser(teamId: string, userId: string): Promise> { 440 | return this.get(`teams/${teamId}/users/${userId}`); 441 | } 442 | 443 | async createTeamUser( 444 | teamId: string, 445 | data: { userId: string; role: string }, 446 | ): Promise> { 447 | return this.post(`teams/${teamId}/users`, data); 448 | } 449 | 450 | async updateTeamMember( 451 | teamId: string, 452 | userId: string, 453 | data: { role: string }, 454 | ): Promise> { 455 | return this.post(`teams/${teamId}/users/${userId}`, data); 456 | } 457 | 458 | async deleteTeamUser(teamId: string, userId: string): Promise> { 459 | return this.del(`teams/${teamId}/users/${userId}`); 460 | } 461 | 462 | async getTeamWebsites( 463 | teamId: string, 464 | params?: Umami.WebsiteSearchParams, 465 | ): Promise>>> { 466 | return this.get(`teams/${teamId}/websites`, params); 467 | } 468 | 469 | async createTeamWebsite( 470 | teamId: string, 471 | data: { name: string; domain: string; shareId: string }, 472 | ): Promise> { 473 | return this.post(`teams/${teamId}/websites`, data); 474 | } 475 | 476 | async deleteTeamWebsite(teamId: string, websiteId: string): Promise> { 477 | return this.del(`teams/${teamId}/websites/${websiteId}`); 478 | } 479 | 480 | async updateTeam( 481 | teamId: string, 482 | data: { 483 | name: string; 484 | accessCode: string; 485 | }, 486 | ): Promise> { 487 | return this.post(`teams/${teamId}`, data); 488 | } 489 | 490 | async deleteTeam(teamId: string): Promise> { 491 | return this.del(`teams/${teamId}`); 492 | } 493 | 494 | async login(username: string, password: string) { 495 | return this.post('auth/login', { username, password }); 496 | } 497 | 498 | async verify() { 499 | return this.get('auth/verify'); 500 | } 501 | 502 | async getMe() { 503 | return this.get('me'); 504 | } 505 | 506 | async getMyWebsites(params?: Umami.WebsiteSearchParams) { 507 | return this.get('me/websites', params); 508 | } 509 | 510 | async getMyTeams(params?: Umami.TeamSearchParams) { 511 | return this.get('me/teams', params); 512 | } 513 | 514 | async updateMyPassword(data: { currentPassword: string; newPassword: string }) { 515 | return this.post('me/password', data); 516 | } 517 | 518 | async getRealtime( 519 | websiteId: string, 520 | data: { 521 | startAt: number; 522 | }, 523 | ) { 524 | return this.get(`realtime/${websiteId}`, data); 525 | } 526 | 527 | async getEventDataEvents( 528 | websiteId: string, 529 | params: { 530 | startAt: number; 531 | endAt: number; 532 | event?: string; 533 | }, 534 | ): Promise> { 535 | return this.get(`websites/${websiteId}/event-data/events`, { websiteId, ...params }); 536 | } 537 | 538 | async getEventDataStats( 539 | websiteId: string, 540 | params: { 541 | startAt: number; 542 | endAt: number; 543 | }, 544 | ): Promise> { 545 | return this.get(`websites/${websiteId}/event-data/stats`, { websiteId, ...params }); 546 | } 547 | 548 | async getEventDataValues( 549 | websiteId: string, 550 | params: { 551 | startAt: number; 552 | endAt: number; 553 | eventName: string; 554 | propertyName: string; 555 | }, 556 | ): Promise> { 557 | return this.get(`websites/${websiteId}/event-data/values`, { websiteId, ...params }); 558 | } 559 | 560 | async getEventDataFields( 561 | websiteId: string, 562 | params: { 563 | startAt: number; 564 | endAt: number; 565 | }, 566 | ): Promise> { 567 | return this.get(`websites/${websiteId}/event-data/fields`, { websiteId, ...params }); 568 | } 569 | 570 | async getSessionDataProperties( 571 | websiteId: string, 572 | params: { 573 | startAt: number; 574 | endAt: number; 575 | }, 576 | ): Promise> { 577 | return this.get(`websites/${websiteId}/session-data/properties`, { websiteId, ...params }); 578 | } 579 | 580 | async getSessionDataValues( 581 | websiteId: string, 582 | params: { 583 | startAt: number; 584 | endAt: number; 585 | eventName: string; 586 | propertyName: string; 587 | }, 588 | ): Promise> { 589 | return this.get(`websites/${websiteId}/session-data/values`, { websiteId, ...params }); 590 | } 591 | 592 | async transferWebsite( 593 | websiteId: string, 594 | params: { 595 | userId?: string; 596 | teamId?: string; 597 | }, 598 | ) { 599 | return this.post(`websites/${websiteId}/transfer`, { websiteId, ...params }); 600 | } 601 | 602 | async runFunnelReport(data: { 603 | websiteId: string; 604 | urls: string[]; 605 | window: number; 606 | dateRange: { 607 | startDate: string; 608 | endDate: string; 609 | }; 610 | }) { 611 | return this.post(`reports/funnel`, data); 612 | } 613 | 614 | async runInsightsReport(data: { 615 | websiteId: string; 616 | dateRange: { 617 | startDate: string; 618 | endDate: string; 619 | }; 620 | fields: { name: string; type: string; label: string }[]; 621 | filters: { name: string; type: string; filter: string; value: string }[]; 622 | groups: { name: string; type: string }[]; 623 | }) { 624 | return this.post(`reports/insights`, data); 625 | } 626 | 627 | async runRetentionReport(data: { 628 | websiteId: string; 629 | dateRange: { startDate: string; endDate: string; timezone: string }; 630 | }) { 631 | return this.post(`reports/retention`, data); 632 | } 633 | 634 | async runUTMReport(data: { 635 | websiteId: string; 636 | dateRange: { startDate: string; endDate: string }; 637 | }) { 638 | return this.post(`reports/utm`, data); 639 | } 640 | 641 | async runGoalsReport(data: { 642 | websiteId: string; 643 | dateRange: { startDate: string; endDate: string }; 644 | }) { 645 | return this.post(`reports/goals`, data); 646 | } 647 | 648 | async runJourneyReport(data: { 649 | websiteId: string; 650 | dateRange: { startDate: string; endDate: string }; 651 | }) { 652 | return this.post(`reports/journey`, data); 653 | } 654 | 655 | async runRevenueReport(data: { 656 | websiteId: string; 657 | dateRange: { startDate: string; endDate: string }; 658 | }) { 659 | return this.post(`reports/revenue`, data); 660 | } 661 | 662 | async runAttributionReport(data: { 663 | websiteId: string; 664 | dateRange: { startDate: string; endDate: string }; 665 | }) { 666 | return this.post(`reports/attribution`, data); 667 | } 668 | 669 | async send(data: { 670 | type: 'event'; 671 | payload: { 672 | data: { [key: string]: any }; 673 | hostname: string; 674 | language: string; 675 | referrer: string; 676 | screen: string; 677 | title: string; 678 | url: string; 679 | website: string; 680 | name: string; 681 | }; 682 | }) { 683 | const { type, payload } = data; 684 | 685 | return this.post('send', { type, payload }); 686 | } 687 | 688 | async config() { 689 | return this.get('config'); 690 | } 691 | 692 | async heartbeat() { 693 | return this.get('heartbeat'); 694 | } 695 | 696 | async executeRoute(url: string, method: string, data: any): Promise> { 697 | const routes = [ 698 | { 699 | path: /^admin\/users$/, 700 | get: async ([]: any, data: Umami.UserSearchParams) => this.getUsers(data), 701 | }, 702 | { 703 | path: /^admin\/websites$/, 704 | get: async ([]: any, data: Umami.UserSearchParams) => this.getWebsites(data), 705 | }, 706 | { 707 | path: /^me$/, 708 | get: async () => this.getMe(), 709 | }, 710 | { 711 | path: /^me\/password$/, 712 | post: async ( 713 | [], 714 | data: { 715 | currentPassword: string; 716 | newPassword: string; 717 | }, 718 | ) => this.updateMyPassword(data), 719 | }, 720 | { 721 | path: /^me\/teams$/, 722 | get: async ([], data: Umami.TeamSearchParams) => this.getMyTeams(data), 723 | }, 724 | { 725 | path: /^me\/websites$/, 726 | get: async ([], data: Umami.WebsiteSearchParams) => this.getMyWebsites(data), 727 | }, 728 | { 729 | path: /^realtime\/[0-9a-f-]+$/, 730 | get: async ([, id], data: { startAt: number }) => this.getRealtime(id, data), 731 | }, 732 | { 733 | path: /^reports$/, 734 | get: async ([], data: Umami.SearchParams) => this.getReports(data), 735 | post: async ( 736 | [], 737 | data: { 738 | websiteId: string; 739 | name: string; 740 | type: string; 741 | description: string; 742 | parameters: { 743 | [key: string]: any; 744 | }; 745 | }, 746 | ) => this.createReport(data), 747 | }, 748 | { 749 | path: /^reports\/funnel$/, 750 | post: async ( 751 | [], 752 | data: { 753 | websiteId: string; 754 | urls: string[]; 755 | window: number; 756 | dateRange: { 757 | startDate: string; 758 | endDate: string; 759 | }; 760 | }, 761 | ) => this.runFunnelReport(data), 762 | }, 763 | { 764 | path: /^reports\/insights$/, 765 | post: async ( 766 | [], 767 | data: { 768 | websiteId: string; 769 | dateRange: { 770 | startDate: string; 771 | endDate: string; 772 | }; 773 | fields: { name: string; type: string; label: string }[]; 774 | filters: { name: string; type: string; filter: string; value: string }[]; 775 | groups: { name: string; type: string }[]; 776 | }, 777 | ) => this.runInsightsReport(data), 778 | }, 779 | { 780 | path: /^reports\/retention$/, 781 | post: async ( 782 | [], 783 | data: { 784 | websiteId: string; 785 | dateRange: { startDate: string; endDate: string; timezone: string }; 786 | }, 787 | ) => this.runRetentionReport(data), 788 | }, 789 | { 790 | path: /^reports\/revenue$/, 791 | post: async ( 792 | [], 793 | data: { 794 | websiteId: string; 795 | dateRange: { startDate: string; endDate: string }; 796 | }, 797 | ) => this.runRevenueReport(data), 798 | }, 799 | { 800 | path: /^reports\/utm$/, 801 | post: async ( 802 | [], 803 | data: { 804 | websiteId: string; 805 | dateRange: { startDate: string; endDate: string }; 806 | }, 807 | ) => this.runUTMReport(data), 808 | }, 809 | { 810 | path: /^reports\/goals$/, 811 | post: async ( 812 | [], 813 | data: { 814 | websiteId: string; 815 | dateRange: { startDate: string; endDate: string }; 816 | }, 817 | ) => this.runGoalsReport(data), 818 | }, 819 | { 820 | path: /^reports\/journey$/, 821 | post: async ( 822 | [], 823 | data: { 824 | websiteId: string; 825 | dateRange: { startDate: string; endDate: string }; 826 | }, 827 | ) => this.runJourneyReport(data), 828 | }, 829 | { 830 | path: /^reports\/attribution$/, 831 | post: async ( 832 | [], 833 | data: { 834 | websiteId: string; 835 | dateRange: { startDate: string; endDate: string }; 836 | }, 837 | ) => this.runAttributionReport(data), 838 | }, 839 | { 840 | path: /^reports\/[0-9a-f-]+$/, 841 | get: async ([, id]) => this.getReport(id), 842 | post: async ( 843 | [, id], 844 | data: { 845 | websiteId: string; 846 | type: string; 847 | name: string; 848 | description: string; 849 | parameters: string; 850 | }, 851 | ) => this.updateReport(id, data), 852 | delete: async ([, id]) => this.deleteReport(id), 853 | }, 854 | { 855 | path: /^teams$/, 856 | get: async ([], data: Umami.TeamSearchParams | undefined) => this.getTeams(data), 857 | post: async ([], data: { name: string; domain: string }) => this.createTeam(data), 858 | }, 859 | { 860 | path: /^teams\/join$/, 861 | post: async ([]: any, data: { accessCode: string }) => this.joinTeam(data), 862 | }, 863 | { 864 | path: /^teams\/[0-9a-f-]+$/, 865 | get: async ([, id]: any) => this.getTeam(id), 866 | post: async ([, id]: any, data: { name: string; accessCode: string }) => 867 | this.updateTeam(id, data), 868 | delete: async ([, id]: any) => this.deleteTeam(id), 869 | }, 870 | { 871 | path: /^teams\/[0-9a-f-]+\/users$/, 872 | get: async ([, id]: any, data: Umami.UserSearchParams | undefined) => 873 | this.getTeamUsers(id, data), 874 | post: async ([, id]: any, data: { userId: string; role: string }) => 875 | this.createTeamUser(id, data), 876 | }, 877 | { 878 | path: /^teams\/[0-9a-f-]+\/users\/[0-9a-f-]+$/, 879 | get: async ([, teamId, , userId]: any) => this.getTeamUser(teamId, userId), 880 | post: async ([, teamId, , userId]: any, data: { role: string }) => 881 | this.updateTeamMember(teamId, userId, data), 882 | delete: async ([, teamId, , userId]: any) => this.deleteTeamUser(teamId, userId), 883 | }, 884 | { 885 | path: /^teams\/[0-9a-f-]+\/websites$/, 886 | get: async ([, id]: any, data: Umami.WebsiteSearchParams | undefined) => 887 | this.getTeamWebsites(id, data), 888 | post: async ([, id]: any, data: { name: string; domain: string; shareId: string }) => 889 | this.createTeamWebsite(id, data), 890 | }, 891 | { 892 | path: /^users$/, 893 | get: async ([]: any, data: Umami.UserSearchParams) => this.getUsers(data), 894 | post: async ([]: any, data: { username: string; password: string }) => 895 | this.createUser(data), 896 | }, 897 | { 898 | path: /^users\/[0-9a-f-]+$/, 899 | get: async ([, id]: any) => this.getUser(id), 900 | post: async ([, id]: any, data: { username: string; password: string }) => 901 | this.updateUser(id, data), 902 | delete: async ([, id]: any) => this.deleteUser(id), 903 | }, 904 | { 905 | path: /^users\/[0-9a-f-]+\/teams$/, 906 | get: async ([, id]: any, data: Umami.WebsiteSearchParams) => this.getUserTeams(id, data), 907 | }, 908 | { 909 | path: /^users\/[0-9a-f-]+\/websites$/, 910 | get: async ([, id]: any, data: Umami.WebsiteSearchParams) => this.getUserWebsites(id, data), 911 | }, 912 | { 913 | path: /^users\/[0-9a-f-]+\/usage$/, 914 | get: async ([, id]: any, data: { startAt: number; endAt: number }) => 915 | this.getUserUsage(id, data), 916 | }, 917 | { 918 | path: /^websites$/, 919 | get: async ([]: any, data: Umami.WebsiteSearchParams | undefined) => this.getWebsites(data), 920 | post: async ( 921 | []: any, 922 | data: { name: string; domain: string; shareId: string; teamId: string }, 923 | ) => this.createWebsite(data), 924 | }, 925 | { 926 | path: /^websites\/[0-9a-f-]+$/, 927 | get: async ([, id]: any) => this.getWebsite(id), 928 | post: async ([, id]: any, data: { name: string; domain: string; shareId: string }) => 929 | this.updateWebsite(id, data), 930 | delete: async ([, id]: any) => this.deleteWebsite(id), 931 | }, 932 | { 933 | path: /^websites\/[0-9a-f-]+\/active$/, 934 | get: async ([, id]: any) => this.getWebsiteActive(id), 935 | }, 936 | { 937 | path: /^websites\/[0-9a-f-]+\/daterange$/, 938 | get: async ([, id]: any) => this.getWebsiteActive(id), 939 | }, 940 | { 941 | path: /^websites\/[0-9a-f-]+\/event-data\/events$/, 942 | get: async ( 943 | [, id]: any, 944 | data: { 945 | startAt: number; 946 | endAt: number; 947 | event?: string; 948 | }, 949 | ) => this.getEventDataEvents(id, data), 950 | }, 951 | { 952 | path: /^websites\/[0-9a-f-]+\/event-data\/stats$/, 953 | get: async ( 954 | [, id]: any, 955 | data: { 956 | startAt: number; 957 | endAt: number; 958 | }, 959 | ) => this.getEventDataStats(id, data), 960 | }, 961 | { 962 | path: /^websites\/[0-9a-f-]+\/event-data\/values$/, 963 | get: async ( 964 | [, id]: any, 965 | data: { startAt: number; endAt: number; eventName: string; propertyName: string }, 966 | ) => this.getEventDataValues(id, data), 967 | }, 968 | { 969 | path: /^websites\/[0-9a-f-]+\/event-data\/fields$/, 970 | get: async ([, id]: any, data: { startAt: number; endAt: number }) => 971 | this.getEventDataFields(id, data), 972 | }, 973 | { 974 | path: /^websites\/[0-9a-f-]+\/events$/, 975 | get: async ( 976 | [, id]: any, 977 | data: { 978 | startAt: string; 979 | endAt: string; 980 | query?: string; 981 | }, 982 | ) => this.getWebsiteEvents(id, data), 983 | }, 984 | { 985 | path: /^websites\/[0-9a-f-]+\/events\/series$/, 986 | get: async ( 987 | [, id]: any, 988 | data: { 989 | startAt: string; 990 | endAt: string; 991 | unit: string; 992 | timezone: string; 993 | url?: string | undefined; 994 | referrer?: string | undefined; 995 | title?: string | undefined; 996 | host?: string | undefined; 997 | os?: string | undefined; 998 | browser?: string | undefined; 999 | device?: string | undefined; 1000 | country?: string | undefined; 1001 | region?: string | undefined; 1002 | city?: string | undefined; 1003 | }, 1004 | ) => this.getEventMetrics(id, data), 1005 | }, 1006 | { 1007 | path: /^websites\/[0-9a-f-]+\/metrics$/, 1008 | get: async ( 1009 | [, id]: any, 1010 | data: { 1011 | type: string; 1012 | startAt: number; 1013 | endAt: number; 1014 | url?: string | undefined; 1015 | referrer?: string | undefined; 1016 | title?: string | undefined; 1017 | query?: string | undefined; 1018 | event?: string | undefined; 1019 | os?: string | undefined; 1020 | browser?: string | undefined; 1021 | device?: string | undefined; 1022 | country?: string | undefined; 1023 | region?: string | undefined; 1024 | city?: string | undefined; 1025 | language?: string | undefined; 1026 | limit?: number | undefined; 1027 | tag?: string | undefined; 1028 | }, 1029 | ) => this.getWebsiteMetrics(id, data), 1030 | }, 1031 | { 1032 | path: /^websites\/[0-9a-f-]+\/pageviews$/, 1033 | get: async ( 1034 | [, id]: any, 1035 | data: { 1036 | startAt: number; 1037 | endAt: number; 1038 | unit: string; 1039 | timezone: string; 1040 | url?: string | undefined; 1041 | referrer?: string | undefined; 1042 | title?: string | undefined; 1043 | os?: string | undefined; 1044 | browser?: string | undefined; 1045 | device?: string | undefined; 1046 | country?: string | undefined; 1047 | region?: string | undefined; 1048 | city?: string | undefined; 1049 | tag?: string | undefined; 1050 | }, 1051 | ) => this.getWebsitePageviews(id, data), 1052 | }, 1053 | { 1054 | path: /^websites\/[0-9a-f-]+\/reports$/, 1055 | post: ([, id]: any) => this.getWebsiteReports(id), 1056 | }, 1057 | { 1058 | path: /^websites\/[0-9a-f-]+\/reset$/, 1059 | post: ([, id]: any) => this.resetWebsite(id), 1060 | }, 1061 | { 1062 | path: /^websites\/[0-9a-f-]+\/session-data\/properties$/, 1063 | get: async ( 1064 | [, id]: any, 1065 | data: { 1066 | startAt: number; 1067 | endAt: number; 1068 | }, 1069 | ) => this.getSessionDataProperties(id, data), 1070 | }, 1071 | { 1072 | path: /^websites\/[0-9a-f-]+\/session-data\/values$/, 1073 | get: async ( 1074 | [, id]: any, 1075 | data: { startAt: number; endAt: number; eventName: string; propertyName: string }, 1076 | ) => this.getSessionDataValues(id, data), 1077 | }, 1078 | { 1079 | path: /^websites\/[0-9a-f-]+\/sessions$/, 1080 | get: async ( 1081 | [, id]: any, 1082 | data: { 1083 | startAt: string; 1084 | endAt: string; 1085 | }, 1086 | ) => this.getWebsiteSessions(id, data), 1087 | }, 1088 | { 1089 | path: /^websites\/[0-9a-f-]+\/sessions\/weekly$/, 1090 | get: async ( 1091 | [, id]: any, 1092 | data: { 1093 | startAt: string; 1094 | endAt: string; 1095 | }, 1096 | ) => this.getWebsiteSessionsWeekly(id, data), 1097 | }, 1098 | { 1099 | path: /^websites\/[0-9a-f-]+\/sessions\/stats$/, 1100 | get: async ( 1101 | [, id]: any, 1102 | data: { 1103 | startAt: string; 1104 | endAt: string; 1105 | url?: string; 1106 | referrer?: string; 1107 | title?: string; 1108 | query?: string; 1109 | event?: string; 1110 | host?: string; 1111 | os?: string; 1112 | browser?: string; 1113 | device?: string; 1114 | country?: string; 1115 | region?: string; 1116 | city?: string; 1117 | }, 1118 | ) => this.getWebsiteSessionStats(id, data), 1119 | }, 1120 | { 1121 | path: /^websites\/[0-9a-f-]+\/sessions\/[0-9a-f-]+$/, 1122 | get: async ([, websiteId, , sessionId]: any) => 1123 | this.getWebsiteSession(websiteId, sessionId), 1124 | }, 1125 | { 1126 | path: /^websites\/[0-9a-f-]+\/sessions\/[0-9a-f-]+\/activity$/, 1127 | get: async ( 1128 | [, websiteId, , sessionId]: any, 1129 | data: { 1130 | startAt: string; 1131 | endAt: string; 1132 | }, 1133 | ) => this.getSessionActivity(websiteId, sessionId, data), 1134 | }, 1135 | { 1136 | path: /^websites\/[0-9a-f-]+\/sessions\/[0-9a-f-]+\/properties$/, 1137 | get: async ([, websiteId, , sessionId]: any) => this.getSessionData(websiteId, sessionId), 1138 | }, 1139 | { 1140 | path: /^websites\/[0-9a-f-]+\/stats$/, 1141 | get: async ( 1142 | [, id]: any, 1143 | data: { 1144 | startAt: number; 1145 | endAt: number; 1146 | url?: string; 1147 | referrer?: string | undefined; 1148 | title?: string | undefined; 1149 | query?: string | undefined; 1150 | event?: string | undefined; 1151 | os?: string | undefined; 1152 | browser?: string | undefined; 1153 | device?: string | undefined; 1154 | country?: string | undefined; 1155 | region?: string | undefined; 1156 | city?: string | undefined; 1157 | tag?: string | undefined; 1158 | }, 1159 | ) => this.getWebsiteStats(id, data), 1160 | }, 1161 | { 1162 | path: /^websites\/[0-9a-f-]+\/transfer$/, 1163 | post: ( 1164 | [, id]: any, 1165 | data: { 1166 | userId?: string; 1167 | teamId?: string; 1168 | }, 1169 | ) => this.transferWebsite(id, data), 1170 | }, 1171 | { 1172 | path: /^websites\/[0-9a-f-]+\/values$/, 1173 | pogetst: ( 1174 | [, id]: any, 1175 | data: { 1176 | startAt: number; 1177 | endAt: number; 1178 | }, 1179 | ) => this.getWebsiteValues(id, data), 1180 | }, 1181 | ]; 1182 | 1183 | const route = routes.find(({ path }) => url.match(path)); 1184 | const key = method.toLowerCase(); 1185 | 1186 | if (route && route[key]) { 1187 | return route[key](url.split('/'), data); 1188 | } 1189 | 1190 | return { ok: false, status: 404, error: { status: 404, message: `Not Found: ${url}` } }; 1191 | } 1192 | } 1193 | 1194 | export default UmamiApiClient; 1195 | -------------------------------------------------------------------------------- /src/client.ts: -------------------------------------------------------------------------------- 1 | import UmamiApiClient from 'UmamiApiClient'; 2 | 3 | export function getClient(params?: { 4 | userId?: string; 5 | secret?: string; 6 | apiEndpoint?: string; 7 | apiKey?: string; 8 | }): UmamiApiClient { 9 | const { 10 | userId = process.env.UMAMI_API_CLIENT_USER_ID, 11 | secret = process.env.UMAMI_API_CLIENT_SECRET, 12 | apiEndpoint = process.env.UMAMI_API_CLIENT_ENDPOINT, 13 | apiKey = process.env.UMAMI_API_KEY, 14 | } = params || {}; 15 | 16 | return new UmamiApiClient({ 17 | userId, 18 | secret, 19 | apiEndpoint, 20 | apiKey, 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /src/declaration.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'debug'; 2 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './client'; 2 | export * from './types'; 3 | export * from './UmamiApiClient'; 4 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export interface User { 2 | id: string; 3 | username: string; 4 | isAdmin: boolean; 5 | createdAt: string; 6 | } 7 | 8 | export interface Website { 9 | id: string; 10 | userId: string; 11 | revId: number; 12 | name: string; 13 | domain: string; 14 | shareId: string; 15 | createdAt: Date; 16 | } 17 | 18 | export interface Report { 19 | id: string; 20 | userId: string; 21 | websiteId: string; 22 | type: string; 23 | name: string; 24 | description: string; 25 | parameters: string; 26 | createdAt: Date; 27 | updatedAt: Date; 28 | } 29 | 30 | export interface Team { 31 | id: string; 32 | name: string; 33 | createdAt: string; 34 | } 35 | 36 | export interface TeamUser { 37 | id: string; 38 | teamId: string; 39 | userId: string; 40 | role: string; 41 | createdAt: Date; 42 | } 43 | 44 | export interface Share { 45 | id: string; 46 | token: string; 47 | } 48 | 49 | export interface WebsiteActive { 50 | x: number; 51 | } 52 | 53 | export interface WebsiteMetric { 54 | x: string; 55 | y: number; 56 | } 57 | 58 | export interface WebsiteEventMetric { 59 | x: string; 60 | t: string; 61 | y: number; 62 | } 63 | 64 | export interface WebsitePageviews { 65 | pageviews: { 66 | t: string; 67 | y: number; 68 | }[]; 69 | sessions: { 70 | t: string; 71 | y: number; 72 | }[]; 73 | } 74 | 75 | export interface WebsiteStats { 76 | pageviews: { value: number; prev: number }; 77 | visitors: { value: number; prev: number }; 78 | visits: { value: number; prev: number }; 79 | bounces: { value: number; prev: number }; 80 | totaltime: { value: number; prev: number }; 81 | } 82 | 83 | export type WebsiteSessionWeekly = number[][]; 84 | 85 | export interface WebsiteSessionStats { 86 | countries: { value: number }; 87 | events: { value: number }; 88 | pageviews: { value: number }; 89 | visitors: { value: number }; 90 | visits: { value: number }; 91 | } 92 | 93 | export interface RealtimeInit { 94 | websites: Website[]; 95 | token: string; 96 | data: RealtimeUpdate; 97 | } 98 | 99 | export interface RealtimeUpdate { 100 | pageviews: any[]; 101 | sessions: any[]; 102 | events: any[]; 103 | timestamp: number; 104 | } 105 | 106 | export interface SessionActivity { 107 | createdAt: Date; 108 | urlPath: string; 109 | urlQuery: string; 110 | referrerDomain: string; 111 | eventId: string; 112 | eventType: number; 113 | eventName: string; 114 | visitId: string; 115 | } 116 | 117 | export interface SessionData { 118 | websiteId: string; 119 | sessionId: string; 120 | dataKey: string; 121 | dataType: string; 122 | stringValue: string; 123 | numberValue: number; 124 | dateValue: Date; 125 | createdAt: Date; 126 | } 127 | 128 | export interface WebsiteEvent { 129 | id: string; 130 | websiteId: string; 131 | sessionId: string; 132 | createdAt: Date; 133 | urlPath: string; 134 | urlQuery: string; 135 | referrerPath: string; 136 | referrerQuery: string; 137 | referrerDomain: string; 138 | pageTitle: string; 139 | eventType: number; 140 | eventName: string; 141 | } 142 | 143 | export interface WebsiteSession { 144 | id: string; 145 | websiteId: string; 146 | hostname: string; 147 | browser: string; 148 | os: string; 149 | device: string; 150 | screen: string; 151 | language: string; 152 | country: string; 153 | subdivision1: string; 154 | city: string; 155 | firstAt: Date; 156 | lastAt: Date; 157 | visits: number; 158 | views: number; 159 | events?: number; 160 | toataltime?: number; 161 | createdAt: Date; 162 | } 163 | 164 | export interface WebsiteEventData { 165 | eventName: string; 166 | propertyName: string; 167 | dataType: number; 168 | propertyValue?: string; 169 | total: number; 170 | } 171 | 172 | export interface WebsiteEventDataStats { 173 | events: number; 174 | properties: number; 175 | records: number; 176 | } 177 | 178 | export interface WebsiteSessionData { 179 | propertyName: string; 180 | total: number; 181 | } 182 | 183 | export interface WebsiteDataField { 184 | propertyName: string; 185 | dataType: number; 186 | value: string; 187 | total: number; 188 | } 189 | 190 | export interface WebsiteDataValue { 191 | value: string; 192 | total: number; 193 | } 194 | 195 | export interface Empty {} 196 | 197 | export interface WebsiteSearchParams extends SearchParams { 198 | userId?: string; 199 | teamId?: string; 200 | includeTeams?: boolean; 201 | } 202 | 203 | export interface UserSearchParams extends SearchParams { 204 | teamId?: string; 205 | } 206 | 207 | export interface TeamSearchParams extends SearchParams { 208 | userId?: string; 209 | } 210 | 211 | export interface ReportSearchParams extends SearchParams { 212 | userId?: string; 213 | websiteId?: string; 214 | } 215 | 216 | export interface SearchParams { 217 | search?: string; 218 | page?: number; 219 | pageSize?: number; 220 | orderBy?: string; 221 | sortDescending?: boolean; 222 | } 223 | 224 | export interface SearchResult { 225 | data: T; 226 | count: number; 227 | pageSize: number; 228 | page: number; 229 | orderBy?: string; 230 | } 231 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | require('cross-fetch/polyfill'); 2 | const apiClient = require('./dist/cjs/index'); 3 | const dotenv = require('dotenv'); 4 | dotenv.config(); 5 | 6 | const START_AT = 1682924400000; 7 | const END_AT = 1696143599999; 8 | 9 | describe('Testing all get functions', () => { 10 | beforeAll(() => { 11 | apiClient.client = apiClient.getClient(); 12 | }); 13 | 14 | async function testGetWebsites() { 15 | const results = await apiClient.client.getWebsites(); 16 | 17 | return results.ok; 18 | } 19 | 20 | test('Testing: getWebsites', () => { 21 | return expect(testGetWebsites()).resolves.toBeTruthy(); 22 | }); 23 | 24 | async function testGetMe() { 25 | const results = await apiClient.client.getMe(); 26 | 27 | return results.ok; 28 | } 29 | 30 | test('Testing: getMe', () => { 31 | return expect(testGetMe()).resolves.toBeTruthy(); 32 | }); 33 | 34 | async function testGetWebsiteMetrics() { 35 | const results = await apiClient.client.getWebsiteMetrics(process.env.UMAMI_WEBSITE_ID, { 36 | startAt: START_AT, 37 | endAt: END_AT, 38 | unit: 'hour', 39 | type: 'url', 40 | }); 41 | 42 | return results.ok; 43 | } 44 | 45 | test('Testing: getWebsiteMetrics', () => { 46 | return expect(testGetWebsiteMetrics()).resolves.toBeTruthy(); 47 | }); 48 | 49 | async function testGetWebsitePageviews() { 50 | const results = await apiClient.client.getWebsitePageviews(process.env.UMAMI_WEBSITE_ID, { 51 | startAt: START_AT, 52 | endAt: END_AT, 53 | unit: 'hour', 54 | url: '/', 55 | timezone: 'America/Los_Angeles', 56 | unit: 'day', 57 | }); 58 | 59 | return results.ok; 60 | } 61 | 62 | test('Testing: getWebsitePageviews', () => { 63 | return expect(testGetWebsitePageviews()).resolves.toBeTruthy(); 64 | }); 65 | 66 | async function testGetWebsitesStats() { 67 | const results = await apiClient.client.getWebsiteStats(process.env.UMAMI_WEBSITE_ID, { 68 | startAt: START_AT, 69 | endAt: END_AT, 70 | url: '/', 71 | }); 72 | 73 | return results.ok; 74 | } 75 | 76 | test('Testing: getWebsitesStats', () => { 77 | return expect(testGetWebsitesStats()).resolves.toBeTruthy(); 78 | }); 79 | }); 80 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "esModuleInterop": true, 5 | "noImplicitAny": false, 6 | "preserveConstEnums": true, 7 | "removeComments": true, 8 | "sourceMap": true, 9 | "allowSyntheticDefaultImports": true, 10 | "allowJs": true, 11 | "strict": true, 12 | "outDir": "./dist", 13 | "target": "es5", 14 | "module": "esnext", 15 | "moduleResolution": "node", 16 | "jsx": "react-jsx", 17 | "lib": ["dom", "dom.iterable", "esnext"], 18 | "skipLibCheck": true, 19 | "baseUrl": ".", 20 | "plugins": [ 21 | { 22 | "transform": "typescript-transform-paths", 23 | "afterDeclarations": true 24 | } 25 | ], 26 | "paths": { "*": ["./src/*"] } 27 | }, 28 | "include": ["./src/**/*"], 29 | "exclude": ["node_modules"] 30 | } 31 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-config-prettier"], 3 | "rules": { 4 | "jsx-boolean-value": "off", 5 | "no-empty-interface": false 6 | }, 7 | "linterOptions": { 8 | "exclude": ["dist"] 9 | } 10 | } 11 | --------------------------------------------------------------------------------