From 9a8de0352d2b39576a7387b624f8b0db2c464ff2 Mon Sep 17 00:00:00 2001 From: newt Date: Sat, 7 Dec 2024 23:34:10 +0000 Subject: [PATCH] chore: add files --- .../workflows/npm-publish-github-packages.yml | 36 + .github/workflows/npm-publish.yml | 33 + DOCS.md | 1020 +++++++++++++++++ LICENSE | 21 + README.md | 216 ++++ package.json | 19 + umami.cjs.js | 2 + umami.js | 936 +++++++++++++++ 8 files changed, 2283 insertions(+) create mode 100644 .github/workflows/npm-publish-github-packages.yml create mode 100644 .github/workflows/npm-publish.yml create mode 100644 DOCS.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 package.json create mode 100644 umami.cjs.js create mode 100644 umami.js diff --git a/.github/workflows/npm-publish-github-packages.yml b/.github/workflows/npm-publish-github-packages.yml new file mode 100644 index 0000000..ea2d329 --- /dev/null +++ b/.github/workflows/npm-publish-github-packages.yml @@ -0,0 +1,36 @@ +# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created +# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages + +name: Node.js Package + +on: + release: + types: [created] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - run: npm ci + - run: npm test + + publish-gpr: + needs: build + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + registry-url: https://npm.pkg.github.com/ + - run: npm ci + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml new file mode 100644 index 0000000..2a4766d --- /dev/null +++ b/.github/workflows/npm-publish.yml @@ -0,0 +1,33 @@ +# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created +# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages + +name: Node.js Package + +on: + release: + types: [created] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + - run: npm ci + - run: npm test + + publish-npm: + needs: build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + registry-url: https://registry.npmjs.org/ + - run: npm ci + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/DOCS.md b/DOCS.md new file mode 100644 index 0000000..2f4fdac --- /dev/null +++ b/DOCS.md @@ -0,0 +1,1020 @@ +## Classes + +
+
UmamiClient
+
+
+ +## Typedefs + +
+
User : Object
+
+
GetTokenResponse : Object
+
+
EventPayload : Object
+
+
Session : Object
+
+
SessionStats : Object
+
+
SessionActivity : Object
+
+
SessionProperty : Object
+
+
PropertyCount : Object
+
+
PropertyValue : Object
+
+
+ + + +## UmamiClient +**Kind**: global class + +* [UmamiClient](#UmamiClient) + * [new UmamiClient(config)](#new_UmamiClient_new) + * [.authenticate()](#UmamiClient+authenticate) ⇒ [Promise.<GetTokenResponse>](#GetTokenResponse) + * [.verifyToken()](#UmamiClient+verifyToken) ⇒ [Promise.<User>](#User) + * [.createUser(params)](#UmamiClient+createUser) ⇒ Promise.<{id: string, username: string, role: string, createdAt: string}> + * [.getUsers()](#UmamiClient+getUsers) ⇒ Promise.<Array.<{id: string, username: string, role: string, createdAt: string}>> + * [.getUser(userId)](#UmamiClient+getUser) ⇒ Promise.<{id: string, username: string, role: string}> + * [.updateUser(userId, params)](#UmamiClient+updateUser) ⇒ Promise.<{id: string, username: string, role: string, createdAt: string}> + * [.deleteUser(userId)](#UmamiClient+deleteUser) ⇒ Promise.<string> + * [.getUserWebsites(userId, [params])](#UmamiClient+getUserWebsites) ⇒ Promise.<Array.<{id: string, userId: string, domain: string, name: string, shareId: (string\|null), createdAt: string, updatedAt: (string\|null), deletedAt: (string\|null), resetAt: (string\|null)}>> + * [.getUserTeams(userId, [params])](#UmamiClient+getUserTeams) ⇒ Promise.<Array.<{id: string, name: string, createdAt: string, updatedAt: (string\|null), deletedAt: (string\|null)}>> + * [.createTeam(params)](#UmamiClient+createTeam) ⇒ Promise.<{accessCode: string, createdAt: string, id: string, name: string, updatedAt: (string\|null)}> + * [.getTeams(params)](#UmamiClient+getTeams) ⇒ Promise.<Array> + * [.joinTeam(params)](#UmamiClient+joinTeam) ⇒ Promise.<Object> + * [.getTeam(teamId)](#UmamiClient+getTeam) ⇒ Promise.<Object> + * [.updateTeam(teamId, params)](#UmamiClient+updateTeam) ⇒ Promise.<Object> + * [.deleteTeam(teamId)](#UmamiClient+deleteTeam) ⇒ Promise.<string> + * [.getTeamUsers(teamId, [params])](#UmamiClient+getTeamUsers) ⇒ Promise.<Array> + * [.addUserToTeam(teamId, params)](#UmamiClient+addUserToTeam) ⇒ Promise.<Object> + * [.getTeamUser(teamId, userId)](#UmamiClient+getTeamUser) ⇒ Promise.<Object> + * [.updateTeamUserRole(teamId, userId, params)](#UmamiClient+updateTeamUserRole) ⇒ Promise.<string> + * [.removeUserFromTeam(teamId, userId)](#UmamiClient+removeUserFromTeam) ⇒ Promise.<string> + * [.getWebsites([params])](#UmamiClient+getWebsites) ⇒ Promise.<Array.<{id: string, name: string, domain: string, shareId: (string\|null), resetAt: (string\|null), createdAt: string, updatedAt: (string\|null), deletedAt: (string\|null)}>> + * [.createWebsite(params)](#UmamiClient+createWebsite) ⇒ Promise.<{id: number, websiteUuid: string, websiteId: number, name: string, domain: string, shareId: (string\|null), createdAt: string}> + * [.getWebsite(websiteId)](#UmamiClient+getWebsite) ⇒ Promise.<{id: string, name: string, domain: string, shareId: (string\|null), resetAt: (string\|null), userId: string, createdAt: string, updatedAt: (string\|null), deletedAt: (string\|null)}> + * [.updateWebsite(websiteId, params)](#UmamiClient+updateWebsite) ⇒ Promise.<{id: string, name: string, domain: string, shareId: (string\|null), resetAt: (string\|null), userId: string, createdAt: string, updatedAt: (string\|null), deletedAt: (string\|null)}> + * [.deleteWebsite(websiteId)](#UmamiClient+deleteWebsite) ⇒ Promise.<string> + * [.resetWebsite(websiteId)](#UmamiClient+resetWebsite) ⇒ Promise.<string> + * [.getTeamWebsites(teamId, [params])](#UmamiClient+getTeamWebsites) ⇒ Promise.<Array> + * [.getSessions(websiteId, params)](#UmamiClient+getSessions) ⇒ Promise.<{data: Array.<Session>, count: number, page: number, pageSize: number}> + * [.getSessionStats(websiteId, params)](#UmamiClient+getSessionStats) ⇒ [Promise.<SessionStats>](#SessionStats) + * [.getSession(websiteId, sessionId)](#UmamiClient+getSession) ⇒ [Promise.<Session>](#Session) + * [.getSessionActivity(websiteId, sessionId, params)](#UmamiClient+getSessionActivity) ⇒ Promise.<Array.<SessionActivity>> + * [.getSessionProperties(websiteId, sessionId)](#UmamiClient+getSessionProperties) ⇒ Promise.<Array.<SessionProperty>> + * [.getSessionDataProperties(websiteId, params)](#UmamiClient+getSessionDataProperties) ⇒ Promise.<Array.<PropertyCount>> + * [.getSessionDataValues(websiteId, params)](#UmamiClient+getSessionDataValues) ⇒ Promise.<Array.<PropertyValue>> + * [.getWebsites([params])](#UmamiClient+getWebsites) ⇒ Promise.<Array> + * [.createWebsite(params)](#UmamiClient+createWebsite) ⇒ Promise.<Object> + * [.getWebsite(websiteId)](#UmamiClient+getWebsite) ⇒ Promise.<Object> + * [.updateWebsite(websiteId, params)](#UmamiClient+updateWebsite) ⇒ Promise.<Object> + * [.deleteWebsite(websiteId)](#UmamiClient+deleteWebsite) ⇒ Promise.<string> + * [.resetWebsite(websiteId)](#UmamiClient+resetWebsite) ⇒ Promise.<string> + * [.getActiveUsers(websiteId)](#UmamiClient+getActiveUsers) ⇒ Promise.<Object> + * [.getEventsSeries(websiteId, params)](#UmamiClient+getEventsSeries) ⇒ Promise.<Array> + * [.getWebsiteEvents(websiteId, params)](#UmamiClient+getWebsiteEvents) ⇒ Promise.<{data: Array, count: number, page: number, pageSize: number}> + * [.getWebsiteStats(websiteId, params)](#UmamiClient+getWebsiteStats) ⇒ Promise.<{pageviews: {value: number, prev: number}, visitors: {value: number, prev: number}, visits: {value: number, prev: number}, bounces: {value: number, prev: number}, totaltime: {value: number, prev: number}}> + * [.getEventDataEvents(websiteId, params)](#UmamiClient+getEventDataEvents) ⇒ Promise.<Array.<{eventName: string, propertyName: string, dataType: number, total: number}>> + * [.getEventDataFields(websiteId, params)](#UmamiClient+getEventDataFields) ⇒ Promise.<Array.<{propertyName: string, dataType: number, value: string, total: number}>> + * [.getEventDataValues(websiteId, params)](#UmamiClient+getEventDataValues) ⇒ Promise.<Array.<{value: string, total: number}>> + * [.getEventDataStats(websiteId, params)](#UmamiClient+getEventDataStats) ⇒ Promise.<Array.<{events: number, fields: number, records: number}>> + * [.getPageviews(websiteId, params)](#UmamiClient+getPageviews) ⇒ Promise.<Object> + * [.getMetrics(websiteId, params)](#UmamiClient+getMetrics) ⇒ Promise.<Array> + * [.sendEvent(payload)](#UmamiClient+sendEvent) ⇒ Promise.<void> + + + +### new UmamiClient(config) +Creates a new UmamiClient instance + + +| Param | Type | Description | +| --- | --- | --- | +| config | Object | Configuration options | +| config.baseUrl | string | Base URL for the Umami API | +| config.username | string | Umami username | +| config.password | string | Umami password | + + + +### umamiClient.authenticate() ⇒ [Promise.<GetTokenResponse>](#GetTokenResponse) +Authenticates with the Umami API + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: [Promise.<GetTokenResponse>](#GetTokenResponse) - Authentication response +**Throws**: + +- Error If authentication fails + + + +### umamiClient.verifyToken() ⇒ [Promise.<User>](#User) +Verifies the current authentication token + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: [Promise.<User>](#User) - User information if token is valid + + +### umamiClient.createUser(params) ⇒ Promise.<{id: string, username: string, role: string, createdAt: string}> +Creates a new user. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<{id: string, username: string, role: string, createdAt: string}> - Created user details. + +| Param | Type | Description | +| --- | --- | --- | +| params | Object | Parameters for creating a user. | +| params.username | string | The user's username. | +| params.password | string | The user's password. | +| params.role | string | The user's role, either 'admin' or 'user'. | + + + +### umamiClient.getUsers() ⇒ Promise.<Array.<{id: string, username: string, role: string, createdAt: string}>> +Returns all users. Admin access is required. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Array.<{id: string, username: string, role: string, createdAt: string}>> - List of users. + + +### umamiClient.getUser(userId) ⇒ Promise.<{id: string, username: string, role: string}> +Gets details of a specific user by ID. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<{id: string, username: string, role: string}> - User details. + +| Param | Type | Description | +| --- | --- | --- | +| userId | string | The ID of the user. | + + + +### umamiClient.updateUser(userId, params) ⇒ Promise.<{id: string, username: string, role: string, createdAt: string}> +Updates details of a user. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<{id: string, username: string, role: string, createdAt: string}> - Updated user details. + +| Param | Type | Description | +| --- | --- | --- | +| userId | string | The ID of the user. | +| params | Object | Update parameters. | +| [params.username] | string | The user's new username (optional). | +| [params.password] | string | The user's new password (optional). | +| [params.role] | string | The user's role, either 'admin' or 'user' (optional). | + + + +### umamiClient.deleteUser(userId) ⇒ Promise.<string> +Deletes a user. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<string> - Confirmation message. + +| Param | Type | Description | +| --- | --- | --- | +| userId | string | The ID of the user. | + + + +### umamiClient.getUserWebsites(userId, [params]) ⇒ Promise.<Array.<{id: string, userId: string, domain: string, name: string, shareId: (string\|null), createdAt: string, updatedAt: (string\|null), deletedAt: (string\|null), resetAt: (string\|null)}>> +Gets all websites that belong to a user. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Array.<{id: string, userId: string, domain: string, name: string, shareId: (string\|null), createdAt: string, updatedAt: (string\|null), deletedAt: (string\|null), resetAt: (string\|null)}>> - List of websites belonging to the user. + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| userId | string | | The ID of the user. | +| [params] | Object | | Query parameters. | +| [params.query] | string | | Search text (optional). | +| [params.page] | number | 1 | Page number (optional). | +| [params.pageSize] | number | | Number of results per page (optional). | +| [params.orderBy] | string | "'name'" | Order by column name (optional). | + + + +### umamiClient.getUserTeams(userId, [params]) ⇒ Promise.<Array.<{id: string, name: string, createdAt: string, updatedAt: (string\|null), deletedAt: (string\|null)}>> +Gets all teams that belong to a user. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Array.<{id: string, name: string, createdAt: string, updatedAt: (string\|null), deletedAt: (string\|null)}>> - List of teams belonging to the user. + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| userId | string | | The ID of the user. | +| [params] | Object | | Query parameters. | +| [params.query] | string | | Search text (optional). | +| [params.page] | number | 1 | Page number (optional). | +| [params.pageSize] | number | | Number of results per page (optional). | +| [params.orderBy] | string | "'name'" | Order by column name (optional). | + + + +### umamiClient.createTeam(params) ⇒ Promise.<{accessCode: string, createdAt: string, id: string, name: string, updatedAt: (string\|null)}> +Creates a new team. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<{accessCode: string, createdAt: string, id: string, name: string, updatedAt: (string\|null)}> - Created team details. + +| Param | Type | Description | +| --- | --- | --- | +| params | Object | Parameters for creating a team. | +| params.name | string | The team's name. | + + + +### umamiClient.getTeams(params) ⇒ Promise.<Array> +Returns all teams. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Array> - List of all teams with team user information. + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| params | Object | | Query parameters. | +| [params.query] | string | | Search text (optional). | +| [params.page] | number | 1 | Page number (optional). | +| [params.pageSize] | number | | Number of results per page (optional). | +| [params.orderBy] | string | "'name'" | Order by column name (optional). | + + + +### umamiClient.joinTeam(params) ⇒ Promise.<Object> +Joins a team using an access code. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Object> - Joined team details. + +| Param | Type | Description | +| --- | --- | --- | +| params | Object | Parameters for joining a team. | +| params.accessCode | string | The team's access code. | + + + +### umamiClient.getTeam(teamId) ⇒ Promise.<Object> +Gets details of a specific team. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Object> - Team details. + +| Param | Type | Description | +| --- | --- | --- | +| teamId | string | The ID of the team. | + + + +### umamiClient.updateTeam(teamId, params) ⇒ Promise.<Object> +Updates team details. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Object> - Updated team details. + +| Param | Type | Description | +| --- | --- | --- | +| teamId | string | The ID of the team. | +| params | Object | Update parameters. | +| [params.name] | string | The team's name (optional). | +| [params.accessCode] | string | The team's access code (optional). | + + + +### umamiClient.deleteTeam(teamId) ⇒ Promise.<string> +Deletes a team. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<string> - Confirmation message. + +| Param | Type | Description | +| --- | --- | --- | +| teamId | string | The ID of the team. | + + + +### umamiClient.getTeamUsers(teamId, [params]) ⇒ Promise.<Array> +Gets all users that belong to a team. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Array> - List of team users. + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| teamId | string | | The ID of the team. | +| [params] | Object | | Query parameters. | +| [params.query] | string | | Search text (optional). | +| [params.page] | number | 1 | Page number (optional). | +| [params.pageSize] | number | | Number of results per page (optional). | +| [params.orderBy] | string | "'name'" | Order by column name (optional). | + + + +### umamiClient.addUserToTeam(teamId, params) ⇒ Promise.<Object> +Adds a user to a team. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Object> - Added team user details. + +| Param | Type | Description | +| --- | --- | --- | +| teamId | string | The ID of the team. | +| params | Object | Parameters for adding a user to the team. | +| params.userId | string | The user's ID. | +| params.role | string | The role to assign (e.g., 'member' or 'view-only'). | + + + +### umamiClient.getTeamUser(teamId, userId) ⇒ Promise.<Object> +Gets details of a user in a team. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Object> - Team user details. + +| Param | Type | Description | +| --- | --- | --- | +| teamId | string | The ID of the team. | +| userId | string | The user's ID. | + + + +### umamiClient.updateTeamUserRole(teamId, userId, params) ⇒ Promise.<string> +Updates a user's role in a team. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<string> - Confirmation message. + +| Param | Type | Description | +| --- | --- | --- | +| teamId | string | The ID of the team. | +| userId | string | The user's ID. | +| params | Object | Parameters for updating user role. | +| params.role | string | The new role (e.g., 'member' or 'view-only'). | + + + +### umamiClient.removeUserFromTeam(teamId, userId) ⇒ Promise.<string> +Removes a user from a team. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<string> - Confirmation message. + +| Param | Type | Description | +| --- | --- | --- | +| teamId | string | The ID of the team. | +| userId | string | The user's ID. | + + + +### umamiClient.getWebsites([params]) ⇒ Promise.<Array.<{id: string, name: string, domain: string, shareId: (string\|null), resetAt: (string\|null), createdAt: string, updatedAt: (string\|null), deletedAt: (string\|null)}>> +Returns all tracked websites. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Array.<{id: string, name: string, domain: string, shareId: (string\|null), resetAt: (string\|null), createdAt: string, updatedAt: (string\|null), deletedAt: (string\|null)}>> - List of websites. + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| [params] | Object | | Query parameters. | +| [params.query] | string | | Search text (optional). | +| [params.page] | number | 1 | Page number (optional). | +| [params.pageSize] | number | | Number of results per page (optional). | +| [params.orderBy] | string | "'name'" | Order by column name (optional). | + + + +### umamiClient.createWebsite(params) ⇒ Promise.<{id: number, websiteUuid: string, websiteId: number, name: string, domain: string, shareId: (string\|null), createdAt: string}> +Creates a new website. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<{id: number, websiteUuid: string, websiteId: number, name: string, domain: string, shareId: (string\|null), createdAt: string}> - Details of the created website. + +| Param | Type | Description | +| --- | --- | --- | +| params | Object | Website parameters. | +| params.domain | string | The full domain of the tracked website. | +| params.name | string | The name of the website in Umami. | +| [params.shareId] | string | A unique string to enable a share URL (optional). | +| [params.teamId] | string | The ID of the team the website will be created under (optional). | + + + +### umamiClient.getWebsite(websiteId) ⇒ Promise.<{id: string, name: string, domain: string, shareId: (string\|null), resetAt: (string\|null), userId: string, createdAt: string, updatedAt: (string\|null), deletedAt: (string\|null)}> +Gets details of a specific website by ID. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<{id: string, name: string, domain: string, shareId: (string\|null), resetAt: (string\|null), userId: string, createdAt: string, updatedAt: (string\|null), deletedAt: (string\|null)}> - Website details. + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | The ID of the website. | + + + +### umamiClient.updateWebsite(websiteId, params) ⇒ Promise.<{id: string, name: string, domain: string, shareId: (string\|null), resetAt: (string\|null), userId: string, createdAt: string, updatedAt: (string\|null), deletedAt: (string\|null)}> +Updates details of a website. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<{id: string, name: string, domain: string, shareId: (string\|null), resetAt: (string\|null), userId: string, createdAt: string, updatedAt: (string\|null), deletedAt: (string\|null)}> - Updated website details. + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | The ID of the website. | +| params | Object | Update parameters. | +| [params.name] | string | The name of the website in Umami (optional). | +| [params.domain] | string | The full domain of the tracked website (optional). | +| [params.shareId] | string | A unique string to enable a share URL or null to unshare (optional). | + + + +### umamiClient.deleteWebsite(websiteId) ⇒ Promise.<string> +Deletes a website. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<string> - Confirmation message. + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | The ID of the website. | + + + +### umamiClient.resetWebsite(websiteId) ⇒ Promise.<string> +Resets a website by removing all data related to it. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<string> - Confirmation message. + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | The ID of the website. | + + + +### umamiClient.getTeamWebsites(teamId, [params]) ⇒ Promise.<Array> +Gets all websites that belong to a team. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Array> - List of team websites. + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| teamId | string | | The ID of the team. | +| [params] | Object | | Query parameters. | +| [params.query] | string | | Search text (optional). | +| [params.page] | number | 1 | Page number (optional). | +| [params.pageSize] | number | | Number of results per page (optional). | +| [params.orderBy] | string | "'name'" | Order by column name (optional). | + + + +### umamiClient.getSessions(websiteId, params) ⇒ Promise.<{data: Array.<Session>, count: number, page: number, pageSize: number}> +Gets website session details within a given time range + +**Kind**: instance method of [UmamiClient](#UmamiClient) + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| websiteId | string | | Website ID | +| params | Object | | Query parameters | +| params.startAt | number | | Timestamp (in ms) of starting date | +| params.endAt | number | | Timestamp (in ms) of end date | +| [params.query] | string | | Search text | +| [params.page] | number | 1 | Page number | +| [params.pageSize] | number | | Results per page | +| [params.orderBy] | string | | Order by column name | + + + +### umamiClient.getSessionStats(websiteId, params) ⇒ [Promise.<SessionStats>](#SessionStats) +Gets summarized website session statistics + +**Kind**: instance method of [UmamiClient](#UmamiClient) + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | Website ID | +| params | Object | Query parameters | +| params.startAt | number | Timestamp (in ms) of starting date | +| params.endAt | number | Timestamp (in ms) of end date | +| [params.url] | string | Filter by URL | +| [params.referrer] | string | Filter by referrer | +| [params.title] | string | Filter by page title | +| [params.query] | string | Filter by query | +| [params.event] | string | Filter by event name | +| [params.host] | string | Filter by hostname | +| [params.os] | string | Filter by operating system | +| [params.browser] | string | Filter by browser | +| [params.device] | string | Filter by device | +| [params.country] | string | Filter by country | +| [params.region] | string | Filter by region | +| [params.city] | string | Filter by city | + + + +### umamiClient.getSession(websiteId, sessionId) ⇒ [Promise.<Session>](#Session) +Gets session details for an individual session + +**Kind**: instance method of [UmamiClient](#UmamiClient) + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | Website ID | +| sessionId | string | Session ID | + + + +### umamiClient.getSessionActivity(websiteId, sessionId, params) ⇒ Promise.<Array.<SessionActivity>> +Gets session activity for an individual session + +**Kind**: instance method of [UmamiClient](#UmamiClient) + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | Website ID | +| sessionId | string | Session ID | +| params | Object | Query parameters | +| params.startAt | number | Timestamp (in ms) of starting date | +| params.endAt | number | Timestamp (in ms) of end date | + + + +### umamiClient.getSessionProperties(websiteId, sessionId) ⇒ Promise.<Array.<SessionProperty>> +Gets session properties for an individual session + +**Kind**: instance method of [UmamiClient](#UmamiClient) + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | Website ID | +| sessionId | string | Session ID | + + + +### umamiClient.getSessionDataProperties(websiteId, params) ⇒ Promise.<Array.<PropertyCount>> +Gets session data counts by property name + +**Kind**: instance method of [UmamiClient](#UmamiClient) + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | Website ID | +| params | Object | Query parameters | +| params.startAt | number | Timestamp (in ms) of starting date | +| params.endAt | number | Timestamp (in ms) of end date | + + + +### umamiClient.getSessionDataValues(websiteId, params) ⇒ Promise.<Array.<PropertyValue>> +Gets session data counts for a given property + +**Kind**: instance method of [UmamiClient](#UmamiClient) + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | Website ID | +| params | Object | Query parameters | +| params.startAt | number | Timestamp (in ms) of starting date | +| params.endAt | number | Timestamp (in ms) of end date | +| params.propertyName | string | Property name | + + + +### umamiClient.getWebsites([params]) ⇒ Promise.<Array> +Gets all tracked websites + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Array> - List of websites + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| [params] | Object | | Query parameters | +| [params.query] | string | | Search text | +| [params.page] | number | 1 | Page number | +| [params.pageSize] | number | | Results per page | +| [params.orderBy] | string | "'name'" | Order by column name | + + + +### umamiClient.createWebsite(params) ⇒ Promise.<Object> +Creates a new website + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Object> - Created website details + +| Param | Type | Description | +| --- | --- | --- | +| params | Object | Website parameters | +| params.domain | string | The full domain of the tracked website | +| params.name | string | The name of the website in Umami | +| [params.shareId] | string | A unique string to enable a share url | +| [params.teamId] | string | The ID of the team the website will be created under | + + + +### umamiClient.getWebsite(websiteId) ⇒ Promise.<Object> +Gets a website by ID + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Object> - Website details + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | Website ID | + + + +### umamiClient.updateWebsite(websiteId, params) ⇒ Promise.<Object> +Updates a website + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Object> - Updated website details + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | Website ID | +| params | Object | Update parameters | +| [params.name] | string | The name of the website in Umami | +| [params.domain] | string | The full domain of the tracked website | +| [params.shareId] | string | A unique string to enable a share url | + + + +### umamiClient.deleteWebsite(websiteId) ⇒ Promise.<string> +Deletes a website + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<string> - Confirmation message + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | Website ID | + + + +### umamiClient.resetWebsite(websiteId) ⇒ Promise.<string> +Resets a website by removing all data + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<string> - Confirmation message + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | Website ID | + + + +### umamiClient.getActiveUsers(websiteId) ⇒ Promise.<Object> +Gets the number of active users on a website + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Object> - Active users count + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | Website ID | + + + +### umamiClient.getEventsSeries(websiteId, params) ⇒ Promise.<Array> +Gets events within a given time range + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Array> - Event series data + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | Website ID | +| params | Object | Query parameters | +| params.startAt | number | Timestamp (in ms) of starting date | +| params.endAt | number | Timestamp (in ms) of end date | +| params.unit | string | Time unit (year | month | hour | day) | +| params.timezone | string | Timezone (ex. America/Los_Angeles) | +| [params.url] | string | Filter by URL | +| [params.referrer] | string | Filter by referrer | +| [params.title] | string | Filter by page title | +| [params.host] | string | Filter by hostname | +| [params.os] | string | Filter by operating system | +| [params.browser] | string | Filter by browser | +| [params.device] | string | Filter by device | +| [params.country] | string | Filter by country | +| [params.region] | string | Filter by region | +| [params.city] | string | Filter by city | + + + +### umamiClient.getWebsiteEvents(websiteId, params) ⇒ Promise.<{data: Array, count: number, page: number, pageSize: number}> +Gets website event details within a given time range. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<{data: Array, count: number, page: number, pageSize: number}> - Event data response. + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| websiteId | string | | The ID of the website. | +| params | Object | | Query parameters. | +| params.startAt | number | | Timestamp (in ms) of the starting date. | +| params.endAt | number | | Timestamp (in ms) of the end date. | +| [params.query] | string | | Search text (optional). | +| [params.page] | number | 1 | Page number (optional). | +| [params.pageSize] | number | | Number of results to return (optional). | +| [params.orderBy] | string | | Order by column name (optional). | + + + +### umamiClient.getWebsiteStats(websiteId, params) ⇒ Promise.<{pageviews: {value: number, prev: number}, visitors: {value: number, prev: number}, visits: {value: number, prev: number}, bounces: {value: number, prev: number}, totaltime: {value: number, prev: number}}> +Gets summarized website statistics. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<{pageviews: {value: number, prev: number}, visitors: {value: number, prev: number}, visits: {value: number, prev: number}, bounces: {value: number, prev: number}, totaltime: {value: number, prev: number}}> - Summarized website statistics. + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | The ID of the website. | +| params | Object | Query parameters. | +| params.startAt | number | Timestamp (in ms) of starting date. | +| params.endAt | number | Timestamp (in ms) of end date. | +| [params.url] | string | Filter by URL (optional). | +| [params.referrer] | string | Filter by referrer (optional). | +| [params.title] | string | Filter by page title (optional). | +| [params.query] | string | Filter by query (optional). | +| [params.event] | string | Filter by event name (optional). | +| [params.host] | string | Filter by hostname (optional). | +| [params.os] | string | Filter by operating system (optional). | +| [params.browser] | string | Filter by browser (optional). | +| [params.device] | string | Filter by device (e.g., Mobile, optional). | +| [params.country] | string | Filter by country (optional). | +| [params.region] | string | Filter by region/state/province (optional). | +| [params.city] | string | Filter by city (optional). | + + + +### umamiClient.getEventDataEvents(websiteId, params) ⇒ Promise.<Array.<{eventName: string, propertyName: string, dataType: number, total: number}>> +Gets event data names, properties, and counts. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Array.<{eventName: string, propertyName: string, dataType: number, total: number}>> - Event data summary. + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | The ID of the website. | +| params | Object | Query parameters. | +| params.startAt | number | Timestamp (in ms) of the starting date. | +| params.endAt | number | Timestamp (in ms) of the end date. | +| [params.event] | string | Event name filter (optional). | + + + +### umamiClient.getEventDataFields(websiteId, params) ⇒ Promise.<Array.<{propertyName: string, dataType: number, value: string, total: number}>> +Gets event data property and value counts within a given time range. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Array.<{propertyName: string, dataType: number, value: string, total: number}>> - Event data fields. + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | The ID of the website. | +| params | Object | Query parameters. | +| params.startAt | number | Timestamp (in ms) of the starting date. | +| params.endAt | number | Timestamp (in ms) of the end date. | + + + +### umamiClient.getEventDataValues(websiteId, params) ⇒ Promise.<Array.<{value: string, total: number}>> +Gets event data counts for a given event and property. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Array.<{value: string, total: number}>> - Event data values. + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | The ID of the website. | +| params | Object | Query parameters. | +| params.startAt | number | Timestamp (in ms) of the starting date. | +| params.endAt | number | Timestamp (in ms) of the end date. | +| params.eventName | string | The name of the event. | +| params.propertyName | string | The property name. | + + + +### umamiClient.getEventDataStats(websiteId, params) ⇒ Promise.<Array.<{events: number, fields: number, records: number}>> +Gets summarized website events, fields, and records within a given time range. + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Array.<{events: number, fields: number, records: number}>> - Summary of events, fields, and records. + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | The ID of the website. | +| params | Object | Query parameters. | +| params.startAt | number | Timestamp (in ms) of the starting date. | +| params.endAt | number | Timestamp (in ms) of the end date. | + + + +### umamiClient.getPageviews(websiteId, params) ⇒ Promise.<Object> +Gets pageviews within a given time range + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Object> - Pageview data + +| Param | Type | Description | +| --- | --- | --- | +| websiteId | string | Website ID | +| params | Object | Query parameters | +| params.startAt | number | Timestamp (in ms) of starting date | +| params.endAt | number | Timestamp (in ms) of end date | +| params.unit | string | Time unit (year | month | hour | day) | +| params.timezone | string | Timezone (ex. America/Los_Angeles) | +| [params.url] | string | Filter by URL | +| [params.referrer] | string | Filter by referrer | +| [params.title] | string | Filter by page title | +| [params.host] | string | Filter by hostname | +| [params.os] | string | Filter by operating system | +| [params.browser] | string | Filter by browser | +| [params.device] | string | Filter by device | +| [params.country] | string | Filter by country | +| [params.region] | string | Filter by region | +| [params.city] | string | Filter by city | + + + +### umamiClient.getMetrics(websiteId, params) ⇒ Promise.<Array> +Gets metrics for a given time range + +**Kind**: instance method of [UmamiClient](#UmamiClient) +**Returns**: Promise.<Array> - Metrics data + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| websiteId | string | | Website ID | +| params | Object | | Query parameters | +| params.startAt | number | | Timestamp (in ms) of starting date | +| params.endAt | number | | Timestamp (in ms) of end date | +| params.type | string | | Metrics type (url | referrer | browser | os | device | country | event) | +| [params.url] | string | | Filter by URL | +| [params.referrer] | string | | Filter by referrer | +| [params.title] | string | | Filter by page title | +| [params.query] | string | | Filter by query | +| [params.host] | string | | Filter by hostname | +| [params.os] | string | | Filter by operating system | +| [params.browser] | string | | Filter by browser | +| [params.device] | string | | Filter by device | +| [params.country] | string | | Filter by country | +| [params.region] | string | | Filter by region | +| [params.city] | string | | Filter by city | +| [params.language] | string | | Filter by language | +| [params.event] | string | | Filter by event | +| [params.limit] | number | 500 | Number of events returned | + + + +### umamiClient.sendEvent(payload) ⇒ Promise.<void> +Sends an event to Umami + +**Kind**: instance method of [UmamiClient](#UmamiClient) + +| Param | Type | Description | +| --- | --- | --- | +| payload | [EventPayload](#EventPayload) | Event data | + + + +## User : Object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| id | string | The user's unique identifier | +| username | string | The user's username | +| role | string | The user's role | +| createdAt | Date | When the user was created | +| isAdmin | boolean | Whether the user has admin privileges | + + + +## GetTokenResponse : Object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| token | string | Authentication token | +| user | [User](#User) | User information | + + + +## EventPayload : Object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| hostname | string | Name of host | +| language | string | Language of visitor (e.g., "en-US") | +| referrer | string | Referrer URL | +| screen | string | Screen resolution (e.g., "1920x1080") | +| title | string | Page title | +| url | string | Page URL | +| website | string | Website ID | +| name | string | Name of the event | +| [data] | Object | Optional additional data for the event | + + + +## Session : Object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| id | string | Session ID | +| websiteId | string | Website ID | +| hostname | string | Hostname | +| browser | string | Browser name | +| os | string | Operating system | +| device | string | Device type | +| screen | string | Screen resolution | +| language | string | Language code | +| country | string | Country code | +| subdivision1 | string | Region/state code | +| city | string | City name | +| firstAt | string | First activity timestamp | +| lastAt | string | Last activity timestamp | +| visits | number | Number of visits | +| views | number | Number of page views | +| createdAt | string | Creation timestamp | + + + +## SessionStats : Object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| pageviews | Object | Pages hits | +| visitors | Object | Number of unique visitors | +| visits | Object | Number of sessions | +| countries | Object | Number of unique countries | +| events | Object | Number of custom events | + + + +## SessionActivity : Object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| createdAt | string | Activity timestamp | +| urlPath | string | URL path | +| urlQuery | string | URL query parameters | +| referrerDomain | string | Referrer domain | +| eventId | string | Event ID | +| eventType | number | Event type | +| eventName | string | Event name | +| visitId | string | Visit ID | + + + +## SessionProperty : Object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| websiteId | string | Website ID | +| sessionId | string | Session ID | +| dataKey | string | Property key | +| dataType | number | Data type | +| stringValue | string \| null | String value | +| numberValue | number \| null | Number value | +| dateValue | string \| null | Date value | +| createdAt | string | Creation timestamp | + + + +## PropertyCount : Object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| propertyName | string | Name of the property | +| total | number | Total count | + + + +## PropertyValue : Object +**Kind**: global typedef +**Properties** + +| Name | Type | Description | +| --- | --- | --- | +| value | string | Property value | +| total | number | Total count | \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0ac6f35 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Abdullah Basheer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..ec6b0e2 --- /dev/null +++ b/README.md @@ -0,0 +1,216 @@ +# UmamiClient +> Note: For self-hosted instances only. For Umami Cloud, consider using the official [Umami API Client](https://github.com/umami-software/api-client/). + +> Documentation generated with the assistance of ChatGPT. Please report any inaccuracies. + +The `UmamiClient` is a JavaScript ~class~ library designed to simplify interaction with the [Umami Analytics API](https://umami.is/docs/api). It provides methods for user authentication, website management, session analysis, event tracking, and data retrieval. This ~client~ library streamlines the process of fetching statistics, sessions, and events from a self-hosted Umami instance for use in applications or reporting dashboards. ~The class definition resides in the `umami.js` file.~ + +## [FULL DOCUMENTATION](./DOCS.md) + +~This is not a published library; it's a standalone class intended for direct integration into projects.~ This is now a published library. It was developed to address specific needs and provide clearer documentation compared to the existing `@umami/api-client`. + +## Table of Contents +- [Key Features](#key-features-of-umamiclient) +- [Getting Started](#getting-started) +- [Authentication](#authentication) +- [User Management](#user-management) +- [Team Management](#team-management) +- [Website Management](#website-management) +- [Session Analysis](#session-analysis) +- [Event Tracking and Data Retrieval](#event-tracking-and-data-retrieval) +- [Examples](#examples) +- [Type Definitions](#type-definitions) + +## Key Features of UmamiClient + +### 1. Automatic Authentication and Token Management + +- `authenticate()` initiates the login process and retrieves an authentication token. +- `#ensureValidToken()` (private method) automatically checks token validity before each API request and refreshes it if expired, eliminating manual token management. + +### 2. Private Helper Methods for Code Consistency + +- Private methods like `#makeAuthenticatedRequest()` and `#formatQueryParams()` handle common tasks: + - Making authenticated requests. + - Injecting authorization tokens into headers. + - Formatting query parameters for clean URL construction. +- This abstraction ensures consistent request structure, headers, and error handling for improved robustness. + +### 3. Modular API Endpoint Coverage + +- `UmamiClient` provides methods for various Umami API endpoints, grouped by functionality: + - **Authentication:** `authenticate()`, `verifyToken()` + - **User Management:** `createUser()`, `getUsers()`, `getUser()`, `updateUser()`, `deleteUser()`, `getUserWebsites()`, `getUserTeams()` + - **Team Management:** `createTeam()`, `getTeams()`, `joinTeam()`, `getTeam()`, `updateTeam()`, `deleteTeam()`, `getTeamUsers()`, `addUserToTeam()`, `getTeamUser()`, `updateTeamUserRole()`, `removeUserFromTeam()`, `getTeamWebsites()` + - **Website Management:** `getWebsites()`, `createWebsite()`, `getWebsite()`, `updateWebsite()`, `deleteWebsite()`, `resetWebsite()` + - **Session Analysis:** `getSessions()`, `getSessionStats()`, `getSession()`, `getSessionActivity()`, `getSessionProperties()`, `getSessionDataProperties()`, `getSessionDataValues()` + - **Event Tracking:** `getEventsSeries()`, `getWebsiteEvents()`, `getWebsiteStats()`, `getEventDataEvents()`, `getEventDataFields()`, `getEventDataValues()`, `getEventDataStats()`, `getPageviews()`, `getMetrics()`, `sendEvent()` , `getActiveUsers()` +- This modularity simplifies using the client for specific tasks. + + +### 4. Flexible Query Parameter Handling + +- `#formatQueryParams()` handles a wide range of query parameters, omitting undefined values for flexibility. +- This allows precise control over filtering, pagination, and sorting without manual query string formatting. + +### 5. Robust Error Handling + +- `#makeAuthenticatedRequest()` and `authenticate()` include error handling, throwing descriptive errors for authentication failures or network issues to aid debugging. + +### 6. Frontend Compatibility + +- `sendEvent()` automatically detects frontend context (e.g., `navigator.language`, `document.referrer`) for seamless event tracking in web applications. + +### 7. Typed Responses with JSDoc + +- Methods return specific data structures (e.g., `Session`, `SessionStats`, `PropertyCount`) or pagination information for predictable and easy-to-use responses. These types are documented using JSDoc typedefs. + + +## Getting Started + +### Installation + +```bash +npm install easy-umami-js +``` + +### Basic Setup + +#### ES6 Import +```javascript +import UmamiClient from 'easy-umami-js'; + +const client = new UmamiClient({ + baseUrl: 'https://your-umami-instance.com', // Your Umami instance URL (no trailing slash) + username: 'your-username', // superadmin username + password: 'your-password' // superadmin password +}); +``` + +#### CJS +```javascript +const UmamiClient = require('easy-umami-js'); + +const client = new UmamiClient({ + baseUrl: 'https://your-umami-instance.com', // Your Umami instance URL (no trailing slash) + username: 'your-username', // superadmin username + password: 'your-password' // superadmin password +}); +``` + +## Authentication + +- **`authenticate()`**: Authenticates with the Umami API and stores the token. +- **`verifyToken()`**: Verifies the current token and returns user information. + + +## User Management + +- **`createUser(params)`**: Creates a new user. Requires admin privileges. +- **`getUsers()`**: Retrieves all users. Requires admin privileges. +- **`getUser(userId)`**: Retrieves a specific user by ID. +- **`updateUser(userId, params)`**: Updates a user's information. +- **`deleteUser(userId)`**: Deletes a user by ID. Requires admin privileges. +- **`getUserWebsites(userId, params)`**: Retrieves websites associated with a user. +- **`getUserTeams(userId, params)`**: Retrieves teams associated with a user. + + +## Team Management + +- **`createTeam(params)`**: Creates a new team. +- **`getTeams(params)`**: Retrieves all teams. +- **`joinTeam(params)`**: Joins a team using an access code. +- **`getTeam(teamId)`**: Retrieves a specific team by ID. +- **`updateTeam(teamId, params)`**: Updates a team's information. +- **`deleteTeam(teamId)`**: Deletes a team by ID. +- **`getTeamUsers(teamId, params)`**: Retrieves users belonging to a team. +- **`addUserToTeam(teamId, params)`**: Adds a user to a team. +- **`getTeamUser(teamId, userId)`**: Retrieves details of a user within a team. +- **`updateTeamUserRole(teamId, userId, params)`**: Updates a user's role within a team. +- **`removeUserFromTeam(teamId, userId)`**: Removes a user from a team. +- **`getTeamWebsites(teamId, params)`**: Retrieves websites associated with a team. + +## Website Management + +- **`getWebsites(params)`**: Retrieves all websites. +- **`createWebsite(params)`**: Creates a new website. +- **`getWebsite(websiteId)`**: Retrieves a specific website by ID. +- **`updateWebsite(websiteId, params)`**: Updates website information. +- **`deleteWebsite(websiteId)`**: Deletes a website by ID. +- **`resetWebsite(websiteId)`**: Resets all data for a website. + + +## Session Analysis + +- **`getSessions(websiteId, params)`**: Retrieves sessions for a website within a time range. +- **`getSessionStats(websiteId, params)`**: Retrieves summarized session statistics for a website. +- **`getSession(websiteId, sessionId)`**: Retrieves a specific session by ID. +- **`getSessionActivity(websiteId, sessionId, params)`**: Retrieves activity details for a session. +- **`getSessionProperties(websiteId, sessionId)`**: Retrieves properties associated with a session. +- **`getSessionDataProperties(websiteId, params)`**: Retrieves session data counts by property name. +- **`getSessionDataValues(websiteId, params)`**: Retrieves session data counts for a given property. + + +## Event Tracking and Data Retrieval + +- **`getActiveUsers(websiteId)`**: Gets the number of active users on a website. +- **`getEventsSeries(websiteId, params)`**: Retrieves event series data for a website. +- **`getWebsiteEvents(websiteId, params)`**: Retrieves detailed event data for a website. +- **`getWebsiteStats(websiteId, params)`**: Retrieves summarized website statistics. +- **`getEventDataEvents(websiteId, params)`**: Retrieves event data summaries (names, properties, counts). +- **`getEventDataFields(websiteId, params)`**: Retrieves event data property and value counts. +- **`getEventDataValues(websiteId, params)`**: Retrieves event data counts for a specific event and property. +- **`getEventDataStats(websiteId, params)`**: Retrieves summarized event data (events, fields, records). +- **`getPageviews(websiteId, params)`**: Retrieves pageview data for a website. +- **`getMetrics(websiteId, params)`**: Retrieves various website metrics (e.g., URLs, referrers, browsers). +- **`sendEvent(payload)`**: Sends a custom event to Umami. + + +## Examples + +### Authentication and Session Retrieval + +```javascript +async function getSessions() { + try { + const authResponse = await client.authenticate(); + console.log("Authentication successful:", authResponse); + + const sessions = await client.getSessions('your-website-id', { + startAt: Date.now() - 7 * 24 * 60 * 60 * 1000, // Last 7 days + endAt: Date.now() + }); + console.log("Sessions:", sessions); + } catch (error) { + console.error("Error:", error); + } +} + +getSessions(); +``` + +### Sending a Custom Event + +```javascript +client.sendEvent({ + website: 'your-website-id', + name: 'product_view', + data: { product_id: '12345' } +}); +``` + + +## Type Definitions + +Refer to the JSDoc typedefs within the `umami.js` file for detailed information on the structure of objects like `User`, `GetTokenResponse`, `EventPayload`, `Session`, `SessionStats`, `SessionActivity`, `SessionProperty`, `PropertyCount`, and `PropertyValue`. These definitions provide clear documentation of the expected data structures for requests and responses. There's an documentation generated with jsdoc2md [here](./DOCS.md) + + +--- + +For complete API details and query parameter options, refer to the official [Umami Analytics API Documentation](https://umami.is/docs/api). + +## TODO to v1: +- [ ] Test all the endpoints +- [ ] Add [`async-retry`](https://www.npmjs.com/package/async-retry) and add a `retries` parameter to class config and individual methods. +- [ ] Add a `timeout` parameter to class config and individual methods. +- [ ] Allow passing the `opts` type directly to class config and individual methods. \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..ffe8d95 --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "easy-umami-js", + "version": "0.8.1", + "main": "umami.js", + "type": "module", + "description": "A JavaScript client for interacting with the Umami analytics API.", + "keywords": ["umami", "analytics", "api", "client"], + "author": "digitaldrreamer", + "license": "MIT", + "exports": { + "require": "./umami.cjs.js", + "import": "./umami.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/digitaldrreamer/easy-umami-js.git" + }, + "homepage": "https://github.com/digitaldrreamer/easy-umami-js#readme" +} diff --git a/umami.cjs.js b/umami.cjs.js new file mode 100644 index 0000000..794ad33 --- /dev/null +++ b/umami.cjs.js @@ -0,0 +1,2 @@ +const UmamiClient = require('./umami.js'); +module.exports = UmamiClient; diff --git a/umami.js b/umami.js new file mode 100644 index 0000000..ecdcb7b --- /dev/null +++ b/umami.js @@ -0,0 +1,936 @@ +/** + * @typedef {Object} User + * @property {string} id - The user's unique identifier + * @property {string} username - The user's username + * @property {string} role - The user's role + * @property {Date} createdAt - When the user was created + * @property {boolean} isAdmin - Whether the user has admin privileges + */ + +/** + * @typedef {Object} GetTokenResponse + * @property {string} token - Authentication token + * @property {User} user - User information + */ + +/** + * @typedef {Object} EventPayload + * @property {string} hostname - Name of host + * @property {string} language - Language of visitor (e.g., "en-US") + * @property {string} referrer - Referrer URL + * @property {string} screen - Screen resolution (e.g., "1920x1080") + * @property {string} title - Page title + * @property {string} url - Page URL + * @property {string} website - Website ID + * @property {string} name - Name of the event + * @property {Object} [data] - Optional additional data for the event + */ + +/** + * @typedef {Object} Session + * @property {string} id - Session ID + * @property {string} websiteId - Website ID + * @property {string} hostname - Hostname + * @property {string} browser - Browser name + * @property {string} os - Operating system + * @property {string} device - Device type + * @property {string} screen - Screen resolution + * @property {string} language - Language code + * @property {string} country - Country code + * @property {string} subdivision1 - Region/state code + * @property {string} city - City name + * @property {string} firstAt - First activity timestamp + * @property {string} lastAt - Last activity timestamp + * @property {number} visits - Number of visits + * @property {number} views - Number of page views + * @property {string} createdAt - Creation timestamp + */ + +/** + * @typedef {Object} SessionStats + * @property {{ value: number }} pageviews - Pages hits + * @property {{ value: number }} visitors - Number of unique visitors + * @property {{ value: number }} visits - Number of sessions + * @property {{ value: number }} countries - Number of unique countries + * @property {{ value: number }} events - Number of custom events + */ + +/** + * @typedef {Object} SessionActivity + * @property {string} createdAt - Activity timestamp + * @property {string} urlPath - URL path + * @property {string} urlQuery - URL query parameters + * @property {string} referrerDomain - Referrer domain + * @property {string} eventId - Event ID + * @property {number} eventType - Event type + * @property {string} eventName - Event name + * @property {string} visitId - Visit ID + */ + +/** + * @typedef {Object} SessionProperty + * @property {string} websiteId - Website ID + * @property {string} sessionId - Session ID + * @property {string} dataKey - Property key + * @property {number} dataType - Data type + * @property {string|null} stringValue - String value + * @property {number|null} numberValue - Number value + * @property {string|null} dateValue - Date value + * @property {string} createdAt - Creation timestamp + */ + +/** + * @typedef {Object} PropertyCount + * @property {string} propertyName - Name of the property + * @property {number} total - Total count + */ + +/** + * @typedef {Object} PropertyValue + * @property {string} value - Property value + * @property {number} total - Total count + */ + +class UmamiClient { + /** + * Creates a new UmamiClient instance + * @param {Object} config - Configuration options + * @param {string} config.baseUrl - Base URL for the Umami API + * @param {string} config.username - Umami username + * @param {string} config.password - Umami password + */ + constructor({ baseUrl, username, password }) { + this.baseUrl = baseUrl; + this.username = username; + this.password = password; + this.token = null; + this.tokenExpiry = null; + } + + /** + * Makes an authenticated API request + * @private + * @param {string} endpoint - API endpoint + * @param {Object} options - Fetch options + * @returns {Promise} - API response + */ + async #makeAuthenticatedRequest(endpoint, options = {}) { + await this.#ensureValidToken(); + + const response = await fetch(`${this.baseUrl}${endpoint}`, { + ...options, + headers: { + ...options.headers, + 'Authorization': `Bearer ${this.token}`, + 'Content-Type': 'application/json', + }, + }); + + if (!response.ok) { + throw new Error(`API request failed: ${response.statusText}`); + } + + return response.json(); + } + + /** + * Ensures a valid authentication token exists, obtaining a new one if necessary + * @private + */ + async #ensureValidToken() { + const tokenLifespan = 24 * 60 * 60 * 1000; // 24 hours in milliseconds + const isTokenExpired = !this.tokenExpiry || Date.now() > this.tokenExpiry; + + if (!this.token || isTokenExpired) { + await this.authenticate(); + } + } + + /** + * Formats query parameters for URL + * @private + * @param {Object} params - Query parameters + * @returns {string} - Formatted query string + */ + #formatQueryParams(params) { + return Object.entries(params) + .filter(([_, value]) => value !== undefined) + .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) + .join('&'); + } + + /** + * Authenticates with the Umami API + * @returns {Promise} Authentication response + * @throws {Error} If authentication fails + */ + async authenticate() { + const response = await fetch(`${this.baseUrl}/api/auth/login`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + username: this.username, + password: this.password, + }), + }); + + if (response.status === 401) { + throw new Error('Authentication failed: Incorrect username or password'); + } + + if (!response.ok) { + throw new Error(`Authentication failed: ${response.statusText}`); + } + + const data = await response.json(); + console.log(data) + this.token = data.token; + this.tokenExpiry = Date.now() + (24 * 60 * 60 * 1000); // Set expiry to 24 hours from now + return data; + } + + /** + * Verifies the current authentication token + * @returns {Promise} User information if token is valid + */ + async verifyToken() { + return this.#makeAuthenticatedRequest('/api/auth/verify'); + } + + /** + * Creates a new user. + * @param {Object} params - Parameters for creating a user. + * @param {string} params.username - The user's username. + * @param {string} params.password - The user's password. + * @param {string} params.role - The user's role, either 'admin' or 'user'. + * @returns {Promise<{ id: string, username: string, role: string, createdAt: string }>} Created user details. + */ + async createUser(params) { + return this.#makeAuthenticatedRequest(`/api/users`, { + method: 'POST', + body: JSON.stringify(params), + }); + } + + /** + * Returns all users. Admin access is required. + * @returns {Promise>} List of users. + */ + async getUsers() { + return this.#makeAuthenticatedRequest(`/api/admin/users`); + } + + /** + * Gets details of a specific user by ID. + * @param {string} userId - The ID of the user. + * @returns {Promise<{ id: string, username: string, role: string }>} User details. + */ + async getUser(userId) { + return this.#makeAuthenticatedRequest(`/api/users/${userId}`); + } + + /** + * Updates details of a user. + * @param {string} userId - The ID of the user. + * @param {Object} params - Update parameters. + * @param {string} [params.username] - The user's new username (optional). + * @param {string} [params.password] - The user's new password (optional). + * @param {string} [params.role] - The user's role, either 'admin' or 'user' (optional). + * @returns {Promise<{ id: string, username: string, role: string, createdAt: string }>} Updated user details. + */ + async updateUser(userId, params) { + return this.#makeAuthenticatedRequest(`/api/users/${userId}`, { + method: 'POST', + body: JSON.stringify(params), + }); + } + + /** + * Deletes a user. + * @param {string} userId - The ID of the user. + * @returns {Promise} Confirmation message. + */ + async deleteUser(userId) { + return this.#makeAuthenticatedRequest(`/api/users/${userId}`, { + method: 'DELETE', + }); + } + + + /** + * Gets all websites that belong to a user. + * @param {string} userId - The ID of the user. + * @param {Object} [params] - Query parameters. + * @param {string} [params.query] - Search text (optional). + * @param {number} [params.page=1] - Page number (optional). + * @param {number} [params.pageSize] - Number of results per page (optional). + * @param {string} [params.orderBy='name'] - Order by column name (optional). + * @returns {Promise>} List of websites belonging to the user. + */ + async getUserWebsites(userId, params = {}) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/users/${userId}/websites?${queryString}`); + } + + /** + * Gets all teams that belong to a user. + * @param {string} userId - The ID of the user. + * @param {Object} [params] - Query parameters. + * @param {string} [params.query] - Search text (optional). + * @param {number} [params.page=1] - Page number (optional). + * @param {number} [params.pageSize] - Number of results per page (optional). + * @param {string} [params.orderBy='name'] - Order by column name (optional). + * @returns {Promise>} List of teams belonging to the user. + */ + async getUserTeams(userId, params = {}) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/users/${userId}/teams?${queryString}`); + } + + /** + * Creates a new team. + * @param {Object} params - Parameters for creating a team. + * @param {string} params.name - The team's name. + * @returns {Promise<{ accessCode: string, createdAt: string, id: string, name: string, updatedAt: string | null }>} Created team details. + */ + async createTeam(params) { + return this.#makeAuthenticatedRequest(`/api/teams`, { + method: 'POST', + body: JSON.stringify(params), + }); + } + + + /** + * Returns all teams. + * @param {Object} params - Query parameters. + * @param {string} [params.query] - Search text (optional). + * @param {number} [params.page=1] - Page number (optional). + * @param {number} [params.pageSize] - Number of results per page (optional). + * @param {string} [params.orderBy='name'] - Order by column name (optional). + * @returns {Promise} List of all teams with team user information. + */ + async getTeams(params = {}) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/teams?${queryString}`); + } + + /** + * Joins a team using an access code. + * @param {Object} params - Parameters for joining a team. + * @param {string} params.accessCode - The team's access code. + * @returns {Promise} Joined team details. + */ + async joinTeam(params) { + return this.#makeAuthenticatedRequest(`/api/teams/join`, { + method: 'POST', + body: JSON.stringify(params), + }); + } + + /** + * Gets details of a specific team. + * @param {string} teamId - The ID of the team. + * @returns {Promise} Team details. + */ + async getTeam(teamId) { + return this.#makeAuthenticatedRequest(`/api/teams/${teamId}`); + } + + /** + * Updates team details. + * @param {string} teamId - The ID of the team. + * @param {Object} params - Update parameters. + * @param {string} [params.name] - The team's name (optional). + * @param {string} [params.accessCode] - The team's access code (optional). + * @returns {Promise} Updated team details. + */ + async updateTeam(teamId, params) { + return this.#makeAuthenticatedRequest(`/api/teams/${teamId}`, { + method: 'POST', + body: JSON.stringify(params), + }); + } + + /** + * Deletes a team. + * @param {string} teamId - The ID of the team. + * @returns {Promise} Confirmation message. + */ + async deleteTeam(teamId) { + return this.#makeAuthenticatedRequest(`/api/teams/${teamId}`, { + method: 'DELETE', + }); + } + + /** + * Gets all users that belong to a team. + * @param {string} teamId - The ID of the team. + * @param {Object} [params] - Query parameters. + * @param {string} [params.query] - Search text (optional). + * @param {number} [params.page=1] - Page number (optional). + * @param {number} [params.pageSize] - Number of results per page (optional). + * @param {string} [params.orderBy='name'] - Order by column name (optional). + * @returns {Promise} List of team users. + */ + async getTeamUsers(teamId, params = {}) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/teams/${teamId}/users?${queryString}`); + } + + /** + * Adds a user to a team. + * @param {string} teamId - The ID of the team. + * @param {Object} params - Parameters for adding a user to the team. + * @param {string} params.userId - The user's ID. + * @param {string} params.role - The role to assign (e.g., 'member' or 'view-only'). + * @returns {Promise} Added team user details. + */ + async addUserToTeam(teamId, params) { + return this.#makeAuthenticatedRequest(`/api/teams/${teamId}/users`, { + method: 'POST', + body: JSON.stringify(params), + }); + } + + /** + * Gets details of a user in a team. + * @param {string} teamId - The ID of the team. + * @param {string} userId - The user's ID. + * @returns {Promise} Team user details. + */ + async getTeamUser(teamId, userId) { + return this.#makeAuthenticatedRequest(`/api/teams/${teamId}/users/${userId}`); + } + + /** + * Updates a user's role in a team. + * @param {string} teamId - The ID of the team. + * @param {string} userId - The user's ID. + * @param {Object} params - Parameters for updating user role. + * @param {string} params.role - The new role (e.g., 'member' or 'view-only'). + * @returns {Promise} Confirmation message. + */ + async updateTeamUserRole(teamId, userId, params) { + return this.#makeAuthenticatedRequest(`/api/teams/${teamId}/users/${userId}`, { + method: 'POST', + body: JSON.stringify(params), + }); + } + + /** + * Removes a user from a team. + * @param {string} teamId - The ID of the team. + * @param {string} userId - The user's ID. + * @returns {Promise} Confirmation message. + */ + async removeUserFromTeam(teamId, userId) { + return this.#makeAuthenticatedRequest(`/api/teams/${teamId}/users/${userId}`, { + method: 'DELETE', + }); + } + + /** + * Returns all tracked websites. + * @param {Object} [params] - Query parameters. + * @param {string} [params.query] - Search text (optional). + * @param {number} [params.page=1] - Page number (optional). + * @param {number} [params.pageSize] - Number of results per page (optional). + * @param {string} [params.orderBy='name'] - Order by column name (optional). + * @returns {Promise>} List of websites. + */ + async getWebsites(params = {}) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites?${queryString}`); + } + + /** + * Creates a new website. + * @param {Object} params - Website parameters. + * @param {string} params.domain - The full domain of the tracked website. + * @param {string} params.name - The name of the website in Umami. + * @param {string} [params.shareId] - A unique string to enable a share URL (optional). + * @param {string} [params.teamId] - The ID of the team the website will be created under (optional). + * @returns {Promise<{ id: number, websiteUuid: string, websiteId: number, name: string, domain: string, shareId: string | null, createdAt: string }>} Details of the created website. + */ + async createWebsite(params) { + return this.#makeAuthenticatedRequest(`/api/websites`, { + method: 'POST', + body: JSON.stringify(params), + }); + } + + /** + * Gets details of a specific website by ID. + * @param {string} websiteId - The ID of the website. + * @returns {Promise<{ id: string, name: string, domain: string, shareId: string | null, resetAt: string | null, userId: string, createdAt: string, updatedAt: string | null, deletedAt: string | null }>} Website details. + */ + async getWebsite(websiteId) { + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}`); + } + + /** + * Updates details of a website. + * @param {string} websiteId - The ID of the website. + * @param {Object} params - Update parameters. + * @param {string} [params.name] - The name of the website in Umami (optional). + * @param {string} [params.domain] - The full domain of the tracked website (optional). + * @param {string} [params.shareId] - A unique string to enable a share URL or null to unshare (optional). + * @returns {Promise<{ id: string, name: string, domain: string, shareId: string | null, resetAt: string | null, userId: string, createdAt: string, updatedAt: string | null, deletedAt: string | null }>} Updated website details. + */ + async updateWebsite(websiteId, params) { + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}`, { + method: 'POST', + body: JSON.stringify(params), + }); + } + + /** + * Deletes a website. + * @param {string} websiteId - The ID of the website. + * @returns {Promise} Confirmation message. + */ + async deleteWebsite(websiteId) { + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}`, { + method: 'DELETE', + }); + } + + /** + * Resets a website by removing all data related to it. + * @param {string} websiteId - The ID of the website. + * @returns {Promise} Confirmation message. + */ + async resetWebsite(websiteId) { + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/reset`, { + method: 'POST', + }); + } + + /** + * Gets all websites that belong to a team. + * @param {string} teamId - The ID of the team. + * @param {Object} [params] - Query parameters. + * @param {string} [params.query] - Search text (optional). + * @param {number} [params.page=1] - Page number (optional). + * @param {number} [params.pageSize] - Number of results per page (optional). + * @param {string} [params.orderBy='name'] - Order by column name (optional). + * @returns {Promise} List of team websites. + */ + async getTeamWebsites(teamId, params = {}) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/teams/${teamId}/websites?${queryString}`); + } + + /** + * Gets website session details within a given time range + * @param {string} websiteId - Website ID + * @param {Object} params - Query parameters + * @param {number} params.startAt - Timestamp (in ms) of starting date + * @param {number} params.endAt - Timestamp (in ms) of end date + * @param {string} [params.query] - Search text + * @param {number} [params.page=1] - Page number + * @param {number} [params.pageSize] - Results per page + * @param {string} [params.orderBy] - Order by column name + * @returns {Promise<{ data: Session[], count: number, page: number, pageSize: number }>} + */ + async getSessions(websiteId, params) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/sessions?${queryString}`); + } + + /** + * Gets summarized website session statistics + * @param {string} websiteId - Website ID + * @param {Object} params - Query parameters + * @param {number} params.startAt - Timestamp (in ms) of starting date + * @param {number} params.endAt - Timestamp (in ms) of end date + * @param {string} [params.url] - Filter by URL + * @param {string} [params.referrer] - Filter by referrer + * @param {string} [params.title] - Filter by page title + * @param {string} [params.query] - Filter by query + * @param {string} [params.event] - Filter by event name + * @param {string} [params.host] - Filter by hostname + * @param {string} [params.os] - Filter by operating system + * @param {string} [params.browser] - Filter by browser + * @param {string} [params.device] - Filter by device + * @param {string} [params.country] - Filter by country + * @param {string} [params.region] - Filter by region + * @param {string} [params.city] - Filter by city + * @returns {Promise} + */ + async getSessionStats(websiteId, params) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/sessions/stats?${queryString}`); + } + + + /** + * Gets session details for an individual session + * @param {string} websiteId - Website ID + * @param {string} sessionId - Session ID + * @returns {Promise} + */ + async getSession(websiteId, sessionId) { + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/sessions/${sessionId}`); + } + + + /** + * Gets session activity for an individual session + * @param {string} websiteId - Website ID + * @param {string} sessionId - Session ID + * @param {Object} params - Query parameters + * @param {number} params.startAt - Timestamp (in ms) of starting date + * @param {number} params.endAt - Timestamp (in ms) of end date + * @returns {Promise} + */ + async getSessionActivity(websiteId, sessionId, params) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/sessions/${sessionId}/activity?${queryString}`); + } + + /** + * Gets session properties for an individual session + * @param {string} websiteId - Website ID + * @param {string} sessionId - Session ID + * @returns {Promise} + */ + async getSessionProperties(websiteId, sessionId) { + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/sessions/${sessionId}/properties`); + } + + /** + * Gets session data counts by property name + * @param {string} websiteId - Website ID + * @param {Object} params - Query parameters + * @param {number} params.startAt - Timestamp (in ms) of starting date + * @param {number} params.endAt - Timestamp (in ms) of end date + * @returns {Promise} + */ + async getSessionDataProperties(websiteId, params) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/session-data/properties?${queryString}`); + } + + /** + * Gets session data counts for a given property + * @param {string} websiteId - Website ID + * @param {Object} params - Query parameters + * @param {number} params.startAt - Timestamp (in ms) of starting date + * @param {number} params.endAt - Timestamp (in ms) of end date + * @param {string} params.propertyName - Property name + * @returns {Promise} + */ + async getSessionDataValues(websiteId, params) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/session-data/values?${queryString}`); + } + + + /** + * Gets all tracked websites + * @param {Object} [params] - Query parameters + * @param {string} [params.query] - Search text + * @param {number} [params.page=1] - Page number + * @param {number} [params.pageSize] - Results per page + * @param {string} [params.orderBy='name'] - Order by column name + * @returns {Promise} List of websites + */ + async getWebsites(params = {}) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites?${queryString}`); + } + + /** + * Creates a new website + * @param {Object} params - Website parameters + * @param {string} params.domain - The full domain of the tracked website + * @param {string} params.name - The name of the website in Umami + * @param {string} [params.shareId] - A unique string to enable a share url + * @param {string} [params.teamId] - The ID of the team the website will be created under + * @returns {Promise} Created website details + */ + async createWebsite(params) { + return this.#makeAuthenticatedRequest('/api/websites', { + method: 'POST', + body: JSON.stringify(params), + }); + } + + /** + * Gets a website by ID + * @param {string} websiteId - Website ID + * @returns {Promise} Website details + */ + async getWebsite(websiteId) { + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}`); + } + + /** + * Updates a website + * @param {string} websiteId - Website ID + * @param {Object} params - Update parameters + * @param {string} [params.name] - The name of the website in Umami + * @param {string} [params.domain] - The full domain of the tracked website + * @param {string} [params.shareId] - A unique string to enable a share url + * @returns {Promise} Updated website details + */ + async updateWebsite(websiteId, params) { + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}`, { + method: 'POST', + body: JSON.stringify(params), + }); + } + + /** + * Deletes a website + * @param {string} websiteId - Website ID + * @returns {Promise} Confirmation message + */ + async deleteWebsite(websiteId) { + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}`, { + method: 'DELETE', + }); + } + + /** + * Resets a website by removing all data + * @param {string} websiteId - Website ID + * @returns {Promise} Confirmation message + */ + async resetWebsite(websiteId) { + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/reset`, { + method: 'POST', + }); + } + + /** + * Gets the number of active users on a website + * @param {string} websiteId - Website ID + * @returns {Promise} Active users count + */ + async getActiveUsers(websiteId) { + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/active`); + } + + /** + * Gets events within a given time range + * @param {string} websiteId - Website ID + * @param {Object} params - Query parameters + * @param {number} params.startAt - Timestamp (in ms) of starting date + * @param {number} params.endAt - Timestamp (in ms) of end date + * @param {string} params.unit - Time unit (year | month | hour | day) + * @param {string} params.timezone - Timezone (ex. America/Los_Angeles) + * @param {string} [params.url] - Filter by URL + * @param {string} [params.referrer] - Filter by referrer + * @param {string} [params.title] - Filter by page title + * @param {string} [params.host] - Filter by hostname + * @param {string} [params.os] - Filter by operating system + * @param {string} [params.browser] - Filter by browser + * @param {string} [params.device] - Filter by device + * @param {string} [params.country] - Filter by country + * @param {string} [params.region] - Filter by region + * @param {string} [params.city] - Filter by city + * @returns {Promise} Event series data + */ + async getEventsSeries(websiteId, params) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/events/series?${queryString}`); + } + + /** + * Gets website event details within a given time range. + * @param {string} websiteId - The ID of the website. + * @param {Object} params - Query parameters. + * @param {number} params.startAt - Timestamp (in ms) of the starting date. + * @param {number} params.endAt - Timestamp (in ms) of the end date. + * @param {string} [params.query] - Search text (optional). + * @param {number} [params.page=1] - Page number (optional). + * @param {number} [params.pageSize] - Number of results to return (optional). + * @param {string} [params.orderBy] - Order by column name (optional). + * @returns {Promise<{ data: Array, count: number, page: number, pageSize: number }>} Event data response. + */ + async getWebsiteEvents(websiteId, params) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/events?${queryString}`); + } + + /** + * Gets summarized website statistics. + * @param {string} websiteId - The ID of the website. + * @param {Object} params - Query parameters. + * @param {number} params.startAt - Timestamp (in ms) of starting date. + * @param {number} params.endAt - Timestamp (in ms) of end date. + * @param {string} [params.url] - Filter by URL (optional). + * @param {string} [params.referrer] - Filter by referrer (optional). + * @param {string} [params.title] - Filter by page title (optional). + * @param {string} [params.query] - Filter by query (optional). + * @param {string} [params.event] - Filter by event name (optional). + * @param {string} [params.host] - Filter by hostname (optional). + * @param {string} [params.os] - Filter by operating system (optional). + * @param {string} [params.browser] - Filter by browser (optional). + * @param {string} [params.device] - Filter by device (e.g., Mobile, optional). + * @param {string} [params.country] - Filter by country (optional). + * @param {string} [params.region] - Filter by region/state/province (optional). + * @param {string} [params.city] - Filter by city (optional). + * @returns {Promise<{ pageviews: { value: number, prev: number }, visitors: { value: number, prev: number }, visits: { value: number, prev: number }, bounces: { value: number, prev: number }, totaltime: { value: number, prev: number } }>} Summarized website statistics. + */ + async getWebsiteStats(websiteId, params) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/stats?${queryString}`); + } + + + /** + * Gets event data names, properties, and counts. + * @param {string} websiteId - The ID of the website. + * @param {Object} params - Query parameters. + * @param {number} params.startAt - Timestamp (in ms) of the starting date. + * @param {number} params.endAt - Timestamp (in ms) of the end date. + * @param {string} [params.event] - Event name filter (optional). + * @returns {Promise>} Event data summary. + */ + async getEventDataEvents(websiteId, params) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/event-data/events?${queryString}`); + } + + /** + * Gets event data property and value counts within a given time range. + * @param {string} websiteId - The ID of the website. + * @param {Object} params - Query parameters. + * @param {number} params.startAt - Timestamp (in ms) of the starting date. + * @param {number} params.endAt - Timestamp (in ms) of the end date. + * @returns {Promise>} Event data fields. + */ + async getEventDataFields(websiteId, params) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/event-data/fields?${queryString}`); + } + + /** + * Gets event data counts for a given event and property. + * @param {string} websiteId - The ID of the website. + * @param {Object} params - Query parameters. + * @param {number} params.startAt - Timestamp (in ms) of the starting date. + * @param {number} params.endAt - Timestamp (in ms) of the end date. + * @param {string} params.eventName - The name of the event. + * @param {string} params.propertyName - The property name. + * @returns {Promise>} Event data values. + */ + async getEventDataValues(websiteId, params) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/event-data/values?${queryString}`); + } + + + /** + * Gets summarized website events, fields, and records within a given time range. + * @param {string} websiteId - The ID of the website. + * @param {Object} params - Query parameters. + * @param {number} params.startAt - Timestamp (in ms) of the starting date. + * @param {number} params.endAt - Timestamp (in ms) of the end date. + * @returns {Promise>} Summary of events, fields, and records. + */ + async getEventDataStats(websiteId, params) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/event-data/stats?${queryString}`); + } + + + + + + /** + * Gets pageviews within a given time range + * @param {string} websiteId - Website ID + * @param {Object} params - Query parameters + * @param {number} params.startAt - Timestamp (in ms) of starting date + * @param {number} params.endAt - Timestamp (in ms) of end date + * @param {string} params.unit - Time unit (year | month | hour | day) + * @param {string} params.timezone - Timezone (ex. America/Los_Angeles) + * @param {string} [params.url] - Filter by URL + * @param {string} [params.referrer] - Filter by referrer + * @param {string} [params.title] - Filter by page title + * @param {string} [params.host] - Filter by hostname + * @param {string} [params.os] - Filter by operating system + * @param {string} [params.browser] - Filter by browser + * @param {string} [params.device] - Filter by device + * @param {string} [params.country] - Filter by country + * @param {string} [params.region] - Filter by region + * @param {string} [params.city] - Filter by city + * @returns {Promise} Pageview data + */ + async getPageviews(websiteId, params) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/pageviews?${queryString}`); + } + + /** + * Gets metrics for a given time range + * @param {string} websiteId - Website ID + * @param {Object} params - Query parameters + * @param {number} params.startAt - Timestamp (in ms) of starting date + * @param {number} params.endAt - Timestamp (in ms) of end date + * @param {string} params.type - Metrics type (url | referrer | browser | os | device | country | event) + * @param {string} [params.url] - Filter by URL + * @param {string} [params.referrer] - Filter by referrer + * @param {string} [params.title] - Filter by page title + * @param {string} [params.query] - Filter by query + * @param {string} [params.host] - Filter by hostname + * @param {string} [params.os] - Filter by operating system + * @param {string} [params.browser] - Filter by browser + * @param {string} [params.device] - Filter by device + * @param {string} [params.country] - Filter by country + * @param {string} [params.region] - Filter by region + * @param {string} [params.city] - Filter by city + * @param {string} [params.language] - Filter by language + * @param {string} [params.event] - Filter by event + * @param {number} [params.limit=500] - Number of events returned + * @returns {Promise} Metrics data + */ + async getMetrics(websiteId, params) { + const queryString = this.#formatQueryParams(params); + return this.#makeAuthenticatedRequest(`/api/websites/${websiteId}/metrics?${queryString}`); + } + + /** + * Sends an event to Umami + * @param {EventPayload} payload - Event data + * @returns {Promise} + */ + async sendEvent(payload) { + // No authentication needed for /api/send + const response = await fetch(`${this.baseUrl}/api/send`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'User-Agent': navigator.userAgent, // Required for event registration + }, + body: JSON.stringify({ + payload: { + hostname: payload.hostname || window.location.hostname, + language: payload.language || navigator.language, + referrer: payload.referrer || document.referrer, + screen: payload.screen || `${window.screen.width}x${window.screen.height}`, + title: payload.title || document.title, + url: payload.url || window.location.pathname, + website: payload.website, + name: payload.name, + data: payload.data, + }, + type: 'event', + }), + }); + + if (!response.ok) { + throw new Error(`Failed to send event: ${response.statusText}`); + } + } + +} + +export default UmamiClient; \ No newline at end of file