diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index bc3a9695fe..56bc75f3fa 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -73,6 +73,7 @@ Quick guide: What docs does your change need? - [ ] I have **commented** my code, particularly where ambiguous - [ ] New and existing **unit tests pass** locally with my changes - [ ] I have completed the **Documentation Checklist** above (or explained why N/A) +- [ ] I have considered **product analytics** for user-facing features (use `@analytics` in learn-card-app) ### 🚀 Ready to squash-and-merge?: - [ ] Code is backwards compatible diff --git a/apps/learn-card-app/package.json b/apps/learn-card-app/package.json index 0d085a0ab6..bc490a7cde 100644 --- a/apps/learn-card-app/package.json +++ b/apps/learn-card-app/package.json @@ -84,6 +84,7 @@ "numeral": "^2.0.6", "papaparse": "^5.5.1", "pdf-lib": "^1.17.1", + "posthog-js": "^1.333.0", "pretty-bytes": "^6.1.1", "qrcode.react": "^4.2.0", "query-string": "^8.2.0", diff --git a/apps/learn-card-app/src/AppRouter.tsx b/apps/learn-card-app/src/AppRouter.tsx index 9255710269..82c56a2720 100644 --- a/apps/learn-card-app/src/AppRouter.tsx +++ b/apps/learn-card-app/src/AppRouter.tsx @@ -44,7 +44,7 @@ import { useIsChapiInteraction } from 'learn-card-base/stores/chapiStore'; import { useSentryIdentify } from './constants/sentry'; import { Modals } from 'learn-card-base'; -import { useSetFirebaseAnalyticsUserId } from './hooks/useSetFirebaseAnalyticsUserId'; +import { useSetAnalyticsUserId } from '@analytics'; import { useDeviceTypeByWidth } from 'learn-card-base'; import { redirectStore } from 'learn-card-base/stores/redirectStore'; import { useAutoVerifyContactMethodWithProofOfLogin } from './hooks/useAutoVerifyContactMethodWithProofOfLogin'; @@ -206,7 +206,7 @@ const AppRouter: React.FC<{ initLoading: boolean }> = ({ initLoading }) => { useLaunchDarklyIdentify({ debug: false }); useSentryIdentify({ debug: false }); - useSetFirebaseAnalyticsUserId({ debug: false }); + useSetAnalyticsUserId({ debug: false }); useAutoVerifyContactMethodWithProofOfLogin(); useFinalizeInboxCredentials(); diff --git a/apps/learn-card-app/src/FullApp.tsx b/apps/learn-card-app/src/FullApp.tsx index 9a8cd509db..6cd5c0500d 100644 --- a/apps/learn-card-app/src/FullApp.tsx +++ b/apps/learn-card-app/src/FullApp.tsx @@ -27,6 +27,7 @@ import NetworkListener from './components/network-listener/NetworkListener'; import { QRCodeScannerStore } from 'learn-card-base'; import Toast from 'learn-card-base/components/toast/Toast'; +import { AnalyticsContextProvider } from '@analytics'; import ExternalAuthServiceProvider from './pages/sync-my-school/ExternalAuthServiceProvider'; import localforage from 'localforage'; @@ -155,13 +156,14 @@ const FullApp: React.FC = () => { client={client} persistOptions={{ persister, maxAge: CACHE_TTL }} > -
- {/* */} - - }> - - - + +
+ {/* */} + + }> + + + @@ -182,12 +184,13 @@ const FullApp: React.FC = () => { )} - - - - - - ); + + + + + + + ); }; export default FullApp; diff --git a/apps/learn-card-app/src/analytics/context.tsx b/apps/learn-card-app/src/analytics/context.tsx new file mode 100644 index 0000000000..55fb0a3ef6 --- /dev/null +++ b/apps/learn-card-app/src/analytics/context.tsx @@ -0,0 +1,157 @@ +import React, { createContext, useContext, useEffect, useState, useMemo, useCallback } from 'react'; + +import type { AnalyticsProvider, AnalyticsProviderName } from './types'; +import type { AnalyticsEventName, EventPayload } from './events'; +import { NoopProvider } from './providers/noop'; + +/** + * Lazily load and instantiate the appropriate analytics provider based on env config. + */ +async function loadProvider(): Promise { + const providerName = ( + import.meta.env.VITE_ANALYTICS_PROVIDER || 'noop' + ) as AnalyticsProviderName; + + switch (providerName) { + case 'posthog': { + const apiKey = import.meta.env.VITE_POSTHOG_KEY; + + if (!apiKey) { + console.warn('[Analytics] PostHog selected but VITE_POSTHOG_KEY not set, falling back to noop'); + return new NoopProvider(); + } + + const { PostHogProvider } = await import('./providers/posthog'); + + return new PostHogProvider({ + apiKey, + apiHost: import.meta.env.VITE_POSTHOG_HOST, + }); + } + + case 'firebase': { + const { FirebaseProvider } = await import('./providers/firebase'); + return new FirebaseProvider(); + } + + case 'noop': + default: { + return new NoopProvider(); + } + } +} + +interface AnalyticsContextValue { + provider: AnalyticsProvider; + isReady: boolean; +} + +const AnalyticsContext = createContext(null); + +interface AnalyticsProviderProps { + children: React.ReactNode; +} + +/** + * Analytics provider component that lazily loads the configured analytics backend. + * Wrap your app with this provider to enable analytics throughout. + */ +export function AnalyticsContextProvider({ children }: AnalyticsProviderProps) { + const [provider, setProvider] = useState(() => new NoopProvider()); + const [isReady, setIsReady] = useState(false); + + useEffect(() => { + let mounted = true; + + loadProvider() + .then(async loadedProvider => { + if (!mounted) return; + + await loadedProvider.init(); + + if (!mounted) return; + + setProvider(loadedProvider); + setIsReady(true); + }) + .catch(error => { + console.error('[Analytics] Failed to load provider', error); + + if (mounted) { + setIsReady(true); + } + }); + + return () => { + mounted = false; + }; + }, []); + + const value = useMemo(() => ({ provider, isReady }), [provider, isReady]); + + return {children}; +} + +/** + * Hook to access the analytics context. + * @internal Use useAnalytics() instead for the public API. + */ +export function useAnalyticsContext(): AnalyticsContextValue { + const context = useContext(AnalyticsContext); + + if (!context) { + throw new Error('useAnalyticsContext must be used within an AnalyticsContextProvider'); + } + + return context; +} + +/** + * Main hook for tracking analytics events. + * Provides type-safe methods for tracking, identifying users, and page views. + */ +export function useAnalytics() { + const { provider, isReady } = useAnalyticsContext(); + + const track = useCallback( + async (event: E, properties: EventPayload) => { + await provider.track(event, properties); + }, + [provider] + ); + + const identify = useCallback( + async (userId: string, traits?: Record) => { + await provider.identify(userId, traits); + }, + [provider] + ); + + const page = useCallback( + async (name: string, properties?: Record) => { + await provider.page(name, properties); + }, + [provider] + ); + + const reset = useCallback(async () => { + await provider.reset(); + }, [provider]); + + const setEnabled = useCallback( + async (enabled: boolean) => { + await provider.setEnabled(enabled); + }, + [provider] + ); + + return { + track, + identify, + page, + reset, + setEnabled, + isReady, + providerName: provider.name, + }; +} diff --git a/apps/learn-card-app/src/analytics/events.ts b/apps/learn-card-app/src/analytics/events.ts new file mode 100644 index 0000000000..28ca7302b2 --- /dev/null +++ b/apps/learn-card-app/src/analytics/events.ts @@ -0,0 +1,104 @@ +/** + * Centralized event catalog - single source of truth for all analytics events. + * Add new events here with their corresponding payload types. + */ + +export const AnalyticsEvents = { + // Boost/Credential Claims + CLAIM_BOOST: 'claim_boost', + + // Boost CMS + BOOST_CMS_PUBLISH: 'boostCMS_publish', + BOOST_CMS_ISSUE_TO: 'boostCMS_issue_to', + BOOST_CMS_CONFIRMATION: 'boostCMS_confirmation', + BOOST_CMS_DATA_ENTRY: 'boostCMS_data_entry', + + // Sharing & Link Generation + GENERATE_SHARE_LINK: 'generate_share_link', + GENERATE_CLAIM_LINK: 'generate_claim_link', + + // Boost Sending + SELF_BOOST: 'self_boost', + SEND_BOOST: 'send_boost', + + // Navigation/Screens + SCREEN_VIEW: 'screen_view', +} as const; + +export type AnalyticsEventName = (typeof AnalyticsEvents)[keyof typeof AnalyticsEvents]; + +/** + * Type-safe payload definitions for each event. + * Extend this interface as you add new events. + */ +export interface AnalyticsEventPayloads { + [AnalyticsEvents.CLAIM_BOOST]: { + category?: string; + boostType?: string; + achievementType?: string; + method: 'VC-API Request' | 'Dashboard' | 'Claim Modal' | 'Notification' | string; + }; + + [AnalyticsEvents.BOOST_CMS_PUBLISH]: { + timestamp: number; + action: 'publish' | 'publish_draft' | 'publish_live'; + boostType?: string; + category?: string; + }; + + [AnalyticsEvents.BOOST_CMS_ISSUE_TO]: { + timestamp: number; + action: 'issue_to'; + boostType?: string; + category?: string; + }; + + [AnalyticsEvents.BOOST_CMS_CONFIRMATION]: { + timestamp: number; + action: 'confirmation'; + boostType?: string; + category?: string; + }; + + [AnalyticsEvents.GENERATE_SHARE_LINK]: { + category?: string; + boostType?: string; + method: 'Earned Boost' | string; + }; + + [AnalyticsEvents.GENERATE_CLAIM_LINK]: { + category?: string; + boostType?: string; + method: 'Claim Link' | string; + }; + + [AnalyticsEvents.BOOST_CMS_DATA_ENTRY]: { + timestamp: number; + action: 'data_entry'; + boostType?: string; + category?: string; + }; + + [AnalyticsEvents.SELF_BOOST]: { + category?: string; + boostType?: string; + method: 'Managed Boost' | string; + }; + + [AnalyticsEvents.SEND_BOOST]: { + category?: string; + boostType?: string; + method: 'Managed Boost' | string; + }; + + [AnalyticsEvents.SCREEN_VIEW]: { + screen_name: string; + }; +} + +/** + * Helper type to get the payload type for a specific event. + */ +export type EventPayload = E extends keyof AnalyticsEventPayloads + ? AnalyticsEventPayloads[E] + : Record; diff --git a/apps/learn-card-app/src/analytics/index.ts b/apps/learn-card-app/src/analytics/index.ts new file mode 100644 index 0000000000..969b7c1f4c --- /dev/null +++ b/apps/learn-card-app/src/analytics/index.ts @@ -0,0 +1,7 @@ +export { AnalyticsContextProvider, useAnalytics, useAnalyticsContext } from './context'; +export { useSetAnalyticsUserId } from './useSetAnalyticsUserId'; + +export { AnalyticsEvents } from './events'; +export type { AnalyticsEventName, AnalyticsEventPayloads, EventPayload } from './events'; + +export type { AnalyticsProvider, AnalyticsProviderName, PostHogConfig } from './types'; diff --git a/apps/learn-card-app/src/analytics/providers/firebase.ts b/apps/learn-card-app/src/analytics/providers/firebase.ts new file mode 100644 index 0000000000..d3cd7f8489 --- /dev/null +++ b/apps/learn-card-app/src/analytics/providers/firebase.ts @@ -0,0 +1,67 @@ +import { FirebaseAnalytics } from '@capacitor-firebase/analytics'; + +import type { AnalyticsProvider } from '../types'; +import type { AnalyticsEventName, EventPayload } from '../events'; + +/** + * Firebase Analytics provider implementation. + * Wraps @capacitor-firebase/analytics for use with the analytics abstraction. + */ +export class FirebaseProvider implements AnalyticsProvider { + readonly name = 'firebase'; + + async init(): Promise { + try { + await FirebaseAnalytics.setEnabled({ enabled: true }); + console.debug('[Analytics:Firebase] Initialized'); + } catch (error) { + console.error('[Analytics:Firebase] Failed to initialize', error); + } + } + + async identify(userId: string, _traits?: Record): Promise { + try { + await FirebaseAnalytics.setUserId({ userId }); + } catch (error) { + console.error('[Analytics:Firebase] identify error', error); + } + } + + async track(event: E, properties: EventPayload): Promise { + try { + await FirebaseAnalytics.logEvent({ + name: event, + params: properties as Record, + }); + } catch (error) { + console.error('[Analytics:Firebase] track error', error); + } + } + + async page(name: string, _properties?: Record): Promise { + try { + await FirebaseAnalytics.setCurrentScreen({ + screenName: name, + screenClassOverride: name, + }); + } catch (error) { + console.error('[Analytics:Firebase] page error', error); + } + } + + async reset(): Promise { + try { + await FirebaseAnalytics.setUserId({ userId: null as unknown as string }); + } catch (error) { + console.error('[Analytics:Firebase] reset error', error); + } + } + + async setEnabled(enabled: boolean): Promise { + try { + await FirebaseAnalytics.setEnabled({ enabled }); + } catch (error) { + console.error('[Analytics:Firebase] setEnabled error', error); + } + } +} diff --git a/apps/learn-card-app/src/analytics/providers/index.ts b/apps/learn-card-app/src/analytics/providers/index.ts new file mode 100644 index 0000000000..bb58bb4178 --- /dev/null +++ b/apps/learn-card-app/src/analytics/providers/index.ts @@ -0,0 +1,3 @@ +export { NoopProvider } from './noop'; +export { PostHogProvider } from './posthog'; +export { FirebaseProvider } from './firebase'; diff --git a/apps/learn-card-app/src/analytics/providers/noop.ts b/apps/learn-card-app/src/analytics/providers/noop.ts new file mode 100644 index 0000000000..1e44ce1f7c --- /dev/null +++ b/apps/learn-card-app/src/analytics/providers/noop.ts @@ -0,0 +1,47 @@ +import type { AnalyticsProvider } from '../types'; +import type { AnalyticsEventName, EventPayload } from '../events'; + +/** + * No-op analytics provider. + * Used as fallback when no provider is configured, or for development/testing. + * All methods are no-ops that resolve immediately. + */ +export class NoopProvider implements AnalyticsProvider { + readonly name = 'noop'; + + async init(): Promise { + if (import.meta.env.DEV) { + console.debug('[Analytics:Noop] Initialized (no-op mode)'); + } + } + + async identify(userId: string, traits?: Record): Promise { + if (import.meta.env.DEV) { + console.debug('[Analytics:Noop] identify', { userId, traits }); + } + } + + async track(event: E, properties: EventPayload): Promise { + if (import.meta.env.DEV) { + console.debug('[Analytics:Noop] track', { event, properties }); + } + } + + async page(name: string, properties?: Record): Promise { + if (import.meta.env.DEV) { + console.debug('[Analytics:Noop] page', { name, properties }); + } + } + + async reset(): Promise { + if (import.meta.env.DEV) { + console.debug('[Analytics:Noop] reset'); + } + } + + async setEnabled(_enabled: boolean): Promise { + if (import.meta.env.DEV) { + console.debug('[Analytics:Noop] setEnabled', { enabled: _enabled }); + } + } +} diff --git a/apps/learn-card-app/src/analytics/providers/posthog.ts b/apps/learn-card-app/src/analytics/providers/posthog.ts new file mode 100644 index 0000000000..33986b833a --- /dev/null +++ b/apps/learn-card-app/src/analytics/providers/posthog.ts @@ -0,0 +1,99 @@ +import type { AnalyticsProvider, PostHogConfig } from '../types'; +import type { AnalyticsEventName, EventPayload } from '../events'; + +/** + * PostHog analytics provider implementation. + * Lazily loads the posthog-js SDK to minimize bundle impact. + */ +export class PostHogProvider implements AnalyticsProvider { + readonly name = 'posthog'; + + private posthog: typeof import('posthog-js').default | null = null; + + private config: PostHogConfig; + + constructor(config: PostHogConfig) { + this.config = config; + } + + async init(): Promise { + if (!this.config.apiKey) { + console.warn('[Analytics:PostHog] No API key provided, skipping initialization'); + return; + } + + try { + const posthogModule = await import('posthog-js'); + this.posthog = posthogModule.default; + + this.posthog.init(this.config.apiKey, { + api_host: this.config.apiHost || 'https://us.i.posthog.com', + capture_pageview: false, + capture_pageleave: true, + persistence: 'localStorage', + }); + + console.debug('[Analytics:PostHog] Initialized'); + } catch (error) { + console.error('[Analytics:PostHog] Failed to initialize', error); + } + } + + async identify(userId: string, traits?: Record): Promise { + if (!this.posthog) return; + + try { + this.posthog.identify(userId, traits); + } catch (error) { + console.error('[Analytics:PostHog] identify error', error); + } + } + + async track(event: E, properties: EventPayload): Promise { + if (!this.posthog) return; + + try { + this.posthog.capture(event, properties as Record); + } catch (error) { + console.error('[Analytics:PostHog] track error', error); + } + } + + async page(name: string, properties?: Record): Promise { + if (!this.posthog) return; + + try { + this.posthog.capture('$pageview', { + $current_url: window.location.href, + screen_name: name, + ...properties, + }); + } catch (error) { + console.error('[Analytics:PostHog] page error', error); + } + } + + async reset(): Promise { + if (!this.posthog) return; + + try { + this.posthog.reset(); + } catch (error) { + console.error('[Analytics:PostHog] reset error', error); + } + } + + async setEnabled(enabled: boolean): Promise { + if (!this.posthog) return; + + try { + if (enabled) { + this.posthog.opt_in_capturing(); + } else { + this.posthog.opt_out_capturing(); + } + } catch (error) { + console.error('[Analytics:PostHog] setEnabled error', error); + } + } +} diff --git a/apps/learn-card-app/src/analytics/types.ts b/apps/learn-card-app/src/analytics/types.ts new file mode 100644 index 0000000000..d5a7e9c1c4 --- /dev/null +++ b/apps/learn-card-app/src/analytics/types.ts @@ -0,0 +1,63 @@ +import type { AnalyticsEventName, EventPayload } from './events'; + +/** + * Interface that all analytics providers must implement. + * This abstraction allows swapping providers without changing application code. + */ +export interface AnalyticsProvider { + /** + * Provider name for debugging/logging purposes. + */ + readonly name: string; + + /** + * Initialize the analytics provider. + * Called once when the provider is loaded. + */ + init(): Promise; + + /** + * Identify the current user. + * @param userId - Unique user identifier (e.g., DID) + * @param traits - Optional user properties/traits + */ + identify(userId: string, traits?: Record): Promise; + + /** + * Track an analytics event with type-safe payloads. + * @param event - Event name from the event catalog + * @param properties - Event-specific properties + */ + track(event: E, properties: EventPayload): Promise; + + /** + * Track a page/screen view. + * @param name - Screen or page name + * @param properties - Optional additional properties + */ + page(name: string, properties?: Record): Promise; + + /** + * Reset the current user session (e.g., on logout). + */ + reset(): Promise; + + /** + * Enable or disable analytics collection. + * @param enabled - Whether analytics should be enabled + */ + setEnabled(enabled: boolean): Promise; +} + +/** + * Configuration for PostHog provider. + */ +export interface PostHogConfig { + apiKey: string; + apiHost?: string; +} + +/** + * Supported analytics provider names. + */ +export type AnalyticsProviderName = 'posthog' | 'firebase' | 'noop'; diff --git a/apps/learn-card-app/src/analytics/useSetAnalyticsUserId.ts b/apps/learn-card-app/src/analytics/useSetAnalyticsUserId.ts new file mode 100644 index 0000000000..420427d536 --- /dev/null +++ b/apps/learn-card-app/src/analytics/useSetAnalyticsUserId.ts @@ -0,0 +1,47 @@ +import { useEffect } from 'react'; + +import { useWallet } from 'learn-card-base'; +import { useIsCurrentUserLCNUser, useCurrentUser } from 'learn-card-base'; + +import { useAnalytics } from './context'; + +export interface UseSetAnalyticsUserIdOptions { + debug?: boolean; +} + +/** + * Hook to automatically identify the current user in analytics when they log in. + * Replaces useSetFirebaseAnalyticsUserId with a provider-agnostic implementation. + */ +export function useSetAnalyticsUserId(options: UseSetAnalyticsUserIdOptions = {}) { + const currentUser = useCurrentUser(); + const { data: currentLCNUser } = useIsCurrentUserLCNUser(); + const { getDID } = useWallet(); + const { identify } = useAnalytics(); + + useEffect(() => { + const setUserId = async () => { + if (options.debug) { + console.debug('[Analytics] Setting userId', currentUser); + } + + try { + if (currentUser) { + const did = await getDID(); + + if (did) { + await identify(did); + } + } + } catch (error) { + console.error('[Analytics] Unable to set userId', error); + } + }; + + if (currentUser) { + setUserId(); + } + }, [currentUser, currentLCNUser, getDID, identify, options.debug]); +} + +export default useSetAnalyticsUserId; diff --git a/apps/learn-card-app/src/components/boost-endorsements/EndorsementRequestForm/EndorsementRequestOptions.tsx b/apps/learn-card-app/src/components/boost-endorsements/EndorsementRequestForm/EndorsementRequestOptions.tsx index 84603c812e..9add970cea 100644 --- a/apps/learn-card-app/src/components/boost-endorsements/EndorsementRequestForm/EndorsementRequestOptions.tsx +++ b/apps/learn-card-app/src/components/boost-endorsements/EndorsementRequestForm/EndorsementRequestOptions.tsx @@ -20,7 +20,7 @@ import { useWallet, useGetCurrentLCNUser, } from 'learn-card-base'; -import useFirebaseAnalytics from '../../../hooks/useFirebaseAnalytics'; +import { useAnalytics, AnalyticsEvents } from '@analytics'; import { EndorsementRequestState } from './endorsement-request.helpers'; import { VC } from '@learncard/types'; @@ -42,7 +42,7 @@ export const EndorsementRequestOptions: React.FC<{ desktop: ModalTypes.FullScreen, }); const { achievementType, title } = useGetVCInfo(credential, categoryType); - const { logAnalyticsEvent } = useFirebaseAnalytics(); + const { track } = useAnalytics(); const { presentToast } = useToast(); const [errors, setErrors] = useState>({}); @@ -70,7 +70,7 @@ export const EndorsementRequestOptions: React.FC<{ setShareLink( `https://${host}/?uri=${uri}&seed=${seed}&pin=${pin}&endorsementRequest=true` ); - logAnalyticsEvent('generate_share_link', { + track(AnalyticsEvents.GENERATE_SHARE_LINK, { category: categoryType, boostType: achievementType, method: 'Share Boost', diff --git a/apps/learn-card-app/src/components/boost/boost-options-menu/ShareBoostLink.tsx b/apps/learn-card-app/src/components/boost/boost-options-menu/ShareBoostLink.tsx index 381dd7bc55..2a64ab411e 100644 --- a/apps/learn-card-app/src/components/boost/boost-options-menu/ShareBoostLink.tsx +++ b/apps/learn-card-app/src/components/boost/boost-options-menu/ShareBoostLink.tsx @@ -22,7 +22,7 @@ import { ToastTypeEnum, useToast, } from 'learn-card-base'; -import useFirebaseAnalytics from 'apps/learn-card-app/src/hooks/useFirebaseAnalytics'; +import { useAnalytics, AnalyticsEvents } from '@analytics'; import { getCredentialName, @@ -61,7 +61,7 @@ const ShareBoostLink: React.FC = ({ const { presentToast } = useToast(); const [shareLink, setShareLink] = useState(''); - const { logAnalyticsEvent } = useFirebaseAnalytics(); + const { track } = useAnalytics(); const { mutate: shareEarnedBoost, isPending: isLinkLoading } = useShareBoostMutation(); @@ -165,7 +165,7 @@ const ShareBoostLink: React.FC = ({ setShareLink(data?.link); } - logAnalyticsEvent('generate_share_link', { + track(AnalyticsEvents.GENERATE_SHARE_LINK, { category: categoryType, boostType: achievementType, method: 'Earned Boost', diff --git a/apps/learn-card-app/src/components/boost/boost-options/boostUserOptions/ShortBoostUserOptions.tsx b/apps/learn-card-app/src/components/boost/boost-options/boostUserOptions/ShortBoostUserOptions.tsx index 46c30d9122..695f7d3c71 100644 --- a/apps/learn-card-app/src/components/boost/boost-options/boostUserOptions/ShortBoostUserOptions.tsx +++ b/apps/learn-card-app/src/components/boost/boost-options/boostUserOptions/ShortBoostUserOptions.tsx @@ -10,7 +10,7 @@ import AddUser from '../../../svgs/AddUser'; import { BoostUserTypeEnum } from '../boostOptions'; -import useFirebaseAnalytics from 'apps/learn-card-app/src/hooks/useFirebaseAnalytics'; +import { useAnalytics, AnalyticsEvents } from '@analytics'; import useBoost from '../../../boost/hooks/useBoost'; import { useModal, @@ -66,7 +66,7 @@ const ShortBoostUserOptions: React.FC<{ const [presentAlert] = useIonAlert(); const sectionPortal = document.getElementById('section-cancel-portal'); - const { logAnalyticsEvent } = useFirebaseAnalytics(); + const { track } = useAnalytics(); const firstPage = draftRecipients?.length && draftRecipients?.length > 0 @@ -103,7 +103,7 @@ const ShortBoostUserOptions: React.FC<{ presentBoostIssueLoadingModal(); await handleSubmitExistingBoostSelf(profileId, boostUri, boost?.status); - logAnalyticsEvent('self_boost', { + track(AnalyticsEvents.SELF_BOOST, { category: boost?.category, boostType: boost?.type, method: 'Managed Boost', @@ -122,7 +122,7 @@ const ShortBoostUserOptions: React.FC<{ setIssueLoading(true); presentBoostIssueLoadingModal(); await handleSubmitExistingBoostOther(state.issueTo, boostUri, boost?.status); - logAnalyticsEvent('send_boost', { + track(AnalyticsEvents.SEND_BOOST, { category: boost?.category, boostType: boost?.type, method: 'Managed Boost', diff --git a/apps/learn-card-app/src/components/boost/boostCMS/BoostCMS.tsx b/apps/learn-card-app/src/components/boost/boostCMS/BoostCMS.tsx index 0b896628da..b99026f3d6 100644 --- a/apps/learn-card-app/src/components/boost/boostCMS/BoostCMS.tsx +++ b/apps/learn-card-app/src/components/boost/boostCMS/BoostCMS.tsx @@ -106,7 +106,7 @@ import { useDeviceTypeByWidth, } from 'learn-card-base'; -import useFirebaseAnalytics from '../../../hooks/useFirebaseAnalytics'; +import { useAnalytics, AnalyticsEvents } from '@analytics'; import { useAddCredentialToWallet } from '../mutations'; import useWallet from 'learn-card-base/hooks/useWallet'; import { useLCAStylesPackRegistry } from 'learn-card-base/hooks/useRegistry'; @@ -155,7 +155,7 @@ const BoostCMS: React.FC = ({ const queryClient = useQueryClient(); const { isDesktop } = useDeviceTypeByWidth(); - const { logAnalyticsEvent } = useFirebaseAnalytics(); + const { track } = useAnalytics(); const { newModal, closeModal } = useModal(); const { mutateAsync: createBoost } = useCreateBoost(); @@ -433,19 +433,19 @@ const BoostCMS: React.FC = ({ closeModal(); setCurrentStep(BoostCMSStepsEnum.publish); - logAnalyticsEvent('boostCMS_publish', { + track(AnalyticsEvents.BOOST_CMS_PUBLISH, { timestamp: Date.now(), action: 'publish', - boostType: state?.basicInfo?.achievementType, + boostType: state?.basicInfo?.achievementType ?? undefined, category: state?.basicInfo?.type, }); } else if (currentStep === BoostCMSStepsEnum.publish) { closeModal(); setCurrentStep(BoostCMSStepsEnum.issueTo); - logAnalyticsEvent('boostCMS_issue_to', { + track(AnalyticsEvents.BOOST_CMS_ISSUE_TO, { timestamp: Date.now(), action: 'issue_to', - boostType: state?.basicInfo?.achievementType, + boostType: state?.basicInfo?.achievementType ?? undefined, category: state?.basicInfo?.type, }); } @@ -547,10 +547,10 @@ const BoostCMS: React.FC = ({ type: ToastTypeEnum.Success, }); - logAnalyticsEvent('boostCMS_publish_draft', { + track(AnalyticsEvents.BOOST_CMS_PUBLISH, { timestamp: Date.now(), action: 'publish_draft', - boostType: state?.basicInfo?.achievementType, + boostType: state?.basicInfo?.achievementType ?? undefined, category: state?.basicInfo?.type, }); @@ -591,10 +591,10 @@ const BoostCMS: React.FC = ({ setIsPublishLoading(false); if (boostUri) { - logAnalyticsEvent('boostCMS_publish_live', { + track(AnalyticsEvents.BOOST_CMS_PUBLISH, { timestamp: Date.now(), action: 'publish_live', - boostType: state?.basicInfo?.achievementType, + boostType: state?.basicInfo?.achievementType ?? undefined, category: state?.basicInfo?.type, }); diff --git a/apps/learn-card-app/src/components/boost/boostCMS/UpdateBoostCMS.tsx b/apps/learn-card-app/src/components/boost/boostCMS/UpdateBoostCMS.tsx index 4dea40de48..aff40db54e 100644 --- a/apps/learn-card-app/src/components/boost/boostCMS/UpdateBoostCMS.tsx +++ b/apps/learn-card-app/src/components/boost/boostCMS/UpdateBoostCMS.tsx @@ -51,7 +51,7 @@ import { unwrapBoostCredential, } from 'learn-card-base/helpers/credentialHelpers'; -import useFirebaseAnalytics from '../../../hooks/useFirebaseAnalytics'; +import { useAnalytics, AnalyticsEvents } from '@analytics'; import useWallet from 'learn-card-base/hooks/useWallet'; import { getAchievementTypeFromCustomType, @@ -82,7 +82,7 @@ const UpdateBoostCMS: React.FC = () => { const location = useLocation(); const query = usePathQuery(); - const { logAnalyticsEvent } = useFirebaseAnalytics(); + const { track } = useAnalytics(); const { initWallet, addVCtoWallet } = useWallet(); const { presentToast } = useToast(); @@ -338,7 +338,7 @@ const UpdateBoostCMS: React.FC = () => { dissmissModal(); if (currentStep === BoostCMSStepsEnum.create) { setCurrentStep(BoostCMSStepsEnum.publish); - logAnalyticsEvent('boostCMS_publish', { + track(AnalyticsEvents.BOOST_CMS_PUBLISH, { timestamp: Date.now(), action: 'publish', boostType: state?.basicInfo?.achievementType, @@ -346,7 +346,7 @@ const UpdateBoostCMS: React.FC = () => { }); } else if (currentStep === BoostCMSStepsEnum.publish) { setCurrentStep(BoostCMSStepsEnum.issueTo); - logAnalyticsEvent('boostCMS_issue_to', { + track(AnalyticsEvents.BOOST_CMS_ISSUE_TO, { timestamp: Date.now(), action: 'issue_to', boostType: state?.basicInfo?.achievementType, @@ -354,7 +354,7 @@ const UpdateBoostCMS: React.FC = () => { }); } else if (currentStep === BoostCMSStepsEnum.issueTo) { setCurrentStep(BoostCMSStepsEnum.confirmation); - logAnalyticsEvent('boostCMS_confirmation', { + track(AnalyticsEvents.BOOST_CMS_CONFIRMATION, { timestamp: Date.now(), action: 'confirmation', boostType: state?.basicInfo?.achievementType, @@ -441,7 +441,7 @@ const UpdateBoostCMS: React.FC = () => { type: ToastTypeEnum.Success, }); - logAnalyticsEvent('boostCMS_publish_draft', { + track(AnalyticsEvents.BOOST_CMS_PUBLISH, { timestamp: Date.now(), action: 'publish_draft', boostType: state?.basicInfo?.achievementType, @@ -484,7 +484,7 @@ const UpdateBoostCMS: React.FC = () => { ); setIsPublishLoading(false); if (updatedBoost) { - logAnalyticsEvent('boostCMS_publish_live', { + track(AnalyticsEvents.BOOST_CMS_PUBLISH, { timestamp: Date.now(), action: 'publish_live', boostType: state?.basicInfo?.achievementType, diff --git a/apps/learn-card-app/src/components/boost/boostCMS/boostCMSForms/boostCMSIssueTo/BoostShareableCode.tsx b/apps/learn-card-app/src/components/boost/boostCMS/boostCMSForms/boostCMSIssueTo/BoostShareableCode.tsx index 6f52b1ced7..12ad592854 100644 --- a/apps/learn-card-app/src/components/boost/boostCMS/boostCMSForms/boostCMSIssueTo/BoostShareableCode.tsx +++ b/apps/learn-card-app/src/components/boost/boostCMS/boostCMSForms/boostCMSIssueTo/BoostShareableCode.tsx @@ -5,7 +5,7 @@ import { createPortal } from 'react-dom'; import { Clipboard } from '@capacitor/clipboard'; import useDebounce from 'apps/learn-card-app/src/hooks/useDebounce'; -import useFirebaseAnalytics from 'apps/learn-card-app/src/hooks/useFirebaseAnalytics'; +import { useAnalytics, AnalyticsEvents } from '@analytics'; import { IonRow, @@ -67,7 +67,7 @@ export const BoostShareableCode: React.FC = ({ }) => { const { newModal, closeModal } = useModal(); const { initWallet } = useWallet(); - const { logAnalyticsEvent } = useFirebaseAnalytics(); + const { track } = useAnalytics(); const { getRegisteredSigningAuthority, getRegisteredSigningAuthorities } = useSigningAuthority(); @@ -181,7 +181,7 @@ export const BoostShareableCode: React.FC = ({ _boostClaimLink?.challenge ) ); - logAnalyticsEvent('generate_claim_link', { + track(AnalyticsEvents.GENERATE_CLAIM_LINK, { category: state?.basicInfo?.type, boostType: state?.basicInfo?.achievementType, method: 'Claim Link', @@ -222,7 +222,7 @@ export const BoostShareableCode: React.FC = ({ _boostClaimLink?.challenge ) ); - logAnalyticsEvent('generate_claim_link', { + track(AnalyticsEvents.GENERATE_CLAIM_LINK, { category: state?.basicInfo?.type, boostType: state?.basicInfo?.achievementType, method: 'Claim Link', diff --git a/apps/learn-card-app/src/components/boost/boostCMS/boostCMSForms/boostCMSTitleForm/BoostCMSTitleForm.tsx b/apps/learn-card-app/src/components/boost/boostCMS/boostCMSForms/boostCMSTitleForm/BoostCMSTitleForm.tsx index 1362623911..513d749186 100644 --- a/apps/learn-card-app/src/components/boost/boostCMS/boostCMSForms/boostCMSTitleForm/BoostCMSTitleForm.tsx +++ b/apps/learn-card-app/src/components/boost/boostCMS/boostCMSForms/boostCMSTitleForm/BoostCMSTitleForm.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react'; import { IonTextarea } from '@ionic/react'; -import useFirebaseAnalytics from '../../../../../hooks/useFirebaseAnalytics'; +import { useAnalytics, AnalyticsEvents } from '@analytics'; import { BoostCMSState } from '../../../boost'; import { BoostCategoryOptionsEnum } from 'learn-card-base'; @@ -12,7 +12,7 @@ const BoostCMSTitleForm: React.FC<{ setState: React.Dispatch>; disabled?: boolean; }> = ({ state, setState, disabled = false }) => { - const { logAnalyticsEvent } = useFirebaseAnalytics(); + const { track } = useAnalytics(); const basicInfo = state?.basicInfo; const isID = state?.basicInfo?.type === BoostCategoryOptionsEnum.id; @@ -22,7 +22,7 @@ const BoostCMSTitleForm: React.FC<{ const maxCount = 100; const handleLogBoostCMSCreateStep = () => { - logAnalyticsEvent('boostCMS_data_entry', { + track(AnalyticsEvents.BOOST_CMS_DATA_ENTRY, { timestamp: Date.now(), action: 'data_entry', boostType: state?.basicInfo?.achievementType, diff --git a/apps/learn-card-app/src/components/boost/claim-boost-card/BoostClaimCard.tsx b/apps/learn-card-app/src/components/boost/claim-boost-card/BoostClaimCard.tsx index 6a43cca0e7..e273d1206a 100644 --- a/apps/learn-card-app/src/components/boost/claim-boost-card/BoostClaimCard.tsx +++ b/apps/learn-card-app/src/components/boost/claim-boost-card/BoostClaimCard.tsx @@ -9,7 +9,7 @@ import HourGlass from '../../../assets/lotties/hourglass.json'; import BoostFooter from 'learn-card-base/components/boost/boostFooter/BoostFooter'; import BoostDetailsSideMenu from '../boostCMS/BoostPreview/BoostDetailsSideMenu'; import BoostDetailsSideBar from '../boostCMS/BoostPreview/BoostDetailsSideBar'; -import useFirebaseAnalytics from 'apps/learn-card-app/src/hooks/useFirebaseAnalytics'; +import { useAnalytics, AnalyticsEvents } from '@analytics'; import { useIsLoggedIn } from 'learn-card-base/stores/currentUserStore'; import { useGetResolvedCredential, useToast, ToastTypeEnum } from 'learn-card-base'; @@ -87,7 +87,7 @@ export const BoostClaimCard: React.FC = ({ verify(); }, [credential]); - const { logAnalyticsEvent } = useFirebaseAnalytics(); + const { track } = useAnalytics(); const [isFront, setIsFront] = useState(true); const [isClaimLoading, setIsClaimLoading] = useState(false); @@ -130,7 +130,7 @@ export const BoostClaimCard: React.FC = ({ } if (credential) { - logAnalyticsEvent('claim_boost', { + track(AnalyticsEvents.CLAIM_BOOST, { category: category, boostType: achievementType, method: 'Notification', diff --git a/apps/learn-card-app/src/components/sidemenu/SideMenu.tsx b/apps/learn-card-app/src/components/sidemenu/SideMenu.tsx index 9c37f60c69..ff22356cbc 100644 --- a/apps/learn-card-app/src/components/sidemenu/SideMenu.tsx +++ b/apps/learn-card-app/src/components/sidemenu/SideMenu.tsx @@ -8,7 +8,7 @@ import { useIsLoggedIn } from 'learn-card-base/stores/currentUserStore'; import { useModal, ModalTypes } from 'learn-card-base'; import { useDeviceTypeByWidth } from 'learn-card-base/hooks/useDeviceTypeByWidth'; import useAiSession from '../../hooks/useAiSession'; -import useFirebaseAnalytics from '../../hooks/useFirebaseAnalytics'; +import { useAnalytics } from '@analytics'; import SideMenuFooter from './SideMenuFooter'; import SideMenuRootLinks from './SideMenuRootLinks'; @@ -48,7 +48,7 @@ const SideMenu: React.FC<{ branding: BrandingEnum.learncard }> = ({ const history = useHistory(); const location = useLocation(); const isLoggedIn = useIsLoggedIn(); - const { setCurrentScreen } = useFirebaseAnalytics(); + const { page: setCurrentScreen } = useAnalytics(); const { gate } = useLCNGatedAction(); const { openNewAiSessionModal } = useAiSession(); diff --git a/apps/learn-card-app/src/pages/claim-from-dashboard/ClaimFromDashboard.tsx b/apps/learn-card-app/src/pages/claim-from-dashboard/ClaimFromDashboard.tsx index ad8ed14fd1..1a827aa8be 100644 --- a/apps/learn-card-app/src/pages/claim-from-dashboard/ClaimFromDashboard.tsx +++ b/apps/learn-card-app/src/pages/claim-from-dashboard/ClaimFromDashboard.tsx @@ -33,7 +33,7 @@ import { } from 'learn-card-base'; import { useQueryClient } from '@tanstack/react-query'; import useRegistry from 'learn-card-base/hooks/useRegistry'; -import useFirebaseAnalytics from '../../hooks/useFirebaseAnalytics'; +import { useAnalytics, AnalyticsEvents } from '@analytics'; import { getAchievementType, @@ -141,7 +141,7 @@ const ClaimFromDashboard: React.FC = () => { const [credential, setCredential] = useState(); const [metadata, setMetadata] = useState(); - const { logAnalyticsEvent } = useFirebaseAnalytics(); + const { track } = useAnalytics(); const queryClient = useQueryClient(); const registry = useRegistry(); @@ -278,7 +278,7 @@ const ClaimFromDashboard: React.FC = () => { const achievementType = getAchievementType(credential); if (credential) { - logAnalyticsEvent('claim_boost', { + track(AnalyticsEvents.CLAIM_BOOST, { category: category, boostType: achievementType, method: 'Dashboard', diff --git a/apps/learn-card-app/src/pages/claim-from-request/ClaimFromRequest.tsx b/apps/learn-card-app/src/pages/claim-from-request/ClaimFromRequest.tsx index c942988238..dcad9a7f46 100644 --- a/apps/learn-card-app/src/pages/claim-from-request/ClaimFromRequest.tsx +++ b/apps/learn-card-app/src/pages/claim-from-request/ClaimFromRequest.tsx @@ -41,7 +41,7 @@ import { } from 'learn-card-base'; import { useQueryClient } from '@tanstack/react-query'; import useRegistry from 'learn-card-base/hooks/useRegistry'; -import useFirebaseAnalytics from '../../hooks/useFirebaseAnalytics'; +import { useAnalytics, AnalyticsEvents } from '@analytics'; import { getAchievementType, @@ -418,7 +418,7 @@ const ClaimFromRequest: React.FC = () => { state: ExchangeState.Loading, }); - const { logAnalyticsEvent } = useFirebaseAnalytics(); + const { track } = useAnalytics(); const queryClient = useQueryClient(); const registry = useRegistry(); @@ -538,7 +538,7 @@ const ClaimFromRequest: React.FC = () => { const achievementType = getAchievementType(credential); if (credential) { - logAnalyticsEvent('claim_boost', { + track(AnalyticsEvents.CLAIM_BOOST, { category: category, boostType: achievementType, method: 'VC-API Request', diff --git a/apps/learn-card-app/src/pages/claim-from-request/ExchangeAcceptCredentials.tsx b/apps/learn-card-app/src/pages/claim-from-request/ExchangeAcceptCredentials.tsx index f2f43ab4cb..c81a4ffe88 100644 --- a/apps/learn-card-app/src/pages/claim-from-request/ExchangeAcceptCredentials.tsx +++ b/apps/learn-card-app/src/pages/claim-from-request/ExchangeAcceptCredentials.tsx @@ -15,7 +15,7 @@ import VCDisplayCardWrapper2 from 'learn-card-base/components/vcmodal/VCDisplayC import X from 'learn-card-base/svgs/X'; import { useWallet, useToast, ToastTypeEnum, BoostPageViewMode } from 'learn-card-base'; -import useFirebaseAnalytics from '../../hooks/useFirebaseAnalytics'; +import { useAnalytics, AnalyticsEvents } from '@analytics'; import { getAchievementType, @@ -76,7 +76,7 @@ const ExchangeAcceptCredentials: React.FC = ({ const history = useHistory(); const { presentToast } = useToast(); const { storeAndAddVCToWallet } = useWallet(); - const { logAnalyticsEvent } = useFirebaseAnalytics(); + const { track } = useAnalytics(); const handleClaim = async () => { if (selectedCredentials.length === 0) { @@ -95,7 +95,7 @@ const ExchangeAcceptCredentials: React.FC = ({ const category = getDefaultCategoryForCredential(credential); const achievementType = getAchievementType(credential); - logAnalyticsEvent('claim_boost', { + track(AnalyticsEvents.CLAIM_BOOST, { category: category, boostType: achievementType, method: 'VC-API Request', diff --git a/apps/learn-card-app/src/pages/claimBoost/ClaimBoost.tsx b/apps/learn-card-app/src/pages/claimBoost/ClaimBoost.tsx index 5c2680a498..022a0b8273 100644 --- a/apps/learn-card-app/src/pages/claimBoost/ClaimBoost.tsx +++ b/apps/learn-card-app/src/pages/claimBoost/ClaimBoost.tsx @@ -32,7 +32,7 @@ import { ToastTypeEnum, } from 'learn-card-base'; -import useFirebaseAnalytics from '../../hooks/useFirebaseAnalytics'; +import { useAnalytics, AnalyticsEvents } from '@analytics'; import useCurrentUser from 'learn-card-base/hooks/useGetCurrentUser'; import useLCNGatedAction from '../../components/network-prompts/hooks/useLCNGatedAction'; import { useUploadVcFromText } from '../../hooks/useUploadVcFromText'; @@ -125,7 +125,7 @@ const ClaimBoost: React.FC<{ const isLoggedIn = useIsLoggedIn(); const { initWallet, addVCtoWallet } = useWallet(); const [presentAlert, dismissAlert] = useIonAlert(); - const { logAnalyticsEvent } = useFirebaseAnalytics(); + const { track } = useAnalytics(); const { newModal, closeModal } = useModal(); const { isMobile } = useDeviceTypeByWidth(); @@ -211,7 +211,7 @@ const ClaimBoost: React.FC<{ const achievementType = getAchievementType(boost); if (boost) { - logAnalyticsEvent('claim_boost', { + track(AnalyticsEvents.CLAIM_BOOST, { boostType: category, achievementType, method: 'Claim Modal', diff --git a/apps/learn-card-app/src/vite-env.d.ts b/apps/learn-card-app/src/vite-env.d.ts new file mode 100644 index 0000000000..0d0408582d --- /dev/null +++ b/apps/learn-card-app/src/vite-env.d.ts @@ -0,0 +1,11 @@ +/// + +interface ImportMetaEnv { + readonly VITE_ANALYTICS_PROVIDER?: 'posthog' | 'firebase' | 'noop'; + readonly VITE_POSTHOG_KEY?: string; + readonly VITE_POSTHOG_HOST?: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/apps/learn-card-app/tsconfig.json b/apps/learn-card-app/tsconfig.json index 32be237730..dd4d86bfea 100644 --- a/apps/learn-card-app/tsconfig.json +++ b/apps/learn-card-app/tsconfig.json @@ -1,6 +1,11 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "baseUrl": ".", + "paths": { + "@analytics": ["src/analytics"], + "@analytics/*": ["src/analytics/*"] + }, "target": "esnext", "lib": [ "dom", diff --git a/apps/learn-card-app/vite.config.ts b/apps/learn-card-app/vite.config.ts index 8fb9ed1acd..7cd2362003 100644 --- a/apps/learn-card-app/vite.config.ts +++ b/apps/learn-card-app/vite.config.ts @@ -50,6 +50,7 @@ export default defineConfig(({ mode }) => { '@web3auth/openlogin-adapter/dist/openloginAdapter.umd.min.js', 'learn-card-base': path.resolve(__dirname, '../../packages/learn-card-base/src'), 'apps/learn-card-app': path.resolve(__dirname), + '@analytics': path.resolve(__dirname, 'src/analytics'), }, dedupe: [ 'react', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8312bf66bb..63e12b7291 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -415,6 +415,9 @@ importers: pdf-lib: specifier: ^1.17.1 version: 1.17.1 + posthog-js: + specifier: ^1.333.0 + version: 1.333.0 pretty-bytes: specifier: ^6.1.1 version: 6.1.1 @@ -1400,7 +1403,7 @@ importers: version: 8.3.0 simple-git: specifier: ^3.9.0 - version: 3.30.0 + version: 3.30.0(supports-color@8.1.1) use-immer: specifier: ^0.7.0 version: 0.7.0(immer@9.0.21)(react@18.3.1) @@ -8997,6 +9000,10 @@ packages: resolution: {integrity: sha512-9B9RU0H7Ya1Dx/Rkyc4stuBZSGVQF27WigitInx2QQoj6KUpEFYPKoWjdFTunJYxmXmh17HeBvbMa1EhGyPmqQ==} engines: {node: '>=8.0.0'} + '@opentelemetry/api-logs@0.208.0': + resolution: {integrity: sha512-CjruKY9V6NMssL/T1kAFgzosF1v9o6oeN+aX5JB/C/xPNtmgIJqcXHG7fA82Ou1zCpWGl4lROQUKwUNE1pMCyg==} + engines: {node: '>=8.0.0'} + '@opentelemetry/api@1.9.0': resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} @@ -9013,12 +9020,42 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/core@2.2.0': + resolution: {integrity: sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/core@2.5.0': + resolution: {integrity: sha512-ka4H8OM6+DlUhSAZpONu0cPBtPPTQKxbxVzC4CzVx5+K4JnroJVBtDzLAMx4/3CDTJXRvVFhpFjtl4SaiTNoyQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.10.0' + + '@opentelemetry/exporter-logs-otlp-http@0.208.0': + resolution: {integrity: sha512-jOv40Bs9jy9bZVLo/i8FwUiuCvbjWDI+ZW13wimJm4LjnlwJxGgB+N/VWOZUTpM+ah/awXeQqKdNlpLf2EjvYg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/instrumentation@0.203.0': resolution: {integrity: sha512-ke1qyM+3AK2zPuBPb6Hk/GCsc5ewbLvPNkEuELx/JmANeEp6ZjnZ+wypPAJSucTw0wvCGrUaibDSdcrGFoWxKQ==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/otlp-exporter-base@0.208.0': + resolution: {integrity: sha512-gMd39gIfVb2OgxldxUtOwGJYSH8P1kVFFlJLuut32L6KgUC4gl1dMhn+YC2mGn0bDOiQYSk/uHOdSjuKp58vvA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + + '@opentelemetry/otlp-transformer@0.208.0': + resolution: {integrity: sha512-DCFPY8C6lAQHUNkzcNT9R+qYExvsk6C5Bto2pbNxgicpcSWbe2WHShLxkOxIdNcBiYPdVHv/e7vH7K6TI+C+fQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/propagator-b3@1.30.1': resolution: {integrity: sha512-oATwWWDIJzybAZ4pO76ATN5N6FFbOA1otibAVlS8v90B4S1wClnhRUk7K+2CHAwN1JKYuj4jh/lpCEG5BAqFuQ==} engines: {node: '>=14'} @@ -9037,12 +9074,42 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/resources@2.2.0': + resolution: {integrity: sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/resources@2.5.0': + resolution: {integrity: sha512-F8W52ApePshpoSrfsSk1H2yJn9aKjCrbpQF1M9Qii0GHzbfVeFUB+rc3X4aggyZD8x9Gu3Slua+s6krmq6Dt8g==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + + '@opentelemetry/sdk-logs@0.208.0': + resolution: {integrity: sha512-QlAyL1jRpOeaqx7/leG1vJMp84g0xKP6gJmfELBpnI4O/9xPX+Hu5m1POk9Kl+veNkyth5t19hRlN6tNY1sjbA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.4.0 <1.10.0' + + '@opentelemetry/sdk-metrics@2.2.0': + resolution: {integrity: sha512-G5KYP6+VJMZzpGipQw7Giif48h6SGQ2PFKEYCybeXJsOCB4fp8azqMAAzE5lnnHK3ZVwYQrgmFbsUJO/zOnwGw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.9.0 <1.10.0' + '@opentelemetry/sdk-trace-base@1.30.1': resolution: {integrity: sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==} engines: {node: '>=14'} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/sdk-trace-base@2.2.0': + resolution: {integrity: sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@opentelemetry/sdk-trace-node@1.30.1': resolution: {integrity: sha512-cBjYOINt1JxXdpw1e5MlHmFRc5fgj4GW/86vsKFxJCJ8AL4PdVtYH41gWwl4qd4uQjqEL1oJVrXkSy5cnduAnQ==} engines: {node: '>=14'} @@ -9053,6 +9120,10 @@ packages: resolution: {integrity: sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==} engines: {node: '>=14'} + '@opentelemetry/semantic-conventions@1.39.0': + resolution: {integrity: sha512-R5R9tb2AXs2IRLNKLBJDynhkfmx7mX0vi8NkhZb3gUkPWHn6HXk5J8iQ/dql0U3ApfWym4kXXmBDRGO+oeOfjg==} + engines: {node: '>=14'} + '@oslojs/encoding@1.1.0': resolution: {integrity: sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==} @@ -9203,6 +9274,12 @@ packages: '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + '@posthog/core@1.13.0': + resolution: {integrity: sha512-knjncrk7qRmssFRbGzBl1Tunt21GRpe0Wv+uVelyL0Rh7PdQUsgguulzXFTps8hA6wPwTU4kq85qnbAJ3eH6Wg==} + + '@posthog/types@1.333.0': + resolution: {integrity: sha512-9Wg/2ez+EZh6NmtOjhtYSkBHz/yIq8WMS0QSIizUoggh35hHVg4BTMXl3rz/tPearJNKU/8oRjEyuZ0OYTEDOA==} + '@prettier/plugin-xml@2.2.0': resolution: {integrity: sha512-UWRmygBsyj4bVXvDiqSccwT1kmsorcwQwaIy30yVh8T+Gspx4OlC0shX1y+ZuwXZvgnafmpRYKks0bAu9urJew==} @@ -16790,6 +16867,9 @@ packages: fetch-retry@5.0.6: resolution: {integrity: sha512-3yurQZ2hD9VISAhJJP9bpYFNQrHHBXE2JxxjY5aLEcDi46RmAzJE2OC9FAde0yis5ElW0jTTzs0zfg/Cca4XqQ==} + fflate@0.4.8: + resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==} + fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} @@ -22421,9 +22501,15 @@ packages: resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} engines: {node: '>=0.10.0'} + posthog-js@1.333.0: + resolution: {integrity: sha512-c7vquERMedjuGE2GnaDDJW/V1BIMMQG7BlYKrH0z8O7fc3WpEsQ/IyQ+9aD9+DLxlDCFpzrwgoxVDWi9K37mdA==} + postmark@4.0.5: resolution: {integrity: sha512-nerZdd3TwOH4CgGboZnlUM/q7oZk0EqpZgJL+Y3Nup8kHeaukxouQ6JcFF3EJEijc4QbuNv1TefGhboAKtf/SQ==} + preact@10.28.2: + resolution: {integrity: sha512-lbteaWGzGHdlIuiJ0l2Jq454m6kcpI1zNje6d8MlGAFlYvP2GO4ibnat7P74Esfz4sPTdM6UxtTwh/d3pwM9JA==} + prebuild-install@7.1.3: resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} engines: {node: '>=10'} @@ -22713,6 +22799,9 @@ packages: quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + query-selector-shadow-dom@1.0.1: + resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} + query-string@7.1.3: resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} engines: {node: '>=6'} @@ -27489,7 +27578,7 @@ snapshots: '@astrojs/telemetry@1.0.1': dependencies: ci-info: 3.9.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) dlv: 1.1.3 dset: 3.1.4 is-docker: 3.0.0 @@ -27502,7 +27591,7 @@ snapshots: '@astrojs/telemetry@3.1.0': dependencies: ci-info: 4.3.1 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) dlv: 1.1.3 dset: 3.1.4 is-docker: 3.0.0 @@ -28416,7 +28505,7 @@ snapshots: '@babel/traverse': 7.28.5 '@babel/types': 7.28.5 convert-source-map: 1.9.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 lodash: 4.17.21 @@ -28439,7 +28528,7 @@ snapshots: '@babel/types': 7.28.5 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -28491,7 +28580,7 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.11 transitivePeerDependencies: @@ -29370,7 +29459,7 @@ snapshots: '@babel/parser': 7.28.5 '@babel/template': 7.27.2 '@babel/types': 7.28.5 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -29479,7 +29568,7 @@ snapshots: '@ionic/utils-subprocess': 3.0.1 '@ionic/utils-terminal': 2.3.5 commander: 12.1.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) env-paths: 2.2.1 fs-extra: 11.3.2 kleur: 4.1.5 @@ -31193,7 +31282,7 @@ snapshots: '@esbuild-plugins/node-resolve@0.1.4(esbuild@0.15.18)': dependencies: '@types/resolve': 1.20.6 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) esbuild: 0.15.18 escape-string-regexp: 4.0.0 resolve: 1.22.11 @@ -31203,7 +31292,7 @@ snapshots: '@esbuild-plugins/node-resolve@0.1.4(esbuild@0.27.1)': dependencies: '@types/resolve': 1.20.6 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) esbuild: 0.27.1 escape-string-regexp: 4.0.0 resolve: 1.22.11 @@ -31213,7 +31302,7 @@ snapshots: '@esbuild-plugins/node-resolve@0.2.2(esbuild@0.27.1)': dependencies: '@types/resolve': 1.20.6 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) esbuild: 0.27.1 escape-string-regexp: 4.0.0 resolve: 1.22.11 @@ -31752,7 +31841,7 @@ snapshots: '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -32087,7 +32176,7 @@ snapshots: ci-info: 3.9.0 compression: 1.8.1 connect: 3.7.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) env-editor: 0.4.2 expo: 54.0.25(@babel/core@7.28.5)(bufferutil@4.0.9)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.27)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(utf-8-validate@5.0.10) expo-server: 1.0.4 @@ -32144,7 +32233,7 @@ snapshots: '@expo/plist': 0.4.7 '@expo/sdk-runtime-versions': 1.0.0 chalk: 4.1.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) getenv: 2.0.0 glob: 10.5.0 resolve-from: 5.0.0 @@ -32199,7 +32288,7 @@ snapshots: '@expo/env@2.0.7': dependencies: chalk: 4.1.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) dotenv: 16.4.7 dotenv-expand: 11.0.7 getenv: 2.0.0 @@ -32212,7 +32301,7 @@ snapshots: '@expo/spawn-async': 1.7.2 arg: 5.0.2 chalk: 4.1.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) getenv: 2.0.0 glob: 10.5.0 ignore: 5.3.2 @@ -32266,7 +32355,7 @@ snapshots: '@expo/spawn-async': 1.7.2 browserslist: 4.28.0 chalk: 4.1.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) dotenv: 16.4.7 dotenv-expand: 11.0.7 getenv: 2.0.0 @@ -32336,7 +32425,7 @@ snapshots: '@expo/image-utils': 0.8.7 '@expo/json-file': 10.0.7 '@react-native/normalize-colors': 0.81.5 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) expo: 54.0.25(@babel/core@7.28.5)(bufferutil@4.0.9)(react-native@0.82.1(@babel/core@7.28.5)(@types/react@18.3.27)(bufferutil@4.0.9)(react@18.3.1)(utf-8-validate@5.0.10))(react@18.3.1)(utf-8-validate@5.0.10) resolve-from: 5.0.0 semver: 7.7.3 @@ -33105,7 +33194,7 @@ snapshots: '@humanwhocodes/config-array@0.13.0': dependencies: '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -33205,7 +33294,7 @@ snapshots: '@ionic/cli-framework-output@2.2.5': dependencies: '@ionic/utils-terminal': 2.3.3 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -33213,7 +33302,7 @@ snapshots: '@ionic/cli-framework-output@2.2.8': dependencies: '@ionic/utils-terminal': 2.3.5 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -33221,7 +33310,7 @@ snapshots: '@ionic/cli-framework-prompts@2.1.10': dependencies: '@ionic/utils-terminal': 2.3.3 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) inquirer: 7.3.3 tslib: 2.8.1 transitivePeerDependencies: @@ -33238,7 +33327,7 @@ snapshots: '@ionic/utils-subprocess': 2.1.11 '@ionic/utils-terminal': 2.3.3 chalk: 4.1.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) lodash: 4.17.21 minimist: 1.2.8 rimraf: 3.0.2 @@ -33260,7 +33349,7 @@ snapshots: '@ionic/utils-subprocess': 2.1.11 '@ionic/utils-terminal': 2.3.3 chalk: 4.1.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) diff: 4.0.2 elementtree: 0.1.7 leek: 0.0.24 @@ -33309,7 +33398,7 @@ snapshots: '@ionic/utils-array@2.1.5': dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -33324,7 +33413,7 @@ snapshots: '@ionic/utils-fs@3.1.6': dependencies: '@types/fs-extra': 8.1.5 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) fs-extra: 9.1.0 tslib: 2.8.1 transitivePeerDependencies: @@ -33341,21 +33430,21 @@ snapshots: '@ionic/utils-network@2.1.5': dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) tslib: 2.8.1 transitivePeerDependencies: - supports-color '@ionic/utils-object@2.1.5': dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) tslib: 2.8.1 transitivePeerDependencies: - supports-color '@ionic/utils-object@2.1.6': dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -33364,7 +33453,7 @@ snapshots: dependencies: '@ionic/utils-object': 2.1.5 '@ionic/utils-terminal': 2.3.3 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) signal-exit: 3.0.7 tree-kill: 1.2.2 tslib: 2.8.1 @@ -33375,7 +33464,7 @@ snapshots: dependencies: '@ionic/utils-object': 2.1.6 '@ionic/utils-terminal': 2.3.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) signal-exit: 3.0.7 tree-kill: 1.2.2 tslib: 2.8.1 @@ -33386,7 +33475,7 @@ snapshots: dependencies: '@ionic/utils-object': 2.1.6 '@ionic/utils-terminal': 2.3.5 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) signal-exit: 3.0.7 tree-kill: 1.2.2 tslib: 2.8.1 @@ -33395,21 +33484,21 @@ snapshots: '@ionic/utils-stream@3.1.5': dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) tslib: 2.8.1 transitivePeerDependencies: - supports-color '@ionic/utils-stream@3.1.6': dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) tslib: 2.8.1 transitivePeerDependencies: - supports-color '@ionic/utils-stream@3.1.7': dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -33422,7 +33511,7 @@ snapshots: '@ionic/utils-stream': 3.1.5 '@ionic/utils-terminal': 2.3.3 cross-spawn: 7.0.6 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -33435,7 +33524,7 @@ snapshots: '@ionic/utils-stream': 3.1.6 '@ionic/utils-terminal': 2.3.4 cross-spawn: 7.0.6 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -33448,7 +33537,7 @@ snapshots: '@ionic/utils-stream': 3.1.7 '@ionic/utils-terminal': 2.3.5 cross-spawn: 7.0.6 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -33456,7 +33545,7 @@ snapshots: '@ionic/utils-terminal@2.3.3': dependencies: '@types/slice-ansi': 4.0.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) signal-exit: 3.0.7 slice-ansi: 4.0.0 string-width: 4.2.3 @@ -33470,7 +33559,7 @@ snapshots: '@ionic/utils-terminal@2.3.4': dependencies: '@types/slice-ansi': 4.0.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) signal-exit: 3.0.7 slice-ansi: 4.0.0 string-width: 4.2.3 @@ -33484,7 +33573,7 @@ snapshots: '@ionic/utils-terminal@2.3.5': dependencies: '@types/slice-ansi': 4.0.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) signal-exit: 3.0.7 slice-ansi: 4.0.0 string-width: 4.2.3 @@ -34283,12 +34372,6 @@ snapshots: dequal: 2.0.3 react: 18.3.1 - '@kwsites/file-exists@1.1.1': - dependencies: - debug: 4.4.3(supports-color@5.5.0) - transitivePeerDependencies: - - supports-color - '@kwsites/file-exists@1.1.1(supports-color@8.1.1)': dependencies: debug: 4.4.3(supports-color@8.1.1) @@ -34638,7 +34721,7 @@ snapshots: '@scure/base': 1.2.6 '@types/debug': 4.1.12 '@types/lodash': 4.17.20 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) lodash: 4.17.21 pony-cause: 2.1.11 semver: 7.7.3 @@ -34657,7 +34740,7 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 '@types/debug': 4.1.12 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) pony-cause: 2.1.11 semver: 7.7.3 uuid: 9.0.1 @@ -34671,7 +34754,7 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 '@types/debug': 4.1.12 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) pony-cause: 2.1.11 semver: 7.7.3 uuid: 9.0.1 @@ -35006,8 +35089,11 @@ snapshots: '@opentelemetry/api': 1.9.0 optional: true - '@opentelemetry/api@1.9.0': - optional: true + '@opentelemetry/api-logs@0.208.0': + dependencies: + '@opentelemetry/api': 1.9.0 + + '@opentelemetry/api@1.9.0': {} '@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.0)': dependencies: @@ -35020,6 +35106,25 @@ snapshots: '@opentelemetry/semantic-conventions': 1.28.0 optional: true + '@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/semantic-conventions': 1.39.0 + + '@opentelemetry/core@2.5.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/semantic-conventions': 1.39.0 + + '@opentelemetry/exporter-logs-otlp-http@0.208.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.208.0 + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-exporter-base': 0.208.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.208.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.208.0(@opentelemetry/api@1.9.0) + '@opentelemetry/instrumentation@0.203.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -35030,6 +35135,23 @@ snapshots: - supports-color optional: true + '@opentelemetry/otlp-exporter-base@0.208.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.208.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/otlp-transformer@0.208.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.208.0 + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.208.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0) + protobufjs: 7.5.4 + '@opentelemetry/propagator-b3@1.30.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -35049,6 +35171,31 @@ snapshots: '@opentelemetry/semantic-conventions': 1.28.0 optional: true + '@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.39.0 + + '@opentelemetry/resources@2.5.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.5.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.39.0 + + '@opentelemetry/sdk-logs@0.208.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.208.0 + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0) + + '@opentelemetry/sdk-metrics@2.2.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -35057,6 +35204,13 @@ snapshots: '@opentelemetry/semantic-conventions': 1.28.0 optional: true + '@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.39.0 + '@opentelemetry/sdk-trace-node@1.30.1(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 @@ -35071,6 +35225,8 @@ snapshots: '@opentelemetry/semantic-conventions@1.28.0': optional: true + '@opentelemetry/semantic-conventions@1.39.0': {} + '@oslojs/encoding@1.1.0': {} '@paralleldrive/cuid2@2.3.1': @@ -35237,12 +35393,18 @@ snapshots: '@pm2/pm2-version-check@1.0.4': dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color '@polka/url@1.0.0-next.29': {} + '@posthog/core@1.13.0': + dependencies: + cross-spawn: 7.0.6 + + '@posthog/types@1.333.0': {} + '@prettier/plugin-xml@2.2.0': dependencies: '@xml-tools/parser': 1.0.11 @@ -35984,7 +36146,7 @@ snapshots: '@react-native/community-cli-plugin@0.82.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@react-native/dev-middleware': 0.82.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) invariant: 2.2.4 metro: 0.83.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) metro-config: 0.83.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -36015,7 +36177,7 @@ snapshots: chrome-launcher: 0.15.2 chromium-edge-launcher: 0.2.0 connect: 3.7.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) invariant: 2.2.4 nullthrows: 1.1.1 open: 7.4.2 @@ -36035,7 +36197,7 @@ snapshots: chrome-launcher: 0.15.2 chromium-edge-launcher: 0.2.0 connect: 3.7.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) invariant: 2.2.4 nullthrows: 1.1.1 open: 7.4.2 @@ -36443,7 +36605,7 @@ snapshots: '@sentry/cli@2.58.2': dependencies: - https-proxy-agent: 5.0.1 + https-proxy-agent: 5.0.1(supports-color@8.1.1) node-fetch: 2.7.0 progress: 2.0.3 proxy-from-env: 1.1.0 @@ -36519,7 +36681,7 @@ snapshots: '@sentry/types': 7.61.0 '@sentry/utils': 7.61.0 cookie: 0.4.2 - https-proxy-agent: 5.0.1 + https-proxy-agent: 5.0.1(supports-color@8.1.1) lru_map: 0.3.3 tslib: 2.8.1 transitivePeerDependencies: @@ -39563,7 +39725,7 @@ snapshots: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1)(typescript@5.6.2) '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.6.2) - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) eslint: 8.57.1 graphemer: 1.4.0 ignore: 5.3.2 @@ -39580,7 +39742,7 @@ snapshots: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.6.2) - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) eslint: 8.57.1 optionalDependencies: typescript: 5.6.2 @@ -39596,7 +39758,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.6.2) '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.6.2) - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) eslint: 8.57.1 tsutils: 3.21.0(typescript@5.6.2) optionalDependencies: @@ -39610,7 +39772,7 @@ snapshots: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.7.3 @@ -40615,12 +40777,6 @@ snapshots: agent-base@5.1.1: {} - agent-base@6.0.2: - dependencies: - debug: 4.4.3(supports-color@5.5.0) - transitivePeerDependencies: - - supports-color - agent-base@6.0.2(supports-color@8.1.1): dependencies: debug: 4.4.3(supports-color@8.1.1) @@ -40869,12 +41025,12 @@ snapshots: github-username: 6.0.0 inquirer: 7.3.3 jest: 29.7.0(@types/node@17.0.45)(ts-node@10.9.2(@swc/core@1.15.2(@swc/helpers@0.5.17))(@types/node@18.19.130)(typescript@5.6.2)) - jest-watch-typeahead: 2.2.2(jest@29.7.0(@types/node@18.19.130)(ts-node@10.9.2(@swc/core@1.15.2(@swc/helpers@0.5.17))(@types/node@18.19.130)(typescript@5.6.2))) + jest-watch-typeahead: 2.2.2(jest@29.7.0(@types/node@17.0.45)(ts-node@10.9.2(@swc/core@1.15.2(@swc/helpers@0.5.17))(@types/node@18.19.130)(typescript@5.6.2))) lodash: 4.17.21 ora: 5.4.1 prettier: 2.8.8 rimraf: 3.0.2 - ts-jest: 29.4.5(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(esbuild@0.15.18)(jest-util@29.7.0)(jest@29.7.0(@types/node@18.19.130)(ts-node@10.9.2(@swc/core@1.15.2(@swc/helpers@0.5.17))(@types/node@18.19.130)(typescript@5.6.2)))(typescript@5.6.2) + ts-jest: 29.4.5(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(esbuild@0.15.18)(jest-util@29.7.0)(jest@29.7.0(@types/node@17.0.45)(ts-node@10.9.2(@swc/core@1.15.2(@swc/helpers@0.5.17))(@types/node@18.19.130)(typescript@5.6.2)))(typescript@5.6.2) typescript: 5.6.2 webpack-merge: 5.10.0 yup: 0.32.11 @@ -41188,7 +41344,7 @@ snapshots: boxen: 6.2.1 ci-info: 3.9.0 common-ancestor-path: 1.0.1 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) diff: 5.2.0 eol: 0.9.1 es-module-lexer: 0.10.5 @@ -41257,7 +41413,7 @@ snapshots: ci-info: 3.9.0 common-ancestor-path: 1.0.1 cookie: 0.5.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) deepmerge-ts: 4.3.0 devalue: 4.3.3 diff: 5.2.0 @@ -41331,7 +41487,7 @@ snapshots: common-ancestor-path: 1.0.1 cookie: 0.7.2 cssesc: 3.0.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) deterministic-object-hash: 2.0.2 devalue: 5.6.1 diff: 5.2.0 @@ -41715,7 +41871,7 @@ snapshots: babel-plugin-react-native-web: 0.21.2 babel-plugin-syntax-hermes-parser: 0.29.1 babel-plugin-transform-flow-enums: 0.0.2(@babel/core@7.28.5) - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) react-refresh: 0.14.2 resolve-from: 5.0.0 optionalDependencies: @@ -43345,7 +43501,7 @@ snapshots: dependencies: '@ionic/utils-array': 2.1.6 '@ionic/utils-fs': 3.1.7 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) elementtree: 0.1.7 sharp: 0.29.3 tslib: 2.8.1 @@ -44079,7 +44235,7 @@ snapshots: detect-port@1.6.1: dependencies: address: 1.2.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -44201,7 +44357,7 @@ snapshots: docker-modem@3.0.8: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) readable-stream: 3.6.2 split-ca: 1.0.1 ssh2: 1.17.0 @@ -44210,7 +44366,7 @@ snapshots: docker-modem@5.0.6: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) readable-stream: 3.6.2 split-ca: 1.0.1 ssh2: 1.17.0 @@ -44295,7 +44451,6 @@ snapshots: dompurify@3.3.1: optionalDependencies: '@types/trusted-types': 2.0.7 - optional: true domutils@2.8.0: dependencies: @@ -44839,7 +44994,7 @@ snapshots: esbuild-register@3.6.0(esbuild@0.18.20): dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) esbuild: 0.18.20 transitivePeerDependencies: - supports-color @@ -45173,7 +45328,7 @@ snapshots: eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.32.0)(eslint@8.57.1): dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) eslint: 8.57.1 eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.6.2))(eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.32.0)(eslint@8.57.1))(eslint@8.57.1) glob: 7.2.3 @@ -45244,7 +45399,7 @@ snapshots: dependencies: '@es-joy/jsdoccomment': 0.36.1 comment-parser: 1.3.1 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) escape-string-regexp: 4.0.0 eslint: 8.57.1 esquery: 1.6.0 @@ -45328,7 +45483,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -46072,6 +46227,8 @@ snapshots: fetch-retry@5.0.6: {} + fflate@0.4.8: {} + fflate@0.8.2: {} figlet@1.9.4: @@ -46156,7 +46313,7 @@ snapshots: '@filestack/loader': 1.0.9 '@sentry/browser': 8.34.0 abab: 2.0.6 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) eventemitter3: 5.0.1 fast-xml-parser: 4.5.3 file-type: 16.5.4 @@ -46180,7 +46337,7 @@ snapshots: '@filestack/loader': 1.0.9 '@sentry/browser': 8.34.0 abab: 2.0.6 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) eventemitter3: 5.0.1 fast-xml-parser: 4.5.3 file-type: 16.5.4 @@ -46406,7 +46563,7 @@ snapshots: follow-redirects@1.15.11(debug@4.4.3): optionalDependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) fontfaceobserver@2.3.0: optional: true @@ -46722,7 +46879,7 @@ snapshots: dependencies: '@tootallnate/once': 1.1.2 data-uri-to-buffer: 3.0.1 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) file-uri-to-path: 2.0.0 fs-extra: 8.1.0 ftp: 0.3.10 @@ -46733,7 +46890,7 @@ snapshots: dependencies: basic-ftp: 5.0.5 data-uri-to-buffer: 6.0.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -47628,23 +47785,23 @@ snapshots: http-proxy-agent@4.0.1: dependencies: '@tootallnate/once': 1.1.2 - agent-base: 6.0.2 - debug: 4.4.3(supports-color@5.5.0) + agent-base: 6.0.2(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color http-proxy-agent@5.0.0: dependencies: '@tootallnate/once': 2.0.0 - agent-base: 6.0.2 - debug: 4.4.3(supports-color@5.5.0) + agent-base: 6.0.2(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -47678,14 +47835,7 @@ snapshots: https-proxy-agent@4.0.0: dependencies: agent-base: 5.1.1 - debug: 4.4.3(supports-color@5.5.0) - transitivePeerDependencies: - - supports-color - - https-proxy-agent@5.0.1: - dependencies: - agent-base: 6.0.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -47699,7 +47849,7 @@ snapshots: https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -48024,7 +48174,7 @@ snapshots: dependencies: '@ioredis/commands': 1.4.0 cluster-key-slot: 1.1.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -48459,7 +48609,7 @@ snapshots: istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -49433,6 +49583,17 @@ snapshots: string-length: 5.0.1 strip-ansi: 7.1.2 + jest-watch-typeahead@2.2.2(jest@29.7.0(@types/node@17.0.45)(ts-node@10.9.2(@swc/core@1.15.2(@swc/helpers@0.5.17))(@types/node@18.19.130)(typescript@5.6.2))): + dependencies: + ansi-escapes: 6.2.1 + chalk: 5.6.2 + jest: 29.7.0(@types/node@17.0.45)(ts-node@10.9.2(@swc/core@1.15.2(@swc/helpers@0.5.17))(@types/node@18.19.130)(typescript@5.6.2)) + jest-regex-util: 29.6.3 + jest-watcher: 29.7.0 + slash: 5.1.0 + string-length: 5.0.1 + strip-ansi: 7.1.2 + jest-watch-typeahead@2.2.2(jest@29.7.0(@types/node@18.19.130)(ts-node@10.9.2(@swc/core@1.15.2(@swc/helpers@0.5.17))(@types/node@18.19.130)(typescript@5.6.2))): dependencies: ansi-escapes: 6.2.1 @@ -49673,7 +49834,7 @@ snapshots: form-data: 4.0.5 html-encoding-sniffer: 3.0.0 http-proxy-agent: 5.0.0 - https-proxy-agent: 5.0.1 + https-proxy-agent: 5.0.1(supports-color@8.1.1) is-potential-custom-element-name: 1.0.1 nwsapi: 2.2.22 parse5: 6.0.1 @@ -49707,7 +49868,7 @@ snapshots: form-data: 4.0.5 html-encoding-sniffer: 3.0.0 http-proxy-agent: 5.0.0 - https-proxy-agent: 5.0.1 + https-proxy-agent: 5.0.1(supports-color@8.1.1) is-potential-custom-element-name: 1.0.1 nwsapi: 2.2.22 parse5: 7.3.0 @@ -49812,7 +49973,7 @@ snapshots: json-schema-resolver@2.0.0: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) rfdc: 1.4.1 uri-js: 4.4.1 transitivePeerDependencies: @@ -49938,7 +50099,7 @@ snapshots: dependencies: '@types/express': 4.17.25 '@types/jsonwebtoken': 9.0.10 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) jose: 4.15.9 limiter: 1.1.5 lru-memoizer: 2.3.0 @@ -51148,7 +51309,7 @@ snapshots: metro-file-map@0.83.2: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) fb-watchman: 2.0.2 flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 @@ -51163,7 +51324,7 @@ snapshots: metro-file-map@0.83.3: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) fb-watchman: 2.0.2 flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 @@ -51345,7 +51506,7 @@ snapshots: chalk: 4.1.2 ci-info: 2.0.0 connect: 3.7.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) error-stack-parser: 2.1.4 flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 @@ -51393,7 +51554,7 @@ snapshots: chalk: 4.1.2 ci-info: 2.0.0 connect: 3.7.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) error-stack-parser: 2.1.4 flow-enums-runtime: 0.0.6 graceful-fs: 4.2.11 @@ -51818,7 +51979,7 @@ snapshots: micromark@3.2.0: dependencies: '@types/debug': 4.1.12 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) decode-named-character-reference: 1.2.0 micromark-core-commonmark: 1.1.0 micromark-factory-space: 1.1.0 @@ -51840,7 +52001,7 @@ snapshots: micromark@4.0.2: dependencies: '@types/debug': 4.1.12 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) decode-named-character-reference: 1.2.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 @@ -52081,7 +52242,7 @@ snapshots: dependencies: async-mutex: 0.5.0 camelcase: 6.3.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) find-cache-dir: 3.3.2 follow-redirects: 1.15.11(debug@4.4.3) https-proxy-agent: 7.0.6 @@ -52107,7 +52268,7 @@ snapshots: dependencies: async-mutex: 0.4.1 camelcase: 6.3.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) find-cache-dir: 3.3.2 follow-redirects: 1.15.11(debug@4.4.3) https-proxy-agent: 7.0.6 @@ -52131,7 +52292,7 @@ snapshots: dependencies: async-mutex: 0.4.1 camelcase: 6.3.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) find-cache-dir: 3.3.2 follow-redirects: 1.15.11(debug@4.4.3) https-proxy-agent: 7.0.6 @@ -52318,7 +52479,7 @@ snapshots: '@ionic/utils-fs': 3.1.7 '@ionic/utils-terminal': 2.3.5 bplist-parser: 0.3.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) elementtree: 0.1.7 ini: 4.1.3 plist: 3.1.0 @@ -52334,7 +52495,7 @@ snapshots: '@ionic/utils-fs': 3.1.7 '@ionic/utils-terminal': 2.3.5 bplist-parser: 0.3.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) elementtree: 0.1.7 ini: 4.1.3 plist: 3.1.0 @@ -52431,7 +52592,7 @@ snapshots: new-find-package-json@2.0.0: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -52463,7 +52624,7 @@ snapshots: nock@13.5.6: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) json-stringify-safe: 5.0.1 propagate: 2.0.1 transitivePeerDependencies: @@ -53268,11 +53429,11 @@ snapshots: pac-proxy-agent@5.0.0: dependencies: '@tootallnate/once': 1.1.2 - agent-base: 6.0.2 - debug: 4.4.3(supports-color@5.5.0) + agent-base: 6.0.2(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) get-uri: 3.0.2 http-proxy-agent: 4.0.1 - https-proxy-agent: 5.0.1 + https-proxy-agent: 5.0.1(supports-color@8.1.1) pac-resolver: 5.0.1 raw-body: 2.5.2 socks-proxy-agent: 5.0.1 @@ -53283,7 +53444,7 @@ snapshots: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) get-uri: 6.0.5 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 @@ -53734,7 +53895,7 @@ snapshots: pm2-axon-rpc@0.7.1: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -53742,7 +53903,7 @@ snapshots: dependencies: amp: 0.3.1 amp-message: 0.1.2 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) escape-string-regexp: 4.0.0 transitivePeerDependencies: - supports-color @@ -53759,7 +53920,7 @@ snapshots: pm2-sysmonit@1.2.8: dependencies: async: 3.2.6 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) pidusage: 2.0.21 systeminformation: 5.27.11 tx2: 1.0.5 @@ -53781,7 +53942,7 @@ snapshots: commander: 2.15.1 croner: 4.1.97 dayjs: 1.11.19 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) enquirer: 2.3.6 eventemitter2: 5.0.1 fclone: 1.0.11 @@ -54121,12 +54282,30 @@ snapshots: dependencies: xtend: 4.0.2 + posthog-js@1.333.0: + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.208.0 + '@opentelemetry/exporter-logs-otlp-http': 0.208.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.5.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.208.0(@opentelemetry/api@1.9.0) + '@posthog/core': 1.13.0 + '@posthog/types': 1.333.0 + core-js: 3.47.0 + dompurify: 3.3.1 + fflate: 0.4.8 + preact: 10.28.2 + query-selector-shadow-dom: 1.0.1 + web-vitals: 4.2.4 + postmark@4.0.5: dependencies: axios: 1.13.2 transitivePeerDependencies: - debug + preact@10.28.2: {} + prebuild-install@7.1.3: dependencies: detect-libc: 2.1.2 @@ -54348,10 +54527,10 @@ snapshots: proxy-agent@5.0.0: dependencies: - agent-base: 6.0.2 - debug: 4.4.3(supports-color@5.5.0) + agent-base: 6.0.2(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) http-proxy-agent: 4.0.1 - https-proxy-agent: 5.0.1 + https-proxy-agent: 5.0.1(supports-color@8.1.1) lru-cache: 5.1.1 pac-proxy-agent: 5.0.0 proxy-from-env: 1.1.0 @@ -54362,7 +54541,7 @@ snapshots: proxy-agent@6.3.1: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.6 lru-cache: 7.18.3 @@ -54423,7 +54602,7 @@ snapshots: puppeteer-core@2.1.1(bufferutil@4.0.9)(utf-8-validate@5.0.10): dependencies: '@types/mime-types': 2.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) extract-zip: 1.7.0 https-proxy-agent: 4.0.0 mime: 2.6.0 @@ -54472,6 +54651,8 @@ snapshots: quansync@0.2.11: {} + query-selector-shadow-dom@1.0.1: {} + query-string@7.1.3: dependencies: decode-uri-component: 0.2.2 @@ -55468,7 +55649,7 @@ snapshots: require-in-the-middle@5.2.0: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) module-details-from-path: 1.0.4 resolve: 1.22.11 transitivePeerDependencies: @@ -55476,7 +55657,7 @@ snapshots: require-in-the-middle@7.5.2: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) module-details-from-path: 1.0.4 resolve: 1.22.11 transitivePeerDependencies: @@ -55772,7 +55953,7 @@ snapshots: rollup-plugin-esbuild@4.10.3(esbuild@0.27.1)(rollup@2.79.2): dependencies: '@rollup/pluginutils': 4.2.1 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) es-module-lexer: 0.9.3 esbuild: 0.27.1 joycon: 3.1.1 @@ -55784,7 +55965,7 @@ snapshots: rollup-plugin-esbuild@4.10.3(esbuild@0.27.2)(rollup@2.79.2): dependencies: '@rollup/pluginutils': 4.2.1 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) es-module-lexer: 0.9.3 esbuild: 0.27.2 joycon: 3.1.1 @@ -56714,14 +56895,6 @@ snapshots: once: 1.4.0 simple-concat: 1.0.1 - simple-git@3.30.0: - dependencies: - '@kwsites/file-exists': 1.1.1 - '@kwsites/promise-deferred': 1.1.1 - debug: 4.4.3(supports-color@5.5.0) - transitivePeerDependencies: - - supports-color - simple-git@3.30.0(supports-color@8.1.1): dependencies: '@kwsites/file-exists': 1.1.1(supports-color@8.1.1) @@ -56866,8 +57039,8 @@ snapshots: socks-proxy-agent@5.0.1: dependencies: - agent-base: 6.0.2 - debug: 4.4.3(supports-color@5.5.0) + agent-base: 6.0.2(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) socks: 2.8.7 transitivePeerDependencies: - supports-color @@ -56875,7 +57048,7 @@ snapshots: socks-proxy-agent@8.0.5: dependencies: agent-base: 7.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) socks: 2.8.7 transitivePeerDependencies: - supports-color @@ -56969,7 +57142,7 @@ snapshots: spdy-transport@3.0.0: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) detect-node: 2.1.0 hpack.js: 2.1.6 obuf: 1.1.2 @@ -56980,7 +57153,7 @@ snapshots: spdy@4.0.2: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) handle-thing: 2.0.1 http-deceiver: 1.2.7 select-hose: 2.0.0 @@ -57405,7 +57578,7 @@ snapshots: superagent-proxy@3.0.0(superagent@5.3.1): dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) proxy-agent: 5.0.0 superagent: 5.3.1 transitivePeerDependencies: @@ -57415,7 +57588,7 @@ snapshots: dependencies: component-emitter: 1.3.1 cookiejar: 2.1.4 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) fast-safe-stringify: 2.1.1 form-data: 3.0.4 formidable: 1.2.6 @@ -57634,7 +57807,7 @@ snapshots: teeny-request@9.0.0: dependencies: http-proxy-agent: 5.0.0 - https-proxy-agent: 5.0.1 + https-proxy-agent: 5.0.1(supports-color@8.1.1) node-fetch: 2.7.0 stream-events: 1.0.5 uuid: 9.0.1 @@ -57721,7 +57894,7 @@ snapshots: archiver: 7.0.1 async-lock: 1.4.1 byline: 5.0.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) docker-compose: 0.24.8 dockerode: 4.0.9 get-port: 7.1.0 @@ -57741,7 +57914,7 @@ snapshots: dependencies: '@types/dockerode': 2.5.34 byline: 5.0.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) docker-compose: 0.23.19 dockerode: 3.3.5 get-port: 5.1.1 @@ -57761,7 +57934,7 @@ snapshots: archiver: 5.3.2 async-lock: 1.4.1 byline: 5.0.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) docker-compose: 0.24.8 dockerode: 3.3.5 get-port: 5.1.1 @@ -58049,6 +58222,27 @@ snapshots: esbuild: 0.15.18 jest-util: 29.7.0 + ts-jest@29.4.5(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(esbuild@0.15.18)(jest-util@29.7.0)(jest@29.7.0(@types/node@17.0.45)(ts-node@10.9.2(@swc/core@1.15.2(@swc/helpers@0.5.17))(@types/node@18.19.130)(typescript@5.6.2)))(typescript@5.6.2): + dependencies: + bs-logger: 0.2.6 + fast-json-stable-stringify: 2.1.0 + handlebars: 4.7.8 + jest: 29.7.0(@types/node@17.0.45)(ts-node@10.9.2(@swc/core@1.15.2(@swc/helpers@0.5.17))(@types/node@18.19.130)(typescript@5.6.2)) + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.7.3 + type-fest: 4.41.0 + typescript: 5.6.2 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.28.5 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.28.5) + esbuild: 0.15.18 + jest-util: 29.7.0 + ts-jest@29.4.5(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(esbuild@0.15.18)(jest-util@29.7.0)(jest@29.7.0(@types/node@18.19.130)(ts-node@10.9.2(@swc/core@1.15.2(@swc/helpers@0.5.17))(@types/node@18.19.130)(typescript@5.6.2)))(typescript@5.6.2): dependencies: bs-logger: 0.2.6 @@ -58277,7 +58471,7 @@ snapshots: dependencies: axios: 1.13.2 dayjs: 1.11.19 - https-proxy-agent: 5.0.1 + https-proxy-agent: 5.0.1(supports-color@8.1.1) jsonwebtoken: 9.0.2 qs: 6.14.0 scmp: 2.1.0 @@ -58980,7 +59174,7 @@ snapshots: velocityjs@2.1.5: dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -59067,7 +59261,7 @@ snapshots: vite-node@1.6.1(@types/node@18.19.130)(less@4.4.2)(lightningcss@1.30.2)(sass@1.94.2)(terser@5.44.1): dependencies: cac: 6.7.14 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) pathe: 1.1.2 picocolors: 1.1.1 vite: 5.4.21(@types/node@18.19.130)(less@4.4.2)(lightningcss@1.30.2)(sass@1.94.2)(terser@5.44.1) @@ -59106,7 +59300,7 @@ snapshots: vite-tsconfig-paths@4.2.3(typescript@5.6.2)(vite@4.3.8(@types/node@12.20.55)(less@4.4.2)(sass@1.94.2)(terser@5.44.1)): dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) globrex: 0.1.2 tsconfck: 2.1.2(typescript@5.6.2) optionalDependencies: @@ -59117,7 +59311,7 @@ snapshots: vite-tsconfig-paths@4.2.3(typescript@5.6.2)(vite@4.5.14(@types/node@12.20.55)(less@4.4.2)(lightningcss@1.30.2)(sass@1.94.2)(terser@5.44.1)): dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) globrex: 0.1.2 tsconfck: 2.1.2(typescript@5.6.2) optionalDependencies: @@ -59128,7 +59322,7 @@ snapshots: vite-tsconfig-paths@4.3.2(typescript@5.6.2)(vite@6.4.1(@types/node@18.19.130)(jiti@2.6.1)(less@4.4.2)(lightningcss@1.30.2)(sass@1.94.2)(terser@5.44.1)(tsx@4.20.6)(yaml@2.8.1)): dependencies: - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.6.2) optionalDependencies: @@ -59269,7 +59463,7 @@ snapshots: '@vitest/utils': 1.6.1 acorn-walk: 8.3.4 chai: 4.5.0 - debug: 4.4.3(supports-color@5.5.0) + debug: 4.4.3(supports-color@8.1.1) execa: 8.0.1 local-pkg: 0.5.1 magic-string: 0.30.21 @@ -59916,7 +60110,7 @@ snapshots: bignumber.js: 9.3.1 bip32: 2.0.6 bip39: 3.1.0 - https-proxy-agent: 5.0.1 + https-proxy-agent: 5.0.1(supports-color@8.1.1) lodash: 4.17.21 ripple-address-codec: 4.3.1 ripple-binary-codec: 1.11.0