Full Code of umami-software/umami for AI

master 0a838649b773 cached
954 files
5.4 MB
1.5M tokens
1364 symbols
1 requests
Download .txt
Showing preview only (5,876K chars total). Download the full file or copy to clipboard to get everything.
Repository: umami-software/umami
Branch: master
Commit: 0a838649b773
Files: 954
Total size: 5.4 MB

Directory structure:
gitextract_u9mmz_t0/

├── .dockerignore
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── 1.bug_report.yml
│   │   ├── 2.feature_request.yml
│   │   └── config.yml
│   └── workflows/
│       ├── cd-cloud.yml
│       ├── cd.yml
│       ├── ci.yml
│       └── stale-issues.yml
├── .gitignore
├── .husky/
│   └── pre-commit
├── .stylelintrc.json
├── Dockerfile
├── LICENSE
├── README.md
├── app.json
├── biome.json
├── cypress/
│   ├── docker-compose.yml
│   ├── e2e/
│   │   ├── api-team.cy.ts
│   │   ├── api-user.cy.ts
│   │   ├── api-website.cy.ts
│   │   ├── login.cy.ts
│   │   ├── user.cy.ts
│   │   └── website.cy.ts
│   ├── fixtures/
│   │   ├── teams.json
│   │   ├── users.json
│   │   └── websites.json
│   ├── support/
│   │   ├── e2e.ts
│   │   └── index.d.ts
│   └── tsconfig.json
├── cypress.config.ts
├── db/
│   ├── clickhouse/
│   │   ├── migrations/
│   │   │   ├── 01_edit_keys.sql
│   │   │   ├── 02_add_visit_id.sql
│   │   │   ├── 03_session_data.sql
│   │   │   ├── 04_add_tag.sql
│   │   │   ├── 05_add_utm_clid.sql
│   │   │   ├── 06_update_subdivision.sql
│   │   │   ├── 07_add_distinct_id.sql
│   │   │   └── 08_update_hostname_view.sql
│   │   └── schema.sql
│   └── postgresql/
│       └── data-migrations/
│           ├── convert-utm-clid-columns.sql
│           └── populate-revenue-table.sql
├── docker/
│   └── middleware.ts
├── docker-compose.yml
├── jest.config.ts
├── netlify.toml
├── next-env.d.ts
├── next.config.ts
├── package.components.json
├── package.json
├── pnpm-workspace.yaml
├── podman/
│   ├── README.md
│   ├── env.sample
│   ├── install-systemd-user-service
│   ├── podman-compose.yml
│   └── umami.service
├── postcss.config.js
├── prisma/
│   ├── migrations/
│   │   ├── 01_init/
│   │   │   └── migration.sql
│   │   ├── 02_report_schema_session_data/
│   │   │   └── migration.sql
│   │   ├── 03_metric_performance_index/
│   │   │   └── migration.sql
│   │   ├── 04_team_redesign/
│   │   │   └── migration.sql
│   │   ├── 05_add_visit_id/
│   │   │   └── migration.sql
│   │   ├── 06_session_data/
│   │   │   └── migration.sql
│   │   ├── 07_add_tag/
│   │   │   └── migration.sql
│   │   ├── 08_add_utm_clid/
│   │   │   └── migration.sql
│   │   ├── 09_update_hostname_region/
│   │   │   └── migration.sql
│   │   ├── 10_add_distinct_id/
│   │   │   └── migration.sql
│   │   ├── 11_add_segment/
│   │   │   └── migration.sql
│   │   ├── 12_update_report_parameter/
│   │   │   └── migration.sql
│   │   ├── 13_add_revenue/
│   │   │   └── migration.sql
│   │   ├── 14_add_link_and_pixel/
│   │   │   └── migration.sql
│   │   └── migration_lock.toml
│   └── schema.prisma
├── prisma.config.ts
├── public/
│   ├── browserconfig.xml
│   ├── datamaps.world.json
│   ├── intl/
│   │   ├── country/
│   │   │   ├── am-ET.json
│   │   │   ├── ar-SA.json
│   │   │   ├── be-BY.json
│   │   │   ├── bg-BG.json
│   │   │   ├── bn-BD.json
│   │   │   ├── bs-BA.json
│   │   │   ├── ca-ES.json
│   │   │   ├── cs-CZ.json
│   │   │   ├── da-DK.json
│   │   │   ├── de-CH.json
│   │   │   ├── de-DE.json
│   │   │   ├── el-GR.json
│   │   │   ├── en-GB.json
│   │   │   ├── en-US.json
│   │   │   ├── es-ES.json
│   │   │   ├── es-MX.json
│   │   │   ├── fa-IR.json
│   │   │   ├── fi-FI.json
│   │   │   ├── fo-FO.json
│   │   │   ├── fr-FR.json
│   │   │   ├── he-IL.json
│   │   │   ├── hi-IN.json
│   │   │   ├── hr-HR.json
│   │   │   ├── hu-HU.json
│   │   │   ├── id-ID.json
│   │   │   ├── it-IT.json
│   │   │   ├── ja-JP.json
│   │   │   ├── km-KH.json
│   │   │   ├── ko-KR.json
│   │   │   ├── lt-LT.json
│   │   │   ├── mn-MN.json
│   │   │   ├── ms-MY.json
│   │   │   ├── my-MM.json
│   │   │   ├── nb-NO.json
│   │   │   ├── nl-NL.json
│   │   │   ├── pl-PL.json
│   │   │   ├── pt-BR.json
│   │   │   ├── pt-PT.json
│   │   │   ├── ro-RO.json
│   │   │   ├── ru-RU.json
│   │   │   ├── si-LK.json
│   │   │   ├── sk-SK.json
│   │   │   ├── sl-SI.json
│   │   │   ├── sv-SE.json
│   │   │   ├── ta-IN.json
│   │   │   ├── th-TH.json
│   │   │   ├── tr-TR.json
│   │   │   ├── uk-UA.json
│   │   │   ├── ur-PK.json
│   │   │   ├── uz-UZ.json
│   │   │   ├── vi-VN.json
│   │   │   ├── zh-CN.json
│   │   │   └── zh-TW.json
│   │   ├── language/
│   │   │   ├── am-ET.json
│   │   │   ├── ar-SA.json
│   │   │   ├── be-BY.json
│   │   │   ├── bg-BG.json
│   │   │   ├── bn-BD.json
│   │   │   ├── bs-BA.json
│   │   │   ├── ca-ES.json
│   │   │   ├── cs-CZ.json
│   │   │   ├── da-DK.json
│   │   │   ├── de-CH.json
│   │   │   ├── de-DE.json
│   │   │   ├── el-GR.json
│   │   │   ├── en-GB.json
│   │   │   ├── en-US.json
│   │   │   ├── es-ES.json
│   │   │   ├── es-MX.json
│   │   │   ├── fa-IR.json
│   │   │   ├── fi-FI.json
│   │   │   ├── fo-FO.json
│   │   │   ├── fr-FR.json
│   │   │   ├── he-IL.json
│   │   │   ├── hi-IN.json
│   │   │   ├── hr-HR.json
│   │   │   ├── hu-HU.json
│   │   │   ├── id-ID.json
│   │   │   ├── it-IT.json
│   │   │   ├── ja-JP.json
│   │   │   ├── km-KH.json
│   │   │   ├── ko-KR.json
│   │   │   ├── lt-LT.json
│   │   │   ├── mn-MN.json
│   │   │   ├── ms-MY.json
│   │   │   ├── my-MM.json
│   │   │   ├── nb-NO.json
│   │   │   ├── nl-NL.json
│   │   │   ├── pl-PL.json
│   │   │   ├── pt-BR.json
│   │   │   ├── pt-PT.json
│   │   │   ├── ro-RO.json
│   │   │   ├── ru-RU.json
│   │   │   ├── si-LK.json
│   │   │   ├── sk-SK.json
│   │   │   ├── sl-SI.json
│   │   │   ├── sv-SE.json
│   │   │   ├── ta-IN.json
│   │   │   ├── th-TH.json
│   │   │   ├── tr-TR.json
│   │   │   ├── uk-UA.json
│   │   │   ├── ur-PK.json
│   │   │   ├── uz-UZ.json
│   │   │   ├── vi-VN.json
│   │   │   ├── zh-CN.json
│   │   │   └── zh-TW.json
│   │   └── messages/
│   │       ├── am-ET.json
│   │       ├── ar-SA.json
│   │       ├── be-BY.json
│   │       ├── bg-BG.json
│   │       ├── bn-BD.json
│   │       ├── bs-BA.json
│   │       ├── ca-ES.json
│   │       ├── cs-CZ.json
│   │       ├── da-DK.json
│   │       ├── de-CH.json
│   │       ├── de-DE.json
│   │       ├── el-GR.json
│   │       ├── en-GB.json
│   │       ├── en-US.json
│   │       ├── es-ES.json
│   │       ├── es-MX.json
│   │       ├── fa-IR.json
│   │       ├── fi-FI.json
│   │       ├── fo-FO.json
│   │       ├── fr-FR.json
│   │       ├── ga-ES.json
│   │       ├── he-IL.json
│   │       ├── hi-IN.json
│   │       ├── hr-HR.json
│   │       ├── hu-HU.json
│   │       ├── id-ID.json
│   │       ├── it-IT.json
│   │       ├── ja-JP.json
│   │       ├── km-KH.json
│   │       ├── ko-KR.json
│   │       ├── lt-LT.json
│   │       ├── mn-MN.json
│   │       ├── ms-MY.json
│   │       ├── my-MM.json
│   │       ├── nb-NO.json
│   │       ├── nl-NL.json
│   │       ├── pl-PL.json
│   │       ├── pt-BR.json
│   │       ├── pt-PT.json
│   │       ├── ro-RO.json
│   │       ├── ru-RU.json
│   │       ├── si-LK.json
│   │       ├── sk-SK.json
│   │       ├── sl-SI.json
│   │       ├── sv-SE.json
│   │       ├── ta-IN.json
│   │       ├── th-TH.json
│   │       ├── tr-TR.json
│   │       ├── uk-UA.json
│   │       ├── ur-PK.json
│   │       ├── uz-UZ.json
│   │       ├── vi-VN.json
│   │       ├── zh-CN.json
│   │       └── zh-TW.json
│   ├── iso-3166-2.json
│   ├── robots.txt
│   └── site.webmanifest
├── rollup.tracker.config.js
├── scripts/
│   ├── build-geo.js
│   ├── build-prisma-client.js
│   ├── check-db.js
│   ├── check-env.js
│   ├── download-country-names.js
│   ├── download-language-names.js
│   ├── format-lang.js
│   ├── merge-messages.js
│   ├── postbuild.js
│   ├── seed/
│   │   ├── distributions/
│   │   │   ├── devices.ts
│   │   │   ├── geographic.ts
│   │   │   ├── referrers.ts
│   │   │   └── temporal.ts
│   │   ├── generators/
│   │   │   ├── events.ts
│   │   │   ├── revenue.ts
│   │   │   └── sessions.ts
│   │   ├── index.ts
│   │   ├── sites/
│   │   │   ├── blog.ts
│   │   │   └── saas.ts
│   │   └── utils.ts
│   ├── seed-data.ts
│   ├── start-env.js
│   ├── telemetry.js
│   └── update-tracker.js
├── src/
│   ├── app/
│   │   ├── (collect)/
│   │   │   ├── p/
│   │   │   │   └── [slug]/
│   │   │   │       └── route.ts
│   │   │   └── q/
│   │   │       └── [slug]/
│   │   │           └── route.ts
│   │   ├── (main)/
│   │   │   ├── App.tsx
│   │   │   ├── MobileNav.tsx
│   │   │   ├── SideNav.tsx
│   │   │   ├── TopNav.tsx
│   │   │   ├── UpdateNotice.tsx
│   │   │   ├── admin/
│   │   │   │   ├── AdminLayout.tsx
│   │   │   │   ├── AdminNav.tsx
│   │   │   │   ├── layout.tsx
│   │   │   │   ├── teams/
│   │   │   │   │   ├── AdminTeamsDataTable.tsx
│   │   │   │   │   ├── AdminTeamsPage.tsx
│   │   │   │   │   ├── AdminTeamsTable.tsx
│   │   │   │   │   ├── [teamId]/
│   │   │   │   │   │   ├── AdminTeamPage.tsx
│   │   │   │   │   │   └── page.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   ├── users/
│   │   │   │   │   ├── UserAddButton.tsx
│   │   │   │   │   ├── UserAddForm.tsx
│   │   │   │   │   ├── UserDeleteButton.tsx
│   │   │   │   │   ├── UserDeleteForm.tsx
│   │   │   │   │   ├── UsersDataTable.tsx
│   │   │   │   │   ├── UsersPage.tsx
│   │   │   │   │   ├── UsersTable.tsx
│   │   │   │   │   ├── [userId]/
│   │   │   │   │   │   ├── UserEditForm.tsx
│   │   │   │   │   │   ├── UserHeader.tsx
│   │   │   │   │   │   ├── UserPage.tsx
│   │   │   │   │   │   ├── UserProvider.tsx
│   │   │   │   │   │   ├── UserSettings.tsx
│   │   │   │   │   │   ├── UserWebsites.tsx
│   │   │   │   │   │   └── page.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   └── websites/
│   │   │   │       ├── AdminWebsitesDataTable.tsx
│   │   │   │       ├── AdminWebsitesPage.tsx
│   │   │   │       ├── AdminWebsitesTable.tsx
│   │   │   │       ├── [websiteId]/
│   │   │   │       │   ├── AdminWebsitePage.tsx
│   │   │   │       │   └── page.tsx
│   │   │   │       └── page.tsx
│   │   │   ├── boards/
│   │   │   │   ├── BoardAddButton.tsx
│   │   │   │   ├── BoardAddForm.tsx
│   │   │   │   ├── BoardsPage.tsx
│   │   │   │   ├── [boardId]/
│   │   │   │   │   ├── Board.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   └── page.tsx
│   │   │   ├── console/
│   │   │   │   └── [websiteId]/
│   │   │   │       ├── TestConsolePage.tsx
│   │   │   │       └── page.tsx
│   │   │   ├── dashboard/
│   │   │   │   ├── DashboardPage.tsx
│   │   │   │   └── page.tsx
│   │   │   ├── layout.tsx
│   │   │   ├── links/
│   │   │   │   ├── LinkAddButton.tsx
│   │   │   │   ├── LinkDeleteButton.tsx
│   │   │   │   ├── LinkEditButton.tsx
│   │   │   │   ├── LinkEditForm.tsx
│   │   │   │   ├── LinkProvider.tsx
│   │   │   │   ├── LinksDataTable.tsx
│   │   │   │   ├── LinksPage.tsx
│   │   │   │   ├── LinksTable.tsx
│   │   │   │   ├── [linkId]/
│   │   │   │   │   ├── LinkControls.tsx
│   │   │   │   │   ├── LinkHeader.tsx
│   │   │   │   │   ├── LinkMetricsBar.tsx
│   │   │   │   │   ├── LinkPage.tsx
│   │   │   │   │   ├── LinkPanels.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   └── page.tsx
│   │   │   ├── pixels/
│   │   │   │   ├── PixelAddButton.tsx
│   │   │   │   ├── PixelDeleteButton.tsx
│   │   │   │   ├── PixelEditButton.tsx
│   │   │   │   ├── PixelEditForm.tsx
│   │   │   │   ├── PixelProvider.tsx
│   │   │   │   ├── PixelsDataTable.tsx
│   │   │   │   ├── PixelsPage.tsx
│   │   │   │   ├── PixelsTable.tsx
│   │   │   │   ├── [pixelId]/
│   │   │   │   │   ├── PixelControls.tsx
│   │   │   │   │   ├── PixelHeader.tsx
│   │   │   │   │   ├── PixelMetricsBar.tsx
│   │   │   │   │   ├── PixelPage.tsx
│   │   │   │   │   ├── PixelPanels.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   └── page.tsx
│   │   │   ├── settings/
│   │   │   │   ├── SettingsLayout.tsx
│   │   │   │   ├── SettingsNav.tsx
│   │   │   │   ├── layout.tsx
│   │   │   │   ├── preferences/
│   │   │   │   │   ├── DateRangeSetting.tsx
│   │   │   │   │   ├── LanguageSetting.tsx
│   │   │   │   │   ├── PreferenceSettings.tsx
│   │   │   │   │   ├── PreferencesPage.tsx
│   │   │   │   │   ├── ThemeSetting.tsx
│   │   │   │   │   ├── TimezoneSetting.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   ├── profile/
│   │   │   │   │   ├── PasswordChangeButton.tsx
│   │   │   │   │   ├── PasswordEditForm.tsx
│   │   │   │   │   ├── ProfileHeader.tsx
│   │   │   │   │   ├── ProfilePage.tsx
│   │   │   │   │   ├── ProfileSettings.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   ├── teams/
│   │   │   │   │   ├── TeamsSettingsPage.tsx
│   │   │   │   │   ├── [teamId]/
│   │   │   │   │   │   ├── TeamSettingsPage.tsx
│   │   │   │   │   │   └── page.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   └── websites/
│   │   │   │       ├── WebsitesSettingsPage.tsx
│   │   │   │       ├── [websiteId]/
│   │   │   │       │   ├── WebsiteSettingsPage.tsx
│   │   │   │       │   └── page.tsx
│   │   │   │       └── page.tsx
│   │   │   ├── teams/
│   │   │   │   ├── TeamAddForm.tsx
│   │   │   │   ├── TeamJoinForm.tsx
│   │   │   │   ├── TeamLeaveButton.tsx
│   │   │   │   ├── TeamLeaveForm.tsx
│   │   │   │   ├── TeamProvider.tsx
│   │   │   │   ├── TeamsAddButton.tsx
│   │   │   │   ├── TeamsDataTable.tsx
│   │   │   │   ├── TeamsHeader.tsx
│   │   │   │   ├── TeamsJoinButton.tsx
│   │   │   │   ├── TeamsPage.tsx
│   │   │   │   ├── TeamsTable.tsx
│   │   │   │   ├── [teamId]/
│   │   │   │   │   ├── TeamDeleteForm.tsx
│   │   │   │   │   ├── TeamEditForm.tsx
│   │   │   │   │   ├── TeamManage.tsx
│   │   │   │   │   ├── TeamMemberEditButton.tsx
│   │   │   │   │   ├── TeamMemberEditForm.tsx
│   │   │   │   │   ├── TeamMemberRemoveButton.tsx
│   │   │   │   │   ├── TeamMembersDataTable.tsx
│   │   │   │   │   ├── TeamMembersTable.tsx
│   │   │   │   │   ├── TeamSettings.tsx
│   │   │   │   │   ├── TeamWebsiteRemoveButton.tsx
│   │   │   │   │   ├── TeamWebsitesDataTable.tsx
│   │   │   │   │   └── TeamWebsitesTable.tsx
│   │   │   │   └── page.tsx
│   │   │   └── websites/
│   │   │       ├── WebsiteAddButton.tsx
│   │   │       ├── WebsiteAddForm.tsx
│   │   │       ├── WebsiteProvider.tsx
│   │   │       ├── WebsitesDataTable.tsx
│   │   │       ├── WebsitesHeader.tsx
│   │   │       ├── WebsitesPage.tsx
│   │   │       ├── WebsitesTable.tsx
│   │   │       ├── [websiteId]/
│   │   │       │   ├── (reports)/
│   │   │       │   │   ├── attribution/
│   │   │       │   │   │   ├── Attribution.tsx
│   │   │       │   │   │   ├── AttributionPage.tsx
│   │   │       │   │   │   └── page.tsx
│   │   │       │   │   ├── breakdown/
│   │   │       │   │   │   ├── Breakdown.tsx
│   │   │       │   │   │   ├── BreakdownPage.tsx
│   │   │       │   │   │   ├── FieldSelectForm.tsx
│   │   │       │   │   │   └── page.tsx
│   │   │       │   │   ├── funnels/
│   │   │       │   │   │   ├── Funnel.tsx
│   │   │       │   │   │   ├── FunnelAddButton.tsx
│   │   │       │   │   │   ├── FunnelEditForm.tsx
│   │   │       │   │   │   ├── FunnelsPage.tsx
│   │   │       │   │   │   └── page.tsx
│   │   │       │   │   ├── goals/
│   │   │       │   │   │   ├── Goal.tsx
│   │   │       │   │   │   ├── GoalAddButton.tsx
│   │   │       │   │   │   ├── GoalEditForm.tsx
│   │   │       │   │   │   ├── GoalsPage.tsx
│   │   │       │   │   │   └── page.tsx
│   │   │       │   │   ├── journeys/
│   │   │       │   │   │   ├── Journey.module.css
│   │   │       │   │   │   ├── Journey.tsx
│   │   │       │   │   │   ├── JourneysPage.tsx
│   │   │       │   │   │   └── page.tsx
│   │   │       │   │   ├── retention/
│   │   │       │   │   │   ├── Retention.tsx
│   │   │       │   │   │   ├── RetentionPage.tsx
│   │   │       │   │   │   └── page.tsx
│   │   │       │   │   ├── revenue/
│   │   │       │   │   │   ├── Revenue.tsx
│   │   │       │   │   │   ├── RevenuePage.tsx
│   │   │       │   │   │   ├── RevenueTable.tsx
│   │   │       │   │   │   └── page.tsx
│   │   │       │   │   └── utm/
│   │   │       │   │       ├── UTM.tsx
│   │   │       │   │       ├── UTMPage.tsx
│   │   │       │   │       └── page.tsx
│   │   │       │   ├── ExpandedViewModal.tsx
│   │   │       │   ├── WebsiteChart.tsx
│   │   │       │   ├── WebsiteControls.tsx
│   │   │       │   ├── WebsiteExpandedMenu.tsx
│   │   │       │   ├── WebsiteExpandedView.tsx
│   │   │       │   ├── WebsiteHeader.tsx
│   │   │       │   ├── WebsiteLayout.tsx
│   │   │       │   ├── WebsiteMenu.tsx
│   │   │       │   ├── WebsiteMetricsBar.tsx
│   │   │       │   ├── WebsiteNav.tsx
│   │   │       │   ├── WebsitePage.tsx
│   │   │       │   ├── WebsitePanels.tsx
│   │   │       │   ├── WebsiteTabs.tsx
│   │   │       │   ├── cohorts/
│   │   │       │   │   ├── CohortAddButton.tsx
│   │   │       │   │   ├── CohortDeleteButton.tsx
│   │   │       │   │   ├── CohortEditButton.tsx
│   │   │       │   │   ├── CohortEditForm.tsx
│   │   │       │   │   ├── CohortsDataTable.tsx
│   │   │       │   │   ├── CohortsPage.tsx
│   │   │       │   │   ├── CohortsTable.tsx
│   │   │       │   │   └── page.tsx
│   │   │       │   ├── compare/
│   │   │       │   │   ├── ComparePage.tsx
│   │   │       │   │   ├── CompareTables.tsx
│   │   │       │   │   └── page.tsx
│   │   │       │   ├── events/
│   │   │       │   │   ├── EventProperties.tsx
│   │   │       │   │   ├── EventsDataTable.tsx
│   │   │       │   │   ├── EventsMetricsBar.tsx
│   │   │       │   │   ├── EventsPage.tsx
│   │   │       │   │   ├── EventsTable.tsx
│   │   │       │   │   └── page.tsx
│   │   │       │   ├── layout.tsx
│   │   │       │   ├── page.tsx
│   │   │       │   ├── realtime/
│   │   │       │   │   ├── RealtimeCountries.tsx
│   │   │       │   │   ├── RealtimeHeader.tsx
│   │   │       │   │   ├── RealtimeLog.tsx
│   │   │       │   │   ├── RealtimePage.tsx
│   │   │       │   │   ├── RealtimePaths.tsx
│   │   │       │   │   ├── RealtimeReferrers.tsx
│   │   │       │   │   └── page.tsx
│   │   │       │   ├── segments/
│   │   │       │   │   ├── SegmentAddButton.tsx
│   │   │       │   │   ├── SegmentDeleteButton.tsx
│   │   │       │   │   ├── SegmentEditButton.tsx
│   │   │       │   │   ├── SegmentEditForm.tsx
│   │   │       │   │   ├── SegmentsDataTable.tsx
│   │   │       │   │   ├── SegmentsPage.tsx
│   │   │       │   │   ├── SegmentsTable.tsx
│   │   │       │   │   └── page.tsx
│   │   │       │   ├── sessions/
│   │   │       │   │   ├── SessionActivity.tsx
│   │   │       │   │   ├── SessionData.tsx
│   │   │       │   │   ├── SessionInfo.tsx
│   │   │       │   │   ├── SessionModal.tsx
│   │   │       │   │   ├── SessionProfile.tsx
│   │   │       │   │   ├── SessionProperties.tsx
│   │   │       │   │   ├── SessionStats.tsx
│   │   │       │   │   ├── SessionsDataTable.tsx
│   │   │       │   │   ├── SessionsMetricsBar.tsx
│   │   │       │   │   ├── SessionsPage.tsx
│   │   │       │   │   ├── SessionsTable.tsx
│   │   │       │   │   └── page.tsx
│   │   │       │   └── settings/
│   │   │       │       ├── SettingsPage.tsx
│   │   │       │       ├── WebsiteData.tsx
│   │   │       │       ├── WebsiteDeleteForm.tsx
│   │   │       │       ├── WebsiteEditForm.tsx
│   │   │       │       ├── WebsiteResetForm.tsx
│   │   │       │       ├── WebsiteSettings.tsx
│   │   │       │       ├── WebsiteSettingsHeader.tsx
│   │   │       │       ├── WebsiteShareForm.tsx
│   │   │       │       ├── WebsiteTrackingCode.tsx
│   │   │       │       ├── WebsiteTransferForm.tsx
│   │   │       │       └── page.tsx
│   │   │       └── page.tsx
│   │   ├── Providers.tsx
│   │   ├── api/
│   │   │   ├── admin/
│   │   │   │   ├── teams/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── users/
│   │   │   │   │   └── route.ts
│   │   │   │   └── websites/
│   │   │   │       └── route.ts
│   │   │   ├── auth/
│   │   │   │   ├── login/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── logout/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── sso/
│   │   │   │   │   └── route.ts
│   │   │   │   └── verify/
│   │   │   │       └── route.ts
│   │   │   ├── batch/
│   │   │   │   └── route.ts
│   │   │   ├── config/
│   │   │   │   └── route.ts
│   │   │   ├── heartbeat/
│   │   │   │   └── route.ts
│   │   │   ├── links/
│   │   │   │   ├── [linkId]/
│   │   │   │   │   └── route.ts
│   │   │   │   └── route.ts
│   │   │   ├── me/
│   │   │   │   ├── password/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── route.ts
│   │   │   │   ├── teams/
│   │   │   │   │   └── route.ts
│   │   │   │   └── websites/
│   │   │   │       └── route.ts
│   │   │   ├── pixels/
│   │   │   │   ├── [pixelId]/
│   │   │   │   │   └── route.ts
│   │   │   │   └── route.ts
│   │   │   ├── realtime/
│   │   │   │   └── [websiteId]/
│   │   │   │       └── route.ts
│   │   │   ├── reports/
│   │   │   │   ├── [reportId]/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── attribution/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── breakdown/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── funnel/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── goal/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── journey/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── retention/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── revenue/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── route.ts
│   │   │   │   └── utm/
│   │   │   │       └── route.ts
│   │   │   ├── scripts/
│   │   │   │   └── telemetry/
│   │   │   │       └── route.ts
│   │   │   ├── send/
│   │   │   │   └── route.ts
│   │   │   ├── share/
│   │   │   │   └── [shareId]/
│   │   │   │       └── route.ts
│   │   │   ├── teams/
│   │   │   │   ├── [teamId]/
│   │   │   │   │   ├── links/
│   │   │   │   │   │   └── route.ts
│   │   │   │   │   ├── pixels/
│   │   │   │   │   │   └── route.ts
│   │   │   │   │   ├── route.ts
│   │   │   │   │   ├── users/
│   │   │   │   │   │   ├── [userId]/
│   │   │   │   │   │   │   └── route.ts
│   │   │   │   │   │   └── route.ts
│   │   │   │   │   └── websites/
│   │   │   │   │       └── route.ts
│   │   │   │   ├── join/
│   │   │   │   │   └── route.ts
│   │   │   │   └── route.ts
│   │   │   ├── users/
│   │   │   │   ├── [userId]/
│   │   │   │   │   ├── route.ts
│   │   │   │   │   ├── teams/
│   │   │   │   │   │   └── route.ts
│   │   │   │   │   └── websites/
│   │   │   │   │       └── route.ts
│   │   │   │   └── route.ts
│   │   │   └── websites/
│   │   │       ├── [websiteId]/
│   │   │       │   ├── active/
│   │   │       │   │   └── route.ts
│   │   │       │   ├── daterange/
│   │   │       │   │   └── route.ts
│   │   │       │   ├── event-data/
│   │   │       │   │   ├── [eventId]/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   ├── events/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   ├── fields/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   ├── properties/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   ├── stats/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   └── values/
│   │   │       │   │       └── route.ts
│   │   │       │   ├── events/
│   │   │       │   │   ├── route.ts
│   │   │       │   │   └── series/
│   │   │       │   │       └── route.ts
│   │   │       │   ├── export/
│   │   │       │   │   └── route.ts
│   │   │       │   ├── metrics/
│   │   │       │   │   ├── expanded/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   └── route.ts
│   │   │       │   ├── pageviews/
│   │   │       │   │   └── route.ts
│   │   │       │   ├── reports/
│   │   │       │   │   └── route.ts
│   │   │       │   ├── reset/
│   │   │       │   │   └── route.ts
│   │   │       │   ├── route.ts
│   │   │       │   ├── segments/
│   │   │       │   │   ├── [segmentId]/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   └── route.ts
│   │   │       │   ├── session-data/
│   │   │       │   │   ├── properties/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   └── values/
│   │   │       │   │       └── route.ts
│   │   │       │   ├── sessions/
│   │   │       │   │   ├── [sessionId]/
│   │   │       │   │   │   ├── activity/
│   │   │       │   │   │   │   └── route.ts
│   │   │       │   │   │   ├── properties/
│   │   │       │   │   │   │   └── route.ts
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   ├── route.ts
│   │   │       │   │   ├── stats/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   └── weekly/
│   │   │       │   │       └── route.ts
│   │   │       │   ├── stats/
│   │   │       │   │   └── route.ts
│   │   │       │   ├── transfer/
│   │   │       │   │   └── route.ts
│   │   │       │   └── values/
│   │   │       │       └── route.ts
│   │   │       └── route.ts
│   │   ├── layout.tsx
│   │   ├── login/
│   │   │   ├── LoginForm.tsx
│   │   │   ├── LoginPage.tsx
│   │   │   └── page.tsx
│   │   ├── logout/
│   │   │   ├── LogoutPage.tsx
│   │   │   └── page.tsx
│   │   ├── not-found.tsx
│   │   ├── page.tsx
│   │   ├── share/
│   │   │   └── [...shareId]/
│   │   │       ├── Footer.tsx
│   │   │       ├── Header.tsx
│   │   │       ├── SharePage.tsx
│   │   │       └── page.tsx
│   │   └── sso/
│   │       ├── SSOPage.tsx
│   │       └── page.tsx
│   ├── components/
│   │   ├── boards/
│   │   │   └── Board.tsx
│   │   ├── charts/
│   │   │   ├── BarChart.tsx
│   │   │   ├── BubbleChart.tsx
│   │   │   ├── Chart.tsx
│   │   │   ├── ChartTooltip.tsx
│   │   │   └── PieChart.tsx
│   │   ├── common/
│   │   │   ├── ActionForm.tsx
│   │   │   ├── AnimatedDiv.tsx
│   │   │   ├── Avatar.tsx
│   │   │   ├── ConfirmationForm.tsx
│   │   │   ├── DataGrid.tsx
│   │   │   ├── DateDisplay.tsx
│   │   │   ├── DateDistance.tsx
│   │   │   ├── Empty.tsx
│   │   │   ├── EmptyPlaceholder.tsx
│   │   │   ├── ErrorBoundary.tsx
│   │   │   ├── ErrorMessage.tsx
│   │   │   ├── ExternalLink.tsx
│   │   │   ├── Favicon.tsx
│   │   │   ├── FilterLink.tsx
│   │   │   ├── FilterRecord.tsx
│   │   │   ├── GridRow.tsx
│   │   │   ├── LinkButton.tsx
│   │   │   ├── LoadingPanel.tsx
│   │   │   ├── PageBody.tsx
│   │   │   ├── PageHeader.tsx
│   │   │   ├── Pager.tsx
│   │   │   ├── Panel.tsx
│   │   │   ├── SectionHeader.tsx
│   │   │   ├── SideMenu.tsx
│   │   │   ├── TypeConfirmationForm.tsx
│   │   │   └── TypeIcon.tsx
│   │   ├── hooks/
│   │   │   ├── context/
│   │   │   │   ├── useLink.ts
│   │   │   │   ├── usePixel.ts
│   │   │   │   ├── useTeam.ts
│   │   │   │   ├── useUser.ts
│   │   │   │   └── useWebsite.ts
│   │   │   ├── index.ts
│   │   │   ├── queries/
│   │   │   │   ├── useActiveUsersQuery.ts
│   │   │   │   ├── useDateRangeQuery.ts
│   │   │   │   ├── useDeleteQuery.ts
│   │   │   │   ├── useEventDataEventsQuery.ts
│   │   │   │   ├── useEventDataPropertiesQuery.ts
│   │   │   │   ├── useEventDataQuery.ts
│   │   │   │   ├── useEventDataValuesQuery.ts
│   │   │   │   ├── useLinkQuery.ts
│   │   │   │   ├── useLinksQuery.ts
│   │   │   │   ├── useLoginQuery.ts
│   │   │   │   ├── usePixelQuery.ts
│   │   │   │   ├── usePixelsQuery.ts
│   │   │   │   ├── useRealtimeQuery.ts
│   │   │   │   ├── useReportQuery.ts
│   │   │   │   ├── useReportsQuery.ts
│   │   │   │   ├── useResultQuery.ts
│   │   │   │   ├── useSessionActivityQuery.ts
│   │   │   │   ├── useSessionDataPropertiesQuery.ts
│   │   │   │   ├── useSessionDataQuery.ts
│   │   │   │   ├── useSessionDataValuesQuery.ts
│   │   │   │   ├── useShareTokenQuery.ts
│   │   │   │   ├── useTeamMembersQuery.ts
│   │   │   │   ├── useTeamQuery.ts
│   │   │   │   ├── useTeamWebsitesQuery.ts
│   │   │   │   ├── useTeamsQuery.ts
│   │   │   │   ├── useUpdateQuery.ts
│   │   │   │   ├── useUserQuery.ts
│   │   │   │   ├── useUserTeamsQuery.ts
│   │   │   │   ├── useUserWebsitesQuery.ts
│   │   │   │   ├── useUsersQuery.ts
│   │   │   │   ├── useWebsiteCohortQuery.ts
│   │   │   │   ├── useWebsiteCohortsQuery.ts
│   │   │   │   ├── useWebsiteEventsQuery.ts
│   │   │   │   ├── useWebsiteEventsSeriesQuery.ts
│   │   │   │   ├── useWebsiteExpandedMetricsQuery.ts
│   │   │   │   ├── useWebsiteMetricsQuery.ts
│   │   │   │   ├── useWebsitePageviewsQuery.ts
│   │   │   │   ├── useWebsiteQuery.ts
│   │   │   │   ├── useWebsiteSegmentQuery.ts
│   │   │   │   ├── useWebsiteSegmentsQuery.ts
│   │   │   │   ├── useWebsiteSessionQuery.ts
│   │   │   │   ├── useWebsiteSessionStatsQuery.ts
│   │   │   │   ├── useWebsiteSessionsQuery.ts
│   │   │   │   ├── useWebsiteStatsQuery.ts
│   │   │   │   ├── useWebsiteValuesQuery.ts
│   │   │   │   ├── useWebsitesQuery.ts
│   │   │   │   └── useWeeklyTrafficQuery.ts
│   │   │   ├── useApi.ts
│   │   │   ├── useConfig.ts
│   │   │   ├── useCountryNames.ts
│   │   │   ├── useDateParameters.ts
│   │   │   ├── useDateRange.ts
│   │   │   ├── useDocumentClick.ts
│   │   │   ├── useEscapeKey.ts
│   │   │   ├── useFields.ts
│   │   │   ├── useFilterParameters.ts
│   │   │   ├── useFilters.ts
│   │   │   ├── useForceUpdate.ts
│   │   │   ├── useFormat.ts
│   │   │   ├── useGlobalState.ts
│   │   │   ├── useLanguageNames.ts
│   │   │   ├── useLocale.ts
│   │   │   ├── useMessages.ts
│   │   │   ├── useMobile.ts
│   │   │   ├── useModified.ts
│   │   │   ├── useNavigation.ts
│   │   │   ├── usePageParameters.ts
│   │   │   ├── usePagedQuery.ts
│   │   │   ├── useRegionNames.ts
│   │   │   ├── useSlug.ts
│   │   │   ├── useSticky.ts
│   │   │   └── useTimezone.ts
│   │   ├── icons.ts
│   │   ├── input/
│   │   │   ├── ActionSelect.tsx
│   │   │   ├── CurrencySelect.tsx
│   │   │   ├── DateFilter.tsx
│   │   │   ├── DialogButton.tsx
│   │   │   ├── DownloadButton.tsx
│   │   │   ├── ExportButton.tsx
│   │   │   ├── FieldFilters.tsx
│   │   │   ├── FilterBar.tsx
│   │   │   ├── FilterButtons.tsx
│   │   │   ├── FilterEditForm.tsx
│   │   │   ├── LanguageButton.tsx
│   │   │   ├── LookupField.tsx
│   │   │   ├── MenuButton.tsx
│   │   │   ├── MobileMenuButton.tsx
│   │   │   ├── MonthFilter.tsx
│   │   │   ├── MonthSelect.tsx
│   │   │   ├── NavButton.tsx
│   │   │   ├── PanelButton.tsx
│   │   │   ├── PreferencesButton.tsx
│   │   │   ├── ProfileButton.tsx
│   │   │   ├── RefreshButton.tsx
│   │   │   ├── ReportEditButton.tsx
│   │   │   ├── SegmentFilters.tsx
│   │   │   ├── SegmentSaveButton.tsx
│   │   │   ├── SettingsButton.tsx
│   │   │   ├── WebsiteDateFilter.tsx
│   │   │   ├── WebsiteFilterButton.tsx
│   │   │   └── WebsiteSelect.tsx
│   │   ├── messages.ts
│   │   ├── metrics/
│   │   │   ├── ActiveUsers.tsx
│   │   │   ├── ChangeLabel.tsx
│   │   │   ├── DatePickerForm.tsx
│   │   │   ├── EventData.tsx
│   │   │   ├── EventsChart.tsx
│   │   │   ├── Legend.tsx
│   │   │   ├── ListTable.tsx
│   │   │   ├── MetricCard.tsx
│   │   │   ├── MetricLabel.tsx
│   │   │   ├── MetricsBar.tsx
│   │   │   ├── MetricsExpandedTable.tsx
│   │   │   ├── MetricsTable.tsx
│   │   │   ├── PageviewsChart.tsx
│   │   │   ├── RealtimeChart.tsx
│   │   │   ├── WeeklyTraffic.tsx
│   │   │   └── WorldMap.tsx
│   │   └── svg/
│   │       ├── AddUser.tsx
│   │       ├── BarChart.tsx
│   │       ├── Bars.tsx
│   │       ├── Bolt.tsx
│   │       ├── Bookmark.tsx
│   │       ├── Calendar.tsx
│   │       ├── Change.tsx
│   │       ├── Clock.tsx
│   │       ├── Compare.tsx
│   │       ├── Dashboard.tsx
│   │       ├── Download.tsx
│   │       ├── Expand.tsx
│   │       ├── Export.tsx
│   │       ├── Flag.tsx
│   │       ├── Funnel.tsx
│   │       ├── Gear.tsx
│   │       ├── Globe.tsx
│   │       ├── Lightbulb.tsx
│   │       ├── Lightning.tsx
│   │       ├── Link.tsx
│   │       ├── Location.tsx
│   │       ├── Lock.tsx
│   │       ├── Logo.tsx
│   │       ├── LogoWhite.tsx
│   │       ├── Magnet.tsx
│   │       ├── Money.tsx
│   │       ├── Moon.tsx
│   │       ├── Network.tsx
│   │       ├── Nodes.tsx
│   │       ├── Overview.tsx
│   │       ├── Path.tsx
│   │       ├── Profile.tsx
│   │       ├── Pushpin.tsx
│   │       ├── Redo.tsx
│   │       ├── Reports.tsx
│   │       ├── Security.tsx
│   │       ├── Speaker.tsx
│   │       ├── Sun.tsx
│   │       ├── Switch.tsx
│   │       ├── Tag.tsx
│   │       ├── Target.tsx
│   │       ├── Visitor.tsx
│   │       ├── Website.tsx
│   │       └── index.ts
│   ├── declaration.d.ts
│   ├── index.ts
│   ├── lang/
│   │   ├── ar-SA.json
│   │   ├── be-BY.json
│   │   ├── bg-BG.json
│   │   ├── bn-BD.json
│   │   ├── bs-BA.json
│   │   ├── ca-ES.json
│   │   ├── cs-CZ.json
│   │   ├── da-DK.json
│   │   ├── de-CH.json
│   │   ├── de-DE.json
│   │   ├── el-GR.json
│   │   ├── en-GB.json
│   │   ├── en-US.json
│   │   ├── es-ES.json
│   │   ├── fa-IR.json
│   │   ├── fi-FI.json
│   │   ├── fo-FO.json
│   │   ├── fr-FR.json
│   │   ├── ga-ES.json
│   │   ├── he-IL.json
│   │   ├── hi-IN.json
│   │   ├── hr-HR.json
│   │   ├── hu-HU.json
│   │   ├── id-ID.json
│   │   ├── it-IT.json
│   │   ├── ja-JP.json
│   │   ├── km-KH.json
│   │   ├── ko-KR.json
│   │   ├── lt-LT.json
│   │   ├── mn-MN.json
│   │   ├── ms-MY.json
│   │   ├── my-MM.json
│   │   ├── nb-NO.json
│   │   ├── nl-NL.json
│   │   ├── pl-PL.json
│   │   ├── pt-BR.json
│   │   ├── pt-PT.json
│   │   ├── ro-RO.json
│   │   ├── ru-RU.json
│   │   ├── si-LK.json
│   │   ├── sk-SK.json
│   │   ├── sl-SI.json
│   │   ├── sv-SE.json
│   │   ├── ta-IN.json
│   │   ├── th-TH.json
│   │   ├── tr-TR.json
│   │   ├── uk-UA.json
│   │   ├── ur-PK.json
│   │   ├── uz-UZ.json
│   │   ├── vi-VN.json
│   │   ├── zh-CN.json
│   │   └── zh-TW.json
│   ├── lib/
│   │   ├── __tests__/
│   │   │   ├── charts.test.ts
│   │   │   ├── detect.test.ts
│   │   │   └── format.test.ts
│   │   ├── auth.ts
│   │   ├── charts.ts
│   │   ├── clickhouse.ts
│   │   ├── client.ts
│   │   ├── colors.ts
│   │   ├── constants.ts
│   │   ├── crypto.ts
│   │   ├── data.ts
│   │   ├── date.ts
│   │   ├── db.ts
│   │   ├── detect.ts
│   │   ├── fetch.ts
│   │   ├── filters.ts
│   │   ├── format.ts
│   │   ├── generate.ts
│   │   ├── ip.ts
│   │   ├── jwt.ts
│   │   ├── kafka.ts
│   │   ├── lang.ts
│   │   ├── load.ts
│   │   ├── params.ts
│   │   ├── password.ts
│   │   ├── prisma.ts
│   │   ├── react.ts
│   │   ├── redis.ts
│   │   ├── request.ts
│   │   ├── response.ts
│   │   ├── schema.ts
│   │   ├── sql.ts
│   │   ├── storage.ts
│   │   ├── types.ts
│   │   ├── url.ts
│   │   └── utils.ts
│   ├── permissions/
│   │   ├── index.ts
│   │   ├── link.ts
│   │   ├── pixel.ts
│   │   ├── report.ts
│   │   ├── team.ts
│   │   ├── user.ts
│   │   └── website.ts
│   ├── queries/
│   │   ├── prisma/
│   │   │   ├── index.ts
│   │   │   ├── link.ts
│   │   │   ├── pixel.ts
│   │   │   ├── report.ts
│   │   │   ├── segment.ts
│   │   │   ├── team.ts
│   │   │   ├── teamUser.ts
│   │   │   ├── user.ts
│   │   │   └── website.ts
│   │   └── sql/
│   │       ├── events/
│   │       │   ├── getEventData.ts
│   │       │   ├── getEventDataEvents.ts
│   │       │   ├── getEventDataFields.ts
│   │       │   ├── getEventDataProperties.ts
│   │       │   ├── getEventDataStats.ts
│   │       │   ├── getEventDataUsage.ts
│   │       │   ├── getEventDataValues.ts
│   │       │   ├── getEventExpandedMetrics.ts
│   │       │   ├── getEventMetrics.ts
│   │       │   ├── getEventStats.ts
│   │       │   ├── getEventUsage.ts
│   │       │   ├── getWebsiteEvents.ts
│   │       │   ├── saveEvent.ts
│   │       │   ├── saveEventData.ts
│   │       │   └── saveRevenue.ts
│   │       ├── getActiveVisitors.ts
│   │       ├── getChannelExpandedMetrics.ts
│   │       ├── getChannelMetrics.ts
│   │       ├── getRealtimeActivity.ts
│   │       ├── getRealtimeData.ts
│   │       ├── getValues.ts
│   │       ├── getWebsiteDateRange.ts
│   │       ├── getWebsiteStats.ts
│   │       ├── getWeeklyTraffic.ts
│   │       ├── index.ts
│   │       ├── pageviews/
│   │       │   ├── getPageviewExpandedMetrics.ts
│   │       │   ├── getPageviewMetrics.ts
│   │       │   └── getPageviewStats.ts
│   │       ├── reports/
│   │       │   ├── getAttribution.ts
│   │       │   ├── getBreakdown.ts
│   │       │   ├── getFunnel.ts
│   │       │   ├── getGoal.ts
│   │       │   ├── getJourney.ts
│   │       │   ├── getRetention.ts
│   │       │   ├── getRevenue.ts
│   │       │   └── getUTM.ts
│   │       └── sessions/
│   │           ├── createSession.ts
│   │           ├── getSessionActivity.ts
│   │           ├── getSessionData.ts
│   │           ├── getSessionDataProperties.ts
│   │           ├── getSessionDataValues.ts
│   │           ├── getSessionExpandedMetrics.ts
│   │           ├── getSessionMetrics.ts
│   │           ├── getSessionStats.ts
│   │           ├── getWebsiteSession.ts
│   │           ├── getWebsiteSessionStats.ts
│   │           ├── getWebsiteSessions.ts
│   │           └── saveSessionData.ts
│   ├── store/
│   │   ├── app.ts
│   │   ├── cache.ts
│   │   ├── dashboard.ts
│   │   ├── version.ts
│   │   └── websites.ts
│   ├── styles/
│   │   ├── global.css
│   │   └── variables.css
│   └── tracker/
│       ├── index.d.ts
│       └── index.js
├── tsconfig.json
├── tsconfig.prisma.json
└── tsup.config.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .dockerignore
================================================
.git
docker-compose.yml
Dockerfile
.gitignore
.DS_Store
node_modules
.idea
.env
.env.*
scripts/seed
scripts/seed-data.ts


================================================
FILE: .github/ISSUE_TEMPLATE/1.bug_report.yml
================================================
name: '🐛 Bug Report'
description: Create a bug report for Umami.
body:
  - type: textarea
    attributes:
      label: Describe the Bug
      description: A clear and concise description of what the bug is.
    validations:
      required: true
  - type: dropdown
    attributes:
      label: Database
      description: What database are you using?
      options:
        - PostgreSQL
        - MySQL
        - Umami Cloud
    validations:
      required: true
  - type: textarea
    attributes:
      label: Relevant log output
      description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
      render: shell
  - type: input
    attributes:
      label: Which Umami version are you using? (if relevant)
      description: 'For example: 2.18.0, 2.15.1, 1.39.0, etc'
  - type: input
    attributes:
      label: Which browser are you using? (if relevant)
      description: 'For example: Chrome, Edge, Firefox, etc'
  - type: input
    attributes:
      label: How are you deploying your application? (if relevant)
      description: 'For example: Vercel, Railway, Docker, etc'


================================================
FILE: .github/ISSUE_TEMPLATE/2.feature_request.yml
================================================
name: '✨ Feature Request'
description: Create a feature or enhancement request for Umami.
body:
  - type: textarea
    attributes:
      label: Describe the feature or enhancement
      description: A clear and concise description of what the feature or enhancement is.
    validations:
      required: true


================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================

blank_issues_enabled: false
contact_links:
  - name: "🤔 Ask a question"
    url: https://github.com/umami-software/umami/discussions
    about: Ask questions and discuss with other community members.

================================================
FILE: .github/workflows/cd-cloud.yml
================================================
name: Create docker images (cloud)

on:
  push:
    branches:
      - analytics
      - cloud

jobs:
  build:
    name: Build, push, and deploy
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Generate random hash
        id: random_hash
        run: echo "hash=$(openssl rand -hex 4)" >> $GITHUB_OUTPUT

      - uses: mr-smithers-excellent/docker-build-push@v6
        name: Build & push Docker image to docker.io
        with:
          image: umamisoftware/umami
          tags: cloud-${{ steps.random_hash.outputs.hash }}, cloud-latest
          buildArgs: DATABASE_TYPE=postgresql
          registry: docker.io
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}


================================================
FILE: .github/workflows/cd.yml
================================================
name: Create docker images

on:
  push:
    tags:
      - "v*.*.*"
  workflow_dispatch:
    inputs:
      version:
        description: "Optional image version (e.g. 3.0.0, v3.0.0, or 3.0.0-beta.1)"
        required: false
        default: ""
      include_latest:
        description: "Include latest tag"
        required: false
        type: boolean
        default: true

jobs:
  build:
    name: Build, push, and deploy
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@v5

      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log into GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Log into Docker Hub
        if: github.repository == 'umami-software/umami'
        uses: docker/login-action@v3
        with:
          registry: docker.io
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Compute version tags
        id: compute
        run: |
          INPUT="${{ github.event.inputs.version }}"
          REF_TYPE="${{ github.ref_type }}"
          REF_NAME="${{ github.ref_name }}"
          INCLUDE_LATEST="${{ github.event.inputs.include_latest }}"

          # Determine version source
          if [[ -n "$INPUT" ]]; then
            VERSION="${INPUT#v}"
          elif [[ "$REF_TYPE" == "tag" ]]; then
            VERSION="${REF_NAME#v}"
          else
            VERSION=""
          fi

          GHCR_TAGS=""
          DOCKER_TAGS=""

          if [[ -n "$VERSION" ]]; then
            MAJOR=$(echo "$VERSION" | cut -d. -f1)
            MINOR=$(echo "$VERSION" | cut -d. -f2)

            if [[ "$VERSION" == *-* ]]; then
              # prerelease: only version tag
              GHCR_TAGS="ghcr.io/${{ github.repository }}:$VERSION"
              DOCKER_TAGS="umamisoftware/umami:$VERSION"
            else
              # stable release: version + hierarchy
              GHCR_TAGS="ghcr.io/${{ github.repository }}:$VERSION"
              GHCR_TAGS="$GHCR_TAGS,ghcr.io/${{ github.repository }}:${MAJOR}.${MINOR}"
              GHCR_TAGS="$GHCR_TAGS,ghcr.io/${{ github.repository }}:${MAJOR}"
              GHCR_TAGS="$GHCR_TAGS,ghcr.io/${{ github.repository }}:postgresql-latest"
          
              DOCKER_TAGS="umamisoftware/umami:$VERSION"
              DOCKER_TAGS="$DOCKER_TAGS,umamisoftware/umami:${MAJOR}.${MINOR}"
              DOCKER_TAGS="$DOCKER_TAGS,umamisoftware/umami:${MAJOR}"
              DOCKER_TAGS="$DOCKER_TAGS,umamisoftware/umami:postgresql-latest"
          
              # Add latest tag based on trigger and input
              if [[ "$REF_TYPE" == "tag" ]] || [[ "$INCLUDE_LATEST" == "true" ]]; then
                GHCR_TAGS="$GHCR_TAGS,ghcr.io/${{ github.repository }}:latest"
                DOCKER_TAGS="$DOCKER_TAGS,umamisoftware/umami:latest"
              fi
            fi
          else
            # Non-tag build (e.g. from main branch)
            GHCR_TAGS="ghcr.io/${{ github.repository }}:${REF_NAME}"
            DOCKER_TAGS="umamisoftware/umami:${REF_NAME}"
          fi

          echo "ghcr_tags=$GHCR_TAGS" >> $GITHUB_OUTPUT
          echo "docker_tags=$DOCKER_TAGS" >> $GITHUB_OUTPUT
          echo "Computed GHCR tags: $GHCR_TAGS"
          echo "Computed Docker Hub tags: $DOCKER_TAGS"

      - name: Build and push to GHCR
        uses: docker/build-push-action@v5
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: ${{ steps.compute.outputs.ghcr_tags }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Build and push to Docker Hub
        if: github.repository == 'umami-software/umami'
        uses: docker/build-push-action@v5
        with:
          context: .
          platforms: linux/amd64,linux/arm64
          push: true
          tags: ${{ steps.compute.outputs.docker_tags }}
          cache-from: type=gha
          cache-to: type=gha,mode=max


================================================
FILE: .github/workflows/ci.yml
================================================
name: Node.js CI

on: [push]

env:
  DATABASE_URL: "postgresql://user:pass@localhost:5432/dummy"
  SKIP_DB_CHECK: 1

jobs:
  build:
    if: github.repository == 'umami-software/umami'
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with:
          version: 10
          run_install: false
      - name: Use Node.js 18.18
        uses: actions/setup-node@v4
        with:
          node-version: 18.18
          cache: "pnpm"
      - run: npm install --global pnpm
      - run: pnpm install
      - run: pnpm test
      - run: pnpm build


================================================
FILE: .github/workflows/stale-issues.yml
================================================
name: Close stale issues
on:
  schedule:
    - cron: '30 1 * * *'

jobs:
  stale:
    runs-on: ubuntu-latest
    permissions:
      issues: write
      pull-requests: write
    steps:
      - uses: actions/stale@v8
        with:
          days-before-issue-stale: 60
          days-before-issue-close: 7
          stale-issue-label: 'stale'
          stale-issue-message: 'This issue is stale because it has been open for 60 days with no activity.'
          close-issue-message: 'This issue was closed because it has been inactive for 7 days since being marked as stale.'
          days-before-pr-stale: -1
          days-before-pr-close: -1
          operations-per-run: 200
          ascending: true
          repo-token: ${{ secrets.GITHUB_TOKEN }}
          exempt-issue-labels: bug,enhancement


================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
node_modules
.pnp
.pnp.js
.pnpm-store
package-lock.json

# testing
/coverage

# next.js
/.next
/out

# production
/build
/public/script.js
/geo
/dist
/generated
/src/generated

# misc
.DS_Store
.idea
.yarn
*.iml
*.log
.vscode
.tool-versions

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env
.env.*
*.env.*

*.dev.yml



================================================
FILE: .husky/pre-commit
================================================
npx lint-staged


================================================
FILE: .stylelintrc.json
================================================
{
  "extends": ["stylelint-config-recommended", "stylelint-config-css-modules"],
  "rules": {
    "no-descending-specificity": null
  }
}


================================================
FILE: Dockerfile
================================================
ARG NODE_IMAGE_VERSION="22-alpine"

# Install dependencies only when needed
FROM node:${NODE_IMAGE_VERSION} AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm
RUN pnpm install --frozen-lockfile

# Rebuild the source code only when needed
FROM node:${NODE_IMAGE_VERSION} AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
COPY docker/middleware.ts ./src

ARG BASE_PATH

ENV BASE_PATH=$BASE_PATH
ENV NEXT_TELEMETRY_DISABLED=1
ENV DATABASE_URL="postgresql://user:pass@localhost:5432/dummy"

RUN npm run build-docker

# Production image, copy all the files and run next
FROM node:${NODE_IMAGE_VERSION} AS runner
WORKDIR /app

ARG PRISMA_VERSION="6.19.0"
ARG NODE_OPTIONS

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_OPTIONS=$NODE_OPTIONS

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
RUN set -x \
    && apk add --no-cache curl \
    && npm install -g pnpm

# Script dependencies
RUN pnpm --allow-build='@prisma/engines' add npm-run-all dotenv chalk semver \
    prisma@${PRISMA_VERSION} \
    @prisma/adapter-pg@${PRISMA_VERSION}

COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder /app/prisma ./prisma
COPY --from=builder /app/scripts ./scripts
COPY --from=builder /app/generated ./generated

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV HOSTNAME=0.0.0.0
ENV PORT=3000

CMD ["pnpm", "start-docker"]


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2022 Umami Software, Inc. <hello@umami.is>

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.

================================================
FILE: README.md
================================================
<p align="center">
  <img src="https://content.umami.is/website/images/umami-logo.png" alt="Umami Logo" width="100">
</p>

<h1 align="center">Umami</h1>

<p align="center">
  <i>Umami is a simple, fast, privacy-focused alternative to Google Analytics.</i>
</p>

<p align="center">
  <a href="https://github.com/umami-software/umami/releases"><img src="https://img.shields.io/github/release/umami-software/umami.svg" alt="GitHub Release" /></a>
  <a href="https://github.com/umami-software/umami/blob/master/LICENSE"><img src="https://img.shields.io/github/license/umami-software/umami.svg" alt="MIT License" /></a>
  <a href="https://github.com/umami-software/umami/actions"><img src="https://img.shields.io/github/actions/workflow/status/umami-software/umami/ci.yml" alt="Build Status" /></a>
  <a href="https://analytics.umami.is/share/LGazGOecbDtaIwDr/umami.is" style="text-decoration: none;"><img src="https://img.shields.io/badge/Try%20Demo%20Now-Click%20Here-brightgreen" alt="Umami Demo" /></a>
</p>

---

## 🚀 Getting Started

A detailed getting started guide can be found at [umami.is/docs](https://umami.is/docs/).

---

## 🛠 Installing from Source

### Requirements

- A server with Node.js version 18.18+.
- A PostgreSQL database version v12.14+.

### Get the source code and install packages

```bash
git clone https://github.com/umami-software/umami.git
cd umami
pnpm install
```

### Configure Umami

Create an `.env` file with the following:

```bash
DATABASE_URL=connection-url
```

The connection URL format:

```bash
postgresql://username:mypassword@localhost:5432/mydb
```

### Build the Application

```bash
pnpm run build
```

The build step will create tables in your database if you are installing for the first time. It will also create a login user with username **admin** and password **umami**.

### Start the Application

```bash
pnpm run start
```

By default, this will launch the application on `http://localhost:3000`. You will need to either [proxy](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) requests from your web server or change the [port](https://nextjs.org/docs/api-reference/cli#production) to serve the application directly.

---

## 🐳 Installing with Docker

Umami provides Docker images as well as a Docker compose file for easy deployment.

Docker image:

```bash
docker pull docker.umami.is/umami-software/umami:latest
```

Docker compose (Runs Umami with a PostgreSQL database):

```bash
docker compose up -d
```

---

## 🔄 Getting Updates

To get the latest features, simply do a pull, install any new dependencies, and rebuild:

```bash
git pull
pnpm install
pnpm build
```

To update the Docker image, simply pull the new images and rebuild:

```bash
docker compose pull
docker compose up --force-recreate -d
```

---

## 🛟 Support

<p align="center">
  <a href="https://github.com/umami-software/umami"><img src="https://img.shields.io/badge/GitHub--blue?style=social&logo=github" alt="GitHub" /></a>
  <a href="https://twitter.com/umami_software"><img src="https://img.shields.io/badge/Twitter--blue?style=social&logo=twitter" alt="Twitter" /></a>
  <a href="https://linkedin.com/company/umami-software"><img src="https://img.shields.io/badge/LinkedIn--blue?style=social&logo=linkedin" alt="LinkedIn" /></a>
  <a href="https://umami.is/discord"><img src="https://img.shields.io/badge/Discord--blue?style=social&logo=discord" alt="Discord" /></a>
</p>

[release-shield]: https://img.shields.io/github/release/umami-software/umami.svg
[releases-url]: https://github.com/umami-software/umami/releases
[license-shield]: https://img.shields.io/github/license/umami-software/umami.svg
[license-url]: https://github.com/umami-software/umami/blob/master/LICENSE
[build-shield]: https://img.shields.io/github/actions/workflow/status/umami-software/umami/ci.yml
[build-url]: https://github.com/umami-software/umami/actions
[github-shield]: https://img.shields.io/badge/GitHub--blue?style=social&logo=github
[github-url]: https://github.com/umami-software/umami
[twitter-shield]: https://img.shields.io/badge/Twitter--blue?style=social&logo=twitter
[twitter-url]: https://twitter.com/umami_software
[linkedin-shield]: https://img.shields.io/badge/LinkedIn--blue?style=social&logo=linkedin
[linkedin-url]: https://linkedin.com/company/umami-software
[discord-shield]: https://img.shields.io/badge/Discord--blue?style=social&logo=discord
[discord-url]: https://discord.com/invite/4dz4zcXYrQ


================================================
FILE: app.json
================================================
{
  "name": "Umami",
  "description": "Umami is a simple, fast, website analytics alternative to Google Analytics.",
  "keywords": ["analytics", "charts", "statistics", "web-analytics"],
  "website": "https://umami.is",
  "repository": "https://github.com/umami-software/umami",
  "addons": ["heroku-postgresql"],
  "env": {
    "APP_SECRET": {
      "description": "Used to generate unique values for your installation",
      "required": true,
      "generator": "secret"
    }
  },
  "success_url": "/"
}


================================================
FILE: biome.json
================================================
{
  "$schema": "https://biomejs.dev/schemas/2.3.6/schema.json",
  "vcs": {
    "enabled": true,
    "clientKind": "git",
    "useIgnoreFile": true
  },
  "files": {
    "includes": ["**", "!!**/dist"]
  },
  "formatter": {
    "enabled": true,
    "lineWidth": 100,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineEnding": "lf"
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true,
      "a11y": "off",
      "correctness": {
        "useExhaustiveDependencies": "off"
      },
      "style": {
        "noDescendingSpecificity": "off"
      },
      "complexity": {
        "noImportantStyles": "off"
      },
      "suspicious": {
        "noArrayIndexKey": "off",
        "noExplicitAny": "off",
        "noImplicitAnyLet": "off"
      },
      "performance": {
        "noImgElement": "off"
      }
    }
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "trailingCommas": "all",
      "arrowParentheses": "asNeeded"
    }
  },
  "css": {
    "formatter": {
      "enabled": true,
      "indentStyle": "space",
      "indentWidth": 2,
      "lineEnding": "lf"
    }
  },
  "assist": {
    "enabled": true,
    "actions": {
      "source": {
        "organizeImports": "on"
      }
    }
  }
}


================================================
FILE: cypress/docker-compose.yml
================================================
---
version: '3'
services:
  umami:
    build: ../
    #image: ghcr.io/umami-software/umami:postgresql-latest
    ports:
      - '3000:3000'
    environment:
      DATABASE_URL: postgresql://umami:umami@db:5432/umami
      DATABASE_TYPE: postgresql
      APP_SECRET: replace-me-with-a-random-string
    depends_on:
      db:
        condition: service_healthy
    restart: always
    healthcheck:
      test: ['CMD-SHELL', 'curl http://localhost:3000/api/heartbeat']
      interval: 5s
      timeout: 5s
      retries: 5
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: umami
      POSTGRES_USER: umami
      POSTGRES_PASSWORD: umami
    volumes:
      - umami-db-data:/var/lib/postgresql/data
    restart: always
    healthcheck:
      test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}']
      interval: 5s
      timeout: 5s
      retries: 5
  cypress:
    image: 'cypress/included:13.6.0'
    depends_on:
      - umami
      - db
    environment:
      - CYPRESS_baseUrl=http://umami:3000
      - CYPRESS_umami_user=admin
      - CYPRESS_umami_password=umami
    volumes:
      - ./tsconfig.json:/tsconfig.json
      - ../cypress.config.ts:/cypress.config.ts
      - ./:/cypress
      - ../node_modules/:/node_modules
      - ../src/lib/crypto.ts:/src/lib/crypto.ts
volumes:
  umami-db-data:


================================================
FILE: cypress/e2e/api-team.cy.ts
================================================
describe('Team API tests', () => {
  Cypress.session.clearAllSavedSessions();

  let teamId;
  let userId;

  before(() => {
    cy.login(Cypress.env('umami_user'), Cypress.env('umami_password'));
    cy.fixture('users').then(data => {
      const userCreate = data.userCreate;
      cy.request({
        method: 'POST',
        url: '/api/users',
        headers: {
          'Content-Type': 'application/json',
          Authorization: Cypress.env('authorization'),
        },
        body: userCreate,
      }).then(response => {
        userId = response.body.id;
        expect(response.status).to.eq(200);
        expect(response.body).to.have.property('username', 'cypress1');
        expect(response.body).to.have.property('role', 'user');
      });
    });
  });

  it('Creates a team.', () => {
    cy.fixture('teams').then(data => {
      const teamCreate = data.teamCreate;
      cy.request({
        method: 'POST',
        url: '/api/teams',
        headers: {
          'Content-Type': 'application/json',
          Authorization: Cypress.env('authorization'),
        },
        body: teamCreate,
      }).then(response => {
        teamId = response.body[0].id;
        expect(response.status).to.eq(200);
        expect(response.body[0]).to.have.property('name', 'cypress');
        expect(response.body[1]).to.have.property('role', 'team-owner');
      });
    });
  });

  it('Gets a teams by ID.', () => {
    cy.request({
      method: 'GET',
      url: `/api/teams/${teamId}`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('id', teamId);
    });
  });

  it('Updates a team.', () => {
    cy.fixture('teams').then(data => {
      const teamUpdate = data.teamUpdate;
      cy.request({
        method: 'POST',
        url: `/api/teams/${teamId}`,
        headers: {
          'Content-Type': 'application/json',
          Authorization: Cypress.env('authorization'),
        },
        body: teamUpdate,
      }).then(response => {
        expect(response.status).to.eq(200);
        expect(response.body).to.have.property('id', teamId);
        expect(response.body).to.have.property('name', 'cypressUpdate');
      });
    });
  });

  it('Get all users that belong to a team.', () => {
    cy.request({
      method: 'GET',
      url: `/api/teams/${teamId}/users`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body.data[0]).to.have.property('id');
      expect(response.body.data[0]).to.have.property('teamId');
      expect(response.body.data[0]).to.have.property('userId');
      expect(response.body.data[0]).to.have.property('user');
    });
  });

  it('Get a user belonging to a team.', () => {
    cy.request({
      method: 'GET',
      url: `/api/teams/${teamId}/users/${Cypress.env('umami_user_id')}`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('teamId');
      expect(response.body).to.have.property('userId');
      expect(response.body).to.have.property('role');
    });
  });

  it('Get all websites belonging to a team.', () => {
    cy.request({
      method: 'GET',
      url: `/api/teams/${teamId}/websites`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('data');
    });
  });

  it('Add a user to a team.', () => {
    cy.request({
      method: 'POST',
      url: `/api/teams/${teamId}/users`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
      body: {
        userId,
        role: 'team-member',
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('userId', userId);
      expect(response.body).to.have.property('role', 'team-member');
    });
  });

  it(`Update a user's role on a team.`, () => {
    cy.request({
      method: 'POST',
      url: `/api/teams/${teamId}/users/${userId}`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
      body: {
        role: 'team-view-only',
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('userId', userId);
      expect(response.body).to.have.property('role', 'team-view-only');
    });
  });

  it(`Remove a user from a team.`, () => {
    cy.request({
      method: 'DELETE',
      url: `/api/teams/${teamId}/users/${userId}`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
    }).then(response => {
      expect(response.status).to.eq(200);
    });
  });

  it('Deletes a team.', () => {
    cy.request({
      method: 'DELETE',
      url: `/api/teams/${teamId}`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('ok', true);
    });
  });

  // it('Gets all teams that belong to a user.', () => {
  //   cy.request({
  //     method: 'GET',
  //     url: `/api/users/${userId}/teams`,
  //     headers: {
  //       'Content-Type': 'application/json',
  //       Authorization: Cypress.env('authorization'),
  //     },
  //   }).then(response => {
  //     expect(response.status).to.eq(200);
  //     expect(response.body).to.have.property('data');
  //   });
  // });

  after(() => {
    cy.deleteUser(userId);
  });
});


================================================
FILE: cypress/e2e/api-user.cy.ts
================================================
describe('User API tests', () => {
  Cypress.session.clearAllSavedSessions();

  before(() => {
    cy.login(Cypress.env('umami_user'), Cypress.env('umami_password'));
  });

  let userId;

  it('Creates a user.', () => {
    cy.fixture('users').then(data => {
      const userCreate = data.userCreate;
      cy.request({
        method: 'POST',
        url: '/api/users',
        headers: {
          'Content-Type': 'application/json',
          Authorization: Cypress.env('authorization'),
        },
        body: userCreate,
      }).then(response => {
        userId = response.body.id;
        expect(response.status).to.eq(200);
        expect(response.body).to.have.property('username', 'cypress1');
        expect(response.body).to.have.property('role', 'user');
      });
    });
  });

  it('Returns all users. Admin access is required.', () => {
    cy.request({
      method: 'GET',
      url: '/api/admin/users',
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body.data[0]).to.have.property('id');
      expect(response.body.data[0]).to.have.property('username');
      expect(response.body.data[0]).to.have.property('password');
      expect(response.body.data[0]).to.have.property('role');
    });
  });

  it('Updates a user.', () => {
    cy.fixture('users').then(data => {
      const userUpdate = data.userUpdate;
      cy.request({
        method: 'POST',
        url: `/api/users/${userId}`,
        headers: {
          'Content-Type': 'application/json',
          Authorization: Cypress.env('authorization'),
        },
        body: userUpdate,
      }).then(response => {
        userId = response.body.id;
        expect(response.status).to.eq(200);
        expect(response.body).to.have.property('id', userId);
        expect(response.body).to.have.property('username', 'cypress1');
        expect(response.body).to.have.property('role', 'view-only');
      });
    });
  });

  it('Gets a user by ID.', () => {
    cy.request({
      method: 'GET',
      url: `/api/users/${userId}`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('id', userId);
      expect(response.body).to.have.property('username', 'cypress1');
      expect(response.body).to.have.property('role', 'view-only');
    });
  });

  it('Deletes a user.', () => {
    cy.request({
      method: 'DELETE',
      url: `/api/users/${userId}`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('ok', true);
    });
  });

  it('Gets all websites that belong to a user.', () => {
    cy.request({
      method: 'GET',
      url: `/api/users/${userId}/websites`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('data');
    });
  });

  it('Gets all teams that belong to a user.', () => {
    cy.request({
      method: 'GET',
      url: `/api/users/${userId}/teams`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('data');
    });
  });
});


================================================
FILE: cypress/e2e/api-website.cy.ts
================================================
import { uuid } from '../../src/lib/crypto';

describe('Website API tests', () => {
  Cypress.session.clearAllSavedSessions();

  let websiteId;
  let teamId;

  before(() => {
    cy.login(Cypress.env('umami_user'), Cypress.env('umami_password'));
    cy.fixture('teams').then(data => {
      const teamCreate = data.teamCreate;
      cy.request({
        method: 'POST',
        url: '/api/teams',
        headers: {
          'Content-Type': 'application/json',
          Authorization: Cypress.env('authorization'),
        },
        body: teamCreate,
      }).then(response => {
        teamId = response.body[0].id;
        expect(response.status).to.eq(200);
        expect(response.body[0]).to.have.property('name', 'cypress');
        expect(response.body[1]).to.have.property('role', 'team-owner');
      });
    });
  });

  it('Creates a website for user.', () => {
    cy.fixture('websites').then(data => {
      const websiteCreate = data.websiteCreate;
      cy.request({
        method: 'POST',
        url: '/api/websites',
        headers: {
          'Content-Type': 'application/json',
          Authorization: Cypress.env('authorization'),
        },
        body: websiteCreate,
      }).then(response => {
        websiteId = response.body.id;
        expect(response.status).to.eq(200);
        expect(response.body).to.have.property('name', 'Cypress Website');
        expect(response.body).to.have.property('domain', 'cypress.com');
      });
    });
  });

  it('Creates a website for team.', () => {
    cy.request({
      method: 'POST',
      url: '/api/websites',
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
      body: {
        name: 'Team Website',
        domain: 'teamwebsite.com',
        teamId: teamId,
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('name', 'Team Website');
      expect(response.body).to.have.property('domain', 'teamwebsite.com');
    });
  });

  it('Creates a website with a fixed ID.', () => {
    cy.fixture('websites').then(data => {
      const websiteCreate = data.websiteCreate;
      const fixedId = uuid();
      cy.request({
        method: 'POST',
        url: '/api/websites',
        headers: {
          'Content-Type': 'application/json',
          Authorization: Cypress.env('authorization'),
        },
        body: { ...websiteCreate, id: fixedId },
      }).then(response => {
        expect(response.status).to.eq(200);
        expect(response.body).to.have.property('id', fixedId);
        expect(response.body).to.have.property('name', 'Cypress Website');
        expect(response.body).to.have.property('domain', 'cypress.com');

        // cleanup
        cy.request({
          method: 'DELETE',
          url: `/api/websites/${fixedId}`,
          headers: {
            'Content-Type': 'application/json',
            Authorization: Cypress.env('authorization'),
          },
        });
      });
    });
  });

  it('Returns all tracked websites.', () => {
    cy.request({
      method: 'GET',
      url: '/api/websites',
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body.data[0]).to.have.property('id');
      expect(response.body.data[0]).to.have.property('name');
      expect(response.body.data[0]).to.have.property('domain');
    });
  });

  it('Gets a website by ID.', () => {
    cy.request({
      method: 'GET',
      url: `/api/websites/${websiteId}`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('name', 'Cypress Website');
      expect(response.body).to.have.property('domain', 'cypress.com');
    });
  });

  it('Updates a website.', () => {
    cy.fixture('websites').then(data => {
      const websiteUpdate = data.websiteUpdate;
      cy.request({
        method: 'POST',
        url: `/api/websites/${websiteId}`,
        headers: {
          'Content-Type': 'application/json',
          Authorization: Cypress.env('authorization'),
        },
        body: websiteUpdate,
      }).then(response => {
        websiteId = response.body.id;
        expect(response.status).to.eq(200);
        expect(response.body).to.have.property('name', 'Cypress Website Updated');
        expect(response.body).to.have.property('domain', 'cypressupdated.com');
      });
    });
  });

  it('Updates a website with only shareId.', () => {
    cy.request({
      method: 'POST',
      url: `/api/websites/${websiteId}`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
      body: { shareId: 'ABCDEF' },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('shareId', 'ABCDEF');
    });
  });

  it('Resets a website by removing all data related to the website.', () => {
    cy.request({
      method: 'POST',
      url: `/api/websites/${websiteId}/reset`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('ok', true);
    });
  });

  it('Deletes a website.', () => {
    cy.request({
      method: 'DELETE',
      url: `/api/websites/${websiteId}`,
      headers: {
        'Content-Type': 'application/json',
        Authorization: Cypress.env('authorization'),
      },
    }).then(response => {
      expect(response.status).to.eq(200);
      expect(response.body).to.have.property('ok', true);
    });
  });

  after(() => {
    cy.deleteTeam(teamId);
  });
});


================================================
FILE: cypress/e2e/login.cy.ts
================================================
describe('Login tests', () => {
  beforeEach(() => {
    cy.visit('/login');
  });

  it(
    'logs user in with correct credentials and logs user out',
    {
      defaultCommandTimeout: 10000,
    },
    () => {
      cy.getDataTest('input-username').find('input').as('inputUsername').click();
      cy.get('@inputUsername').type(Cypress.env('umami_user'), { delay: 0 });
      cy.get('@inputUsername').click();
      cy.getDataTest('input-password')
        .find('input')
        .type(Cypress.env('umami_password'), { delay: 0 });
      cy.getDataTest('button-submit').click();
      cy.url().should('eq', Cypress.config().baseUrl + '/dashboard');
      cy.logout();
    },
  );

  it('login with blank inputs or incorrect credentials', () => {
    cy.getDataTest('button-submit').click();
    cy.contains(/Required/i).should('be.visible');

    cy.getDataTest('input-username').find('input').as('inputUsername');
    cy.get('@inputUsername').click();
    cy.get('@inputUsername').type(Cypress.env('umami_user'), { delay: 0 });
    cy.get('@inputUsername').click();
    cy.getDataTest('input-password').find('input').type('wrongpassword', { delay: 0 });
    cy.getDataTest('button-submit').click();
    cy.contains(/Incorrect username and\/or password./i).should('be.visible');
  });
});


================================================
FILE: cypress/e2e/user.cy.ts
================================================
describe('User tests', () => {
  Cypress.session.clearAllSavedSessions();

  beforeEach(() => {
    cy.login(Cypress.env('umami_user'), Cypress.env('umami_password'));
    cy.visit('/settings/users');
  });

  it('Add a User', () => {
    // add user
    cy.contains(/Create user/i).should('be.visible');
    cy.getDataTest('button-create-user').click();
    cy.getDataTest('input-username').find('input').as('inputName').click();
    cy.get('@inputName').type('Test-user', { delay: 0 });
    cy.getDataTest('input-password').find('input').as('inputPassword').click();
    cy.get('@inputPassword').type('testPasswordCypress', { delay: 0 });
    cy.getDataTest('dropdown-role').click();
    cy.getDataTest('dropdown-item-user').click();
    cy.getDataTest('button-submit').click();
    cy.get('td[label="Username"]').should('contain.text', 'Test-user');
    cy.get('td[label="Role"]').should('contain.text', 'User');
  });

  it('Edit a User role and password', () => {
    // edit user
    cy.get('table tbody tr')
      .contains('td', /Test-user/i)
      .parent()
      .within(() => {
        cy.getDataTest('link-button-edit').click(); // Clicks the button inside the row
      });
    cy.getDataTest('input-password').find('input').as('inputPassword').click();
    cy.get('@inputPassword').type('newPassword', { delay: 0 });
    cy.getDataTest('dropdown-role').click();
    cy.getDataTest('dropdown-item-viewOnly').click();
    cy.getDataTest('button-submit').click();

    cy.visit('/settings/users');
    cy.get('table tbody tr')
      .contains('td', /Test-user/i)
      .parent()
      .should('contain.text', 'View only');

    cy.logout();
    cy.url().should('eq', Cypress.config().baseUrl + '/login');
    cy.getDataTest('input-username').find('input').as('inputUsername').click();
    cy.get('@inputUsername').type('Test-user', { delay: 0 });
    cy.get('@inputUsername').click();
    cy.getDataTest('input-password').find('input').type('newPassword', { delay: 0 });
    cy.getDataTest('button-submit').click();
    cy.url().should('eq', Cypress.config().baseUrl + '/dashboard');
  });

  it('Delete a user', () => {
    // delete user
    cy.get('table tbody tr')
      .contains('td', /Test-user/i)
      .parent()
      .within(() => {
        cy.getDataTest('button-delete').click(); // Clicks the button inside the row
      });
    cy.contains(/Are you sure you want to delete Test-user?/i).should('be.visible');
    cy.getDataTest('button-confirm').click();
  });
});


================================================
FILE: cypress/e2e/website.cy.ts
================================================
describe('Website tests', () => {
  Cypress.session.clearAllSavedSessions();

  beforeEach(() => {
    cy.login(Cypress.env('umami_user'), Cypress.env('umami_password'));
  });

  it('Add a website', () => {
    // add website
    cy.visit('/settings/websites');
    cy.getDataTest('button-website-add').click();
    cy.contains(/Add website/i).should('be.visible');
    cy.getDataTest('input-name').find('input').as('inputUsername').click();
    cy.getDataTest('input-name').find('input').type('Add test', { delay: 0 });
    cy.getDataTest('input-domain').find('input').click();
    cy.getDataTest('input-domain').find('input').type('addtest.com', { delay: 0 });
    cy.getDataTest('button-submit').click();
    cy.get('td[label="Name"]').should('contain.text', 'Add test');
    cy.get('td[label="Domain"]').should('contain.text', 'addtest.com');

    // clean-up data
    cy.getDataTest('link-button-edit').first().click();
    cy.contains(/Details/i).should('be.visible');
    cy.getDataTest('text-field-websiteId')
      .find('input')
      .then($input => {
        const websiteId = $input[0].value;
        cy.deleteWebsite(websiteId);
      });
    cy.visit('/settings/websites');
    cy.contains(/Add test/i).should('not.exist');
  });

  it('Edit a website', () => {
    // prep data
    cy.addWebsite('Update test', 'updatetest.com');
    cy.visit('/settings/websites');

    // edit website
    cy.getDataTest('link-button-edit').first().click();
    cy.contains(/Details/i).should('be.visible');
    cy.getDataTest('input-name').find('input').click();
    cy.getDataTest('input-name').find('input').clear();
    cy.getDataTest('input-name').find('input').type('Updated website', { delay: 0 });
    cy.getDataTest('input-domain').find('input').click();
    cy.getDataTest('input-domain').find('input').clear();
    cy.getDataTest('input-domain').find('input').type('updatedwebsite.com', { delay: 0 });
    cy.getDataTest('button-submit').click({ force: true });
    cy.getDataTest('input-name').find('input').should('have.value', 'Updated website');
    cy.getDataTest('input-domain').find('input').should('have.value', 'updatedwebsite.com');

    // verify tracking script
    cy.get('div')
      .contains(/Tracking code/i)
      .click();
    cy.get('textarea').should('contain.text', Cypress.config().baseUrl + '/script.js');

    // clean-up data
    cy.get('div')
      .contains(/Details/i)
      .click();
    cy.contains(/Details/i).should('be.visible');
    cy.getDataTest('text-field-websiteId')
      .find('input')
      .then($input => {
        const websiteId = $input[0].value;
        cy.deleteWebsite(websiteId);
      });
    cy.visit('/settings/websites');
    cy.contains(/Add test/i).should('not.exist');
  });

  it('Delete a website', () => {
    // prep data
    cy.addWebsite('Delete test', 'deletetest.com');
    cy.visit('/settings/websites');

    // delete website
    cy.getDataTest('link-button-edit').first().click();
    cy.contains(/Data/i).should('be.visible');
    cy.get('div').contains(/Data/i).click();
    cy.contains(/All website data will be deleted./i).should('be.visible');
    cy.getDataTest('button-delete').click();
    cy.contains(/Type DELETE in the box below to confirm./i).should('be.visible');
    cy.get('input[name="confirm"').type('DELETE');
    cy.get('button[type="submit"]').click();
    cy.contains(/Delete test/i).should('not.exist');
  });
});


================================================
FILE: cypress/fixtures/teams.json
================================================
{
  "teamCreate": {
    "name": "cypress"
  },
  "teamUpdate": {
    "name": "cypressUpdate"
  }
}


================================================
FILE: cypress/fixtures/users.json
================================================
{
  "userCreate": {
    "username": "cypress1",
    "password": "password",
    "role": "user"
  },
  "userUpdate": {
    "username": "cypress1",
    "role": "view-only"
  }
}


================================================
FILE: cypress/fixtures/websites.json
================================================
{
  "websiteCreate": {
    "name": "Cypress Website",
    "domain": "cypress.com"
  },
  "websiteUpdate": {
    "name": "Cypress Website Updated",
    "domain": "cypressupdated.com"
  }
}


================================================
FILE: cypress/support/e2e.ts
================================================
/// <reference types="cypress" />
import { uuid } from '../../src/lib/crypto';

Cypress.Commands.add('getDataTest', (value: string) => {
  return cy.get(`[data-test=${value}]`);
});

Cypress.Commands.add('logout', () => {
  cy.getDataTest('button-profile').click();
  cy.getDataTest('item-logout').click();
  cy.url().should('eq', Cypress.config().baseUrl + '/login');
});

Cypress.Commands.add('login', (username: string, password: string) => {
  cy.session([username, password], () => {
    cy.request({
      method: 'POST',
      url: '/api/auth/login',
      body: {
        username,
        password,
      },
    })
      .then(response => {
        Cypress.env('authorization', `bearer ${response.body.token}`);
        window.localStorage.setItem('umami.auth', JSON.stringify(response.body.token));
      })
      .its('status')
      .should('eq', 200);
  });
});

Cypress.Commands.add('addWebsite', (name: string, domain: string) => {
  cy.request({
    method: 'POST',
    url: '/api/websites',
    headers: {
      'Content-Type': 'application/json',
      Authorization: Cypress.env('authorization'),
    },
    body: {
      id: uuid(),
      createdBy: '41e2b680-648e-4b09-bcd7-3e2b10c06264',
      name: name,
      domain: domain,
    },
  }).then(response => {
    expect(response.status).to.eq(200);
  });
});

Cypress.Commands.add('deleteWebsite', (websiteId: string) => {
  cy.request({
    method: 'DELETE',
    url: `/api/websites/${websiteId}`,
    headers: {
      'Content-Type': 'application/json',
      Authorization: Cypress.env('authorization'),
    },
  }).then(response => {
    expect(response.status).to.eq(200);
  });
});

Cypress.Commands.add('addUser', (username: string, password: string, role: string) => {
  cy.request({
    method: 'POST',
    url: '/api/users',
    headers: {
      'Content-Type': 'application/json',
      Authorization: Cypress.env('authorization'),
    },
    body: {
      username: username,
      password: password,
      role: role,
    },
  }).then(response => {
    expect(response.status).to.eq(200);
  });
});

Cypress.Commands.add('deleteUser', (userId: string) => {
  cy.request({
    method: 'DELETE',
    url: `/api/users/${userId}`,
    headers: {
      'Content-Type': 'application/json',
      Authorization: Cypress.env('authorization'),
    },
  }).then(response => {
    expect(response.status).to.eq(200);
  });
});

Cypress.Commands.add('addTeam', (name: string) => {
  cy.request({
    method: 'POST',
    url: '/api/teams',
    headers: {
      'Content-Type': 'application/json',
      Authorization: Cypress.env('authorization'),
    },
    body: {
      name: name,
    },
  }).then(response => {
    expect(response.status).to.eq(200);
  });
});

Cypress.Commands.add('deleteTeam', (teamId: string) => {
  cy.request({
    method: 'DELETE',
    url: `/api/teams/${teamId}`,
    headers: {
      'Content-Type': 'application/json',
      Authorization: Cypress.env('authorization'),
    },
  }).then(response => {
    expect(response.status).to.eq(200);
  });
});


================================================
FILE: cypress/support/index.d.ts
================================================
/// <reference types="cypress" />
/* global JQuery */

declare namespace Cypress {
  interface Chainable {
    /**
     * Custom command to select DOM element by data-test attribute.
     * @example cy.getDataTest('greeting')
     */
    getDataTest(value: string): Chainable<JQuery<HTMLElement>>;
    /**
     * Custom command to logout through UI.
     * @example cy.logout()
     */
    logout(): Chainable<JQuery<HTMLElement>>;
    /**
     * Custom command to login user into the app.
     * @example cy.login('admin', 'password)
     */
    login(username: string, password: string): Chainable<JQuery<HTMLElement>>;
    /**
     * Custom command to create a website
     * @example cy.addWebsite('test', 'test.com')
     */
    addWebsite(name: string, domain: string): Chainable<JQuery<HTMLElement>>;
    /**
     * Custom command to delete a website
     * @example cy.deleteWebsite('02d89813-7a72-41e1-87f0-8d668f85008b')
     */
    deleteWebsite(websiteId: string): Chainable<JQuery<HTMLElement>>;
    /**
     * Custom command to create a website
     * @example cy.deleteWebsite('02d89813-7a72-41e1-87f0-8d668f85008b')
     */
    /**
     * Custom command to create a user
     * @example cy.addUser('cypress', 'password', 'User')
     */
    addUser(username: string, password: string, role: string): Chainable<JQuery<HTMLElement>>;
    /**
     * Custom command to delete a user
     * @example cy.deleteUser('02d89813-7a72-41e1-87f0-8d668f85008b')
     */
    deleteUser(userId: string): Chainable<JQuery<HTMLElement>>;
    /**
     * Custom command to create a team
     * @example cy.addTeam('cypressTeam')
     */
    addTeam(name: string): Chainable<JQuery<HTMLElement>>;
    /**
     * Custom command to create a website
     * @example cy.deleteTeam('02d89813-7a72-41e1-87f0-8d668f85008b')
     */
    deleteTeam(teamId: string): Chainable<JQuery<HTMLElement>>;
  }
}


================================================
FILE: cypress/tsconfig.json
================================================
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["es5", "dom"],
    "types": ["cypress", "node"]
  },
  "include": ["**/*.ts", "../cypress.config.ts"]
}


================================================
FILE: cypress.config.ts
================================================
import { defineConfig } from 'cypress';

export default defineConfig({
  e2e: {
    baseUrl: 'http://localhost:3000',
  },
  // default username / password on init
  env: {
    umami_user: 'admin',
    umami_password: 'umami',
    umami_user_id: '41e2b680-648e-4b09-bcd7-3e2b10c06264',
  },
});


================================================
FILE: db/clickhouse/migrations/01_edit_keys.sql
================================================
-- edit event_data values
ALTER TABLE "event_data" RENAME COLUMN "event_date_value" TO "date_value";
ALTER TABLE "event_data" RENAME COLUMN "event_numeric_value" TO "number_value";
ALTER TABLE "event_data" RENAME COLUMN "event_string_value" TO "string_value";
ALTER TABLE "event_data" RENAME COLUMN "event_data_type" TO "data_type";

-- add job_id
ALTER TABLE "website_event" ADD COLUMN "job_id" UUID AFTER "created_at";
ALTER TABLE "event_data" ADD COLUMN "job_id" UUID AFTER "created_at";

-- update event_data string
alter table umami.event_data
update string_value = number_value
where data_type = 2

alter table umami.event_data
update string_value = replaceOne(concat(CAST(toDateTime(date_value, 'UTC'), 'String'),'Z'), ' ', 'T')
where data_type = 4

================================================
FILE: db/clickhouse/migrations/02_add_visit_id.sql
================================================
CREATE TABLE umami.website_event_join
(
    session_id UUID,
    visit_id UUID,
    created_at DateTime('UTC')
)
    engine = MergeTree
        ORDER BY (session_id, created_at)
        SETTINGS index_granularity = 8192;

INSERT INTO umami.website_event_join
SELECT DISTINCT
    s.session_id,
    generateUUIDv4() visit_id,
    s.created_at
FROM (SELECT DISTINCT session_id,
        date_trunc('hour', created_at) created_at
    FROM website_event) s;

-- create new table
CREATE TABLE umami.website_event_new
(
    website_id UUID,
    session_id UUID,
    visit_id UUID,
    event_id UUID,
    hostname LowCardinality(String),
    browser LowCardinality(String),
    os LowCardinality(String),
    device LowCardinality(String),
    screen LowCardinality(String),
    language LowCardinality(String),
    country LowCardinality(String),
    subdivision1 LowCardinality(String),
    subdivision2 LowCardinality(String),
    city String,
    url_path String,
    url_query String,
    referrer_path String,
    referrer_query String,
    referrer_domain String,
    page_title String,
    event_type UInt32,
    event_name String,
    created_at DateTime('UTC'),
    job_id UUID
)
    engine = MergeTree
        ORDER BY (website_id, session_id, created_at)
        SETTINGS index_granularity = 8192;

INSERT INTO umami.website_event_new
SELECT we.website_id,
    we.session_id,
    j.visit_id,
    we.event_id,
    we.hostname,
    we.browser,
    we.os,
    we.device,
    we.screen,
    we.language,
    we.country,
    we.subdivision1,
    we.subdivision2,
    we.city,
    we.url_path,
    we.url_query,
    we.referrer_path,
    we.referrer_query,
    we.referrer_domain,
    we.page_title,
    we.event_type,
    we.event_name,
    we.created_at,
    we.job_id
FROM umami.website_event we
JOIN umami.website_event_join j
    ON we.session_id = j.session_id
        and date_trunc('hour', we.created_at) = j.created_at

RENAME TABLE umami.website_event TO umami.website_event_old;
RENAME TABLE umami.website_event_new TO umami.website_event;

/*

 DROP TABLE umami.website_event_old
 DROP TABLE umami.website_event_join

 */

================================================
FILE: db/clickhouse/migrations/03_session_data.sql
================================================
CREATE TABLE umami.event_data_new
(
    website_id UUID,
    session_id UUID,
    event_id UUID,
    url_path String,
    event_name String,
    data_key String,
    string_value Nullable(String),
    number_value Nullable(Decimal64(4)),
    date_value Nullable(DateTime('UTC')),
    data_type UInt32,
    created_at DateTime('UTC'),
    job_id Nullable(UUID)
)
    engine = MergeTree
        ORDER BY (website_id, event_id, data_key, created_at)
        SETTINGS index_granularity = 8192;

INSERT INTO umami.event_data_new
SELECT website_id,
    session_id,
    event_id,
    url_path,
    event_name,
    event_key,
    string_value,
    number_value,
    date_value,
    data_type,
    created_at,
    NULL
FROM umami.event_data;

CREATE TABLE umami.session_data
(
    website_id UUID,
    session_id UUID,
    data_key String,
    string_value Nullable(String),
    number_value Nullable(Decimal64(4)),
    date_value Nullable(DateTime('UTC')),
    data_type UInt32,
    created_at DateTime('UTC'),
    job_id Nullable(UUID)
)
    engine = MergeTree
        ORDER BY (website_id, session_id, data_key, created_at)
        SETTINGS index_granularity = 8192;

RENAME TABLE umami.event_data TO umami.event_data_old;
RENAME TABLE umami.event_data_new TO umami.event_data;

/*
DROP TABLE umami.event_data_old
 */



================================================
FILE: db/clickhouse/migrations/04_add_tag.sql
================================================
-- add tag column
ALTER TABLE umami.website_event ADD COLUMN "tag" String AFTER "event_name";
ALTER TABLE umami.website_event_stats_hourly ADD COLUMN "tag" SimpleAggregateFunction(groupArrayArray, Array(String)) AFTER "max_time";

-- update materialized view
DROP TABLE umami.website_event_stats_hourly_mv;

CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv
TO umami.website_event_stats_hourly
AS
SELECT
    website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    subdivision1,
    city,
    entry_url,
    exit_url,
    url_paths as url_path,
    url_query,
    referrer_domain,
    page_title,
    event_type,
    event_name,
    views,
    min_time,
    max_time,
    tag,
    timestamp as created_at
FROM (SELECT
    website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    subdivision1,
    city,
    argMinState(url_path, created_at) entry_url,
    argMaxState(url_path, created_at) exit_url,
    arrayFilter(x -> x != '', groupArray(url_path)) as url_paths,
    arrayFilter(x -> x != '', groupArray(url_query)) url_query,
    arrayFilter(x -> x != '', groupArray(referrer_domain)) referrer_domain,
    arrayFilter(x -> x != '', groupArray(page_title)) page_title,
    event_type,
    if(event_type = 2, groupArray(event_name), []) event_name,
    sumIf(1, event_type = 1) views,
    min(created_at) min_time,
    max(created_at) max_time,
    arrayFilter(x -> x != '', groupArray(tag)) tag,
    toStartOfHour(created_at) timestamp
FROM umami.website_event
GROUP BY website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    subdivision1,
    city,
    event_type,
    timestamp);

================================================
FILE: db/clickhouse/migrations/05_add_utm_clid.sql
================================================
-- Create Event
CREATE TABLE umami.website_event_new
(
    website_id UUID,
    session_id UUID,
    visit_id UUID,
    event_id UUID,
    --sessions
    hostname LowCardinality(String),
    browser LowCardinality(String),
    os LowCardinality(String),
    device LowCardinality(String),
    screen LowCardinality(String),
    language LowCardinality(String),
    country LowCardinality(String),
    subdivision1 LowCardinality(String),
    subdivision2 LowCardinality(String),
    city String,
    --pageviews
    url_path String,
    url_query String,
    utm_source String,
    utm_medium String,
    utm_campaign String,
    utm_content String,
    utm_term String,
    referrer_path String,
    referrer_query String,
    referrer_domain String,
    page_title String,
    --clickIDs
    gclid String,
    fbclid String,
    msclkid String,
    ttclid String,
    li_fat_id String,
    twclid String,
    --events
    event_type UInt32,
    event_name String,
    tag String,
    created_at DateTime('UTC'),
    job_id Nullable(UUID)
)
ENGINE = MergeTree
    PARTITION BY toYYYYMM(created_at)
    ORDER BY (toStartOfHour(created_at), website_id, session_id, visit_id, created_at)
    PRIMARY KEY (toStartOfHour(created_at), website_id, session_id, visit_id)
    SETTINGS index_granularity = 8192;

-- stats hourly
CREATE TABLE umami.website_event_stats_hourly_new
(
    website_id UUID,
    session_id UUID,
    visit_id UUID,
    hostname LowCardinality(String),
    browser LowCardinality(String),
    os LowCardinality(String),
    device LowCardinality(String),
    screen LowCardinality(String),
    language LowCardinality(String),
    country LowCardinality(String),
    subdivision1 LowCardinality(String),
    city String,
    entry_url AggregateFunction(argMin, String, DateTime('UTC')),
    exit_url AggregateFunction(argMax, String, DateTime('UTC')),
    url_path SimpleAggregateFunction(groupArrayArray, Array(String)),
    url_query SimpleAggregateFunction(groupArrayArray, Array(String)),
    utm_source SimpleAggregateFunction(groupArrayArray, Array(String)),
    utm_medium SimpleAggregateFunction(groupArrayArray, Array(String)),
    utm_campaign SimpleAggregateFunction(groupArrayArray, Array(String)),
    utm_content SimpleAggregateFunction(groupArrayArray, Array(String)),
    utm_term SimpleAggregateFunction(groupArrayArray, Array(String)),
    referrer_domain SimpleAggregateFunction(groupArrayArray, Array(String)),
    page_title SimpleAggregateFunction(groupArrayArray, Array(String)),
    gclid SimpleAggregateFunction(groupArrayArray, Array(String)),
    fbclid SimpleAggregateFunction(groupArrayArray, Array(String)),
    msclkid SimpleAggregateFunction(groupArrayArray, Array(String)),
    ttclid SimpleAggregateFunction(groupArrayArray, Array(String)),
    li_fat_id SimpleAggregateFunction(groupArrayArray, Array(String)),
    twclid SimpleAggregateFunction(groupArrayArray, Array(String)),
    event_type UInt32,
    event_name SimpleAggregateFunction(groupArrayArray, Array(String)),
    views SimpleAggregateFunction(sum, UInt64),
    min_time SimpleAggregateFunction(min, DateTime('UTC')),
    max_time SimpleAggregateFunction(max, DateTime('UTC')),
    tag SimpleAggregateFunction(groupArrayArray, Array(String)),
    created_at Datetime('UTC')
)
ENGINE = AggregatingMergeTree
    PARTITION BY toYYYYMM(created_at)
    ORDER BY (
        website_id,
        event_type,
        toStartOfHour(created_at),
        cityHash64(visit_id),
        visit_id
    )
    SAMPLE BY cityHash64(visit_id);

CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv_new
TO umami.website_event_stats_hourly_new
AS
SELECT
    website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    subdivision1,
    city,
    entry_url,
    exit_url,
    url_paths as url_path,
    url_query,
    utm_source,
    utm_medium,
    utm_campaign,
    utm_content,
    utm_term,
    referrer_domain,
    page_title,
    gclid,
    fbclid,
    msclkid,
    ttclid,
    li_fat_id,
    twclid,
    event_type,
    event_name,
    views,
    min_time,
    max_time,
    tag,
    timestamp as created_at
FROM (SELECT
    website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    subdivision1,
    city,
    argMinState(url_path, created_at) entry_url,
    argMaxState(url_path, created_at) exit_url,
    arrayFilter(x -> x != '', groupArray(url_path)) as url_paths,
    arrayFilter(x -> x != '', groupArray(url_query)) url_query,
    arrayFilter(x -> x != '', groupArray(utm_source)) utm_source,
    arrayFilter(x -> x != '', groupArray(utm_medium)) utm_medium,
    arrayFilter(x -> x != '', groupArray(utm_campaign)) utm_campaign,
    arrayFilter(x -> x != '', groupArray(utm_content)) utm_content,
    arrayFilter(x -> x != '', groupArray(utm_term)) utm_term,
    arrayFilter(x -> x != '', groupArray(referrer_domain)) referrer_domain,
    arrayFilter(x -> x != '', groupArray(page_title)) page_title,
    arrayFilter(x -> x != '', groupArray(gclid)) gclid,
    arrayFilter(x -> x != '', groupArray(fbclid)) fbclid,
    arrayFilter(x -> x != '', groupArray(msclkid)) msclkid,
    arrayFilter(x -> x != '', groupArray(ttclid)) ttclid,
    arrayFilter(x -> x != '', groupArray(li_fat_id)) li_fat_id,
    arrayFilter(x -> x != '', groupArray(twclid)) twclid,
    event_type,
    if(event_type = 2, groupArray(event_name), []) event_name,
    sumIf(1, event_type = 1) views,
    min(created_at) min_time,
    max(created_at) max_time,
    arrayFilter(x -> x != '', groupArray(tag)) tag,
    toStartOfHour(created_at) timestamp
FROM umami.website_event_new
GROUP BY website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    subdivision1,
    city,
    event_type,
    timestamp);

-- projections
ALTER TABLE umami.website_event_new
ADD PROJECTION website_event_url_path_projection (
SELECT * ORDER BY toStartOfDay(created_at), website_id, url_path, created_at
);

ALTER TABLE umami.website_event_new MATERIALIZE PROJECTION website_event_url_path_projection;

ALTER TABLE umami.website_event_new
ADD PROJECTION website_event_referrer_domain_projection (
SELECT * ORDER BY toStartOfDay(created_at), website_id, referrer_domain, created_at
);

ALTER TABLE umami.website_event_new MATERIALIZE PROJECTION website_event_referrer_domain_projection;

-- migration
INSERT INTO umami.website_event_new
SELECT website_id, session_id, visit_id, event_id, hostname, browser, os, device, screen, language, country, subdivision1, subdivision2, city, url_path, url_query,
    extract(url_query, 'utm_source=([^&]*)') AS utm_source,
    extract(url_query, 'utm_medium=([^&]*)') AS utm_medium,
    extract(url_query, 'utm_campaign=([^&]*)') AS utm_campaign,
    extract(url_query, 'utm_content=([^&]*)') AS utm_content,
    extract(url_query, 'utm_term=([^&]*)') AS utm_term,referrer_path, referrer_query, referrer_domain,
    page_title,
    extract(url_query, 'gclid=([^&]*)') gclid,
    extract(url_query, 'fbclid=([^&]*)') fbclid,
    extract(url_query, 'msclkid=([^&]*)') msclkid,
    extract(url_query, 'ttclid=([^&]*)') ttclid,
    extract(url_query, 'li_fat_id=([^&]*)') li_fat_id,
    extract(url_query, 'twclid=([^&]*)') twclid,
    event_type, event_name, tag, created_at, job_id
FROM umami.website_event

-- rename tables
RENAME TABLE umami.website_event TO umami.website_event_old;
RENAME TABLE umami.website_event_new TO umami.website_event;

RENAME TABLE umami.website_event_stats_hourly TO umami.website_event_stats_hourly_old;
RENAME TABLE umami.website_event_stats_hourly_new TO umami.website_event_stats_hourly;

RENAME TABLE umami.website_event_stats_hourly_mv TO umami.website_event_stats_hourly_mv_old;
RENAME TABLE umami.website_event_stats_hourly_mv_new TO umami.website_event_stats_hourly_mv;

-- recreate view
DROP TABLE umami.website_event_stats_hourly_mv;

CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv
TO umami.website_event_stats_hourly
AS
SELECT
    website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    subdivision1,
    city,
    entry_url,
    exit_url,
    url_paths as url_path,
    url_query,
    utm_source,
    utm_medium,
    utm_campaign,
    utm_content,
    utm_term,
    referrer_domain,
    page_title,
    gclid,
    fbclid,
    msclkid,
    ttclid,
    li_fat_id,
    twclid,
    event_type,
    event_name,
    views,
    min_time,
    max_time,
    tag,
    timestamp as created_at
FROM (SELECT
    website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    subdivision1,
    city,
    argMinState(url_path, created_at) entry_url,
    argMaxState(url_path, created_at) exit_url,
    arrayFilter(x -> x != '', groupArray(url_path)) as url_paths,
    arrayFilter(x -> x != '', groupArray(url_query)) url_query,
    arrayFilter(x -> x != '', groupArray(utm_source)) utm_source,
    arrayFilter(x -> x != '', groupArray(utm_medium)) utm_medium,
    arrayFilter(x -> x != '', groupArray(utm_campaign)) utm_campaign,
    arrayFilter(x -> x != '', groupArray(utm_content)) utm_content,
    arrayFilter(x -> x != '', groupArray(utm_term)) utm_term,
    arrayFilter(x -> x != '', groupArray(referrer_domain)) referrer_domain,
    arrayFilter(x -> x != '', groupArray(page_title)) page_title,
    arrayFilter(x -> x != '', groupArray(gclid)) gclid,
    arrayFilter(x -> x != '', groupArray(fbclid)) fbclid,
    arrayFilter(x -> x != '', groupArray(msclkid)) msclkid,
    arrayFilter(x -> x != '', groupArray(ttclid)) ttclid,
    arrayFilter(x -> x != '', groupArray(li_fat_id)) li_fat_id,
    arrayFilter(x -> x != '', groupArray(twclid)) twclid,
    event_type,
    if(event_type = 2, groupArray(event_name), []) event_name,
    sumIf(1, event_type = 1) views,
    min(created_at) min_time,
    max(created_at) max_time,
    arrayFilter(x -> x != '', groupArray(tag)) tag,
    toStartOfHour(created_at) timestamp
FROM umami.website_event
GROUP BY website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    subdivision1,
    city,
    event_type,
    timestamp);

================================================
FILE: db/clickhouse/migrations/06_update_subdivision.sql
================================================
-- drop projections
ALTER TABLE umami.website_event  DROP PROJECTION website_event_url_path_projection;
ALTER TABLE umami.website_event  DROP PROJECTION website_event_referrer_domain_projection;

--drop view
DROP TABLE umami.website_event_stats_hourly_mv;

-- rename columns
ALTER TABLE umami.website_event RENAME COLUMN "subdivision1" TO "region";
ALTER TABLE umami.website_event_stats_hourly RENAME COLUMN "subdivision1" TO "region";

-- drop columns
ALTER TABLE umami.website_event DROP COLUMN "subdivision2";

-- recreate projections
ALTER TABLE umami.website_event 
ADD PROJECTION website_event_url_path_projection (
SELECT * ORDER BY toStartOfDay(created_at), website_id, url_path, created_at
);

ALTER TABLE umami.website_event MATERIALIZE PROJECTION website_event_url_path_projection;

ALTER TABLE umami.website_event 
ADD PROJECTION website_event_referrer_domain_projection (
SELECT * ORDER BY toStartOfDay(created_at), website_id, referrer_domain, created_at
);

ALTER TABLE umami.website_event MATERIALIZE PROJECTION website_event_referrer_domain_projection;

-- recreate view
CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv
TO umami.website_event_stats_hourly
AS
SELECT
    website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    region,
    city,
    entry_url,
    exit_url,
    url_paths as url_path,
    url_query,
    utm_source,
    utm_medium,
    utm_campaign,
    utm_content,
    utm_term,
    referrer_domain,
    page_title,
    gclid,
    fbclid,
    msclkid,
    ttclid,
    li_fat_id,
    twclid,
    event_type,
    event_name,
    views,
    min_time,
    max_time,
    tag,
    timestamp as created_at
FROM (SELECT
    website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    region,
    city,
    argMinState(url_path, created_at) entry_url,
    argMaxState(url_path, created_at) exit_url,
    arrayFilter(x -> x != '', groupArray(url_path)) as url_paths,
    arrayFilter(x -> x != '', groupArray(url_query)) url_query,
    arrayFilter(x -> x != '', groupArray(utm_source)) utm_source,
    arrayFilter(x -> x != '', groupArray(utm_medium)) utm_medium,
    arrayFilter(x -> x != '', groupArray(utm_campaign)) utm_campaign,
    arrayFilter(x -> x != '', groupArray(utm_content)) utm_content,
    arrayFilter(x -> x != '', groupArray(utm_term)) utm_term,
    arrayFilter(x -> x != '', groupArray(referrer_domain)) referrer_domain,
    arrayFilter(x -> x != '', groupArray(page_title)) page_title,
    arrayFilter(x -> x != '', groupArray(gclid)) gclid,
    arrayFilter(x -> x != '', groupArray(fbclid)) fbclid,
    arrayFilter(x -> x != '', groupArray(msclkid)) msclkid,
    arrayFilter(x -> x != '', groupArray(ttclid)) ttclid,
    arrayFilter(x -> x != '', groupArray(li_fat_id)) li_fat_id,
    arrayFilter(x -> x != '', groupArray(twclid)) twclid,
    event_type,
    if(event_type = 2, groupArray(event_name), []) event_name,
    sumIf(1, event_type = 1) views,
    min(created_at) min_time,
    max(created_at) max_time,
    arrayFilter(x -> x != '', groupArray(tag)) tag,
    toStartOfHour(created_at) timestamp
FROM umami.website_event
GROUP BY website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    region,
    city,
    event_type,
    timestamp);

================================================
FILE: db/clickhouse/migrations/07_add_distinct_id.sql
================================================
-- add tag column
ALTER TABLE umami.website_event ADD COLUMN "distinct_id" String AFTER "tag";
ALTER TABLE umami.website_event_stats_hourly ADD COLUMN "distinct_id" String AFTER "tag";
ALTER TABLE umami.session_data ADD COLUMN "distinct_id" String AFTER "data_type";

-- update materialized view
DROP TABLE umami.website_event_stats_hourly_mv;

CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv
TO umami.website_event_stats_hourly
AS
SELECT
    website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    region,
    city,
    entry_url,
    exit_url,
    url_paths as url_path,
    url_query,
    utm_source,
    utm_medium,
    utm_campaign,
    utm_content,
    utm_term,
    referrer_domain,
    page_title,
    gclid,
    fbclid,
    msclkid,
    ttclid,
    li_fat_id,
    twclid,
    event_type,
    event_name,
    views,
    min_time,
    max_time,
    tag,
    distinct_id,
    timestamp as created_at
FROM (SELECT
    website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    region,
    city,
    argMinState(url_path, created_at) entry_url,
    argMaxState(url_path, created_at) exit_url,
    arrayFilter(x -> x != '', groupArray(url_path)) as url_paths,
    arrayFilter(x -> x != '', groupArray(url_query)) url_query,
    arrayFilter(x -> x != '', groupArray(utm_source)) utm_source,
    arrayFilter(x -> x != '', groupArray(utm_medium)) utm_medium,
    arrayFilter(x -> x != '', groupArray(utm_campaign)) utm_campaign,
    arrayFilter(x -> x != '', groupArray(utm_content)) utm_content,
    arrayFilter(x -> x != '', groupArray(utm_term)) utm_term,
    arrayFilter(x -> x != '', groupArray(referrer_domain)) referrer_domain,
    arrayFilter(x -> x != '', groupArray(page_title)) page_title,
    arrayFilter(x -> x != '', groupArray(gclid)) gclid,
    arrayFilter(x -> x != '', groupArray(fbclid)) fbclid,
    arrayFilter(x -> x != '', groupArray(msclkid)) msclkid,
    arrayFilter(x -> x != '', groupArray(ttclid)) ttclid,
    arrayFilter(x -> x != '', groupArray(li_fat_id)) li_fat_id,
    arrayFilter(x -> x != '', groupArray(twclid)) twclid,
    event_type,
    if(event_type = 2, groupArray(event_name), []) event_name,
    sumIf(1, event_type = 1) views,
    min(created_at) min_time,
    max(created_at) max_time,
    arrayFilter(x -> x != '', groupArray(tag)) tag,
    distinct_id,
    toStartOfHour(created_at) timestamp
FROM umami.website_event
GROUP BY website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    region,
    city,
    event_type,
    distinct_id,
    timestamp);

================================================
FILE: db/clickhouse/migrations/08_update_hostname_view.sql
================================================
-- create new hourly table
CREATE TABLE umami.website_event_stats_hourly_new
(
    website_id UUID,
    session_id UUID,
    visit_id UUID,
    hostname SimpleAggregateFunction(groupArrayArray, Array(String)),
    browser LowCardinality(String),
    os LowCardinality(String),
    device LowCardinality(String),
    screen LowCardinality(String),
    language LowCardinality(String),
    country LowCardinality(String),
    region LowCardinality(String),
    city String,
    entry_url AggregateFunction(argMin, String, DateTime('UTC')),
    exit_url AggregateFunction(argMax, String, DateTime('UTC')),
    url_path SimpleAggregateFunction(groupArrayArray, Array(String)),
    url_query SimpleAggregateFunction(groupArrayArray, Array(String)),
    utm_source SimpleAggregateFunction(groupArrayArray, Array(String)),
    utm_medium SimpleAggregateFunction(groupArrayArray, Array(String)),
    utm_campaign SimpleAggregateFunction(groupArrayArray, Array(String)),
    utm_content SimpleAggregateFunction(groupArrayArray, Array(String)),
    utm_term SimpleAggregateFunction(groupArrayArray, Array(String)),
    referrer_domain SimpleAggregateFunction(groupArrayArray, Array(String)),
    page_title SimpleAggregateFunction(groupArrayArray, Array(String)),
    gclid SimpleAggregateFunction(groupArrayArray, Array(String)),
    fbclid SimpleAggregateFunction(groupArrayArray, Array(String)),
    msclkid SimpleAggregateFunction(groupArrayArray, Array(String)),
    ttclid SimpleAggregateFunction(groupArrayArray, Array(String)),
    li_fat_id SimpleAggregateFunction(groupArrayArray, Array(String)),
    twclid SimpleAggregateFunction(groupArrayArray, Array(String)),
    event_type UInt32,
    event_name SimpleAggregateFunction(groupArrayArray, Array(String)),
    views SimpleAggregateFunction(sum, UInt64),
    min_time SimpleAggregateFunction(min, DateTime('UTC')),
    max_time SimpleAggregateFunction(max, DateTime('UTC')),
    tag SimpleAggregateFunction(groupArrayArray, Array(String)),
    distinct_id String,
    created_at Datetime('UTC')
)
ENGINE = AggregatingMergeTree
    PARTITION BY toYYYYMM(created_at)
    ORDER BY (
        website_id,
        event_type,
        toStartOfHour(created_at),
        cityHash64(visit_id),
        visit_id
    )
    SAMPLE BY cityHash64(visit_id);

-- create view
CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv_new
TO umami.website_event_stats_hourly_new
AS
SELECT
    website_id,
    session_id,
    visit_id,
    hostnames as hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    region,
    city,
    entry_url,
    exit_url,
    url_paths as url_path,
    url_query,
    utm_source,
    utm_medium,
    utm_campaign,
    utm_content,
    utm_term,
    referrer_domain,
    page_title,
    gclid,
    fbclid,
    msclkid,
    ttclid,
    li_fat_id,
    twclid,
    event_type,
    event_name,
    views,
    min_time,
    max_time,
    tag,
    distinct_id,
    timestamp as created_at
FROM (SELECT
    website_id,
    session_id,
    visit_id,
    arrayFilter(x -> x != '', groupArray(hostname)) hostnames,
    browser,
    os,
    device,
    screen,
    language,
    country,
    region,
    city,
    argMinState(url_path, created_at) entry_url,
    argMaxState(url_path, created_at) exit_url,
    arrayFilter(x -> x != '', groupArray(url_path)) as url_paths,
    arrayFilter(x -> x != '', groupArray(url_query)) url_query,
    arrayFilter(x -> x != '', groupArray(utm_source)) utm_source,
    arrayFilter(x -> x != '', groupArray(utm_medium)) utm_medium,
    arrayFilter(x -> x != '', groupArray(utm_campaign)) utm_campaign,
    arrayFilter(x -> x != '', groupArray(utm_content)) utm_content,
    arrayFilter(x -> x != '', groupArray(utm_term)) utm_term,
    arrayFilter(x -> x != '' and x != hostname, groupArray(referrer_domain)) referrer_domain,
    arrayFilter(x -> x != '', groupArray(page_title)) page_title,
    arrayFilter(x -> x != '', groupArray(gclid)) gclid,
    arrayFilter(x -> x != '', groupArray(fbclid)) fbclid,
    arrayFilter(x -> x != '', groupArray(msclkid)) msclkid,
    arrayFilter(x -> x != '', groupArray(ttclid)) ttclid,
    arrayFilter(x -> x != '', groupArray(li_fat_id)) li_fat_id,
    arrayFilter(x -> x != '', groupArray(twclid)) twclid,
    event_type,
    if(event_type = 2, groupArray(event_name), []) event_name,
    sumIf(1, event_type = 1) views,
    min(created_at) min_time,
    max(created_at) max_time,
    arrayFilter(x -> x != '', groupArray(tag)) tag,
    distinct_id,
    toStartOfHour(created_at) timestamp
FROM umami.website_event
GROUP BY website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    region,
    city,
    event_type,
    distinct_id,
    timestamp);

-- rename tables
RENAME TABLE umami.website_event_stats_hourly TO umami.website_event_stats_hourly_old;
RENAME TABLE umami.website_event_stats_hourly_new TO umami.website_event_stats_hourly;

-- drop views
DROP TABLE umami.website_event_stats_hourly_mv;
DROP TABLE umami.website_event_stats_hourly_mv_new;

-- recreate view
CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv
TO umami.website_event_stats_hourly
AS
SELECT
    website_id,
    session_id,
    visit_id,
    hostnames as hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    region,
    city,
    entry_url,
    exit_url,
    url_paths as url_path,
    url_query,
    utm_source,
    utm_medium,
    utm_campaign,
    utm_content,
    utm_term,
    referrer_domain,
    page_title,
    gclid,
    fbclid,
    msclkid,
    ttclid,
    li_fat_id,
    twclid,
    event_type,
    event_name,
    views,
    min_time,
    max_time,
    tag,
    distinct_id,
    timestamp as created_at
FROM (SELECT
    website_id,
    session_id,
    visit_id,
    arrayFilter(x -> x != '', groupArray(hostname)) hostnames,
    browser,
    os,
    device,
    screen,
    language,
    country,
    region,
    city,
    argMinState(url_path, created_at) entry_url,
    argMaxState(url_path, created_at) exit_url,
    arrayFilter(x -> x != '', groupArray(url_path)) as url_paths,
    arrayFilter(x -> x != '', groupArray(url_query)) url_query,
    arrayFilter(x -> x != '', groupArray(utm_source)) utm_source,
    arrayFilter(x -> x != '', groupArray(utm_medium)) utm_medium,
    arrayFilter(x -> x != '', groupArray(utm_campaign)) utm_campaign,
    arrayFilter(x -> x != '', groupArray(utm_content)) utm_content,
    arrayFilter(x -> x != '', groupArray(utm_term)) utm_term,
    arrayFilter(x -> x != '' and x != hostname, groupArray(referrer_domain)) referrer_domain,
    arrayFilter(x -> x != '', groupArray(page_title)) page_title,
    arrayFilter(x -> x != '', groupArray(gclid)) gclid,
    arrayFilter(x -> x != '', groupArray(fbclid)) fbclid,
    arrayFilter(x -> x != '', groupArray(msclkid)) msclkid,
    arrayFilter(x -> x != '', groupArray(ttclid)) ttclid,
    arrayFilter(x -> x != '', groupArray(li_fat_id)) li_fat_id,
    arrayFilter(x -> x != '', groupArray(twclid)) twclid,
    event_type,
    if(event_type = 2, groupArray(event_name), []) event_name,
    sumIf(1, event_type = 1) views,
    min(created_at) min_time,
    max(created_at) max_time,
    arrayFilter(x -> x != '', groupArray(tag)) tag,
    distinct_id,
    toStartOfHour(created_at) timestamp
FROM umami.website_event
GROUP BY website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    region,
    city,
    event_type,
    distinct_id,
    timestamp);


================================================
FILE: db/clickhouse/schema.sql
================================================
-- Create Event
CREATE TABLE umami.website_event
(
    website_id UUID,
    session_id UUID,
    visit_id UUID,
    event_id UUID,
    --sessions
    hostname LowCardinality(String),
    browser LowCardinality(String),
    os LowCardinality(String),
    device LowCardinality(String),
    screen LowCardinality(String),
    language LowCardinality(String),
    country LowCardinality(String),
    region LowCardinality(String),
    city String,
    --pageviews
    url_path String,
    url_query String,
    utm_source String,
    utm_medium String,
    utm_campaign String,
    utm_content String,
    utm_term String,
    referrer_path String,
    referrer_query String,
    referrer_domain String,
    page_title String,
    --clickIDs
    gclid String,
    fbclid String,
    msclkid String,
    ttclid String,
    li_fat_id String,
    twclid String,
    --events
    event_type UInt32,
    event_name String,
    tag String,
    distinct_id String,
    created_at DateTime('UTC'),
    job_id Nullable(UUID)
)
ENGINE = MergeTree
    PARTITION BY toYYYYMM(created_at)
    ORDER BY (toStartOfHour(created_at), website_id, session_id, visit_id, created_at)
    PRIMARY KEY (toStartOfHour(created_at), website_id, session_id, visit_id)
    SETTINGS index_granularity = 8192;

CREATE TABLE umami.event_data
(
    website_id UUID,
    session_id UUID,
    event_id UUID,
    url_path String,
    event_name String,
    data_key String,
    string_value Nullable(String),
    number_value Nullable(Decimal(22, 4)),
    date_value Nullable(DateTime('UTC')),
    data_type UInt32,
    created_at DateTime('UTC'),
    job_id Nullable(UUID)
)
ENGINE = MergeTree
    ORDER BY (website_id, event_id, data_key, created_at)
    SETTINGS index_granularity = 8192;

CREATE TABLE umami.session_data
(
    website_id UUID,
    session_id UUID,
    data_key String,
    string_value Nullable(String),
    number_value Nullable(Decimal(22, 4)),
    date_value Nullable(DateTime('UTC')),
    data_type UInt32,
    distinct_id String,
    created_at DateTime('UTC'),
    job_id Nullable(UUID)
)
ENGINE = ReplacingMergeTree
    ORDER BY (website_id, session_id, data_key)
    SETTINGS index_granularity = 8192;

-- stats hourly
CREATE TABLE umami.website_event_stats_hourly
(
    website_id UUID,
    session_id UUID,
    visit_id UUID,
    hostname SimpleAggregateFunction(groupArrayArray, Array(String)),
    browser LowCardinality(String),
    os LowCardinality(String),
    device LowCardinality(String),
    screen LowCardinality(String),
    language LowCardinality(String),
    country LowCardinality(String),
    region LowCardinality(String),
    city String,
    entry_url AggregateFunction(argMin, String, DateTime('UTC')),
    exit_url AggregateFunction(argMax, String, DateTime('UTC')),
    url_path SimpleAggregateFunction(groupArrayArray, Array(String)),
    url_query SimpleAggregateFunction(groupArrayArray, Array(String)),
    utm_source SimpleAggregateFunction(groupArrayArray, Array(String)),
    utm_medium SimpleAggregateFunction(groupArrayArray, Array(String)),
    utm_campaign SimpleAggregateFunction(groupArrayArray, Array(String)),
    utm_content SimpleAggregateFunction(groupArrayArray, Array(String)),
    utm_term SimpleAggregateFunction(groupArrayArray, Array(String)),
    referrer_domain SimpleAggregateFunction(groupArrayArray, Array(String)),
    page_title SimpleAggregateFunction(groupArrayArray, Array(String)),
    gclid SimpleAggregateFunction(groupArrayArray, Array(String)),
    fbclid SimpleAggregateFunction(groupArrayArray, Array(String)),
    msclkid SimpleAggregateFunction(groupArrayArray, Array(String)),
    ttclid SimpleAggregateFunction(groupArrayArray, Array(String)),
    li_fat_id SimpleAggregateFunction(groupArrayArray, Array(String)),
    twclid SimpleAggregateFunction(groupArrayArray, Array(String)),
    event_type UInt32,
    event_name SimpleAggregateFunction(groupArrayArray, Array(String)),
    views SimpleAggregateFunction(sum, UInt64),
    min_time SimpleAggregateFunction(min, DateTime('UTC')),
    max_time SimpleAggregateFunction(max, DateTime('UTC')),
    tag SimpleAggregateFunction(groupArrayArray, Array(String)),
    distinct_id String,
    created_at Datetime('UTC')
)
ENGINE = AggregatingMergeTree
    PARTITION BY toYYYYMM(created_at)
    ORDER BY (
        website_id,
        event_type,
        toStartOfHour(created_at),
        cityHash64(visit_id),
        visit_id
    )
    SAMPLE BY cityHash64(visit_id);

CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv
TO umami.website_event_stats_hourly
AS
SELECT
    website_id,
    session_id,
    visit_id,
    hostnames as hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    region,
    city,
    entry_url,
    exit_url,
    url_paths as url_path,
    url_query,
    utm_source,
    utm_medium,
    utm_campaign,
    utm_content,
    utm_term,
    referrer_domain,
    page_title,
    gclid,
    fbclid,
    msclkid,
    ttclid,
    li_fat_id,
    twclid,
    event_type,
    event_name,
    views,
    min_time,
    max_time,
    tag,
    distinct_id,
    timestamp as created_at
FROM (SELECT
    website_id,
    session_id,
    visit_id,
    arrayFilter(x -> x != '', groupArray(hostname)) hostnames,
    browser,
    os,
    device,
    screen,
    language,
    country,
    region,
    city,
    argMinState(url_path, created_at) entry_url,
    argMaxState(url_path, created_at) exit_url,
    arrayFilter(x -> x != '', groupArray(url_path)) as url_paths,
    arrayFilter(x -> x != '', groupArray(url_query)) url_query,
    arrayFilter(x -> x != '', groupArray(utm_source)) utm_source,
    arrayFilter(x -> x != '', groupArray(utm_medium)) utm_medium,
    arrayFilter(x -> x != '', groupArray(utm_campaign)) utm_campaign,
    arrayFilter(x -> x != '', groupArray(utm_content)) utm_content,
    arrayFilter(x -> x != '', groupArray(utm_term)) utm_term,
    arrayFilter(x -> x != '' and x != hostname, groupArray(referrer_domain)) referrer_domain,
    arrayFilter(x -> x != '', groupArray(page_title)) page_title,
    arrayFilter(x -> x != '', groupArray(gclid)) gclid,
    arrayFilter(x -> x != '', groupArray(fbclid)) fbclid,
    arrayFilter(x -> x != '', groupArray(msclkid)) msclkid,
    arrayFilter(x -> x != '', groupArray(ttclid)) ttclid,
    arrayFilter(x -> x != '', groupArray(li_fat_id)) li_fat_id,
    arrayFilter(x -> x != '', groupArray(twclid)) twclid,
    event_type,
    if(event_type = 2, groupArray(event_name), []) event_name,
    sumIf(1, event_type != 2) views,
    min(created_at) min_time,
    max(created_at) max_time,
    arrayFilter(x -> x != '', groupArray(tag)) tag,
    distinct_id,
    toStartOfHour(created_at) timestamp
FROM umami.website_event
GROUP BY website_id,
    session_id,
    visit_id,
    hostname,
    browser,
    os,
    device,
    screen,
    language,
    country,
    region,
    city,
    event_type,
    distinct_id,
    timestamp);

-- projections
ALTER TABLE umami.website_event 
ADD PROJECTION website_event_url_path_projection (
SELECT * ORDER BY toStartOfDay(created_at), website_id, url_path, created_at
);

ALTER TABLE umami.website_event MATERIALIZE PROJECTION website_event_url_path_projection;

ALTER TABLE umami.website_event 
ADD PROJECTION website_event_referrer_domain_projection (
SELECT * ORDER BY toStartOfDay(created_at), website_id, referrer_domain, created_at
);

ALTER TABLE umami.website_event MATERIALIZE PROJECTION website_event_referrer_domain_projection;

-- revenue
CREATE TABLE umami.website_revenue
(
    website_id UUID,
    session_id UUID,
    event_id UUID,
    event_name String,
    currency String,
    revenue DECIMAL(18,4),
    created_at DateTime('UTC')
)
ENGINE = MergeTree
    PARTITION BY toYYYYMM(created_at)
    ORDER BY (website_id, session_id, created_at)
    SETTINGS index_granularity = 8192;


CREATE MATERIALIZED VIEW umami.website_revenue_mv
TO umami.website_revenue
AS
SELECT DISTINCT
    ed.website_id,
    ed.session_id,
    ed.event_id,
    ed.event_name,
    c.currency,
    coalesce(toDecimal64(ed.number_value, 2), toDecimal64(ed.string_value, 2)) revenue,
    ed.created_at
FROM umami.event_data ed
JOIN (SELECT event_id, string_value as currency
        FROM umami.event_data
        WHERE positionCaseInsensitive(data_key, 'currency') > 0) c
      ON c.event_id = ed.event_id
WHERE positionCaseInsensitive(data_key, 'revenue') > 0;


================================================
FILE: db/postgresql/data-migrations/convert-utm-clid-columns.sql
================================================
-----------------------------------------------------
-- PostgreSQL
-----------------------------------------------------
UPDATE "website_event" we
SET fbclid = LEFT(url.fbclid, 255),
    gclid = LEFT(url.gclid, 255),
    li_fat_id = LEFT(url.li_fat_id, 255),
    msclkid = LEFT(url.msclkid, 255),
    ttclid = LEFT(url.ttclid, 255),
    twclid = LEFT(url.twclid, 255),
    utm_campaign = LEFT(url.utm_campaign, 255),
    utm_content = LEFT(url.utm_content, 255),
    utm_medium = LEFT(url.utm_medium, 255),
    utm_source = LEFT(url.utm_source, 255),
    utm_term = LEFT(url.utm_term, 255)
FROM (SELECT event_id, website_id, session_id,
          (regexp_matches(url_query, '(?:[&?]|^)fbclid=([^&]+)', 'i'))[1] AS fbclid,
          (regexp_matches(url_query, '(?:[&?]|^)gclid=([^&]+)', 'i'))[1] AS gclid,
          (regexp_matches(url_query, '(?:[&?]|^)li_fat_id=([^&]+)', 'i'))[1] AS li_fat_id,
          (regexp_matches(url_query, '(?:[&?]|^)msclkid=([^&]+)', 'i'))[1] AS msclkid,
          (regexp_matches(url_query, '(?:[&?]|^)ttclid=([^&]+)', 'i'))[1] AS ttclid,
          (regexp_matches(url_query, '(?:[&?]|^)twclid=([^&]+)', 'i'))[1] AS twclid,
          (regexp_matches(url_query, '(?:[&?]|^)utm_campaign=([^&]+)', 'i'))[1] AS utm_campaign,
          (regexp_matches(url_query, '(?:[&?]|^)utm_content=([^&]+)', 'i'))[1] AS utm_content,
          (regexp_matches(url_query, '(?:[&?]|^)utm_medium=([^&]+)', 'i'))[1] AS utm_medium,
          (regexp_matches(url_query, '(?:[&?]|^)utm_source=([^&]+)', 'i'))[1] AS utm_source,
          (regexp_matches(url_query, '(?:[&?]|^)utm_term=([^&]+)', 'i'))[1] AS utm_term
    FROM "website_event"
    WHERE url_query IS NOT NULL) url
WHERE we.event_id = url.event_id
    and we.session_id = url.session_id
    and we.website_id = url.website_id;

-----------------------------------------------------
-- MySQL
-----------------------------------------------------
UPDATE `website_event`
SET fbclid = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)fbclid=[^&]+'), '=', -1), '&', 1), 255),
    gclid = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)gclid=[^&]+'), '=', -1), '&', 1), 255),
    li_fat_id = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)li_fat_id=[^&]+'), '=', -1), '&', 1), 255),
    msclkid = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)msclkid=[^&]+'), '=', -1), '&', 1), 255),
    ttclid = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)ttclid=[^&]+'), '=', -1), '&', 1), 255),
    twclid = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)twclid=[^&]+'), '=', -1), '&', 1), 255),
    utm_campaign = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)utm_campaign=[^&]+'), '=', -1), '&', 1), 255),
    utm_content = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)utm_content=[^&]+'), '=', -1), '&', 1), 255),
    utm_medium = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)utm_medium=[^&]+'), '=', -1), '&', 1), 255),
    utm_source = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)utm_source=[^&]+'), '=', -1), '&', 1), 255),
    utm_term = LEFT(SUBSTRING_INDEX(SUBSTRING_INDEX(REGEXP_SUBSTR(url_query, '(?:[&?]|^)utm_term=[^&]+'), '=', -1), '&', 1), 255)
WHERE url_query IS NOT NULL;


================================================
FILE: db/postgresql/data-migrations/populate-revenue-table.sql
================================================
-----------------------------------------------------
-- PostgreSQL
-----------------------------------------------------
INSERT INTO "revenue"
SELECT gen_random_uuid() revenue_id,
    ed.website_id,
    we.session_id,
    we.event_id,
    we.event_name,
    currency.string_value currency,
    coalesce(ed.number_value, cast(ed.string_value as numeric(19,4))) revenue,
    ed.created_at
FROM event_data ed
JOIN website_event we 
ON we.event_id = ed.website_event_id
JOIN (SELECT website_event_id, string_value
      FROM event_data
      WHERE data_key ilike '%currency%') currency
ON currency.website_event_id = ed.website_event_id
WHERE ed.data_key ilike '%revenue%';

-----------------------------------------------------
-- MySQL
-----------------------------------------------------
INSERT INTO `revenue`
SELECT UUID() revenue_id,
    ed.website_id,
    we.session_id,
    we.event_id,
    we.event_name,
    currency.string_value currency,
    coalesce(ed.number_value, cast(ed.string_value as decimal(19,4))) revenue,
    ed.created_at
FROM event_data ed
JOIN website_event we
ON we.event_id = ed.website_event_id
JOIN (SELECT website_event_id, string_value
      FROM event_data
      WHERE data_key like '%currency%') currency
ON currency.website_event_id = ed.website_event_id
WHERE ed.data_key like '%revenue%';

================================================
FILE: docker/middleware.ts
================================================
import { type NextRequest, NextResponse } from 'next/server';

export const config = {
  matcher: '/:path*',
};

const TRACKER_PATH = '/script.js';
const COLLECT_PATH = '/api/send';
const LOGIN_PATH = '/login';

const apiHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': '*',
  'Access-Control-Allow-Methods': 'GET, DELETE, POST, PUT',
  'Access-Control-Max-Age': process.env.CORS_MAX_AGE || '86400',
  'Cache-Control': 'no-cache',
};

const trackerHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Cache-Control': 'public, max-age=86400, must-revalidate',
};

function customCollectEndpoint(request: NextRequest) {
  const collectEndpoint = process.env.COLLECT_API_ENDPOINT;

  if (collectEndpoint) {
    const url = request.nextUrl.clone();

    if (url.pathname.endsWith(collectEndpoint)) {
      url.pathname = COLLECT_PATH;
      return NextResponse.rewrite(url, { headers: apiHeaders });
    }
  }
}

function customScriptName(request: NextRequest) {
  const scriptName = process.env.TRACKER_SCRIPT_NAME;

  if (scriptName) {
    const url = request.nextUrl.clone();
    const names = scriptName.split(',').map(name => name.trim().replace(/^\/+/, ''));

    if (names.find(name => url.pathname.endsWith(name))) {
      url.pathname = TRACKER_PATH;
      return NextResponse.rewrite(url, { headers: trackerHeaders });
    }
  }
}

function customScriptUrl(request: NextRequest) {
  const scriptUrl = process.env.TRACKER_SCRIPT_URL;

  if (scriptUrl && request.nextUrl.pathname.endsWith(TRACKER_PATH)) {
    return NextResponse.rewrite(scriptUrl, { headers: trackerHeaders });
  }
}

function disableLogin(request: NextRequest) {
  const loginDisabled = process.env.DISABLE_LOGIN;

  if (loginDisabled && request.nextUrl.pathname.endsWith(LOGIN_PATH)) {
    return new NextResponse('Access denied', { status: 403 });
  }
}

export default function middleware(req: NextRequest) {
  const fns = [customCollectEndpoint, customScriptName, customScriptUrl, disableLogin];

  for (const fn of fns) {
    const res = fn(req);
    if (res) {
      return res;
    }
  }

  return NextResponse.next();
}


================================================
FILE: docker-compose.yml
================================================
---
services:
  umami:
    image: ghcr.io/umami-software/umami:latest
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgresql://umami:umami@db:5432/umami
      APP_SECRET: replace-me-with-a-random-string
    depends_on:
      db:
        condition: service_healthy
    init: true
    restart: always
    healthcheck:
      test: ["CMD-SHELL", "curl http://localhost:3000/api/heartbeat"]
      interval: 5s
      timeout: 5s
      retries: 5
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: umami
      POSTGRES_USER: umami
      POSTGRES_PASSWORD: umami
    volumes:
      - umami-db-data:/var/lib/postgresql/data
    restart: always
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
      interval: 5s
      timeout: 5s
      retries: 5
volumes:
  umami-db-data:


================================================
FILE: jest.config.ts
================================================
export default {
  roots: ['./src'],
  testMatch: ['**/__tests__/**/*.+(ts|tsx|js)', '**/?(*.)+(spec|test).+(ts|tsx|js)'],
  transform: {
    '^.+\\.(ts|tsx)$': 'ts-jest',
  },
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/src/$1',
  },
};


================================================
FILE: netlify.toml
================================================
[functions]
included_files = ["node_modules/.geo/**"]

[[plugins]]
package = "@netlify/plugin-nextjs"


================================================
FILE: next-env.d.ts
================================================
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference path="./.next/types/routes.d.ts" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.


================================================
FILE: next.config.ts
================================================
import 'dotenv/config';
import pkg from './package.json' with { type: 'json' };

const TRACKER_SCRIPT = '/script.js';

const basePath = process.env.BASE_PATH || '';
const cloudMode = process.env.CLOUD_MODE || '';
const cloudUrl = process.env.CLOUD_URL || '';
const collectApiEndpoint = process.env.COLLECT_API_ENDPOINT || '';
const corsMaxAge = process.env.CORS_MAX_AGE || '';
const defaultLocale = process.env.DEFAULT_LOCALE || '';
const forceSSL = process.env.FORCE_SSL || '';
const frameAncestors = process.env.ALLOWED_FRAME_URLS || '';
const trackerScriptName = process.env.TRACKER_SCRIPT_NAME || '';
const trackerScriptURL = process.env.TRACKER_SCRIPT_URL || '';

const contentSecurityPolicy = `
  default-src 'self';
  img-src 'self' https: data:;
  script-src 'self' 'unsafe-eval' 'unsafe-inline';
  style-src 'self' 'unsafe-inline';
  connect-src 'self' https:;
  frame-ancestors 'self' ${frameAncestors};
`;

const defaultHeaders = [
  {
    key: 'X-DNS-Prefetch-Control',
    value: 'on',
  },
  {
    key: 'Content-Security-Policy',
    value: contentSecurityPolicy.replace(/\s{2,}/g, ' ').trim(),
  },
];

if (forceSSL) {
  defaultHeaders.push({
    key: 'Strict-Transport-Security',
    value: 'max-age=63072000; includeSubDomains; preload',
  });
}

const trackerHeaders = [
  {
    key: 'Access-Control-Allow-Origin',
    value: '*',
  },
  {
    key: 'Cache-Control',
    value: 'public, max-age=86400, must-revalidate',
  },
];

const apiHeaders = [
  {
    key: 'Access-Control-Allow-Origin',
    value: '*',
  },
  {
    key: 'Access-Control-Allow-Headers',
    value: '*',
  },
  {
    key: 'Access-Control-Allow-Methods',
    value: 'GET, DELETE, POST, PUT',
  },
  {
    key: 'Access-Control-Max-Age',
    value: corsMaxAge || '86400',
  },
  {
    key: 'Cache-Control',
    value: 'no-cache',
  },
];

const headers = [
  {
    source: '/api/:path*',
    headers: apiHeaders,
  },
  {
    source: '/:path*',
    headers: defaultHeaders,
  },
  {
    source: TRACKER_SCRIPT,
    headers: trackerHeaders,
  },
];

const rewrites = [];

if (trackerScriptURL) {
  rewrites.push({
    source: TRACKER_SCRIPT,
    destination: trackerScriptURL,
  });
}

if (collectApiEndpoint) {
  headers.push({
    source: collectApiEndpoint,
    headers: apiHeaders,
  });

  rewrites.push({
    source: collectApiEndpoint,
    destination: '/api/send',
  });
}

const redirects = [
  {
    source: '/settings',
    destination: '/settings/preferences',
    permanent: false,
  },
  {
    source: '/teams/:id',
    destination: '/teams/:id/websites',
    permanent: false,
  },
  {
    source: '/teams/:id/settings',
    destination: '/teams/:id/settings/preferences',
    permanent: false,
  },
  {
    source: '/admin',
    destination: '/admin/users',
    permanent: false,
  },
];

// Adding rewrites + headers for all alternative tracker script names.
if (trackerScriptName) {
  const names = trackerScriptName?.split(',').map(name => name.trim());

  if (names) {
    names.forEach(name => {
      const normalizedSource = `/${name.replace(/^\/+/, '')}`;

      rewrites.push({
        source: normalizedSource,
        destination: TRACKER_SCRIPT,
      });

      headers.push({
        source: normalizedSource,
        headers: trackerHeaders,
      });
    });
  }
}

if (cloudMode) {
  rewrites.push({
    source: '/script.js',
    destination: 'https://cloud.umami.is/script.js',
  });
}

/** @type {import('next').NextConfig} */
export default {
  reactStrictMode: false,
  env: {
    basePath,
    cloudMode,
    cloudUrl,
    currentVersion: pkg.version,
    defaultLocale,
  },
  basePath,
  output: 'standalone',
  eslint: {
    ignoreDuringBuilds: true,
  },
  typescript: {
    ignoreBuildErrors: true,
  },
  async headers() {
    return headers;
  },
  async rewrites() {
    return [
      ...rewrites,
      {
        source: '/telemetry.js',
        destination: '/api/scripts/telemetry',
      },
      {
        source: '/teams/:teamId/:path*',
        destination: '/:path*',
      },
    ];
  },
  async redirects() {
    return [...redirects];
  },
};


================================================
FILE: package.components.json
================================================
{
  "name": "@umami/components",
  "version": "0.130.0",
  "description": "Umami React components.",
  "author": "Mike Cao <mike@mikecao.com>",
  "license": "MIT",
  "type": "module",
  "main": "./index.js",
  "types": "./index.d.ts"
}


================================================
FILE: package.json
================================================
{
  "name": "umami",
  "version": "3.0.3",
  "description": "A modern, privacy-focused alternative to Google Analytics.",
  "author": "Umami Software, Inc. <hello@umami.is>",
  "license": "MIT",
  "homepage": "https://umami.is",
  "repository": {
    "type": "git",
    "url": "https://github.com/umami-software/umami.git"
  },
  "type": "module",
  "scripts": {
    "dev": "next dev -p 3001 --turbo",
    "build": "npm-run-all check-env build-db check-db build-tracker build-geo build-app",
    "start": "next start",
    "build-docker": "npm-run-all build-db build-tracker build-geo build-app",
    "start-docker": "npm-run-all check-db update-tracker start-server",
    "start-env": "node scripts/start-env.js",
    "start-server": "node server.js",
    "build-app": "next build --turbo",
    "build-icons": "svgr ./src/assets --out-dir src/components/svg --typescript",
    "build-components": "tsup",
    "build-tracker": "rollup -c rollup.tracker.config.js",
    "build-prisma-client": "node scripts/build-prisma-client.js",
    "build-lang": "npm-run-all format-lang compile-lang download-country-names download-language-names clean-lang",
    "build-geo": "node scripts/build-geo.js",
    "build-db": "npm-run-all build-db-client build-prisma-client",
    "build-db-schema": "prisma db pull",
    "build-db-client": "prisma generate",
    "update-tracker": "node scripts/update-tracker.js",
    "update-db": "prisma migrate deploy",
    "check-db": "node scripts/check-db.js",
    "check-env": "node scripts/check-env.js",
    "copy-db-files": "node scripts/copy-db-files.js",
    "extract-messages": "formatjs extract \"src/components/messages.ts\" --out-file build/extracted-messages.json",
    "merge-messages": "node scripts/merge-messages.js",
    "generate-lang": "npm-run-all extract-messages merge-messages",
    "format-lang": "node scripts/format-lang.js",
    "compile-lang": "formatjs compile-folder --ast build/messages public/intl/messages",
    "clean-lang": "prettier --write ./public/intl/**/*.json",
    "download-country-names": "node scripts/download-country-names.js",
    "download-language-names": "node scripts/download-language-names.js",
    "change-password": "node scripts/change-password.js",
    "prepare": "node -e \"if (process.env.NODE_ENV !== 'production'){process.exit(1)} \" || husky install",
    "postbuild": "node scripts/postbuild.js",
    "test": "jest",
    "cypress-open": "cypress open cypress run",
    "cypress-run": "cypress run cypress run",
    "seed-data": "tsx scripts/seed-data.ts",
    "lint": "biome lint .",
    "format": "biome format --write .",
    "check": "biome check --write"
  },
  "lint-staged": {
    "**/*.{js,jsx,ts,tsx,json,css}": [
      "biome check --write --no-errors-on-unmatched --files-ignore-unknown=true"
    ]
  },
  "cacheDirectories": [
    ".next/cache"
  ],
  "dependencies": {
    "@clickhouse/client": "^1.12.0",
    "@date-fns/utc": "^1.2.0",
    "@dicebear/collection": "^9.2.3",
    "@dicebear/core": "^9.2.3",
    "@fontsource/inter": "^5.2.8",
    "@hello-pangea/dnd": "^17.0.0",
    "@prisma/adapter-pg": "^6.18.0",
    "@prisma/client": "^6.18.0",
    "@prisma/extension-read-replicas": "^0.4.1",
    "@react-spring/web": "^10.0.3",
    "@svgr/cli": "^8.1.0",
    "@tanstack/react-query": "^5.90.11",
    "@umami/react-zen": "^0.211.0",
    "@umami/redis-client": "^0.29.0",
    "bcryptjs": "^3.0.2",
    "chalk": "^5.6.2",
    "chart.js": "^4.5.1",
    "chartjs-adapter-date-fns": "^3.0.0",
    "classnames": "^2.3.1",
    "colord": "^2.9.2",
    "cors": "^2.8.5",
    "cross-spawn": "^7.0.3",
    "date-fns": "^2.23.0",
    "date-fns-tz": "^1.1.4",
    "debug": "^4.4.3",
    "del": "^6.0.0",
    "detect-browser": "^5.2.0",
    "dotenv": "^17.2.3",
    "esbuild": "^0.25.11",
    "fs-extra": "^11.3.2",
    "immer": "^10.2.0",
    "ipaddr.js": "^2.3.0",
    "is-ci": "^3.0.1",
    "is-docker": "^3.0.0",
    "is-localhost-ip": "^2.0.0",
    "isbot": "^5.1.31",
    "jsonwebtoken": "^9.0.2",
    "jszip": "^3.10.1",
    "kafkajs": "^2.1.0",
    "lucide-react": "^0.543.0",
    "maxmind": "^5.0.0",
    "next": "^15.5.9",
    "node-fetch": "^3.2.8",
    "npm-run-all": "^4.1.5",
    "papaparse": "^5.5.3",
    "pg": "^8.16.3",
    "prisma": "^6.18.0",
    "pure-rand": "^7.0.1",
    "react": "^19.2.3",
    "react-dom": "^19.2.3",
    "react-error-boundary": "^4.0.4",
    "react-intl": "^7.1.14",
    "react-simple-maps": "^2.3.0",
    "react-use-measure": "^2.0.4",
    "react-window": "^1.8.6",
    "request-ip": "^3.3.0",
    "semver": "^7.7.3",
    "serialize-error": "^12.0.0",
    "thenby": "^1.3.4",
    "ua-parser-js": "^2.0.6",
    "uuid": "^11.1.0",
    "zod": "^4.1.13",
    "zustand": "^5.0.9"
  },
  "devDependencies": {
    "@biomejs/biome": "^2.3.8",
    "@formatjs/cli": "^4.2.29",
    "@netlify/plugin-nextjs": "^5.15.1",
    "@rollup/plugin-alias": "^5.0.0",
    "@rollup/plugin-commonjs": "^25.0.4",
    "@rollup/plugin-json": "^6.0.0",
    "@rollup/plugin-node-resolve": "^15.2.0",
    "@rollup/plugin-replace": "^5.0.2",
    "@rollup/plugin-terser": "^0.4.4",
    "@rollup/plugin-typescript": "^12.3.0",
    "@types/jest": "^30.0.0",
    "@types/node": "^24.9.2",
    "@types/react": "^19.2.7",
    "@types/react-dom": "^19.2.2",
    "@types/react-window": "^1.8.8",
    "babel-plugin-react-compiler": "19.1.0-rc.2",
    "cross-env": "^10.1.0",
    "cypress": "^13.6.6",
    "extract-react-intl-messages": "^4.1.1",
    "husky": "^9.1.7",
    "jest": "^29.7.0",
    "lint-staged": "^16.2.6",
    "postcss": "^8.5.6",
    "postcss-flexbugs-fixes": "^5.0.2",
    "postcss-import": "^15.1.0",
    "postcss-preset-env": "7.8.3",
    "prompts": "2.4.2",
    "rollup": "^4.52.5",
    "rollup-plugin-copy": "^3.4.0",
    "rollup-plugin-delete": "^3.0.1",
    "rollup-plugin-dts": "^6.3.0",
    "rollup-plugin-node-externals": "^8.1.1",
    "rollup-plugin-peer-deps-external": "^2.2.4",
    "rollup-plugin-postcss": "^4.0.2",
    "stylelint": "^15.10.1",
    "stylelint-config-css-modules": "^4.5.1",
    "stylelint-config-prettier": "^9.0.3",
    "stylelint-config-recommended": "^14.0.0",
    "tar": "^6.1.2",
    "ts-jest": "^29.4.6",
    "ts-node": "^10.9.1",
    "tsup": "^8.5.0",
    "tsx": "^4.19.0",
    "typescript": "^5.9.3"
  }
}


================================================
FILE: pnpm-workspace.yaml
================================================
packages:
  - '**'
ignoredBuiltDependencies:
  - cypress
  - esbuild
  - sharp
onlyBuiltDependencies:
  - '@prisma/client'
  - '@prisma/engines'
  - prisma


================================================
FILE: podman/README.md
================================================
# How to deploy umami on podman


## How to use

1. Rename `env.sample` to `.env`
2. Edit `.env` file. At the minimum set the passwords.
3. Start umami by running `podman-compose up -d`.

If you need to stop umami, you can do so by running `podman-compose down`.


### Install systemd service (optional)

If you want to install a systemd service to run umami, you can use the provided
systemd service.

Edit `umami.service` and change these two variables:


	WorkingDirectory=/opt/apps/umami
	EnvironmentFile=/opt/apps/umami/.env

`WorkingDirectory` should be changed to the path in which `podman-compose.yml`
is located.

`EnvironmentFile` should be changed to the path in which your `.env`file is
located.

You can run the script `install-systemd-user-service` to install the systemd
service under the current user.


	./install-systemd-user-service

Note: this script will enable the service and also start it. So it will assume
that umami is not currently running.  If you started it previously, bring it
down using:

	podman-compose down



## Compatibility

These files should be compatible with podman 4.3+.

I have tested this on Debian GNU/Linux 12 (bookworm) and with the podman that
is distributed with the official Debian stable mirrors (podman
v4.3.1+ds1-8+deb12u1, podman-compose v1.0.3-3).


================================================
FILE: podman/env.sample
================================================
# Rename this file to .env and modify the values
#
# Connection string for Umami’s database.
# If you use the bundled DB container, "db" is the hostname.
DATABASE_URL=postgresql://umami:replace-me-with-a-random-string@db:5432/umami

# Database type (e.g. postgresql)
DATABASE_TYPE=postgresql

# A secret string used by Umami (replace with a strong random string)
APP_SECRET=replace-me-with-a-random-string

# Postgres container defaults.
POSTGRES_DB=umami
POSTGRES_USER=umami
POSTGRES_PASSWORD=replace-me-with-a-random-string


================================================
FILE: podman/install-systemd-user-service
================================================
#!/bin/bash
set -e
service_name="umami"
mkdir -p ~/.config/systemd/user
cp $service_name.service ~/.config/systemd/user


systemctl --user daemon-reload
systemctl --user enable $service_name.service
systemctl --user start $service_name.service


================================================
FILE: podman/podman-compose.yml
================================================
version: "3.8"

services:
  umami:
    container_name: umami
    image: ghcr.io/umami-software/umami:postgresql-latest
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      DATABASE_URL: ${DATABASE_URL}
      DATABASE_TYPE: ${DATABASE_TYPE}
      APP_SECRET: ${APP_SECRET}
    depends_on:
      db:
        condition: service_healthy
    init: true
    restart: always
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:3000/api/heartbeat || exit 1"]
      interval: 5s
      timeout: 5s
      retries: 5

  db:
    container_name: umami-db
    image: docker.io/library/postgres:15-alpine
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - umami-db-data:/var/lib/postgresql/data:Z
    restart: always
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  umami-db-data:


================================================
FILE: podman/umami.service
================================================
[Unit]
Description=Umami Container Stack via Podman-Compose
After=network.target

[Service]
Type=simple
WorkingDirectory=/opt/apps/umami
EnvironmentFile=/opt/apps/umami/.env
ExecStart=/usr/bin/podman-compose -f podman-compose.yml up -d
ExecStop=/usr/bin/podman-compose -f podman-compose.yml down
RemainAfterExit=yes

[Install]
WantedBy=default.target


================================================
FILE: postcss.config.js
================================================
export default {
  plugins: [
    'postcss-flexbugs-fixes',
    [
      'postcss-preset-env',
      {
        autoprefixer: {
          flexbox: 'no-2009',
        },
        stage: 3,
        features: {
          'custom-properties': false,
        },
      },
    ],
  ],
};


================================================
FILE: prisma/migrations/01_init/migration.sql
================================================
-- CreateExtension
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

-- CreateTable
CREATE TABLE "user" (
    "user_id" UUID NOT NULL,
    "username" VARCHAR(255) NOT NULL,
    "password" VARCHAR(60) NOT NULL,
    "role" VARCHAR(50) NOT NULL,
    "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
    "updated_at" TIMESTAMPTZ(6),
    "deleted_at" TIMESTAMPTZ(6),

    CONSTRAINT "user_pkey" PRIMARY KEY ("user_id")
);

-- CreateTable
CREATE TABLE "session" (
    "session_id" UUID NOT NULL,
    "website_id" UUID NOT NULL,
    "hostname" VARCHAR(100),
    "browser" VARCHAR(20),
    "os" VARCHAR(20),
    "device" VARCHAR(20),
    "screen" VARCHAR(11),
    "language" VARCHAR(35),
    "country" CHAR(2),
    "subdivision1" VARCHAR(20),
    "subdivision2" VARCHAR(50),
    "city" VARCHAR(50),
    "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "session_pkey" PRIMARY KEY ("session_id")
);

-- CreateTable
CREATE TABLE "website" (
    "website_id" UUID NOT NULL,
    "name" VARCHAR(100) NOT NULL,
    "domain" VARCHAR(500),
    "share_id" VARCHAR(50),
    "reset_at" TIMESTAMPTZ(6),
    "user_id" UUID,
    "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
    "updated_at" TIMESTAMPTZ(6),
    "deleted_at" TIMESTAMPTZ(6),

    CONSTRAINT "website_pkey" PRIMARY KEY ("website_id")
);

-- CreateTable
CREATE TABLE "website_event" (
    "event_id" UUID NOT NULL,
    "website_id" UUID NOT NULL,
    "session_id" UUID NOT NULL,
    "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
    "url_path" VARCHAR(500) NOT NULL,
    "url_query" VARCHAR(500),
    "referrer_path" VARCHAR(500),
    "referrer_query" VARCHAR(500),
    "referrer_domain" VARCHAR(500),
    "page_title" VARCHAR(500),
    "event_type" INTEGER NOT NULL DEFAULT 1,
    "event_name" VARCHAR(50),

    CONSTRAINT "website_event_pkey" PRIMARY KEY ("event_id")
);

-- CreateTable
CREATE TABLE "event_data" (
    "event_id" UUID NOT NULL,
    "website_id" UUID NOT NULL,
    "website_event_id" UUID NOT NULL,
    "event_key" VARCHAR(500) NOT NULL,
    "event_string_value" VARCHAR(500),
    "event_numeric_value" DECIMAL(19,4),
    "event_date_value" TIMESTAMPTZ(6),
    "event_data_type" INTEGER NOT NULL,
    "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "event_data_pkey" PRIMARY KEY ("event_id")
);

-- CreateTable
CREATE TABLE "team" (
    "team_id" UUID NOT NULL,
    "name" VARCHAR(50) NOT NULL,
    "access_code" VARCHAR(50),
    "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
    "updated_at" TIMESTAMPTZ(6),

    CONSTRAINT "team_pkey" PRIMARY KEY ("team_id")
);

-- CreateTable
CREATE TABLE "team_user" (
    "team_user_id" UUID NOT NULL,
    "team_id" UUID NOT NULL,
    "user_id" UUID NOT NULL,
    "role" VARCHAR(50) NOT NULL,
    "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
    "updated_at" TIMESTAMPTZ(6),

    CONSTRAINT "team_user_pkey" PRIMARY KEY ("team_user_id")
);

-- CreateTable
CREATE TABLE "team_website" (
    "team_website_id" UUID NOT NULL,
    "team_id" UUID NOT NULL,
    "website_id" UUID NOT NULL,
    "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "team_website_pkey" PRIMARY KEY ("team_website_id")
);

-- CreateIndex
CREATE UNIQUE INDEX "user_user_id_key" ON "user"("user_id");

-- CreateIndex
CREATE UNIQUE INDEX "user_username_key" ON "user"("username");

-- CreateIndex
CREATE UNIQUE INDEX "session_session_id_key" ON "session"("session_id");

-- CreateIndex
CREATE INDEX "session_created_at_idx" ON "session"("created_at");

-- CreateIndex
CREATE INDEX "session_website_id_idx" ON "session"("website_id");

-- CreateIndex
CREATE UNIQUE INDEX "website_website_id_key" ON "website"("website_id");

-- CreateIndex
CREATE UNIQUE INDEX "website_share_id_key" ON "website"("share_id");

-- CreateIndex
CREATE INDEX "website_user_id_idx" ON "website"("user_id");

-- CreateIndex
CREATE INDEX "website_created_at_idx" ON "website"("created_at");

-- CreateIndex
CREATE INDEX "website_share_id_idx" ON "website"("share_id");

-- CreateIndex
CREATE INDEX "website_event_created_at_idx" ON "website_event"("created_at");

-- CreateIndex
CREATE INDEX "website_event_session_id_idx" ON "website_event"("session_id");

-- CreateIndex
CREATE INDEX "website_event_website_id_idx" ON "website_event"("website_id");

-- CreateIndex
CREATE INDEX "website_event_website_id_created_at_idx" ON "website_event"("website_id", "created_at");

-- CreateIndex
CREATE INDEX "website_event_website_id_session_id_created_at_idx" ON "website_event"("website_id", "session_id", "created_at");

-- CreateIndex
CREATE INDEX "event_data_created_at_idx" ON "event_data"("created_at");

-- CreateIndex
CREATE INDEX "event_data_website_id_idx" ON "event_data"("website_id");

-- CreateIndex
CREATE INDEX "event_data_website_event_id_idx" ON "event_data"("website_event_id");

-- CreateIndex
CREATE UNIQUE INDEX "team_team_id_key" ON "team"("team_id");

-- CreateIndex
CREATE UNIQUE INDEX "team_access_code_key" ON "team"("access_code");

-- CreateIndex
CREATE INDEX "team_access_code_idx" ON "team"("access_code");

-- CreateIndex
CREATE UNIQUE INDEX "team_user_team_user_id_key" ON "team_user"("team_user_id");

-- CreateIndex
CREATE INDEX "team_user_team_id_idx" ON "team_user"("team_id");

-- CreateIndex
CREATE INDEX "team_user_user_id_idx" ON "team_user"("user_id");

-- CreateIndex
CREATE UNIQUE INDEX "team_website_team_website_id_key" ON "team_website"("team_website_id");

-- CreateIndex
CREATE INDEX "team_website_team_id_idx" ON "team_website"("team_id");

-- CreateIndex
CREATE INDEX "team_website_website_id_idx" ON "team_website"("website_id");

-- AddSystemUser
INSERT INTO "user" (user_id, username, role, password) VALUES ('41e2b680-648e-4b09-bcd7-3e2b10c06264' , 'admin', 'admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa');

================================================
FILE: prisma/migrations/02_report_schema_session_data/migration.sql
================================================
-- AlterTable
ALTER TABLE "event_data" RENAME COLUMN "event_data_type" TO "data_type";
ALTER TABLE "event_data" RENAME COLUMN "event_date_value" TO "date_value";
ALTER TABLE "event_data" RENAME COLUMN "event_id" TO "event_data_id";
ALTER TABLE "event_data" RENAME COLUMN "event_numeric_value" TO "number_value";
ALTER TABLE "event_data" RENAME COLUMN "event_string_value" TO "string_value";

-- CreateTable
CREATE TABLE "session_data" (
    "session_data_id" UUID NOT NULL,
    "website_id" UUID NOT NULL,
    "session_id" UUID NOT NULL,
    "session_key" VARCHAR(500) NOT NULL,
    "string_value" VARCHAR(500),
    "number_value" DECIMAL(19,4),
    "date_value" TIMESTAMPTZ(6),
    "data_type" INTEGER NOT NULL,
    "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
    "deleted_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "session_data_pkey" PRIMARY KEY ("session_data_id")
);

-- CreateTable
CREATE TABLE "report" (
    "report_id" UUID NOT NULL,
    "user_id" UUID NOT NULL,
    "website_id" UUID NOT NULL,
    "type" VARCHAR(200) NOT NULL,
    "name" VARCHAR(200) NOT NULL,
    "description" VARCHAR(500) NOT NULL,
    "parameters" VARCHAR(6000) NOT NULL,
    "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
    "updated_at" TIMESTAMPTZ(6),

    CONSTRAINT "report_pkey" PRIMARY KEY ("report_id")
);

-- CreateIndex
CREATE INDEX "session_data_created_at_idx" ON "session_data"("created_at");

-- CreateIndex
CREATE INDEX "session_data_website_id_idx" ON "session_data"("website_id");

-- CreateIndex
CREATE INDEX "session_data_session_id_idx" ON "session_data"("session_id");

-- CreateIndex
CREATE UNIQUE INDEX "report_report_id_key" ON "report"("report_id");

-- CreateIndex
CREATE INDEX "report_user_id_idx" ON "report"("user_id");

-- CreateIndex
CREATE INDEX "report_website_id_idx" ON "report"("website_id");

-- CreateIndex
CREATE INDEX "report_type_idx" ON "report"("type");

-- CreateIndex
CREATE INDEX "report_name_idx" ON "report"("name");

-- EventData migration
UPDATE "event_data"
SET string_value = number_value
WHERE data_type = 2;

UPDATE "event_data"
SET string_value = CONCAT(REPLACE(TO_CHAR(date_value, 'YYYY-MM-DD HH24:MI:SS'), ' ', 'T'), 'Z')
WHERE data_type = 4;

================================================
FILE: prisma/migrations/03_metric_performance_index/migration.sql
================================================
-- CreateIndex
CREATE INDEX "event_data_website_id_created_at_idx" ON "event_data"("website_id", "created_at");

-- CreateIndex
CREATE INDEX "event_data_website_id_created_at_event_key_idx" ON "event_data"("website_id", "created_at", "event_key");

-- CreateIndex
CREATE INDEX "session_website_id_created_at_idx" ON "session"("website_id", "created_at");

-- CreateIndex
CREATE INDEX "session_website_id_created_at_hostname_idx" ON "session"("website_id", "created_at", "hostname");

-- CreateIndex
CREATE INDEX "session_website_id_created_at_browser_idx" ON "session"("website_id", "created_at", "browser");

-- CreateIndex
CREATE INDEX "session_website_id_created_at_os_idx" ON "session"("website_id", "created_at", "os");

-- CreateIndex
CREATE INDEX "session_website_id_created_at_device_idx" ON "session"("website_id", "created_at", "device");

-- CreateIndex
CREATE INDEX "session_website_id_created_at_screen_idx" ON "session"("website_id", "created_at", "screen");

-- CreateIndex
CREATE INDEX "session_website_id_created_at_language_idx" ON "session"("website_id", "created_at", "language");

-- CreateIndex
CREATE INDEX "session_website_id_created_at_country_idx" ON "session"("website_id", "created_at", "country");

-- CreateIndex
CREATE INDEX "session_website_id_created_at_subdivision1_idx" ON "session"("website_id", "created_at", "subdivision1");

-- CreateIndex
CREATE INDEX "session_website_id_created_at_city_idx" ON "session"("website_id", "created_at", "city");

-- CreateIndex
CREATE INDEX "website_event_website_id_created_at_url_path_idx" ON "website_event"("website_id", "created_at", "url_path");

-- CreateIndex
CREATE INDEX "website_event_website_id_created_at_url_query_idx" ON "website_event"("website_id", "created_at", "url_query");

-- CreateIndex
CREATE INDEX "website_event_website_id_created_at_referrer_domain_idx" ON "website_event"("website_id", "created_at", "referrer_domain");

-- CreateIndex
CREATE INDEX "website_event_website_id_created_at_page_title_idx" ON "website_event"("website_id", "created_at", "page_title");

-- CreateIndex
CREATE INDEX "website_event_website_id_created_at_event_name_idx" ON "website_event"("website_id", "created_at", "event_name");


================================================
FILE: prisma/migrations/04_team_redesign/migration.sql
================================================
/*
  Warnings:

  - You are about to drop the `team_website` table. If the table is not empty, all the data it contains will be lost.

*/
-- AlterTable
ALTER TABLE "team" ADD COLUMN     "deleted_at" TIMESTAMPTZ(6),
ADD COLUMN     "logo_url" VARCHAR(2183);

-- AlterTable
ALTER TABLE "user" ADD COLUMN     "display_name" VARCHAR(255),
ADD COLUMN     "logo_url" VARCHAR(2183);

-- AlterTable
ALTER TABLE "website" ADD COLUMN     "created_by" UUID,
ADD COLUMN     "team_id" UUID;

-- MigrateData
UPDATE "website" SET created_by = user_id WHERE team_id IS NULL;

-- DropTable
DROP TABLE "team_website";

-- CreateIndex
CREATE INDEX "website_team_id_idx" ON "website"("team_id");

-- CreateIndex
CREATE INDEX "website_created_by_idx" ON "website"("created_by");

================================================
FILE: prisma/migrations/05_add_visit_id/migration.sql
================================================
-- AlterTable
ALTER TABLE "website_event" ADD COLUMN "visit_id" UUID NULL;

UPDATE "website_event" we
SET visit_id = a.uuid
FROM (SELECT DISTINCT
        s.session_id,
        s.visit_time,
        gen_random_uuid() uuid
    FROM (SELECT DISTINCT session_id,
            date_trunc('hour', created_at) visit_time
        FROM "website_event") s) a
WHERE we.session_id = a.session_id 
    and date_trunc('hour', we.created_at) = a.visit_time;

ALTER TABLE "website_event" ALTER COLUMN "visit_id" SET NOT NULL;

-- CreateIndex
CREATE INDEX "website_event_visit_id_idx" ON "website_event"("visit_id");

-- CreateIndex
CREATE INDEX "website_event_website_id_visit_id_created_at_idx" ON "website_event"("website_id", "visit_id", "created_at");

================================================
FILE: prisma/migrations/06_session_data/migration.sql
================================================
-- DropIndex
DROP INDEX IF EXISTS "event_data_website_id_created_at_event_key_idx";

-- AlterTable
ALTER TABLE "event_data" RENAME COLUMN "event_key" TO "data_key";

-- AlterTable
ALTER TABLE "session_data" DROP COLUMN "deleted_at";
ALTER TABLE "session_data" RENAME COLUMN "session_key" TO "data_key";

-- CreateIndex
CREATE INDEX "event_data_website_id_created_at_data_key_idx" ON "event_data"("website_id", "created_at", "data_key");

-- CreateIndex
CREATE INDEX "session_data_session_id_created_at_idx" ON "session_data"("session_id", "created_at");

-- CreateIndex
CREATE INDEX "session_data_website_id_created_at_data_key_idx" ON "session_data"("website_id", "created_at", "data_key");


================================================
FILE: prisma/migrations/07_add_tag/migration.sql
================================================
-- AlterTable
ALTER TABLE "website_event" ADD COLUMN     "tag" VARCHAR(50);

-- CreateIndex
CREATE INDEX "website_event_website_id_created_at_tag_idx" ON "website_event"("website_id", "created_at", "tag");


================================================
FILE: prisma/migrations/08_add_utm_clid/migration.sql
================================================
-- AlterTable
ALTER TABLE "website_event" 
ADD COLUMN     "fbclid" VARCHAR(255),
ADD COLUMN     "gclid" VARCHAR(255),
ADD COLUMN     "li_fat_id" VARCHAR(255),
ADD COLUMN     "msclkid" VARCHAR(255),
ADD COLUMN     "ttclid" VARCHAR(255),
ADD COLUMN     "twclid" VARCHAR(255),
ADD COLUMN     "utm_campaign" VARCHAR(255),
ADD COLUMN     "utm_content" VARCHAR(255),
ADD COLUMN     "utm_medium" VARCHAR(255),
ADD COLUMN     "utm_source" VARCHAR(255),
ADD COLUMN     "utm_term" VARCHAR(255);


================================================
FILE: prisma/migrations/09_update_hostname_region/migration.sql
================================================
-- AlterTable
ALTER TABLE "website_event" ADD COLUMN     "hostname" VARCHAR(100);

-- DataMigration
UPDATE "website_event" w
SET hostname = s.hostname
FROM "session" s
WHERE s.website_id = w.website_id
    and s.session_id = w.session_id;

-- DropIndex
DROP INDEX IF EXISTS "session_website_id_created_at_hostname_idx";
DROP INDEX IF EXISTS "session_website_id_created_at_subdivision1_idx";

-- AlterTable
ALTER TABLE "session" RENAME COLUMN "subdivision1" TO "region";
ALTER TABLE "session" DROP COLUMN "subdivision2";
ALTER TABLE "session" DROP COLUMN "hostname";

-- CreateIndex
CREATE INDEX "website_event_website_id_created_at_hostname_idx" ON "website_event"("website_id", "created_at", "hostname");
CREATE INDEX "session_website_id_created_at_region_idx" ON "session"("website_id", "created_at", "region");





================================================
FILE: prisma/migrations/10_add_distinct_id/migration.sql
================================================
-- AlterTable
ALTER TABLE "session" ADD COLUMN     "distinct_id" VARCHAR(50);

-- AlterTable
ALTER TABLE "session_data" ADD COLUMN     "distinct_id" VARCHAR(50);


================================================
FILE: prisma/migrations/11_add_segment/migration.sql
================================================
-- CreateTable
CREATE TABLE "segment" (
    "segment_id" UUID NOT NULL,
    "website_id" UUID NOT NULL,
    "type" VARCHAR(200) NOT NULL,
    "name" VARCHAR(200) NOT NULL,
    "parameters" JSONB NOT NULL,
    "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
    "updated_at" TIMESTAMPTZ(6),

    CONSTRAINT "segment_pkey" PRIMARY KEY ("segment_id")
);

-- CreateIndex
CREATE UNIQUE INDEX "segment_segment_id_key" ON "segment"("segment_id");

-- CreateIndex
CREATE INDEX "segment_website_id_idx" ON "segment"("website_id");


================================================
FILE: prisma/migrations/12_update_report_parameter/migration.sql
================================================
-- AlterTable
ALTER TABLE "report"
ALTER COLUMN "parameters" SET DATA TYPE JSONB USING parameters::JSONB;


================================================
FILE: prisma/migrations/13_add_revenue/migration.sql
================================================
-- CreateTable
CREATE TABLE "revenue" (
    "revenue_id" UUID NOT NULL,
    "website_id" UUID NOT NULL,
    "session_id" UUID NOT NULL,
    "event_id" UUID NOT NULL,
    "event_name" VARCHAR(50) NOT NULL,
    "currency" VARCHAR(100) NOT NULL,
    "revenue" DECIMAL(19,4),
    "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,

    CONSTRAINT "revenue_pkey" PRIMARY KEY ("revenue_id")
);

-- CreateIndex
CREATE UNIQUE INDEX "revenue_revenue_id_key" ON "revenue"("revenue_id");

-- CreateIndex
CREATE INDEX "revenue_website_id_idx" ON "revenue"("website_id");

-- CreateIndex
CREATE INDEX "revenue_session_id_idx" ON "revenue"("session_id");

-- CreateIndex
CREATE INDEX "revenue_website_id_created_at_idx" ON "revenue"("website_id", "created_at");

-- CreateIndex
CREATE INDEX "revenue_website_id_session_id_created_at_idx" ON "revenue"("website_id", "session_id", "created_at");


================================================
FILE: prisma/migrations/14_add_link_and_pixel/migration.sql
================================================
-- AlterTable
ALTER TABLE "report" ALTER COLUMN "type" SET DATA TYPE VARCHAR(50);

-- AlterTable
ALTER TABLE "revenue" ALTER COLUMN "currency" SET DATA TYPE VARCHAR(10);

-- AlterTable
ALTER TABLE "segment" ALTER COLUMN "type" SET DATA TYPE VARCHAR(50);

-- CreateTable
CREATE TABLE "link" (
    "link_id" UUID NOT NULL,
    "name" VARCHAR(100) NOT NULL,
    "url" VARCHAR(500) NOT NULL,
    "slug" VARCHAR(100) NOT NULL,
    "user_id" UUID,
    "team_id" UUID,
    "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
    "updated_at" TIMESTAMPTZ(6),
    "deleted_at" TIMESTAMPTZ(6),

    CONSTRAINT "link_pkey" PRIMARY KEY ("link_id")
);

-- CreateTable
CREATE TABLE "pixel" (
    "pixel_id" UUID NOT NULL,
    "name" VARCHAR(100) NOT NULL,
    "slug" VARCHAR(100) NOT NULL,
    "user_id" UUID,
    "team_id" UUID,
    "created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
    "updated_at" TIMESTAMPTZ(6),
    "deleted_at" TIMESTAMPTZ(6),

    CONSTRAINT "pixel_pkey" PRIMARY KEY ("pixel_id")
);

-- CreateIndex
CREATE UNIQUE INDEX "link_link_id_key" ON "link"("link_id");

-- CreateIndex
CREATE UNIQUE INDEX "link_slug_key" ON "link"("slug");

-- CreateIndex
CREATE INDEX "link_slug_idx" ON "link"("slug");

-- CreateIndex
CREATE INDEX "link_user_id_idx" ON "link"("user_id");

-- CreateIndex
CREATE INDEX "link_team_id_idx" ON "link"("team_id");

-- CreateIndex
CREATE INDEX "link_created_at_idx" ON "link"("created_at");

-- CreateIndex
CREATE UNIQUE INDEX "pixel_pixel_id_key" ON "pixel"("pixel_id");

-- CreateIndex
CREATE UNIQUE INDEX "pixel_slug_key" ON "pixel"("slug");

-- CreateIndex
CREATE INDEX "pixel_slug_idx" ON "pixel"("slug");

-- CreateIndex
CREATE INDEX "pixel_user_id_idx" ON "pixel"("user_id");

-- CreateIndex
CREATE INDEX "pixel_team_id_idx" ON "pixel"("team_id");

-- CreateIndex
CREATE INDEX "pixel_created_at_idx" ON "pixel"("created_at");

-- DataMigration Funnel
DELETE FROM "report" WHERE type = 'funnel' and jsonb_array_length(parameters->'steps') = 1;
UPDATE "report" SET parameters = parameters - 'websiteId' - 'dateRange' - 'urls' WHERE type = 'funnel';

UPDATE "report"
SET parameters = jsonb_set(
    parameters,
    '{steps}',
    (
      SELECT jsonb_agg(
               CASE
                 WHEN step->>'type' = 'url'
                 THEN jsonb_set(step, '{type}', '"path"')
                 ELSE step
               END
             )
      FROM jsonb_array_elements(parameters->'steps') step
    )
)
WHERE type = 'funnel'
    and parameters @> '{"steps":[{"type":"url"}]}';

-- DataMigration Goals
UPDATE "report" SET type = 'goal' WHERE type = 'goals';

INSERT INTO "report" (report_id, user_id, website_id, type, name, description, parameters, created_at, updated_at)
SELECT gen_random_uuid(),
    user_id,
    website_id,
    'goal',
    concat(name, ' - ', elem ->> 'value'),
    description,
    jsonb_build_object(
           'type', CASE WHEN elem ->> 'type' = 'url' THEN 'path'
                        ELSE elem ->> 'type' END,
           'value', elem ->> 'value'
       ) AS parameters,
    created_at,
    updated_at
FROM "report"
CROSS JOIN LATERAL jsonb_array_elements(parameters -> 'goals') elem
WHERE type = 'goal'
    and elem ->> 'type' IN ('event', 'url');

DELETE FROM "report" WHERE type = 'goal' and parameters ? 'goals';

================================================
FILE: prisma/migrations/migration_lock.toml
================================================
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "postgresql"


================================================
FILE: prisma/schema.prisma
================================================
generator client {
  provider   = "prisma-client"
  output     = "../src/generated/prisma"
  engineType = "client"
}

datasource db {
  provider     = "postgresql"
  url          = env("DATABASE_URL")
  relationMode = "prisma"
}

model User {
  id          String    @id @unique @map("user_id") @db.Uuid
  username    String    @unique @db.VarChar(255)
  password    String    @db.VarChar(60)
  role        String    @map("role") @db.VarChar(50)
  logoUrl     String?   @map("logo_url") @db.VarChar(2183)
  displayName String?   @map("display_name") @db.VarChar(255)
  createdAt   DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)
  updatedAt   DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6)
  deletedAt   DateTime? @map("deleted_at") @db.Timestamptz(6)

  websites  Website[]  @relation("user")
  createdBy Website[]  @relation("createUser")
  links     Link[]     @relation("user")
  pixels    Pixel[]    @relation("user")
  teams     TeamUser[]
  reports   Report[]

  @@map("user")
}

model Session {
  id         String    @id @unique @map("session_id") @db.Uuid
  websiteId  String    @map("website_id") @db.Uuid
  browser    String?   @db.VarChar(20)
  os         String?   @db.VarChar(20)
  device     String?   @db.VarChar(20)
  screen     String?   @db.VarChar(11)
  language   String?   @db.VarChar(35)
  country    String?   @db.Char(2)
  region     String?   @db.VarChar(20)
  city       String?   @db.VarChar(50)
  distinctId String?   @map("distinct_id") @db.VarChar(50)
  createdAt  DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)

  websiteEvents WebsiteEvent[]
  sessionData   SessionData[]
  revenue       Revenue[]

  @@index([createdAt])
  @@index([websiteId])
  @@index([websiteId, createdAt])
  @@index([websiteId, createdAt, browser])
  @@index([websiteId, createdAt, os])
  @@index([websiteId, createdAt, device])
  @@index([websiteId, createdAt, screen])
  @@index([websiteId, createdAt, language])
  @@index([websiteId, createdAt, country])
  @@index([websiteId, createdAt, region])
  @@index([websiteId, createdAt, city])
  @@map("session")
}

model Website {
  id        String    @id @unique @map("website_id") @db.Uuid
  name      String    @db.VarChar(100)
  domain    String?   @db.VarChar(500)
  shareId   String?   @unique @map("share_id") @db.VarChar(50)
  resetAt   DateTime? @map("reset_at") @db.Timestamptz(6)
  userId    String?   @map("user_id") @db.Uuid
  teamId    String?   @map("team_id") @db.Uuid
  createdBy String?   @map("created_by") @db.Uuid
  createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)
  updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6)
  deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6)

  user        User?         @relation("user", fields: [userId], references: [id])
  createUser  User?         @relation("createUser", fields: [createdBy], references: [id])
  team        Team?         @relation(fields: [teamId], references: [id])
  eventData   EventData[]
  reports     Report[]
  revenue     Revenue[]
  segments    Segment[]
  sessionData SessionData[]

  @@index([userId])
  @@index([teamId])
  @@index([createdAt])
  @@index([shareId])
  @@index([createdBy])
  @@map("website")
}

model WebsiteEvent {
  id             String    @id() @map("event_id") @db.Uuid
  websiteId      String    @map("website_id") @db.Uuid
  sessionId      String    @map("session_id") @db.Uuid
  visitId        String    @map("visit_id") @db.Uuid
  createdAt      DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)
  urlPath        String    @map("url_path") @db.VarChar(500)
  urlQuery       String?   @map("url_query") @db.VarChar(500)
  utmSource      String?   @map("utm_source") @db.VarChar(255)
  utmMedium      String?   @map("utm_medium") @db.VarChar(255)
  utmCampaign    String?   @map("utm_campaign") @db.VarChar(255)
  utmContent     String?   @map("utm_content") @db.VarChar(255)
  utmTerm        String?   @map("utm_term") @db.VarChar(255)
  referrerPath   String?   @map("referrer_path") @db.VarChar(500)
  referrerQuery  String?   @map("referrer_query") @db.VarChar(500)
  referrerDomain String?   @map("referrer_domain") @db.VarChar(500)
  pageTitle      String?   @map("page_title") @db.VarChar(500)
  gclid          String?   @db.VarChar(255)
  fbclid         String?   @db.VarChar(255)
  msclkid        String?   @db.VarChar(255)
  ttclid         String?   @db.VarChar(255)
  lifatid        String?   @map("li_fat_id") @db.VarChar(255)
  twclid         String?   @db.VarChar(255)
  eventType      Int       @default(1) @map("event_type") @db.Integer
  eventName      String?   @map("event_name") @db.VarChar(50)
  tag            String?   @db.VarChar(50)
  hostname       String?   @db.VarChar(100)

  eventData EventData[]
  session   Session     @relation(fields: [sessionId], references: [id])

  @@index([createdAt])
  @@index([sessionId])
  @@index([visitId])
  @@index([websiteId])
  @@index([websiteId, createdAt])
  @@index([websiteId, createdAt, urlPath])
  @@index([websiteId, createdAt, urlQuery])
  @@index([websiteId, createdAt, referrerDomain])
  @@index([websiteId, createdAt, pageTitle])
  @@index([websiteId, createdAt, eventName])
  @@index([websiteId, createdAt, tag])
  @@index([websiteId, sessionId, createdAt])
  @@index([websiteId, visitId, createdAt])
  @@index([websiteId, createdAt, hostname])
  @@map("website_event")
}

model EventData {
  id             String    @id() @map("event_data_id") @db.Uuid
  websiteId      String    @map("website_id") @db.Uuid
  websiteEventId String    @map("website_event_id") @db.Uuid
  dataKey        String    @map("data_key") @db.VarChar(500)
  stringValue    String?   @map("string_value") @db.VarChar(500)
  numberValue    Decimal?  @map("number_value") @db.Decimal(19, 4)
  dateValue      DateTime? @map("date_value") @db.Timestamptz(6)
  dataType       Int       @map("data_type") @db.Integer
  createdAt      DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)

  website      Website      @relation(fields: [websiteId], references: [id])
  websiteEvent WebsiteEvent @relation(fields: [websiteEventId], references: [id])

  @@index([createdAt])
  @@index([websiteId])
  @@index([websiteEventId])
  @@index([websiteId, createdAt])
  @@index([websiteId, createdAt, dataKey])
  @@map("event_data")
}

model SessionData {
  id          String    @id() @map("session_data_id") @db.Uuid
  websiteId   String    @map("website_id") @db.Uuid
  sessionId   String    @map("session_id") @db.Uuid
  dataKey     String    @map("data_key") @db.VarChar(500)
  stringValue String?   @map("string_value") @db.VarChar(500)
  numberValue Decimal?  @map("number_value") @db.Decimal(19, 4)
  dateValue   DateTime? @map("date_value") @db.Timestamptz(6)
  dataType    Int       @map("data_type") @db.Integer
  distinctId  String?   @map("distinct_id") @db.VarChar(50)
  createdAt   DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)

  website Website @relation(fields: [websiteId], references: [id])
  session Session @relation(fields: [sessionId], references: [id])

  @@index([createdAt])
  @@index([websiteId])
  @@index([sessionId])
  @@index([sessionId, createdAt])
  @@index([websiteId, createdAt, dataKey])
  @@map("session_data")
}

model Team {
  id         String    @id() @unique() @map("team_id") @db.Uuid
  name       String    @db.VarChar(50)
  accessCode String?   @unique @map("access_code") @db.VarChar(50)
  logoUrl    String?   @map("logo_url") @db.VarChar(2183)
  createdAt  DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)
  updatedAt  DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6)
  deletedAt  DateTime? @map("deleted_at") @db.Timestamptz(6)

  websites Website[]
  members  TeamUser[]
  links    Link[]
  pixels   Pixel[]

  @@index([accessCode])
  @@map("team")
}

model TeamUser {
  id        String    @id() @unique() @map("team_user_id") @db.Uuid
  teamId    String    @map("team_id") @db.Uuid
  userId    String    @map("user_id") @db.Uuid
  role      String    @db.VarChar(50)
  createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)
  updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6)

  team Team @relation(fields: [teamId], references: [id])
  user User @relation(fields: [userId], references: [id])

  @@index([teamId])
  @@index([userId])
  @@map("team_user")
}

model Report {
  id          String    @id() @unique() @map("report_id") @db.Uuid
  userId      String    @map("user_id") @db.Uuid
  websiteId   String    @map("website_id") @db.Uuid
  type        String    @db.VarChar(50)
  name        String    @db.VarChar(200)
  description String    @db.VarChar(500)
  parameters  Json
  createdAt   DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)
  updatedAt   DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6)

  user    User    @relation(fields: [userId], references: [id])
  website Website @relation(fields: [websiteId], references: [id])

  @@index([userId])
  @@index([websiteId])
  @@index([type])
  @@index([name])
  @@map("report")
}

model Segment {
  id         String    @id() @unique() @map("segment_id") @db.Uuid
  websiteId  String    @map("website_id") @db.Uuid
  type       String    @db.VarChar(50)
  name       String    @db.VarChar(200)
  parameters Json
  createdAt  DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)
  updatedAt  DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6)

  website Website @relation(fields: [websiteId], references: [id])

  @@index([websiteId])
  @@map("segment")
}

model Revenue {
  id        String    @id() @unique() @map("revenue_id") @db.Uuid
  websiteId String    @map("website_id") @db.Uuid
  sessionId String    @map("session_id") @db.Uuid
  eventId   String    @map("event_id") @db.Uuid
  eventName String    @map("event_name") @db.VarChar(50)
  currency  String    @db.VarChar(10)
  revenue   Decimal?  @db.Decimal(19, 4)
  createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)

  website Website @relation(fields: [websiteId], references: [id])
  session Session @relation(fields: [sessionId], references: [id])

  @@index([websiteId])
  @@index([sessionId])
  @@index([websiteId, createdAt])
  @@index([websiteId, sessionId, createdAt])
  @@map("revenue")
}

model Link {
  id        String    @id() @unique() @map("link_id") @db.Uuid
  name      String    @db.VarChar(100)
  url       String    @db.VarChar(500)
  slug      String    @unique() @db.VarChar(100)
  userId    String?   @map("user_id") @db.Uuid
  teamId    String?   @map("team_id") @db.Uuid
  createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)
  updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6)
  deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6)

  user User? @relation("user", fields: [userId], references: [id])
  team Team? @relation(fields: [teamId], references: [id])

  @@index([slug])
  @@index([userId])
  @@index([teamId])
  @@index([createdAt])
  @@map("link")
}

model Pixel {
  id        String    @id() @unique() @map("pixel_id") @db.Uuid
  name      String    @db.VarChar(100)
  slug      String    @unique() @db.VarChar(100)
  userId    String?   @map("user_id") @db.Uuid
  teamId    String?   @map("team_id") @db.Uuid
  createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)
  updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6)
  deletedAt DateTime? @map("deleted_at") @db.Timestamptz(6)

  user User? @relation("user", fields: [userId], references: [id])
  team Team? @relation(fields: [teamId], references: [id])

  @@index([slug])
  @@index([userId])
  @@index([teamId])
  @@index([createdAt])
  @@map("pixel")
}


================================================
FILE: prisma.config.ts
================================================
import 'dotenv/config';
import { defineConfig, env } from 'prisma/config';

export default defineConfig({
  datasource: {
    url: env('DATABASE_URL'),
  },
});


================================================
FILE: public/browserconfig.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
    <msapplication>
        <tile>
            <square150x150logo src="/mstile-150x150.png"/>
            <TileColor>#da532c</TileColor>
        </tile>
    </msapplication>
</browserconfig>


================================================
FILE: public/datamaps.world.json
================================================
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": { "name": "Afghanistan" },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [61.210817, 35.650072],
            [62.230651, 35.270664],
            [62.984662, 35.404041],
            [63.193538, 35.857166],
            [63.982896, 36.007957],
            [64.546479, 36.312073],
            [64.746105, 37.111818],
            [65.588948, 37.305217],
            [65.745631, 37.661164],
            [66.217385, 37.39379],
            [66.518607, 37.362784],
            [67.075782, 37.356144],
            [67.83, 37.144994],
            [68.135562, 37.023115],
            [68.859446, 37.344336],
            [69.196273, 37.151144],
            [69.518785, 37.608997],
            [70.116578, 37.588223],
            [70.270574, 37.735165],
            [70.376304, 38.138396],
            [70.806821, 38.486282],
            [71.348131, 38.258905],
            [71.239404, 37.953265],
            [71.541918, 37.905774],
            [71.448693, 37.065645],
            [71.844638, 36.738171],
            [72.193041, 36.948288],
            [72.63689, 37.047558],
            [73.260056, 37.495257],
            [73.948696, 37.421566],
            [74.980002, 37.41999],
            [75.158028, 37.133031],
            [74.575893, 37.020841],
            [74.067552, 36.836176],
            [72.920025, 36.720007],
            [71.846292, 36.509942],
            [71.262348, 36.074388],
            [71.498768, 35.650563],
            [71.613076, 35.153203],
            [71.115019, 34.733126],
            [71.156773, 34.348911],
            [70.881803, 33.988856],
            [69.930543, 34.02012],
            [70.323594, 33.358533],
            [69.687147, 33.105499],
            [69.262522, 32.501944],
            [69.317764, 31.901412],
            [68.926677, 31.620189],
            [68.556932, 31.71331],
            [67.792689, 31.58293],
            [67.683394, 31.303154],
            [66.938891, 31.304911],
            [66.381458, 30.738899],
            [66.346473, 29.887943],
            [65.046862, 29.472181],
            [64.350419, 29.560031],
            [64.148002, 29.340819],
            [63.550261, 29.468331],
            [62.549857, 29.318572],
            [60.874248, 29.829239],
            [61.781222, 30.73585],
            [61.699314, 31.379506],
            [60.941945, 31.548075],
            [60.863655, 32.18292],
            [60.536078, 32.981269],
            [60.9637, 33.528832],
            [60.52843, 33.676446],
            [60.803193, 34.404102],
            [61.210817, 35.650072]
          ]
        ]
      },
      "id": "AFG"
    },
    {
      "type": "Feature",
      "properties": { "name": "Angola" },
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
          [
            [
              [16.326528, -5.87747],
              [16.57318, -6.622645],
              [16.860191, -7.222298],
              [17.089996, -7.545689],
              [17.47297, -8.068551],
              [18.134222, -7.987678],
              [18.464176, -7.847014],
              [19.016752, -7.988246],
              [19.166613, -7.738184],
              [19.417502, -7.155429],
              [20.037723, -7.116361],
              [20.091622, -6.94309],
              [20.601823, -6.939318],
              [20.514748, -7.299606],
              [21.728111, -7.290872],
              [21.746456, -7.920085],
              [21.949131, -8.305901],
              [21.801801, -8.908707],
              [21.875182, -9.523708],
              [22.208753, -9.894796],
              [22.155268, -11.084801],
              [22.402798, -10.993075],
              [22.837345, -11.017622],
              [23.456791, -10.867863],
              [23.912215, -10.926826],
              [24.017894, -11.237298],
              [23.904154, -11.722282],
              [24.079905, -12.191297],
              [23.930922, -12.565848],
              [24.016137, -12.911046],
              [21.933886, -12.898437],
              [21.887843, -16.08031],
              [22.562478, -16.898451],
              [23.215048, -17.523116],
              [21.377176, -17.930636],
              [18.956187, -17.789095],
              [18.263309, -17.309951],
              [14.209707, -17.353101],
              [14.058501, -17.423381],
              [13.462362, -16.971212],
              [12.814081, -16.941343],
              [12.215461, -17.111668],
              [11.734199, -17.301889],
              [11.640096, -16.673142],
              [11.778537, -15.793816],
              [12.123581, -14.878316],
              [12.175619, -14.449144],
              [12.500095, -13.5477],
              [12.738479, -13.137906],
              [13.312914, -12.48363],
              [13.633721, -12.038645],
              [13.738728, -11.297863],
              [13.686379, -10.731076],
              [13.387328, -10.373578],
              [13.120988, -9.766897],
              [12.87537, -9.166934],
              [12.929061, -8.959091],
              [13.236433, -8.562629],
              [12.93304, -7.596539],
              [12.728298, -6.927122],
              [12.227347, -6.294448],
              [12.322432, -6.100092],
              [12.735171, -5.965682],
              [13.024869, -5.984389],
              [13.375597, -5.864241],
              [16.326528, -5.87747]
            ]
          ],
          [
            [
              [12.436688, -5.684304],
              [12.182337, -5.789931],
              [11.914963, -5.037987],
              [12.318608, -4.60623],
              [12.62076, -4.438023],
              [12.995517, -4.781103],
              [12.631612, -4.991271],
              [12.468004, -5.248362],
              [12.436688, -5.684304]
            ]
          ]
        ]
      },
      "id": "AGO"
    },
    {
      "type": "Feature",
      "properties": { "name": "Albania" },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [20.590247, 41.855404],
            [20.463175, 41.515089],
            [20.605182, 41.086226],
            [21.02004, 40.842727],
            [20.99999, 40.580004],
            [20.674997, 40.435],
            [20.615, 40.110007],
            [20.150016, 39.624998],
            [19.98, 39.694993],
            [19.960002, 39.915006],
            [19.406082, 40.250773],
            [19.319059, 40.72723],
            [19.40355, 41.409566],
            [19.540027, 41.719986],
            [19.371769, 41.877548],
            [19.304486, 42.195745],
            [19.738051, 42.688247],
            [19.801613, 42.500093],
            [20.0707, 42.58863],
            [20.283755, 42.32026],
            [20.52295, 42.21787],
            [20.590247, 41.855404]
          ]
        ]
      },
      "id": "ALB"
    },
    {
      "type": "Feature",
      "properties": { "name": "United Arab Emirates" },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [51.579519, 24.245497],
            [51.757441, 24.294073],
            [51.794389, 24.019826],
            [52.577081, 24.177439],
            [53.404007, 24.151317],
            [54.008001, 24.121758],
            [54.693024, 24.797892],
            [55.439025, 25.439145],
            [56.070821, 26.055464],
            [56.261042, 25.714606],
            [56.396847, 24.924732],
            [55.886233, 24.920831],
            [55.804119, 24.269604],
            [55.981214, 24.130543],
            [55.528632, 23.933604],
            [55.525841, 23.524869],
            [55.234489, 23.110993],
            [55.208341, 22.70833],
            [55.006803, 22.496948],
            [52.000733, 23.001154],
            [51.617708, 24.014219],
            [51.579519, 24.245497]
          ]
        ]
      },
      "id": "ARE"
    },
    {
      "type": "Feature",
      "properties": { "name": "Argentina" },
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
          [
            [
              [-65.5, -55.2],
              [-66.45, -55.25],
              [-66.95992, -54.89681],
              [-67.56244, -54.87001],
              [-68.63335, -54.8695],
              [-68.63401, -52.63637],
              [-68.25, -53.1],
              [-67.75, -53.85],
              [-66.45, -54.45],
              [-65.05, -54.7],
              [-65.5, -55.2]
            ]
          ],
          [
            [
              [-64.964892, -22.075862],
              [-64.377021, -22.798091],
              [-63.986838, -21.993644],
              [-62.846468, -22.034985],
              [-62.685057, -22.249029],
              [-60.846565, -23.880713],
              [-60.028966, -24.032796],
              [-58.807128, -24.771459],
              [-57.777217, -25.16234],
              [-57.63366, -25.603657],
              [-58.618174, -27.123719],
              [-57.60976, -27.395899],
              [-56.486702, -27.548499],
              [-55.695846, -27.387837],
              [-54.788795, -26.621786],
              [-54.625291, -25.739255],
              [-54.13005, -25.547639],
              [-53.628349, -26.124865],
              [-53.648735, -26.923473],
              [-54.490725, -27.474757],
              [-55.162286, -27.881915],
              [-56.2909, -28.852761],
              [-57.625133, -30.216295],
              [-57.874937, -31.016556],
              [-58.14244, -32.044504],
              [-58.132648, -33.040567],
              [-58.349611, -33.263189],
              [-58.427074, -33.909454],
              [-58.495442, -34.43149],
              [-57.22583, -35.288027],
              [-57.362359, -35.97739],
              [-56.737487, -36.413126],
              [-56.788285, -36.901572],
              [-57.749157, -38.183871],
              [-59.231857, -38.72022],
              [-61.237445, -38.928425],
              [-62.335957, -38.827707],
              [-62.125763, -39.424105],
              [-62.330531, -40.172586],
              [-62.145994, -40.676897],
              [-62.745803, -41.028761],
              [-63.770495, -41.166789],
              [-64.73209, -40.802677],
              [-65.118035, -41.064315],
              [-64.978561, -42.058001],
              [-64.303408, -42.359016],
              [-63.755948, -42.043687],
              [-63.458059, -42.563138],
              [-64.378804, -42.873558],
              [-65.181804, -43.495381],
              [-65.328823, -44.501366],
              [-65.565269, -45.036786],
              [-66.509966, -45.039628],
              [-67.293794, -45.551896],
              [-67.580546, -46.301773],
              [-66.597066, -47.033925],
              [-65.641027, -47.236135],
              [-65.985088, -48.133289],
              [-67.166179, -48.697337],
              [-67.816088, -49.869669],
              [-68.728745, -50.264218],
              [-69.138539, -50.73251],
              [-68.815561, -51.771104],
              [-68.149995, -52.349983],
              [-68.571545, -52.299444],
              [-69.498362, -52.142761],
              [-71.914804, -52.009022],
              [-72.329404, -51.425956],
              [-72.309974, -50.67701],
              [-72.975747, -50.74145],
              [-73.328051, -50.378785],
              [-73.415436, -49.318436],
              [-72.648247, -48.878618],
              [-72.331161, -48.244238],
              [-72.447355, -47.738533],
              [-71.917258, -46.884838],
              [-71.552009, -45.560733],
              [-71.659316, -44.973689],
              [-71.222779, -44.784243],
              [-71.329801, -44.407522],
              [-71.793623, -44.207172],
              [-71.464056, -43.787611],
              [-71.915424, -43.408565],
              [-72.148898, -42.254888],
              [-71.746804, -42.051386],
              [-71.915734, -40.832339],
              [-71.680761, -39.808164],
              [-71.413517, -38.916022],
              [-70.814664, -38.552995],
              [-71.118625, -37.576827],
              [-71.121881, -36.658124],
              [-70.364769, -36.005089],
              [-70.388049, -35.169688],
              [-69.817309, -34.193571],
              [-69.814777, -33.273886],
              [-70.074399, -33.09121],
              [-70.535069, -31.36501],
              [-69.919008, -30.336339],
              [-70.01355, -29.367923],
              [-69.65613, -28.459141],
              [-69.001235, -27.521214],
              [-68.295542, -26.89934],
              [-68.5948, -26.506909],
              [-68.386001, -26.185016],
              [-68.417653, -24.518555],
              [-67.328443, -24.025303],
              [-66.985234, -22.986349],
              [-67.106674, -22.735925],
              [-66.273339, -21.83231],
              [-64.964892, -22.075862]
            ]
          ]
        ]
      },
      "id": "ARG"
    },
    {
      "type": "Feature",
      "properties": { "name": "Armenia" },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [43.582746, 41.092143],
            [44.97248, 41.248129],
            [45.179496, 40.985354],
            [45.560351, 40.81229],
            [45.359175, 40.561504],
            [45.891907, 40.218476],
            [45.610012, 39.899994],
            [46.034534, 39.628021],
            [46.483499, 39.464155],
            [46.50572, 38.770605],
            [46.143623, 38.741201],
            [45.735379, 39.319719],
            [45.739978, 39.473999],
            [45.298145, 39.471751],
            [45.001987, 39.740004],
            [44.79399, 39.713003],
            [44.400009, 40.005],
            [43.656436, 40.253564],
            [43.752658, 40.740201],
            [43.582746, 41.092143]
          ]
        ]
      },
      "id": "ARM"
    },
    {
      "type": "Feature",
      "properties": { "name": "Antarctica" },
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
          [
            [
              [-59.572095, -80.040179],
              [-59.865849, -80.549657],
              [-60.159656, -81.000327],
              [-62.255393, -80.863178],
              [-64.488125, -80.921934],
              [-65.741666, -80.588827],
              [-65.741666, -80.549657],
              [-66.290031, -80.255773],
              [-64.037688, -80.294944],
              [-61.883246, -80.39287],
              [-61.138976, -79.981371],
              [-60.610119, -79.628679],
              [-59.572095, -80.040179]
            ]
          ],
          [
            [
              [-159.208184, -79.497059],
              [-161.127601, -79.634209],
              [-162.439847, -79.281465],
              [-163.027408, -78.928774],
              [-163.066604, -78.869966],
              [-163.712896, -78.595667],
              [-163.712896, -78.595667],
              [-163.105801, -78.223338],
              [-161.245113, -78.380176],
              [-160.246208, -78.693645],
              [-159.482405, -79.046338],
              [-159.208184, -79.497059]
            ]
          ],
          [
            [
              [-45.154758, -78.04707],
              [-43.920828, -78.478103],
              [-43.48995, -79.08556],
              [-43.372438, -79.516645],
              [-43.333267, -80.026123],
              [-44.880537, -80.339644],
              [-46.506174, -80.594357],
              [-48.386421, -80.829485],
              [-50.482107, -81.025442],
              [-52.851988, -80.966685],
              [-54.164259, -80.633528],
              [-53.987991, -80.222028],
              [-51.853134, -79.94773],
              [-50.991326, -79.614623],
              [-50.364595, -79.183487],
              [-49.914131, -78.811209],
              [-49.306959, -78.458569],
              [-48.660616, -78.047018],
              [-48.660616, -78.047019],
              [-48.151396, -78.04707],
              [-46.662857, -77.831476],
              [-45.154758, -78.04707]
            ]
          ],
          [
            [
              [-121.211511, -73.50099],
              [-119.918851, -73.657725],
              [-118.724143, -73.481353],
              [-119.292119, -73.834097],
              [-120.232217, -74.08881],
              [-121.62283, -74.010468],
              [-122.621735, -73.657778],
              [-122.621735, -73.657777],
              [-122.406245, -73.324619],
              [-121.211511, -73.50099]
            ]
          ],
          [
            [
              [-125.559566, -73.481353],
              [-124.031882, -73.873268],
              [-124.619469, -73.834097],
              [-125.912181, -73.736118],
              [-127.28313, -73.461769],
              [-127.28313, -73.461768],
              [-126.558472, -73.246226],
              [-125.559566, -73.481353]
            ]
          ],
          [
            [
              [-98.98155, -71.933334],
              [-97.884743, -72.070535],
              [-96.787937, -71.952971],
              [-96.20035, -72.521205],
              [-96.983765, -72.442864],
              [-98.198083, -72.482035],
              [-99.432013, -72.442864],
              [-100.783455, -72.50162],
              [-101.801868, -72.305663],
              [-102.330725, -71.894164],
              [-102.330725, -71.894164],
              [-101.703967, -71.717792],
              [-100.430919, -71.854993],
              [-98.98155, -71.933334]
            ]
          ],
          [
            [
              [-68.451346, -70.955823],
              [-68.333834, -71.406493],
              [-68.510128, -71.798407],
              [-68.784297, -72.170736],
              [-69.959471, -72.307885],
              [-71.075889, -72.503842],
              [-72.388134, -72.484257],
              [-71.8985, -72.092343],
              [-73.073622, -72.229492],
              [-74.19004, -72.366693],
              [-74.953895, -72.072757],
              [-75.012625, -71.661258],
              [-73.915819, -71.269345],
              [-73.915819, -71.269344],
              [-73.230331, -71.15178],
              [-72.074717, -71.190951],
              [-71.780962, -70.681473],
              [-71.72218, -70.309196],
              [-71.741791, -69.505782],
              [-71.173815, -69.035475],
              [-70.253252, -68.87874],
              [-69.724447, -69.251017],
              [-69.489422, -69.623346],
              [-69.058518, -70.074016],
              [-68.725541, -70.505153],
              [-68.451346, -70.955823]
            ]
          ],
          [
            [
              [-58.614143, -64.152467],
              [-59.045073, -64.36801],
              [-59.789342, -64.211223],
              [-60.611928, -64.309202],
              [-61.297416, -64.54433],
              [-62.0221, -64.799094],
              [-62.51176, -65.09303],
              [-62.648858, -65.484942],
              [-62.590128, -65.857219],
              [-62.120079, -66.190326],
              [-62.805567, -66.425505],
              [-63.74569, -66.503847],
              [-64.294106, -66.837004],
              [-64.881693, -67.150474],
              [-65.508425, -67.58161],
              [-65.665082, -67.953887],
              [-65.312545, -68.365335],
              [-64.783715, -68.678908],
              [-63.961103, -68.913984],
              [-63.1973, -69.227556],
              [-62.785955, -69.619419],
              [-62.570516, -69.991747],
              [-62.276736, -70.383661],
              [-61.806661, -70.716768],
              [-61.512906, -71.089045],
              [-61.375809, -72.010074],
              [-61.081977, -72.382351],
              [-61.003661, -72.774265],
              [-60.690269, -73.166179],
              [-60.827367, -73.695242],
              [-61.375809, -74.106742],
              [-61.96337, -74.439848],
              [-63.295201, -74.576997],
              [-63.74569, -74.92974],
              [-64.352836, -75.262847],
              [-65.860987, -75.635124],
              [-67.192818, -75.79191],
              [-68.446282, -76.007452],
              [-69.797724, -76.222995],
              [-70.600724, -76.634494],
              [-72.206776, -76.673665],
              [-73.969536, -76.634494],
              [-75.555977, -76.712887],
              [-77.24037, -76.712887],
              [-76.926979, -77.104802],
              [-75.399294, -77.28107],
              [-74.282876, -77.55542],
              [-73.656119, -77.908112],
              [-74.772536, -78.221633],
              [-76.4961, -78.123654],
              [-77.925858, -78.378419],
              [-77.984666, -78.789918],
              [-78.023785, -79.181833],
              [-76.848637, -79.514939],
              [-76.633224, -79.887216],
              [-75.360097, -80.259545],
              [-73.244852, -80.416331],
              [-71.442946, -80.69063],
              [-70.013163, -81.004151],
              [-68.191646, -81.317672],
              [-65.704279, -81.474458],
              [-63.25603, -81.748757],
              [-61.552026, -82.042692],
              [-59.691416, -82.37585],
              [-58.712121, -82.846106],
              [-58.222487, -83.218434],
              [-57.008117, -82.865691],
              [-55.362894, -82.571755],
              [-53.619771, -82.258235],
              [-51.543644, -82.003521],
              [-49.76135, -81.729171],
              [-47.273931, -81.709586],
              [-44.825708, -81.846735],
              [-42.808363, -82.081915],
              [-42.16202, -81.65083],
              [-40.771433, -81.356894],
              [-38.244818, -81.337309],
              [-36.26667, -81.121715],
              [-34.386397, -80.906172],
              [-32.310296, -80.769023],
              [-30.097098, -80.592651],
              [-28.549802, -80.337938],
              [-29.254901, -79.985195],
              [-29.685805, -79.632503],
              [-29.685805, -79.260226],
              [-31.624808, -79.299397],
              [-33.681324, -79.456132],
              [-35.639912, -79.456132],
              [-35.914107, -79.083855],
              [-35.77701, -78.339248],
              [-35.326546, -78.123654],
              [-33.896763, -77.888526],
              [-32.212369, -77.65345],
              [-30.998051, -77.359515],
              [-29.783732, -77.065579],
              [-28.882779, -76.673665],
              [-27.511752, -76.497345],
              [-26.160336, -76.360144],
              [-25.474822, -76.281803],
              [-23.927552, -76.24258],
              [-22.458598, -76.105431],
              [-21.224694, -75.909474],
              [-20.010375, -75.674346],
              [-18.913543, -75.439218],
              [-17.522982, -75.125698],
              [-16.641589, -74.79254],
              [-15.701491, -74.498604],
              [-15.40771, -74.106742],
              [-16.46532, -73.871614],
              [-16.112784, -73.460114],
              [-15.446855, -73.146542],
              [-14.408805, -72.950585],
              [-13.311973, -72.715457],
              [-12.293508, -72.401936],
              [-11.510067, -72.010074],
              [-11.020433, -71.539767],
              [-10.295774, -71.265416],
              [-9.101015, -71.324224],
              [-8.611381, -71.65733],
              [-7.416622, -71.696501],
              [-7.377451, -71.324224],
              [-6.868232, -70.93231],
              [-5.790985, -71.030289],
              [-5.536375, -71.402617],
              [-4.341667, -71.461373],
              [-3.048981, -71.285053],
              [-1.795492, -71.167438],
              [-0.659489, -71.226246],
              [-0.228637, -71.637745],
              [0.868195, -71.304639],
              [1.886686, -71.128267],
              [3.022638, -70.991118],
              [4.139055, -70.853917],
              [5.157546, -70.618789],
              [6.273912, -70.462055],
              [7.13572, -70.246512],
              [7.742866, -69.893769],
              [8.48711, -70.148534],
              [9.525135, -70.011333],
              [10.249845, -70.48164],
              [10.817821, -70.834332],
              [11.953824, -70.638375],
              [12.404287, -70.246512],
              [13.422778, -69.972162],
              [14.734998, -70.030918],
              [15.126757, -70.403247],
              [15.949342, -70.030918],
              [17.026589, -69.913354],
              [18.201711, -69.874183],
              [19.259373, -69.893769],
              [20.375739, -70.011333],
              [21.452985, -70.07014],
              [21.923034, -70.403247],
              [22.569403, -70.697182],
              [23.666184, -70.520811],
              [24.841357, -70.48164],
              [25.977309, -70.48164],
              [27.093726, -70.462055],
              [28.09258, -70.324854],
              [29.150242, -70.20729],
              [30.031583, -69.93294],
              [30.971733, -69.75662],
              [31.990172, -69.658641],
              [32.754053, -69.384291],
              [33.302443, -68.835642],
              [33.870419, -68.502588],
              [34.908495, -68.659271],
              [35.300202, -69.012014],
              [36.16201, -69.247142],
              [37.200035, -69.168748],
              [37.905108, -69.52144],
              [38.649404, -69.776205],
              [39.667894, -69.541077],
              [40.020431, -69.109941],
              [40.921358, -68.933621],
              [41.959434, -68.600514],
              [42.938702, -68.463313],
              [44.113876, -68.267408],
              [44.897291, -68.051866],
              [45.719928, -67.816738],
              [46.503343, -67.601196],
              [47.44344, -67.718759],
              [48.344419, -67.366068],
              [48.990736, -67.091718],
              [49.930885, -67.111303],
              [50.753471, -66.876175],
              [50.949325, -66.523484],
              [51.791547, -66.249133],
              [52.614133, -66.053176],
              [53.613038, -65.89639],
              [54.53355, -65.818049],
              [55.414943, -65.876805],
              [56.355041, -65.974783],
              [57.158093, -66.249133],
              [57.255968, -66.680218],
              [58.137361, -67.013324],
              [58.744508, -67.287675],
              [59.939318, -67.405239],
              [60.605221, -67.679589],
              [61.427806, -67.953887],
              [62.387489, -68.012695],
              [63.19049, -67.816738],
              [64.052349, -67.405239],
              [64.992447, -67.620729],
              [65.971715, -67.738345],
              [66.911864, -67.855909],
              [67.891133, -67.934302],
              [68.890038, -67.934302],
              [69.712624, -68.972791],
              [69.673453, -69.227556],
              [69.555941, -69.678226],
              [68.596258, -69.93294],
              [67.81274, -70.305268],
              [67.949889, -70.697182],
              [69.066307, -70.677545],
              [68.929157, -71.069459],
              [68.419989, -71.441788],
              [67.949889, -71.853287],
              [68.71377, -72.166808],
              [69.869307, -72.264787],
              [71.024895, -72.088415],
              [71.573285, -71.696501],
              [71.906288, -71.324224],
              [72.454627, -71.010703],
              [73.08141, -70.716768],
              [73.33602, -70.364024],
              [73.864877, -69.874183],
              [74.491557, -69.776205],
              [75.62756, -69.737034],
              [76.626465, -69.619419],
              [77.644904, -69.462684],
              [78.134539, -69.07077],
              [78.428371, -68.698441],
              [79.113859, -68.326216],
              [80.093127, -68.071503],
              [80.93535, -67.875546],
              [81.483792, -67.542388],
              [82.051767, -67.366068],
              [82.776426, -67.209282],
              [83.775331, -67.30726],
              [84.676206, -67.209282],
              [85.655527, -67.091718],
              [86.752359, -67.150474],
              [87.477017, -66.876175],
              [87.986289, -66.209911],
              [88.358411, -66.484261],
              [88.828408, -66.954568],
              [89.67063, -67.150474],
              [90.630365, -67.228867],
              [91.5901, -67.111303],
              [92.608539, -67.189696],
              [93.548637, -67.209282],
              [94.17542, -67.111303],
              [95.017591, -67.170111],
              [95.781472, -67.385653],
              [96.682399, -67.248504],
              [97.759646, -67.248504],
              [98.68021, -67.111303],
              [99.718182, -67.248504],
              [100.384188, -66.915346],
              [100.893356, -66.58224],
              [101.578896, -66.30789],
              [102.832411, -65.563284],
              [103.478676, -65.700485],
              [104.242557, -65.974783],
              [104.90846, -66.327527],
              [106.181561, -66.934931],
              [107.160881, -66.954568],
              [108.081393, -66.954568],
              [109.15864, -66.837004],
              [110.235835, -66.699804],
              [111.058472, -66.425505],
              [111.74396, -66.13157],
              [112.860378, -66.092347],
              [113.604673, -65.876805],
              [114.388088, -66.072762],
              [114.897308, -66.386283],
              [115.602381, -66.699804],
              [116.699161, -66.660633],
              [117.384701, -66.915346],
              [118.57946, -67.170111],
              [119.832924, -67.268089],
              [120.871, -67.189696],
              [121.654415, -66.876175],
              [122.320369, -66.562654],
              [123.221296, -66.484261],
              [124.122274, -66.621462],
              [125.160247, -66.719389],
              [126.100396, -66.562654],
              [127.001427, -66.562654],
              [127.882768, -66.660633],
              [128.80328, -66.758611],
              [129.704259, -66.58224],
              [130.781454, -66.425505],
              [131.799945, -66.386283],
              [132.935896, -66.386283],
              [133.85646, -66.288304],
              [134.757387, -66.209963],
              [135.031582, -65.72007],
              [135.070753, -65.308571],
              [135.697485, -65.582869],
              [135.873805, -66.033591],
              [136.206705, -66.44509],
              [136.618049, -66.778197],
              [137.460271, -66.954568],
              [138.596223, -66.895761],
              [139.908442, -66.876175],
              [140.809421, -66.817367],
              [142.121692, -66.817367],
              [143.061842, -66.797782],
              [144.374061, -66.837004],
              [145.490427, -66.915346],
              [146.195552, -67.228867],
              [145.999699, -67.601196],
              [146.646067, -67.895131],
              [147.723263, -68.130259],
              [148.839629, -68.385024],
              [150.132314, -68.561292],
              [151.483705, -68.71813],
              [152.502247, -68.874813],
              [153.638199, -68.894502],
              [154.284567, -68.561292],
              [155.165857, -68.835642],
              [155.92979, -69.149215],
              [156.811132, -69.384291],
              [158.025528, -69.482269],
              [159.181013, -69.599833],
              [159.670699, -69.991747],
              [160.80665, -70.226875],
              [161.570479, -70.579618],
              [162.686897, -70.736353],
              [163.842434, -70.716768],
              [164.919681, -70.775524],
              [166.11444, -70.755938],
              [167.309095, -70.834332],
              [168.425616, -70.971481],
              [169.463589, -71.20666],
              [170.501665, -71.402617],
              [171.20679, -71.696501],
              [171.089227, -72.088415],
              [170.560422, -72.441159],
              [170.109958, -72.891829],
              [169.75737, -73.24452],
              [169.287321, -73.65602],
              [167.975101, -73.812806],
              [167.387489, -74.165498],
              [166.094803, -74.38104],
              [165.644391, -74.772954],
              [164.958851, -75.145283],
              [164.234193, -75.458804],
              [163.822797, -75.870303],
              [163.568239, -76.24258],
              [163.47026, -76.693302],
              [163.489897, -77.065579],
              [164.057873, -77.457442],
              [164.273363, -77.82977],
              [164.743464, -78.182514],
              [166.604126, -78.319611],
              [166.995781, -78.750748],
              [165.193876, -78.907483],
              [163.666217, -79.123025],
              [161.766385, -79.162248],
              [160.924162, -79.730482],
              [160.747894, -80.200737],
              [160.316964, -80.573066],
              [159.788211, -80.945395],
              [161.120016, -81.278501],
              [161.629287, -81.690001],
              [162.490992, -82.062278],
              [163.705336, -82.395435],
              [165.095949, -82.708956],
              [166.604126, -83.022477],
              [168.895665, -83.335998],
              [169.404782, -83.825891],
              [172.283934, -84.041433],
              [172.477049, -84.117914],
              [173.224083, -84.41371],
              [175.985672, -84.158997],
              [178.277212, -84.472518],
              [180, -84.71338],
              [-179.942499, -84.721443],
              [-179.058677, -84.139412],
              [-177.256772, -84.452933],
              [-177.140807, -84.417941],
              [-176.084673, -84.099259],
              [-175.947235, -84.110449],
              [-175.829882, -84.117914],
              [-174.382503, -84.534323],
              [-173.116559, -84.117914],
              [-172.889106, -84.061019],
              [-169.951223, -83.884647],
              [-168.999989, -84.117914],
              [-168.530199, -84.23739],
              [-167.022099, -84.570497],
              [-164.182144, -84.82521],
              [-161.929775, -85.138731],
              [-158.07138, -85.37391],
              [-155.192253, -85.09956],
              [-150.942099, -85.295517],
              [-148.533073, -85.609038],
              [-145.888918, -85.315102],
              [-143.107718, -85.040752],
              [-142.892279, -84.570497],
              [-146.829068, -84.531274],
              [-150.060732, -84.296146],
              [-150.902928, -83.904232],
              [-153.586201, -83.68869],
              [-153.409907, -83.23802],
              [-153.037759, -82.82652],
              [-152.665637, -82.454192],
              [-152.861517, -82.042692],
              [-154.526299, -81.768394],
              [-155.29018, -81.41565],
              [-156.83745, -81.102129],
              [-154.408787, -81.160937],
              [-152.097662, -81.004151],
              [-150.648293, -81.337309],
              [-148.865998, -81.043373],
              [-147.22075, -80.671045],
              [-146.417749, -80.337938],
              [-146.770286, -79.926439],
              [-148.062947, -79.652089],
              [-149.531901, -79.358205],
              [-151.588416, -79.299397],
              [-153.390322, -79.162248],
              [-155.329376, -79.064269],
              [-155.975668, -78.69194],
              [-157.268302, -78.378419],
              [-158.051768, -78.025676],
              [-158.365134, -76.889207],
              [-157.875474, -76.987238],
              [-156.974573, -77.300759],
              [-155.329376, -77.202728],
              [-153.742832, -77.065579],
              [-152.920247, -77.496664],
              [-151.33378, -77.398737],
              [-150.00195, -77.183143],
              [-148.748486, -76.908845],
              [-147.612483, -76.575738],
              [-146.104409, -76.47776],
              [-146.143528, -76.105431],
              [-146.496091, -75.733154],
              [-146.20231, -75.380411],
              [-144.909624, -75.204039],
              [-144.322037, -75.537197],
              [-142.794353, -75.34124],
              [-141.638764, -75.086475],
              [-140.209007, -75.06689],
              [-138.85759, -74.968911],
              [-137.5062, -74.733783],
              [-136.428901, -74.518241],
              [-135.214583, -74.302699],
              [-134.431194, -74.361455],
              [-133.745654, -74.439848],
              [-132.257168, -74.302699],
              [-130.925311, -74.479019],
              [-129.554284, -74.459433],
              [-128.242038, -74.322284],
              [-126.890622, -74.420263],
              [-125.402082, -74.518241],
              [-124.011496, -74.479019],
              [-122.562152, -74.498604],
              [-121.073613, -74.518241],
              [-119.70256, -74.479019],
              [-118.684145, -74.185083],
              [-117.469801, -74.028348],
              [-116.216312, -74.243891],
              [-115.021552, -74.067519],
              [-113.944331, -73.714828],
              [-113.297988, -74.028348],
              [-112.945452, -74.38104],
              [-112.299083, -74.714198],
              [-111.261059, -74.420263],
              [-110.066325, -74.79254],
              [-108.714909, -74.910103],
              [-107.559346, -75.184454],
              [-106.149148, -75.125698],
              [-104.876074, -74.949326],
              [-103.367949, -74.988497],
              [-102.016507, -75.125698],
              [-100.645531, -75.302018],
              [-100.1167, -74.870933],
              [-100.763043, -74.537826],
              [-101.252703, -74.185083],
              [-102.545337, -74.106742],
              [-103.113313, -73.734413],
              [-103.328752, -73.362084],
              [-103.681289, -72.61753],
              [-102.917485, -72.754679],
              [-101.60524, -72.813436],
              [-100.312528, -72.754679],
              [-99.13738, -72.911414],
              [-98.118889, -73.20535],
              [-97.688037, -73.558041],
              [-96.336595, -73.616849],
              [-95.043961, -73.4797],
              [-93.672907, -73.283743],
              [-92.439003, -73.166179],
              [-91.420564, -73.401307],
              [-90.088733, -73.322914],
              [-89.226951, -72.558722],
              [-88.423951, -73.009393],
              [-87.268337, -73.185764],
              [-86.014822, -73.087786],
              [-85.192236, -73.4797],
              [-83.879991, -73.518871],
              [-82.665646, -73.636434],
              [-81.470913, -73.851977],
              [-80.687447, -73.4797],
              [-80.295791, -73.126956],
              [-79.296886, -73.518871],
              [-77.925858, -73.420892],
              [-76.907367, -73.636434],
              [-76.221879, -73.969541],
              [-74.890049, -73.871614],
              [-73.852024, -73.65602],
              [-72.833533, -73.401307],
              [-71.619215, -73.264157],
              [-70.209042, -73.146542],
              [-68.935916, -73.009393],
              [-67.956622, -72.79385],
              [-67.369061, -72.480329],
              [-67.134036, -72.049244],
              [-67.251548, -71.637745],
              [-67.56494, -71.245831],
              [-67.917477, -70.853917],
              [-68.230843, -70.462055],
              [-68.485452, -70.109311],
              [-68.544209, -69.717397],
              [-68.446282, -69.325535],
              [-67.976233, -68.953206],
              [-67.5845, -68.541707],
              [-67.427843, -68.149844],
              [-67.62367, -67.718759],
              [-67.741183, -67.326845],
              [-67.251548, -66.876175],
              [-66.703184, -66.58224],
              [-66.056815, -66.209963],
              [-65.371327, -65.89639],
              [-64.568276, -65.602506],
              [-64.176542, -65.171423],
              [-63.628152, -64.897073],
              [-63.001394, -64.642308],
              [-62.041686, -64.583552],
              [-61.414928, -64.270031],
              [-60.709855, -64.074074],
              [-59.887269, -63.95651],
              [-59.162585, -63.701745],
              [-58.594557, -63.388224],
              [-57.811143, -63.27066],
              [-57.223582, -63.525425],
              [-57.59573, -63.858532],
              [-58.614143, -64.152467]
            ]
          ]
        ]
      },
      "id": "ATA"
    },
    {
      "type": "Feature",
      "properties": { "name": "French Southern and Antarctic Lands" },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [68.935, -48.625],
            [69.58, -48.94],
            [70.525, -49.065],
            [70.56, -49.255],
            [70.28, -49.71],
            [68.745, -49.775],
            [68.72, -49.2425],
            [68.8675, -48.83],
            [68.935, -48.625]
          ]
        ]
      },
      "id": "ATF"
    },
    {
      "type": "Feature",
      "properties": { "name": "Australia" },
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
          [
            [
              [145.397978, -40.792549],
              [146.364121, -41.137695],
              [146.908584, -41.000546],
              [147.689259, -40.808258],
              [148.289068, -40.875438],
              [148.359865, -42.062445],
              [148.017301, -42.407024],
              [147.914052, -43.211522],
              [147.564564, -42.937689],
              [146.870343, -43.634597],
              [146.663327, -43.580854],
              [146.048378, -43.549745],
              [145.43193, -42.693776],
              [145.29509, -42.03361],
              [144.718071, -41.162552],
              [144.743755, -40.703975],
              [145.397978, -40.792549]
            ]
          ],
          [
            [
              [143.561811, -13.763656],
              [143.922099, -14.548311],
              [144.563714, -14.171176],
              [144.894908, -14.594458],
              [145.374724, -14.984976],
              [145.271991, -15.428205],
              [145.48526, -16.285672],
              [145.637033, -16.784918],
              [145.888904, -16.906926],
              [146.160309, -17.761655],
              [146.063674, -18.280073],
              [146.387478, -18.958274],
              [147.471082, -19.480723],
              [148.177602, -19.955939],
              [148.848414, -20.39121],
              [148.717465, -20.633469],
              [149.28942, -21.260511],
              [149.678337, -22.342512],
              [150.077382, -22.122784],
              [150.482939, -22.556142],
              [150.727265, -22.402405],
              [150.899554, -23.462237],
              [151.609175, -24.076256],
              [152.07354, -24.457887],
              [152.855197, -25.267501],
              [153.136162, -26.071173],
              [153.161949, -26.641319],
              [153.092909, -27.2603],
              [153.569469, -28.110067],
              [153.512108, -28.995077],
              [153.339095, -29.458202],
              [153.069241, -30.35024],
              [153.089602, -30.923642],
              [152.891578, -31.640446],
              [152.450002, -32.550003],
              [151.709117, -33.041342],
              [151.343972, -33.816023],
              [151.010555, -34.31036],
              [150.714139, -35.17346],
              [150.32822, -35.671879],
              [150.075212, -36.420206],
              [149.946124, -37.109052],
              [149.997284, -37.425261],
              [149.423882, -37.772681],
              [148.304622, -37.809061],
              [147.381733, -38.219217],
              [146.922123, -38.606532],
              [146.317922, -39.035757],
              [145.489652, -38.593768],
              [144.876976, -38.417448],
              [145.032212, -37.896188],
              [144.485682, -38.085324],
              [143.609974, -38.809465],
              [142.745427, -38.538268],
              [142.17833, -38.380034],
              [141.606582, -38.308514],
              [140.638579, -38.019333],
              [139.992158, -37.402936],
              [139.806588, -36.643603],
              [139.574148, -36.138362],
              [139.082808, -35.732754],
              [138.120748, -35.612296],
              [138.449462, -35.127261],
              [138.207564, -34.384723],
              [137.71917, -35.076825],
              [136.829406, -35.260535],
              [137.352371, -34.707339],
              [137.503886, -34.130268],
              [137.890116, -33.640479],
              [137.810328, -32.900007],
              [136.996837, -33.752771],
              [136.372069, -34.094766],
              [135.989043, -34.890118],
              [135.208213, -34.47867],
              [135.239218, -33.947953],
              [134.613417, -33.222778],
              [134.085904, -32.848072],
              [134.273903, -32.617234],
              [132.990777, -32.011224],
              [132.288081, -31.982647],
              [131.326331, -31.495803],
              [129.535794, -31.590423],
              [128.240938, -31.948489],
              [127.102867, -32.282267],
              [126.148714, -32.215966],
              [125.088623, -32.728751],
              [124.221648, -32.959487],
              [124.028947, -33.483847],
              [123.659667, -33.890179],
              [122.811036, -33.914467],
              [122.183064, -34.003402],
              [121.299191, -33.821036],
              [120.580268, -33.930177],
              [119.893695, -33.976065],
              [119.298899, -34.509366],
              [119.007341, -34.464149],
              [118.505718, -34.746819],
              [118.024972, -35.064733],
              [117.295507, -35.025459],
              [116.625109, -35.025097],
              [115.564347, -34.386428],
              [115.026809, -34.196517],
              [115.048616, -33.623425],
              [115.545123, -33.487258],
              [115.714674, -33.259572],
              [115.679379, -32.900369],
              [115.801645, -32.205062],
              [115.689611, -31.612437],
              [115.160909, -30.601594],
              [114.997043, -30.030725],
              [115.040038, -29.461095],
              [114.641974, -28.810231],
              [114.616498, -28.516399],
              [114.173579, -28.118077],
              [114.048884, -27.334765],
              [113.477498, -26.543134],
              [113.338953, -26.116545],
              [113.778358, -26.549025],
              [113.440962, -25.621278],
              [113.936901, -25.911235],
              [114.232852, -26.298446],
              [114.216161, -25.786281],
              [113.721255, -24.998939],
              [113.625344, -24.683971],
              [113.393523, -24.384764],
              [113.502044, -23.80635],
              [113.706993, -23.560215],
              [113.843418, -23.059987],
              [113.736552, -22.475475],
              [114.149756, -21.755881],
              [114.225307, -22.517488],
              [114.647762, -21.82952],
              [115.460167, -21.495173],
              [115.947373, -21.068688],
              [116.711615, -20.701682],
              [117.166316, -20.623599],
              [117.441545, -20.746899],
              [118.229559, -20.374208],
              [118.836085, -20.263311],
              [118.987807, -20.044203],
              [119.252494, -19.952942],
              [119.805225, -19.976506],
              [120.85622, -19.683708],
              [121.399856, -19.239756],
              [121.655138, -18.705318],
              [122.241665, -18.197649],
              [122.286624, -17.798603],
              [122.312772, -17.254967],
              [123.012574, -16.4052],
              [123.433789, -17.268558],
              [123.859345, -17.069035],
              [123.503242, -16.596506],
              [123.817073, -16.111316],
              [124.258287, -16.327944],
              [124.379726, -15.56706],
              [124.926153, -15.0751],
              [125.167275, -14.680396],
              [125.670087, -14.51007],
              [125.685796, -14.230656],
              [126.125149, -14.347341],
              [126.142823, -14.095987],
              [126.582589, -13.952791],
              [127.065867, -13.817968],
              [127.804633, -14.276906],
              [128.35969, -14.86917],
              [128.985543, -14.875991],
              [129.621473, -14.969784],
              [129.4096, -14.42067],
              [129.888641, -13.618703],
              [130.339466, -13.357376],
              [130.183506, -13.10752],
              [130.617795, -12.536392],
              [131.223
Download .txt
gitextract_u9mmz_t0/

├── .dockerignore
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── 1.bug_report.yml
│   │   ├── 2.feature_request.yml
│   │   └── config.yml
│   └── workflows/
│       ├── cd-cloud.yml
│       ├── cd.yml
│       ├── ci.yml
│       └── stale-issues.yml
├── .gitignore
├── .husky/
│   └── pre-commit
├── .stylelintrc.json
├── Dockerfile
├── LICENSE
├── README.md
├── app.json
├── biome.json
├── cypress/
│   ├── docker-compose.yml
│   ├── e2e/
│   │   ├── api-team.cy.ts
│   │   ├── api-user.cy.ts
│   │   ├── api-website.cy.ts
│   │   ├── login.cy.ts
│   │   ├── user.cy.ts
│   │   └── website.cy.ts
│   ├── fixtures/
│   │   ├── teams.json
│   │   ├── users.json
│   │   └── websites.json
│   ├── support/
│   │   ├── e2e.ts
│   │   └── index.d.ts
│   └── tsconfig.json
├── cypress.config.ts
├── db/
│   ├── clickhouse/
│   │   ├── migrations/
│   │   │   ├── 01_edit_keys.sql
│   │   │   ├── 02_add_visit_id.sql
│   │   │   ├── 03_session_data.sql
│   │   │   ├── 04_add_tag.sql
│   │   │   ├── 05_add_utm_clid.sql
│   │   │   ├── 06_update_subdivision.sql
│   │   │   ├── 07_add_distinct_id.sql
│   │   │   └── 08_update_hostname_view.sql
│   │   └── schema.sql
│   └── postgresql/
│       └── data-migrations/
│           ├── convert-utm-clid-columns.sql
│           └── populate-revenue-table.sql
├── docker/
│   └── middleware.ts
├── docker-compose.yml
├── jest.config.ts
├── netlify.toml
├── next-env.d.ts
├── next.config.ts
├── package.components.json
├── package.json
├── pnpm-workspace.yaml
├── podman/
│   ├── README.md
│   ├── env.sample
│   ├── install-systemd-user-service
│   ├── podman-compose.yml
│   └── umami.service
├── postcss.config.js
├── prisma/
│   ├── migrations/
│   │   ├── 01_init/
│   │   │   └── migration.sql
│   │   ├── 02_report_schema_session_data/
│   │   │   └── migration.sql
│   │   ├── 03_metric_performance_index/
│   │   │   └── migration.sql
│   │   ├── 04_team_redesign/
│   │   │   └── migration.sql
│   │   ├── 05_add_visit_id/
│   │   │   └── migration.sql
│   │   ├── 06_session_data/
│   │   │   └── migration.sql
│   │   ├── 07_add_tag/
│   │   │   └── migration.sql
│   │   ├── 08_add_utm_clid/
│   │   │   └── migration.sql
│   │   ├── 09_update_hostname_region/
│   │   │   └── migration.sql
│   │   ├── 10_add_distinct_id/
│   │   │   └── migration.sql
│   │   ├── 11_add_segment/
│   │   │   └── migration.sql
│   │   ├── 12_update_report_parameter/
│   │   │   └── migration.sql
│   │   ├── 13_add_revenue/
│   │   │   └── migration.sql
│   │   ├── 14_add_link_and_pixel/
│   │   │   └── migration.sql
│   │   └── migration_lock.toml
│   └── schema.prisma
├── prisma.config.ts
├── public/
│   ├── browserconfig.xml
│   ├── datamaps.world.json
│   ├── intl/
│   │   ├── country/
│   │   │   ├── am-ET.json
│   │   │   ├── ar-SA.json
│   │   │   ├── be-BY.json
│   │   │   ├── bg-BG.json
│   │   │   ├── bn-BD.json
│   │   │   ├── bs-BA.json
│   │   │   ├── ca-ES.json
│   │   │   ├── cs-CZ.json
│   │   │   ├── da-DK.json
│   │   │   ├── de-CH.json
│   │   │   ├── de-DE.json
│   │   │   ├── el-GR.json
│   │   │   ├── en-GB.json
│   │   │   ├── en-US.json
│   │   │   ├── es-ES.json
│   │   │   ├── es-MX.json
│   │   │   ├── fa-IR.json
│   │   │   ├── fi-FI.json
│   │   │   ├── fo-FO.json
│   │   │   ├── fr-FR.json
│   │   │   ├── he-IL.json
│   │   │   ├── hi-IN.json
│   │   │   ├── hr-HR.json
│   │   │   ├── hu-HU.json
│   │   │   ├── id-ID.json
│   │   │   ├── it-IT.json
│   │   │   ├── ja-JP.json
│   │   │   ├── km-KH.json
│   │   │   ├── ko-KR.json
│   │   │   ├── lt-LT.json
│   │   │   ├── mn-MN.json
│   │   │   ├── ms-MY.json
│   │   │   ├── my-MM.json
│   │   │   ├── nb-NO.json
│   │   │   ├── nl-NL.json
│   │   │   ├── pl-PL.json
│   │   │   ├── pt-BR.json
│   │   │   ├── pt-PT.json
│   │   │   ├── ro-RO.json
│   │   │   ├── ru-RU.json
│   │   │   ├── si-LK.json
│   │   │   ├── sk-SK.json
│   │   │   ├── sl-SI.json
│   │   │   ├── sv-SE.json
│   │   │   ├── ta-IN.json
│   │   │   ├── th-TH.json
│   │   │   ├── tr-TR.json
│   │   │   ├── uk-UA.json
│   │   │   ├── ur-PK.json
│   │   │   ├── uz-UZ.json
│   │   │   ├── vi-VN.json
│   │   │   ├── zh-CN.json
│   │   │   └── zh-TW.json
│   │   ├── language/
│   │   │   ├── am-ET.json
│   │   │   ├── ar-SA.json
│   │   │   ├── be-BY.json
│   │   │   ├── bg-BG.json
│   │   │   ├── bn-BD.json
│   │   │   ├── bs-BA.json
│   │   │   ├── ca-ES.json
│   │   │   ├── cs-CZ.json
│   │   │   ├── da-DK.json
│   │   │   ├── de-CH.json
│   │   │   ├── de-DE.json
│   │   │   ├── el-GR.json
│   │   │   ├── en-GB.json
│   │   │   ├── en-US.json
│   │   │   ├── es-ES.json
│   │   │   ├── es-MX.json
│   │   │   ├── fa-IR.json
│   │   │   ├── fi-FI.json
│   │   │   ├── fo-FO.json
│   │   │   ├── fr-FR.json
│   │   │   ├── he-IL.json
│   │   │   ├── hi-IN.json
│   │   │   ├── hr-HR.json
│   │   │   ├── hu-HU.json
│   │   │   ├── id-ID.json
│   │   │   ├── it-IT.json
│   │   │   ├── ja-JP.json
│   │   │   ├── km-KH.json
│   │   │   ├── ko-KR.json
│   │   │   ├── lt-LT.json
│   │   │   ├── mn-MN.json
│   │   │   ├── ms-MY.json
│   │   │   ├── my-MM.json
│   │   │   ├── nb-NO.json
│   │   │   ├── nl-NL.json
│   │   │   ├── pl-PL.json
│   │   │   ├── pt-BR.json
│   │   │   ├── pt-PT.json
│   │   │   ├── ro-RO.json
│   │   │   ├── ru-RU.json
│   │   │   ├── si-LK.json
│   │   │   ├── sk-SK.json
│   │   │   ├── sl-SI.json
│   │   │   ├── sv-SE.json
│   │   │   ├── ta-IN.json
│   │   │   ├── th-TH.json
│   │   │   ├── tr-TR.json
│   │   │   ├── uk-UA.json
│   │   │   ├── ur-PK.json
│   │   │   ├── uz-UZ.json
│   │   │   ├── vi-VN.json
│   │   │   ├── zh-CN.json
│   │   │   └── zh-TW.json
│   │   └── messages/
│   │       ├── am-ET.json
│   │       ├── ar-SA.json
│   │       ├── be-BY.json
│   │       ├── bg-BG.json
│   │       ├── bn-BD.json
│   │       ├── bs-BA.json
│   │       ├── ca-ES.json
│   │       ├── cs-CZ.json
│   │       ├── da-DK.json
│   │       ├── de-CH.json
│   │       ├── de-DE.json
│   │       ├── el-GR.json
│   │       ├── en-GB.json
│   │       ├── en-US.json
│   │       ├── es-ES.json
│   │       ├── es-MX.json
│   │       ├── fa-IR.json
│   │       ├── fi-FI.json
│   │       ├── fo-FO.json
│   │       ├── fr-FR.json
│   │       ├── ga-ES.json
│   │       ├── he-IL.json
│   │       ├── hi-IN.json
│   │       ├── hr-HR.json
│   │       ├── hu-HU.json
│   │       ├── id-ID.json
│   │       ├── it-IT.json
│   │       ├── ja-JP.json
│   │       ├── km-KH.json
│   │       ├── ko-KR.json
│   │       ├── lt-LT.json
│   │       ├── mn-MN.json
│   │       ├── ms-MY.json
│   │       ├── my-MM.json
│   │       ├── nb-NO.json
│   │       ├── nl-NL.json
│   │       ├── pl-PL.json
│   │       ├── pt-BR.json
│   │       ├── pt-PT.json
│   │       ├── ro-RO.json
│   │       ├── ru-RU.json
│   │       ├── si-LK.json
│   │       ├── sk-SK.json
│   │       ├── sl-SI.json
│   │       ├── sv-SE.json
│   │       ├── ta-IN.json
│   │       ├── th-TH.json
│   │       ├── tr-TR.json
│   │       ├── uk-UA.json
│   │       ├── ur-PK.json
│   │       ├── uz-UZ.json
│   │       ├── vi-VN.json
│   │       ├── zh-CN.json
│   │       └── zh-TW.json
│   ├── iso-3166-2.json
│   ├── robots.txt
│   └── site.webmanifest
├── rollup.tracker.config.js
├── scripts/
│   ├── build-geo.js
│   ├── build-prisma-client.js
│   ├── check-db.js
│   ├── check-env.js
│   ├── download-country-names.js
│   ├── download-language-names.js
│   ├── format-lang.js
│   ├── merge-messages.js
│   ├── postbuild.js
│   ├── seed/
│   │   ├── distributions/
│   │   │   ├── devices.ts
│   │   │   ├── geographic.ts
│   │   │   ├── referrers.ts
│   │   │   └── temporal.ts
│   │   ├── generators/
│   │   │   ├── events.ts
│   │   │   ├── revenue.ts
│   │   │   └── sessions.ts
│   │   ├── index.ts
│   │   ├── sites/
│   │   │   ├── blog.ts
│   │   │   └── saas.ts
│   │   └── utils.ts
│   ├── seed-data.ts
│   ├── start-env.js
│   ├── telemetry.js
│   └── update-tracker.js
├── src/
│   ├── app/
│   │   ├── (collect)/
│   │   │   ├── p/
│   │   │   │   └── [slug]/
│   │   │   │       └── route.ts
│   │   │   └── q/
│   │   │       └── [slug]/
│   │   │           └── route.ts
│   │   ├── (main)/
│   │   │   ├── App.tsx
│   │   │   ├── MobileNav.tsx
│   │   │   ├── SideNav.tsx
│   │   │   ├── TopNav.tsx
│   │   │   ├── UpdateNotice.tsx
│   │   │   ├── admin/
│   │   │   │   ├── AdminLayout.tsx
│   │   │   │   ├── AdminNav.tsx
│   │   │   │   ├── layout.tsx
│   │   │   │   ├── teams/
│   │   │   │   │   ├── AdminTeamsDataTable.tsx
│   │   │   │   │   ├── AdminTeamsPage.tsx
│   │   │   │   │   ├── AdminTeamsTable.tsx
│   │   │   │   │   ├── [teamId]/
│   │   │   │   │   │   ├── AdminTeamPage.tsx
│   │   │   │   │   │   └── page.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   ├── users/
│   │   │   │   │   ├── UserAddButton.tsx
│   │   │   │   │   ├── UserAddForm.tsx
│   │   │   │   │   ├── UserDeleteButton.tsx
│   │   │   │   │   ├── UserDeleteForm.tsx
│   │   │   │   │   ├── UsersDataTable.tsx
│   │   │   │   │   ├── UsersPage.tsx
│   │   │   │   │   ├── UsersTable.tsx
│   │   │   │   │   ├── [userId]/
│   │   │   │   │   │   ├── UserEditForm.tsx
│   │   │   │   │   │   ├── UserHeader.tsx
│   │   │   │   │   │   ├── UserPage.tsx
│   │   │   │   │   │   ├── UserProvider.tsx
│   │   │   │   │   │   ├── UserSettings.tsx
│   │   │   │   │   │   ├── UserWebsites.tsx
│   │   │   │   │   │   └── page.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   └── websites/
│   │   │   │       ├── AdminWebsitesDataTable.tsx
│   │   │   │       ├── AdminWebsitesPage.tsx
│   │   │   │       ├── AdminWebsitesTable.tsx
│   │   │   │       ├── [websiteId]/
│   │   │   │       │   ├── AdminWebsitePage.tsx
│   │   │   │       │   └── page.tsx
│   │   │   │       └── page.tsx
│   │   │   ├── boards/
│   │   │   │   ├── BoardAddButton.tsx
│   │   │   │   ├── BoardAddForm.tsx
│   │   │   │   ├── BoardsPage.tsx
│   │   │   │   ├── [boardId]/
│   │   │   │   │   ├── Board.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   └── page.tsx
│   │   │   ├── console/
│   │   │   │   └── [websiteId]/
│   │   │   │       ├── TestConsolePage.tsx
│   │   │   │       └── page.tsx
│   │   │   ├── dashboard/
│   │   │   │   ├── DashboardPage.tsx
│   │   │   │   └── page.tsx
│   │   │   ├── layout.tsx
│   │   │   ├── links/
│   │   │   │   ├── LinkAddButton.tsx
│   │   │   │   ├── LinkDeleteButton.tsx
│   │   │   │   ├── LinkEditButton.tsx
│   │   │   │   ├── LinkEditForm.tsx
│   │   │   │   ├── LinkProvider.tsx
│   │   │   │   ├── LinksDataTable.tsx
│   │   │   │   ├── LinksPage.tsx
│   │   │   │   ├── LinksTable.tsx
│   │   │   │   ├── [linkId]/
│   │   │   │   │   ├── LinkControls.tsx
│   │   │   │   │   ├── LinkHeader.tsx
│   │   │   │   │   ├── LinkMetricsBar.tsx
│   │   │   │   │   ├── LinkPage.tsx
│   │   │   │   │   ├── LinkPanels.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   └── page.tsx
│   │   │   ├── pixels/
│   │   │   │   ├── PixelAddButton.tsx
│   │   │   │   ├── PixelDeleteButton.tsx
│   │   │   │   ├── PixelEditButton.tsx
│   │   │   │   ├── PixelEditForm.tsx
│   │   │   │   ├── PixelProvider.tsx
│   │   │   │   ├── PixelsDataTable.tsx
│   │   │   │   ├── PixelsPage.tsx
│   │   │   │   ├── PixelsTable.tsx
│   │   │   │   ├── [pixelId]/
│   │   │   │   │   ├── PixelControls.tsx
│   │   │   │   │   ├── PixelHeader.tsx
│   │   │   │   │   ├── PixelMetricsBar.tsx
│   │   │   │   │   ├── PixelPage.tsx
│   │   │   │   │   ├── PixelPanels.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   └── page.tsx
│   │   │   ├── settings/
│   │   │   │   ├── SettingsLayout.tsx
│   │   │   │   ├── SettingsNav.tsx
│   │   │   │   ├── layout.tsx
│   │   │   │   ├── preferences/
│   │   │   │   │   ├── DateRangeSetting.tsx
│   │   │   │   │   ├── LanguageSetting.tsx
│   │   │   │   │   ├── PreferenceSettings.tsx
│   │   │   │   │   ├── PreferencesPage.tsx
│   │   │   │   │   ├── ThemeSetting.tsx
│   │   │   │   │   ├── TimezoneSetting.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   ├── profile/
│   │   │   │   │   ├── PasswordChangeButton.tsx
│   │   │   │   │   ├── PasswordEditForm.tsx
│   │   │   │   │   ├── ProfileHeader.tsx
│   │   │   │   │   ├── ProfilePage.tsx
│   │   │   │   │   ├── ProfileSettings.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   ├── teams/
│   │   │   │   │   ├── TeamsSettingsPage.tsx
│   │   │   │   │   ├── [teamId]/
│   │   │   │   │   │   ├── TeamSettingsPage.tsx
│   │   │   │   │   │   └── page.tsx
│   │   │   │   │   └── page.tsx
│   │   │   │   └── websites/
│   │   │   │       ├── WebsitesSettingsPage.tsx
│   │   │   │       ├── [websiteId]/
│   │   │   │       │   ├── WebsiteSettingsPage.tsx
│   │   │   │       │   └── page.tsx
│   │   │   │       └── page.tsx
│   │   │   ├── teams/
│   │   │   │   ├── TeamAddForm.tsx
│   │   │   │   ├── TeamJoinForm.tsx
│   │   │   │   ├── TeamLeaveButton.tsx
│   │   │   │   ├── TeamLeaveForm.tsx
│   │   │   │   ├── TeamProvider.tsx
│   │   │   │   ├── TeamsAddButton.tsx
│   │   │   │   ├── TeamsDataTable.tsx
│   │   │   │   ├── TeamsHeader.tsx
│   │   │   │   ├── TeamsJoinButton.tsx
│   │   │   │   ├── TeamsPage.tsx
│   │   │   │   ├── TeamsTable.tsx
│   │   │   │   ├── [teamId]/
│   │   │   │   │   ├── TeamDeleteForm.tsx
│   │   │   │   │   ├── TeamEditForm.tsx
│   │   │   │   │   ├── TeamManage.tsx
│   │   │   │   │   ├── TeamMemberEditButton.tsx
│   │   │   │   │   ├── TeamMemberEditForm.tsx
│   │   │   │   │   ├── TeamMemberRemoveButton.tsx
│   │   │   │   │   ├── TeamMembersDataTable.tsx
│   │   │   │   │   ├── TeamMembersTable.tsx
│   │   │   │   │   ├── TeamSettings.tsx
│   │   │   │   │   ├── TeamWebsiteRemoveButton.tsx
│   │   │   │   │   ├── TeamWebsitesDataTable.tsx
│   │   │   │   │   └── TeamWebsitesTable.tsx
│   │   │   │   └── page.tsx
│   │   │   └── websites/
│   │   │       ├── WebsiteAddButton.tsx
│   │   │       ├── WebsiteAddForm.tsx
│   │   │       ├── WebsiteProvider.tsx
│   │   │       ├── WebsitesDataTable.tsx
│   │   │       ├── WebsitesHeader.tsx
│   │   │       ├── WebsitesPage.tsx
│   │   │       ├── WebsitesTable.tsx
│   │   │       ├── [websiteId]/
│   │   │       │   ├── (reports)/
│   │   │       │   │   ├── attribution/
│   │   │       │   │   │   ├── Attribution.tsx
│   │   │       │   │   │   ├── AttributionPage.tsx
│   │   │       │   │   │   └── page.tsx
│   │   │       │   │   ├── breakdown/
│   │   │       │   │   │   ├── Breakdown.tsx
│   │   │       │   │   │   ├── BreakdownPage.tsx
│   │   │       │   │   │   ├── FieldSelectForm.tsx
│   │   │       │   │   │   └── page.tsx
│   │   │       │   │   ├── funnels/
│   │   │       │   │   │   ├── Funnel.tsx
│   │   │       │   │   │   ├── FunnelAddButton.tsx
│   │   │       │   │   │   ├── FunnelEditForm.tsx
│   │   │       │   │   │   ├── FunnelsPage.tsx
│   │   │       │   │   │   └── page.tsx
│   │   │       │   │   ├── goals/
│   │   │       │   │   │   ├── Goal.tsx
│   │   │       │   │   │   ├── GoalAddButton.tsx
│   │   │       │   │   │   ├── GoalEditForm.tsx
│   │   │       │   │   │   ├── GoalsPage.tsx
│   │   │       │   │   │   └── page.tsx
│   │   │       │   │   ├── journeys/
│   │   │       │   │   │   ├── Journey.module.css
│   │   │       │   │   │   ├── Journey.tsx
│   │   │       │   │   │   ├── JourneysPage.tsx
│   │   │       │   │   │   └── page.tsx
│   │   │       │   │   ├── retention/
│   │   │       │   │   │   ├── Retention.tsx
│   │   │       │   │   │   ├── RetentionPage.tsx
│   │   │       │   │   │   └── page.tsx
│   │   │       │   │   ├── revenue/
│   │   │       │   │   │   ├── Revenue.tsx
│   │   │       │   │   │   ├── RevenuePage.tsx
│   │   │       │   │   │   ├── RevenueTable.tsx
│   │   │       │   │   │   └── page.tsx
│   │   │       │   │   └── utm/
│   │   │       │   │       ├── UTM.tsx
│   │   │       │   │       ├── UTMPage.tsx
│   │   │       │   │       └── page.tsx
│   │   │       │   ├── ExpandedViewModal.tsx
│   │   │       │   ├── WebsiteChart.tsx
│   │   │       │   ├── WebsiteControls.tsx
│   │   │       │   ├── WebsiteExpandedMenu.tsx
│   │   │       │   ├── WebsiteExpandedView.tsx
│   │   │       │   ├── WebsiteHeader.tsx
│   │   │       │   ├── WebsiteLayout.tsx
│   │   │       │   ├── WebsiteMenu.tsx
│   │   │       │   ├── WebsiteMetricsBar.tsx
│   │   │       │   ├── WebsiteNav.tsx
│   │   │       │   ├── WebsitePage.tsx
│   │   │       │   ├── WebsitePanels.tsx
│   │   │       │   ├── WebsiteTabs.tsx
│   │   │       │   ├── cohorts/
│   │   │       │   │   ├── CohortAddButton.tsx
│   │   │       │   │   ├── CohortDeleteButton.tsx
│   │   │       │   │   ├── CohortEditButton.tsx
│   │   │       │   │   ├── CohortEditForm.tsx
│   │   │       │   │   ├── CohortsDataTable.tsx
│   │   │       │   │   ├── CohortsPage.tsx
│   │   │       │   │   ├── CohortsTable.tsx
│   │   │       │   │   └── page.tsx
│   │   │       │   ├── compare/
│   │   │       │   │   ├── ComparePage.tsx
│   │   │       │   │   ├── CompareTables.tsx
│   │   │       │   │   └── page.tsx
│   │   │       │   ├── events/
│   │   │       │   │   ├── EventProperties.tsx
│   │   │       │   │   ├── EventsDataTable.tsx
│   │   │       │   │   ├── EventsMetricsBar.tsx
│   │   │       │   │   ├── EventsPage.tsx
│   │   │       │   │   ├── EventsTable.tsx
│   │   │       │   │   └── page.tsx
│   │   │       │   ├── layout.tsx
│   │   │       │   ├── page.tsx
│   │   │       │   ├── realtime/
│   │   │       │   │   ├── RealtimeCountries.tsx
│   │   │       │   │   ├── RealtimeHeader.tsx
│   │   │       │   │   ├── RealtimeLog.tsx
│   │   │       │   │   ├── RealtimePage.tsx
│   │   │       │   │   ├── RealtimePaths.tsx
│   │   │       │   │   ├── RealtimeReferrers.tsx
│   │   │       │   │   └── page.tsx
│   │   │       │   ├── segments/
│   │   │       │   │   ├── SegmentAddButton.tsx
│   │   │       │   │   ├── SegmentDeleteButton.tsx
│   │   │       │   │   ├── SegmentEditButton.tsx
│   │   │       │   │   ├── SegmentEditForm.tsx
│   │   │       │   │   ├── SegmentsDataTable.tsx
│   │   │       │   │   ├── SegmentsPage.tsx
│   │   │       │   │   ├── SegmentsTable.tsx
│   │   │       │   │   └── page.tsx
│   │   │       │   ├── sessions/
│   │   │       │   │   ├── SessionActivity.tsx
│   │   │       │   │   ├── SessionData.tsx
│   │   │       │   │   ├── SessionInfo.tsx
│   │   │       │   │   ├── SessionModal.tsx
│   │   │       │   │   ├── SessionProfile.tsx
│   │   │       │   │   ├── SessionProperties.tsx
│   │   │       │   │   ├── SessionStats.tsx
│   │   │       │   │   ├── SessionsDataTable.tsx
│   │   │       │   │   ├── SessionsMetricsBar.tsx
│   │   │       │   │   ├── SessionsPage.tsx
│   │   │       │   │   ├── SessionsTable.tsx
│   │   │       │   │   └── page.tsx
│   │   │       │   └── settings/
│   │   │       │       ├── SettingsPage.tsx
│   │   │       │       ├── WebsiteData.tsx
│   │   │       │       ├── WebsiteDeleteForm.tsx
│   │   │       │       ├── WebsiteEditForm.tsx
│   │   │       │       ├── WebsiteResetForm.tsx
│   │   │       │       ├── WebsiteSettings.tsx
│   │   │       │       ├── WebsiteSettingsHeader.tsx
│   │   │       │       ├── WebsiteShareForm.tsx
│   │   │       │       ├── WebsiteTrackingCode.tsx
│   │   │       │       ├── WebsiteTransferForm.tsx
│   │   │       │       └── page.tsx
│   │   │       └── page.tsx
│   │   ├── Providers.tsx
│   │   ├── api/
│   │   │   ├── admin/
│   │   │   │   ├── teams/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── users/
│   │   │   │   │   └── route.ts
│   │   │   │   └── websites/
│   │   │   │       └── route.ts
│   │   │   ├── auth/
│   │   │   │   ├── login/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── logout/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── sso/
│   │   │   │   │   └── route.ts
│   │   │   │   └── verify/
│   │   │   │       └── route.ts
│   │   │   ├── batch/
│   │   │   │   └── route.ts
│   │   │   ├── config/
│   │   │   │   └── route.ts
│   │   │   ├── heartbeat/
│   │   │   │   └── route.ts
│   │   │   ├── links/
│   │   │   │   ├── [linkId]/
│   │   │   │   │   └── route.ts
│   │   │   │   └── route.ts
│   │   │   ├── me/
│   │   │   │   ├── password/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── route.ts
│   │   │   │   ├── teams/
│   │   │   │   │   └── route.ts
│   │   │   │   └── websites/
│   │   │   │       └── route.ts
│   │   │   ├── pixels/
│   │   │   │   ├── [pixelId]/
│   │   │   │   │   └── route.ts
│   │   │   │   └── route.ts
│   │   │   ├── realtime/
│   │   │   │   └── [websiteId]/
│   │   │   │       └── route.ts
│   │   │   ├── reports/
│   │   │   │   ├── [reportId]/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── attribution/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── breakdown/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── funnel/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── goal/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── journey/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── retention/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── revenue/
│   │   │   │   │   └── route.ts
│   │   │   │   ├── route.ts
│   │   │   │   └── utm/
│   │   │   │       └── route.ts
│   │   │   ├── scripts/
│   │   │   │   └── telemetry/
│   │   │   │       └── route.ts
│   │   │   ├── send/
│   │   │   │   └── route.ts
│   │   │   ├── share/
│   │   │   │   └── [shareId]/
│   │   │   │       └── route.ts
│   │   │   ├── teams/
│   │   │   │   ├── [teamId]/
│   │   │   │   │   ├── links/
│   │   │   │   │   │   └── route.ts
│   │   │   │   │   ├── pixels/
│   │   │   │   │   │   └── route.ts
│   │   │   │   │   ├── route.ts
│   │   │   │   │   ├── users/
│   │   │   │   │   │   ├── [userId]/
│   │   │   │   │   │   │   └── route.ts
│   │   │   │   │   │   └── route.ts
│   │   │   │   │   └── websites/
│   │   │   │   │       └── route.ts
│   │   │   │   ├── join/
│   │   │   │   │   └── route.ts
│   │   │   │   └── route.ts
│   │   │   ├── users/
│   │   │   │   ├── [userId]/
│   │   │   │   │   ├── route.ts
│   │   │   │   │   ├── teams/
│   │   │   │   │   │   └── route.ts
│   │   │   │   │   └── websites/
│   │   │   │   │       └── route.ts
│   │   │   │   └── route.ts
│   │   │   └── websites/
│   │   │       ├── [websiteId]/
│   │   │       │   ├── active/
│   │   │       │   │   └── route.ts
│   │   │       │   ├── daterange/
│   │   │       │   │   └── route.ts
│   │   │       │   ├── event-data/
│   │   │       │   │   ├── [eventId]/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   ├── events/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   ├── fields/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   ├── properties/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   ├── stats/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   └── values/
│   │   │       │   │       └── route.ts
│   │   │       │   ├── events/
│   │   │       │   │   ├── route.ts
│   │   │       │   │   └── series/
│   │   │       │   │       └── route.ts
│   │   │       │   ├── export/
│   │   │       │   │   └── route.ts
│   │   │       │   ├── metrics/
│   │   │       │   │   ├── expanded/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   └── route.ts
│   │   │       │   ├── pageviews/
│   │   │       │   │   └── route.ts
│   │   │       │   ├── reports/
│   │   │       │   │   └── route.ts
│   │   │       │   ├── reset/
│   │   │       │   │   └── route.ts
│   │   │       │   ├── route.ts
│   │   │       │   ├── segments/
│   │   │       │   │   ├── [segmentId]/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   └── route.ts
│   │   │       │   ├── session-data/
│   │   │       │   │   ├── properties/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   └── values/
│   │   │       │   │       └── route.ts
│   │   │       │   ├── sessions/
│   │   │       │   │   ├── [sessionId]/
│   │   │       │   │   │   ├── activity/
│   │   │       │   │   │   │   └── route.ts
│   │   │       │   │   │   ├── properties/
│   │   │       │   │   │   │   └── route.ts
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   ├── route.ts
│   │   │       │   │   ├── stats/
│   │   │       │   │   │   └── route.ts
│   │   │       │   │   └── weekly/
│   │   │       │   │       └── route.ts
│   │   │       │   ├── stats/
│   │   │       │   │   └── route.ts
│   │   │       │   ├── transfer/
│   │   │       │   │   └── route.ts
│   │   │       │   └── values/
│   │   │       │       └── route.ts
│   │   │       └── route.ts
│   │   ├── layout.tsx
│   │   ├── login/
│   │   │   ├── LoginForm.tsx
│   │   │   ├── LoginPage.tsx
│   │   │   └── page.tsx
│   │   ├── logout/
│   │   │   ├── LogoutPage.tsx
│   │   │   └── page.tsx
│   │   ├── not-found.tsx
│   │   ├── page.tsx
│   │   ├── share/
│   │   │   └── [...shareId]/
│   │   │       ├── Footer.tsx
│   │   │       ├── Header.tsx
│   │   │       ├── SharePage.tsx
│   │   │       └── page.tsx
│   │   └── sso/
│   │       ├── SSOPage.tsx
│   │       └── page.tsx
│   ├── components/
│   │   ├── boards/
│   │   │   └── Board.tsx
│   │   ├── charts/
│   │   │   ├── BarChart.tsx
│   │   │   ├── BubbleChart.tsx
│   │   │   ├── Chart.tsx
│   │   │   ├── ChartTooltip.tsx
│   │   │   └── PieChart.tsx
│   │   ├── common/
│   │   │   ├── ActionForm.tsx
│   │   │   ├── AnimatedDiv.tsx
│   │   │   ├── Avatar.tsx
│   │   │   ├── ConfirmationForm.tsx
│   │   │   ├── DataGrid.tsx
│   │   │   ├── DateDisplay.tsx
│   │   │   ├── DateDistance.tsx
│   │   │   ├── Empty.tsx
│   │   │   ├── EmptyPlaceholder.tsx
│   │   │   ├── ErrorBoundary.tsx
│   │   │   ├── ErrorMessage.tsx
│   │   │   ├── ExternalLink.tsx
│   │   │   ├── Favicon.tsx
│   │   │   ├── FilterLink.tsx
│   │   │   ├── FilterRecord.tsx
│   │   │   ├── GridRow.tsx
│   │   │   ├── LinkButton.tsx
│   │   │   ├── LoadingPanel.tsx
│   │   │   ├── PageBody.tsx
│   │   │   ├── PageHeader.tsx
│   │   │   ├── Pager.tsx
│   │   │   ├── Panel.tsx
│   │   │   ├── SectionHeader.tsx
│   │   │   ├── SideMenu.tsx
│   │   │   ├── TypeConfirmationForm.tsx
│   │   │   └── TypeIcon.tsx
│   │   ├── hooks/
│   │   │   ├── context/
│   │   │   │   ├── useLink.ts
│   │   │   │   ├── usePixel.ts
│   │   │   │   ├── useTeam.ts
│   │   │   │   ├── useUser.ts
│   │   │   │   └── useWebsite.ts
│   │   │   ├── index.ts
│   │   │   ├── queries/
│   │   │   │   ├── useActiveUsersQuery.ts
│   │   │   │   ├── useDateRangeQuery.ts
│   │   │   │   ├── useDeleteQuery.ts
│   │   │   │   ├── useEventDataEventsQuery.ts
│   │   │   │   ├── useEventDataPropertiesQuery.ts
│   │   │   │   ├── useEventDataQuery.ts
│   │   │   │   ├── useEventDataValuesQuery.ts
│   │   │   │   ├── useLinkQuery.ts
│   │   │   │   ├── useLinksQuery.ts
│   │   │   │   ├── useLoginQuery.ts
│   │   │   │   ├── usePixelQuery.ts
│   │   │   │   ├── usePixelsQuery.ts
│   │   │   │   ├── useRealtimeQuery.ts
│   │   │   │   ├── useReportQuery.ts
│   │   │   │   ├── useReportsQuery.ts
│   │   │   │   ├── useResultQuery.ts
│   │   │   │   ├── useSessionActivityQuery.ts
│   │   │   │   ├── useSessionDataPropertiesQuery.ts
│   │   │   │   ├── useSessionDataQuery.ts
│   │   │   │   ├── useSessionDataValuesQuery.ts
│   │   │   │   ├── useShareTokenQuery.ts
│   │   │   │   ├── useTeamMembersQuery.ts
│   │   │   │   ├── useTeamQuery.ts
│   │   │   │   ├── useTeamWebsitesQuery.ts
│   │   │   │   ├── useTeamsQuery.ts
│   │   │   │   ├── useUpdateQuery.ts
│   │   │   │   ├── useUserQuery.ts
│   │   │   │   ├── useUserTeamsQuery.ts
│   │   │   │   ├── useUserWebsitesQuery.ts
│   │   │   │   ├── useUsersQuery.ts
│   │   │   │   ├── useWebsiteCohortQuery.ts
│   │   │   │   ├── useWebsiteCohortsQuery.ts
│   │   │   │   ├── useWebsiteEventsQuery.ts
│   │   │   │   ├── useWebsiteEventsSeriesQuery.ts
│   │   │   │   ├── useWebsiteExpandedMetricsQuery.ts
│   │   │   │   ├── useWebsiteMetricsQuery.ts
│   │   │   │   ├── useWebsitePageviewsQuery.ts
│   │   │   │   ├── useWebsiteQuery.ts
│   │   │   │   ├── useWebsiteSegmentQuery.ts
│   │   │   │   ├── useWebsiteSegmentsQuery.ts
│   │   │   │   ├── useWebsiteSessionQuery.ts
│   │   │   │   ├── useWebsiteSessionStatsQuery.ts
│   │   │   │   ├── useWebsiteSessionsQuery.ts
│   │   │   │   ├── useWebsiteStatsQuery.ts
│   │   │   │   ├── useWebsiteValuesQuery.ts
│   │   │   │   ├── useWebsitesQuery.ts
│   │   │   │   └── useWeeklyTrafficQuery.ts
│   │   │   ├── useApi.ts
│   │   │   ├── useConfig.ts
│   │   │   ├── useCountryNames.ts
│   │   │   ├── useDateParameters.ts
│   │   │   ├── useDateRange.ts
│   │   │   ├── useDocumentClick.ts
│   │   │   ├── useEscapeKey.ts
│   │   │   ├── useFields.ts
│   │   │   ├── useFilterParameters.ts
│   │   │   ├── useFilters.ts
│   │   │   ├── useForceUpdate.ts
│   │   │   ├── useFormat.ts
│   │   │   ├── useGlobalState.ts
│   │   │   ├── useLanguageNames.ts
│   │   │   ├── useLocale.ts
│   │   │   ├── useMessages.ts
│   │   │   ├── useMobile.ts
│   │   │   ├── useModified.ts
│   │   │   ├── useNavigation.ts
│   │   │   ├── usePageParameters.ts
│   │   │   ├── usePagedQuery.ts
│   │   │   ├── useRegionNames.ts
│   │   │   ├── useSlug.ts
│   │   │   ├── useSticky.ts
│   │   │   └── useTimezone.ts
│   │   ├── icons.ts
│   │   ├── input/
│   │   │   ├── ActionSelect.tsx
│   │   │   ├── CurrencySelect.tsx
│   │   │   ├── DateFilter.tsx
│   │   │   ├── DialogButton.tsx
│   │   │   ├── DownloadButton.tsx
│   │   │   ├── ExportButton.tsx
│   │   │   ├── FieldFilters.tsx
│   │   │   ├── FilterBar.tsx
│   │   │   ├── FilterButtons.tsx
│   │   │   ├── FilterEditForm.tsx
│   │   │   ├── LanguageButton.tsx
│   │   │   ├── LookupField.tsx
│   │   │   ├── MenuButton.tsx
│   │   │   ├── MobileMenuButton.tsx
│   │   │   ├── MonthFilter.tsx
│   │   │   ├── MonthSelect.tsx
│   │   │   ├── NavButton.tsx
│   │   │   ├── PanelButton.tsx
│   │   │   ├── PreferencesButton.tsx
│   │   │   ├── ProfileButton.tsx
│   │   │   ├── RefreshButton.tsx
│   │   │   ├── ReportEditButton.tsx
│   │   │   ├── SegmentFilters.tsx
│   │   │   ├── SegmentSaveButton.tsx
│   │   │   ├── SettingsButton.tsx
│   │   │   ├── WebsiteDateFilter.tsx
│   │   │   ├── WebsiteFilterButton.tsx
│   │   │   └── WebsiteSelect.tsx
│   │   ├── messages.ts
│   │   ├── metrics/
│   │   │   ├── ActiveUsers.tsx
│   │   │   ├── ChangeLabel.tsx
│   │   │   ├── DatePickerForm.tsx
│   │   │   ├── EventData.tsx
│   │   │   ├── EventsChart.tsx
│   │   │   ├── Legend.tsx
│   │   │   ├── ListTable.tsx
│   │   │   ├── MetricCard.tsx
│   │   │   ├── MetricLabel.tsx
│   │   │   ├── MetricsBar.tsx
│   │   │   ├── MetricsExpandedTable.tsx
│   │   │   ├── MetricsTable.tsx
│   │   │   ├── PageviewsChart.tsx
│   │   │   ├── RealtimeChart.tsx
│   │   │   ├── WeeklyTraffic.tsx
│   │   │   └── WorldMap.tsx
│   │   └── svg/
│   │       ├── AddUser.tsx
│   │       ├── BarChart.tsx
│   │       ├── Bars.tsx
│   │       ├── Bolt.tsx
│   │       ├── Bookmark.tsx
│   │       ├── Calendar.tsx
│   │       ├── Change.tsx
│   │       ├── Clock.tsx
│   │       ├── Compare.tsx
│   │       ├── Dashboard.tsx
│   │       ├── Download.tsx
│   │       ├── Expand.tsx
│   │       ├── Export.tsx
│   │       ├── Flag.tsx
│   │       ├── Funnel.tsx
│   │       ├── Gear.tsx
│   │       ├── Globe.tsx
│   │       ├── Lightbulb.tsx
│   │       ├── Lightning.tsx
│   │       ├── Link.tsx
│   │       ├── Location.tsx
│   │       ├── Lock.tsx
│   │       ├── Logo.tsx
│   │       ├── LogoWhite.tsx
│   │       ├── Magnet.tsx
│   │       ├── Money.tsx
│   │       ├── Moon.tsx
│   │       ├── Network.tsx
│   │       ├── Nodes.tsx
│   │       ├── Overview.tsx
│   │       ├── Path.tsx
│   │       ├── Profile.tsx
│   │       ├── Pushpin.tsx
│   │       ├── Redo.tsx
│   │       ├── Reports.tsx
│   │       ├── Security.tsx
│   │       ├── Speaker.tsx
│   │       ├── Sun.tsx
│   │       ├── Switch.tsx
│   │       ├── Tag.tsx
│   │       ├── Target.tsx
│   │       ├── Visitor.tsx
│   │       ├── Website.tsx
│   │       └── index.ts
│   ├── declaration.d.ts
│   ├── index.ts
│   ├── lang/
│   │   ├── ar-SA.json
│   │   ├── be-BY.json
│   │   ├── bg-BG.json
│   │   ├── bn-BD.json
│   │   ├── bs-BA.json
│   │   ├── ca-ES.json
│   │   ├── cs-CZ.json
│   │   ├── da-DK.json
│   │   ├── de-CH.json
│   │   ├── de-DE.json
│   │   ├── el-GR.json
│   │   ├── en-GB.json
│   │   ├── en-US.json
│   │   ├── es-ES.json
│   │   ├── fa-IR.json
│   │   ├── fi-FI.json
│   │   ├── fo-FO.json
│   │   ├── fr-FR.json
│   │   ├── ga-ES.json
│   │   ├── he-IL.json
│   │   ├── hi-IN.json
│   │   ├── hr-HR.json
│   │   ├── hu-HU.json
│   │   ├── id-ID.json
│   │   ├── it-IT.json
│   │   ├── ja-JP.json
│   │   ├── km-KH.json
│   │   ├── ko-KR.json
│   │   ├── lt-LT.json
│   │   ├── mn-MN.json
│   │   ├── ms-MY.json
│   │   ├── my-MM.json
│   │   ├── nb-NO.json
│   │   ├── nl-NL.json
│   │   ├── pl-PL.json
│   │   ├── pt-BR.json
│   │   ├── pt-PT.json
│   │   ├── ro-RO.json
│   │   ├── ru-RU.json
│   │   ├── si-LK.json
│   │   ├── sk-SK.json
│   │   ├── sl-SI.json
│   │   ├── sv-SE.json
│   │   ├── ta-IN.json
│   │   ├── th-TH.json
│   │   ├── tr-TR.json
│   │   ├── uk-UA.json
│   │   ├── ur-PK.json
│   │   ├── uz-UZ.json
│   │   ├── vi-VN.json
│   │   ├── zh-CN.json
│   │   └── zh-TW.json
│   ├── lib/
│   │   ├── __tests__/
│   │   │   ├── charts.test.ts
│   │   │   ├── detect.test.ts
│   │   │   └── format.test.ts
│   │   ├── auth.ts
│   │   ├── charts.ts
│   │   ├── clickhouse.ts
│   │   ├── client.ts
│   │   ├── colors.ts
│   │   ├── constants.ts
│   │   ├── crypto.ts
│   │   ├── data.ts
│   │   ├── date.ts
│   │   ├── db.ts
│   │   ├── detect.ts
│   │   ├── fetch.ts
│   │   ├── filters.ts
│   │   ├── format.ts
│   │   ├── generate.ts
│   │   ├── ip.ts
│   │   ├── jwt.ts
│   │   ├── kafka.ts
│   │   ├── lang.ts
│   │   ├── load.ts
│   │   ├── params.ts
│   │   ├── password.ts
│   │   ├── prisma.ts
│   │   ├── react.ts
│   │   ├── redis.ts
│   │   ├── request.ts
│   │   ├── response.ts
│   │   ├── schema.ts
│   │   ├── sql.ts
│   │   ├── storage.ts
│   │   ├── types.ts
│   │   ├── url.ts
│   │   └── utils.ts
│   ├── permissions/
│   │   ├── index.ts
│   │   ├── link.ts
│   │   ├── pixel.ts
│   │   ├── report.ts
│   │   ├── team.ts
│   │   ├── user.ts
│   │   └── website.ts
│   ├── queries/
│   │   ├── prisma/
│   │   │   ├── index.ts
│   │   │   ├── link.ts
│   │   │   ├── pixel.ts
│   │   │   ├── report.ts
│   │   │   ├── segment.ts
│   │   │   ├── team.ts
│   │   │   ├── teamUser.ts
│   │   │   ├── user.ts
│   │   │   └── website.ts
│   │   └── sql/
│   │       ├── events/
│   │       │   ├── getEventData.ts
│   │       │   ├── getEventDataEvents.ts
│   │       │   ├── getEventDataFields.ts
│   │       │   ├── getEventDataProperties.ts
│   │       │   ├── getEventDataStats.ts
│   │       │   ├── getEventDataUsage.ts
│   │       │   ├── getEventDataValues.ts
│   │       │   ├── getEventExpandedMetrics.ts
│   │       │   ├── getEventMetrics.ts
│   │       │   ├── getEventStats.ts
│   │       │   ├── getEventUsage.ts
│   │       │   ├── getWebsiteEvents.ts
│   │       │   ├── saveEvent.ts
│   │       │   ├── saveEventData.ts
│   │       │   └── saveRevenue.ts
│   │       ├── getActiveVisitors.ts
│   │       ├── getChannelExpandedMetrics.ts
│   │       ├── getChannelMetrics.ts
│   │       ├── getRealtimeActivity.ts
│   │       ├── getRealtimeData.ts
│   │       ├── getValues.ts
│   │       ├── getWebsiteDateRange.ts
│   │       ├── getWebsiteStats.ts
│   │       ├── getWeeklyTraffic.ts
│   │       ├── index.ts
│   │       ├── pageviews/
│   │       │   ├── getPageviewExpandedMetrics.ts
│   │       │   ├── getPageviewMetrics.ts
│   │       │   └── getPageviewStats.ts
│   │       ├── reports/
│   │       │   ├── getAttribution.ts
│   │       │   ├── getBreakdown.ts
│   │       │   ├── getFunnel.ts
│   │       │   ├── getGoal.ts
│   │       │   ├── getJourney.ts
│   │       │   ├── getRetention.ts
│   │       │   ├── getRevenue.ts
│   │       │   └── getUTM.ts
│   │       └── sessions/
│   │           ├── createSession.ts
│   │           ├── getSessionActivity.ts
│   │           ├── getSessionData.ts
│   │           ├── getSessionDataProperties.ts
│   │           ├── getSessionDataValues.ts
│   │           ├── getSessionExpandedMetrics.ts
│   │           ├── getSessionMetrics.ts
│   │           ├── getSessionStats.ts
│   │           ├── getWebsiteSession.ts
│   │           ├── getWebsiteSessionStats.ts
│   │           ├── getWebsiteSessions.ts
│   │           └── saveSessionData.ts
│   ├── store/
│   │   ├── app.ts
│   │   ├── cache.ts
│   │   ├── dashboard.ts
│   │   ├── version.ts
│   │   └── websites.ts
│   ├── styles/
│   │   ├── global.css
│   │   └── variables.css
│   └── tracker/
│       ├── index.d.ts
│       └── index.js
├── tsconfig.json
├── tsconfig.prisma.json
└── tsup.config.js
Download .txt
SYMBOL INDEX (1364 symbols across 563 files)

FILE: cypress/support/index.d.ts
  type Chainable (line 5) | interface Chainable {

FILE: db/clickhouse/migrations/02_add_visit_id.sql
  type umami (line 1) | CREATE TABLE umami.website_event_join
  type umami (line 21) | CREATE TABLE umami.website_event_new

FILE: db/clickhouse/migrations/03_session_data.sql
  type umami (line 1) | CREATE TABLE umami.event_data_new
  type umami (line 35) | CREATE TABLE umami.session_data

FILE: db/clickhouse/migrations/05_add_utm_clid.sql
  type umami (line 2) | CREATE TABLE umami.website_event_new
  type umami (line 52) | CREATE TABLE umami.website_event_stats_hourly_new

FILE: db/clickhouse/migrations/08_update_hostname_view.sql
  type umami (line 2) | CREATE TABLE umami.website_event_stats_hourly_new

FILE: db/clickhouse/schema.sql
  type umami (line 2) | CREATE TABLE umami.website_event
  type umami (line 51) | CREATE TABLE umami.event_data
  type umami (line 70) | CREATE TABLE umami.session_data
  type umami (line 88) | CREATE TABLE umami.website_event_stats_hourly
  type umami (line 251) | CREATE TABLE umami.website_revenue

FILE: docker/middleware.ts
  constant TRACKER_PATH (line 7) | const TRACKER_PATH = '/script.js';
  constant COLLECT_PATH (line 8) | const COLLECT_PATH = '/api/send';
  constant LOGIN_PATH (line 9) | const LOGIN_PATH = '/login';
  function customCollectEndpoint (line 24) | function customCollectEndpoint(request: NextRequest) {
  function customScriptName (line 37) | function customScriptName(request: NextRequest) {
  function customScriptUrl (line 51) | function customScriptUrl(request: NextRequest) {
  function disableLogin (line 59) | function disableLogin(request: NextRequest) {
  function middleware (line 67) | function middleware(req: NextRequest) {

FILE: next.config.ts
  constant TRACKER_SCRIPT (line 4) | const TRACKER_SCRIPT = '/script.js';
  method headers (line 183) | async headers() {
  method rewrites (line 186) | async rewrites() {
  method redirects (line 199) | async redirects() {

FILE: prisma/migrations/01_init/migration.sql
  type "user" (line 5) | CREATE TABLE "user" (
  type "session" (line 18) | CREATE TABLE "session" (
  type "website" (line 37) | CREATE TABLE "website" (
  type "website_event" (line 52) | CREATE TABLE "website_event" (
  type "event_data" (line 70) | CREATE TABLE "event_data" (
  type "team" (line 85) | CREATE TABLE "team" (
  type "team_user" (line 96) | CREATE TABLE "team_user" (
  type "team_website" (line 108) | CREATE TABLE "team_website" (
  type "user" (line 118) | CREATE UNIQUE INDEX "user_user_id_key" ON "user"("user_id")
  type "user" (line 121) | CREATE UNIQUE INDEX "user_username_key" ON "user"("username")
  type "session" (line 124) | CREATE UNIQUE INDEX "session_session_id_key" ON "session"("session_id")
  type "session" (line 127) | CREATE INDEX "session_created_at_idx" ON "session"("created_at")
  type "session" (line 130) | CREATE INDEX "session_website_id_idx" ON "session"("website_id")
  type "website" (line 133) | CREATE UNIQUE INDEX "website_website_id_key" ON "website"("website_id")
  type "website" (line 136) | CREATE UNIQUE INDEX "website_share_id_key" ON "website"("share_id")
  type "website" (line 139) | CREATE INDEX "website_user_id_idx" ON "website"("user_id")
  type "website" (line 142) | CREATE INDEX "website_created_at_idx" ON "website"("created_at")
  type "website" (line 145) | CREATE INDEX "website_share_id_idx" ON "website"("share_id")
  type "website_event" (line 148) | CREATE INDEX "website_event_created_at_idx" ON "website_event"("created_...
  type "website_event" (line 151) | CREATE INDEX "website_event_session_id_idx" ON "website_event"("session_...
  type "website_event" (line 154) | CREATE INDEX "website_event_website_id_idx" ON "website_event"("website_...
  type "website_event" (line 157) | CREATE INDEX "website_event_website_id_created_at_idx" ON "website_event...
  type "website_event" (line 160) | CREATE INDEX "website_event_website_id_session_id_created_at_idx" ON "we...
  type "event_data" (line 163) | CREATE INDEX "event_data_created_at_idx" ON "event_data"("created_at")
  type "event_data" (line 166) | CREATE INDEX "event_data_website_id_idx" ON "event_data"("website_id")
  type "event_data" (line 169) | CREATE INDEX "event_data_website_event_id_idx" ON "event_data"("website_...
  type "team" (line 172) | CREATE UNIQUE INDEX "team_team_id_key" ON "team"("team_id")
  type "team" (line 175) | CREATE UNIQUE INDEX "team_access_code_key" ON "team"("access_code")
  type "team" (line 178) | CREATE INDEX "team_access_code_idx" ON "team"("access_code")
  type "team_user" (line 181) | CREATE UNIQUE INDEX "team_user_team_user_id_key" ON "team_user"("team_us...
  type "team_user" (line 184) | CREATE INDEX "team_user_team_id_idx" ON "team_user"("team_id")
  type "team_user" (line 187) | CREATE INDEX "team_user_user_id_idx" ON "team_user"("user_id")
  type "team_website" (line 190) | CREATE UNIQUE INDEX "team_website_team_website_id_key" ON "team_website"...
  type "team_website" (line 193) | CREATE INDEX "team_website_team_id_idx" ON "team_website"("team_id")
  type "team_website" (line 196) | CREATE INDEX "team_website_website_id_idx" ON "team_website"("website_id")

FILE: prisma/migrations/02_report_schema_session_data/migration.sql
  type "session_data" (line 9) | CREATE TABLE "session_data" (
  type "report" (line 25) | CREATE TABLE "report" (
  type "session_data" (line 40) | CREATE INDEX "session_data_created_at_idx" ON "session_data"("created_at")
  type "session_data" (line 43) | CREATE INDEX "session_data_website_id_idx" ON "session_data"("website_id")
  type "session_data" (line 46) | CREATE INDEX "session_data_session_id_idx" ON "session_data"("session_id")
  type "report" (line 49) | CREATE UNIQUE INDEX "report_report_id_key" ON "report"("report_id")
  type "report" (line 52) | CREATE INDEX "report_user_id_idx" ON "report"("user_id")
  type "report" (line 55) | CREATE INDEX "report_website_id_idx" ON "report"("website_id")
  type "report" (line 58) | CREATE INDEX "report_type_idx" ON "report"("type")
  type "report" (line 61) | CREATE INDEX "report_name_idx" ON "report"("name")

FILE: prisma/migrations/03_metric_performance_index/migration.sql
  type "event_data" (line 2) | CREATE INDEX "event_data_website_id_created_at_idx" ON "event_data"("web...
  type "event_data" (line 5) | CREATE INDEX "event_data_website_id_created_at_event_key_idx" ON "event_...
  type "session" (line 8) | CREATE INDEX "session_website_id_created_at_idx" ON "session"("website_i...
  type "session" (line 11) | CREATE INDEX "session_website_id_created_at_hostname_idx" ON "session"("...
  type "session" (line 14) | CREATE INDEX "session_website_id_created_at_browser_idx" ON "session"("w...
  type "session" (line 17) | CREATE INDEX "session_website_id_created_at_os_idx" ON "session"("websit...
  type "session" (line 20) | CREATE INDEX "session_website_id_created_at_device_idx" ON "session"("we...
  type "session" (line 23) | CREATE INDEX "session_website_id_created_at_screen_idx" ON "session"("we...
  type "session" (line 26) | CREATE INDEX "session_website_id_created_at_language_idx" ON "session"("...
  type "session" (line 29) | CREATE INDEX "session_website_id_created_at_country_idx" ON "session"("w...
  type "session" (line 32) | CREATE INDEX "session_website_id_created_at_subdivision1_idx" ON "sessio...
  type "session" (line 35) | CREATE INDEX "session_website_id_created_at_city_idx" ON "session"("webs...
  type "website_event" (line 38) | CREATE INDEX "website_event_website_id_created_at_url_path_idx" ON "webs...
  type "website_event" (line 41) | CREATE INDEX "website_event_website_id_created_at_url_query_idx" ON "web...
  type "website_event" (line 44) | CREATE INDEX "website_event_website_id_created_at_referrer_domain_idx" O...
  type "website_event" (line 47) | CREATE INDEX "website_event_website_id_created_at_page_title_idx" ON "we...
  type "website_event" (line 50) | CREATE INDEX "website_event_website_id_created_at_event_name_idx" ON "we...

FILE: prisma/migrations/04_team_redesign/migration.sql
  type "website" (line 26) | CREATE INDEX "website_team_id_idx" ON "website"("team_id")
  type "website" (line 29) | CREATE INDEX "website_created_by_idx" ON "website"("created_by")

FILE: prisma/migrations/05_add_visit_id/migration.sql
  type "website_event" (line 19) | CREATE INDEX "website_event_visit_id_idx" ON "website_event"("visit_id")
  type "website_event" (line 22) | CREATE INDEX "website_event_website_id_visit_id_created_at_idx" ON "webs...

FILE: prisma/migrations/06_session_data/migration.sql
  type "event_data" (line 12) | CREATE INDEX "event_data_website_id_created_at_data_key_idx" ON "event_d...
  type "session_data" (line 15) | CREATE INDEX "session_data_session_id_created_at_idx" ON "session_data"(...
  type "session_data" (line 18) | CREATE INDEX "session_data_website_id_created_at_data_key_idx" ON "sessi...

FILE: prisma/migrations/07_add_tag/migration.sql
  type "website_event" (line 5) | CREATE INDEX "website_event_website_id_created_at_tag_idx" ON "website_e...

FILE: prisma/migrations/09_update_hostname_region/migration.sql
  type "website_event" (line 21) | CREATE INDEX "website_event_website_id_created_at_hostname_idx" ON "webs...
  type "session" (line 22) | CREATE INDEX "session_website_id_created_at_region_idx" ON "session"("we...

FILE: prisma/migrations/11_add_segment/migration.sql
  type "segment" (line 2) | CREATE TABLE "segment" (
  type "segment" (line 15) | CREATE UNIQUE INDEX "segment_segment_id_key" ON "segment"("segment_id")
  type "segment" (line 18) | CREATE INDEX "segment_website_id_idx" ON "segment"("website_id")

FILE: prisma/migrations/13_add_revenue/migration.sql
  type "revenue" (line 2) | CREATE TABLE "revenue" (
  type "revenue" (line 16) | CREATE UNIQUE INDEX "revenue_revenue_id_key" ON "revenue"("revenue_id")
  type "revenue" (line 19) | CREATE INDEX "revenue_website_id_idx" ON "revenue"("website_id")
  type "revenue" (line 22) | CREATE INDEX "revenue_session_id_idx" ON "revenue"("session_id")
  type "revenue" (line 25) | CREATE INDEX "revenue_website_id_created_at_idx" ON "revenue"("website_i...
  type "revenue" (line 28) | CREATE INDEX "revenue_website_id_session_id_created_at_idx" ON "revenue"...

FILE: prisma/migrations/14_add_link_and_pixel/migration.sql
  type "link" (line 11) | CREATE TABLE "link" (
  type "pixel" (line 26) | CREATE TABLE "pixel" (
  type "link" (line 40) | CREATE UNIQUE INDEX "link_link_id_key" ON "link"("link_id")
  type "link" (line 43) | CREATE UNIQUE INDEX "link_slug_key" ON "link"("slug")
  type "link" (line 46) | CREATE INDEX "link_slug_idx" ON "link"("slug")
  type "link" (line 49) | CREATE INDEX "link_user_id_idx" ON "link"("user_id")
  type "link" (line 52) | CREATE INDEX "link_team_id_idx" ON "link"("team_id")
  type "link" (line 55) | CREATE INDEX "link_created_at_idx" ON "link"("created_at")
  type "pixel" (line 58) | CREATE UNIQUE INDEX "pixel_pixel_id_key" ON "pixel"("pixel_id")
  type "pixel" (line 61) | CREATE UNIQUE INDEX "pixel_slug_key" ON "pixel"("slug")
  type "pixel" (line 64) | CREATE INDEX "pixel_slug_idx" ON "pixel"("slug")
  type "pixel" (line 67) | CREATE INDEX "pixel_user_id_idx" ON "pixel"("user_id")
  type "pixel" (line 70) | CREATE INDEX "pixel_team_id_idx" ON "pixel"("team_id")
  type "pixel" (line 73) | CREATE INDEX "pixel_created_at_idx" ON "pixel"("created_at")

FILE: scripts/check-db.js
  constant MIN_VERSION (line 9) | const MIN_VERSION = '9.4.0';
  function success (line 25) | function success(msg) {
  function error (line 29) | function error(msg) {
  function checkEnv (line 33) | async function checkEnv() {
  function checkConnection (line 45) | async function checkConnection() {
  function checkDatabaseVersion (line 55) | async function checkDatabaseVersion() {
  function applyMigration (line 68) | async function applyMigration() {

FILE: scripts/check-env.js
  function checkMissing (line 4) | function checkMissing(vars) {

FILE: scripts/format-lang.js
  function run (line 17) | async function run() {

FILE: scripts/postbuild.js
  function run (line 4) | async function run() {

FILE: scripts/seed-data.ts
  function parseArgs (line 21) | function parseArgs(): SeedConfig {
  function printHelp (line 59) | function printHelp(): void {
  function checkEnvironment (line 90) | function checkEnvironment(): void {
  function main (line 106) | async function main(): Promise<void> {

FILE: scripts/seed/distributions/devices.ts
  type DeviceType (line 3) | type DeviceType = 'desktop' | 'mobile' | 'tablet';
  type DeviceInfo (line 66) | interface DeviceInfo {
  function getRandomDevice (line 73) | function getRandomDevice(): DeviceInfo {

FILE: scripts/seed/distributions/geographic.ts
  type GeoLocation (line 3) | interface GeoLocation {
  function getRandomGeo (line 110) | function getRandomGeo(): GeoLocation {
  function getRandomLanguage (line 142) | function getRandomLanguage(): string {

FILE: scripts/seed/distributions/referrers.ts
  type ReferrerType (line 3) | type ReferrerType = 'direct' | 'organic' | 'social' | 'paid' | 'referral';
  type ReferrerInfo (line 5) | interface ReferrerInfo {
  type PaidCampaign (line 54) | interface PaidCampaign {
  function generateClickId (line 77) | function generateClickId(): string {
  function getRandomReferrer (line 86) | function getRandomReferrer(): ReferrerInfo {

FILE: scripts/seed/distributions/temporal.ts
  function getWeightedHour (line 40) | function getWeightedHour(): number {
  function getDayOfWeekMultiplier (line 44) | function getDayOfWeekMultiplier(dayOfWeek: number): number {
  function generateTimestampForDay (line 49) | function generateTimestampForDay(day: Date): Date {
  function getSessionCountForDay (line 61) | function getSessionCountForDay(baseCount: number, day: Date): number {

FILE: scripts/seed/generators/events.ts
  constant EVENT_TYPE (line 5) | const EVENT_TYPE = {
  type PageConfig (line 10) | interface PageConfig {
  type CustomEventConfig (line 17) | interface CustomEventConfig {
  type JourneyConfig (line 24) | interface JourneyConfig {
  type EventData (line 29) | interface EventData {
  type EventDataEntry (line 53) | interface EventDataEntry {
  type SiteConfig (line 65) | interface SiteConfig {
  function getPageTitle (line 72) | function getPageTitle(pages: PageConfig[], path: string): string | null {
  function getPageTimeOnPage (line 77) | function getPageTimeOnPage(pages: PageConfig[], path: string): number {
  function generateEventsForSession (line 82) | function generateEventsForSession(

FILE: scripts/seed/generators/revenue.ts
  type RevenueConfig (line 4) | interface RevenueConfig {
  type RevenueData (line 12) | interface RevenueData {
  function generateRevenue (line 23) | function generateRevenue(event: EventData, config: RevenueConfig): Reven...
  function generateRevenueForEvents (line 46) | function generateRevenueForEvents(

FILE: scripts/seed/generators/sessions.ts
  type SessionData (line 6) | interface SessionData {
  function createSession (line 20) | function createSession(websiteId: string, day: Date): SessionData {
  function createSessions (line 41) | function createSessions(websiteId: string, day: Date, count: number): Se...

FILE: scripts/seed/index.ts
  constant BATCH_SIZE (line 34) | const BATCH_SIZE = 1000;
  type SessionCreateInput (line 36) | type SessionCreateInput = Prisma.SessionCreateManyInput;
  type WebsiteEventCreateInput (line 37) | type WebsiteEventCreateInput = Prisma.WebsiteEventCreateManyInput;
  type EventDataCreateInput (line 38) | type EventDataCreateInput = Prisma.EventDataCreateManyInput;
  type RevenueCreateInput (line 39) | type RevenueCreateInput = Prisma.RevenueCreateManyInput;
  type SeedConfig (line 41) | interface SeedConfig {
  type SeedResult (line 47) | interface SeedResult {
  function batchInsertSessions (line 55) | async function batchInsertSessions(
  function batchInsertEvents (line 71) | async function batchInsertEvents(
  function batchInsertEventData (line 87) | async function batchInsertEventData(
  function batchInsertRevenue (line 103) | async function batchInsertRevenue(
  function findAdminUser (line 119) | async function findAdminUser(prisma: PrismaClient): Promise<string> {
  function createWebsite (line 136) | async function createWebsite(
  function clearDemoData (line 157) | async function clearDemoData(prisma: PrismaClient): Promise<void> {
  type SiteGeneratorConfig (line 189) | interface SiteGeneratorConfig {
  function generateSiteData (line 198) | async function generateSiteData(
  function createPrismaClient (line 272) | function createPrismaClient(): PrismaClient {
  function seed (line 302) | async function seed(config: SeedConfig): Promise<SeedResult> {

FILE: scripts/seed/sites/blog.ts
  constant BLOG_WEBSITE_NAME (line 9) | const BLOG_WEBSITE_NAME = 'Demo Blog';
  constant BLOG_WEBSITE_DOMAIN (line 10) | const BLOG_WEBSITE_DOMAIN = 'blog.example.com';
  function getBlogSiteConfig (line 90) | function getBlogSiteConfig(): SiteConfig {
  function getBlogJourney (line 99) | function getBlogJourney(): string[] {
  constant BLOG_SESSIONS_PER_DAY (line 108) | const BLOG_SESSIONS_PER_DAY = 3;

FILE: scripts/seed/sites/saas.ts
  constant SAAS_WEBSITE_NAME (line 10) | const SAAS_WEBSITE_NAME = 'Demo SaaS';
  constant SAAS_WEBSITE_DOMAIN (line 11) | const SAAS_WEBSITE_DOMAIN = 'app.example.com';
  function getSaasSiteConfig (line 167) | function getSaasSiteConfig(): SiteConfig {
  function getSaasJourney (line 176) | function getSaasJourney(): string[] {
  constant SAAS_SESSIONS_PER_DAY (line 185) | const SAAS_SESSIONS_PER_DAY = 500;

FILE: scripts/seed/utils.ts
  type WeightedOption (line 3) | interface WeightedOption<T> {
  function weightedRandom (line 8) | function weightedRandom<T>(options: WeightedOption<T>[]): T {
  function randomInt (line 22) | function randomInt(min: number, max: number): number {
  function randomFloat (line 26) | function randomFloat(min: number, max: number): number {
  function pickRandom (line 30) | function pickRandom<T>(array: T[]): T {
  function shuffleArray (line 34) | function shuffleArray<T>(array: T[]): T[] {
  function uuid (line 43) | function uuid(): string {
  function generateDatesBetween (line 47) | function generateDatesBetween(startDate: Date, endDate: Date): Date[] {
  function addHours (line 60) | function addHours(date: Date, hours: number): Date {
  function addMinutes (line 64) | function addMinutes(date: Date, minutes: number): Date {
  function addSeconds (line 68) | function addSeconds(date: Date, seconds: number): Date {
  function subDays (line 72) | function subDays(date: Date, days: number): Date {
  function formatNumber (line 76) | function formatNumber(num: number): string {
  function progressBar (line 80) | function progressBar(current: number, total: number, width = 30): string {

FILE: scripts/telemetry.js
  function sendTelemetry (line 11) | async function sendTelemetry(type) {

FILE: src/app/(collect)/p/[slug]/route.ts
  function GET (line 12) | async function GET(request: Request, { params }: { params: Promise<{ slu...

FILE: src/app/(collect)/q/[slug]/route.ts
  function GET (line 10) | async function GET(request: Request, { params }: { params: Promise<{ slu...

FILE: src/app/(main)/App.tsx
  function App (line 12) | function App({ children }) {

FILE: src/app/(main)/MobileNav.tsx
  function MobileNav (line 12) | function MobileNav() {

FILE: src/app/(main)/SideNav.tsx
  function SideNav (line 19) | function SideNav(props: SidebarProps) {

FILE: src/app/(main)/TopNav.tsx
  function TopNav (line 5) | function TopNav() {

FILE: src/app/(main)/UpdateNotice.tsx
  function UpdateNotice (line 9) | function UpdateNotice({ user, config }) {

FILE: src/app/(main)/admin/AdminLayout.tsx
  function AdminLayout (line 8) | function AdminLayout({ children }: { children: ReactNode }) {

FILE: src/app/(main)/admin/AdminNav.tsx
  function AdminNav (line 5) | function AdminNav({ onItemClick }: { onItemClick?: () => void }) {

FILE: src/app/(main)/admin/teams/AdminTeamsDataTable.tsx
  function AdminTeamsDataTable (line 6) | function AdminTeamsDataTable({

FILE: src/app/(main)/admin/teams/AdminTeamsPage.tsx
  function AdminTeamsPage (line 8) | function AdminTeamsPage() {

FILE: src/app/(main)/admin/teams/AdminTeamsTable.tsx
  function AdminTeamsTable (line 10) | function AdminTeamsTable({

FILE: src/app/(main)/admin/teams/[teamId]/AdminTeamPage.tsx
  function AdminTeamPage (line 5) | function AdminTeamPage({ teamId }: { teamId: string }) {

FILE: src/app/(main)/admin/users/UserAddButton.tsx
  function UserAddButton (line 6) | function UserAddButton({ onSave }: { onSave?: () => void }) {

FILE: src/app/(main)/admin/users/UserAddForm.tsx
  function UserAddForm (line 15) | function UserAddForm({ onSave, onClose }) {

FILE: src/app/(main)/admin/users/UserDeleteButton.tsx
  function UserDeleteButton (line 6) | function UserDeleteButton({

FILE: src/app/(main)/admin/users/UserDeleteForm.tsx
  function UserDeleteForm (line 4) | function UserDeleteForm({

FILE: src/app/(main)/admin/users/UsersDataTable.tsx
  function UsersDataTable (line 6) | function UsersDataTable({ showActions }: { showActions?: boolean; childr...

FILE: src/app/(main)/admin/users/UsersPage.tsx
  function UsersPage (line 9) | function UsersPage() {

FILE: src/app/(main)/admin/users/UsersTable.tsx
  function UsersTable (line 11) | function UsersTable({

FILE: src/app/(main)/admin/users/[userId]/UserEditForm.tsx
  function UserEditForm (line 14) | function UserEditForm({ userId, onSave }: { userId: string; onSave?: () ...

FILE: src/app/(main)/admin/users/[userId]/UserHeader.tsx
  function UserHeader (line 5) | function UserHeader() {

FILE: src/app/(main)/admin/users/[userId]/UserPage.tsx
  function UserPage (line 8) | function UserPage({ userId }: { userId: string }) {

FILE: src/app/(main)/admin/users/[userId]/UserProvider.tsx
  function UserProvider (line 8) | function UserProvider({ userId, children }: { userId: string; children: ...

FILE: src/app/(main)/admin/users/[userId]/UserSettings.tsx
  function UserSettings (line 6) | function UserSettings({ userId }: { userId: string }) {

FILE: src/app/(main)/admin/users/[userId]/UserWebsites.tsx
  function UserWebsites (line 5) | function UserWebsites({ userId }) {

FILE: src/app/(main)/admin/websites/AdminWebsitesDataTable.tsx
  function AdminWebsitesDataTable (line 5) | function AdminWebsitesDataTable() {

FILE: src/app/(main)/admin/websites/AdminWebsitesPage.tsx
  function AdminWebsitesPage (line 8) | function AdminWebsitesPage() {

FILE: src/app/(main)/admin/websites/AdminWebsitesTable.tsx
  function AdminWebsitesTable (line 10) | function AdminWebsitesTable({ data = [] }: { data: any[] }) {

FILE: src/app/(main)/admin/websites/[websiteId]/AdminWebsitePage.tsx
  function AdminWebsitePage (line 6) | function AdminWebsitePage({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/boards/BoardAddButton.tsx
  function BoardAddButton (line 6) | function BoardAddButton() {

FILE: src/app/(main)/boards/BoardAddForm.tsx
  function BoardAddForm (line 5) | function BoardAddForm({

FILE: src/app/(main)/boards/BoardsPage.tsx
  function BoardsPage (line 7) | function BoardsPage() {

FILE: src/app/(main)/boards/[boardId]/Board.tsx
  function Board (line 3) | function Board({ boardId }: { boardId: string }) {

FILE: src/app/(main)/console/[websiteId]/TestConsolePage.tsx
  function TestConsolePage (line 12) | function TestConsolePage({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/console/[websiteId]/page.tsx
  function getEnabled (line 4) | async function getEnabled() {

FILE: src/app/(main)/dashboard/DashboardPage.tsx
  function DashboardPage (line 7) | function DashboardPage() {

FILE: src/app/(main)/links/LinkAddButton.tsx
  function LinkAddButton (line 6) | function LinkAddButton({ teamId }: { teamId?: string }) {

FILE: src/app/(main)/links/LinkDeleteButton.tsx
  function LinkDeleteButton (line 7) | function LinkDeleteButton({

FILE: src/app/(main)/links/LinkEditButton.tsx
  function LinkEditButton (line 6) | function LinkEditButton({ linkId }: { linkId: string }) {

FILE: src/app/(main)/links/LinkEditForm.tsx
  function LinkEditForm (line 23) | function LinkEditForm({

FILE: src/app/(main)/links/LinkProvider.tsx
  function LinkProvider (line 9) | function LinkProvider({ linkId, children }: { linkId?: string; children:...

FILE: src/app/(main)/links/LinksDataTable.tsx
  function LinksDataTable (line 5) | function LinksDataTable() {

FILE: src/app/(main)/links/LinksPage.tsx
  function LinksPage (line 10) | function LinksPage() {

FILE: src/app/(main)/links/LinksTable.tsx
  function LinksTable (line 9) | function LinksTable(props: DataTableProps) {

FILE: src/app/(main)/links/[linkId]/LinkControls.tsx
  function LinkControls (line 8) | function LinkControls({

FILE: src/app/(main)/links/[linkId]/LinkHeader.tsx
  function LinkHeader (line 7) | function LinkHeader() {

FILE: src/app/(main)/links/[linkId]/LinkMetricsBar.tsx
  function LinkMetricsBar (line 8) | function LinkMetricsBar({

FILE: src/app/(main)/links/[linkId]/LinkPage.tsx
  function LinkPage (line 15) | function LinkPage({ linkId }: { linkId: string }) {

FILE: src/app/(main)/links/[linkId]/LinkPanels.tsx
  function LinkPanels (line 8) | function LinkPanels({ linkId }: { linkId: string }) {

FILE: src/app/(main)/pixels/PixelAddButton.tsx
  function PixelAddButton (line 6) | function PixelAddButton({ teamId }: { teamId?: string }) {

FILE: src/app/(main)/pixels/PixelDeleteButton.tsx
  function PixelDeleteButton (line 7) | function PixelDeleteButton({

FILE: src/app/(main)/pixels/PixelEditButton.tsx
  function PixelEditButton (line 6) | function PixelEditButton({ pixelId }: { pixelId: string }) {

FILE: src/app/(main)/pixels/PixelEditForm.tsx
  function PixelEditForm (line 22) | function PixelEditForm({

FILE: src/app/(main)/pixels/PixelProvider.tsx
  function PixelProvider (line 9) | function PixelProvider({ pixelId, children }: { pixelId?: string; childr...

FILE: src/app/(main)/pixels/PixelsDataTable.tsx
  function PixelsDataTable (line 5) | function PixelsDataTable() {

FILE: src/app/(main)/pixels/PixelsPage.tsx
  function PixelsPage (line 10) | function PixelsPage() {

FILE: src/app/(main)/pixels/PixelsTable.tsx
  function PixelsTable (line 9) | function PixelsTable(props: DataTableProps) {

FILE: src/app/(main)/pixels/[pixelId]/PixelControls.tsx
  function PixelControls (line 8) | function PixelControls({

FILE: src/app/(main)/pixels/[pixelId]/PixelHeader.tsx
  function PixelHeader (line 7) | function PixelHeader() {

FILE: src/app/(main)/pixels/[pixelId]/PixelMetricsBar.tsx
  function PixelMetricsBar (line 8) | function PixelMetricsBar({

FILE: src/app/(main)/pixels/[pixelId]/PixelPage.tsx
  function PixelPage (line 15) | function PixelPage({ pixelId }: { pixelId: string }) {

FILE: src/app/(main)/pixels/[pixelId]/PixelPanels.tsx
  function PixelPanels (line 8) | function PixelPanels({ pixelId }: { pixelId: string }) {

FILE: src/app/(main)/settings/SettingsLayout.tsx
  function SettingsLayout (line 7) | function SettingsLayout({ children }: { children: ReactNode }) {

FILE: src/app/(main)/settings/SettingsNav.tsx
  function SettingsNav (line 5) | function SettingsNav({ onItemClick }: { onItemClick?: () => void }) {

FILE: src/app/(main)/settings/preferences/DateRangeSetting.tsx
  function DateRangeSetting (line 8) | function DateRangeSetting() {

FILE: src/app/(main)/settings/preferences/LanguageSetting.tsx
  function LanguageSetting (line 7) | function LanguageSetting() {

FILE: src/app/(main)/settings/preferences/PreferenceSettings.tsx
  function PreferenceSettings (line 8) | function PreferenceSettings() {

FILE: src/app/(main)/settings/preferences/PreferencesPage.tsx
  function PreferencesPage (line 9) | function PreferencesPage() {

FILE: src/app/(main)/settings/preferences/ThemeSetting.tsx
  function ThemeSetting (line 4) | function ThemeSetting() {

FILE: src/app/(main)/settings/preferences/TimezoneSetting.tsx
  function TimezoneSetting (line 8) | function TimezoneSetting() {

FILE: src/app/(main)/settings/profile/PasswordChangeButton.tsx
  function PasswordChangeButton (line 6) | function PasswordChangeButton() {

FILE: src/app/(main)/settings/profile/PasswordEditForm.tsx
  function PasswordEditForm (line 11) | function PasswordEditForm({ onSave, onClose }) {

FILE: src/app/(main)/settings/profile/ProfileHeader.tsx
  function ProfileHeader (line 4) | function ProfileHeader() {

FILE: src/app/(main)/settings/profile/ProfilePage.tsx
  function ProfilePage (line 9) | function ProfilePage() {

FILE: src/app/(main)/settings/profile/ProfileSettings.tsx
  function ProfileSettings (line 6) | function ProfileSettings() {

FILE: src/app/(main)/settings/teams/TeamsSettingsPage.tsx
  function TeamsSettingsPage (line 7) | function TeamsSettingsPage() {

FILE: src/app/(main)/settings/teams/[teamId]/TeamSettingsPage.tsx
  function TeamSettingsPage (line 5) | function TeamSettingsPage({ teamId }: { teamId: string }) {

FILE: src/app/(main)/settings/websites/WebsitesSettingsPage.tsx
  function WebsitesSettingsPage (line 7) | function WebsitesSettingsPage({ teamId }: { teamId: string }) {

FILE: src/app/(main)/settings/websites/[websiteId]/WebsiteSettingsPage.tsx
  function WebsiteSettingsPage (line 7) | function WebsiteSettingsPage({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/teams/TeamAddForm.tsx
  function TeamAddForm (line 11) | function TeamAddForm({ onSave, onClose }: { onSave: () => void; onClose:...

FILE: src/app/(main)/teams/TeamJoinForm.tsx
  function TeamJoinForm (line 11) | function TeamJoinForm({ onSave, onClose }: { onSave: () => void; onClose...

FILE: src/app/(main)/teams/TeamLeaveButton.tsx
  function TeamLeaveButton (line 7) | function TeamLeaveButton({ teamId, teamName }: { teamId: string; teamNam...

FILE: src/app/(main)/teams/TeamLeaveForm.tsx
  function TeamLeaveForm (line 4) | function TeamLeaveForm({

FILE: src/app/(main)/teams/TeamProvider.tsx
  function TeamProvider (line 9) | function TeamProvider({ teamId, children }: { teamId?: string; children:...

FILE: src/app/(main)/teams/TeamsAddButton.tsx
  function TeamsAddButton (line 7) | function TeamsAddButton({ onSave }: { onSave?: () => void }) {

FILE: src/app/(main)/teams/TeamsDataTable.tsx
  function TeamsDataTable (line 6) | function TeamsDataTable() {

FILE: src/app/(main)/teams/TeamsHeader.tsx
  function TeamsHeader (line 8) | function TeamsHeader({

FILE: src/app/(main)/teams/TeamsJoinButton.tsx
  function TeamsJoinButton (line 6) | function TeamsJoinButton() {

FILE: src/app/(main)/teams/TeamsPage.tsx
  function TeamsPage (line 8) | function TeamsPage() {

FILE: src/app/(main)/teams/TeamsTable.tsx
  type TeamsTableProps (line 6) | interface TeamsTableProps extends DataTableProps {
  function TeamsTable (line 10) | function TeamsTable({ renderLink, ...props }: TeamsTableProps) {

FILE: src/app/(main)/teams/[teamId]/TeamDeleteForm.tsx
  constant CONFIRM_VALUE (line 4) | const CONFIRM_VALUE = 'DELETE';
  function TeamDeleteForm (line 6) | function TeamDeleteForm({

FILE: src/app/(main)/teams/[teamId]/TeamEditForm.tsx
  function TeamEditForm (line 17) | function TeamEditForm({

FILE: src/app/(main)/teams/[teamId]/TeamManage.tsx
  function TeamManage (line 7) | function TeamManage({ teamId }: { teamId: string }) {

FILE: src/app/(main)/teams/[teamId]/TeamMemberEditButton.tsx
  function TeamMemberEditButton (line 7) | function TeamMemberEditButton({

FILE: src/app/(main)/teams/[teamId]/TeamMemberEditForm.tsx
  function TeamMemberEditForm (line 13) | function TeamMemberEditForm({

FILE: src/app/(main)/teams/[teamId]/TeamMemberRemoveButton.tsx
  function TeamMemberRemoveButton (line 7) | function TeamMemberRemoveButton({

FILE: src/app/(main)/teams/[teamId]/TeamMembersDataTable.tsx
  function TeamMembersDataTable (line 5) | function TeamMembersDataTable({

FILE: src/app/(main)/teams/[teamId]/TeamMembersTable.tsx
  function TeamMembersTable (line 7) | function TeamMembersTable({

FILE: src/app/(main)/teams/[teamId]/TeamSettings.tsx
  function TeamSettings (line 12) | function TeamSettings({ teamId }: { teamId: string }) {

FILE: src/app/(main)/teams/[teamId]/TeamWebsiteRemoveButton.tsx
  function TeamWebsiteRemoveButton (line 5) | function TeamWebsiteRemoveButton({ teamId, websiteId, onSave }) {

FILE: src/app/(main)/teams/[teamId]/TeamWebsitesDataTable.tsx
  function TeamWebsitesDataTable (line 5) | function TeamWebsitesDataTable({

FILE: src/app/(main)/teams/[teamId]/TeamWebsitesTable.tsx
  function TeamWebsitesTable (line 8) | function TeamWebsitesTable({

FILE: src/app/(main)/websites/WebsiteAddButton.tsx
  function WebsiteAddButton (line 7) | function WebsiteAddButton({ teamId, onSave }: { teamId: string; onSave?:...

FILE: src/app/(main)/websites/WebsiteAddForm.tsx
  function WebsiteAddForm (line 5) | function WebsiteAddForm({

FILE: src/app/(main)/websites/WebsiteProvider.tsx
  function WebsiteProvider (line 9) | function WebsiteProvider({

FILE: src/app/(main)/websites/WebsitesDataTable.tsx
  function WebsitesDataTable (line 8) | function WebsitesDataTable({

FILE: src/app/(main)/websites/WebsitesHeader.tsx
  type WebsitesHeaderProps (line 5) | interface WebsitesHeaderProps {
  function WebsitesHeader (line 9) | function WebsitesHeader({ allowCreate = true }: WebsitesHeaderProps) {

FILE: src/app/(main)/websites/WebsitesPage.tsx
  function WebsitesPage (line 10) | function WebsitesPage() {

FILE: src/app/(main)/websites/WebsitesTable.tsx
  type WebsitesTableProps (line 7) | interface WebsitesTableProps extends DataTableProps {
  function WebsitesTable (line 14) | function WebsitesTable({ showActions, renderLink, ...props }: WebsitesTa...

FILE: src/app/(main)/websites/[websiteId]/(reports)/attribution/Attribution.tsx
  type AttributionProps (line 12) | interface AttributionProps {
  function Attribution (line 22) | function Attribution({

FILE: src/app/(main)/websites/[websiteId]/(reports)/attribution/AttributionPage.tsx
  function AttributionPage (line 8) | function AttributionPage({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/(reports)/breakdown/Breakdown.tsx
  type BreakdownProps (line 6) | interface BreakdownProps {
  function Breakdown (line 13) | function Breakdown({ websiteId, selectedFields = [], startDate, endDate ...

FILE: src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx
  function BreakdownPage (line 12) | function BreakdownPage({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/(reports)/breakdown/FieldSelectForm.tsx
  function FieldSelectForm (line 5) | function FieldSelectForm({

FILE: src/app/(main)/websites/[websiteId]/(reports)/funnels/Funnel.tsx
  type FunnelResult (line 11) | type FunnelResult = {
  function Funnel (line 21) | function Funnel({ id, name, type, parameters, websiteId }) {

FILE: src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelAddButton.tsx
  function FunnelAddButton (line 6) | function FunnelAddButton({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelEditForm.tsx
  constant FUNNEL_STEPS_MAX (line 21) | const FUNNEL_STEPS_MAX = 8;
  function FunnelEditForm (line 23) | function FunnelEditForm({

FILE: src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage.tsx
  function FunnelsPage (line 11) | function FunnelsPage({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/(reports)/goals/Goal.tsx
  type GoalProps (line 10) | interface GoalProps {
  type GoalData (line 24) | type GoalData = { num: number; total: number };
  function Goal (line 26) | function Goal({ id, name, type, parameters, websiteId, startDate, endDat...

FILE: src/app/(main)/websites/[websiteId]/(reports)/goals/GoalAddButton.tsx
  function GoalAddButton (line 6) | function GoalAddButton({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/(reports)/goals/GoalEditForm.tsx
  function GoalEditForm (line 17) | function GoalEditForm({

FILE: src/app/(main)/websites/[websiteId]/(reports)/goals/GoalsPage.tsx
  function GoalsPage (line 11) | function GoalsPage({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/(reports)/journeys/Journey.tsx
  constant NODE_HEIGHT (line 13) | const NODE_HEIGHT = 60;
  constant NODE_GAP (line 14) | const NODE_GAP = 10;
  constant LINE_WIDTH (line 15) | const LINE_WIDTH = 3;
  type JourneyProps (line 17) | interface JourneyProps {
  function Journey (line 26) | function Journey({ websiteId, steps, startStep, endStep }: JourneyProps) {

FILE: src/app/(main)/websites/[websiteId]/(reports)/journeys/JourneysPage.tsx
  constant JOURNEY_STEPS (line 9) | const JOURNEY_STEPS = [2, 3, 4, 5, 6, 7];
  constant DEFAULT_STEP (line 10) | const DEFAULT_STEP = 3;
  function JourneysPage (line 12) | function JourneysPage({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/(reports)/retention/Retention.tsx
  constant DAYS (line 10) | const DAYS = [1, 2, 3, 4, 5, 6, 7, 14, 21, 28];
  type RetentionProps (line 12) | interface RetentionProps {
  function Retention (line 19) | function Retention({ websiteId, days = DAYS, startDate, endDate }: Reten...

FILE: src/app/(main)/websites/[websiteId]/(reports)/retention/RetentionPage.tsx
  function RetentionPage (line 8) | function RetentionPage({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/(reports)/revenue/Revenue.tsx
  type RevenueProps (line 19) | interface RevenueProps {
  function Revenue (line 26) | function Revenue({ websiteId, startDate, endDate, unit }: RevenueProps) {

FILE: src/app/(main)/websites/[websiteId]/(reports)/revenue/RevenuePage.tsx
  function RevenuePage (line 7) | function RevenuePage({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/(reports)/revenue/RevenueTable.tsx
  function RevenueTable (line 5) | function RevenueTable({ data = [] }) {

FILE: src/app/(main)/websites/[websiteId]/(reports)/utm/UTM.tsx
  type UTMProps (line 9) | interface UTMProps {
  function UTM (line 15) | function UTM({ websiteId, startDate, endDate }: UTMProps) {

FILE: src/app/(main)/websites/[websiteId]/(reports)/utm/UTMPage.tsx
  function UTMPage (line 7) | function UTMPage({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/ExpandedViewModal.tsx
  function ExpandedViewModal (line 5) | function ExpandedViewModal({

FILE: src/app/(main)/websites/[websiteId]/WebsiteChart.tsx
  function WebsiteChart (line 7) | function WebsiteChart({

FILE: src/app/(main)/websites/[websiteId]/WebsiteControls.tsx
  function WebsiteControls (line 8) | function WebsiteControls({

FILE: src/app/(main)/websites/[websiteId]/WebsiteExpandedMenu.tsx
  function WebsiteExpandedMenu (line 25) | function WebsiteExpandedMenu({

FILE: src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx
  function WebsiteExpandedView (line 7) | function WebsiteExpandedView({

FILE: src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx
  function WebsiteHeader (line 11) | function WebsiteHeader({ showActions }: { showActions?: boolean }) {

FILE: src/app/(main)/websites/[websiteId]/WebsiteLayout.tsx
  function WebsiteLayout (line 9) | function WebsiteLayout({ websiteId, children }: { websiteId: string; chi...

FILE: src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx
  function WebsiteMenu (line 15) | function WebsiteMenu({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx
  function WebsiteMetricsBar (line 8) | function WebsiteMetricsBar({

FILE: src/app/(main)/websites/[websiteId]/WebsiteNav.tsx
  function WebsiteNav (line 17) | function WebsiteNav({

FILE: src/app/(main)/websites/[websiteId]/WebsitePage.tsx
  function WebsitePage (line 10) | function WebsitePage({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/WebsitePanels.tsx
  function WebsitePanels (line 10) | function WebsitePanels({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/WebsiteTabs.tsx
  function WebsiteTabs (line 6) | function WebsiteTabs() {

FILE: src/app/(main)/websites/[websiteId]/cohorts/CohortAddButton.tsx
  function CohortAddButton (line 6) | function CohortAddButton({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/cohorts/CohortDeleteButton.tsx
  function CohortDeleteButton (line 7) | function CohortDeleteButton({

FILE: src/app/(main)/websites/[websiteId]/cohorts/CohortEditButton.tsx
  function CohortEditButton (line 7) | function CohortEditButton({

FILE: src/app/(main)/websites/[websiteId]/cohorts/CohortEditForm.tsx
  function CohortEditForm (line 19) | function CohortEditForm({

FILE: src/app/(main)/websites/[websiteId]/cohorts/CohortsDataTable.tsx
  function CohortsDataTable (line 6) | function CohortsDataTable({ websiteId }: { websiteId?: string }) {

FILE: src/app/(main)/websites/[websiteId]/cohorts/CohortsPage.tsx
  function CohortsPage (line 7) | function CohortsPage({ websiteId }) {

FILE: src/app/(main)/websites/[websiteId]/cohorts/CohortsTable.tsx
  function CohortsTable (line 9) | function CohortsTable(props: DataTableProps) {

FILE: src/app/(main)/websites/[websiteId]/compare/ComparePage.tsx
  function ComparePage (line 9) | function ComparePage({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/compare/CompareTables.tsx
  function CompareTables (line 10) | function CompareTables({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/events/EventProperties.tsx
  function EventProperties (line 13) | function EventProperties({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/events/EventsDataTable.tsx
  function EventsDataTable (line 7) | function EventsDataTable({

FILE: src/app/(main)/websites/[websiteId]/events/EventsMetricsBar.tsx
  function EventsMetricsBar (line 8) | function EventsMetricsBar({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/events/EventsPage.tsx
  constant KEY_NAME (line 14) | const KEY_NAME = 'umami.events.tab';
  function EventsPage (line 16) | function EventsPage({ websiteId }) {

FILE: src/app/(main)/websites/[websiteId]/events/EventsTable.tsx
  function EventsTable (line 23) | function EventsTable(props: DataTableProps) {

FILE: src/app/(main)/websites/[websiteId]/realtime/RealtimeCountries.tsx
  function RealtimeCountries (line 7) | function RealtimeCountries({ data }) {

FILE: src/app/(main)/websites/[websiteId]/realtime/RealtimeHeader.tsx
  function RealtimeHeader (line 5) | function RealtimeHeader({ data }: { data: any }) {

FILE: src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx
  constant TYPE_ALL (line 23) | const TYPE_ALL = 'all';
  constant TYPE_PAGEVIEW (line 24) | const TYPE_PAGEVIEW = 'pageview';
  constant TYPE_SESSION (line 25) | const TYPE_SESSION = 'session';
  constant TYPE_EVENT (line 26) | const TYPE_EVENT = 'event';
  function RealtimeLog (line 34) | function RealtimeLog({ data }: { data: any }) {

FILE: src/app/(main)/websites/[websiteId]/realtime/RealtimePage.tsx
  function RealtimePage (line 17) | function RealtimePage({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/realtime/RealtimePaths.tsx
  function RealtimePaths (line 6) | function RealtimePaths({ data }: { data: any }) {

FILE: src/app/(main)/websites/[websiteId]/realtime/RealtimeReferrers.tsx
  function RealtimeReferrers (line 6) | function RealtimeReferrers({ data }: { data: any }) {

FILE: src/app/(main)/websites/[websiteId]/segments/SegmentAddButton.tsx
  function SegmentAddButton (line 6) | function SegmentAddButton({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/segments/SegmentDeleteButton.tsx
  function SegmentDeleteButton (line 7) | function SegmentDeleteButton({

FILE: src/app/(main)/websites/[websiteId]/segments/SegmentEditButton.tsx
  function SegmentEditButton (line 7) | function SegmentEditButton({

FILE: src/app/(main)/websites/[websiteId]/segments/SegmentEditForm.tsx
  function SegmentEditForm (line 15) | function SegmentEditForm({

FILE: src/app/(main)/websites/[websiteId]/segments/SegmentsDataTable.tsx
  function SegmentsDataTable (line 6) | function SegmentsDataTable({ websiteId }: { websiteId?: string }) {

FILE: src/app/(main)/websites/[websiteId]/segments/SegmentsPage.tsx
  function SegmentsPage (line 7) | function SegmentsPage({ websiteId }) {

FILE: src/app/(main)/websites/[websiteId]/segments/SegmentsTable.tsx
  function SegmentsTable (line 8) | function SegmentsTable(props: DataTableProps) {

FILE: src/app/(main)/websites/[websiteId]/sessions/SessionActivity.tsx
  function SessionActivity (line 20) | function SessionActivity({

FILE: src/app/(main)/websites/[websiteId]/sessions/SessionData.tsx
  function SessionData (line 7) | function SessionData({ websiteId, sessionId }: { websiteId: string; sess...

FILE: src/app/(main)/websites/[websiteId]/sessions/SessionInfo.tsx
  function SessionInfo (line 8) | function SessionInfo({ data }) {

FILE: src/app/(main)/websites/[websiteId]/sessions/SessionModal.tsx
  type SessionModalProps (line 5) | interface SessionModalProps extends ModalProps {
  function SessionModal (line 9) | function SessionModal({ websiteId, ...props }: SessionModalProps) {

FILE: src/app/(main)/websites/[websiteId]/sessions/SessionProfile.tsx
  function SessionProfile (line 21) | function SessionProfile({

FILE: src/app/(main)/websites/[websiteId]/sessions/SessionProperties.tsx
  function SessionProperties (line 13) | function SessionProperties({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/sessions/SessionStats.tsx
  function SessionStats (line 6) | function SessionStats({ data }) {

FILE: src/app/(main)/websites/[websiteId]/sessions/SessionsDataTable.tsx
  function SessionsDataTable (line 5) | function SessionsDataTable({ websiteId }: { websiteId?: string; teamId?:...

FILE: src/app/(main)/websites/[websiteId]/sessions/SessionsMetricsBar.tsx
  function SessionsMetricsBar (line 8) | function SessionsMetricsBar({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/sessions/SessionsPage.tsx
  constant KEY_NAME (line 12) | const KEY_NAME = 'umami.sessions.tab';
  function SessionsPage (line 14) | function SessionsPage({ websiteId }) {

FILE: src/app/(main)/websites/[websiteId]/sessions/SessionsTable.tsx
  function SessionsTable (line 8) | function SessionsTable(props: DataTableProps) {

FILE: src/app/(main)/websites/[websiteId]/settings/SettingsPage.tsx
  function SettingsPage (line 4) | function SettingsPage({ websiteId }: { websiteId: string }) {

FILE: src/app/(main)/websites/[websiteId]/settings/WebsiteData.tsx
  function WebsiteData (line 15) | function WebsiteData({ websiteId, onSave }: { websiteId: string; onSave?...

FILE: src/app/(main)/websites/[websiteId]/settings/WebsiteDeleteForm.tsx
  constant CONFIRM_VALUE (line 4) | const CONFIRM_VALUE = 'DELETE';
  function WebsiteDeleteForm (line 6) | function WebsiteDeleteForm({

FILE: src/app/(main)/websites/[websiteId]/settings/WebsiteEditForm.tsx
  function WebsiteEditForm (line 5) | function WebsiteEditForm({ websiteId, onSave }: { websiteId: string; onS...

FILE: src/app/(main)/websites/[websiteId]/settings/WebsiteResetForm.tsx
  constant CONFIRM_VALUE (line 4) | const CONFIRM_VALUE = 'RESET';
  function WebsiteResetForm (line 6) | function WebsiteResetForm({

FILE: src/app/(main)/websites/[websiteId]/settings/WebsiteSettings.tsx
  function WebsiteSettings (line 9) | function WebsiteSettings({ websiteId }: { websiteId: string; openExterna...

FILE: src/app/(main)/websites/[websiteId]/settings/WebsiteSettingsHeader.tsx
  function WebsiteSettingsHeader (line 7) | function WebsiteSettingsHeader() {

FILE: src/app/(main)/websites/[websiteId]/settings/WebsiteShareForm.tsx
  type WebsiteShareFormProps (line 20) | interface WebsiteShareFormProps {
  function WebsiteShareForm (line 27) | function WebsiteShareForm({ websiteId, shareId, onSave, onClose }: Websi...

FILE: src/app/(main)/websites/[websiteId]/settings/WebsiteTrackingCode.tsx
  constant SCRIPT_NAME (line 4) | const SCRIPT_NAME = 'script.js';
  function WebsiteTrackingCode (line 6) | function WebsiteTrackingCode({

FILE: src/app/(main)/websites/[websiteId]/settings/WebsiteTransferForm.tsx
  function WebsiteTransferForm (line 22) | function WebsiteTransferForm({

FILE: src/app/Providers.tsx
  function MessagesProvider (line 21) | function MessagesProvider({ children }) {
  function Providers (line 36) | function Providers({ children }) {

FILE: src/app/api/admin/teams/route.ts
  function GET (line 8) | async function GET(request: Request) {

FILE: src/app/api/admin/users/route.ts
  function GET (line 8) | async function GET(request: Request) {

FILE: src/app/api/admin/websites/route.ts
  function GET (line 9) | async function GET(request: Request) {

FILE: src/app/api/auth/login/route.ts
  function POST (line 12) | async function POST(request: Request) {

FILE: src/app/api/auth/logout/route.ts
  function POST (line 4) | async function POST(request: Request) {

FILE: src/app/api/auth/sso/route.ts
  function POST (line 6) | async function POST(request: Request) {

FILE: src/app/api/auth/verify/route.ts
  function POST (line 5) | async function POST(request: Request) {

FILE: src/app/api/batch/route.ts
  function POST (line 9) | async function POST(request: Request) {

FILE: src/app/api/config/route.ts
  function GET (line 4) | async function GET(request: Request) {

FILE: src/app/api/heartbeat/route.ts
  function GET (line 1) | async function GET() {

FILE: src/app/api/links/[linkId]/route.ts
  function GET (line 7) | async function GET(request: Request, { params }: { params: Promise<{ lin...
  function POST (line 25) | async function POST(request: Request, { params }: { params: Promise<{ li...
  function DELETE (line 58) | async function DELETE(

FILE: src/app/api/links/route.ts
  function GET (line 9) | async function GET(request: Request) {
  function POST (line 28) | async function POST(request: Request) {

FILE: src/app/api/me/password/route.ts
  function POST (line 7) | async function POST(request: Request) {

FILE: src/app/api/me/route.ts
  function GET (line 4) | async function GET(request: Request) {

FILE: src/app/api/me/teams/route.ts
  function GET (line 7) | async function GET(request: Request) {

FILE: src/app/api/me/websites/route.ts
  function GET (line 7) | async function GET(request: Request) {

FILE: src/app/api/pixels/[pixelId]/route.ts
  function GET (line 7) | async function GET(request: Request, { params }: { params: Promise<{ pix...
  function POST (line 25) | async function POST(request: Request, { params }: { params: Promise<{ pi...
  function DELETE (line 57) | async function DELETE(

FILE: src/app/api/pixels/route.ts
  function GET (line 9) | async function GET(request: Request) {
  function POST (line 28) | async function POST(request: Request) {

FILE: src/app/api/realtime/[websiteId]/route.ts
  function GET (line 8) | async function GET(

FILE: src/app/api/reports/[reportId]/route.ts
  function GET (line 7) | async function GET(request: Request, { params }: { params: Promise<{ rep...
  function POST (line 25) | async function POST(
  function DELETE (line 60) | async function DELETE(

FILE: src/app/api/reports/attribution/route.ts
  function POST (line 7) | async function POST(request: Request) {

FILE: src/app/api/reports/breakdown/route.ts
  function POST (line 7) | async function POST(request: Request) {

FILE: src/app/api/reports/funnel/route.ts
  function POST (line 7) | async function POST(request: Request) {

FILE: src/app/api/reports/goal/route.ts
  function POST (line 7) | async function POST(request: Request) {

FILE: src/app/api/reports/journey/route.ts
  function POST (line 7) | async function POST(request: Request) {

FILE: src/app/api/reports/retention/route.ts
  function POST (line 7) | async function POST(request: Request) {

FILE: src/app/api/reports/revenue/route.ts
  function POST (line 7) | async function POST(request: Request) {

FILE: src/app/api/reports/route.ts
  function GET (line 9) | async function GET(request: Request) {
  function POST (line 49) | async function POST(request: Request) {

FILE: src/app/api/reports/utm/route.ts
  function POST (line 8) | async function POST(request: Request) {

FILE: src/app/api/scripts/telemetry/route.ts
  function GET (line 3) | async function GET() {

FILE: src/app/api/send/route.ts
  type Cache (line 17) | interface Cache {
  function POST (line 61) | async function POST(request: Request) {

FILE: src/app/api/share/[shareId]/route.ts
  function GET (line 6) | async function GET(_request: Request, { params }: { params: Promise<{ sh...

FILE: src/app/api/teams/[teamId]/links/route.ts
  function GET (line 8) | async function GET(request: Request, { params }: { params: Promise<{ tea...

FILE: src/app/api/teams/[teamId]/pixels/route.ts
  function GET (line 8) | async function GET(request: Request, { params }: { params: Promise<{ tea...

FILE: src/app/api/teams/[teamId]/route.ts
  function GET (line 7) | async function GET(request: Request, { params }: { params: Promise<{ tea...
  function POST (line 29) | async function POST(request: Request, { params }: { params: Promise<{ te...
  function DELETE (line 52) | async function DELETE(

FILE: src/app/api/teams/[teamId]/users/[userId]/route.ts
  function GET (line 8) | async function GET(
  function POST (line 29) | async function POST(
  function DELETE (line 60) | async function DELETE(

FILE: src/app/api/teams/[teamId]/users/route.ts
  function GET (line 8) | async function GET(request: Request, { params }: { params: Promise<{ tea...
  function POST (line 54) | async function POST(request: Request, { params }: { params: Promise<{ te...

FILE: src/app/api/teams/[teamId]/websites/route.ts
  function GET (line 8) | async function GET(request: Request, { params }: { params: Promise<{ tea...

FILE: src/app/api/teams/join/route.ts
  function POST (line 7) | async function POST(request: Request) {

FILE: src/app/api/teams/route.ts
  function GET (line 10) | async function GET(request: Request) {
  function POST (line 28) | async function POST(request: Request) {

FILE: src/app/api/users/[userId]/route.ts
  function GET (line 9) | async function GET(request: Request, { params }: { params: Promise<{ use...
  function POST (line 27) | async function POST(request: Request, { params }: { params: Promise<{ us...
  function DELETE (line 79) | async function DELETE(

FILE: src/app/api/users/[userId]/teams/route.ts
  function GET (line 7) | async function GET(request: Request, { params }: { params: Promise<{ use...

FILE: src/app/api/users/[userId]/websites/route.ts
  function GET (line 7) | async function GET(request: Request, { params }: { params: Promise<{ use...

FILE: src/app/api/users/route.ts
  function POST (line 10) | async function POST(request: Request) {

FILE: src/app/api/websites/[websiteId]/active/route.ts
  function GET (line 6) | async function GET(

FILE: src/app/api/websites/[websiteId]/daterange/route.ts
  function GET (line 6) | async function GET(

FILE: src/app/api/websites/[websiteId]/event-data/[eventId]/route.ts
  function GET (line 6) | async function GET(

FILE: src/app/api/websites/[websiteId]/event-data/events/route.ts
  function GET (line 8) | async function GET(

FILE: src/app/api/websites/[websiteId]/event-data/fields/route.ts
  function GET (line 8) | async function GET(

FILE: src/app/api/websites/[websiteId]/event-data/properties/route.ts
  function GET (line 8) | async function GET(

FILE: src/app/api/websites/[websiteId]/event-data/stats/route.ts
  function GET (line 8) | async function GET(

FILE: src/app/api/websites/[websiteId]/event-data/values/route.ts
  function GET (line 8) | async function GET(

FILE: src/app/api/websites/[websiteId]/events/route.ts
  function GET (line 8) | async function GET(

FILE: src/app/api/websites/[websiteId]/events/series/route.ts
  function GET (line 8) | async function GET(

FILE: src/app/api/websites/[websiteId]/export/route.ts
  function GET (line 10) | async function GET(

FILE: src/app/api/websites/[websiteId]/metrics/expanded/route.ts
  function GET (line 14) | async function GET(

FILE: src/app/api/websites/[websiteId]/metrics/route.ts
  function GET (line 14) | async function GET(

FILE: src/app/api/websites/[websiteId]/pageviews/route.ts
  function GET (line 9) | async function GET(

FILE: src/app/api/websites/[websiteId]/reports/route.ts
  function GET (line 8) | async function GET(

FILE: src/app/api/websites/[websiteId]/reset/route.ts
  function POST (line 6) | async function POST(

FILE: src/app/api/websites/[websiteId]/route.ts
  function GET (line 8) | async function GET(
  function POST (line 29) | async function POST(
  function DELETE (line 65) | async function DELETE(

FILE: src/app/api/websites/[websiteId]/segments/[segmentId]/route.ts
  function GET (line 8) | async function GET(
  function POST (line 29) | async function POST(
  function DELETE (line 67) | async function DELETE(

FILE: src/app/api/websites/[websiteId]/segments/route.ts
  function GET (line 9) | async function GET(
  function POST (line 38) | async function POST(

FILE: src/app/api/websites/[websiteId]/session-data/properties/route.ts
  function GET (line 8) | async function GET(

FILE: src/app/api/websites/[websiteId]/session-data/values/route.ts
  function GET (line 8) | async function GET(

FILE: src/app/api/websites/[websiteId]/sessions/[sessionId]/activity/route.ts
  function GET (line 7) | async function GET(

FILE: src/app/api/websites/[websiteId]/sessions/[sessionId]/properties/route.ts
  function GET (line 6) | async function GET(

FILE: src/app/api/websites/[websiteId]/sessions/[sessionId]/route.ts
  function GET (line 6) | async function GET(

FILE: src/app/api/websites/[websiteId]/sessions/route.ts
  function GET (line 8) | async function GET(

FILE: src/app/api/websites/[websiteId]/sessions/stats/route.ts
  function GET (line 8) | async function GET(

FILE: src/app/api/websites/[websiteId]/sessions/weekly/route.ts
  function GET (line 8) | async function GET(

FILE: src/app/api/websites/[websiteId]/stats/route.ts
  function GET (line 9) | async function GET(

FILE: src/app/api/websites/[websiteId]/transfer/route.ts
  function POST (line 7) | async function POST(

FILE: src/app/api/websites/[websiteId]/values/route.ts
  function GET (line 10) | async function GET(

FILE: src/app/api/websites/route.ts
  constant CLOUD_WEBSITE_LIMIT (line 11) | const CLOUD_WEBSITE_LIMIT = 3;
  function GET (line 13) | async function GET(request: Request) {
  function POST (line 37) | async function POST(request: Request) {

FILE: src/app/login/LoginForm.tsx
  function LoginForm (line 18) | function LoginForm() {

FILE: src/app/login/LoginPage.tsx
  function LoginPage (line 5) | function LoginPage() {

FILE: src/app/logout/LogoutPage.tsx
  function LogoutPage (line 8) | function LogoutPage() {

FILE: src/app/page.tsx
  function RootPage (line 7) | function RootPage() {

FILE: src/app/share/[...shareId]/Footer.tsx
  function Footer (line 4) | function Footer() {

FILE: src/app/share/[...shareId]/Header.tsx
  function Header (line 6) | function Header() {

FILE: src/app/share/[...shareId]/SharePage.tsx
  function SharePage (line 12) | function SharePage({ shareId }) {

FILE: src/app/sso/SSOPage.tsx
  function SSOPage (line 7) | function SSOPage() {

FILE: src/components/boards/Board.tsx
  type BoardProps (line 3) | interface BoardProps {
  function Board (line 7) | function Board({ children }: BoardProps) {

FILE: src/components/charts/BarChart.tsx
  type BarChartProps (line 23) | interface BarChartProps extends ChartProps {
  function BarChart (line 35) | function BarChart({

FILE: src/components/charts/BubbleChart.tsx
  type BubbleChartProps (line 5) | interface BubbleChartProps extends ChartProps {
  function BubbleChart (line 9) | function BubbleChart({ type = 'bubble', ...props }: BubbleChartProps) {

FILE: src/components/charts/Chart.tsx
  type ChartProps (line 14) | interface ChartProps extends BoxProps {
  function Chart (line 23) | function Chart({

FILE: src/components/charts/ChartTooltip.tsx
  function ChartTooltip (line 4) | function ChartTooltip({

FILE: src/components/charts/PieChart.tsx
  type PieChartProps (line 5) | interface PieChartProps extends ChartProps {
  function PieChart (line 9) | function PieChart({ type = 'pie', ...props }: PieChartProps) {

FILE: src/components/common/ActionForm.tsx
  function ActionForm (line 3) | function ActionForm({ label, description, children }) {

FILE: src/components/common/Avatar.tsx
  function Avatar (line 8) | function Avatar({ seed, size = 128, ...props }: { seed: string; size?: n...

FILE: src/components/common/ConfirmationForm.tsx
  type ConfirmationFormProps (line 5) | interface ConfirmationFormProps {
  function ConfirmationForm (line 15) | function ConfirmationForm({

FILE: src/components/common/DataGrid.tsx
  constant DEFAULT_SEARCH_DELAY (line 17) | const DEFAULT_SEARCH_DELAY = 600;
  type DataGridProps (line 19) | interface DataGridProps {
  function DataGrid (line 30) | function DataGrid({

FILE: src/components/common/DateDisplay.tsx
  function DateDisplay (line 7) | function DateDisplay({ startDate, endDate }) {

FILE: src/components/common/DateDistance.tsx
  function DateDistance (line 6) | function DateDistance({ date }: { date: Date }) {

FILE: src/components/common/Empty.tsx
  type EmptyProps (line 4) | interface EmptyProps {
  function Empty (line 8) | function Empty({ message }: EmptyProps) {

FILE: src/components/common/EmptyPlaceholder.tsx
  type EmptyPlaceholderProps (line 4) | interface EmptyPlaceholderProps {
  function EmptyPlaceholder (line 11) | function EmptyPlaceholder({ title, description, icon, children }: EmptyP...

FILE: src/components/common/ErrorBoundary.tsx
  function ErrorBoundary (line 11) | function ErrorBoundary({ children }: { children: ReactNode }) {

FILE: src/components/common/ErrorMessage.tsx
  function ErrorMessage (line 5) | function ErrorMessage() {

FILE: src/components/common/ExternalLink.tsx
  function ExternalLink (line 6) | function ExternalLink({

FILE: src/components/common/Favicon.tsx
  function getHostName (line 4) | function getHostName(url: string) {
  function Favicon (line 9) | function Favicon({ domain, ...props }) {

FILE: src/components/common/FilterLink.tsx
  type FilterLinkProps (line 7) | interface FilterLinkProps extends HTMLAttributes<HTMLDivElement> {
  function FilterLink (line 15) | function FilterLink({ type, value, label, externalUrl, icon }: FilterLin...

FILE: src/components/common/FilterRecord.tsx
  type FilterRecordProps (line 8) | interface FilterRecordProps {
  function FilterRecord (line 21) | function FilterRecord({

FILE: src/components/common/GridRow.tsx
  constant LAYOUTS (line 3) | const LAYOUTS = {
  function GridRow (line 21) | function GridRow(props: {

FILE: src/components/common/LinkButton.tsx
  type LinkButtonProps (line 6) | interface LinkButtonProps extends ButtonProps {
  function LinkButton (line 16) | function LinkButton({

FILE: src/components/common/LoadingPanel.tsx
  type LoadingPanelProps (line 6) | interface LoadingPanelProps extends ColumnProps {
  function LoadingPanel (line 18) | function LoadingPanel({
  function checkEmpty (line 59) | function checkEmpty(data: any) {

FILE: src/components/common/PageBody.tsx
  constant DEFAULT_WIDTH (line 6) | const DEFAULT_WIDTH = '1320px';
  function PageBody (line 8) | function PageBody({

FILE: src/components/common/PageHeader.tsx
  function PageHeader (line 5) | function PageHeader({

FILE: src/components/common/Pager.tsx
  type PagerProps (line 5) | interface PagerProps {
  function Pager (line 13) | function Pager({ page, pageSize, count, onPageChange }: PagerProps) {

FILE: src/components/common/Panel.tsx
  type PanelProps (line 15) | interface PanelProps extends ColumnProps {
  function Panel (line 30) | function Panel({ title, allowFullscreen, style, children, ...props }: Pa...

FILE: src/components/common/SectionHeader.tsx
  function SectionHeader (line 4) | function SectionHeader({

FILE: src/components/common/SideMenu.tsx
  type SideMenuData (line 13) | interface SideMenuData {
  type SideMenuItems (line 20) | interface SideMenuItems {
  type SideMenuProps (line 25) | interface SideMenuProps extends NavMenuProps {
  function SideMenu (line 32) | function SideMenu({

FILE: src/components/common/TypeConfirmationForm.tsx
  function TypeConfirmationForm (line 11) | function TypeConfirmationForm({

FILE: src/components/common/TypeIcon.tsx
  function TypeIcon (line 4) | function TypeIcon({

FILE: src/components/hooks/context/useLink.ts
  function useLink (line 4) | function useLink() {

FILE: src/components/hooks/context/usePixel.ts
  function usePixel (line 4) | function usePixel() {

FILE: src/components/hooks/context/useTeam.ts
  function useTeam (line 4) | function useTeam() {

FILE: src/components/hooks/context/useUser.ts
  function useUser (line 4) | function useUser() {

FILE: src/components/hooks/context/useWebsite.ts
  function useWebsite (line 4) | function useWebsite() {

FILE: src/components/hooks/queries/useActiveUsersQuery.ts
  function useActyiveUsersQuery (line 4) | function useActyiveUsersQuery(websiteId: string, options?: ReactQueryOpt...

FILE: src/components/hooks/queries/useDateRangeQuery.ts
  type DateRange (line 4) | type DateRange = {
  function useDateRangeQuery (line 9) | function useDateRangeQuery(websiteId: string, options?: ReactQueryOption...

FILE: src/components/hooks/queries/useDeleteQuery.ts
  function useDeleteQuery (line 4) | function useDeleteQuery(path: string, params?: Record<string, any>) {

FILE: src/components/hooks/queries/useEventDataEventsQuery.ts
  function useEventDataEventsQuery (line 6) | function useEventDataEventsQuery(websiteId: string, options?: ReactQuery...

FILE: src/components/hooks/queries/useEventDataPropertiesQuery.ts
  function useEventDataPropertiesQuery (line 6) | function useEventDataPropertiesQuery(websiteId: string, options?: ReactQ...

FILE: src/components/hooks/queries/useEventDataQuery.ts
  function useEventDataQuery (line 6) | function useEventDataQuery(websiteId: string, eventId: string, options?:...

FILE: src/components/hooks/queries/useEventDataValuesQuery.ts
  function useEventDataValuesQuery (line 6) | function useEventDataValuesQuery(

FILE: src/components/hooks/queries/useLinkQuery.ts
  function useLinkQuery (line 4) | function useLinkQuery(linkId: string) {

FILE: src/components/hooks/queries/useLinksQuery.ts
  function useLinksQuery (line 6) | function useLinksQuery({ teamId }: { teamId?: string }, options?: ReactQ...

FILE: src/components/hooks/queries/useLoginQuery.ts
  function useLoginQuery (line 6) | function useLoginQuery() {

FILE: src/components/hooks/queries/usePixelQuery.ts
  function usePixelQuery (line 4) | function usePixelQuery(pixelId: string) {

FILE: src/components/hooks/queries/usePixelsQuery.ts
  function usePixelsQuery (line 6) | function usePixelsQuery({ teamId }: { teamId?: string }, options?: React...

FILE: src/components/hooks/queries/useRealtimeQuery.ts
  function useRealtimeQuery (line 5) | function useRealtimeQuery(websiteId: string) {

FILE: src/components/hooks/queries/useReportQuery.ts
  function useReportQuery (line 4) | function useReportQuery(reportId: string) {

FILE: src/components/hooks/queries/useReportsQuery.ts
  function useReportsQuery (line 6) | function useReportsQuery(

FILE: src/components/hooks/queries/useResultQuery.ts
  function useResultQuery (line 6) | function useResultQuery<T = any>(

FILE: src/components/hooks/queries/useSessionActivityQuery.ts
  function useSessionActivityQuery (line 3) | function useSessionActivityQuery(

FILE: src/components/hooks/queries/useSessionDataPropertiesQuery.ts
  function useSessionDataPropertiesQuery (line 6) | function useSessionDataPropertiesQuery(websiteId: string, options?: Reac...

FILE: src/components/hooks/queries/useSessionDataQuery.ts
  function useSessionDataQuery (line 3) | function useSessionDataQuery(websiteId: string, sessionId: string) {

FILE: src/components/hooks/queries/useSessionDataValuesQuery.ts
  function useSessionDataValuesQuery (line 6) | function useSessionDataValuesQuery(

FILE: src/components/hooks/queries/useShareTokenQuery.ts
  function useShareTokenQuery (line 6) | function useShareTokenQuery(shareId: string): {

FILE: src/components/hooks/queries/useTeamMembersQuery.ts
  function useTeamMembersQuery (line 5) | function useTeamMembersQuery(teamId: string) {

FILE: src/components/hooks/queries/useTeamQuery.ts
  function useTeamQuery (line 6) | function useTeamQuery(teamId: string, options?: ReactQueryOptions) {

FILE: src/components/hooks/queries/useTeamWebsitesQuery.ts
  function useTeamWebsitesQuery (line 5) | function useTeamWebsitesQuery(teamId: string) {

FILE: src/components/hooks/queries/useTeamsQuery.ts
  function useTeamsQuery (line 6) | function useTeamsQuery(params?: Record<string, any>, options?: ReactQuer...

FILE: src/components/hooks/queries/useUpdateQuery.ts
  function useUpdateQuery (line 6) | function useUpdateQuery(path: string, params?: Record<string, any>) {

FILE: src/components/hooks/queries/useUserQuery.ts
  function useUserQuery (line 6) | function useUserQuery(userId: string, options?: ReactQueryOptions) {

FILE: src/components/hooks/queries/useUserTeamsQuery.ts
  function useUserTeamsQuery (line 4) | function useUserTeamsQuery(userId: string) {

FILE: src/components/hooks/queries/useUserWebsitesQuery.ts
  function useUserWebsitesQuery (line 6) | function useUserWebsitesQuery(

FILE: src/components/hooks/queries/useUsersQuery.ts
  function useUsersQuery (line 5) | function useUsersQuery() {

FILE: src/components/hooks/queries/useWebsiteCohortQuery.ts
  function useWebsiteCohortQuery (line 6) | function useWebsiteCohortQuery(

FILE: src/components/hooks/queries/useWebsiteCohortsQuery.ts
  function useWebsiteCohortsQuery (line 7) | function useWebsiteCohortsQuery(

FILE: src/components/hooks/queries/useWebsiteEventsQuery.ts
  constant EVENT_TYPES (line 7) | const EVENT_TYPES = {
  function useWebsiteEventsQuery (line 12) | function useWebsiteEventsQuery(

FILE: src/components/hooks/queries/useWebsiteEventsSeriesQuery.ts
  function useWebsiteEventsSeriesQuery (line 6) | function useWebsiteEventsSeriesQuery(websiteId: string, options?: ReactQ...

FILE: src/components/hooks/queries/useWebsiteExpandedMetricsQuery.ts
  type WebsiteExpandedMetricsData (line 7) | type WebsiteExpandedMetricsData = {
  function useWebsiteExpandedMetricsQuery (line 16) | function useWebsiteExpandedMetricsQuery(

FILE: src/components/hooks/queries/useWebsiteMetricsQuery.ts
  type WebsiteMetricsData (line 7) | type WebsiteMetricsData = {
  function useWebsiteMetricsQuery (line 12) | function useWebsiteMetricsQuery(

FILE: src/components/hooks/queries/useWebsitePageviewsQuery.ts
  type WebsitePageviewsData (line 6) | interface WebsitePageviewsData {
  function useWebsitePageviewsQuery (line 11) | function useWebsitePageviewsQuery(

FILE: src/components/hooks/queries/useWebsiteQuery.ts
  function useWebsiteQuery (line 6) | function useWebsiteQuery(websiteId: string, options?: ReactQueryOptions) {

FILE: src/components/hooks/queries/useWebsiteSegmentQuery.ts
  function useWebsiteSegmentQuery (line 6) | function useWebsiteSegmentQuery(

FILE: src/components/hooks/queries/useWebsiteSegmentsQuery.ts
  function useWebsiteSegmentsQuery (line 7) | function useWebsiteSegmentsQuery(

FILE: src/components/hooks/queries/useWebsiteSessionQuery.ts
  function useWebsiteSessionQuery (line 3) | function useWebsiteSessionQuery(websiteId: string, sessionId: string) {

FILE: src/components/hooks/queries/useWebsiteSessionStatsQuery.ts
  function useWebsiteSessionStatsQuery (line 5) | function useWebsiteSessionStatsQuery(websiteId: string, options?: Record...

FILE: src/components/hooks/queries/useWebsiteSessionsQuery.ts
  function useWebsiteSessionsQuery (line 7) | function useWebsiteSessionsQuery(

FILE: src/components/hooks/queries/useWebsiteStatsQuery.ts
  type WebsiteStatsData (line 6) | interface WebsiteStatsData {
  function useWebsiteStatsQuery (line 21) | function useWebsiteStatsQuery(

FILE: src/components/hooks/queries/useWebsiteValuesQuery.ts
  function useWebsiteValuesQuery (line 6) | function useWebsiteValuesQuery({

FILE: src/components/hooks/queries/useWebsitesQuery.ts
  function useWebsitesQuery (line 6) | function useWebsitesQuery(params?: Record<string, any>, options?: ReactQ...

FILE: src/components/hooks/queries/useWeeklyTrafficQuery.ts
  function useWeeklyTrafficQuery (line 6) | function useWeeklyTrafficQuery(websiteId: string, params?: Record<string...

FILE: src/components/hooks/useApi.ts
  function handleResponse (line 10) | async function handleResponse(res: FetchResponse): Promise<any> {
  function useApi (line 19) | function useApi() {

FILE: src/components/hooks/useConfig.ts
  type Config (line 5) | type Config = {
  function useConfig (line 16) | function useConfig(): Config {

FILE: src/components/hooks/useCountryNames.ts
  function useCountryNames (line 9) | function useCountryNames(locale: string) {

FILE: src/components/hooks/useDateParameters.ts
  function useDateParameters (line 4) | function useDateParameters() {

FILE: src/components/hooks/useDateRange.ts
  function useDateRange (line 8) | function useDateRange(options: { ignoreOffset?: boolean; timezone?: stri...

FILE: src/components/hooks/useDocumentClick.ts
  function useDocumentClick (line 3) | function useDocumentClick(handler: (event: MouseEvent) => any) {

FILE: src/components/hooks/useEscapeKey.ts
  function useEscapeKey (line 3) | function useEscapeKey(handler: (event: KeyboardEvent) => void) {

FILE: src/components/hooks/useFields.ts
  function useFields (line 3) | function useFields() {

FILE: src/components/hooks/useFilterParameters.ts
  function useFilterParameters (line 4) | function useFilterParameters() {

FILE: src/components/hooks/useFilters.ts
  function useFilters (line 7) | function useFilters() {

FILE: src/components/hooks/useForceUpdate.ts
  function useForceUpdate (line 3) | function useForceUpdate() {

FILE: src/components/hooks/useFormat.ts
  function useFormat (line 8) | function useFormat() {

FILE: src/components/hooks/useLanguageNames.ts
  function useLanguageNames (line 9) | function useLanguageNames(locale) {

FILE: src/components/hooks/useLocale.ts
  function useLocale (line 16) | function useLocale() {

FILE: src/components/hooks/useMessages.ts
  type FormatMessage (line 5) | type FormatMessage = (
  type UseMessages (line 11) | interface UseMessages {
  function useMessages (line 20) | function useMessages(): UseMessages {

FILE: src/components/hooks/useMobile.ts
  function useMobile (line 3) | function useMobile() {

FILE: src/components/hooks/useModified.ts
  function touch (line 5) | function touch(key: string) {
  function useModified (line 9) | function useModified(key?: string) {

FILE: src/components/hooks/useNavigation.ts
  function useNavigation (line 5) | function useNavigation() {

FILE: src/components/hooks/usePageParameters.ts
  function usePageParameters (line 4) | function usePageParameters() {

FILE: src/components/hooks/usePagedQuery.ts
  function usePagedQuery (line 6) | function usePagedQuery<TData = any, TError = Error>({

FILE: src/components/hooks/useRegionNames.ts
  function useRegionNames (line 4) | function useRegionNames(locale: string) {

FILE: src/components/hooks/useSlug.ts
  function useSlug (line 4) | function useSlug(type: 'link' | 'pixel') {

FILE: src/components/hooks/useSticky.ts
  function useSticky (line 3) | function useSticky({ enabled = true, threshold = 1 }) {

FILE: src/components/hooks/useTimezone.ts
  function useTimezone (line 10) | function useTimezone() {

FILE: src/components/input/ActionSelect.tsx
  type ActionSelectProps (line 4) | interface ActionSelectProps {
  function ActionSelect (line 9) | function ActionSelect({ value = 'path', onChange }: ActionSelectProps) {

FILE: src/components/input/CurrencySelect.tsx
  function CurrencySelect (line 6) | function CurrencySelect({ value, onChange }) {

FILE: src/components/input/DateFilter.tsx
  type DateFilterProps (line 9) | interface DateFilterProps extends SelectProps {
  function DateFilter (line 17) | function DateFilter({

FILE: src/components/input/DialogButton.tsx
  type DialogButtonProps (line 13) | interface DialogButtonProps extends Omit<ButtonProps, 'children'> {
  function DialogButton (line 24) | function DialogButton({

FILE: src/components/input/DownloadButton.tsx
  function DownloadButton (line 6) | function DownloadButton({
  function downloadCsv (line 32) | function downloadCsv(filename: string, data: any) {

FILE: src/components/input/ExportButton.tsx
  function ExportButton (line 9) | function ExportButton({ websiteId }: { websiteId: string }) {
  function loadZip (line 49) | async function loadZip(zip: string) {

FILE: src/components/input/FieldFilters.tsx
  type FieldFiltersProps (line 21) | interface FieldFiltersProps {
  function FieldFilters (line 28) | function FieldFilters({ websiteId, value, exclude = [], onChange }: Fiel...

FILE: src/components/input/FilterBar.tsx
  function FilterBar (line 23) | function FilterBar({ websiteId }: { websiteId: string }) {

FILE: src/components/input/FilterButtons.tsx
  type FilterButtonsProps (line 4) | interface FilterButtonsProps {
  function FilterButtons (line 10) | function FilterButtons({ items, value, onChange }: FilterButtonsProps) {

FILE: src/components/input/FilterEditForm.tsx
  type FilterEditFormProps (line 7) | interface FilterEditFormProps {
  function FilterEditForm (line 13) | function FilterEditForm({ websiteId, onChange, onClose }: FilterEditForm...

FILE: src/components/input/LanguageButton.tsx
  function LanguageButton (line 6) | function LanguageButton() {

FILE: src/components/input/LookupField.tsx
  type LookupFieldProps (line 7) | interface LookupFieldProps extends ComboBoxProps {
  function LookupField (line 14) | function LookupField({ websiteId, type, value, onChange, ...props }: Loo...

FILE: src/components/input/MenuButton.tsx
  function MenuButton (line 5) | function MenuButton({

FILE: src/components/input/MobileMenuButton.tsx
  function MobileMenuButton (line 4) | function MobileMenuButton(props: DialogProps) {

FILE: src/components/input/MonthFilter.tsx
  function MonthFilter (line 5) | function MonthFilter() {

FILE: src/components/input/MonthSelect.tsx
  function MonthSelect (line 5) | function MonthSelect({ date = new Date(), onChange }) {

FILE: src/components/input/NavButton.tsx
  type TeamsButtonProps (line 40) | interface TeamsButtonProps {
  function NavButton (line 45) | function NavButton({ showText = true }: TeamsButtonProps) {

FILE: src/components/input/PanelButton.tsx
  function PanelButton (line 5) | function PanelButton(props: ButtonProps) {

FILE: src/components/input/PreferencesButton.tsx
  function PreferencesButton (line 8) | function PreferencesButton() {

FILE: src/components/input/ProfileButton.tsx
  function ProfileButton (line 17) | function ProfileButton() {

FILE: src/components/input/RefreshButton.tsx
  function RefreshButton (line 6) | function RefreshButton({

FILE: src/components/input/ReportEditButton.tsx
  function ReportEditButton (line 18) | function ReportEditButton({

FILE: src/components/input/SegmentFilters.tsx
  type SegmentFiltersProps (line 7) | interface SegmentFiltersProps {
  function SegmentFilters (line 14) | function SegmentFilters({

FILE: src/components/input/SegmentSaveButton.tsx
  function SegmentSaveButton (line 6) | function SegmentSaveButton({ websiteId }: { websiteId: string }) {

FILE: src/components/input/SettingsButton.tsx
  function SettingsButton (line 24) | function SettingsButton() {

FILE: src/components/input/WebsiteDateFilter.tsx
  type WebsiteDateFilterProps (line 9) | interface WebsiteDateFilterProps {
  function WebsiteDateFilter (line 17) | function WebsiteDateFilter({

FILE: src/components/input/WebsiteFilterButton.tsx
  function WebsiteFilterButton (line 7) | function WebsiteFilterButton({

FILE: src/components/input/WebsiteSelect.tsx
  function WebsiteSelect (line 11) | function WebsiteSelect({

FILE: src/components/metrics/ActiveUsers.tsx
  function ActiveUsers (line 6) | function ActiveUsers({

FILE: src/components/metrics/ChangeLabel.tsx
  constant STYLES (line 5) | const STYLES = {
  function ChangeLabel (line 20) | function ChangeLabel({

FILE: src/components/metrics/DatePickerForm.tsx
  constant FILTER_DAY (line 6) | const FILTER_DAY = 'filter-day';
  constant FILTER_RANGE (line 7) | const FILTER_RANGE = 'filter-range';
  function DatePickerForm (line 9) | function DatePickerForm({

FILE: src/components/metrics/EventData.tsx
  function EventData (line 5) | function EventData({ websiteId, eventId }: { websiteId: string; eventId:...

FILE: src/components/metrics/EventsChart.tsx
  type EventsChartProps (line 15) | interface EventsChartProps extends BarChartProps {
  function EventsChart (line 20) | function EventsChart({ websiteId, focusLabel }: EventsChartProps) {

FILE: src/components/metrics/Legend.tsx
  function Legend (line 5) | function Legend({

FILE: src/components/metrics/ListTable.tsx
  constant ITEM_SIZE (line 10) | const ITEM_SIZE = 30;
  type ListData (line 12) | interface ListData {
  type ListTableProps (line 18) | interface ListTableProps {
  function ListTable (line 32) | function ListTable({

FILE: src/components/metrics/MetricCard.tsx
  type MetricCardProps (line 7) | interface MetricCardProps {

FILE: src/components/metrics/MetricLabel.tsx
  type MetricLabelProps (line 14) | interface MetricLabelProps {
  function MetricLabel (line 20) | function MetricLabel({ type, data }: MetricLabelProps) {

FILE: src/components/metrics/MetricsBar.tsx
  type MetricsBarProps (line 4) | interface MetricsBarProps extends GridProps {
  function MetricsBar (line 8) | function MetricsBar({ children, ...props }: MetricsBarProps) {

FILE: src/components/metrics/MetricsExpandedTable.tsx
  type MetricsExpandedTableProps (line 11) | interface MetricsExpandedTableProps {
  function MetricsExpandedTable (line 25) | function MetricsExpandedTable({

FILE: src/components/metrics/MetricsTable.tsx
  type MetricsTableProps (line 11) | interface MetricsTableProps extends ListTableProps {
  function MetricsTable (line 22) | function MetricsTable({

FILE: src/components/metrics/PageviewsChart.tsx
  type PageviewsChartProps (line 9) | interface PageviewsChartProps extends BarChartProps {
  function PageviewsChart (line 21) | function PageviewsChart({ data, unit, minDate, maxDate, ...props }: Page...

FILE: src/components/metrics/RealtimeChart.tsx
  type RealtimeChartProps (line 8) | interface RealtimeChartProps {
  function RealtimeChart (line 14) | function RealtimeChart({ data, unit, ...props }: RealtimeChartProps) {

FILE: src/components/metrics/WeeklyTraffic.tsx
  function WeeklyTraffic (line 7) | function WeeklyTraffic({ websiteId }: { websiteId: string }) {

FILE: src/components/metrics/WorldMap.tsx
  type WorldMapProps (line 16) | interface WorldMapProps extends ColumnProps {
  function WorldMap (line 21) | function WorldMap({ websiteId, data, ...props }: WorldMapProps) {

FILE: src/lib/__tests__/detect.test.ts
  constant BAD_IP (line 4) | const BAD_IP = '127.127.127.127';

FILE: src/lib/auth.ts
  function getBearerToken (line 12) | function getBearerToken(request: Request) {
  function checkAuth (line 18) | async function checkAuth(request: Request) {
  function saveAuth (line 55) | async function saveAuth(data: any, expire = 0) {
  function hasPermission (line 69) | async function hasPermission(role: string, permission: string | string[]) {
  function parseShareToken (line 73) | function parseShareToken(request: Request) {

FILE: src/lib/charts.ts
  function renderNumberLabels (line 4) | function renderNumberLabels(label: string) {
  function renderDateLabels (line 8) | function renderDateLabels(unit: string, locale: string) {

FILE: src/lib/clickhouse.ts
  constant CLICKHOUSE_DATE_FORMATS (line 9) | const CLICKHOUSE_DATE_FORMATS = {
  function getClient (line 24) | function getClient() {
  function getUTCString (line 50) | function getUTCString(date?: Date | string | number) {
  function getDateStringSQL (line 54) | function getDateStringSQL(data: any, unit: string = 'utc', timezone?: st...
  function getDateSQL (line 62) | function getDateSQL(field: string, unit: string, timezone?: string) {
  function getSearchSQL (line 69) | function getSearchSQL(column: string, param: string = 'search'): string {
  function mapFilter (line 73) | function mapFilter(column: string, operator: string, name: string, type:...
  function getFilterQuery (line 90) | function getFilterQuery(filters: Record<string, any>, options: QueryOpti...
  function getCohortQuery (line 116) | function getCohortQuery(filters: Record<string, any>) {
  function getDateQuery (line 134) | function getDateQuery(filters: Record<string, any>) {
  function getQueryParams (line 154) | function getQueryParams(filters: Record<string, any>) {
  function parseFilters (line 167) | function parseFilters(filters: Record<string, any>, options?: QueryOptio...
  function pagedRawQuery (line 180) | async function pagedRawQuery(
  function rawQuery (line 207) | async function rawQuery<T = unknown>(
  function insert (line 231) | async function insert(table: string, values: any[]) {
  function findUnique (line 237) | async function findUnique(data: any[]) {
  function findFirst (line 245) | async function findFirst(data: any[]) {
  function connect (line 249) | async function connect() {

FILE: src/lib/client.ts
  function getClientAuthToken (line 4) | function getClientAuthToken() {
  function setClientAuthToken (line 8) | function setClientAuthToken(token: string) {
  function removeClientAuthToken (line 12) | function removeClientAuthToken() {

FILE: src/lib/colors.ts
  function hex6 (line 4) | function hex6(str: string) {
  function clamp (line 18) | function clamp(num: number, min: number, max: number) {
  function hex2RGB (line 22) | function hex2RGB(color: string, min: number = 0, max: number = 255) {
  function rgb2Hex (line 37) | function rgb2Hex(r: number, g: number, b: number, prefix = '') {
  function getPastel (line 41) | function getPastel(color: string, factor: number = 0.5, prefix = '') {
  function getColor (line 51) | function getColor(seed: string, min: number = 0, max: number = 255) {
  function getThemeColors (line 58) | function getThemeColors(theme: string) {

FILE: src/lib/constants.ts
  constant CURRENT_VERSION (line 1) | const CURRENT_VERSION = process.env.currentVersion;
  constant AUTH_TOKEN (line 2) | const AUTH_TOKEN = 'umami.auth';
  constant LOCALE_CONFIG (line 3) | const LOCALE_CONFIG = 'umami.locale';
  constant TIMEZONE_CONFIG (line 4) | const TIMEZONE_CONFIG = 'umami.timezone';
  constant DATE_RANGE_CONFIG (line 5) | const DATE_RANGE_CONFIG = 'umami.date-range';
  constant THEME_CONFIG (line 6) | const THEME_CONFIG = 'umami.theme';
  constant DASHBOARD_CONFIG (line 7) | const DASHBOARD_CONFIG = 'umami.dashboard';
  constant LAST_TEAM_CONFIG (line 8) | const LAST_TEAM_CONFIG = 'umami.last-team';
  constant VERSION_CHECK (line 9) | const VERSION_CHECK = 'umami.version-check';
  constant SHARE_TOKEN_HEADER (line 10) | const SHARE_TOKEN_HEADER = 'x-umami-share-token';
  constant HOMEPAGE_URL (line 11) | const HOMEPAGE_URL = 'https://umami.is';
  constant DOCS_URL (line 12) | const DOCS_URL = 'https://umami.is/docs';
  constant REPO_URL (line 13) | const REPO_URL = 'https://github.com/umami-software/umami';
  constant UPDATES_URL (line 14) | const UPDATES_URL = 'https://api.umami.is/v1/updates';
  constant TELEMETRY_PIXEL (line 15) | const TELEMETRY_PIXEL = 'https://i.umami.is/a.png';
  constant FAVICON_URL (line 16) | const FAVICON_URL = 'https://icons.duckduckgo.com/ip3/{{domain}}.ico';
  constant LINKS_URL (line 17) | const LINKS_URL = `${globalThis?.location?.origin}/q`;
  constant PIXELS_URL (line 18) | const PIXELS_URL = `${globalThis?.location?.origin}/p`;
  constant DEFAULT_LOCALE (line 20) | const DEFAULT_LOCALE = 'en-US';
  constant DEFAULT_THEME (line 21) | const DEFAULT_THEME = 'light';
  constant DEFAULT_ANIMATION_DURATION (line 22) | const DEFAULT_ANIMATION_DURATION = 300;
  constant DEFAULT_DATE_RANGE_VALUE (line 23) | const DEFAULT_DATE_RANGE_VALUE = '24hour';
  constant DEFAULT_WEBSITE_LIMIT (line 24) | const DEFAULT_WEBSITE_LIMIT = 10;
  constant DEFAULT_RESET_DATE (line 25) | const DEFAULT_RESET_DATE = '2000-01-01';
  constant DEFAULT_PAGE_SIZE (line 26) | const DEFAULT_PAGE_SIZE = 20;
  constant DEFAULT_DATE_COMPARE (line 27) | const DEFAULT_DATE_COMPARE = 'prev';
  constant REALTIME_RANGE (line 29) | const REALTIME_RANGE = 30;
  constant REALTIME_INTERVAL (line 30) | const REALTIME_INTERVAL = 10000;
  constant UNIT_TYPES (line 32) | const UNIT_TYPES = ['year', 'month', 'hour', 'day', 'minute'];
  constant EVENT_COLUMNS (line 34) | const EVENT_COLUMNS = [
  constant SESSION_COLUMNS (line 47) | const SESSION_COLUMNS = [
  constant SEGMENT_TYPES (line 58) | const SEGMENT_TYPES = {
  constant FILTER_COLUMNS (line 63) | const FILTER_COLUMNS = {
  constant COLLECTION_TYPE (line 84) | const COLLECTION_TYPE = {
  constant EVENT_TYPE (line 89) | const EVENT_TYPE = {
  constant DATA_TYPE (line 96) | const DATA_TYPE = {
  constant OPERATORS (line 104) | const OPERATORS = {
  constant DATA_TYPES (line 121) | const DATA_TYPES = {
  constant ROLES (line 129) | const ROLES = {
  constant PERMISSIONS (line 139) | const PERMISSIONS = {
  constant ROLE_PERMISSIONS (line 151) | const ROLE_PERMISSIONS = {
  constant THEME_COLORS (line 184) | const THEME_COLORS = {
  constant CHART_COLORS (line 199) | const CHART_COLORS = [
  constant DOMAIN_REGEX (line 214) | const DOMAIN_REGEX =
  constant SHARE_ID_REGEX (line 216) | const SHARE_ID_REGEX = /^[a-zA-Z0-9]{8,50}$/;
  constant DATETIME_REGEX (line 217) | const DATETIME_REGEX =
  constant URL_LENGTH (line 220) | const URL_LENGTH = 500;
  constant PAGE_TITLE_LENGTH (line 221) | const PAGE_TITLE_LENGTH = 500;
  constant EVENT_NAME_LENGTH (line 222) | const EVENT_NAME_LENGTH = 50;
  constant UTM_PARAMS (line 224) | const UTM_PARAMS = ['utm_campaign', 'utm_content', 'utm_medium', 'utm_so...
  constant OS_NAMES (line 226) | const OS_NAMES = {
  constant BROWSERS (line 234) | const BROWSERS = {
  constant SOCIAL_DOMAINS (line 265) | const SOCIAL_DOMAINS = [
  constant SEARCH_DOMAINS (line 283) | const SEARCH_DOMAINS = [
  constant SHOPPING_DOMAINS (line 296) | const SHOPPING_DOMAINS = [
  constant EMAIL_DOMAINS (line 308) | const EMAIL_DOMAINS = [
  constant VIDEO_DOMAINS (line 317) | const VIDEO_DOMAINS = ['twitch.', 'youtube.'];
  constant PAID_AD_PARAMS (line 319) | const PAID_AD_PARAMS = [
  constant GROUPED_DOMAINS (line 340) | const GROUPED_DOMAINS = [
  constant MAP_FILE (line 360) | const MAP_FILE = '/datamaps.world.json';
  constant ISO_COUNTRIES (line 362) | const ISO_COUNTRIES = {
  constant CURRENCIES (line 610) | const CURRENCIES = [
  constant TIMEZONE_LEGACY (line 663) | const TIMEZONE_LEGACY: Record<string, string> = {

FILE: src/lib/crypto.ts
  constant ALGORITHM (line 4) | const ALGORITHM = 'aes-256-gcm';
  constant IV_LENGTH (line 5) | const IV_LENGTH = 16;
  constant SALT_LENGTH (line 6) | const SALT_LENGTH = 64;
  constant TAG_LENGTH (line 7) | const TAG_LENGTH = 16;
  constant TAG_POSITION (line 8) | const TAG_POSITION = SALT_LENGTH + IV_LENGTH;
  constant ENC_POSITION (line 9) | const ENC_POSITION = TAG_POSITION + TAG_LENGTH;
  constant HASH_ALGO (line 11) | const HASH_ALGO = 'sha512';
  constant HASH_ENCODING (line 12) | const HASH_ENCODING = 'hex';
  function encrypt (line 17) | function encrypt(value: any, secret: any) {
  function decrypt (line 31) | function decrypt(value: any, secret: any) {
  function hash (line 47) | function hash(...args: string[]) {
  function md5 (line 51) | function md5(...args: string[]) {
  function secret (line 55) | function secret() {
  function uuid (line 59) | function uuid(...args: any) {

FILE: src/lib/data.ts
  function flattenJSON (line 4) | function flattenJSON(
  function isValidDateValue (line 27) | function isValidDateValue(value: string) {
  function getDataType (line 31) | function getDataType(value: any): string {
  function getStringValue (line 41) | function getStringValue(value: string, dataType: number) {
  function createKey (line 53) | function createKey(key: string, value: string, acc: { keyValues: any[]; ...
  function getKeyName (line 84) | function getKeyName(key: string, parentKey: string) {
  function objectToArray (line 92) | function objectToArray(obj: object) {

FILE: src/lib/date.ts
  constant TIME_UNIT (line 44) | const TIME_UNIT = {
  constant DATE_FUNCTIONS (line 53) | const DATE_FUNCTIONS = {
  constant DATE_FORMATS (line 98) | const DATE_FORMATS = {
  constant TIMEZONE_MAPPINGS (line 107) | const TIMEZONE_MAPPINGS: Record<string, string> = {
  function normalizeTimezone (line 111) | function normalizeTimezone(timezone: string): string {
  function isValidTimezone (line 115) | function isValidTimezone(timezone: string) {
  function getTimezone (line 125) | function getTimezone() {
  function parseDateValue (line 129) | function parseDateValue(value: string) {
  function parseDateRange (line 139) | function parseDateRange(value: string, locale = 'en-US', timezone?: stri...
  function getOffsetDateRange (line 216) | function getOffsetDateRange(dateRange: DateRange, offset: number) {
  function getAllowedUnits (line 268) | function getAllowedUnits(startDate: Date, endDate: Date) {
  function getMinimumUnit (line 276) | function getMinimumUnit(startDate: number | Date, endDate: number | Date) {
  function maxDate (line 290) | function maxDate(...args: Date[]) {
  function minDate (line 294) | function minDate(...args: any[]) {
  function getCompareDate (line 298) | function getCompareDate(compare: string, startDate: Date, endDate: Date) {
  function getDayOfWeekAsDate (line 312) | function getDayOfWeekAsDate(dayOfWeek: number) {
  function formatDate (line 325) | function formatDate(
  function generateTimeSeries (line 335) | function generateTimeSeries(
  function getDateRangeValue (line 365) | function getDateRangeValue(startDate: Date, endDate: Date) {
  function getMonthDateRangeValue (line 369) | function getMonthDateRangeValue(date: Date) {
  function isInvalidDate (line 373) | function isInvalidDate(date: any) {

FILE: src/lib/db.ts
  constant PRISMA (line 1) | const PRISMA = 'prisma';
  constant POSTGRESQL (line 2) | const POSTGRESQL = 'postgresql';
  constant CLICKHOUSE (line 3) | const CLICKHOUSE = 'clickhouse';
  constant KAFKA (line 4) | const KAFKA = 'kafka';
  constant KAFKA_PRODUCER (line 5) | const KAFKA_PRODUCER = 'kafka-producer';
  function getDatabaseType (line 12) | function getDatabaseType(url = process.env.DATABASE_URL) {
  function runQuery (line 22) | async function runQuery(queries: any) {
  function notImplemented (line 38) | function notImplemented() {

FILE: src/lib/detect.ts
  constant MAXMIND (line 10) | const MAXMIND = 'maxmind';
  constant PROVIDER_HEADERS (line 12) | const PROVIDER_HEADERS = [
  function getDevice (line 33) | function getDevice(userAgent: string, screen: string = '') {
  function getRegionCode (line 47) | function getRegionCode(country: string, region: string) {
  function decodeHeader (line 55) | function decodeHeader(s: string | undefined | null): string | undefined ...
  function getLocation (line 63) | async function getLocation(ip: string = '', headers: Headers, hasPayload...
  function getClientInfo (line 110) | async function getClientInfo(request: Request, payload: Record<string, a...
  function hasBlockedIp (line 124) | function hasBlockedIp(clientIp: string) {

FILE: src/lib/fetch.ts
  type ErrorResponse (line 3) | interface ErrorResponse {
  type FetchResponse (line 11) | interface FetchResponse {
  function request (line 18) | async function request(
  function httpGet (line 44) | async function httpGet(path: string, params: object = {}, headers: objec...
  function httpDelete (line 48) | async function httpDelete(path: string, params: object = {}, headers: ob...
  function httpPost (line 52) | async function httpPost(path: string, params: object = {}, headers: obje...
  function httpPut (line 56) | async function httpPut(path: string, params: object = {}, headers: objec...

FILE: src/lib/format.ts
  function parseTime (line 1) | function parseTime(val: number) {
  function formatTime (line 17) | function formatTime(val: number) {
  function formatShortTime (line 26) | function formatShortTime(val: number, formats = ['m', 's'], space = '') {
  function formatNumber (line 43) | function formatNumber(n: string | number) {
  function formatLongNumber (line 47) | function formatLongNumber(value: number) {
  function stringToColor (line 69) | function stringToColor(str: string) {
  function formatCurrency (line 85) | function formatCurrency(value: number, currency: string, locale = 'en-US...
  function formatLongCurrency (line 104) | function formatLongCurrency(value: number, currency: string, locale = 'e...

FILE: src/lib/generate.ts
  function random (line 6) | function random(min: number, max: number) {
  function getRandomChars (line 10) | function getRandomChars(

FILE: src/lib/ip.ts
  constant IP_ADDRESS_HEADERS (line 1) | const IP_ADDRESS_HEADERS = [
  function getIpAddress (line 16) | function getIpAddress(headers: Headers) {
  function stripPort (line 44) | function stripPort(ip: string) {

FILE: src/lib/jwt.ts
  function createToken (line 4) | function createToken(payload: any, secret: any, options?: any) {
  function parseToken (line 8) | function parseToken(token: string, secret: any) {
  function createSecureToken (line 16) | function createSecureToken(payload: any, secret: any, options?: any) {
  function parseSecureToken (line 20) | function parseSecureToken(token: string, secret: any) {
  function parseAuthToken (line 28) | async function parseAuthToken(req: Request, secret: string) {

FILE: src/lib/kafka.ts
  constant CONNECT_TIMEOUT (line 8) | const CONNECT_TIMEOUT = 5000;
  constant SEND_TIMEOUT (line 9) | const SEND_TIMEOUT = 3000;
  constant ACKS (line 10) | const ACKS = 1;
  function getClient (line 16) | function getClient() {
  function getProducer (line 53) | async function getProducer(): Promise<Producer> {
  function sendMessage (line 66) | async function sendMessage(
  function connect (line 93) | async function connect(): Promise<Kafka> {

FILE: src/lib/lang.ts
  function getDateLocale (line 105) | function getDateLocale(locale: string) {
  function getTextDirection (line 109) | function getTextDirection(locale: string) {

FILE: src/lib/load.ts
  function fetchWebsite (line 6) | async function fetchWebsite(websiteId: string): Promise<Website> {
  function fetchSession (line 22) | async function fetchSession(websiteId: string, sessionId: string): Promi...

FILE: src/lib/params.ts
  function parseFilterValue (line 4) | function parseFilterValue(param: any) {
  function isEqualsOperator (line 18) | function isEqualsOperator(operator: any) {
  function isSearchOperator (line 22) | function isSearchOperator(operator: any) {
  function filtersObjectToArray (line 26) | function filtersObjectToArray(filters: QueryFilters, options: QueryOptio...
  function filtersArrayToObject (line 54) | function filtersArrayToObject(filters: Filter[]) {

FILE: src/lib/password.ts
  constant SALT_ROUNDS (line 3) | const SALT_ROUNDS = 10;
  function hashPassword (line 5) | function hashPassword(password: string, rounds = SALT_ROUNDS) {
  function checkPassword (line 9) | function checkPassword(password: string, passwordHash: string) {

FILE: src/lib/prisma.ts
  constant PRISMA (line 11) | const PRISMA = 'prisma';
  constant PRISMA_LOG_OPTIONS (line 13) | const PRISMA_LOG_OPTIONS = {
  constant DATE_FORMATS (line 22) | const DATE_FORMATS = {
  constant DATE_FORMATS_UTC (line 30) | const DATE_FORMATS_UTC = {
  function getAddIntervalQuery (line 38) | function getAddIntervalQuery(field: string, interval: string): string {
  function getDayDiffQuery (line 42) | function getDayDiffQuery(field1: string, field2: string): string {
  function getCastColumnQuery (line 46) | function getCastColumnQuery(field: string, type: string): string {
  function getDateSQL (line 50) | function getDateSQL(field: string, unit: string, timezone?: string): str...
  function getDateWeeklySQL (line 58) | function getDateWeeklySQL(field: string, timezone?: string) {
  function getTimestampSQL (line 62) | function getTimestampSQL(field: string) {
  function getTimestampDiffSQL (line 66) | function getTimestampDiffSQL(field1: string, field2: string): string {
  function getSearchSQL (line 70) | function getSearchSQL(column: string, param: string = 'search'): string {
  function mapFilter (line 74) | function mapFilter(column: string, operator: string, name: string, type:...
  function getFilterQuery (line 91) | function getFilterQuery(filters: Record<string, any>, options: QueryOpti...
  function getCohortQuery (line 118) | function getCohortQuery(filters: QueryFilters = {}) {
  function getDateQuery (line 138) | function getDateQuery(filters: Record<string, any>) {
  function getQueryParams (line 152) | function getQueryParams(filters: Record<string, any>) {
  function parseFilters (line 165) | function parseFilters(filters: Record<string, any>, options?: QueryOptio...
  function rawQuery (line 186) | async function rawQuery(sql: string, data: Record<string, any>, name?: s...
  function pagedQuery (line 216) | async function pagedQuery<T>(model: string, criteria: T, filters?: Query...
  function pagedRawQuery (line 239) | async function pagedRawQuery(
  function getSearchParameters (line 266) | function getSearchParameters(query: string, filters: Record<string, any>...
  function transaction (line 292) | function transaction(input: any, options?: any) {
  function getSchema (line 296) | function getSchema() {
  function getClient (line 302) | function getClient() {

FILE: src/lib/react.ts
  function getFragmentChildren (line 11) | function getFragmentChildren(children: ReactNode) {
  function isValidChild (line 17) | function isValidChild(child: ReactElement, types: FC | FC[]) {
  function mapChildren (line 24) | function mapChildren(
  function cloneChildren (line 36) | function cloneChildren(
  function renderChildren (line 62) | function renderChildren(
  function countChildren (line 75) | function countChildren(children: ReactNode): number {

FILE: src/lib/redis.ts
  constant REDIS (line 3) | const REDIS = 'redis';
  function getClient (line 6) | function getClient() {

FILE: src/lib/request.ts
  function parseRequest (line 11) | async function parseRequest(
  function getJsonBody (line 46) | async function getJsonBody(request: Request) {
  function getRequestDateRange (line 54) | function getRequestDateRange(query: Record<string, string>) {
  function getRequestFilters (line 70) | function getRequestFilters(query: Record<string, any>) {
  function setWebsiteDate (line 83) | async function setWebsiteDate(websiteId: string, data: Record<string, an...
  function getQueryFilters (line 93) | async function getQueryFilters(

FILE: src/lib/response.ts
  function ok (line 1) | function ok() {
  function json (line 5) | function json(data: Record<string, any> = {}) {
  function badRequest (line 9) | function badRequest(error?: Record<string, any>) {
  function unauthorized (line 18) | function unauthorized(error?: Record<string, any>) {
  function forbidden (line 32) | function forbidden(error?: Record<string, any>) {
  function notFound (line 39) | function notFound(error?: Record<string, any>) {
  function serverError (line 46) | function serverError(error?: Record<string, any>) {

FILE: src/lib/storage.ts
  function setItem (line 1) | function setItem(key: string, data: any, session?: boolean) {
  function getItem (line 7) | function getItem(key: string, session?: boolean): any {
  function removeItem (line 21) | function removeItem(key: string, session?: boolean) {

FILE: src/lib/types.ts
  type ObjectValues (line 5) | type ObjectValues<T> = T[keyof T];
  type ReactQueryOptions (line 7) | type ReactQueryOptions<T = any> = Omit<UseQueryOptions<T, Error, T>, 'qu...
  type TimeUnit (line 9) | type TimeUnit = ObjectValues<typeof TIME_UNIT>;
  type Role (line 10) | type Role = ObjectValues<typeof ROLES>;
  type DynamicDataType (line 11) | type DynamicDataType = ObjectValues<typeof DATA_TYPE>;
  type Operator (line 12) | type Operator = (typeof OPERATORS)[keyof typeof OPERATORS];
  type Auth (line 14) | interface Auth {
  type Filter (line 26) | interface Filter {
  type DateRange (line 35) | interface DateRange {
  type DynamicData (line 44) | interface DynamicData {
  type QueryOptions (line 48) | interface QueryOptions {
  type QueryFilters (line 56) | interface QueryFilters
  type DateParams (line 65) | interface DateParams {
  type FilterParams (line 73) | interface FilterParams {
  type SortParams (line 95) | interface SortParams {
  type PageParams (line 100) | interface PageParams {
  type SegmentParams (line 105) | interface SegmentParams {
  type PageResult (line 110) | interface PageResult<T> {
  type RealtimeData (line 120) | interface RealtimeData {
  type ApiError (line 140) | interface ApiError extends Error {

FILE: src/lib/url.ts
  function getQueryString (line 1) | function getQueryString(params: object = {}): string {
  function buildPath (line 13) | function buildPath(path: string, params: object = {}): string {
  function safeDecodeURI (line 18) | function safeDecodeURI(s: string | undefined | null): string | undefined...
  function safeDecodeURIComponent (line 30) | function safeDecodeURIComponent(s: string | undefined | null): string | ...
  function isValidUrl (line 42) | function isValidUrl(url: string) {

FILE: src/lib/utils.ts
  function hook (line 1) | function hook(
  function sleep (line 15) | function sleep(ms: number | undefined) {
  function shuffleArray (line 19) | function shuffleArray(a) {
  function chunkArray (line 30) | function chunkArray(arr: any[], size: number) {
  function ensureArray (line 42) | function ensureArray(arr?: any) {

FILE: src/permissions/link.ts
  function canViewLink (line 6) | async function canViewLink({ user }: Auth, linkId: string) {
  function canUpdateLink (line 26) | async function canUpdateLink({ user }: Auth, linkId: string) {
  function canDeleteLink (line 46) | async function canDeleteLink({ user }: Auth, linkId: string) {

FILE: src/permissions/pixel.ts
  function canViewPixel (line 6) | async function canViewPixel({ user }: Auth, pixelId: string) {
  function canUpdatePixel (line 26) | async function canUpdatePixel({ user }: Auth, pixelId: string) {
  function canDeletePixel (line 46) | async function canDeletePixel({ user }: Auth, pixelId: string) {

FILE: src/permissions/report.ts
  function canViewReport (line 5) | async function canViewReport(auth: Auth, report: Report) {
  function canUpdateReport (line 17) | async function canUpdateReport({ user }: Auth, report: Report) {
  function canDeleteReport (line 25) | async function canDeleteReport(auth: Auth, report: Report) {

FILE: src/permissions/team.ts
  function canViewTeam (line 6) | async function canViewTeam({ user }: Auth, teamId: string) {
  function canCreateTeam (line 14) | async function canCreateTeam({ user }: Auth) {
  function canUpdateTeam (line 22) | async function canUpdateTeam({ user }: Auth, teamId: string) {
  function canDeleteTeam (line 32) | async function canDeleteTeam({ user }: Auth, teamId: string) {
  function canDeleteTeamUser (line 42) | async function canDeleteTeamUser({ user }: Auth, teamId: string, removeU...
  function canCreateTeamWebsite (line 56) | async function canCreateTeamWebsite({ user }: Auth, teamId: string) {
  function canViewAllTeams (line 66) | async function canViewAllTeams({ user }: Auth) {

FILE: src/permissions/user.ts
  function canCreateUser (line 3) | async function canCreateUser({ user }: Auth) {
  function canViewUser (line 7) | async function canViewUser({ user }: Auth, viewedUserId: string) {
  function canViewUsers (line 15) | async function canViewUsers({ user }: Auth) {
  function canUpdateUser (line 19) | async function canUpdateUser({ user }: Auth, viewedUserId: string) {
  function canDeleteUser (line 27) | async function canDeleteUser({ user }: Auth) {

FILE: src/permissions/website.ts
  function canViewWebsite (line 6) | async function canViewWebsite({ user, shareToken }: Auth, websiteId: str...
  function canViewAllWebsites (line 38) | async function canViewAllWebsites({ user }: Auth) {
  function canCreateWebsite (line 42) | async function canCreateWebsite({ user }: Auth) {
  function canUpdateWebsite (line 50) | async function canUpdateWebsite({ user }: Auth, websiteId: string) {
  function canDeleteWebsite (line 74) | async function canDeleteWebsite({ user }: Auth, websiteId: string) {
  function canTransferWebsiteToUser (line 98) | async function canTransferWebsiteToUser({ user }: Auth, websiteId: strin...
  function canTransferWebsiteToTeam (line 114) | async function canTransferWebsiteToTeam({ user }: Auth, websiteId: strin...

FILE: src/queries/prisma/link.ts
  function findLink (line 5) | async function findLink(criteria: Prisma.LinkFindUniqueArgs) {
  function getLink (line 9) | async function getLink(linkId: string) {
  function getLinks (line 17) | async function getLinks(criteria: Prisma.LinkFindManyArgs, filters: Quer...
  function getUserLinks (line 33) | async function getUserLinks(userId: string, filters?: QueryFilters) {
  function getTeamLinks (line 45) | async function getTeamLinks(teamId: string, filters?: QueryFilters) {
  function createLink (line 56) | async function createLink(data: Prisma.LinkUncheckedCreateInput) {
  function updateLink (line 60) | async function updateLink(linkId: string, data: any) {
  function deleteLink (line 64) | async function deleteLink(linkId: string) {

FILE: src/queries/prisma/pixel.ts
  function findPixel (line 5) | async function findPixel(criteria: Prisma.PixelFindUniqueArgs) {
  function getPixel (line 9) | async function getPixel(pixelId: string) {
  function getPixels (line 17) | async function getPixels(criteria: Prisma.PixelFindManyArgs, filters: Qu...
  function getUserPixels (line 28) | async function getUserPixels(userId: string, filters?: QueryFilters) {
  function getTeamPixels (line 39) | async function getTeamPixels(teamId: string, filters?: QueryFilters) {
  function createPixel (line 50) | async function createPixel(data: Prisma.PixelUncheckedCreateInput) {
  function updatePixel (line 54) | async function updatePixel(pixelId: string, data: any) {
  function deletePixel (line 58) | async function deletePixel(pixelId: string) {

FILE: src/queries/prisma/report.ts
  function findReport (line 7) | async function findReport(criteria: Prisma.ReportFindUniqueArgs) {
  function getReport (line 11) | async function getReport(reportId: string) {
  function getReports (line 19) | async function getReports(criteria: ReportFindManyArgs, filters: QueryFi...
  function getUserReports (line 49) | async function getUserReports(userId: string, filters?: QueryFilters) {
  function getWebsiteReports (line 68) | async function getWebsiteReports(websiteId: string, filters: QueryFilter...
  function createReport (line 79) | async function createReport(data: Prisma.ReportUncheckedCreateInput) {
  function updateReport (line 83) | async function updateReport(reportId: string, data: any) {
  function deleteReport (line 87) | async function deleteReport(reportId: string) {

FILE: src/queries/prisma/segment.ts
  function findSegment (line 5) | async function findSegment(criteria: Prisma.SegmentFindUniqueArgs) {
  function getSegment (line 9) | async function getSegment(segmentId: string) {
  function getSegments (line 17) | async function getSegments(criteria: Prisma.SegmentFindManyArgs, filters...
  function getWebsiteSegment (line 33) | async function getWebsiteSegment(websiteId: string, segmentId: string) {
  function getWebsiteSegments (line 39) | async function getWebsiteSegments(websiteId: string, type: string, filte...
  function createSegment (line 51) | async function createSegment(data: Prisma.SegmentUncheckedCreateInput) {
  function updateSegment (line 55) | async function updateSegment(SegmentId: string, data: Prisma.SegmentUpda...
  function deleteSegment (line 59) | async function deleteSegment(SegmentId: string) {

FILE: src/queries/prisma/team.ts
  function findTeam (line 9) | async function findTeam(criteria: Prisma.TeamFindUniqueArgs): Promise<Te...
  function getTeam (line 13) | async function getTeam(
  function getTeams (line 27) | async function getTeams(
  function getUserTeams (line 49) | async function getUserTeams(userId: string, filters: QueryFilters = {}) {
  function getAllUserTeams (line 87) | async function getAllUserTeams(userId: string) {
  function createTeam (line 103) | async function createTeam(data: Prisma.TeamCreateInput, userId: string):...
  function updateTeam (line 122) | async function updateTeam(teamId: string, data: Prisma.TeamUpdateInput):...
  function deleteTeam (line 136) | async function deleteTeam(teamId: string) {

FILE: src/queries/prisma/teamUser.ts
  function findTeamUser (line 8) | async function findTeamUser(criteria: Prisma.TeamUserFindUniqueArgs) {
  function getTeamUser (line 12) | async function getTeamUser(teamId: string, userId: string) {
  function getTeamUsers (line 21) | async function getTeamUsers(criteria: TeamUserFindManyArgs, filters?: Qu...
  function createTeamUser (line 39) | async function createTeamUser(userId: string, teamId: string, role: stri...
  function updateTeamUser (line 50) | async function updateTeamUser(teamUserId: string, data: Prisma.TeamUserU...
  function deleteTeamUser (line 59) | async function deleteTeamUser(teamId: string, userId: string) {

FILE: src/queries/prisma/user.ts
  type GetUserOptions (line 9) | interface GetUserOptions {
  function findUser (line 14) | async function findUser(criteria: Prisma.UserFindUniqueArgs, options: Ge...
  function getUser (line 33) | async function getUser(userId: string, options: GetUserOptions = {}) {
  function getUserByUsername (line 44) | async function getUserByUsername(username: string, options: GetUserOptio...
  function getUsers (line 48) | async function getUsers(criteria: UserFindManyArgs, filters: QueryFilter...
  function createUser (line 71) | async function createUser(data: {
  function updateUser (line 87) | async function updateUser(userId: string, data: Prisma.UserUpdateInput) {
  function deleteUser (line 102) | async function deleteUser(userId: string) {

FILE: src/queries/prisma/website.ts
  function findWebsite (line 7) | async function findWebsite(criteria: Prisma.WebsiteFindUniqueArgs) {
  function getWebsite (line 11) | async function getWebsite(websiteId: string) {
  function getSharedWebsite (line 19) | async function getSharedWebsite(shareId: string) {
  function getWebsites (line 28) | async function getWebsites(criteria: Prisma.WebsiteFindManyArgs, filters...
  function getAllUserWebsitesIncludingTeamOwner (line 46) | async function getAllUserWebsitesIncludingTeamOwner(userId: string, filt...
  function getUserWebsites (line 73) | async function getUserWebsites(userId: string, filters?: QueryFilters) {
  function getTeamWebsites (line 95) | async function getTeamWebsites(teamId: string, filters?: QueryFilters) {
  function createWebsite (line 114) | async function createWebsite(
  function updateWebsite (line 122) | async function updateWebsite(
  function resetWebsite (line 134) | async function resetWebsite(websiteId: string) {
  function deleteWebsite (line 177) | async function deleteWebsite(websiteId: string) {
  function getWebsiteCount (line 227) | async function getWebsiteCount(userId: string) {

FILE: src/queries/sql/events/getEventData.ts
  constant FUNCTION_NAME (line 6) | const FUNCTION_NAME = 'getEventData';
  function getEventData (line 8) | async function getEventData(
  function relationalQuery (line 17) | async function relationalQuery(websiteId: string, eventId: string) {
  function clickhouseQuery (line 42) | async function clickhouseQuery(websiteId: string, eventId: string): Prom...

FILE: src/queries/sql/events/getEventDataEvents.ts
  constant FUNCTION_NAME (line 6) | const FUNCTION_NAME = 'getEventDataEvents';
  type WebsiteEventData (line 8) | interface WebsiteEventData {
  function getEventDataEvents (line 16) | async function getEventDataEvents(
  function relationalQuery (line 25) | async function relationalQuery(websiteId: string, filters: QueryFilters) {
  function clickhouseQuery (line 75) | async function clickhouseQuery(

FILE: src/queries/sql/events/getEventDataFields.ts
  constant FUNCTION_NAME (line 6) | const FUNCTION_NAME = 'getEventDataFields';
  function getEventDataFields (line 8) | async function getEventDataFields(...args: [websiteId: string, filters: ...
  function relationalQuery (line 15) | async function relationalQuery(websiteId: string, filters: QueryFilters) {
  function clickhouseQuery (line 51) | async function clickhouseQuery(

FILE: src/queries/sql/events/getEventDataProperties.ts
  constant FUNCTION_NAME (line 6) | const FUNCTION_NAME = 'getEventDataProperties';
  function getEventDataProperties (line 8) | async function getEventDataProperties(
  function relationalQuery (line 17) | async function relationalQuery(
  function clickhouseQuery (line 53) | async function clickhouseQuery(

FILE: src/queries/sql/events/getEventDataStats.ts
  constant FUNCTION_NAME (line 6) | const FUNCTION_NAME = 'getEventDataStats';
  function getEventDataStats (line 8) | async function getEventDataStats(
  function relationalQuery (line 21) | async function relationalQuery(websiteId: string, filters: QueryFilters) {
  function clickhouseQuery (line 56) | async function clickhouseQuery(

FILE: src/queries/sql/events/getEventDataUsage.ts
  constant FUNCTION_NAME (line 5) | const FUNCTION_NAME = 'getEventDataUsage';
  function getEventDataUsage (line 7) | function getEventDataUsage(...args: [websiteIds: string[], filters: Quer...
  function clickhouseQuery (line 14) | function clickhouseQuery(

FILE: src/queries/sql/events/getEventDataValues.ts
  constant FUNCTION_NAME (line 6) | const FUNCTION_NAME = 'getEventDataValues';
  type WebsiteEventData (line 8) | interface WebsiteEventData {
  function getEventDataValues (line 13) | async function getEventDataValues(
  function relationalQuery (line 22) | async function relationalQuery(
  function clickhouseQuery (line 60) | async function clickhouseQuery(

FILE: src/queries/sql/events/getEventExpandedMetrics.ts
  constant FUNCTION_NAME (line 7) | const FUNCTION_NAME = 'getEventExpandedMetrics';
  type EventExpandedMetricParameters (line 9) | interface EventExpandedMetricParameters {
  type EventExpandedMetricData (line 15) | interface EventExpandedMetricData {
  function getEventExpandedMetrics (line 24) | async function getEventExpandedMetrics(
  function relationalQuery (line 33) | async function relationalQuery(
  function clickhouseQuery (line 85) | async function clickhouseQuery(

FILE: src/queries/sql/events/getEventMetrics.ts
  constant FUNCTION_NAME (line 7) | const FUNCTION_NAME = 'getEventMetrics';
  type EventMetricParameters (line 9) | interface EventMetricParameters {
  type EventMetricData (line 15) | interface EventMetricData {
  function getEventMetrics (line 21) | async function getEventMetrics(
  function relationalQuery (line 30) | async function relationalQuery(
  function clickhouseQuery (line 67) | async function clickhouseQuery(

FILE: src/queries/sql/events/getEventStats.ts
  constant FUNCTION_NAME (line 7) | const FUNCTION_NAME = 'getEventStats';
  type WebsiteEventMetric (line 9) | interface WebsiteEventMetric {
  function getEventStats (line 15) | async function getEventStats(
  function relationalQuery (line 24) | async function relationalQuery(websiteId: string, filters: QueryFilters) {
  function clickhouseQuery (line 53) | async function clickhouseQuery(

FILE: src/queries/sql/events/getEventUsage.ts
  constant FUNCTION_NAME (line 5) | const FUNCTION_NAME = 'getEventUsage';
  function getEventUsage (line 7) | function getEventUsage(...args: [websiteIds: string[], filters: QueryFil...
  function clickhouseQuery (line 14) | function clickhouseQuery(

FILE: src/queries/sql/events/getWebsiteEvents.ts
  constant FUNCTION_NAME (line 6) | const FUNCTION_NAME = 'getWebsiteEvents';
  function getWebsiteEvents (line 8) | function getWebsiteEvents(...args: [websiteId: string, filters: QueryFil...
  function relationalQuery (line 15) | async function relationalQuery(websiteId: string, filters: QueryFilters) {
  function clickhouseQuery (line 69) | async function clickhouseQuery(websiteId: string, filters: QueryFilters) {

FILE: src/queries/sql/events/saveEvent.ts
  type SaveEventArgs (line 10) | interface SaveEventArgs {
  function saveEvent (line 58) | async function saveEvent(args: SaveEventArgs) {
  function relationalQuery (line 65) | async function relationalQuery({
  function clickhouseQuery (line 153) | async function clickhouseQuery({

FILE: src/queries/sql/events/saveEventData.ts
  type SaveEventDataArgs (line 10) | interface SaveEventDataArgs {
  function saveEventData (line 20) | async function saveEventData(data: SaveEventDataArgs) {
  function relationalQuery (line 27) | async function relationalQuery(data: SaveEventDataArgs) {
  function clickhouseQuery (line 50) | async function clickhouseQuery(data: SaveEventDataArgs) {

FILE: src/queries/sql/events/saveRevenue.ts
  type SaveRevenueArgs (line 5) | interface SaveRevenueArgs {
  function saveRevenue (line 15) | async function saveRevenue(data: SaveRevenueArgs) {
  function relationalQuery (line 21) | async function relationalQuery(data: SaveRevenueArgs) {

FILE: src/queries/sql/getActiveVisitors.ts
  constant FUNCTION_NAME (line 6) | const FUNCTION_NAME = 'getActiveVisitors';
  function getActiveVisitors (line 8) | async function getActiveVisitors(...args: [websiteId: string]) {
  function relationalQuery (line 15) | async function relationalQuery(websiteId: string) {
  function clickhouseQuery (line 33) | async function clickhouseQuery(websiteId: string): Promise<{ x: number }> {

FILE: src/queries/sql/getChannelExpandedMetrics.ts
  constant FUNCTION_NAME (line 14) | const FUNCTION_NAME = 'getChannelExpandedMetrics';
  type ChannelExpandedMetricsParameters (line 16) | interface ChannelExpandedMetricsParameters {
  type ChannelExpandedMetricsData (line 21) | interface ChannelExpandedMetricsData {
  function getChannelExpandedMetrics (line 30) | async function getChannelExpandedMetrics(
  function relationalQuery (line 39) | async function relationalQuery(
  function clickhouseQuery (line 117) | async function clickhouseQuery(
  function toClickHouseStringArray (line 184) | function toClickHouseStringArray(arr: string[]): string {
  function toPostgresPositionClause (line 188) | function toPostgresPositionClause(column: string, arr: string[]) {

FILE: src/queries/sql/getChannelMetrics.ts
  constant FUNCTION_NAME (line 14) | const FUNCTION_NAME = 'getChannelMetrics';
  function getChannelMetrics (line 16) | async function getChannelMetrics(...args: [websiteId: string, filters?: ...
  function relationalQuery (line 23) | async function relationalQuery(websiteId: string, filters: QueryFilters) {
  function clickhouseQuery (line 79) | async function clickhouseQuery(
  function toClickHouseStringArray (line 136) | function toClickHouseStringArray(arr: string[]): string {
  function toPostgresLikeClause (line 140) | function toPostgresLikeClause(column: string, arr: string[]) {

FILE: src/queries/sql/getRealtimeActivity.ts
  constant FUNCTION_NAME (line 6) | const FUNCTION_NAME = 'getRealtimeActivity';
  function getRealtimeActivity (line 8) | async function getRealtimeActivity(...args: [websiteId: string, filters:...
  function relationalQuery (line 15) | async function relationalQuery(websiteId: string, filters: QueryFilters) {
  function clickhouseQuery (line 50) | async function clickhouseQuery(websiteId: string, filters: QueryFilters)...

FILE: src/queries/sql/getRealtimeData.ts
  function increment (line 6) | function increment(data: object, key: string) {
  function getRealtimeData (line 16) | async function getRealtimeData(websiteId: string, filters: QueryFilters) {

FILE: src/queries/sql/getValues.ts
  constant FUNCTION_NAME (line 6) | const FUNCTION_NAME = 'getValues';
  function getValues (line 8) | async function getValues(
  function relationalQuery (line 17) | async function relationalQuery(websiteId: string, column: string, filter...
  function clickhouseQuery (line 74) | async function clickhouseQuery(websiteId: string, column: string, filter...

FILE: src/queries/sql/getWebsiteDateRange.ts
  function getWebsiteDateRange (line 6) | async function getWebsiteDateRange(...args: [websiteId: string]) {
  function relationalQuery (line 13) | async function relationalQuery(websiteId: string) {
  function clickhouseQuery (line 35) | async function clickhouseQuery(websiteId: string) {

FILE: src/queries/sql/getWebsiteStats.ts
  constant FUNCTION_NAME (line 7) | const FUNCTION_NAME = 'getWebsiteStats';
  type WebsiteStatsData (line 9) | interface WebsiteStatsData {
  function getWebsiteStats (line 17) | async function getWebsiteStats(
  function relationalQuery (line 26) | async function relationalQuery(
  function clickhouseQuery (line 66) | async function clickhouseQuery(

FILE: src/queries/sql/getWeeklyTraffic.ts
  constant FUNCTION_NAME (line 7) | const FUNCTION_NAME = 'getWeeklyTraffic';
  function getWeeklyTraffic (line 9) | async function getWeeklyTraffic(...args: [websiteId: string, filters: Qu...
  function relationalQuery (line 16) | async function relationalQuery(websiteId: string, filters: QueryFilters) {
  function clickhouseQuery (line 43) | async function clickhouseQuery(websiteId: string, filters: QueryFilters) {
  function formatResults (line 81) | function formatResults(data: any) {

FILE: src/queries/sql/pageviews/getPageviewExpandedMetrics.ts
  constant FUNCTION_NAME (line 7) | const FUNCTION_NAME = 'getPageviewExpandedMetrics';
  type PageviewExpandedMetricsParameters (line 9) | interface PageviewExpandedMetricsParameters {
  type PageviewExpandedMetricsData (line 15) | interface PageviewExpandedMetricsData {
  function getPageviewExpandedMetrics (line 24) | async function getPageviewExpandedMetrics(
  function relationalQuery (line 33) | async function relationalQuery(
  function clickhouseQuery (line 117) | async function clickhouseQuery(
  function toClickHouseGroupedReferrer (line 193) | function toClickHouseGroupedReferrer(
  function toPostgresGroupedReferrer (line 209) | function toPostgresGroupedReferrer(
  function toPostgresLikeClause (line 225) | function toPostgresLikeClause(column: string, arr: string[]) {

FILE: src/queries/sql/pageviews/getPageviewMetrics.ts
  constant FUNCTION_NAME (line 7) | const FUNCTION_NAME = 'getPageviewMetrics';
  type PageviewMetricsParameters (line 9) | interface PageviewMetricsParameters {
  type PageviewMetricsData (line 15) | interface PageviewMetricsData {
  function getPageviewMetrics (line 20) | async function getPageviewMetrics(
  function relationalQuery (line 29) | async function relationalQuery(
  function clickhouseQuery (line 95) | async function clickhouseQuery(

FILE: src/queries/sql/pageviews/getPageviewStats.ts
  constant FUNCTION_NAME (line 7) | const FUNCTION_NAME = 'getPageviewStats';
  function getPageviewStats (line 9) | async function getPageviewStats(...args: [websiteId: string, filters: Qu...
  function relationalQuery (line 16) | async function relationalQuery(websiteId: string, filters: QueryFilters) {
  function clickhouseQuery (line 44) | async function clickhouseQuery(

FILE: src/queries/sql/reports/getAttribution.ts
  type AttributionParameters (line 7) | interface AttributionParameters {
  type AttributionResult (line 16) | interface AttributionResult {
  function getAttribution (line 27) | async function getAttribution(
  function relationalQuery (line 36) | async function relationalQuery(
  function clickhouseQuery (line 262) | async function clickhouseQuery(

FILE: src/queries/sql/reports/getBreakdown.ts
  type BreakdownParameters (line 7) | interface BreakdownParameters {
  type BreakdownData (line 13) | interface BreakdownData {
  function getBreakdown (line 18) | async function getBreakdown(
  function relationalQuery (line 27) | async function relationalQuery(
  function clickhouseQuery (line 81) | async function clickhouseQuery(
  function parseFields (line 129) | function parseFields(fields: string[]) {
  function parseFieldsByName (line 133) | function parseFieldsByName(fields: string[]) {

FILE: src/queries/sql/reports/getFunnel.ts
  type FunnelParameters (line 6) | interface FunnelParameters {
  type FunnelResult (line 13) | interface FunnelResult {
  function getFunnel (line 19) | async function getFunnel(
  function relationalQuery (line 28) | async function relationalQuery(
  function clickhouseQuery (line 124) | async function clickhouseQuery(

FILE: src/queries/sql/reports/getGoal.ts
  type GoalParameters (line 7) | interface GoalParameters {
  function getGoal (line 16) | async function getGoal(
  function relationalQuery (line 25) | async function relationalQuery(
  function clickhouseQuery (line 67) | async function clickhouseQuery(

FILE: src/queries/sql/reports/getJourney.ts
  type JourneyParameters (line 6) | interface JourneyParameters {
  type JourneyResult (line 14) | interface JourneyResult {
  function getJourney (line 25) | async function getJourney(
  function relationalQuery (line 34) | async function relationalQuery(
  function clickhouseQuery (line 146) | async function clickhouseQuery(
  function combineSequentialDuplicates (line 256) | function combineSequentialDuplicates(array: any) {
  function parseResult (line 270) | function parseResult(data: any) {

FILE: src/queries/sql/reports/getRetention.ts
  type RetentionParameters (line 6) | interface RetentionParameters {
  type RetentionResult (line 12) | interface RetentionResult {
  function getRetention (line 20) | async function getRetention(
  function relationalQuery (line 29) | async function relationalQuery(
  function clickhouseQuery (line 103) | async function clickhouseQuery(

FILE: src/queries/sql/reports/getRevenue.ts
  type RevenuParameters (line 6) | interface RevenuParameters {
  type RevenueResult (line 14) | interface RevenueResult {
  function getRevenue (line 20) | async function getRevenue(
  function relationalQuery (line 29) | async function relationalQuery(
  function clickhouseQuery (line 116) | async function clickhouseQuery(

FILE: src/queries/sql/reports/getUTM.ts
  type UTMParameters (line 7) | interface UTMParameters {
  function getUTM (line 13) | async function getUTM(
  function relationalQuery (line 22) | async function relationalQuery(
  function clickhouseQuery (line 55) | async function clickhouseQuery(

FILE: src/queries/sql/sessions/createSession.ts
  constant FUNCTION_NAME (line 4) | const FUNCTION_NAME = 'createSession';
  function createSession (line 6) | async function createSession(data: Prisma.SessionCreateInput) {

FILE: src/queries/sql/sessions/getSessionActivity.ts
  constant FUNCTION_NAME (line 6) | const FUNCTION_NAME = 'getSessionActivity';
  function getSessionActivity (line 8) | async function getSessionActivity(
  function relationalQuery (line 17) | async function relationalQuery(websiteId: string, sessionId: string, fil...
  function clickhouseQuery (line 48) | async function clickhouseQuery(websiteId: string, sessionId: string, fil...

FILE: src/queries/sql/sessions/getSessionData.ts
  constant FUNCTION_NAME (line 5) | const FUNCTION_NAME = 'getSessionData';
  function getSessionData (line 7) | async function getSessionData(...args: [websiteId: string, sessionId: st...
  function relationalQuery (line 14) | async function relationalQuery(websiteId: string, sessionId: string) {
  function clickhouseQuery (line 38) | async function clickhouseQuery(websiteId: string, sessionId: string) {

FILE: src/queries/sql/sessions/getSessionDataProperties.ts
  constant FUNCTION_NAME (line 6) | const FUNCTION_NAME = 'getSessionDataProperties';
  function getSessionDataProperties (line 8) | async function getSessionDataProperties(
  function relationalQuery (line 17) | async function relationalQuery(websiteId: string, filters: QueryFilters) {
  function clickhouseQuery (line 47) | async function clickhouseQuery(

FILE: src/queries/sql/sessions/getSessionDataValues.ts
  constant FUNCTION_NAME (line 6) | const FUNCTION_NAME = 'getSessionDataValues';
  function getSessionDataValues (line 8) | async function getSessionDataValues(
  function relationalQuery (line 17) | async function relationalQuery(
  function clickhouseQuery (line 55) | async function clickhouseQuery(

FILE: src/queries/sql/sessions/getSessionExpandedMetrics.ts
  constant FUNCTION_NAME (line 7) | const FUNCTION_NAME = 'getSessionExpandedMetrics';
  type SessionExpandedMetricsParameters (line 9) | interface SessionExpandedMetricsParameters {
  type SessionExpandedMetricsData (line 15) | interface SessionExpandedMetricsData {
  function getSessionExpandedMetrics (line 24) | async function getSessionExpandedMetrics(
  function relationalQuery (line 33) | async function relationalQuery(
  function clickhouseQuery (line 96) | async function clickhouseQuery(

FILE: src/queries/sql/sessions/getSessionMetrics.ts
  constant FUNCTION_NAME (line 7) | const FUNCTION_NAME = 'getSessionMetrics';
  type SessionMetricsParameters (line 9) | interface SessionMetricsParameters {
  function getSessionMetrics (line 15) | async function getSessionMetrics(
  function relationalQuery (line 24) | async function relationalQuery(
  function clickhouseQuery (line 71) | async function clickhouseQuery(

FILE: src/queries/sql/sessions/getSessionStats.ts
  constant FUNCTION_NAME (line 7) | const FUNCTION_NAME = 'getSessionStats';
  function getSessionStats (line 9) | async function getSessionStats(...args: [websiteId: string, filters: Que...
  function relationalQuery (line 16) | async function relationalQuery(websiteId: string, filters: QueryFilters) {
  function clickhouseQuery (line 44) | async function clickhouseQuery(

FILE: src/queries/sql/sessions/getWebsiteSession.ts
  constant FUNCTION_NAME (line 5) | const FUNCTION_NAME = 'getWebsiteSession';
  function getWebsiteSession (line 7) | async function getWebsiteSession(...args: [websiteId: string, sessionId:...
  function relationalQuery (line 14) | async function relationalQuery(websiteId: string, sessionId: string) {
  function clickhouseQuery (line 65) | async function clickhouseQuery(websiteId: string, sessionId: string) {

FILE: src/queries/sql/sessions/getWebsiteSessionStats.ts
  constant FUNCTION_NAME (line 7) | const FUNCTION_NAME = 'getWebsiteSessionStats';
  type WebsiteSessionStatsData (line 9) | interface WebsiteSessionStatsData {
  function getWebsiteSessionStats (line 17) | async function getWebsiteSessionStats(
  function relationalQuery (line 26) | async function relationalQuery(
  function clickhouseQuery (line 57) | async function clickhouseQuery(

FILE: src/queries/sql/sessions/getWebsiteSessions.ts
  constant FUNCTION_NAME (line 7) | const FUNCTION_NAME = 'getWebsiteSessions';
  function getWebsiteSessions (line 9) | async function getWebsiteSessions(...args: [websiteId: string, filters: ...
  function relationalQuery (line 16) | async function relationalQuery(websiteId: string, filters: QueryFilters) {
  function clickhouseQuery (line 79) | async function clickhouseQuery(websiteId: string, filters: QueryFilters) {

FILE: src/queries/sql/sessions/saveSessionData.ts
  type SaveSessionDataArgs (line 10) | interface SaveSessionDataArgs {
  function saveSessionData (line 18) | async function saveSessionData(data: SaveSessionDataArgs) {
  function relationalQuery (line 25) | async function relationalQuery({
  function clickhouseQuery (line 81) | async function clickhouseQuery({

FILE: src/store/app.ts
  function setTimezone (line 26) | function setTimezone(timezone: string) {
  function setLocale (line 30) | function setLocale(locale: string) {
  function setShareToken (line 34) | function setShareToken(shareToken: string) {
  function setUser (line 38) | function setUser(user: object) {
  function setConfig (line 42) | function setConfig(config: object) {
  function setDateRangeValue (line 46) | function setDateRangeValue(dateRangeValue: string) {

FILE: src/store/cache.ts
  function setValue (line 5) | function setValue(key: string, value: any) {

FILE: src/store/dashboard.ts
  function saveDashboard (line 16) | function saveDashboard(settings) {

FILE: src/store/version.ts
  function checkVersion (line 17) | async function checkVersion() {

FILE: src/store/websites.ts
  function setWebsiteDateRange (line 7) | function setWebsiteDateRange(websiteId: string, dateRange: DateRange) {
  function setWebsiteDateCompare (line 21) | function setWebsiteDateCompare(websiteId: string, dateCompare: string) {

FILE: src/tracker/index.d.ts
  type TrackedProperties (line 1) | type TrackedProperties = {
  type WithRequired (line 58) | type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };
  type EventData (line 68) | interface EventData {
  type EventProperties (line 72) | type EventProperties = {
  type PageViewProperties (line 79) | type PageViewProperties = WithRequired<TrackedProperties, 'website'>;
  type CustomEventFunction (line 80) | type CustomEventFunction = (
  type UmamiTracker (line 84) | type UmamiTracker = {
  type Window (line 151) | interface Window {

FILE: tsup.config.js
  method esbuildOptions (line 12) | esbuildOptions(options) {
Condensed preview — 954 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (6,558K chars).
[
  {
    "path": ".dockerignore",
    "chars": 121,
    "preview": ".git\ndocker-compose.yml\nDockerfile\n.gitignore\n.DS_Store\nnode_modules\n.idea\n.env\n.env.*\nscripts/seed\nscripts/seed-data.ts"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/1.bug_report.yml",
    "chars": 1157,
    "preview": "name: '🐛 Bug Report'\ndescription: Create a bug report for Umami.\nbody:\n  - type: textarea\n    attributes:\n      label: D"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/2.feature_request.yml",
    "chars": 308,
    "preview": "name: '✨ Feature Request'\ndescription: Create a feature or enhancement request for Umami.\nbody:\n  - type: textarea\n    a"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "chars": 200,
    "preview": "\nblank_issues_enabled: false\ncontact_links:\n  - name: \"🤔 Ask a question\"\n    url: https://github.com/umami-software/umam"
  },
  {
    "path": ".github/workflows/cd-cloud.yml",
    "chars": 757,
    "preview": "name: Create docker images (cloud)\n\non:\n  push:\n    branches:\n      - analytics\n      - cloud\n\njobs:\n  build:\n    name: "
  },
  {
    "path": ".github/workflows/cd.yml",
    "chars": 4235,
    "preview": "name: Create docker images\n\non:\n  push:\n    tags:\n      - \"v*.*.*\"\n  workflow_dispatch:\n    inputs:\n      version:\n     "
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 605,
    "preview": "name: Node.js CI\n\non: [push]\n\nenv:\n  DATABASE_URL: \"postgresql://user:pass@localhost:5432/dummy\"\n  SKIP_DB_CHECK: 1\n\njob"
  },
  {
    "path": ".github/workflows/stale-issues.yml",
    "chars": 800,
    "preview": "name: Close stale issues\non:\n  schedule:\n    - cron: '30 1 * * *'\n\njobs:\n  stale:\n    runs-on: ubuntu-latest\n    permiss"
  },
  {
    "path": ".gitignore",
    "chars": 450,
    "preview": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\nnode_modules\n.pnp\n"
  },
  {
    "path": ".husky/pre-commit",
    "chars": 16,
    "preview": "npx lint-staged\n"
  },
  {
    "path": ".stylelintrc.json",
    "chars": 138,
    "preview": "{\n  \"extends\": [\"stylelint-config-recommended\", \"stylelint-config-css-modules\"],\n  \"rules\": {\n    \"no-descending-specifi"
  },
  {
    "path": "Dockerfile",
    "chars": 1883,
    "preview": "ARG NODE_IMAGE_VERSION=\"22-alpine\"\n\n# Install dependencies only when needed\nFROM node:${NODE_IMAGE_VERSION} AS deps\n# Ch"
  },
  {
    "path": "LICENSE",
    "chars": 1093,
    "preview": "MIT License\n\nCopyright (c) 2022 Umami Software, Inc. <hello@umami.is>\n\nPermission is hereby granted, free of charge, to "
  },
  {
    "path": "README.md",
    "chars": 4455,
    "preview": "<p align=\"center\">\n  <img src=\"https://content.umami.is/website/images/umami-logo.png\" alt=\"Umami Logo\" width=\"100\">\n</p"
  },
  {
    "path": "app.json",
    "chars": 508,
    "preview": "{\n  \"name\": \"Umami\",\n  \"description\": \"Umami is a simple, fast, website analytics alternative to Google Analytics.\",\n  \""
  },
  {
    "path": "biome.json",
    "chars": 1264,
    "preview": "{\n  \"$schema\": \"https://biomejs.dev/schemas/2.3.6/schema.json\",\n  \"vcs\": {\n    \"enabled\": true,\n    \"clientKind\": \"git\","
  },
  {
    "path": "cypress/docker-compose.yml",
    "chars": 1339,
    "preview": "---\nversion: '3'\nservices:\n  umami:\n    build: ../\n    #image: ghcr.io/umami-software/umami:postgresql-latest\n    ports:"
  },
  {
    "path": "cypress/e2e/api-team.cy.ts",
    "chars": 6121,
    "preview": "describe('Team API tests', () => {\n  Cypress.session.clearAllSavedSessions();\n\n  let teamId;\n  let userId;\n\n  before(() "
  },
  {
    "path": "cypress/e2e/api-user.cy.ts",
    "chars": 3751,
    "preview": "describe('User API tests', () => {\n  Cypress.session.clearAllSavedSessions();\n\n  before(() => {\n    cy.login(Cypress.env"
  },
  {
    "path": "cypress/e2e/api-website.cy.ts",
    "chars": 5997,
    "preview": "import { uuid } from '../../src/lib/crypto';\n\ndescribe('Website API tests', () => {\n  Cypress.session.clearAllSavedSessi"
  },
  {
    "path": "cypress/e2e/login.cy.ts",
    "chars": 1293,
    "preview": "describe('Login tests', () => {\n  beforeEach(() => {\n    cy.visit('/login');\n  });\n\n  it(\n    'logs user in with correct"
  },
  {
    "path": "cypress/e2e/user.cy.ts",
    "chars": 2490,
    "preview": "describe('User tests', () => {\n  Cypress.session.clearAllSavedSessions();\n\n  beforeEach(() => {\n    cy.login(Cypress.env"
  },
  {
    "path": "cypress/e2e/website.cy.ts",
    "chars": 3420,
    "preview": "describe('Website tests', () => {\n  Cypress.session.clearAllSavedSessions();\n\n  beforeEach(() => {\n    cy.login(Cypress."
  },
  {
    "path": "cypress/fixtures/teams.json",
    "chars": 99,
    "preview": "{\n  \"teamCreate\": {\n    \"name\": \"cypress\"\n  },\n  \"teamUpdate\": {\n    \"name\": \"cypressUpdate\"\n  }\n}\n"
  },
  {
    "path": "cypress/fixtures/users.json",
    "chars": 176,
    "preview": "{\n  \"userCreate\": {\n    \"username\": \"cypress1\",\n    \"password\": \"password\",\n    \"role\": \"user\"\n  },\n  \"userUpdate\": {\n  "
  },
  {
    "path": "cypress/fixtures/websites.json",
    "chars": 188,
    "preview": "{\n  \"websiteCreate\": {\n    \"name\": \"Cypress Website\",\n    \"domain\": \"cypress.com\"\n  },\n  \"websiteUpdate\": {\n    \"name\": "
  },
  {
    "path": "cypress/support/e2e.ts",
    "chars": 3056,
    "preview": "/// <reference types=\"cypress\" />\nimport { uuid } from '../../src/lib/crypto';\n\nCypress.Commands.add('getDataTest', (val"
  },
  {
    "path": "cypress/support/index.d.ts",
    "chars": 1891,
    "preview": "/// <reference types=\"cypress\" />\n/* global JQuery */\n\ndeclare namespace Cypress {\n  interface Chainable {\n    /**\n     "
  },
  {
    "path": "cypress/tsconfig.json",
    "chars": 162,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"es5\", \"dom\"],\n    \"types\": [\"cypress\", \"node\"]\n  },\n  \"includ"
  },
  {
    "path": "cypress.config.ts",
    "chars": 295,
    "preview": "import { defineConfig } from 'cypress';\n\nexport default defineConfig({\n  e2e: {\n    baseUrl: 'http://localhost:3000',\n  "
  },
  {
    "path": "db/clickhouse/migrations/01_edit_keys.sql",
    "chars": 755,
    "preview": "-- edit event_data values\nALTER TABLE \"event_data\" RENAME COLUMN \"event_date_value\" TO \"date_value\";\nALTER TABLE \"event_"
  },
  {
    "path": "db/clickhouse/migrations/02_add_visit_id.sql",
    "chars": 2130,
    "preview": "CREATE TABLE umami.website_event_join\n(\n    session_id UUID,\n    visit_id UUID,\n    created_at DateTime('UTC')\n)\n    eng"
  },
  {
    "path": "db/clickhouse/migrations/03_session_data.sql",
    "chars": 1313,
    "preview": "CREATE TABLE umami.event_data_new\n(\n    website_id UUID,\n    session_id UUID,\n    event_id UUID,\n    url_path String,\n  "
  },
  {
    "path": "db/clickhouse/migrations/04_add_tag.sql",
    "chars": 1821,
    "preview": "-- add tag column\nALTER TABLE umami.website_event ADD COLUMN \"tag\" String AFTER \"event_name\";\nALTER TABLE umami.website_"
  },
  {
    "path": "db/clickhouse/migrations/05_add_utm_clid.sql",
    "chars": 10350,
    "preview": "-- Create Event\nCREATE TABLE umami.website_event_new\n(\n    website_id UUID,\n    session_id UUID,\n    visit_id UUID,\n    "
  },
  {
    "path": "db/clickhouse/migrations/06_update_subdivision.sql",
    "chars": 3425,
    "preview": "-- drop projections\nALTER TABLE umami.website_event  DROP PROJECTION website_event_url_path_projection;\nALTER TABLE umam"
  },
  {
    "path": "db/clickhouse/migrations/07_add_distinct_id.sql",
    "chars": 2733,
    "preview": "-- add tag column\nALTER TABLE umami.website_event ADD COLUMN \"distinct_id\" String AFTER \"tag\";\nALTER TABLE umami.website"
  },
  {
    "path": "db/clickhouse/migrations/08_update_hostname_view.sql",
    "chars": 7584,
    "preview": "-- create new hourly table\nCREATE TABLE umami.website_event_stats_hourly_new\n(\n    website_id UUID,\n    session_id UUID,"
  },
  {
    "path": "db/clickhouse/schema.sql",
    "chars": 8406,
    "preview": "-- Create Event\nCREATE TABLE umami.website_event\n(\n    website_id UUID,\n    session_id UUID,\n    visit_id UUID,\n    even"
  },
  {
    "path": "db/postgresql/data-migrations/convert-utm-clid-columns.sql",
    "chars": 3408,
    "preview": "-----------------------------------------------------\n-- PostgreSQL\n----------------------------------------------------"
  },
  {
    "path": "db/postgresql/data-migrations/populate-revenue-table.sql",
    "chars": 1323,
    "preview": "-----------------------------------------------------\n-- PostgreSQL\n----------------------------------------------------"
  },
  {
    "path": "docker/middleware.ts",
    "chars": 2136,
    "preview": "import { type NextRequest, NextResponse } from 'next/server';\n\nexport const config = {\n  matcher: '/:path*',\n};\n\nconst T"
  },
  {
    "path": "docker-compose.yml",
    "chars": 857,
    "preview": "---\nservices:\n  umami:\n    image: ghcr.io/umami-software/umami:latest\n    ports:\n      - \"3000:3000\"\n    environment:\n  "
  },
  {
    "path": "jest.config.ts",
    "chars": 243,
    "preview": "export default {\n  roots: ['./src'],\n  testMatch: ['**/__tests__/**/*.+(ts|tsx|js)', '**/?(*.)+(spec|test).+(ts|tsx|js)'"
  },
  {
    "path": "netlify.toml",
    "chars": 102,
    "preview": "[functions]\nincluded_files = [\"node_modules/.geo/**\"]\n\n[[plugins]]\npackage = \"@netlify/plugin-nextjs\"\n"
  },
  {
    "path": "next-env.d.ts",
    "chars": 262,
    "preview": "/// <reference types=\"next\" />\n/// <reference types=\"next/image-types/global\" />\n/// <reference path=\"./.next/types/rout"
  },
  {
    "path": "next.config.ts",
    "chars": 4086,
    "preview": "import 'dotenv/config';\nimport pkg from './package.json' with { type: 'json' };\n\nconst TRACKER_SCRIPT = '/script.js';\n\nc"
  },
  {
    "path": "package.components.json",
    "chars": 236,
    "preview": "{\n  \"name\": \"@umami/components\",\n  \"version\": \"0.130.0\",\n  \"description\": \"Umami React components.\",\n  \"author\": \"Mike C"
  },
  {
    "path": "package.json",
    "chars": 6255,
    "preview": "{\n  \"name\": \"umami\",\n  \"version\": \"3.0.3\",\n  \"description\": \"A modern, privacy-focused alternative to Google Analytics.\""
  },
  {
    "path": "pnpm-workspace.yaml",
    "chars": 156,
    "preview": "packages:\n  - '**'\nignoredBuiltDependencies:\n  - cypress\n  - esbuild\n  - sharp\nonlyBuiltDependencies:\n  - '@prisma/clien"
  },
  {
    "path": "podman/README.md",
    "chars": 1305,
    "preview": "# How to deploy umami on podman\n\n\n## How to use\n\n1. Rename `env.sample` to `.env`\n2. Edit `.env` file. At the minimum se"
  },
  {
    "path": "podman/env.sample",
    "chars": 526,
    "preview": "# Rename this file to .env and modify the values\n#\n# Connection string for Umami’s database.\n# If you use the bundled DB"
  },
  {
    "path": "podman/install-systemd-user-service",
    "chars": 244,
    "preview": "#!/bin/bash\nset -e\nservice_name=\"umami\"\nmkdir -p ~/.config/systemd/user\ncp $service_name.service ~/.config/systemd/user\n"
  },
  {
    "path": "podman/podman-compose.yml",
    "chars": 1010,
    "preview": "version: \"3.8\"\n\nservices:\n  umami:\n    container_name: umami\n    image: ghcr.io/umami-software/umami:postgresql-latest\n "
  },
  {
    "path": "podman/umami.service",
    "chars": 351,
    "preview": "[Unit]\nDescription=Umami Container Stack via Podman-Compose\nAfter=network.target\n\n[Service]\nType=simple\nWorkingDirectory"
  },
  {
    "path": "postcss.config.js",
    "chars": 278,
    "preview": "export default {\n  plugins: [\n    'postcss-flexbugs-fixes',\n    [\n      'postcss-preset-env',\n      {\n        autoprefix"
  },
  {
    "path": "prisma/migrations/01_init/migration.sql",
    "chars": 5822,
    "preview": "-- CreateExtension\nCREATE EXTENSION IF NOT EXISTS \"pgcrypto\";\n\n-- CreateTable\nCREATE TABLE \"user\" (\n    \"user_id\" UUID N"
  },
  {
    "path": "prisma/migrations/02_report_schema_session_data/migration.sql",
    "chars": 2220,
    "preview": "-- AlterTable\nALTER TABLE \"event_data\" RENAME COLUMN \"event_data_type\" TO \"data_type\";\nALTER TABLE \"event_data\" RENAME C"
  },
  {
    "path": "prisma/migrations/03_metric_performance_index/migration.sql",
    "chars": 2207,
    "preview": "-- CreateIndex\nCREATE INDEX \"event_data_website_id_created_at_idx\" ON \"event_data\"(\"website_id\", \"created_at\");\n\n-- Crea"
  },
  {
    "path": "prisma/migrations/04_team_redesign/migration.sql",
    "chars": 756,
    "preview": "/*\n  Warnings:\n\n  - You are about to drop the `team_website` table. If the table is not empty, all the data it contains "
  },
  {
    "path": "prisma/migrations/05_add_visit_id/migration.sql",
    "chars": 738,
    "preview": "-- AlterTable\nALTER TABLE \"website_event\" ADD COLUMN \"visit_id\" UUID NULL;\n\nUPDATE \"website_event\" we\nSET visit_id = a.u"
  },
  {
    "path": "prisma/migrations/06_session_data/migration.sql",
    "chars": 692,
    "preview": "-- DropIndex\nDROP INDEX IF EXISTS \"event_data_website_id_created_at_event_key_idx\";\n\n-- AlterTable\nALTER TABLE \"event_da"
  },
  {
    "path": "prisma/migrations/07_add_tag/migration.sql",
    "chars": 206,
    "preview": "-- AlterTable\nALTER TABLE \"website_event\" ADD COLUMN     \"tag\" VARCHAR(50);\n\n-- CreateIndex\nCREATE INDEX \"website_event_"
  },
  {
    "path": "prisma/migrations/08_add_utm_clid/migration.sql",
    "chars": 485,
    "preview": "-- AlterTable\nALTER TABLE \"website_event\" \nADD COLUMN     \"fbclid\" VARCHAR(255),\nADD COLUMN     \"gclid\" VARCHAR(255),\nAD"
  },
  {
    "path": "prisma/migrations/09_update_hostname_region/migration.sql",
    "chars": 817,
    "preview": "-- AlterTable\nALTER TABLE \"website_event\" ADD COLUMN     \"hostname\" VARCHAR(100);\n\n-- DataMigration\nUPDATE \"website_even"
  },
  {
    "path": "prisma/migrations/10_add_distinct_id/migration.sql",
    "chars": 162,
    "preview": "-- AlterTable\nALTER TABLE \"session\" ADD COLUMN     \"distinct_id\" VARCHAR(50);\n\n-- AlterTable\nALTER TABLE \"session_data\" "
  },
  {
    "path": "prisma/migrations/11_add_segment/migration.sql",
    "chars": 529,
    "preview": "-- CreateTable\nCREATE TABLE \"segment\" (\n    \"segment_id\" UUID NOT NULL,\n    \"website_id\" UUID NOT NULL,\n    \"type\" VARCH"
  },
  {
    "path": "prisma/migrations/12_update_report_parameter/migration.sql",
    "chars": 106,
    "preview": "-- AlterTable\nALTER TABLE \"report\"\nALTER COLUMN \"parameters\" SET DATA TYPE JSONB USING parameters::JSONB;\n"
  },
  {
    "path": "prisma/migrations/13_add_revenue/migration.sql",
    "chars": 884,
    "preview": "-- CreateTable\nCREATE TABLE \"revenue\" (\n    \"revenue_id\" UUID NOT NULL,\n    \"website_id\" UUID NOT NULL,\n    \"session_id\""
  },
  {
    "path": "prisma/migrations/14_add_link_and_pixel/migration.sql",
    "chars": 3289,
    "preview": "-- AlterTable\nALTER TABLE \"report\" ALTER COLUMN \"type\" SET DATA TYPE VARCHAR(50);\n\n-- AlterTable\nALTER TABLE \"revenue\" A"
  },
  {
    "path": "prisma/migrations/migration_lock.toml",
    "chars": 128,
    "preview": "# Please do not edit this file manually\n# It should be added in your version-control system (e.g., Git)\nprovider = \"post"
  },
  {
    "path": "prisma/schema.prisma",
    "chars": 11763,
    "preview": "generator client {\n  provider   = \"prisma-client\"\n  output     = \"../src/generated/prisma\"\n  engineType = \"client\"\n}\n\nda"
  },
  {
    "path": "prisma.config.ts",
    "chars": 161,
    "preview": "import 'dotenv/config';\nimport { defineConfig, env } from 'prisma/config';\n\nexport default defineConfig({\n  datasource: "
  },
  {
    "path": "public/browserconfig.xml",
    "chars": 246,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig>\n    <msapplication>\n        <tile>\n            <square150x150logo"
  },
  {
    "path": "public/datamaps.world.json",
    "chars": 433278,
    "preview": "{\n  \"type\": \"FeatureCollection\",\n  \"features\": [\n    {\n      \"type\": \"Feature\",\n      \"properties\": { \"name\": \"Afghanist"
  },
  {
    "path": "public/intl/country/am-ET.json",
    "chars": 11765,
    "preview": "{\n  \"HU\": \"\\u1200\\u1295\\u130b\\u122a\",\n  \"HT\": \"\\u1200\\u12ed\\u1272\",\n  \"IN\": \"\\u1205\\u1295\\u12f5\",\n  \"HN\": \"\\u1206\\u1295\\"
  },
  {
    "path": "public/intl/country/ar-SA.json",
    "chars": 16464,
    "preview": "{\n  \"IS\": \"\\u0622\\u064a\\u0633\\u0644\\u0646\\u062f\\u0627\",\n  \"ET\": \"\\u0625\\u062b\\u064a\\u0648\\u0628\\u064a\\u0627\",\n  \"AZ\": \"\\"
  },
  {
    "path": "public/intl/country/be-BY.json",
    "chars": 17873,
    "preview": "{\n  \"AE\": \"\\u0410\\u0431\\u2019\\u044f\\u0434\\u043d\\u0430\\u043d\\u044b\\u044f \\u0410\\u0440\\u0430\\u0431\\u0441\\u043a\\u0456\\u044f"
  },
  {
    "path": "public/intl/country/bg-BG.json",
    "chars": 17343,
    "preview": "{\n  \"AU\": \"\\u0410\\u0432\\u0441\\u0442\\u0440\\u0430\\u043b\\u0438\\u044f\",\n  \"AT\": \"\\u0410\\u0432\\u0441\\u0442\\u0440\\u0438\\u044f\""
  },
  {
    "path": "public/intl/country/bn-BD.json",
    "chars": 18852,
    "preview": "{\n  \"AT\": \"\\u0985\\u09b8\\u09cd\\u099f\\u09cd\\u09b0\\u09bf\\u09af\\u09bc\\u09be\",\n  \"AU\": \"\\u0985\\u09b8\\u09cd\\u099f\\u09cd\\u09b0\\"
  },
  {
    "path": "public/intl/country/bs-BA.json",
    "chars": 5734,
    "preview": "{\n  \"AF\": \"Afganistan\",\n  \"AL\": \"Albanija\",\n  \"DZ\": \"Al\\u017eir\",\n  \"VI\": \"Ameri\\u010dka Djevi\\u010danska ostrva\",\n  \"AS"
  },
  {
    "path": "public/intl/country/ca-ES.json",
    "chars": 5972,
    "preview": "{\n  \"AF\": \"Afganistan\",\n  \"AL\": \"Alb\\u00e0nia\",\n  \"DE\": \"Alemanya\",\n  \"DZ\": \"Alg\\u00e8ria\",\n  \"AD\": \"Andorra\",\n  \"AO\": \""
  },
  {
    "path": "public/intl/country/cs-CZ.json",
    "chars": 6364,
    "preview": "{\n  \"AF\": \"Afgh\\u00e1nist\\u00e1n\",\n  \"AX\": \"\\u00c5landy\",\n  \"AL\": \"Alb\\u00e1nie\",\n  \"DZ\": \"Al\\u017e\\u00edrsko\",\n  \"AS\": "
  },
  {
    "path": "public/intl/country/da-DK.json",
    "chars": 5627,
    "preview": "{\n  \"AF\": \"Afghanistan\",\n  \"AL\": \"Albanien\",\n  \"DZ\": \"Algeriet\",\n  \"AS\": \"Amerikansk Samoa\",\n  \"UM\": \"Amerikanske overs\\"
  },
  {
    "path": "public/intl/country/de-CH.json",
    "chars": 5738,
    "preview": "{\n  \"AF\": \"Afghanistan\",\n  \"EG\": \"\\u00c4gypten\",\n  \"AX\": \"\\u00c5landinseln\",\n  \"AL\": \"Albanien\",\n  \"DZ\": \"Algerien\",\n  \""
  },
  {
    "path": "public/intl/country/de-DE.json",
    "chars": 5754,
    "preview": "{\n  \"AF\": \"Afghanistan\",\n  \"EG\": \"\\u00c4gypten\",\n  \"AX\": \"\\u00c5landinseln\",\n  \"AL\": \"Albanien\",\n  \"DZ\": \"Algerien\",\n  \""
  },
  {
    "path": "public/intl/country/el-GR.json",
    "chars": 18166,
    "preview": "{\n  \"SH\": \"\\u0391\\u03b3\\u03af\\u03b1 \\u0395\\u03bb\\u03ad\\u03bd\\u03b7\",\n  \"LC\": \"\\u0391\\u03b3\\u03af\\u03b1 \\u039b\\u03bf\\u03c"
  },
  {
    "path": "public/intl/country/en-GB.json",
    "chars": 5468,
    "preview": "{\n  \"AF\": \"Afghanistan\",\n  \"AX\": \"\\u00c5land Islands\",\n  \"AL\": \"Albania\",\n  \"DZ\": \"Algeria\",\n  \"AS\": \"American Samoa\",\n "
  },
  {
    "path": "public/intl/country/en-US.json",
    "chars": 5468,
    "preview": "{\n  \"AF\": \"Afghanistan\",\n  \"AX\": \"\\u00c5land Islands\",\n  \"AL\": \"Albania\",\n  \"DZ\": \"Algeria\",\n  \"AS\": \"American Samoa\",\n "
  },
  {
    "path": "public/intl/country/es-ES.json",
    "chars": 5816,
    "preview": "{\n  \"AF\": \"Afganist\\u00e1n\",\n  \"AL\": \"Albania\",\n  \"DE\": \"Alemania\",\n  \"AD\": \"Andorra\",\n  \"AO\": \"Angola\",\n  \"AI\": \"Anguil"
  },
  {
    "path": "public/intl/country/es-MX.json",
    "chars": 5808,
    "preview": "{\n  \"AF\": \"Afganist\\u00e1n\",\n  \"AL\": \"Albania\",\n  \"DE\": \"Alemania\",\n  \"AD\": \"Andorra\",\n  \"AO\": \"Angola\",\n  \"AI\": \"Anguil"
  },
  {
    "path": "public/intl/country/fa-IR.json",
    "chars": 15222,
    "preview": "{\n  \"AR\": \"\\u0622\\u0631\\u0698\\u0627\\u0646\\u062a\\u06cc\\u0646\",\n  \"AW\": \"\\u0622\\u0631\\u0648\\u0628\\u0627\",\n  \"AL\": \"\\u0622\\"
  },
  {
    "path": "public/intl/country/fi-FI.json",
    "chars": 5650,
    "preview": "{\n  \"AF\": \"Afganistan\",\n  \"AX\": \"Ahvenanmaa\",\n  \"NL\": \"Alankomaat\",\n  \"AL\": \"Albania\",\n  \"DZ\": \"Algeria\",\n  \"AS\": \"Ameri"
  },
  {
    "path": "public/intl/country/fo-FO.json",
    "chars": 5737,
    "preview": "{\n  \"AF\": \"Afganistan\",\n  \"AX\": \"\\u00c1land\",\n  \"AL\": \"Albania\",\n  \"DZ\": \"Algeria\",\n  \"AS\": \"Amerikanska Samoa\",\n  \"AD\":"
  },
  {
    "path": "public/intl/country/fr-FR.json",
    "chars": 6138,
    "preview": "{\n  \"AF\": \"Afghanistan\",\n  \"ZA\": \"Afrique du Sud\",\n  \"AL\": \"Albanie\",\n  \"DZ\": \"Alg\\u00e9rie\",\n  \"DE\": \"Allemagne\",\n  \"AD"
  },
  {
    "path": "public/intl/country/he-IL.json",
    "chars": 15350,
    "preview": "{\n  \"UG\": \"\\u05d0\\u05d5\\u05d2\\u05e0\\u05d3\\u05d4\",\n  \"UZ\": \"\\u05d0\\u05d5\\u05d6\\u05d1\\u05e7\\u05d9\\u05e1\\u05d8\\u05df\",\n  \"A"
  },
  {
    "path": "public/intl/country/hi-IN.json",
    "chars": 17534,
    "preview": "{\n  \"AO\": \"\\u0905\\u0902\\u0917\\u094b\\u0932\\u093e\",\n  \"AQ\": \"\\u0905\\u0902\\u091f\\u093e\\u0930\\u094d\\u0915\\u091f\\u093f\\u0915\\"
  },
  {
    "path": "public/intl/country/hr-HR.json",
    "chars": 5779,
    "preview": "{\n  \"AF\": \"Afganistan\",\n  \"AX\": \"\\u00c5landski otoci\",\n  \"AL\": \"Albanija\",\n  \"DZ\": \"Al\\u017eir\",\n  \"AS\": \"Ameri\\u010dka "
  },
  {
    "path": "public/intl/country/hu-HU.json",
    "chars": 6480,
    "preview": "{\n  \"AF\": \"Afganiszt\\u00e1n\",\n  \"AX\": \"\\u00c5land-szigetek\",\n  \"AL\": \"Alb\\u00e1nia\",\n  \"DZ\": \"Alg\\u00e9ria\",\n  \"AS\": \"Am"
  },
  {
    "path": "public/intl/country/id-ID.json",
    "chars": 5520,
    "preview": "{\n  \"AF\": \"Afganistan\",\n  \"ZA\": \"Afrika Selatan\",\n  \"AL\": \"Albania\",\n  \"DZ\": \"Aljazair\",\n  \"US\": \"Amerika Serikat\",\n  \"A"
  },
  {
    "path": "public/intl/country/it-IT.json",
    "chars": 5545,
    "preview": "{\n  \"AF\": \"Afghanistan\",\n  \"AL\": \"Albania\",\n  \"DZ\": \"Algeria\",\n  \"UM\": \"Altre isole americane del Pacifico\",\n  \"AD\": \"An"
  },
  {
    "path": "public/intl/country/ja-JP.json",
    "chars": 11262,
    "preview": "{\n  \"IS\": \"\\u30a2\\u30a4\\u30b9\\u30e9\\u30f3\\u30c9\",\n  \"IE\": \"\\u30a2\\u30a4\\u30eb\\u30e9\\u30f3\\u30c9\",\n  \"AZ\": \"\\u30a2\\u30bc\\"
  },
  {
    "path": "public/intl/country/km-KH.json",
    "chars": 18001,
    "preview": "{\n  \"KH\": \"\\u1780\\u1798\\u17d2\\u1796\\u17bb\\u1787\\u17b6\",\n  \"CA\": \"\\u1780\\u17b6\\u178e\\u17b6\\u178a\\u17b6\",\n  \"QA\": \"\\u1780\\"
  },
  {
    "path": "public/intl/country/ko-KR.json",
    "chars": 9451,
    "preview": "{\n  \"GH\": \"\\uac00\\ub098\",\n  \"GA\": \"\\uac00\\ubd09\",\n  \"GY\": \"\\uac00\\uc774\\uc544\\ub098\",\n  \"GM\": \"\\uac10\\ube44\\uc544\",\n  \"G"
  },
  {
    "path": "public/intl/country/lt-LT.json",
    "chars": 6225,
    "preview": "{\n  \"AF\": \"Afganistanas\",\n  \"IE\": \"Airija\",\n  \"AX\": \"Aland\\u0173 Salos\",\n  \"AL\": \"Albanija\",\n  \"DZ\": \"Al\\u017eyras\",\n  \""
  },
  {
    "path": "public/intl/country/mn-MN.json",
    "chars": 16782,
    "preview": "{\n  \"AU\": \"\\u0410\\u0432\\u0441\\u0442\\u0440\\u0430\\u043b\\u0438\",\n  \"AT\": \"\\u0410\\u0432\\u0441\\u0442\\u0440\\u0438\",\n  \"AZ\": \"\\"
  },
  {
    "path": "public/intl/country/ms-MY.json",
    "chars": 5473,
    "preview": "{\n  \"AF\": \"Afghanistan\",\n  \"ZA\": \"Afrika Selatan\",\n  \"AL\": \"Albania\",\n  \"DZ\": \"Algeria\",\n  \"US\": \"Amerika Syarikat\",\n  \""
  },
  {
    "path": "public/intl/country/my-MM.json",
    "chars": 19326,
    "preview": "{\n  \"CA\": \"\\u1000\\u1014\\u1031\\u1012\\u102b\",\n  \"KG\": \"\\u1000\\u102c\\u1002\\u103b\\u1005\\u1039\\u1005\\u1010\\u1014\\u103a\",\n  \"K"
  },
  {
    "path": "public/intl/country/nb-NO.json",
    "chars": 5557,
    "preview": "{\n  \"AF\": \"Afghanistan\",\n  \"AL\": \"Albania\",\n  \"DZ\": \"Algerie\",\n  \"AS\": \"Amerikansk Samoa\",\n  \"AD\": \"Andorra\",\n  \"AO\": \"A"
  },
  {
    "path": "public/intl/country/nl-NL.json",
    "chars": 5762,
    "preview": "{\n  \"AF\": \"Afghanistan\",\n  \"AX\": \"\\u00c5land\",\n  \"AL\": \"Albani\\u00eb\",\n  \"DZ\": \"Algerije\",\n  \"AS\": \"Amerikaans-Samoa\",\n "
  },
  {
    "path": "public/intl/country/pl-PL.json",
    "chars": 5777,
    "preview": "{\n  \"AF\": \"Afganistan\",\n  \"AL\": \"Albania\",\n  \"DZ\": \"Algieria\",\n  \"AD\": \"Andora\",\n  \"AO\": \"Angola\",\n  \"AI\": \"Anguilla\",\n "
  },
  {
    "path": "public/intl/country/pt-BR.json",
    "chars": 6108,
    "preview": "{\n  \"AF\": \"Afeganist\\u00e3o\",\n  \"ZA\": \"\\u00c1frica do Sul\",\n  \"AL\": \"Alb\\u00e2nia\",\n  \"DE\": \"Alemanha\",\n  \"AD\": \"Andorra"
  },
  {
    "path": "public/intl/country/pt-PT.json",
    "chars": 6195,
    "preview": "{\n  \"AF\": \"Afeganist\\u00e3o\",\n  \"ZA\": \"\\u00c1frica do Sul\",\n  \"AX\": \"Alanda\",\n  \"AL\": \"Alb\\u00e2nia\",\n  \"DE\": \"Alemanha\""
  },
  {
    "path": "public/intl/country/ro-RO.json",
    "chars": 5836,
    "preview": "{\n  \"AF\": \"Afganistan\",\n  \"ZA\": \"Africa de Sud\",\n  \"AL\": \"Albania\",\n  \"DZ\": \"Algeria\",\n  \"AD\": \"Andorra\",\n  \"AO\": \"Angol"
  },
  {
    "path": "public/intl/country/ru-RU.json",
    "chars": 17150,
    "preview": "{\n  \"AU\": \"\\u0410\\u0432\\u0441\\u0442\\u0440\\u0430\\u043b\\u0438\\u044f\",\n  \"AT\": \"\\u0410\\u0432\\u0441\\u0442\\u0440\\u0438\\u044f\""
  },
  {
    "path": "public/intl/country/si-LK.json",
    "chars": 18395,
    "preview": "{\n  \"IE\": \"\\u0d85\\u0dba\\u0dbb\\u0dca\\u0dbd\\u0db1\\u0dca\\u0dad\\u0dba\",\n  \"IM\": \"\\u0d85\\u0dba\\u0dd2\\u0dbd\\u0dca \\u0d94\\u0dc6"
  },
  {
    "path": "public/intl/country/sk-SK.json",
    "chars": 6371,
    "preview": "{\n  \"AF\": \"Afganistan\",\n  \"AX\": \"Alandy\",\n  \"AL\": \"Alb\\u00e1nsko\",\n  \"DZ\": \"Al\\u017e\\u00edrsko\",\n  \"AS\": \"Americk\\u00e1 "
  },
  {
    "path": "public/intl/country/sl-SI.json",
    "chars": 5883,
    "preview": "{\n  \"AF\": \"Afganistan\",\n  \"AX\": \"\\u00c5landski otoki\",\n  \"AL\": \"Albanija\",\n  \"DZ\": \"Al\\u017eirija\",\n  \"AS\": \"Ameri\\u0161"
  },
  {
    "path": "public/intl/country/sv-SE.json",
    "chars": 5584,
    "preview": "{\n  \"AF\": \"Afghanistan\",\n  \"AL\": \"Albanien\",\n  \"DZ\": \"Algeriet\",\n  \"VI\": \"Amerikanska Jungfru\\u00f6arna\",\n  \"AS\": \"Ameri"
  },
  {
    "path": "public/intl/country/ta-IN.json",
    "chars": 18855,
    "preview": "{\n  \"AI\": \"\\u0b85\\u0b99\\u0bcd\\u0b95\\u0bbf\\u0baf\\u0bc1\\u0bb2\\u0bbe\",\n  \"AO\": \"\\u0b85\\u0b99\\u0bcd\\u0b95\\u0bcb\\u0bb2\\u0bbe\""
  },
  {
    "path": "public/intl/country/th-TH.json",
    "chars": 18245,
    "preview": "{\n  \"GR\": \"\\u0e01\\u0e23\\u0e35\\u0e0b\",\n  \"GL\": \"\\u0e01\\u0e23\\u0e35\\u0e19\\u0e41\\u0e25\\u0e19\\u0e14\\u0e4c\",\n  \"GU\": \"\\u0e01\\"
  },
  {
    "path": "public/intl/country/tr-TR.json",
    "chars": 5933,
    "preview": "{\n  \"UM\": \"ABD K\\u00fc\\u00e7\\u00fck Harici Adalar\\u0131\",\n  \"VI\": \"ABD Virjin Adalar\\u0131\",\n  \"AF\": \"Afganistan\",\n  \"AX"
  },
  {
    "path": "public/intl/country/uk-UA.json",
    "chars": 17812,
    "preview": "{\n  \"AU\": \"\\u0410\\u0432\\u0441\\u0442\\u0440\\u0430\\u043b\\u0456\\u044f\",\n  \"AT\": \"\\u0410\\u0432\\u0441\\u0442\\u0440\\u0456\\u044f\""
  },
  {
    "path": "public/intl/country/ur-PK.json",
    "chars": 15452,
    "preview": "{\n  \"IT\": \"\\u0627\\u0679\\u0644\\u06cc\",\n  \"AR\": \"\\u0627\\u0631\\u062c\\u0646\\u0679\\u06cc\\u0646\\u0627\",\n  \"JO\": \"\\u0627\\u0631\\"
  },
  {
    "path": "public/intl/country/uz-UZ.json",
    "chars": 5673,
    "preview": "{\n  \"AF\": \"Afg\\u02bboniston\",\n  \"AX\": \"Aland orollari\",\n  \"AL\": \"Albaniya\",\n  \"US\": \"Amerika Qo\\u2018shma Shtatlari\",\n  "
  },
  {
    "path": "public/intl/country/vi-VN.json",
    "chars": 6345,
    "preview": "{\n  \"SA\": \"\\u1ea2 R\\u1eadp X\\u00ea-\\u00fat\",\n  \"AF\": \"Afghanistan\",\n  \"EG\": \"Ai C\\u1eadp\",\n  \"AL\": \"Albania\",\n  \"DZ\": \"A"
  },
  {
    "path": "public/intl/country/zh-CN.json",
    "chars": 8775,
    "preview": "{\n  \"AL\": \"\\u963f\\u5c14\\u5df4\\u5c3c\\u4e9a\",\n  \"DZ\": \"\\u963f\\u5c14\\u53ca\\u5229\\u4e9a\",\n  \"AF\": \"\\u963f\\u5bcc\\u6c57\",\n  \"A"
  },
  {
    "path": "public/intl/country/zh-TW.json",
    "chars": 8679,
    "preview": "{\n  \"TT\": \"\\u5343\\u91cc\\u9054\\u53ca\\u6258\\u5df4\\u54e5\",\n  \"TR\": \"\\u571f\\u8033\\u5176\",\n  \"TC\": \"\\u571f\\u514b\\u65af\\u53ca\\"
  },
  {
    "path": "public/intl/language/am-ET.json",
    "chars": 18493,
    "preview": "{\n  \"hu\": \"\\u1200\\u1295\\u130b\\u122a\\u129b\",\n  \"haw\": \"\\u1203\\u12ca\\u12eb\\u129b\",\n  \"ha\": \"\\u1203\\u12cd\\u1233\\u129b\",\n  \""
  },
  {
    "path": "public/intl/language/ar-SA.json",
    "chars": 37441,
    "preview": "{\n  \"bss\": \"\\u0623\\u0643\\u0648\\u0633\",\n  \"arc\": \"\\u0627\\u0644\\u0622\\u0631\\u0627\\u0645\\u064a\\u0629\",\n  \"sam\": \"\\u0627\\u06"
  },
  {
    "path": "public/intl/language/be-BY.json",
    "chars": 19536,
    "preview": "{\n  \"ab\": \"\\u0430\\u0431\\u0445\\u0430\\u0437\\u0441\\u043a\\u0430\\u044f\",\n  \"av\": \"\\u0430\\u0432\\u0430\\u0440\\u0441\\u043a\\u0430\\"
  },
  {
    "path": "public/intl/language/bg-BG.json",
    "chars": 32661,
    "preview": "{\n  \"ab\": \"\\u0430\\u0431\\u0445\\u0430\\u0437\\u043a\\u0438\",\n  \"awa\": \"\\u0430\\u0432\\u0430\\u0434\\u0438\",\n  \"av\": \"\\u0430\\u0432"
  },
  {
    "path": "public/intl/language/bn-BD.json",
    "chars": 32498,
    "preview": "{\n  \"oc\": \"\\u0985\\u0995\\u09cd\\u09b8\\u09bf\\u099f\\u09be\\u09a8\",\n  \"und\": \"\\u0985\\u099c\\u09be\\u09a8\\u09be \\u09ad\\u09be\\u09b"
  },
  {
    "path": "public/intl/language/bs-BA.json",
    "chars": 13563,
    "preview": "{\n  \"ab\": \"abhazijski\",\n  \"ace\": \"a\\u010dineski\",\n  \"ada\": \"adangmejski\",\n  \"ady\": \"adigejski\",\n  \"aa\": \"afarski\",\n  \"af"
  },
  {
    "path": "public/intl/language/ca-ES.json",
    "chars": 13552,
    "preview": "{\n  \"ab\": \"abkhaz\",\n  \"akk\": \"accadi\",\n  \"ach\": \"acoli\",\n  \"ada\": \"adangme\",\n  \"ady\": \"adigu\\u00e9\",\n  \"aa\": \"\\u00e0far\""
  },
  {
    "path": "public/intl/language/cs-CZ.json",
    "chars": 18304,
    "preview": "{\n  \"ab\": \"abch\\u00e1z\\u0161tina\",\n  \"ace\": \"aceh\\u0161tina\",\n  \"ada\": \"adangme\",\n  \"ady\": \"adygej\\u0161tina\",\n  \"aa\": \""
  },
  {
    "path": "public/intl/language/da-DK.json",
    "chars": 12818,
    "preview": "{\n  \"ab\": \"abkhasisk\",\n  \"ace\": \"achinesisk\",\n  \"ach\": \"acoli\",\n  \"ada\": \"adangme\",\n  \"ady\": \"adyghe\",\n  \"aa\": \"afar\",\n "
  },
  {
    "path": "public/intl/language/de-CH.json",
    "chars": 14236,
    "preview": "{\n  \"ab\": \"Abchasisch\",\n  \"ace\": \"Aceh-Sprache\",\n  \"ach\": \"Acholi-Sprache\",\n  \"ada\": \"Adangme\",\n  \"ady\": \"Adygeisch\",\n  "
  },
  {
    "path": "public/intl/language/de-DE.json",
    "chars": 14244,
    "preview": "{\n  \"ab\": \"Abchasisch\",\n  \"ace\": \"Aceh-Sprache\",\n  \"ach\": \"Acholi-Sprache\",\n  \"ada\": \"Adangme\",\n  \"ady\": \"Adygeisch\",\n  "
  },
  {
    "path": "public/intl/language/el-GR.json",
    "chars": 35057,
    "preview": "{\n  \"av\": \"\\u0386\\u03b2\\u03b1\\u03c1\\u03b9\\u03ba\",\n  \"ae\": \"\\u0391\\u03b2\\u03b5\\u03c3\\u03c4\\u03ac\\u03bd\",\n  \"en\": \"\\u0391\\"
  },
  {
    "path": "public/intl/language/en-GB.json",
    "chars": 12704,
    "preview": "{\n  \"ab\": \"Abkhazian\",\n  \"ace\": \"Achinese\",\n  \"ach\": \"Acoli\",\n  \"ada\": \"Adangme\",\n  \"ady\": \"Adyghe\",\n  \"aa\": \"Afar\",\n  \""
  },
  {
    "path": "public/intl/language/en-US.json",
    "chars": 3916,
    "preview": "{\n  \"ab\": \"Abkhaz\",\n  \"aa\": \"Afar\",\n  \"af\": \"Afrikaans\",\n  \"ak\": \"Akan\",\n  \"sq\": \"Albanian\",\n  \"am\": \"Amharic\",\n  \"ar\": "
  },
  {
    "path": "public/intl/language/es-ES.json",
    "chars": 13497,
    "preview": "{\n  \"ab\": \"abjasio\",\n  \"akk\": \"acadio\",\n  \"ace\": \"acehn\\u00e9s\",\n  \"ach\": \"acoli\",\n  \"ada\": \"adangme\",\n  \"ady\": \"adigeo\""
  },
  {
    "path": "public/intl/language/es-MX.json",
    "chars": 13498,
    "preview": "{\n  \"ab\": \"abjasio\",\n  \"akk\": \"acadio\",\n  \"ace\": \"acehn\\u00e9s\",\n  \"ach\": \"acoli\",\n  \"ada\": \"adangme\",\n  \"ady\": \"adigeo\""
  },
  {
    "path": "public/intl/language/fa-IR.json",
    "chars": 31216,
    "preview": "{\n  \"ab\": \"\\u0622\\u0628\\u062e\\u0627\\u0632\\u06cc\",\n  \"ace\": \"\\u0622\\u0686\\u0626\\u06cc\",\n  \"ach\": \"\\u0622\\u0686\\u0648\\u064"
  },
  {
    "path": "public/intl/language/fi-FI.json",
    "chars": 12832,
    "preview": "{\n  \"ab\": \"abhaasi\",\n  \"ada\": \"adangme\",\n  \"ady\": \"adyge\",\n  \"aa\": \"afar\",\n  \"afh\": \"afrihili\",\n  \"af\": \"afrikaans\",\n  \""
  },
  {
    "path": "public/intl/language/fo-FO.json",
    "chars": 12936,
    "preview": "{\n  \"ab\": \"abkhaziskt\",\n  \"ace\": \"Achinese\",\n  \"ach\": \"Acoli\",\n  \"ada\": \"Adangme\",\n  \"ady\": \"Adyghe\",\n  \"aa\": \"Afar\",\n  "
  },
  {
    "path": "public/intl/language/fr-FR.json",
    "chars": 13297,
    "preview": "{\n  \"ab\": \"abkhaze\",\n  \"ace\": \"aceh\",\n  \"ach\": \"acoli\",\n  \"ada\": \"adangme\",\n  \"ady\": \"adygh\\u00e9en\",\n  \"aa\": \"afar\",\n  "
  },
  {
    "path": "public/intl/language/he-IL.json",
    "chars": 29907,
    "preview": "{\n  \"av\": \"\\u05d0\\u05d1\\u05d0\\u05e8\\u05d9\\u05ea\",\n  \"ab\": \"\\u05d0\\u05d1\\u05d7\\u05d6\\u05d9\\u05ea\",\n  \"ae\": \"\\u05d0\\u05d1\\"
  },
  {
    "path": "public/intl/language/hi-IN.json",
    "chars": 30975,
    "preview": "{\n  \"anp\": \"\\u0905\\u0902\\u0917\\u093f\\u0915\\u093e\",\n  \"en\": \"\\u0905\\u0902\\u0917\\u094d\\u0930\\u0947\\u091c\\u093c\\u0940\",\n  \""
  },
  {
    "path": "public/intl/language/hr-HR.json",
    "chars": 13468,
    "preview": "{\n  \"ab\": \"abhaski\",\n  \"ace\": \"achinese\",\n  \"ach\": \"acoli\",\n  \"ada\": \"adangme\",\n  \"ady\": \"adigejski\",\n  \"aa\": \"afarski\","
  },
  {
    "path": "public/intl/language/hu-HU.json",
    "chars": 13578,
    "preview": "{\n  \"ab\": \"abh\\u00e1z\",\n  \"ace\": \"achin\\u00e9z\",\n  \"ada\": \"adangme\",\n  \"ady\": \"adyghe\",\n  \"aa\": \"afar\",\n  \"afh\": \"afrihi"
  },
  {
    "path": "public/intl/language/id-ID.json",
    "chars": 12544,
    "preview": "{\n  \"ab\": \"Abkhaz\",\n  \"ace\": \"Aceh\",\n  \"ach\": \"Acoli\",\n  \"ada\": \"Adangme\",\n  \"ady\": \"Adygei\",\n  \"aa\": \"Afar\",\n  \"afh\": \""
  },
  {
    "path": "public/intl/language/it-IT.json",
    "chars": 12831,
    "preview": "{\n  \"ab\": \"abcaso\",\n  \"akk\": \"accado\",\n  \"ace\": \"accinese\",\n  \"ach\": \"acioli\",\n  \"ada\": \"adangme\",\n  \"ady\": \"adyghe\",\n  "
  },
  {
    "path": "public/intl/language/ja-JP.json",
    "chars": 27845,
    "preview": "{\n  \"de_AT\": \"Austrian German\",\n  \"bar\": \"Bavarian\",\n  \"pt_BR\": \"Brazilian Portuguese\",\n  \"fr_CA\": \"Canadian French\",\n  "
  },
  {
    "path": "public/intl/language/km-KH.json",
    "chars": 19435,
    "preview": "{\n  \"kn\": \"\\u1780\\u1793\\u17d2\\u1793\\u178a\",\n  \"ca\": \"\\u1780\\u17b6\\u178f\\u17b6\\u17a1\\u17b6\\u1793\",\n  \"ks\": \"\\u1780\\u17b6\\"
  },
  {
    "path": "public/intl/language/ko-KR.json",
    "chars": 22933,
    "preview": "{\n  \"gag\": \"\\uac00\\uac00\\uc6b0\\uc2a4\\uc5b4\",\n  \"gaa\": \"\\uac00\\uc5b4\",\n  \"gay\": \"\\uac00\\uc694\\uc5b4\",\n  \"lg\": \"\\uac04\\ub2"
  },
  {
    "path": "public/intl/language/lt-LT.json",
    "chars": 16058,
    "preview": "{\n  \"zbl\": \"\\u201eBliss\\u201c simboli\\u0173\",\n  \"ab\": \"abchaz\\u0173\",\n  \"ace\": \"a\\u010dinez\\u0173\",\n  \"ada\": \"adangm\\u01"
  },
  {
    "path": "public/intl/language/mn-MN.json",
    "chars": 20221,
    "preview": "{\n  \"ab\": \"\\u0430\\u0431\\u0445\\u0430\\u0437\",\n  \"en_AU\": \"\\u0430\\u0432\\u0441\\u0442\\u0440\\u0430\\u043b\\u0438 \\u0430\\u043d\\u0"
  },
  {
    "path": "public/intl/language/ms-MY.json",
    "chars": 12596,
    "preview": "{\n  \"ab\": \"Abkhazia\",\n  \"ace\": \"Achinese\",\n  \"ada\": \"Adangme\",\n  \"ady\": \"Adyghe\",\n  \"aa\": \"Afar\",\n  \"afh\": \"Afrihili\",\n "
  },
  {
    "path": "public/intl/language/my-MM.json",
    "chars": 24360,
    "preview": "{\n  \"kac\": \"\\u1000\\u1001\\u103b\\u1004\\u103a\",\n  \"fr_CA\": \"\\u1000\\u1014\\u1031\\u1012\\u102b \\u1015\\u103c\\u1004\\u103a\\u101e\\u"
  },
  {
    "path": "public/intl/language/nb-NO.json",
    "chars": 12912,
    "preview": "{\n  \"ab\": \"abkhasisk\",\n  \"ace\": \"achinesisk\",\n  \"ach\": \"acoli\",\n  \"ada\": \"adangme\",\n  \"ady\": \"adyghe\",\n  \"aa\": \"afar\",\n "
  },
  {
    "path": "public/intl/language/nl-NL.json",
    "chars": 12901,
    "preview": "{\n  \"ab\": \"Abchazisch\",\n  \"ada\": \"Adangme\",\n  \"ady\": \"Adygees\",\n  \"om\": \"Afaan Oromo\",\n  \"aa\": \"Afar\",\n  \"afh\": \"Afrihil"
  },
  {
    "path": "public/intl/language/pl-PL.json",
    "chars": 13943,
    "preview": "{\n  \"ab\": \"abchaski\",\n  \"ace\": \"aceh\",\n  \"ach\": \"aczoli\",\n  \"ada\": \"adangme\",\n  \"ady\": \"adygejski\",\n  \"aa\": \"afar\",\n  \"a"
  },
  {
    "path": "public/intl/language/pt-BR.json",
    "chars": 13543,
    "preview": "{\n  \"ab\": \"abc\\u00e1zio\",\n  \"akk\": \"acadiano\",\n  \"ace\": \"ach\\u00e9m\",\n  \"ach\": \"acoli\",\n  \"ada\": \"adangme\",\n  \"ady\": \"ad"
  },
  {
    "path": "public/intl/language/pt-PT.json",
    "chars": 13533,
    "preview": "{\n  \"ab\": \"abc\\u00e1zio\",\n  \"akk\": \"acadiano\",\n  \"ace\": \"ach\\u00e9m\",\n  \"ach\": \"acoli\",\n  \"ada\": \"adangme\",\n  \"ady\": \"ad"
  },
  {
    "path": "public/intl/language/ro-RO.json",
    "chars": 14138,
    "preview": "{\n  \"ab\": \"abhaz\\u0103\",\n  \"ace\": \"aceh\",\n  \"ach\": \"acoli\",\n  \"ada\": \"adangme\",\n  \"ady\": \"adyghe\",\n  \"aa\": \"afar\",\n  \"af"
  },
  {
    "path": "public/intl/language/ru-RU.json",
    "chars": 36297,
    "preview": "{\n  \"ab\": \"\\u0430\\u0431\\u0445\\u0430\\u0437\\u0441\\u043a\\u0438\\u0439\",\n  \"awa\": \"\\u0430\\u0432\\u0430\\u0434\\u0445\\u0438\",\n  \""
  },
  {
    "path": "public/intl/language/si-LK.json",
    "chars": 21908,
    "preview": "{\n  \"ak\": \"\\u0d85\\u0d9a\\u0dcf\\u0db1\\u0dca\",\n  \"af\": \"\\u0d85\\u0db4\\u0dca\\u200d\\u0dbb\\u0dd2\\u0d9a\\u0dcf\\u0db1\\u0dd4\",\n  \"g"
  },
  {
    "path": "public/intl/language/sk-SK.json",
    "chars": 16585,
    "preview": "{\n  \"ab\": \"abch\\u00e1z\\u010dina\",\n  \"ace\": \"aceh\\u010dina\",\n  \"ach\": \"a\\u010doli\",\n  \"ada\": \"adangme\",\n  \"ady\": \"adyg\\u0"
  },
  {
    "path": "public/intl/language/sl-SI.json",
    "chars": 18452,
    "preview": "{\n  \"ab\": \"abha\\u0161\\u010dina\",\n  \"ace\": \"a\\u010dej\\u0161\\u010dina\",\n  \"ach\": \"a\\u010dolij\\u0161\\u010dina\",\n  \"ada\": \"a"
  },
  {
    "path": "public/intl/language/sv-SE.json",
    "chars": 13412,
    "preview": "{\n  \"ab\": \"abchaziska\",\n  \"ace\": \"acehnesiska\",\n  \"ach\": \"acholi\",\n  \"ada\": \"adangme\",\n  \"ady\": \"adygeiska\",\n  \"aa\": \"af"
  },
  {
    "path": "public/intl/language/ta-IN.json",
    "chars": 33409,
    "preview": "{\n  \"afh\": \"\\u0b85\\u0b83\\u0baa\\u0bcd\\u0bb0\\u0bbf\\u0bb9\\u0bbf\\u0bb2\\u0bbf\",\n  \"aa\": \"\\u0b85\\u0b83\\u0baa\\u0bbe\\u0bb0\\u0bcd"
  },
  {
    "path": "public/intl/language/th-TH.json",
    "chars": 34999,
    "preview": "{\n  \"gba\": \"\\u0e01\\u0e1a\\u0e32\\u0e22\\u0e32\",\n  \"bkm\": \"\\u0e01\\u0e21\",\n  \"el\": \"\\u0e01\\u0e23\\u0e35\\u0e01\",\n  \"grc\": \"\\u0e"
  },
  {
    "path": "public/intl/language/tr-TR.json",
    "chars": 14357,
    "preview": "{\n  \"ab\": \"Abhazca\",\n  \"ace\": \"Achinese\",\n  \"ach\": \"Acoli\",\n  \"ada\": \"Adangme\",\n  \"ady\": \"Adigece\",\n  \"aa\": \"Afar\",\n  \"a"
  },
  {
    "path": "public/intl/language/uk-UA.json",
    "chars": 34608,
    "preview": "{\n  \"ab\": \"\\u0430\\u0431\\u0445\\u0430\\u0437\\u044c\\u043a\\u0430\",\n  \"awa\": \"\\u0430\\u0432\\u0430\\u0434\\u0445\\u0456\",\n  \"av\": \""
  },
  {
    "path": "public/intl/language/ur-PK.json",
    "chars": 20890,
    "preview": "{\n  \"ab\": \"\\u0627\\u0628\\u0642\\u0627\\u0632\\u06cc\\u0627\\u0646\",\n  \"hsb\": \"\\u0627\\u067e\\u0631 \\u0633\\u0631\\u0628\\u06cc\\u062"
  },
  {
    "path": "public/intl/language/uz-UZ.json",
    "chars": 13227,
    "preview": "{\n  \"ab\": \"abxazcha\",\n  \"ace\": \"Achinese\",\n  \"ach\": \"Acoli\",\n  \"ada\": \"Adangme\",\n  \"ady\": \"Adyghe\",\n  \"aa\": \"Afar\",\n  \"a"
  },
  {
    "path": "public/intl/language/vi-VN.json",
    "chars": 18853,
    "preview": "{\n  \"akz\": \"Alabama\",\n  \"arq\": \"Algerian Arabic\",\n  \"ase\": \"American Sign Language\",\n  \"njo\": \"Ao Naga\",\n  \"aro\": \"Araon"
  },
  {
    "path": "public/intl/language/zh-CN.json",
    "chars": 21429,
    "preview": "{\n  \"ab\": \"\\u963f\\u5e03\\u54c8\\u897f\\u4e9a\\u6587\",\n  \"cch\": \"\\u963f\\u707f\\u6587\",\n  \"ada\": \"\\u963f\\u5f53\\u6885\\u6587\",\n  "
  },
  {
    "path": "public/intl/language/zh-TW.json",
    "chars": 21429,
    "preview": "{\n  \"din\": \"\\u4e01\\u5361\\u6587\",\n  \"hsb\": \"\\u4e0a\\u7d22\\u5e03\\u6587\",\n  \"dsb\": \"\\u4e0b\\u7d22\\u5e03\\u6587\",\n  \"tr\": \"\\u57"
  },
  {
    "path": "public/intl/messages/am-ET.json",
    "chars": 32516,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Access code\"\n    }\n  ],\n  \"label.actions\": [\n    {\n   "
  },
  {
    "path": "public/intl/messages/ar-SA.json",
    "chars": 32044,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"كود الدعوة\"\n    }\n  ],\n  \"label.actions\": [\n    {\n    "
  },
  {
    "path": "public/intl/messages/be-BY.json",
    "chars": 32933,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Код доступу\"\n    }\n  ],\n  \"label.actions\": [\n    {\n   "
  },
  {
    "path": "public/intl/messages/bg-BG.json",
    "chars": 33259,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Код за достъп\"\n    }\n  ],\n  \"label.actions\": [\n    {\n "
  },
  {
    "path": "public/intl/messages/bn-BD.json",
    "chars": 32785,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"এক্সেস কোড\"\n    }\n  ],\n  \"label.actions\": [\n    {\n    "
  },
  {
    "path": "public/intl/messages/bs-BA.json",
    "chars": 33000,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Pristupni kod\"\n    }\n  ],\n  \"label.actions\": [\n    {\n "
  },
  {
    "path": "public/intl/messages/ca-ES.json",
    "chars": 33177,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Codi d'accés\"\n    }\n  ],\n  \"label.actions\": [\n    {\n  "
  },
  {
    "path": "public/intl/messages/cs-CZ.json",
    "chars": 32509,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Přístupový kód\"\n    }\n  ],\n  \"label.actions\": [\n    {\n"
  },
  {
    "path": "public/intl/messages/da-DK.json",
    "chars": 32524,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Adgangskode\"\n    }\n  ],\n  \"label.actions\": [\n    {\n   "
  },
  {
    "path": "public/intl/messages/de-CH.json",
    "chars": 32876,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Zuegangscode\"\n    }\n  ],\n  \"label.actions\": [\n    {\n  "
  },
  {
    "path": "public/intl/messages/de-DE.json",
    "chars": 33169,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Zugangscode\"\n    }\n  ],\n  \"label.actions\": [\n    {\n   "
  },
  {
    "path": "public/intl/messages/el-GR.json",
    "chars": 32649,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Access code\"\n    }\n  ],\n  \"label.actions\": [\n    {\n   "
  },
  {
    "path": "public/intl/messages/en-GB.json",
    "chars": 32323,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Access code\"\n    }\n  ],\n  \"label.actions\": [\n    {\n   "
  },
  {
    "path": "public/intl/messages/en-US.json",
    "chars": 32515,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Access code\"\n    }\n  ],\n  \"label.actions\": [\n    {\n   "
  },
  {
    "path": "public/intl/messages/es-ES.json",
    "chars": 33280,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Código de acceso\"\n    }\n  ],\n  \"label.actions\": [\n    "
  },
  {
    "path": "public/intl/messages/es-MX.json",
    "chars": 21533,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Código de acceso\"\n    }\n  ],\n  \"label.actions\": [\n    "
  },
  {
    "path": "public/intl/messages/fa-IR.json",
    "chars": 32166,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"کد دسترسی\"\n    }\n  ],\n  \"label.actions\": [\n    {\n     "
  },
  {
    "path": "public/intl/messages/fi-FI.json",
    "chars": 32888,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Pääsykoodi\"\n    }\n  ],\n  \"label.actions\": [\n    {\n    "
  },
  {
    "path": "public/intl/messages/fo-FO.json",
    "chars": 32534,
    "preview": "{\n  \"label.access-code\": [\n    {\n      \"type\": 0,\n      \"value\": \"Aðgangskoda\"\n    }\n  ],\n  \"label.actions\": [\n    {\n   "
  }
]

// ... and 754 more files (download for full content)

About this extraction

This page contains the full source code of the umami-software/umami GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 954 files (5.4 MB), approximately 1.5M tokens, and a symbol index with 1364 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!