Files
AFFiNE-Mirror/packages/frontend/track/src/state.ts
T
DarkSky 9c55edeb62 feat(server): adapt gemini3.1 preview (#14583)
#### 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 -->
2026-03-08 00:53:16 +08:00

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;
}
}