Merge remote-tracking branch 'origin/main' into dev

Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
Innei 2024-10-18 15:37:01 +08:00
commit 662d33672b
No known key found for this signature in database
GPG Key ID: 0F62D33977F021F7
36 changed files with 909 additions and 239 deletions

View File

@ -3,5 +3,6 @@ VITE_API_URL=http://localhost:3000
VITE_IMGPROXY_URL=http://localhost:2873
VITE_SENTRY_DSN=
VITE_BUILD_TYPE=production
VITE_POSTHOG_KEY=
VITE_INBOXES_EMAIL=@follow.re
VITE_OPENPANEL_CLIENT_ID=
VITE_OPENPANEL_API_URL=

View File

@ -20,7 +20,8 @@ env:
VITE_API_URL: ${{ vars.VITE_API_URL }}
VITE_IMGPROXY_URL: ${{ vars.VITE_IMGPROXY_URL }}
VITE_SENTRY_DSN: ${{ vars.VITE_SENTRY_DSN }}
VITE_POSTHOG_KEY: ${{ vars.VITE_POSTHOG_KEY }}
VITE_OPENPANEL_CLIENT_ID: ${{ vars.VITE_OPENPANEL_CLIENT_ID }}
VITE_OPENPANEL_API_URL: ${{ vars.VITE_OPENPANEL_API_URL }}
VITE_FIREBASE_CONFIG: ${{ vars.VITE_FIREBASE_CONFIG }}
NODE_OPTIONS: --max-old-space-size=8192

View File

@ -9,7 +9,8 @@ env:
VITE_API_URL: ${{ vars.VITE_API_URL }}
VITE_IMGPROXY_URL: ${{ vars.VITE_IMGPROXY_URL }}
VITE_SENTRY_DSN: ${{ vars.VITE_SENTRY_DSN }}
VITE_POSTHOG_KEY: ${{ vars.VITE_POSTHOG_KEY }}
VITE_OPENPANEL_CLIENT_ID: ${{ vars.VITE_OPENPANEL_CLIENT_ID }}
VITE_OPENPANEL_API_URL: ${{ vars.VITE_OPENPANEL_API_URL }}
VITE_FIREBASE_CONFIG: ${{ vars.VITE_FIREBASE_CONFIG }}
NODE_OPTIONS: --max-old-space-size=8192

View File

@ -72,6 +72,7 @@ function bootstrap() {
userAgent = userAgent.replace(/\s?Electron\/[\d.]+/, "")
userAgent = userAgent.replace(/\s?Follow\/[\d.a-zA-Z-]+/, "")
}
details.requestHeaders["Origin"] = "https://app.follow.is"
details.requestHeaders["User-Agent"] = userAgent
callback({ cancel: false, requestHeaders: details.requestHeaders })
})

View File

@ -1,17 +0,0 @@
import { env } from "@follow/shared/env"
import { PostHog } from "posthog-node"
import { getUser } from "./user"
export const initPosthog = () => {
if (env.VITE_POSTHOG_KEY === undefined) return
return new PostHog(env.VITE_POSTHOG_KEY, {})
}
export const posthog = initPosthog()
export const trackEvent = (event: string, properties?: Record<string, any>) => {
const userId = getUser()?.id
if (!userId) return
posthog?.capture({ event, properties, distinctId: userId })
}

View File

@ -1,6 +1,5 @@
import type { User } from "@auth/core/types"
import { posthog } from "../lib/posthog"
import { setUser } from "../lib/user"
import { t } from "./_instance"
@ -13,13 +12,5 @@ export const trackerRoute = {
const { user } = input
setUser(user)
posthog?.capture({
event: "login",
distinctId: user.id ?? "",
properties: {
name: user.name,
handle: user.handle ?? "",
},
})
}),
}

View File

@ -2,7 +2,6 @@ import { getRendererHandlers } from "@egoist/tipc/main"
import { autoUpdater } from "electron-updater"
import { channel, isDev } from "../env"
import { trackEvent } from "../lib/posthog"
import { logger } from "../logger"
import type { RendererHandlers } from "../renderer-handlers"
import { destroyMainWindow, getMainWindow } from "../window"
@ -112,7 +111,7 @@ export const registerUpdater = async () => {
autoUpdater.on("download-progress", (e) => {
logger.info(`Download progress: ${e.percent}`)
})
autoUpdater.on("update-downloaded", (e) => {
autoUpdater.on("update-downloaded", () => {
downloading = false
logger.info("Update downloaded, ready to install")
@ -120,10 +119,6 @@ export const registerUpdater = async () => {
if (!mainWindow) return
const handlers = getRendererHandlers<RendererHandlers>(mainWindow.webContents)
trackEvent("update_ready_to_install", {
version: e.version,
releaseVersion: e.releaseName,
})
handlers.updateDownloaded.send()
})
autoUpdater.on("error", (e) => {

View File

@ -20,6 +20,7 @@
"@lottiefiles/dotlottie-react": "0.9.1",
"@microflash/remark-callout-directives": "4.3.1",
"@mozilla/readability": "^0.5.0",
"@openpanel/web": "1.0.1",
"@radix-ui/react-avatar": "1.1.1",
"@radix-ui/react-checkbox": "1.1.2",
"@radix-ui/react-context-menu": "2.2.2",
@ -55,6 +56,7 @@
"dexie": "4.0.8",
"dnum": "^2.14.0",
"electron-log": "5.2.0",
"firebase": "10.14.1",
"foxact": "0.2.39",
"framer-motion": "11.11.9",
"franc-min": "6.2.0",
@ -73,7 +75,7 @@
"nanoid": "5.0.7",
"ofetch": "1.4.1",
"path-to-regexp": "8.2.0",
"posthog-js": "1.169.0",
"posthog-js": "1.169.1",
"re-resizable": "6.10.0",
"react-blurhash": "^0.3.0",
"react-error-boundary": "4.0.13",

View File

@ -70,7 +70,7 @@ const AppLayer = () => {
useEffect(() => {
const doneTime = Math.trunc(performance.now())
window.posthog?.capture("ui_render_init", {
window.analytics?.capture("ui_render_init", {
time: doneTime,
})
appLog("App is ready", `${doneTime}ms`)

View File

@ -26,7 +26,7 @@ const ImpressionViewImpl: Component<ImpressionProps> = memo((props) => {
}
setImpression(true)
window.posthog?.capture(props.event, {
window.analytics?.capture(props.event, {
impression: 1,
...props.properties,
})

View File

@ -1,37 +1,39 @@
import { useAtomValue } from "jotai"
import PostHog from "posthog-js"
import { useFeatureFlagEnabled } from "posthog-js/react"
// import { useAtomValue } from "jotai"
// import PostHog from "posthog-js"
// import { useFeatureFlagEnabled } from "posthog-js/react"
import { jotaiStore } from "~/lib/jotai"
import type { FeatureKeys } from "~/modules/ab/atoms"
import { debugFeaturesAtom, enableDebugOverrideAtom, IS_DEBUG_ENV } from "~/modules/ab/atoms"
import { abPayloadFallback } from "~/modules/ab/fallback"
// import { jotaiStore } from "~/lib/jotai"
// import type { FeatureKeys } from "~/modules/ab/atoms"
// import { debugFeaturesAtom, enableDebugOverrideAtom, IS_DEBUG_ENV } from "~/modules/ab/atoms"
// import { abPayloadFallback } from "~/modules/ab/fallback"
export const useAb = (feature: FeatureKeys) => {
const isEnableDebugOverrides = useAtomValue(enableDebugOverrideAtom)
const debugFeatureOverrides = useAtomValue(debugFeaturesAtom)
// export const useAb = (feature: FeatureKeys) => {
// const isEnableDebugOverrides = useAtomValue(enableDebugOverrideAtom)
// const debugFeatureOverrides = useAtomValue(debugFeaturesAtom)
const isEnabled = useFeatureFlagEnabled(feature)
// const isEnabled = useFeatureFlagEnabled(feature)
if (IS_DEBUG_ENV && isEnableDebugOverrides) return debugFeatureOverrides[feature]
// if (IS_DEBUG_ENV && isEnableDebugOverrides) return debugFeatureOverrides[feature]
return isEnabled
}
// return isEnabled
// }
export const isAbEnabled = (feature: FeatureKeys) => {
const featureFlag = PostHog.getFeatureFlag(feature)
const enabled = typeof featureFlag === "boolean" ? featureFlag : featureFlag === "enabled"
const debugOverride = jotaiStore.get(debugFeaturesAtom)
// export const isAbEnabled = (feature: FeatureKeys) => {
// const featureFlag = PostHog.getFeatureFlag(feature)
// const enabled = typeof featureFlag === "boolean" ? featureFlag : featureFlag === "enabled"
// const debugOverride = jotaiStore.get(debugFeaturesAtom)
const isEnableOverride = jotaiStore.get(enableDebugOverrideAtom)
// const isEnableOverride = jotaiStore.get(enableDebugOverrideAtom)
if (isEnableOverride) {
return debugOverride[feature]
}
// if (isEnableOverride) {
// return debugOverride[feature]
// }
return enabled
}
// return enabled
// }
export const getAbValue = (feature: FeatureKeys) => {
return PostHog.getFeatureFlagPayload(feature) || abPayloadFallback[feature]
}
// export const getAbValue = (feature: FeatureKeys) => {
// return PostHog.getFeatureFlagPayload(feature) || abPayloadFallback[feature]
// }
export {}

View File

@ -58,8 +58,8 @@ export const navigateEntry = (options: NavigateEntryOptions) => {
const finalView = nextSearchParams.get("view")
if (window.posthog) {
window.posthog.capture("Navigate Entry", {
if (window.analytics) {
window.analytics.capture("Navigate Entry", {
feedId: finalFeedId,
entryId,
view: finalView ? Number.parseInt(finalView, 10) : FeedViewType.Articles,

View File

@ -17,7 +17,7 @@ export const useSignOut = () =>
// Clear local storage
clearStorage()
window.posthog?.reset()
window.analytics?.reset()
// clear local store data
await Promise.allSettled([clearLocalPersistStoreData(), tipcClient?.cleanAuthSessionToken()])
// Sign out

View File

@ -0,0 +1,45 @@
import { env } from "@follow/shared/env"
import type { TrackProperties } from "@openpanel/web"
import { getGeneralSettings } from "~/atoms/settings/general"
import { op } from "./op"
import { initPostHog } from "./posthog"
declare global {
interface Window {
analytics?: {
capture: (event_name: string, properties?: TrackProperties | null) => void
reset: () => void
}
}
}
export const initAnalytics = () => {
// TODO remove this
initPostHog()
if (env.VITE_OPENPANEL_CLIENT_ID === undefined) return
op.setGlobalProperties({
build: ELECTRON ? "electron" : "web",
version: APP_VERSION,
hash: GIT_COMMIT_SHA,
})
window.analytics = {
reset: () => {
// op.clear()
// TODO remove this if op ready
window.posthog?.reset()
},
capture(event_name: string, properties?: TrackProperties | null) {
if (import.meta.env.DEV) return
if (!getGeneralSettings().sendAnonymousData) {
return
}
// TODO remove this if op ready
window.posthog?.capture(event_name, properties as TrackProperties)
op.track(event_name, properties as TrackProperties)
},
}
}

View File

@ -0,0 +1,19 @@
import { getAnalytics } from "firebase/analytics"
import { initializeApp } from "firebase/app"
// See: https://firebase.google.com/docs/web/learn-more#config-object
// For Firebase JavaScript SDK v7.20.0 and later, `measurementId` is an optional field
const firebaseConfig = {
apiKey: "AIzaSyDuM93019tp8VI7wsszJv8ChOs7b1EE5Hk",
authDomain: "follow-428106.firebaseapp.com",
projectId: "follow-428106",
storageBucket: "follow-428106.appspot.com",
messagingSenderId: "194977404578",
appId: "1:194977404578:web:1920bb0c9ea5e2373669fb",
measurementId: "G-SJE57D4F14",
}
// Initialize Firebase
const app = initializeApp(firebaseConfig)
// Initialize Analytics and get a reference to the service
export const analytics = getAnalytics(app)

View File

@ -1,15 +1,20 @@
import type { User } from "@auth/core/types"
export const setIntegrationIdentify = (user: User) =>
Promise.all([
import("@sentry/react").then(({ setTag }) => {
setTag("user_id", user.id)
setTag("user_name", user.name)
}),
import("posthog-js").then(({ default: posthog }) => {
posthog.identify(user.id, {
name: user.name,
handle: user.handle,
})
}),
])
import { op } from "./op"
export const setIntegrationIdentify = async (user: User) => {
op.identify({
profileId: user.id,
email: user.email,
avatar: user.image,
lastName: user.name,
properties: {
handle: user.handle,
name: user.name,
},
})
await import("@sentry/react").then(({ setTag }) => {
setTag("user_id", user.id)
setTag("user_name", user.name)
})
}

View File

@ -19,9 +19,9 @@ import { CleanerService } from "~/services/cleaner"
import { subscribeNetworkStatus } from "../atoms/network"
import { getGeneralSettings, subscribeShouldUseIndexedDB } from "../atoms/settings/general"
import { appLog } from "../lib/log"
import { initAnalytics } from "./analytics"
import { hydrateDatabaseToStore, hydrateSettings, setHydrated } from "./hydrate"
import { doMigration } from "./migrates"
import { initPostHog } from "./posthog"
import { initSentry } from "./sentry"
const cleanup = subscribeShouldUseIndexedDB((value) => {
@ -93,7 +93,7 @@ export const initializeApp = async () => {
const { dataPersist: enabledDataPersist } = getGeneralSettings()
initSentry()
initPostHog()
initAnalytics()
await apm("i18n", initI18n)
let dataHydratedTime: undefined | number
@ -106,7 +106,7 @@ export const initializeApp = async () => {
const loadingTime = Date.now() - now
appLog(`Initialize ${APP_NAME} done,`, `${loadingTime}ms`)
window.posthog?.capture("app_init", {
window.analytics?.capture("app_init", {
electron: IN_ELECTRON,
loading_time: loadingTime,
using_indexed_db: enabledDataPersist,

View File

@ -0,0 +1,10 @@
import { env } from "@follow/shared/env"
import { OpenPanel } from "@openpanel/web"
export const op = new OpenPanel({
clientId: env.VITE_OPENPANEL_CLIENT_ID,
trackScreenViews: true,
trackOutgoingLinks: true,
trackAttributes: true,
apiUrl: env.VITE_OPENPANEL_API_URL,
})

View File

@ -15,10 +15,7 @@ import { SentryConfig } from "../configs"
export const initSentry = async () => {
if (!window.SENTRY_RELEASE) return
if (import.meta.env.DEV) return
const [Sentry, posthog] = await Promise.all([
import("@sentry/react"),
import("posthog-js").then((module) => module.default),
])
const Sentry = await import("@sentry/react")
Sentry.init({
dsn: env.VITE_SENTRY_DSN,
environment: RELEASE_CHANNEL,
@ -35,12 +32,6 @@ export const initSentry = async () => {
Sentry.captureConsoleIntegration({
levels: ["error"],
}),
posthog.sentryIntegration({
organization: "follow-rg",
projectId: 4507570439979008,
severityAllowList: ["error", "info"], // optional: here is set to handle captureMessage (info) and captureException (error)
}),
],
...SentryConfig,
})

View File

@ -1,30 +1,32 @@
import type { FC } from "react"
import { forwardRef } from "react"
// import type { FC } from "react"
// import { forwardRef } from "react"
import { useAb } from "~/hooks/biz/useAb"
// import { useAb } from "~/hooks/biz/useAb"
import type { FeatureKeys } from "./atoms"
// import type { FeatureKeys } from "./atoms"
const Noop = () => null
export const withFeature =
(feature: FeatureKeys) =>
<T extends object>(
Component: FC<T>,
// const Noop = () => null
// export const withFeature =
// (feature: FeatureKeys) =>
// <T extends object>(
// Component: FC<T>,
FallbackComponent: any = Noop,
) => {
// @ts-expect-error
const WithFeature = forwardRef((props: T, ref: any) => {
const isEnabled = useAb(feature)
// FallbackComponent: any = Noop,
// ) => {
// // @ts-expect-error
// const WithFeature = forwardRef((props: T, ref: any) => {
// const isEnabled = useAb(feature)
if (isEnabled === undefined) return null
// if (isEnabled === undefined) return null
return isEnabled ? (
<Component {...props} ref={ref} />
) : (
<FallbackComponent {...props} ref={ref} />
)
})
// return isEnabled ? (
// <Component {...props} ref={ref} />
// ) : (
// <FallbackComponent {...props} ref={ref} />
// )
// })
return WithFeature
}
// return WithFeature
// }
export {}

View File

@ -1,84 +1,72 @@
import { useAtomValue, useSetAtom } from "jotai"
import { Divider } from "~/components/ui/divider"
import { Label } from "~/components/ui/label"
import { useModalStack } from "~/components/ui/modal"
import { RootPortal } from "~/components/ui/portal"
import { Switch } from "~/components/ui/switch"
import type { FeatureKeys } from "./atoms"
import { debugFeaturesAtom, enableDebugOverrideAtom, IS_DEBUG_ENV } from "./atoms"
export const FeatureFlagDebugger = () => {
if (IS_DEBUG_ENV) return <DebugToggle />
return null
// if (IS_DEBUG_ENV) return <DebugToggle />
}
const DebugToggle = () => {
const { present } = useModalStack()
return (
<RootPortal>
<div
tabIndex={-1}
onClick={() => {
present({
title: "A/B",
content: ABModalContent,
})
}}
className="fixed bottom-5 right-0 flex size-5 items-center justify-center opacity-40 duration-200 hover:opacity-100"
>
<i className="i-mingcute-switch-line" />
</div>
</RootPortal>
)
}
// const DebugToggle = () => {
// const { present } = useModalStack()
// return (
// <RootPortal>
// <div
// tabIndex={-1}
// onClick={() => {
// present({
// title: "A/B",
// content: ABModalContent,
// })
// }}
// className="fixed bottom-5 right-0 flex size-5 items-center justify-center opacity-40 duration-200 hover:opacity-100"
// >
// <i className="i-mingcute-switch-line" />
// </div>
// </RootPortal>
// )
// }
const SwitchInternal = ({ Key }: { Key: FeatureKeys }) => {
const enabled = useAtomValue(debugFeaturesAtom)[Key]
const setDebugFeatures = useSetAtom(debugFeaturesAtom)
return (
<Switch
checked={enabled}
onCheckedChange={(checked) => {
setDebugFeatures((prev) => ({ ...prev, [Key]: checked }))
}}
/>
)
}
// const SwitchInternal = ({ Key }: { Key: FeatureKeys }) => {
// const enabled = useAtomValue(debugFeaturesAtom)[Key]
// const setDebugFeatures = useSetAtom(debugFeaturesAtom)
// return (
// <Switch
// checked={enabled}
// onCheckedChange={(checked) => {
// setDebugFeatures((prev) => ({ ...prev, [Key]: checked }))
// }}
// />
// )
// }
const ABModalContent = () => {
const features = useAtomValue(debugFeaturesAtom)
// const ABModalContent = () => {
// const features = useAtomValue(debugFeaturesAtom)
const enableOverride = useAtomValue(enableDebugOverrideAtom)
const setEnableDebugOverride = useSetAtom(enableDebugOverrideAtom)
return (
<div>
<Label className="flex items-center justify-between gap-4">
Enable Override A/B
<Switch
checked={enableOverride}
onCheckedChange={(checked) => {
setEnableDebugOverride(checked)
}}
/>
</Label>
// const enableOverride = useAtomValue(enableDebugOverrideAtom)
// const setEnableDebugOverride = useSetAtom(enableDebugOverrideAtom)
// return (
// <div>
// <Label className="flex items-center justify-between gap-4">
// Enable Override A/B
// <Switch
// checked={enableOverride}
// onCheckedChange={(checked) => {
// setEnableDebugOverride(checked)
// }}
// />
// </Label>
<Divider />
// <Divider />
<div className={enableOverride ? "opacity-100" : "pointer-events-none opacity-40"}>
{Object.keys(features).map((key) => {
return (
<div key={key} className="flex w-full items-center justify-between">
<Label className="flex w-full items-center justify-between gap-4 text-sm">
{key}
<SwitchInternal Key={key as any} />
</Label>
</div>
)
})}
</div>
</div>
)
}
// <div className={enableOverride ? "opacity-100" : "pointer-events-none opacity-40"}>
// {Object.keys(features).map((key) => {
// return (
// <div key={key} className="flex w-full items-center justify-between">
// <Label className="flex w-full items-center justify-between gap-4 text-sm">
// {key}
// <SwitchInternal Key={key as any} />
// </Label>
// </div>
// )
// })}
// </div>
// </div>
// )
// }

View File

@ -171,7 +171,7 @@ const DailyReportButton: FC = () => {
<ActionButton
onClick={() => {
present()
window.posthog?.capture("Daily Report Modal", {
window.analytics?.capture("Daily Report Modal", {
click: 1,
})
}}
@ -216,7 +216,7 @@ const SwitchToMasonryButton = () => {
<ActionButton
onClick={() => {
setUISetting("pictureViewMasonry", !isMasonry)
window.posthog?.capture("Switch to Masonry", {
window.analytics?.capture("Switch to Masonry", {
masonry: !isMasonry ? 1 : 0,
click: 1,
})
@ -250,7 +250,7 @@ const WideModeButton = () => {
setUISetting("wideMode", !isWideMode)
// TODO: Remove this after useMeasure can get bounds in time
window.dispatchEvent(new Event("resize"))
window.posthog?.capture("Switch to Wide Mode", {
window.analytics?.capture("Switch to Wide Mode", {
wideMode: !isWideMode ? 1 : 0,
click: 1,
})

View File

@ -22,7 +22,7 @@ export const AutoUpdater = () => {
const handleClick = useCallback(() => {
setUpdaterStatus(false)
window.posthog?.capture("update_restart")
window.analytics?.capture("update_restart")
tipcClient?.quitAndInstall()
}, [])

View File

@ -68,15 +68,11 @@ const usePlayerTracker = () => {
useEffect(() => {
const handler = () => {
const playerState = getAudioPlayerAtomValue()
window.posthog?.capture(
"player_open_duration",
{
duration: Date.now() - playerOpenAt,
status: playerState.status,
trigger: "beforeunload",
},
{ transport: "sendBeacon" },
)
window.analytics?.capture("player_open_duration", {
duration: Date.now() - playerOpenAt,
status: playerState.status,
trigger: "beforeunload",
})
}
window.addEventListener("beforeunload", handler)
@ -86,7 +82,7 @@ const usePlayerTracker = () => {
useEffect(() => {
if (!show) {
const playerState = getAudioPlayerAtomValue()
window.posthog?.capture("player_open_duration", {
window.analytics?.capture("player_open_duration", {
duration: Date.now() - playerOpenAt,
status: playerState.status,
trigger: "manual",

View File

@ -46,7 +46,7 @@ export const SearchCmdK: React.FC = () => {
React.useEffect(() => {
if (!open) return
window.posthog?.capture("search_open")
window.analytics?.capture("search_open")
// Refresh data
setPage(0)
setSearchInstance(() => searchActions.createLocalDbSearch())

View File

@ -44,7 +44,7 @@ const CmdNPanel = () => {
const defaultView = getSidebarActiveView() as FeedViewType
window.posthog?.capture("quick_add_feed", { url, defaultView })
window.analytics?.capture("quick_add_feed", { url, defaultView })
present({
title: "Add Feed",

View File

@ -27,7 +27,7 @@ import {
} from "~/components/ui/select"
import { useProxyValue, useSetProxy } from "~/hooks/biz/useProxySetting"
import { fallbackLanguage } from "~/i18n"
import { initPostHog } from "~/initialize/posthog"
import { initAnalytics } from "~/initialize/analytics"
import { tipcClient } from "~/lib/client"
import { cn } from "~/lib/utils"
import { clearLocalPersistStoreData } from "~/store/utils/clear"
@ -125,10 +125,10 @@ export const SettingGeneral = () => {
onChange(value) {
setGeneralSetting("sendAnonymousData", value)
if (value) {
initPostHog()
initAnalytics()
} else {
window.posthog?.reset()
delete window.posthog
window.analytics?.reset()
delete window.analytics
}
},
}),

View File

@ -23,7 +23,7 @@ export const useTipModal = ({
toast.error("Invalid feed id or entry id")
return
}
window.posthog?.capture("tip_modal_opened", { entryId })
window.analytics?.capture("tip_modal_opened", { entryId })
present({
title: t("tip_modal.tip_title"),
content: () => createElement(TipModalContent, { userId, feedId, entryId }),

View File

@ -1,4 +1,4 @@
import { useEffect, useLayoutEffect } from "react"
import { useLayoutEffect } from "react"
import type { NavigateFunction } from "react-router-dom"
import { useLocation, useNavigate, useParams, useSearchParams } from "react-router-dom"
@ -43,19 +43,5 @@ export const StableRouterProvider = () => {
setNavigate({ fn: nav })
}, [searchParams, params, location, nav])
// Posthog tracking
useEffect(() => {
const { pathname } = location
if (pathname && window.posthog) {
let url = window.origin + pathname
if (searchParams.toString()) {
url = `${url}?${searchParams.toString()}`
}
window.posthog.capture("$pageview", {
$current_url: url,
})
}
}, [location, searchParams])
return null
}

View File

@ -61,7 +61,7 @@ export const useClaimFeedMutation = (feedId: string) =>
toastFetchError(err)
},
onSuccess() {
window.posthog?.capture("feed_claimed", {
window.analytics?.capture("feed_claimed", {
feedId,
})
},

View File

@ -95,7 +95,7 @@ export const useClaimWalletDailyRewardMutation = () => {
onSuccess() {
wallet.get().invalidate()
wallet.claimCheck().invalidate()
window.posthog?.capture("daily_reward_claimed")
window.analytics?.capture("daily_reward_claimed")
toast(
<div className="flex items-center gap-1 text-lg" onClick={() => navigate("/power")}>
@ -124,7 +124,7 @@ export const useWalletTipMutation = () =>
onSuccess(_, variables) {
wallet.get().invalidate()
wallet.transactions.get().invalidate()
window.posthog?.capture("tip_sent", {
window.analytics?.capture("tip_sent", {
amount: variables.amount,
entryId: variables.entryId,
})

View File

@ -9,9 +9,12 @@ export const env = createEnv({
VITE_API_URL: z.string().url(),
VITE_IMGPROXY_URL: z.string().url(),
VITE_SENTRY_DSN: z.string().optional(),
VITE_POSTHOG_KEY: z.string().optional(),
VITE_INBOXES_EMAIL: z.string().default("@follow.re"),
VITE_FIREBASE_CONFIG: z.string().optional(),
VITE_OPENPANEL_CLIENT_ID: z.string(),
VITE_OPENPANEL_API_URL: z.string().url(),
VITE_POSTHOG_KEY: z.string().optional(),
},
emptyStringAsUndefined: true,

View File

@ -11,9 +11,11 @@ export function createDependencyChunksPlugin(dependencies: string[][]): Plugin {
const { output } = config.build.rollupOptions
const outputConfig = Array.isArray(output) ? output[0] : output
outputConfig.manualChunks = outputConfig.manualChunks || {}
outputConfig.assetFileNames = "assets/[name].[hash][extname]"
outputConfig.assetFileNames = "assets/[name].[hash:6][extname]"
outputConfig.chunkFileNames = (chunkInfo) => {
return chunkInfo.name.startsWith("vendor/") ? "[name].[hash].js" : "assets/[name].[hash].js"
return chunkInfo.name.startsWith("vendor/")
? "[name].[hash].js"
: "assets/[name].[hash:9].js"
}
const manualChunks = Array.isArray(output) ? output[0].manualChunks : output.manualChunks
@ -22,7 +24,7 @@ export function createDependencyChunksPlugin(dependencies: string[][]): Plugin {
dependencies.forEach((dep, index) => {
if (Array.isArray(dep)) {
const chunkName = `vendor/a${index}`
const chunkName = `vendor/${index}`
manualChunks[chunkName] = dep
} else {
manualChunks[`vendor/${dep}`] = [dep]

View File

@ -354,6 +354,9 @@ importers:
'@mozilla/readability':
specifier: ^0.5.0
version: 0.5.0(patch_hash=43niildbdafdxi7qfcwhpkkxwa)
'@openpanel/web':
specifier: 1.0.1
version: 1.0.1
'@radix-ui/react-avatar':
specifier: 1.1.1
version: 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@ -459,6 +462,9 @@ importers:
electron-log:
specifier: 5.2.0
version: 5.2.0
firebase:
specifier: 10.14.1
version: 10.14.1
foxact:
specifier: 0.2.39
version: 0.2.39(react@18.3.1)
@ -514,8 +520,8 @@ importers:
specifier: 8.2.0
version: 8.2.0
posthog-js:
specifier: 1.169.0
version: 1.169.0
specifier: 1.169.1
version: 1.169.1
re-resizable:
specifier: 6.10.0
version: 6.10.0(patch_hash=yitcmpfwcomg2fky72uc3lhk2i)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@ -1987,6 +1993,200 @@ packages:
'@essentials/request-timeout@1.3.0':
resolution: {integrity: sha512-lKZPhKScNFnR1MBnk4+sxshk46fpvdN+Uh1LlKWFO5g1ocuz4EcknNIL7tm/rsCAs/+xMWiBTwbDUvm+pDNlXw==}
'@firebase/analytics-compat@0.2.14':
resolution: {integrity: sha512-unRVY6SvRqfNFIAA/kwl4vK+lvQAL2HVcgu9zTrUtTyYDmtIt/lOuHJynBMYEgLnKm39YKBDhtqdapP2e++ASw==}
peerDependencies:
'@firebase/app-compat': 0.x
'@firebase/analytics-types@0.8.2':
resolution: {integrity: sha512-EnzNNLh+9/sJsimsA/FGqzakmrAUKLeJvjRHlg8df1f97NLUlFidk9600y0ZgWOp3CAxn6Hjtk+08tixlUOWyw==}
'@firebase/analytics@0.10.8':
resolution: {integrity: sha512-CVnHcS4iRJPqtIDc411+UmFldk0ShSK3OB+D0bKD8Ck5Vro6dbK5+APZpkuWpbfdL359DIQUnAaMLE+zs/PVyA==}
peerDependencies:
'@firebase/app': 0.x
'@firebase/app-check-compat@0.3.15':
resolution: {integrity: sha512-zFIvIFFNqDXpOT2huorz9cwf56VT3oJYRFjSFYdSbGYEJYEaXjLJbfC79lx/zjx4Fh+yuN8pry3TtvwaevrGbg==}
peerDependencies:
'@firebase/app-compat': 0.x
'@firebase/app-check-interop-types@0.3.2':
resolution: {integrity: sha512-LMs47Vinv2HBMZi49C09dJxp0QT5LwDzFaVGf/+ITHe3BlIhUiLNttkATSXplc89A2lAaeTqjgqVkiRfUGyQiQ==}
'@firebase/app-check-types@0.5.2':
resolution: {integrity: sha512-FSOEzTzL5bLUbD2co3Zut46iyPWML6xc4x+78TeaXMSuJap5QObfb+rVvZJtla3asN4RwU7elaQaduP+HFizDA==}
'@firebase/app-check@0.8.8':
resolution: {integrity: sha512-O49RGF1xj7k6BuhxGpHmqOW5hqBIAEbt2q6POW0lIywx7emYtzPDeQI+ryQpC4zbKX646SoVZ711TN1DBLNSOQ==}
peerDependencies:
'@firebase/app': 0.x
'@firebase/app-compat@0.2.43':
resolution: {integrity: sha512-HM96ZyIblXjAC7TzE8wIk2QhHlSvksYkQ4Ukh1GmEenzkucSNUmUX4QvoKrqeWsLEQ8hdcojABeCV8ybVyZmeg==}
'@firebase/app-types@0.9.2':
resolution: {integrity: sha512-oMEZ1TDlBz479lmABwWsWjzHwheQKiAgnuKxE0pz0IXCVx7/rtlkx1fQ6GfgK24WCrxDKMplZrT50Kh04iMbXQ==}
'@firebase/app@0.10.13':
resolution: {integrity: sha512-OZiDAEK/lDB6xy/XzYAyJJkaDqmQ+BCtOEPLqFvxWKUz5JbBmej7IiiRHdtiIOD/twW7O5AxVsfaaGA/V1bNsA==}
'@firebase/auth-compat@0.5.14':
resolution: {integrity: sha512-2eczCSqBl1KUPJacZlFpQayvpilg3dxXLy9cSMTKtQMTQSmondUtPI47P3ikH3bQAXhzKLOE+qVxJ3/IRtu9pw==}
peerDependencies:
'@firebase/app-compat': 0.x
'@firebase/auth-interop-types@0.2.3':
resolution: {integrity: sha512-Fc9wuJGgxoxQeavybiuwgyi+0rssr76b+nHpj+eGhXFYAdudMWyfBHvFL/I5fEHniUM/UQdFzi9VXJK2iZF7FQ==}
'@firebase/auth-types@0.12.2':
resolution: {integrity: sha512-qsEBaRMoGvHO10unlDJhaKSuPn4pyoTtlQuP1ghZfzB6rNQPuhp/N/DcFZxm9i4v0SogjCbf9reWupwIvfmH6w==}
peerDependencies:
'@firebase/app-types': 0.x
'@firebase/util': 1.x
'@firebase/auth@1.7.9':
resolution: {integrity: sha512-yLD5095kVgDw965jepMyUrIgDklD6qH/BZNHeKOgvu7pchOKNjVM+zQoOVYJIKWMWOWBq8IRNVU6NXzBbozaJg==}
peerDependencies:
'@firebase/app': 0.x
'@react-native-async-storage/async-storage': ^1.18.1
peerDependenciesMeta:
'@react-native-async-storage/async-storage':
optional: true
'@firebase/component@0.6.9':
resolution: {integrity: sha512-gm8EUEJE/fEac86AvHn8Z/QW8BvR56TBw3hMW0O838J/1mThYQXAIQBgUv75EqlCZfdawpWLrKt1uXvp9ciK3Q==}
'@firebase/data-connect@0.1.0':
resolution: {integrity: sha512-vSe5s8dY13ilhLnfY0eYRmQsdTbH7PUFZtBbqU6JVX/j8Qp9A6G5gG6//ulbX9/1JFOF1IWNOne9c8S/DOCJaQ==}
peerDependencies:
'@firebase/app': 0.x
'@firebase/database-compat@1.0.8':
resolution: {integrity: sha512-OpeWZoPE3sGIRPBKYnW9wLad25RaWbGyk7fFQe4xnJQKRzlynWeFBSRRAoLE2Old01WXwskUiucNqUUVlFsceg==}
'@firebase/database-types@1.0.5':
resolution: {integrity: sha512-fTlqCNwFYyq/C6W7AJ5OCuq5CeZuBEsEwptnVxlNPkWCo5cTTyukzAHRSO/jaQcItz33FfYrrFk1SJofcu2AaQ==}
'@firebase/database@1.0.8':
resolution: {integrity: sha512-dzXALZeBI1U5TXt6619cv0+tgEhJiwlUtQ55WNZY7vGAjv7Q1QioV969iYwt1AQQ0ovHnEW0YW9TiBfefLvErg==}
'@firebase/firestore-compat@0.3.38':
resolution: {integrity: sha512-GoS0bIMMkjpLni6StSwRJarpu2+S5m346Na7gr9YZ/BZ/W3/8iHGNr9PxC+f0rNZXqS4fGRn88pICjrZEgbkqQ==}
peerDependencies:
'@firebase/app-compat': 0.x
'@firebase/firestore-types@3.0.2':
resolution: {integrity: sha512-wp1A+t5rI2Qc/2q7r2ZpjUXkRVPtGMd6zCLsiWurjsQpqPgFin3AhNibKcIzoF2rnToNa/XYtyWXuifjOOwDgg==}
peerDependencies:
'@firebase/app-types': 0.x
'@firebase/util': 1.x
'@firebase/firestore@4.7.3':
resolution: {integrity: sha512-NwVU+JPZ/3bhvNSJMCSzfcBZZg8SUGyzZ2T0EW3/bkUeefCyzMISSt/TTIfEHc8cdyXGlMqfGe3/62u9s74UEg==}
engines: {node: '>=10.10.0'}
peerDependencies:
'@firebase/app': 0.x
'@firebase/functions-compat@0.3.14':
resolution: {integrity: sha512-dZ0PKOKQFnOlMfcim39XzaXonSuPPAVuzpqA4ONTIdyaJK/OnBaIEVs/+BH4faa1a2tLeR+Jy15PKqDRQoNIJw==}
peerDependencies:
'@firebase/app-compat': 0.x
'@firebase/functions-types@0.6.2':
resolution: {integrity: sha512-0KiJ9lZ28nS2iJJvimpY4nNccV21rkQyor5Iheu/nq8aKXJqtJdeSlZDspjPSBBiHRzo7/GMUttegnsEITqR+w==}
'@firebase/functions@0.11.8':
resolution: {integrity: sha512-Lo2rTPDn96naFIlSZKVd1yvRRqqqwiJk7cf9TZhUerwnPKgBzXy+aHE22ry+6EjCaQusUoNai6mU6p+G8QZT1g==}
peerDependencies:
'@firebase/app': 0.x
'@firebase/installations-compat@0.2.9':
resolution: {integrity: sha512-2lfdc6kPXR7WaL4FCQSQUhXcPbI7ol3wF+vkgtU25r77OxPf8F/VmswQ7sgIkBBWtymn5ZF20TIKtnOj9rjb6w==}
peerDependencies:
'@firebase/app-compat': 0.x
'@firebase/installations-types@0.5.2':
resolution: {integrity: sha512-que84TqGRZJpJKHBlF2pkvc1YcXrtEDOVGiDjovP/a3s6W4nlbohGXEsBJo0JCeeg/UG9A+DEZVDUV9GpklUzA==}
peerDependencies:
'@firebase/app-types': 0.x
'@firebase/installations@0.6.9':
resolution: {integrity: sha512-hlT7AwCiKghOX3XizLxXOsTFiFCQnp/oj86zp1UxwDGmyzsyoxtX+UIZyVyH/oBF5+XtblFG9KZzZQ/h+dpy+Q==}
peerDependencies:
'@firebase/app': 0.x
'@firebase/logger@0.4.2':
resolution: {integrity: sha512-Q1VuA5M1Gjqrwom6I6NUU4lQXdo9IAQieXlujeHZWvRt1b7qQ0KwBaNAjgxG27jgF9/mUwsNmO8ptBCGVYhB0A==}
'@firebase/messaging-compat@0.2.12':
resolution: {integrity: sha512-pKsiUVZrbmRgdImYqhBNZlkKJbqjlPkVdQRZGRbkTyX4OSGKR0F/oJeCt1a8jEg5UnBp4fdVwSWSp4DuCovvEQ==}
peerDependencies:
'@firebase/app-compat': 0.x
'@firebase/messaging-interop-types@0.2.2':
resolution: {integrity: sha512-l68HXbuD2PPzDUOFb3aG+nZj5KA3INcPwlocwLZOzPp9rFM9yeuI9YLl6DQfguTX5eAGxO0doTR+rDLDvQb5tA==}
'@firebase/messaging@0.12.12':
resolution: {integrity: sha512-6q0pbzYBJhZEtUoQx7hnPhZvAbuMNuBXKQXOx2YlWhSrlv9N1m0ZzlNpBbu/ItTzrwNKTibdYzUyaaxdWLg+4w==}
peerDependencies:
'@firebase/app': 0.x
'@firebase/performance-compat@0.2.9':
resolution: {integrity: sha512-dNl95IUnpsu3fAfYBZDCVhXNkASE0uo4HYaEPd2/PKscfTvsgqFAOxfAXzBEDOnynDWiaGUnb5M1O00JQ+3FXA==}
peerDependencies:
'@firebase/app-compat': 0.x
'@firebase/performance-types@0.2.2':
resolution: {integrity: sha512-gVq0/lAClVH5STrIdKnHnCo2UcPLjJlDUoEB/tB4KM+hAeHUxWKnpT0nemUPvxZ5nbdY/pybeyMe8Cs29gEcHA==}
'@firebase/performance@0.6.9':
resolution: {integrity: sha512-PnVaak5sqfz5ivhua+HserxTJHtCar/7zM0flCX6NkzBNzJzyzlH4Hs94h2Il0LQB99roBqoE5QT1JqWqcLJHQ==}
peerDependencies:
'@firebase/app': 0.x
'@firebase/remote-config-compat@0.2.9':
resolution: {integrity: sha512-AxzGpWfWFYejH2twxfdOJt5Cfh/ATHONegTd/a0p5flEzsD5JsxXgfkFToop+mypEL3gNwawxrxlZddmDoNxyA==}
peerDependencies:
'@firebase/app-compat': 0.x
'@firebase/remote-config-types@0.3.2':
resolution: {integrity: sha512-0BC4+Ud7y2aPTyhXJTMTFfrGGLqdYXrUB9sJVAB8NiqJswDTc4/2qrE/yfUbnQJhbSi6ZaTTBKyG3n1nplssaA==}
'@firebase/remote-config@0.4.9':
resolution: {integrity: sha512-EO1NLCWSPMHdDSRGwZ73kxEEcTopAxX1naqLJFNApp4hO8WfKfmEpmjxmP5TrrnypjIf2tUkYaKsfbEA7+AMmA==}
peerDependencies:
'@firebase/app': 0.x
'@firebase/storage-compat@0.3.12':
resolution: {integrity: sha512-hA4VWKyGU5bWOll+uwzzhEMMYGu9PlKQc1w4DWxB3aIErWYzonrZjF0icqNQZbwKNIdh8SHjZlFeB2w6OSsjfg==}
peerDependencies:
'@firebase/app-compat': 0.x
'@firebase/storage-types@0.8.2':
resolution: {integrity: sha512-0vWu99rdey0g53lA7IShoA2Lol1jfnPovzLDUBuon65K7uKG9G+L5uO05brD9pMw+l4HRFw23ah3GwTGpEav6g==}
peerDependencies:
'@firebase/app-types': 0.x
'@firebase/util': 1.x
'@firebase/storage@0.13.2':
resolution: {integrity: sha512-fxuJnHshbhVwuJ4FuISLu+/76Aby2sh+44ztjF2ppoe0TELIDxPW6/r1KGlWYt//AD0IodDYYA8ZTN89q8YqUw==}
peerDependencies:
'@firebase/app': 0.x
'@firebase/util@1.10.0':
resolution: {integrity: sha512-xKtx4A668icQqoANRxyDLBLz51TAbDP9KRfpbKGxiCAW346d0BeJe5vN6/hKxxmWwnZ0mautyv39JxviwwQMOQ==}
'@firebase/vertexai-preview@0.0.4':
resolution: {integrity: sha512-EBSqyu9eg8frQlVU9/HjKtHN7odqbh9MtAcVz3WwHj4gLCLOoN9F/o+oxlq3CxvFrd3CNTZwu6d2mZtVlEInng==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@firebase/app': 0.x
'@firebase/app-types': 0.x
'@firebase/webchannel-wrapper@1.0.1':
resolution: {integrity: sha512-jmEnr/pk0yVkA7mIlHNnxCi+wWzOFUg0WyIotgkKAb2u1J7fAeDBcVNSTjTihbAYNusCLQdW5s9IJ5qwnEufcQ==}
'@floating-ui/core@0.6.2':
resolution: {integrity: sha512-jktYRmZwmau63adUG3GKOAVCofBXkk55S/zQ94XOorAHhwqFIOFAy1rSp2N0Wp6/tGbe9V3u/ExlGZypyY17rg==}
@ -2030,6 +2230,15 @@ packages:
'@gar/promisify@1.1.3':
resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==}
'@grpc/grpc-js@1.9.15':
resolution: {integrity: sha512-nqE7Hc0AzI+euzUwDAy0aY5hCp10r734gMGRdU+qOPX0XSceI2ULrcXB5U2xSc5VkWwalCj4M7GzCAygZl2KoQ==}
engines: {node: ^8.13.0 || >=10.10.0}
'@grpc/proto-loader@0.7.13':
resolution: {integrity: sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==}
engines: {node: '>=6'}
hasBin: true
'@headlessui/react@2.1.10':
resolution: {integrity: sha512-6mLa2fjMDAFQi+/R10B+zU3edsUk/MDtENB2zHho0lqKU1uzhAfJLUduWds4nCo8wbl3vULtC5rJfZAQ1yqIng==}
engines: {node: '>=10'}
@ -2282,6 +2491,12 @@ packages:
'@octokit/types@6.41.0':
resolution: {integrity: sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==}
'@openpanel/sdk@1.0.0':
resolution: {integrity: sha512-FNmmfjdXoC/VHEjA+WkrQ4lyM5lxEmV7xDd57uj4E+lIS0sU3DLG2mV/dpS8AscnZbUvuMn3kPhiLCqYzuv/gg==}
'@openpanel/web@1.0.1':
resolution: {integrity: sha512-cVZ7Kr9SicczJ/RDIfEtZs8+1iGDzwkabVA/j3NqSl8VSucsC8m1+LVbjmCDzCJNnK4yVn6tEcc9PJRi2rtllw==}
'@opentelemetry/api-logs@0.52.1':
resolution: {integrity: sha512-qnSqB2DQ9TPP96dl8cDubDvrUyWc0/sK81xHTK8eSUspzDM3bsewX903qclQFvVhgStjRWdC5bLb3kQqMkfV5A==}
engines: {node: '>=14'}
@ -5443,6 +5658,10 @@ packages:
fastq@1.17.1:
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
faye-websocket@0.11.4:
resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==}
engines: {node: '>=0.8.0'}
fd-slicer@1.1.0:
resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
@ -5492,6 +5711,9 @@ packages:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
firebase@10.14.1:
resolution: {integrity: sha512-0KZxU+Ela9rUCULqFsUUOYYkjh7OM1EWdIfG6///MtXd0t2/uUIf0iNV5i0KariMhRQ5jve/OY985nrAXFaZeQ==}
flat-cache@4.0.1:
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
engines: {node: '>=16'}
@ -5917,6 +6139,9 @@ packages:
http-cache-semantics@4.1.1:
resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==}
http-parser-js@0.5.8:
resolution: {integrity: sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==}
http-proxy-agent@5.0.0:
resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==}
engines: {node: '>= 6'}
@ -5973,6 +6198,9 @@ packages:
idb-keyval@6.2.1:
resolution: {integrity: sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==}
idb@7.1.1:
resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==}
ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
@ -6449,6 +6677,9 @@ packages:
lodash-es@4.17.21:
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
lodash.camelcase@4.3.0:
resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==}
lodash.castarray@4.4.0:
resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==}
@ -7598,6 +7829,9 @@ packages:
posthog-js@1.169.0:
resolution: {integrity: sha512-C0TiNv6ehbiy78F9gKZIqy3RbCRsWDSQDbQMi1YW2iuO4kDQUQwacmx2DKyaCwsH0/oN69FdBl99WoEJdjmxXg==}
posthog-js@1.169.1:
resolution: {integrity: sha512-zyse2166QgptTXVMgRB5zsJuM2BWR4N+Vzl08ti7KU5gtQA5PSmsMYR6R2YR/LGQsJve4PBRpR8jRHOj1RZZrA==}
posthog-node@4.2.1:
resolution: {integrity: sha512-l+fsjYEkTik3m/G0pE7gMr4qBJP84LhK779oQm6MBzhBGpd4By4qieTW+4FUAlNCyzQTynn3Nhsa50c0IELSxQ==}
engines: {node: '>=15.0.0'}
@ -8677,6 +8911,10 @@ packages:
undici-types@6.19.8:
resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==}
undici@6.19.7:
resolution: {integrity: sha512-HR3W/bMGPSr90i8AAp2C4DM3wChFdJPLrWYpIS++LxS8K+W535qftjt+4MyjNYHeWabMj1nvtmLIi7l++iq91A==}
engines: {node: '>=18.17'}
undici@6.19.8:
resolution: {integrity: sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==}
engines: {node: '>=18.17'}
@ -8958,6 +9196,14 @@ packages:
webpack-virtual-modules@0.5.0:
resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==}
websocket-driver@0.7.4:
resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==}
engines: {node: '>=0.8.0'}
websocket-extensions@0.1.4:
resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==}
engines: {node: '>=0.8.0'}
whatwg-encoding@3.1.1:
resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
engines: {node: '>=18'}
@ -10890,6 +11136,328 @@ snapshots:
dependencies:
'@essentials/raf': 1.2.0
'@firebase/analytics-compat@0.2.14(@firebase/app-compat@0.2.43)(@firebase/app@0.10.13)':
dependencies:
'@firebase/analytics': 0.10.8(@firebase/app@0.10.13)
'@firebase/analytics-types': 0.8.2
'@firebase/app-compat': 0.2.43
'@firebase/component': 0.6.9
'@firebase/util': 1.10.0
tslib: 2.7.0
transitivePeerDependencies:
- '@firebase/app'
'@firebase/analytics-types@0.8.2': {}
'@firebase/analytics@0.10.8(@firebase/app@0.10.13)':
dependencies:
'@firebase/app': 0.10.13
'@firebase/component': 0.6.9
'@firebase/installations': 0.6.9(@firebase/app@0.10.13)
'@firebase/logger': 0.4.2
'@firebase/util': 1.10.0
tslib: 2.7.0
'@firebase/app-check-compat@0.3.15(@firebase/app-compat@0.2.43)(@firebase/app@0.10.13)':
dependencies:
'@firebase/app-check': 0.8.8(@firebase/app@0.10.13)
'@firebase/app-check-types': 0.5.2
'@firebase/app-compat': 0.2.43
'@firebase/component': 0.6.9
'@firebase/logger': 0.4.2
'@firebase/util': 1.10.0
tslib: 2.7.0
transitivePeerDependencies:
- '@firebase/app'
'@firebase/app-check-interop-types@0.3.2': {}
'@firebase/app-check-types@0.5.2': {}
'@firebase/app-check@0.8.8(@firebase/app@0.10.13)':
dependencies:
'@firebase/app': 0.10.13
'@firebase/component': 0.6.9
'@firebase/logger': 0.4.2
'@firebase/util': 1.10.0
tslib: 2.7.0
'@firebase/app-compat@0.2.43':
dependencies:
'@firebase/app': 0.10.13
'@firebase/component': 0.6.9
'@firebase/logger': 0.4.2
'@firebase/util': 1.10.0
tslib: 2.7.0
'@firebase/app-types@0.9.2': {}
'@firebase/app@0.10.13':
dependencies:
'@firebase/component': 0.6.9
'@firebase/logger': 0.4.2
'@firebase/util': 1.10.0
idb: 7.1.1
tslib: 2.7.0
'@firebase/auth-compat@0.5.14(@firebase/app-compat@0.2.43)(@firebase/app-types@0.9.2)(@firebase/app@0.10.13)':
dependencies:
'@firebase/app-compat': 0.2.43
'@firebase/auth': 1.7.9(@firebase/app@0.10.13)
'@firebase/auth-types': 0.12.2(@firebase/app-types@0.9.2)(@firebase/util@1.10.0)
'@firebase/component': 0.6.9
'@firebase/util': 1.10.0
tslib: 2.7.0
undici: 6.19.7
transitivePeerDependencies:
- '@firebase/app'
- '@firebase/app-types'
- '@react-native-async-storage/async-storage'
'@firebase/auth-interop-types@0.2.3': {}
'@firebase/auth-types@0.12.2(@firebase/app-types@0.9.2)(@firebase/util@1.10.0)':
dependencies:
'@firebase/app-types': 0.9.2
'@firebase/util': 1.10.0
'@firebase/auth@1.7.9(@firebase/app@0.10.13)':
dependencies:
'@firebase/app': 0.10.13
'@firebase/component': 0.6.9
'@firebase/logger': 0.4.2
'@firebase/util': 1.10.0
tslib: 2.7.0
undici: 6.19.7
'@firebase/component@0.6.9':
dependencies:
'@firebase/util': 1.10.0
tslib: 2.7.0
'@firebase/data-connect@0.1.0(@firebase/app@0.10.13)':
dependencies:
'@firebase/app': 0.10.13
'@firebase/auth-interop-types': 0.2.3
'@firebase/component': 0.6.9
'@firebase/logger': 0.4.2
'@firebase/util': 1.10.0
tslib: 2.7.0
'@firebase/database-compat@1.0.8':
dependencies:
'@firebase/component': 0.6.9
'@firebase/database': 1.0.8
'@firebase/database-types': 1.0.5
'@firebase/logger': 0.4.2
'@firebase/util': 1.10.0
tslib: 2.7.0
'@firebase/database-types@1.0.5':
dependencies:
'@firebase/app-types': 0.9.2
'@firebase/util': 1.10.0
'@firebase/database@1.0.8':
dependencies:
'@firebase/app-check-interop-types': 0.3.2
'@firebase/auth-interop-types': 0.2.3
'@firebase/component': 0.6.9
'@firebase/logger': 0.4.2
'@firebase/util': 1.10.0
faye-websocket: 0.11.4
tslib: 2.7.0
'@firebase/firestore-compat@0.3.38(@firebase/app-compat@0.2.43)(@firebase/app-types@0.9.2)(@firebase/app@0.10.13)':
dependencies:
'@firebase/app-compat': 0.2.43
'@firebase/component': 0.6.9
'@firebase/firestore': 4.7.3(@firebase/app@0.10.13)
'@firebase/firestore-types': 3.0.2(@firebase/app-types@0.9.2)(@firebase/util@1.10.0)
'@firebase/util': 1.10.0
tslib: 2.7.0
transitivePeerDependencies:
- '@firebase/app'
- '@firebase/app-types'
'@firebase/firestore-types@3.0.2(@firebase/app-types@0.9.2)(@firebase/util@1.10.0)':
dependencies:
'@firebase/app-types': 0.9.2
'@firebase/util': 1.10.0
'@firebase/firestore@4.7.3(@firebase/app@0.10.13)':
dependencies:
'@firebase/app': 0.10.13
'@firebase/component': 0.6.9
'@firebase/logger': 0.4.2
'@firebase/util': 1.10.0
'@firebase/webchannel-wrapper': 1.0.1
'@grpc/grpc-js': 1.9.15
'@grpc/proto-loader': 0.7.13
tslib: 2.7.0
undici: 6.19.7
'@firebase/functions-compat@0.3.14(@firebase/app-compat@0.2.43)(@firebase/app@0.10.13)':
dependencies:
'@firebase/app-compat': 0.2.43
'@firebase/component': 0.6.9
'@firebase/functions': 0.11.8(@firebase/app@0.10.13)
'@firebase/functions-types': 0.6.2
'@firebase/util': 1.10.0
tslib: 2.7.0
transitivePeerDependencies:
- '@firebase/app'
'@firebase/functions-types@0.6.2': {}
'@firebase/functions@0.11.8(@firebase/app@0.10.13)':
dependencies:
'@firebase/app': 0.10.13
'@firebase/app-check-interop-types': 0.3.2
'@firebase/auth-interop-types': 0.2.3
'@firebase/component': 0.6.9
'@firebase/messaging-interop-types': 0.2.2
'@firebase/util': 1.10.0
tslib: 2.7.0
undici: 6.19.7
'@firebase/installations-compat@0.2.9(@firebase/app-compat@0.2.43)(@firebase/app-types@0.9.2)(@firebase/app@0.10.13)':
dependencies:
'@firebase/app-compat': 0.2.43
'@firebase/component': 0.6.9
'@firebase/installations': 0.6.9(@firebase/app@0.10.13)
'@firebase/installations-types': 0.5.2(@firebase/app-types@0.9.2)
'@firebase/util': 1.10.0
tslib: 2.7.0
transitivePeerDependencies:
- '@firebase/app'
- '@firebase/app-types'
'@firebase/installations-types@0.5.2(@firebase/app-types@0.9.2)':
dependencies:
'@firebase/app-types': 0.9.2
'@firebase/installations@0.6.9(@firebase/app@0.10.13)':
dependencies:
'@firebase/app': 0.10.13
'@firebase/component': 0.6.9
'@firebase/util': 1.10.0
idb: 7.1.1
tslib: 2.7.0
'@firebase/logger@0.4.2':
dependencies:
tslib: 2.7.0
'@firebase/messaging-compat@0.2.12(@firebase/app-compat@0.2.43)(@firebase/app@0.10.13)':
dependencies:
'@firebase/app-compat': 0.2.43
'@firebase/component': 0.6.9
'@firebase/messaging': 0.12.12(@firebase/app@0.10.13)
'@firebase/util': 1.10.0
tslib: 2.7.0
transitivePeerDependencies:
- '@firebase/app'
'@firebase/messaging-interop-types@0.2.2': {}
'@firebase/messaging@0.12.12(@firebase/app@0.10.13)':
dependencies:
'@firebase/app': 0.10.13
'@firebase/component': 0.6.9
'@firebase/installations': 0.6.9(@firebase/app@0.10.13)
'@firebase/messaging-interop-types': 0.2.2
'@firebase/util': 1.10.0
idb: 7.1.1
tslib: 2.7.0
'@firebase/performance-compat@0.2.9(@firebase/app-compat@0.2.43)(@firebase/app@0.10.13)':
dependencies:
'@firebase/app-compat': 0.2.43
'@firebase/component': 0.6.9
'@firebase/logger': 0.4.2
'@firebase/performance': 0.6.9(@firebase/app@0.10.13)
'@firebase/performance-types': 0.2.2
'@firebase/util': 1.10.0
tslib: 2.7.0
transitivePeerDependencies:
- '@firebase/app'
'@firebase/performance-types@0.2.2': {}
'@firebase/performance@0.6.9(@firebase/app@0.10.13)':
dependencies:
'@firebase/app': 0.10.13
'@firebase/component': 0.6.9
'@firebase/installations': 0.6.9(@firebase/app@0.10.13)
'@firebase/logger': 0.4.2
'@firebase/util': 1.10.0
tslib: 2.7.0
'@firebase/remote-config-compat@0.2.9(@firebase/app-compat@0.2.43)(@firebase/app@0.10.13)':
dependencies:
'@firebase/app-compat': 0.2.43
'@firebase/component': 0.6.9
'@firebase/logger': 0.4.2
'@firebase/remote-config': 0.4.9(@firebase/app@0.10.13)
'@firebase/remote-config-types': 0.3.2
'@firebase/util': 1.10.0
tslib: 2.7.0
transitivePeerDependencies:
- '@firebase/app'
'@firebase/remote-config-types@0.3.2': {}
'@firebase/remote-config@0.4.9(@firebase/app@0.10.13)':
dependencies:
'@firebase/app': 0.10.13
'@firebase/component': 0.6.9
'@firebase/installations': 0.6.9(@firebase/app@0.10.13)
'@firebase/logger': 0.4.2
'@firebase/util': 1.10.0
tslib: 2.7.0
'@firebase/storage-compat@0.3.12(@firebase/app-compat@0.2.43)(@firebase/app-types@0.9.2)(@firebase/app@0.10.13)':
dependencies:
'@firebase/app-compat': 0.2.43
'@firebase/component': 0.6.9
'@firebase/storage': 0.13.2(@firebase/app@0.10.13)
'@firebase/storage-types': 0.8.2(@firebase/app-types@0.9.2)(@firebase/util@1.10.0)
'@firebase/util': 1.10.0
tslib: 2.7.0
transitivePeerDependencies:
- '@firebase/app'
- '@firebase/app-types'
'@firebase/storage-types@0.8.2(@firebase/app-types@0.9.2)(@firebase/util@1.10.0)':
dependencies:
'@firebase/app-types': 0.9.2
'@firebase/util': 1.10.0
'@firebase/storage@0.13.2(@firebase/app@0.10.13)':
dependencies:
'@firebase/app': 0.10.13
'@firebase/component': 0.6.9
'@firebase/util': 1.10.0
tslib: 2.7.0
undici: 6.19.7
'@firebase/util@1.10.0':
dependencies:
tslib: 2.7.0
'@firebase/vertexai-preview@0.0.4(@firebase/app-types@0.9.2)(@firebase/app@0.10.13)':
dependencies:
'@firebase/app': 0.10.13
'@firebase/app-check-interop-types': 0.3.2
'@firebase/app-types': 0.9.2
'@firebase/component': 0.6.9
'@firebase/logger': 0.4.2
'@firebase/util': 1.10.0
tslib: 2.7.0
'@firebase/webchannel-wrapper@1.0.1': {}
'@floating-ui/core@0.6.2': {}
'@floating-ui/core@1.6.8':
@ -10945,6 +11513,18 @@ snapshots:
'@gar/promisify@1.1.3': {}
'@grpc/grpc-js@1.9.15':
dependencies:
'@grpc/proto-loader': 0.7.13
'@types/node': 22.7.5
'@grpc/proto-loader@0.7.13':
dependencies:
lodash.camelcase: 4.3.0
long: 5.2.3
protobufjs: 7.4.0
yargs: 17.7.2
'@headlessui/react@2.1.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies:
'@floating-ui/react': 0.26.25(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@ -11283,6 +11863,12 @@ snapshots:
dependencies:
'@octokit/openapi-types': 12.11.0
'@openpanel/sdk@1.0.0': {}
'@openpanel/web@1.0.1':
dependencies:
'@openpanel/sdk': 1.0.0
'@opentelemetry/api-logs@0.52.1':
dependencies:
'@opentelemetry/api': 1.9.0
@ -15149,6 +15735,10 @@ snapshots:
dependencies:
reusify: 1.0.4
faye-websocket@0.11.4:
dependencies:
websocket-driver: 0.7.4
fd-slicer@1.1.0:
dependencies:
pend: 1.2.0
@ -15195,6 +15785,39 @@ snapshots:
locate-path: 6.0.0
path-exists: 4.0.0
firebase@10.14.1:
dependencies:
'@firebase/analytics': 0.10.8(@firebase/app@0.10.13)
'@firebase/analytics-compat': 0.2.14(@firebase/app-compat@0.2.43)(@firebase/app@0.10.13)
'@firebase/app': 0.10.13
'@firebase/app-check': 0.8.8(@firebase/app@0.10.13)
'@firebase/app-check-compat': 0.3.15(@firebase/app-compat@0.2.43)(@firebase/app@0.10.13)
'@firebase/app-compat': 0.2.43
'@firebase/app-types': 0.9.2
'@firebase/auth': 1.7.9(@firebase/app@0.10.13)
'@firebase/auth-compat': 0.5.14(@firebase/app-compat@0.2.43)(@firebase/app-types@0.9.2)(@firebase/app@0.10.13)
'@firebase/data-connect': 0.1.0(@firebase/app@0.10.13)
'@firebase/database': 1.0.8
'@firebase/database-compat': 1.0.8
'@firebase/firestore': 4.7.3(@firebase/app@0.10.13)
'@firebase/firestore-compat': 0.3.38(@firebase/app-compat@0.2.43)(@firebase/app-types@0.9.2)(@firebase/app@0.10.13)
'@firebase/functions': 0.11.8(@firebase/app@0.10.13)
'@firebase/functions-compat': 0.3.14(@firebase/app-compat@0.2.43)(@firebase/app@0.10.13)
'@firebase/installations': 0.6.9(@firebase/app@0.10.13)
'@firebase/installations-compat': 0.2.9(@firebase/app-compat@0.2.43)(@firebase/app-types@0.9.2)(@firebase/app@0.10.13)
'@firebase/messaging': 0.12.12(@firebase/app@0.10.13)
'@firebase/messaging-compat': 0.2.12(@firebase/app-compat@0.2.43)(@firebase/app@0.10.13)
'@firebase/performance': 0.6.9(@firebase/app@0.10.13)
'@firebase/performance-compat': 0.2.9(@firebase/app-compat@0.2.43)(@firebase/app@0.10.13)
'@firebase/remote-config': 0.4.9(@firebase/app@0.10.13)
'@firebase/remote-config-compat': 0.2.9(@firebase/app-compat@0.2.43)(@firebase/app@0.10.13)
'@firebase/storage': 0.13.2(@firebase/app@0.10.13)
'@firebase/storage-compat': 0.3.12(@firebase/app-compat@0.2.43)(@firebase/app-types@0.9.2)(@firebase/app@0.10.13)
'@firebase/util': 1.10.0
'@firebase/vertexai-preview': 0.0.4(@firebase/app-types@0.9.2)(@firebase/app@0.10.13)
transitivePeerDependencies:
- '@react-native-async-storage/async-storage'
flat-cache@4.0.1:
dependencies:
flatted: 3.3.1
@ -15786,6 +16409,8 @@ snapshots:
http-cache-semantics@4.1.1: {}
http-parser-js@0.5.8: {}
http-proxy-agent@5.0.0:
dependencies:
'@tootallnate/once': 2.0.0
@ -15852,6 +16477,8 @@ snapshots:
idb-keyval@6.2.1: {}
idb@7.1.1: {}
ieee754@1.2.1: {}
ignore@5.3.2: {}
@ -16297,6 +16924,8 @@ snapshots:
lodash-es@4.17.21: {}
lodash.camelcase@4.3.0: {}
lodash.castarray@4.4.0: {}
lodash.debounce@4.0.8: {}
@ -17659,6 +18288,12 @@ snapshots:
preact: 10.24.3
web-vitals: 4.2.3
posthog-js@1.169.1:
dependencies:
fflate: 0.4.8
preact: 10.24.3
web-vitals: 4.2.3
posthog-node@4.2.1:
dependencies:
axios: 1.7.7(debug@4.3.7)
@ -18829,6 +19464,8 @@ snapshots:
undici-types@6.19.8: {}
undici@6.19.7: {}
undici@6.19.8: {}
unicode-canonical-property-names-ecmascript@2.0.0: {}
@ -19120,6 +19757,14 @@ snapshots:
webpack-virtual-modules@0.5.0: {}
websocket-driver@0.7.4:
dependencies:
http-parser-js: 0.5.8
safe-buffer: 5.2.1
websocket-extensions: 0.1.4
websocket-extensions@0.1.4: {}
whatwg-encoding@3.1.1:
dependencies:
iconv-lite: 0.6.3

3
types/vite.d.ts vendored
View File

@ -5,7 +5,8 @@ interface ImportMetaEnv {
VITE_API_URL: string
VITE_IMGPROXY_URL: string
VITE_SENTRY_DSN: string
VITE_POSTHOG_KEY: string
VITE_OPENPANEL_CLIENT_ID: string
VITE_OPENPANEL_API_URL: string
VITE_FIREBASE_CONFIG: string
}

View File

@ -135,7 +135,7 @@ export default ({ mode }) => {
],
["tldts"],
["shiki", "@shikijs/transformers"],
["@sentry/react", "posthog-js"],
["@sentry/react", "@openpanel/web"],
["zod", "react-hook-form", "@hookform/resolvers"],
["swiper"],