mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-10-16 06:25:42 -04:00
Migrate the entire monorepo from Biome 2.4.7 to oxlint 1.56.0 (linter) and oxfmt 0.41.0 (formatter) for faster lint/format and broader rule coverage. - Add `.oxlintrc.json` with React, TypeScript, unicorn, import plugins and correctness/suspicious categories - Add `.oxfmtrc.json` with 2-space indent, import sorting, and Tailwind class sorting (all 30+ custom className attributes migrated) - Add `docs/.oxlintrc.json` and `docs/.oxfmtrc.json` with Next.js plugin - Update all 12 workspace package.json scripts: `oxlint`, `oxfmt`, `oxfmt --check` - Add `format:check` turbo task and CI step - Update VS Code settings/extensions to use `oxc.oxc-vscode` - Update CI path triggers from `biome.json` to new config files - Remove all `biome-ignore` comments and fix shadowed variables - Delete `biome.json` and `docs/biome.json` - Reformat entire codebase with oxfmt Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
91 lines
2.5 KiB
TypeScript
91 lines
2.5 KiB
TypeScript
import { db } from "@sofa/db/client";
|
|
import { count } from "@sofa/db/helpers";
|
|
import { titles } from "@sofa/db/schema";
|
|
import { createLogger } from "@sofa/logger";
|
|
|
|
import { imageCacheEnabled } from "./image-cache";
|
|
import { getInstanceId, getSetting, getUserCount, setSetting } from "./settings";
|
|
|
|
const APP_VERSION = process.env.APP_VERSION || "0.0.0";
|
|
const PUBLIC_API_URL = process.env.PUBLIC_API_URL || "https://public-api.sofa.watch";
|
|
const REPORT_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
|
|
const log = createLogger("telemetry");
|
|
|
|
export function isTelemetryEnabled(): boolean {
|
|
return getSetting("telemetryEnabled") === "true";
|
|
}
|
|
|
|
function bucketUsers(n: number): string {
|
|
if (n <= 1) return "1";
|
|
if (n <= 5) return "2-5";
|
|
if (n <= 10) return "6-10";
|
|
if (n <= 25) return "11-25";
|
|
return "26+";
|
|
}
|
|
|
|
function bucketTitles(n: number): string {
|
|
if (n === 0) return "0";
|
|
if (n <= 50) return "1-50";
|
|
if (n <= 200) return "51-200";
|
|
if (n <= 500) return "201-500";
|
|
return "501+";
|
|
}
|
|
|
|
function getTitleCount(): number {
|
|
const result = db.select({ count: count() }).from(titles).get();
|
|
return result?.count ?? 0;
|
|
}
|
|
|
|
export async function performTelemetryReport(): Promise<void> {
|
|
if (!isTelemetryEnabled()) {
|
|
log.debug("Telemetry disabled, skipping");
|
|
return;
|
|
}
|
|
|
|
// Respect report interval
|
|
const lastReported = getSetting("telemetryLastReportedAt");
|
|
if (lastReported) {
|
|
const elapsed = Date.now() - new Date(lastReported).getTime();
|
|
if (elapsed < REPORT_INTERVAL_MS) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
try {
|
|
const body = {
|
|
instanceId: getInstanceId(),
|
|
version: APP_VERSION,
|
|
arch: `${process.platform}-${process.arch}`,
|
|
users: bucketUsers(getUserCount()),
|
|
titles: bucketTitles(getTitleCount()),
|
|
features: {
|
|
imageCache: imageCacheEnabled(),
|
|
oidc: !!(
|
|
process.env.OIDC_CLIENT_ID &&
|
|
process.env.OIDC_CLIENT_SECRET &&
|
|
process.env.OIDC_ISSUER_URL
|
|
),
|
|
scheduledBackups: getSetting("scheduledBackups") === "true",
|
|
},
|
|
};
|
|
|
|
const res = await fetch(`${PUBLIC_API_URL}/v1/telemetry`, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
"User-Agent": "sofa-telemetry",
|
|
},
|
|
body: JSON.stringify(body),
|
|
signal: AbortSignal.timeout(10_000),
|
|
});
|
|
|
|
if (!res.ok) throw new Error(`Public API ${res.status}`);
|
|
|
|
setSetting("telemetryLastReportedAt", new Date().toISOString());
|
|
log.info("Telemetry report sent");
|
|
} catch (err) {
|
|
log.warn("Telemetry report failed:", err);
|
|
}
|
|
}
|