47 lines
1.7 KiB
TypeScript
47 lines
1.7 KiB
TypeScript
import { AppMetaDb } from './database';
|
|
import { getConfiguredBackendRootUrl } from '../utils/backendUrl';
|
|
import { getAppInfoHeaders } from '../utils/appInfoHeaders';
|
|
|
|
const INSTALL_ID_KEY = 'install_ping_id_v1';
|
|
const INSTALL_REPORTED_KEY = 'install_ping_reported_v1';
|
|
const REQUEST_TIMEOUT_MS = 10000;
|
|
|
|
const getOrCreateInstallId = (): string => {
|
|
const existing = AppMetaDb.get(INSTALL_ID_KEY);
|
|
if (existing) return existing;
|
|
const installId = `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}-${Math.random().toString(36).slice(2, 12)}`;
|
|
AppMetaDb.set(INSTALL_ID_KEY, installId);
|
|
return installId;
|
|
};
|
|
|
|
// Reports this install to the backend exactly once (fire-and-forget). The
|
|
// backend dedupes by install id, so retrying after a failed attempt is safe.
|
|
export const reportInstallOnce = async (): Promise<void> => {
|
|
try {
|
|
if (AppMetaDb.get(INSTALL_REPORTED_KEY) === '1') return;
|
|
const backendBaseUrl = getConfiguredBackendRootUrl();
|
|
if (!backendBaseUrl) return;
|
|
|
|
const controller = new AbortController();
|
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
try {
|
|
const response = await fetch(`${backendBaseUrl.replace(/\/$/, '')}/v1/app-install`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...getAppInfoHeaders(),
|
|
},
|
|
body: JSON.stringify({ installId: getOrCreateInstallId() }),
|
|
signal: controller.signal,
|
|
});
|
|
if (response.ok) {
|
|
AppMetaDb.set(INSTALL_REPORTED_KEY, '1');
|
|
}
|
|
} finally {
|
|
clearTimeout(timeout);
|
|
}
|
|
} catch {
|
|
// Offline or backend unreachable — retried on next app start.
|
|
}
|
|
};
|