Switch to PostHog for app analytics (#2316)

This commit is contained in:
Geometrically
2024-08-27 21:19:07 -07:00
committed by GitHub
parent 38d95b4faf
commit bf16d360af
26 changed files with 222 additions and 199 deletions

View File

@@ -21,14 +21,15 @@
"@vintl/vintl": "^4.4.1", "@vintl/vintl": "^4.4.1",
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"floating-vue": "^5.2.2", "floating-vue": "^5.2.2",
"mixpanel-browser": "^2.49.0",
"ofetch": "^1.3.4", "ofetch": "^1.3.4",
"pinia": "^2.1.7", "pinia": "^2.1.7",
"vite-svg-loader": "^5.1.0", "vite-svg-loader": "^5.1.0",
"vue": "^3.4.21", "vue": "^3.4.21",
"vue-multiselect": "3.0.0", "vue-multiselect": "3.0.0",
"vue-router": "4.3.0", "vue-router": "4.3.0",
"vue-virtual-scroller": "v2.0.0-beta.8" "vue-virtual-scroller": "v2.0.0-beta.8",
"posthog-js": "^1.158.2",
"@sentry/vue": "^8.27.0"
}, },
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": "^2.0.0-rc", "@tauri-apps/cli": "^2.0.0-rc",

View File

@@ -17,16 +17,9 @@ import { command_listener, warning_listener } from '@/helpers/events.js'
import { MinimizeIcon, MaximizeIcon } from '@/assets/icons' import { MinimizeIcon, MaximizeIcon } from '@/assets/icons'
import { type } from '@tauri-apps/plugin-os' import { type } from '@tauri-apps/plugin-os'
import { isDev, getOS } from '@/helpers/utils.js' import { isDev, getOS } from '@/helpers/utils.js'
import { import { initAnalytics, debugAnalytics, optOutAnalytics, trackEvent } from '@/helpers/analytics'
mixpanel_track,
mixpanel_init,
mixpanel_opt_out_tracking,
mixpanel_is_loaded,
} from '@/helpers/mixpanel'
import { saveWindowState, StateFlags } from '@tauri-apps/plugin-window-state'
import { getCurrentWindow } from '@tauri-apps/api/window' import { getCurrentWindow } from '@tauri-apps/api/window'
import { getVersion } from '@tauri-apps/api/app' import { getVersion } from '@tauri-apps/api/app'
import { TauriEvent } from '@tauri-apps/api/event'
import URLConfirmModal from '@/components/ui/URLConfirmModal.vue' import URLConfirmModal from '@/components/ui/URLConfirmModal.vue'
import { install_from_file } from './helpers/pack' import { install_from_file } from './helpers/pack'
import { useError } from '@/store/error.js' import { useError } from '@/store/error.js'
@@ -90,11 +83,12 @@ async function setupApp() {
themeStore.collapsedNavigation = collapsed_navigation themeStore.collapsedNavigation = collapsed_navigation
themeStore.advancedRendering = advanced_rendering themeStore.advancedRendering = advanced_rendering
mixpanel_init('014c7d6a336d0efaefe3aca91063748d', { debug: dev, persistence: 'localStorage' }) initAnalytics()
if (!telemetry) { if (!telemetry) {
mixpanel_opt_out_tracking() optOutAnalytics()
} }
mixpanel_track('Launched', { version, dev, onboarded }) if (dev) debugAnalytics()
trackEvent('Launched', { version, dev, onboarded })
if (!dev) document.addEventListener('contextmenu', (event) => event.preventDefault()) if (!dev) document.addEventListener('contextmenu', (event) => event.preventDefault())
@@ -137,9 +131,7 @@ const handleClose = async () => {
const router = useRouter() const router = useRouter()
router.afterEach((to, from, failure) => { router.afterEach((to, from, failure) => {
if (mixpanel_is_loaded()) { trackEvent('PageView', { path: to.path, fromPath: from.path, failed: failure })
mixpanel_track('PageView', { path: to.path, fromPath: from.path, failed: failure })
}
}) })
const route = useRoute() const route = useRoute()
const isOnBrowse = computed(() => route.path.startsWith('/browse')) const isOnBrowse = computed(() => route.path.startsWith('/browse'))
@@ -214,7 +206,7 @@ async function handleCommand(e) {
// RunMRPack should directly install a local mrpack given a path // RunMRPack should directly install a local mrpack given a path
if (e.path.endsWith('.mrpack')) { if (e.path.endsWith('.mrpack')) {
await install_from_file(e.path).catch(handleError) await install_from_file(e.path).catch(handleError)
mixpanel_track('InstanceCreate', { trackEvent('InstanceCreate', {
source: 'CreationModalFileDrop', source: 'CreationModalFileDrop',
}) })
} }

View File

@@ -23,7 +23,7 @@ import { duplicate, kill, remove, run } from '@/helpers/profile.js'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { showProfileInFolder } from '@/helpers/utils.js' import { showProfileInFolder } from '@/helpers/utils.js'
import { useTheming } from '@/store/state.js' import { useTheming } from '@/store/state.js'
import { mixpanel_track } from '@/helpers/mixpanel' import { trackEvent } from '@/helpers/analytics'
import { handleSevereError } from '@/store/error.js' import { handleSevereError } from '@/store/error.js'
import { install as installVersion } from '@/store/install.js' import { install as installVersion } from '@/store/install.js'
@@ -125,14 +125,14 @@ const handleOptionsClick = async (args) => {
await run(args.item.path).catch((err) => await run(args.item.path).catch((err) =>
handleSevereError(err, { profilePath: args.item.path }), handleSevereError(err, { profilePath: args.item.path }),
) )
mixpanel_track('InstanceStart', { trackEvent('InstanceStart', {
loader: args.item.loader, loader: args.item.loader,
game_version: args.item.game_version, game_version: args.item.game_version,
}) })
break break
case 'stop': case 'stop':
await kill(args.item.path).catch(handleError) await kill(args.item.path).catch(handleError)
mixpanel_track('InstanceStop', { trackEvent('InstanceStop', {
loader: args.item.loader, loader: args.item.loader,
game_version: args.item.game_version, game_version: args.item.game_version,
}) })

View File

@@ -70,7 +70,7 @@ import {
get_default_user, get_default_user,
} from '@/helpers/auth' } from '@/helpers/auth'
import { handleError } from '@/store/state.js' import { handleError } from '@/store/state.js'
import { mixpanel_track } from '@/helpers/mixpanel' import { trackEvent } from '@/helpers/analytics'
import { process_listener } from '@/helpers/events' import { process_listener } from '@/helpers/events'
import { handleSevereError } from '@/store/error.js' import { handleSevereError } from '@/store/error.js'
@@ -118,7 +118,7 @@ async function login() {
await refreshValues() await refreshValues()
} }
mixpanel_track('AccountLogIn') trackEvent('AccountLogIn')
} }
const logout = async (id) => { const logout = async (id) => {
@@ -130,7 +130,7 @@ const logout = async (id) => {
} else { } else {
emit('change') emit('change')
} }
mixpanel_track('AccountLogOut') trackEvent('AccountLogOut')
} }
let showCard = ref(false) let showCard = ref(false)

View File

@@ -5,10 +5,10 @@ import { ChatIcon } from '@/assets/icons'
import { ref } from 'vue' import { ref } from 'vue'
import { login as login_flow, set_default_user } from '@/helpers/auth.js' import { login as login_flow, set_default_user } from '@/helpers/auth.js'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import mixpanel from 'mixpanel-browser'
import { handleSevereError } from '@/store/error.js' import { handleSevereError } from '@/store/error.js'
import { cancel_directory_change } from '@/helpers/settings.js' import { cancel_directory_change } from '@/helpers/settings.js'
import { install } from '@/helpers/profile.js' import { install } from '@/helpers/profile.js'
import { trackEvent } from '@/helpers/analytics'
const errorModal = ref() const errorModal = ref()
const error = ref() const error = ref()
@@ -85,7 +85,7 @@ async function loginMinecraft() {
await set_default_user(loggedIn.id).catch(handleError) await set_default_user(loggedIn.id).catch(handleError)
} }
await mixpanel.track('AccountLogIn') await trackEvent('AccountLogIn', { source: 'ErrorModal' })
loadingMinecraft.value = false loadingMinecraft.value = false
errorModal.value.hide() errorModal.value.hide()
} catch (err) { } catch (err) {

View File

@@ -9,8 +9,8 @@ import { get_by_profile_path } from '@/helpers/process'
import { process_listener } from '@/helpers/events' import { process_listener } from '@/helpers/events'
import { handleError } from '@/store/state.js' import { handleError } from '@/store/state.js'
import { showProfileInFolder } from '@/helpers/utils.js' import { showProfileInFolder } from '@/helpers/utils.js'
import { mixpanel_track } from '@/helpers/mixpanel'
import { handleSevereError } from '@/store/error.js' import { handleSevereError } from '@/store/error.js'
import { trackEvent } from '@/helpers/analytics'
const props = defineProps({ const props = defineProps({
instance: { instance: {
@@ -45,7 +45,7 @@ const play = async (e, context) => {
) )
modLoading.value = false modLoading.value = false
mixpanel_track('InstancePlay', { trackEvent('InstancePlay', {
loader: props.instance.loader, loader: props.instance.loader,
game_version: props.instance.game_version, game_version: props.instance.game_version,
source: context, source: context,
@@ -58,7 +58,7 @@ const stop = async (e, context) => {
await kill(props.instance.path).catch(handleError) await kill(props.instance.path).catch(handleError)
mixpanel_track('InstanceStop', { trackEvent('InstanceStop', {
loader: props.instance.loader, loader: props.instance.loader,
game_version: props.instance.game_version, game_version: props.instance.game_version,
source: context, source: context,

View File

@@ -216,7 +216,7 @@ import { convertFileSrc } from '@tauri-apps/api/core'
import { get_game_versions, get_loader_versions } from '@/helpers/metadata' import { get_game_versions, get_loader_versions } from '@/helpers/metadata'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import Multiselect from 'vue-multiselect' import Multiselect from 'vue-multiselect'
import { mixpanel_track } from '@/helpers/mixpanel' import { trackEvent } from '@/helpers/analytics'
import { useTheming } from '@/store/state.js' import { useTheming } from '@/store/state.js'
import { listen } from '@tauri-apps/api/event' import { listen } from '@tauri-apps/api/event'
import { install_from_file } from '@/helpers/pack.js' import { install_from_file } from '@/helpers/pack.js'
@@ -264,13 +264,13 @@ defineExpose({
hide() hide()
if (event.payload && event.payload.length > 0 && event.payload[0].endsWith('.mrpack')) { if (event.payload && event.payload.length > 0 && event.payload[0].endsWith('.mrpack')) {
await install_from_file(event.payload[0]).catch(handleError) await install_from_file(event.payload[0]).catch(handleError)
mixpanel_track('InstanceCreate', { trackEvent('InstanceCreate', {
source: 'CreationModalFileDrop', source: 'CreationModalFileDrop',
}) })
} }
}) })
mixpanel_track('InstanceCreateStart', { source: 'CreationModal' }) trackEvent('InstanceCreateStart', { source: 'CreationModal' })
}, },
}) })
@@ -360,7 +360,7 @@ const create_instance = async () => {
icon.value, icon.value,
).catch(handleError) ).catch(handleError)
mixpanel_track('InstanceCreate', { trackEvent('InstanceCreate', {
profile_name: profile_name.value, profile_name: profile_name.value,
game_version: game_version.value, game_version: game_version.value,
loader: loader.value, loader: loader.value,
@@ -419,7 +419,7 @@ const openFile = async () => {
hide() hide()
await install_from_file(newProject).catch(handleError) await install_from_file(newProject).catch(handleError)
mixpanel_track('InstanceCreate', { trackEvent('InstanceCreate', {
source: 'CreationModalFileOpen', source: 'CreationModalFileOpen',
}) })
} }

View File

@@ -40,8 +40,8 @@ import { Modal, Button } from '@modrinth/ui'
import { ref } from 'vue' import { ref } from 'vue'
import { find_filtered_jres } from '@/helpers/jre.js' import { find_filtered_jres } from '@/helpers/jre.js'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import { mixpanel_track } from '@/helpers/mixpanel'
import { useTheming } from '@/store/theme.js' import { useTheming } from '@/store/theme.js'
import { trackEvent } from '@/helpers/analytics'
const themeStore = useTheming() const themeStore = useTheming()
@@ -67,7 +67,7 @@ const emit = defineEmits(['submit'])
function setJavaInstall(javaInstall) { function setJavaInstall(javaInstall) {
emit('submit', javaInstall) emit('submit', javaInstall)
detectJavaModal.value.hide() detectJavaModal.value.hide()
mixpanel_track('JavaAutoDetect', { trackEvent('JavaAutoDetect', {
path: javaInstall.path, path: javaInstall.path,
version: javaInstall.version, version: javaInstall.version,
}) })

View File

@@ -65,8 +65,8 @@ import { auto_install_java, find_filtered_jres, get_jre, test_jre } from '@/help
import { ref } from 'vue' import { ref } from 'vue'
import { open } from '@tauri-apps/plugin-dialog' import { open } from '@tauri-apps/plugin-dialog'
import JavaDetectionModal from '@/components/ui/JavaDetectionModal.vue' import JavaDetectionModal from '@/components/ui/JavaDetectionModal.vue'
import { mixpanel_track } from '@/helpers/mixpanel'
import { handleError } from '@/store/state.js' import { handleError } from '@/store/state.js'
import { trackEvent } from '@/helpers/analytics'
const props = defineProps({ const props = defineProps({
version: { version: {
@@ -113,7 +113,7 @@ async function testJava() {
) )
testingJava.value = false testingJava.value = false
mixpanel_track('JavaTest', { trackEvent('JavaTest', {
path: props.modelValue ? props.modelValue.path : '', path: props.modelValue ? props.modelValue.path : '',
success: testingJavaSuccess.value, success: testingJavaSuccess.value,
}) })
@@ -136,7 +136,7 @@ async function handleJavaFileInput() {
} }
} }
mixpanel_track('JavaManualSelect', { trackEvent('JavaManualSelect', {
path: filePath, path: filePath,
version: props.version, version: props.version,
}) })
@@ -170,7 +170,7 @@ async function reinstallJava() {
} }
} }
mixpanel_track('JavaReInstall', { trackEvent('JavaReInstall', {
path: path, path: path,
version: props.version, version: props.version,
}) })

View File

@@ -117,9 +117,9 @@ import { useRouter } from 'vue-router'
import { progress_bars_list } from '@/helpers/state.js' import { progress_bars_list } from '@/helpers/state.js'
import ProgressBar from '@/components/ui/ProgressBar.vue' import ProgressBar from '@/components/ui/ProgressBar.vue'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import { mixpanel_track } from '@/helpers/mixpanel'
import { ChatIcon } from '@/assets/icons' import { ChatIcon } from '@/assets/icons'
import { get_many } from '@/helpers/profile.js' import { get_many } from '@/helpers/profile.js'
import { trackEvent } from '@/helpers/analytics'
const router = useRouter() const router = useRouter()
const card = ref(null) const card = ref(null)
@@ -164,7 +164,7 @@ const stop = async (process) => {
try { try {
await killProcess(process.uuid).catch(handleError) await killProcess(process.uuid).catch(handleError)
mixpanel_track('InstanceStop', { trackEvent('InstanceStop', {
loader: process.profile.loader, loader: process.profile.loader,
game_version: process.profile.game_version, game_version: process.profile.game_version,
source: 'AppBar', source: 'AppBar',

View File

@@ -61,7 +61,7 @@ import { formatCategory } from '@modrinth/utils'
import { add_project_from_version as installMod } from '@/helpers/profile' import { add_project_from_version as installMod } from '@/helpers/profile'
import { ref } from 'vue' import { ref } from 'vue'
import { handleError, useTheming } from '@/store/state.js' import { handleError, useTheming } from '@/store/state.js'
import { mixpanel_track } from '@/helpers/mixpanel' import { trackEvent } from '@/helpers/analytics'
const themeStore = useTheming() const themeStore = useTheming()
@@ -87,7 +87,7 @@ defineExpose({
incompatibleModal.value.show() incompatibleModal.value.show()
mixpanel_track('ProjectInstallStart', { source: 'ProjectIncompatibilityWarningModal' }) trackEvent('ProjectInstallStart', { source: 'ProjectIncompatibilityWarningModal' })
}, },
}) })
@@ -98,7 +98,7 @@ const install = async () => {
onInstall.value(selectedVersion.value.id) onInstall.value(selectedVersion.value.id)
incompatibleModal.value.hide() incompatibleModal.value.hide()
mixpanel_track('ProjectInstall', { trackEvent('ProjectInstall', {
loader: instance.value.loader, loader: instance.value.loader,
game_version: instance.value.game_version, game_version: instance.value.game_version,
id: project.value, id: project.value,

View File

@@ -3,7 +3,7 @@ import { XIcon, DownloadIcon } from '@modrinth/assets'
import { Button, Modal } from '@modrinth/ui' import { Button, Modal } from '@modrinth/ui'
import { install as pack_install } from '@/helpers/pack' import { install as pack_install } from '@/helpers/pack'
import { ref } from 'vue' import { ref } from 'vue'
import { mixpanel_track } from '@/helpers/mixpanel' import { trackEvent } from '@/helpers/analytics'
import { useTheming } from '@/store/theme.js' import { useTheming } from '@/store/theme.js'
import { handleError } from '@/store/state.js' import { handleError } from '@/store/state.js'
@@ -25,7 +25,7 @@ defineExpose({
onInstall.value = callback onInstall.value = callback
mixpanel_track('PackInstallStart') trackEvent('PackInstallStart')
}, },
}) })
@@ -39,7 +39,7 @@ async function install() {
project.value.title, project.value.title,
project.value.icon_url, project.value.icon_url,
).catch(handleError) ).catch(handleError)
mixpanel_track('PackInstall', { trackEvent('PackInstall', {
id: project.value.id, id: project.value.id,
version_id: versionId.value, version_id: versionId.value,
title: project.value.title, title: project.value.title,

View File

@@ -19,10 +19,10 @@ import {
import { open } from '@tauri-apps/plugin-dialog' import { open } from '@tauri-apps/plugin-dialog'
import { installVersionDependencies } from '@/store/install.js' import { installVersionDependencies } from '@/store/install.js'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import { mixpanel_track } from '@/helpers/mixpanel'
import { useTheming } from '@/store/theme.js' import { useTheming } from '@/store/theme.js'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { convertFileSrc } from '@tauri-apps/api/core' import { convertFileSrc } from '@tauri-apps/api/core'
import { trackEvent } from '@/helpers/analytics'
const themeStore = useTheming() const themeStore = useTheming()
const router = useRouter() const router = useRouter()
@@ -88,7 +88,7 @@ defineExpose({
installModal.value.show() installModal.value.show()
mixpanel_track('ProjectInstallStart', { source: 'ProjectInstallModal' }) trackEvent('ProjectInstallStart', { source: 'ProjectInstallModal' })
}, },
}) })
@@ -115,7 +115,7 @@ async function install(instance) {
instance.installedMod = true instance.installedMod = true
instance.installing = false instance.installing = false
mixpanel_track('ProjectInstall', { trackEvent('ProjectInstall', {
loader: instance.loader, loader: instance.loader,
game_version: instance.game_version, game_version: instance.game_version,
id: project.value.id, id: project.value.id,
@@ -137,7 +137,7 @@ const toggleCreation = () => {
loader.value = null loader.value = null
if (showCreation.value) { if (showCreation.value) {
mixpanel_track('InstanceCreateStart', { source: 'ProjectInstallModal' }) trackEvent('InstanceCreateStart', { source: 'ProjectInstallModal' })
} }
} }
@@ -186,7 +186,7 @@ const createInstance = async () => {
const instance = await get(id, true) const instance = await get(id, true)
await installVersionDependencies(instance, versions.value[0]) await installVersionDependencies(instance, versions.value[0])
mixpanel_track('InstanceCreate', { trackEvent('InstanceCreate', {
profile_name: name.value, profile_name: name.value,
game_version: versions.value[0].game_versions[0], game_version: versions.value[0].game_versions[0],
loader: loader, loader: loader,
@@ -195,7 +195,7 @@ const createInstance = async () => {
source: 'ProjectInstallModal', source: 'ProjectInstallModal',
}) })
mixpanel_track('ProjectInstall', { trackEvent('ProjectInstall', {
loader: loader, loader: loader,
game_version: versions.value[0].game_versions[0], game_version: versions.value[0].game_versions[0],
id: project.value, id: project.value,

View File

@@ -0,0 +1,23 @@
import { posthog } from 'posthog-js'
export const initAnalytics = () => {
posthog.init('phc_hm2ihMpTAoE86xIm7XzsCB8RPiTRKivViK5biiHedm', {
persistence: 'localStorage',
})
}
export const debugAnalytics = () => {
posthog.debug()
}
export const optOutAnalytics = () => {
posthog.opt_out_capturing()
}
export const optInAnalytics = () => {
posthog.opt_in_capturing()
}
export const trackEvent = (eventName, properties) => {
posthog.capture(eventName, properties)
}

View File

@@ -1,57 +0,0 @@
import mixpanel from 'mixpanel-browser'
// mixpanel_track
function trackWrapper(originalTrack) {
return function (event_name, properties = {}) {
try {
originalTrack(event_name, properties)
} catch (e) {
console.error(e)
}
}
}
export const mixpanel_track = trackWrapper(mixpanel.track.bind(mixpanel))
// mixpanel_opt_out_tracking()
function optOutTrackingWrapper(originalOptOutTracking) {
return function () {
try {
originalOptOutTracking()
} catch (e) {
console.error(e)
}
}
}
export const mixpanel_opt_out_tracking = optOutTrackingWrapper(
mixpanel.opt_out_tracking.bind(mixpanel),
)
// mixpanel_opt_in_tracking()
function optInTrackingWrapper(originalOptInTracking) {
return function () {
try {
originalOptInTracking()
} catch (e) {
console.error(e)
}
}
}
export const mixpanel_opt_in_tracking = optInTrackingWrapper(
mixpanel.opt_in_tracking.bind(mixpanel),
)
// mixpanel_init
function initWrapper(originalInit) {
return function (token, config = {}) {
try {
originalInit(token, config)
} catch (e) {
console.error(e)
}
}
}
export const mixpanel_init = initWrapper(mixpanel.init.bind(mixpanel))
export const mixpanel_is_loaded = () => {
return mixpanel.__loaded
}

View File

@@ -5,6 +5,7 @@ import { createPinia } from 'pinia'
import FloatingVue from 'floating-vue' import FloatingVue from 'floating-vue'
import 'floating-vue/dist/style.css' import 'floating-vue/dist/style.css'
import { createPlugin } from '@vintl/vintl/plugin' import { createPlugin } from '@vintl/vintl/plugin'
import * as Sentry from '@sentry/vue'
const VIntlPlugin = createPlugin({ const VIntlPlugin = createPlugin({
controllerOpts: { controllerOpts: {
@@ -26,6 +27,14 @@ const VIntlPlugin = createPlugin({
const pinia = createPinia() const pinia = createPinia()
let app = createApp(App) let app = createApp(App)
Sentry.init({
app,
dsn: 'https://9508775ee5034536bc70433f5f531dd4@o485889.ingest.us.sentry.io/4504579615227904',
integrations: [Sentry.browserTracingIntegration({ router })],
tracesSampleRate: 0.1,
})
app.use(router) app.use(router)
app.use(pinia) app.use(pinia)
app.use(FloatingVue) app.use(FloatingVue)

View File

@@ -8,7 +8,7 @@ import { get_java_versions, get_max_memory, set_java_version } from '@/helpers/j
import { get as getCreds, logout } from '@/helpers/mr_auth.js' import { get as getCreds, logout } from '@/helpers/mr_auth.js'
import JavaSelector from '@/components/ui/JavaSelector.vue' import JavaSelector from '@/components/ui/JavaSelector.vue'
import ModrinthLoginScreen from '@/components/ui/tutorial/ModrinthLoginScreen.vue' import ModrinthLoginScreen from '@/components/ui/tutorial/ModrinthLoginScreen.vue'
import { mixpanel_opt_out_tracking, mixpanel_opt_in_tracking } from '@/helpers/mixpanel' import { optOutAnalytics, optInAnalytics } from '@/helpers/analytics'
import { open } from '@tauri-apps/plugin-dialog' import { open } from '@tauri-apps/plugin-dialog'
import { getOS } from '@/helpers/utils.js' import { getOS } from '@/helpers/utils.js'
import { getVersion } from '@tauri-apps/api/app' import { getVersion } from '@tauri-apps/api/app'
@@ -45,9 +45,9 @@ watch(
const setSettings = JSON.parse(JSON.stringify(newSettings)) const setSettings = JSON.parse(JSON.stringify(newSettings))
if (setSettings.telemetry) { if (setSettings.telemetry) {
mixpanel_opt_out_tracking() optInAnalytics()
} else { } else {
mixpanel_opt_in_tracking() optOutAnalytics()
} }
setSettings.extra_launch_args = setSettings.launchArgs.trim().split(/\s+/).filter(Boolean) setSettings.extra_launch_args = setSettings.launchArgs.trim().split(/\s+/).filter(Boolean)

View File

@@ -131,9 +131,8 @@ import { ref, onUnmounted } from 'vue'
import { handleError, useBreadcrumbs, useLoading } from '@/store/state' import { handleError, useBreadcrumbs, useLoading } from '@/store/state'
import { showProfileInFolder } from '@/helpers/utils.js' import { showProfileInFolder } from '@/helpers/utils.js'
import ContextMenu from '@/components/ui/ContextMenu.vue' import ContextMenu from '@/components/ui/ContextMenu.vue'
import { mixpanel_track } from '@/helpers/mixpanel' import { trackEvent } from '@/helpers/analytics'
import { convertFileSrc } from '@tauri-apps/api/core' import { convertFileSrc } from '@tauri-apps/api/core'
import { useFetch } from '@/helpers/fetch'
import { handleSevereError } from '@/store/error.js' import { handleSevereError } from '@/store/error.js'
import { get_project, get_version_many } from '@/helpers/cache.js' import { get_project, get_version_many } from '@/helpers/cache.js'
import dayjs from 'dayjs' import dayjs from 'dayjs'
@@ -183,7 +182,7 @@ const startInstance = async (context) => {
} }
loading.value = false loading.value = false
mixpanel_track('InstanceStart', { trackEvent('InstanceStart', {
loader: instance.value.loader, loader: instance.value.loader,
game_version: instance.value.game_version, game_version: instance.value.game_version,
source: context, source: context,
@@ -220,7 +219,7 @@ const stopInstance = async (context) => {
playing.value = false playing.value = false
await kill(route.params.id).catch(handleError) await kill(route.params.id).catch(handleError)
mixpanel_track('InstanceStop', { trackEvent('InstanceStop', {
loader: instance.value.loader, loader: instance.value.loader,
game_version: instance.value.game_version, game_version: instance.value.game_version,
source: context, source: context,

View File

@@ -379,7 +379,7 @@ import {
update_project, update_project,
} from '@/helpers/profile.js' } from '@/helpers/profile.js'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import { mixpanel_track } from '@/helpers/mixpanel' import { trackEvent } from '@/helpers/analytics'
import { listen } from '@tauri-apps/api/event' import { listen } from '@tauri-apps/api/event'
import { highlightModInProfile } from '@/helpers/utils.js' import { highlightModInProfile } from '@/helpers/utils.js'
import { MenuIcon, ToggleIcon, TextInputIcon, AddProjectImage, PackageIcon } from '@/assets/icons' import { MenuIcon, ToggleIcon, TextInputIcon, AddProjectImage, PackageIcon } from '@/assets/icons'
@@ -682,7 +682,7 @@ const updateAll = async () => {
projects.value[project].updating = false projects.value[project].updating = false
} }
mixpanel_track('InstanceUpdateAll', { trackEvent('InstanceUpdateAll', {
loader: props.instance.loader, loader: props.instance.loader,
game_version: props.instance.game_version, game_version: props.instance.game_version,
count: setProjects.length, count: setProjects.length,
@@ -708,7 +708,7 @@ const updateProject = async (mod) => {
mod.version = mod.updateVersion.version_number mod.version = mod.updateVersion.version_number
mod.updateVersion = null mod.updateVersion = null
mixpanel_track('InstanceProjectUpdate', { trackEvent('InstanceProjectUpdate', {
loader: props.instance.loader, loader: props.instance.loader,
game_version: props.instance.game_version, game_version: props.instance.game_version,
id: mod.id, id: mod.id,
@@ -735,7 +735,7 @@ const toggleDisableMod = async (mod) => {
.then((newPath) => { .then((newPath) => {
mod.path = newPath mod.path = newPath
mod.disabled = !mod.disabled mod.disabled = !mod.disabled
mixpanel_track('InstanceProjectDisable', { trackEvent('InstanceProjectDisable', {
loader: props.instance.loader, loader: props.instance.loader,
game_version: props.instance.game_version, game_version: props.instance.game_version,
id: mod.id, id: mod.id,
@@ -756,7 +756,7 @@ const removeMod = async (mod) => {
await remove_project(props.instance.path, mod.path).catch(handleError) await remove_project(props.instance.path, mod.path).catch(handleError)
projects.value = projects.value.filter((x) => mod.path !== x.path) projects.value = projects.value.filter((x) => mod.path !== x.path)
mixpanel_track('InstanceProjectRemove', { trackEvent('InstanceProjectRemove', {
loader: props.instance.loader, loader: props.instance.loader,
game_version: props.instance.game_version, game_version: props.instance.game_version,
id: mod.id, id: mod.id,

View File

@@ -546,10 +546,10 @@ import { open } from '@tauri-apps/plugin-dialog'
import { get_loader_versions } from '@/helpers/metadata.js' import { get_loader_versions } from '@/helpers/metadata.js'
import { get_game_versions, get_loaders } from '@/helpers/tags.js' import { get_game_versions, get_loaders } from '@/helpers/tags.js'
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import { mixpanel_track } from '@/helpers/mixpanel'
import { useTheming } from '@/store/theme.js' import { useTheming } from '@/store/theme.js'
import { useBreadcrumbs } from '@/store/breadcrumbs' import { useBreadcrumbs } from '@/store/breadcrumbs'
import ModpackVersionModal from '@/components/ui/ModpackVersionModal.vue' import ModpackVersionModal from '@/components/ui/ModpackVersionModal.vue'
import { trackEvent } from '@/helpers/analytics'
const breadcrumbs = useBreadcrumbs() const breadcrumbs = useBreadcrumbs()
@@ -590,7 +590,7 @@ const availableGroups = ref([
async function resetIcon() { async function resetIcon() {
icon.value = null icon.value = null
await edit_icon(props.instance.path, null).catch(handleError) await edit_icon(props.instance.path, null).catch(handleError)
mixpanel_track('InstanceRemoveIcon') trackEvent('InstanceRemoveIcon')
} }
async function setIcon() { async function setIcon() {
@@ -609,7 +609,7 @@ async function setIcon() {
icon.value = value icon.value = value
await edit_icon(props.instance.path, icon.value).catch(handleError) await edit_icon(props.instance.path, icon.value).catch(handleError)
mixpanel_track('InstanceSetIcon') trackEvent('InstanceSetIcon')
} }
const globalSettings = await get().catch(handleError) const globalSettings = await get().catch(handleError)
@@ -754,7 +754,7 @@ const repairing = ref(false)
async function duplicateProfile() { async function duplicateProfile() {
await duplicate(props.instance.path).catch(handleError) await duplicate(props.instance.path).catch(handleError)
mixpanel_track('InstanceDuplicate', { trackEvent('InstanceDuplicate', {
loader: props.instance.loader, loader: props.instance.loader,
game_version: props.instance.game_version, game_version: props.instance.game_version,
}) })
@@ -765,7 +765,7 @@ async function repairProfile(force) {
await install(props.instance.path, force).catch(handleError) await install(props.instance.path, force).catch(handleError)
repairing.value = false repairing.value = false
mixpanel_track('InstanceRepair', { trackEvent('InstanceRepair', {
loader: props.instance.loader, loader: props.instance.loader,
game_version: props.instance.game_version, game_version: props.instance.game_version,
}) })
@@ -796,7 +796,7 @@ async function repairModpack() {
await update_repair_modrinth(props.instance.path).catch(handleError) await update_repair_modrinth(props.instance.path).catch(handleError)
inProgress.value = false inProgress.value = false
mixpanel_track('InstanceRepair', { trackEvent('InstanceRepair', {
loader: props.instance.loader, loader: props.instance.loader,
game_version: props.instance.game_version, game_version: props.instance.game_version,
}) })
@@ -808,7 +808,7 @@ async function removeProfile() {
await remove(props.instance.path).catch(handleError) await remove(props.instance.path).catch(handleError)
removing.value = false removing.value = false
mixpanel_track('InstanceRemove', { trackEvent('InstanceRemove', {
loader: props.instance.loader, loader: props.instance.loader,
game_version: props.instance.game_version, game_version: props.instance.game_version,
}) })

View File

@@ -93,7 +93,7 @@ import {
} from '@modrinth/assets' } from '@modrinth/assets'
import { Button, Card } from '@modrinth/ui' import { Button, Card } from '@modrinth/ui'
import { ref } from 'vue' import { ref } from 'vue'
import { mixpanel_track } from '@/helpers/mixpanel' import { trackEvent } from '@/helpers/analytics'
const props = defineProps({ const props = defineProps({
project: { project: {
@@ -112,7 +112,7 @@ const nextImage = () => {
expandedGalleryIndex.value = 0 expandedGalleryIndex.value = 0
} }
expandedGalleryItem.value = props.project.gallery[expandedGalleryIndex.value] expandedGalleryItem.value = props.project.gallery[expandedGalleryIndex.value]
mixpanel_track('GalleryImageNext', { trackEvent('GalleryImageNext', {
project_id: props.project.id, project_id: props.project.id,
url: expandedGalleryItem.value.url, url: expandedGalleryItem.value.url,
}) })
@@ -124,7 +124,7 @@ const previousImage = () => {
expandedGalleryIndex.value = props.project.gallery.length - 1 expandedGalleryIndex.value = props.project.gallery.length - 1
} }
expandedGalleryItem.value = props.project.gallery[expandedGalleryIndex.value] expandedGalleryItem.value = props.project.gallery[expandedGalleryIndex.value]
mixpanel_track('GalleryImagePrevious', { trackEvent('GalleryImagePrevious', {
project_id: props.project.id, project_id: props.project.id,
url: expandedGalleryItem.value, url: expandedGalleryItem.value,
}) })
@@ -135,7 +135,7 @@ const expandImage = (item, index) => {
expandedGalleryIndex.value = index expandedGalleryIndex.value = index
zoomedIn.value = false zoomedIn.value = false
mixpanel_track('GalleryImageExpand', { trackEvent('GalleryImageExpand', {
project_id: props.project.id, project_id: props.project.id,
url: item.url, url: item.url,
}) })

View File

@@ -10,7 +10,7 @@ import {
import { handleError } from '@/store/notifications.js' import { handleError } from '@/store/notifications.js'
import { get_project, get_version_many } from '@/helpers/cache.js' import { get_project, get_version_many } from '@/helpers/cache.js'
import { install as packInstall } from '@/helpers/pack.js' import { install as packInstall } from '@/helpers/pack.js'
import { mixpanel_track } from '@/helpers/mixpanel.js' import { trackEvent } from '@/helpers/analytics.js'
import dayjs from 'dayjs' import dayjs from 'dayjs'
export const useInstall = defineStore('installStore', { export const useInstall = defineStore('installStore', {
@@ -51,7 +51,7 @@ export const install = async (projectId, versionId, instancePath, source, callba
if (packs.length === 0 || !packs.find((pack) => pack.linked_data?.project_id === project.id)) { if (packs.length === 0 || !packs.find((pack) => pack.linked_data?.project_id === project.id)) {
await packInstall(project.id, version, project.title, project.icon_url).catch(handleError) await packInstall(project.id, version, project.title, project.icon_url).catch(handleError)
mixpanel_track('PackInstall', { trackEvent('PackInstall', {
id: project.id, id: project.id,
version_id: version, version_id: version,
title: project.title, title: project.title,
@@ -107,7 +107,7 @@ export const install = async (projectId, versionId, instancePath, source, callba
await add_project_from_version(instance.path, version.id).catch(handleError) await add_project_from_version(instance.path, version.id).catch(handleError)
await installVersionDependencies(instance, version) await installVersionDependencies(instance, version)
mixpanel_track('ProjectInstall', { trackEvent('ProjectInstall', {
loader: instance.loader, loader: instance.loader,
game_version: instance.game_version, game_version: instance.game_version,
id: project.id, id: project.id,

View File

@@ -23,7 +23,3 @@ export const handleError = (err) => {
}) })
console.error(err) console.error(err)
} }
export const handleMixpanelError = (err) => {
console.error(err)
}

View File

@@ -86,7 +86,7 @@
], ],
"enable": true "enable": true
}, },
"csp": "default-src 'self'; connect-src ipc: http://ipc.localhost https://modrinth.com https://*.modrinth.com https://mixpanel.com https://*.mixpanel.com https://*.cloudflare.com https://api.mclo.gs; font-src https://cdn-raw.modrinth.com/fonts/inter/; img-src tauri: https: data: blob: 'unsafe-inline' asset: https://asset.localhost; script-src https://*.cloudflare.com 'self'; frame-src https://*.cloudflare.com https://www.youtube.com https://www.youtube-nocookie.com https://discord.com 'self'; style-src unsafe-inline 'self'" "csp": "default-src 'self'; connect-src ipc: http://ipc.localhost https://modrinth.com https://*.modrinth.com https://*.posthog.com https://*.sentry.io https://*.cloudflare.com https://api.mclo.gs; font-src https://cdn-raw.modrinth.com/fonts/inter/; img-src tauri: https: data: blob: 'unsafe-inline' asset: https://asset.localhost; script-src https://*.cloudflare.com 'self'; frame-src https://*.cloudflare.com https://www.youtube.com https://www.youtube-nocookie.com https://discord.com 'self'; style-src unsafe-inline 'self'"
} }
} }
} }

View File

@@ -109,7 +109,7 @@
<p>This data is used to deliver statistics.</p> <p>This data is used to deliver statistics.</p>
<h3>Usage data</h3> <h3>Usage data</h3>
<p>When you interact with the Modrinth App or the Website, we collect through MixPanel:</p> <p>When you interact with the Modrinth App or the Website, we collect through PostHog:</p>
<ul> <ul>
<li>Your IP address</li> <li>Your IP address</li>
<li>Your anonymized user ID</li> <li>Your anonymized user ID</li>
@@ -150,9 +150,10 @@
<a href="https://www.cloudflare.com/en-gb/gdpr/introduction/"> Cloudflare </a> <a href="https://www.cloudflare.com/en-gb/gdpr/introduction/"> Cloudflare </a>
</li> </li>
<li><a href="https://sentry.io/trust/privacy/">Sentry</a></li> <li><a href="https://sentry.io/trust/privacy/">Sentry</a></li>
<li><a href="https://mixpanel.com/legal/privacy-policy">MixPanel</a></li> <li><a href="https://posthog.com/privacy">PostHog</a></li>
<li><a href="https://www.beehiiv.com/privacy">BeeHiiv</a></li> <li><a href="https://www.beehiiv.com/privacy">BeeHiiv</a></li>
<li><a href="https://www.paypal.com/us/legalhub/privacy-full">PayPal</a></li> <li><a href="https://www.paypal.com/us/legalhub/privacy-full">PayPal</a></li>
<li><a href="https://stripe.com/privacy">Stripe</a></li>
</ul> </ul>
<p> <p>
Data that we specifically collect isn't shared with any other third party. We do not sell any Data that we specifically collect isn't shared with any other third party. We do not sell any

171
pnpm-lock.yaml generated
View File

@@ -47,6 +47,9 @@ importers:
'@modrinth/utils': '@modrinth/utils':
specifier: workspace:* specifier: workspace:*
version: link:../../packages/utils version: link:../../packages/utils
'@sentry/vue':
specifier: ^8.27.0
version: 8.27.0(vue@3.4.31(typescript@5.5.3))
'@tauri-apps/api': '@tauri-apps/api':
specifier: ^2.0.0-rc.3 specifier: ^2.0.0-rc.3
version: 2.0.0-rc.3 version: 2.0.0-rc.3
@@ -71,15 +74,15 @@ importers:
floating-vue: floating-vue:
specifier: ^5.2.2 specifier: ^5.2.2
version: 5.2.2(@nuxt/kit@3.12.3)(vue@3.4.31(typescript@5.5.3)) version: 5.2.2(@nuxt/kit@3.12.3)(vue@3.4.31(typescript@5.5.3))
mixpanel-browser:
specifier: ^2.49.0
version: 2.53.0
ofetch: ofetch:
specifier: ^1.3.4 specifier: ^1.3.4
version: 1.3.4 version: 1.3.4
pinia: pinia:
specifier: ^2.1.7 specifier: ^2.1.7
version: 2.1.7(typescript@5.5.3)(vue@3.4.31(typescript@5.5.3)) version: 2.1.7(typescript@5.5.3)(vue@3.4.31(typescript@5.5.3))
posthog-js:
specifier: ^1.158.2
version: 1.158.2
vite-svg-loader: vite-svg-loader:
specifier: ^5.1.0 specifier: ^5.1.0
version: 5.1.0(vue@3.4.31(typescript@5.5.3)) version: 5.1.0(vue@3.4.31(typescript@5.5.3))
@@ -1900,8 +1903,43 @@ packages:
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
'@rrweb/types@2.0.0-alpha.16': '@sentry-internal/browser-utils@8.27.0':
resolution: {integrity: sha512-E6cACNVsm+NUhn7dzocQoKyXI7BHrHRRm5Ab23yrAzEQ2caWocCEYJhqDlc4KRVJBkQfXZfyWm8+2d0uggFuZg==} resolution: {integrity: sha512-YTIwQ1GM1NTRXgN4DvpFSQ2x4pjlqQ0FQAyHW5x2ZYv4z7VmqG4Xkid1P/srQUipECk6nxkebfD4WR19nLsvnQ==}
engines: {node: '>=14.18'}
'@sentry-internal/feedback@8.27.0':
resolution: {integrity: sha512-b71PQc9aK1X9b/SO1DiJlrnAEx4n0MzPZQ/tKd9oRWDyGit6pJWZfQns9r2rvc96kJPMOTxFAa/upXRCkA723A==}
engines: {node: '>=14.18'}
'@sentry-internal/replay-canvas@8.27.0':
resolution: {integrity: sha512-uuEfiWbjwugB9M4KxXxovHYiKRqg/R6U4EF8xM/Ub4laUuEcWsfRp7lQ3MxL3qYojbca8ncIFic2bIoKMPeejA==}
engines: {node: '>=14.18'}
'@sentry-internal/replay@8.27.0':
resolution: {integrity: sha512-Ofucncaon98dvlxte2L//hwuG9yILSxNrTz/PmO0k+HzB9q+oBic4667QF+azWR2qv4oKSWpc+vEovP3hVqveA==}
engines: {node: '>=14.18'}
'@sentry/browser@8.27.0':
resolution: {integrity: sha512-eL1eaHwoYUGkp4mpeYesH6WtCrm+0u9jYCW5Lm0MAeTmpx22BZKEmj0OljuUJXGnJwFbvPDlRjyz6QG11m8kZA==}
engines: {node: '>=14.18'}
'@sentry/core@8.27.0':
resolution: {integrity: sha512-4frlXluHT3Du+Omw91K04jpvbfMtydvg4Bxj2+gt/DT19Swhm/fbEpzdUjgbAd3Jinj/n0qk/jFRXjr9JZKFjg==}
engines: {node: '>=14.18'}
'@sentry/types@8.27.0':
resolution: {integrity: sha512-B6lrP46+m2x0lfqWc9F4VcUbN893mVGnPEd7KIMRk95mPzkFJ3sNxggTQF5/ZfNO7lDQYQb22uysB5sj/BqFiw==}
engines: {node: '>=14.18'}
'@sentry/utils@8.27.0':
resolution: {integrity: sha512-gyJM3SyLQe0A3mkQVVNdKYvk3ZoikkYgyA/D+5StFNLKdyUgEbJgXOGXrQSSYPF7BSX6Sc5b0KHCglPII0KuKw==}
engines: {node: '>=14.18'}
'@sentry/vue@8.27.0':
resolution: {integrity: sha512-kCjrdKCQk9ZgE7HirVaT/hvyBhoryEHickiWQET7fzyEo6Zs7/KoFnNiXzGuZ+XJcZ8R76wlog+awBBmZBuBsQ==}
engines: {node: '>=14.18'}
peerDependencies:
vue: 2.x || 3.x
'@sindresorhus/merge-streams@2.3.0': '@sindresorhus/merge-streams@2.3.0':
resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==}
@@ -2056,9 +2094,6 @@ packages:
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}
'@types/css-font-loading-module@0.0.7':
resolution: {integrity: sha512-nl09VhutdjINdWyXxHWN/w9zlNCfr60JUqJbd24YXUuCwgeL0TpFSdElCwb6cxfB6ybE19Gjj4g0jsgkXxKv1Q==}
'@types/eslint-scope@3.7.7': '@types/eslint-scope@3.7.7':
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
@@ -2470,9 +2505,6 @@ packages:
'@webassemblyjs/wast-printer@1.12.1': '@webassemblyjs/wast-printer@1.12.1':
resolution: {integrity: sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==} resolution: {integrity: sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==}
'@xstate/fsm@1.6.5':
resolution: {integrity: sha512-b5o1I6aLNeYlU/3CPlj/Z91ybk1gUsKT+5NAJI+2W4UjvS5KLG28K9v5UvNoFVjHV8PajVZ00RH3vnjyQO7ZAw==}
'@xtuc/ieee754@1.2.0': '@xtuc/ieee754@1.2.0':
resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==}
@@ -2651,10 +2683,6 @@ packages:
bare-events@2.4.2: bare-events@2.4.2:
resolution: {integrity: sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==} resolution: {integrity: sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==}
base64-arraybuffer@1.0.2:
resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
engines: {node: '>= 0.6.0'}
base64-js@1.5.1: base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@@ -4335,9 +4363,6 @@ packages:
mitt@3.0.1: mitt@3.0.1:
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
mixpanel-browser@2.53.0:
resolution: {integrity: sha512-8U7zCTT82yCIH2vfdCvs0ZRWlCgyHMuU4jtC6yOAiNUR4HhnQYk7re/o2GnhfdvYtkPxdda60/3eH1igUlIXuw==}
mkdirp@1.0.4: mkdirp@1.0.4:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
engines: {node: '>=10'} engines: {node: '>=10'}
@@ -4887,6 +4912,12 @@ packages:
resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==} resolution: {integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
posthog-js@1.158.2:
resolution: {integrity: sha512-ovb7GHHRNDf6vmuL+8lbDukewzDzQlLZXg3d475hrfHSBgidYeTxtLGtoBcUz4x6558BLDFjnSip+f3m4rV9LA==}
preact@10.23.2:
resolution: {integrity: sha512-kKYfePf9rzKnxOAKDpsWhg/ysrHPqT+yQ7UW4JjdnqjFIeNUnNcEJvhuA8fDenxAGWzUqtd51DfVg7xp/8T9NA==}
prelude-ls@1.2.1: prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@@ -5114,15 +5145,6 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'} engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true hasBin: true
rrdom@2.0.0-alpha.16:
resolution: {integrity: sha512-m8aoeORWUz7AFdEb7hES7wPeL6fl/oP23RoAlzLXyA/f2+NqCDM7KEyCXY4sHu6CChN3OAUP2BaUGEXn0zynlw==}
rrweb-snapshot@2.0.0-alpha.16:
resolution: {integrity: sha512-p81OrzUiCmUMZzJu4fGHeLB00PIbVIqsV/zhqzr2pitHTUXpMYcyOvDWt0vHdla0vnowEPaHq3Wsu6cUc732/w==}
rrweb@2.0.0-alpha.13:
resolution: {integrity: sha512-a8GXOCnzWHNaVZPa7hsrLZtNZ3CGjiL+YrkpLo0TfmxGLhjNZbWY2r7pE06p+FcjFNlgUVTmFrSJbK3kO7yxvw==}
run-applescript@7.0.0: run-applescript@7.0.0:
resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==}
engines: {node: '>=18'} engines: {node: '>=18'}
@@ -5974,6 +5996,9 @@ packages:
resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==}
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}
web-vitals@4.2.3:
resolution: {integrity: sha512-/CFAm1mNxSmOj6i0Co+iGFJ58OS4NRGVP+AWS/l509uIK5a1bSoIVaHz/ZumpHTfHSZBpgrJ+wjfpAOrTHok5Q==}
webidl-conversions@3.0.1: webidl-conversions@3.0.1:
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
@@ -7699,9 +7724,60 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.18.0': '@rollup/rollup-win32-x64-msvc@4.18.0':
optional: true optional: true
'@rrweb/types@2.0.0-alpha.16': '@sentry-internal/browser-utils@8.27.0':
dependencies: dependencies:
rrweb-snapshot: 2.0.0-alpha.16 '@sentry/core': 8.27.0
'@sentry/types': 8.27.0
'@sentry/utils': 8.27.0
'@sentry-internal/feedback@8.27.0':
dependencies:
'@sentry/core': 8.27.0
'@sentry/types': 8.27.0
'@sentry/utils': 8.27.0
'@sentry-internal/replay-canvas@8.27.0':
dependencies:
'@sentry-internal/replay': 8.27.0
'@sentry/core': 8.27.0
'@sentry/types': 8.27.0
'@sentry/utils': 8.27.0
'@sentry-internal/replay@8.27.0':
dependencies:
'@sentry-internal/browser-utils': 8.27.0
'@sentry/core': 8.27.0
'@sentry/types': 8.27.0
'@sentry/utils': 8.27.0
'@sentry/browser@8.27.0':
dependencies:
'@sentry-internal/browser-utils': 8.27.0
'@sentry-internal/feedback': 8.27.0
'@sentry-internal/replay': 8.27.0
'@sentry-internal/replay-canvas': 8.27.0
'@sentry/core': 8.27.0
'@sentry/types': 8.27.0
'@sentry/utils': 8.27.0
'@sentry/core@8.27.0':
dependencies:
'@sentry/types': 8.27.0
'@sentry/utils': 8.27.0
'@sentry/types@8.27.0': {}
'@sentry/utils@8.27.0':
dependencies:
'@sentry/types': 8.27.0
'@sentry/vue@8.27.0(vue@3.4.31(typescript@5.5.3))':
dependencies:
'@sentry/browser': 8.27.0
'@sentry/core': 8.27.0
'@sentry/types': 8.27.0
'@sentry/utils': 8.27.0
vue: 3.4.31(typescript@5.5.3)
'@sindresorhus/merge-streams@2.3.0': {} '@sindresorhus/merge-streams@2.3.0': {}
@@ -7811,8 +7887,6 @@ snapshots:
'@trysound/sax@0.2.0': {} '@trysound/sax@0.2.0': {}
'@types/css-font-loading-module@0.0.7': {}
'@types/eslint-scope@3.7.7': '@types/eslint-scope@3.7.7':
dependencies: dependencies:
'@types/eslint': 9.6.0 '@types/eslint': 9.6.0
@@ -8475,8 +8549,6 @@ snapshots:
'@xtuc/long': 4.2.2 '@xtuc/long': 4.2.2
optional: true optional: true
'@xstate/fsm@1.6.5': {}
'@xtuc/ieee754@1.2.0': '@xtuc/ieee754@1.2.0':
optional: true optional: true
@@ -8688,8 +8760,6 @@ snapshots:
bare-events@2.4.2: bare-events@2.4.2:
optional: true optional: true
base64-arraybuffer@1.0.2: {}
base64-js@1.5.1: {} base64-js@1.5.1: {}
binary-extensions@2.3.0: {} binary-extensions@2.3.0: {}
@@ -10583,10 +10653,6 @@ snapshots:
mitt@3.0.1: {} mitt@3.0.1: {}
mixpanel-browser@2.53.0:
dependencies:
rrweb: 2.0.0-alpha.13
mkdirp@1.0.4: {} mkdirp@1.0.4: {}
mlly@1.7.1: mlly@1.7.1:
@@ -11267,6 +11333,14 @@ snapshots:
picocolors: 1.0.1 picocolors: 1.0.1
source-map-js: 1.2.0 source-map-js: 1.2.0
posthog-js@1.158.2:
dependencies:
fflate: 0.4.8
preact: 10.23.2
web-vitals: 4.2.3
preact@10.23.2: {}
prelude-ls@1.2.1: {} prelude-ls@1.2.1: {}
prettier-linter-helpers@1.0.0: prettier-linter-helpers@1.0.0:
@@ -11468,23 +11542,6 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.18.0 '@rollup/rollup-win32-x64-msvc': 4.18.0
fsevents: 2.3.3 fsevents: 2.3.3
rrdom@2.0.0-alpha.16:
dependencies:
rrweb-snapshot: 2.0.0-alpha.16
rrweb-snapshot@2.0.0-alpha.16: {}
rrweb@2.0.0-alpha.13:
dependencies:
'@rrweb/types': 2.0.0-alpha.16
'@types/css-font-loading-module': 0.0.7
'@xstate/fsm': 1.6.5
base64-arraybuffer: 1.0.2
fflate: 0.4.8
mitt: 3.0.1
rrdom: 2.0.0-alpha.16
rrweb-snapshot: 2.0.0-alpha.16
run-applescript@7.0.0: {} run-applescript@7.0.0: {}
run-parallel@1.2.0: run-parallel@1.2.0:
@@ -12455,6 +12512,8 @@ snapshots:
graceful-fs: 4.2.11 graceful-fs: 4.2.11
optional: true optional: true
web-vitals@4.2.3: {}
webidl-conversions@3.0.1: {} webidl-conversions@3.0.1: {}
webpack-sources@3.2.3: {} webpack-sources@3.2.3: {}