mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-14 08:36:22 +08:00
9c55edeb62
#### PR Dependency Tree * **PR #14583** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added Gemini 3.1 Pro Preview support (text, image, audio) and new GPT‑5 variants as defaults; centralized persistent telemetry state for more reliable client identity. * **UX** * Improved model submenu placement in chat preferences. * More robust mindmap parsing, preview, regeneration and replace behavior. * **Chores** * Bumped AI SDK and related dependencies. * **Tests** * Expanded/updated tests and increased timeouts for flaky flows. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
100 lines
2.4 KiB
TypeScript
100 lines
2.4 KiB
TypeScript
import { nanoid } from 'nanoid';
|
|
|
|
export type TrackProperties = Record<string, unknown> | undefined;
|
|
|
|
export type Middleware = (
|
|
name: string,
|
|
properties?: TrackProperties
|
|
) => Record<string, unknown>;
|
|
|
|
type TrackerState = {
|
|
enabled: boolean;
|
|
clientStorage: Storage | null;
|
|
clientId: string;
|
|
pendingFirstVisit: boolean;
|
|
sessionId: number;
|
|
sessionNumber: number;
|
|
lastActivityMs: number;
|
|
sessionStartSent: boolean;
|
|
engagementTrackingEnabled: boolean;
|
|
visibleSinceMs: number | null;
|
|
pendingEngagementMs: number;
|
|
visibilityChangeHandler: (() => void) | null;
|
|
pageHideHandler: (() => void) | null;
|
|
userId: string | undefined;
|
|
userProperties: Record<string, unknown>;
|
|
middlewares: Set<Middleware>;
|
|
};
|
|
|
|
const CLIENT_ID_KEY = 'affine_telemetry_client_id';
|
|
|
|
export let trackerState = createTrackerState();
|
|
|
|
export function resetTrackerState() {
|
|
cleanupTrackerState(trackerState);
|
|
trackerState = createTrackerState();
|
|
}
|
|
|
|
function createTrackerState(): TrackerState {
|
|
const clientStorage = localStorageSafe();
|
|
const hasClientId = !!clientStorage?.getItem(CLIENT_ID_KEY);
|
|
|
|
return {
|
|
enabled: true,
|
|
clientStorage,
|
|
clientId: readPersistentId(CLIENT_ID_KEY, clientStorage),
|
|
pendingFirstVisit: !hasClientId,
|
|
sessionId: 0,
|
|
sessionNumber: 0,
|
|
lastActivityMs: 0,
|
|
sessionStartSent: false,
|
|
engagementTrackingEnabled: false,
|
|
visibleSinceMs: null,
|
|
pendingEngagementMs: 0,
|
|
visibilityChangeHandler: null,
|
|
pageHideHandler: null,
|
|
userId: undefined,
|
|
userProperties: {},
|
|
middlewares: new Set<Middleware>(),
|
|
};
|
|
}
|
|
|
|
function cleanupTrackerState(state: TrackerState) {
|
|
if (state.visibilityChangeHandler && typeof document !== 'undefined') {
|
|
document.removeEventListener(
|
|
'visibilitychange',
|
|
state.visibilityChangeHandler
|
|
);
|
|
}
|
|
if (state.pageHideHandler && typeof window !== 'undefined') {
|
|
window.removeEventListener('pagehide', state.pageHideHandler);
|
|
}
|
|
}
|
|
|
|
function readPersistentId(key: string, storage: Storage | null, renew = false) {
|
|
if (!storage) {
|
|
return nanoid();
|
|
}
|
|
if (!renew) {
|
|
const existing = storage.getItem(key);
|
|
if (existing) {
|
|
return existing;
|
|
}
|
|
}
|
|
const id = nanoid();
|
|
try {
|
|
storage.setItem(key, id);
|
|
} catch {
|
|
return id;
|
|
}
|
|
return id;
|
|
}
|
|
|
|
function localStorageSafe(): Storage | null {
|
|
try {
|
|
return typeof localStorage === 'undefined' ? null : localStorage;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|