Add player bug reports and profile identity features

This commit is contained in:
2026-10-08 18:27:20 +05:00
parent 36e8d11eb4
commit 0b08672f4a
51 changed files with 3938 additions and 45 deletions

123
lib/support-sync.ts Normal file
View File

@@ -0,0 +1,123 @@
import "server-only";
import { randomUUID } from "node:crypto";
import { after } from "next/server";
import { admin, required } from "./supabase";
import { LinearSupportClient } from "./linear-support-client";
export function supportReady() {
return !!(
process.env.LINEAR_API_KEY &&
process.env.LINEAR_TEAM_ID &&
process.env.LINEAR_WEBHOOK_SECRET
);
}
export async function syncBugReport(id: string) {
if (!supportReady()) return;
const db = admin(),
worker = randomUUID();
if (
!required(
await db.rpc("claim_bug_sync", { p_report: id, p_worker: worker }),
)
)
return;
try {
const linear = new LinearSupportClient(
process.env.LINEAR_API_KEY!,
process.env.LINEAR_TEAM_ID!,
process.env.LINEAR_PROJECT_ID,
);
const report = required(
await db.from("bug_reports").select("*").eq("id", id).single(),
);
if (!report.issue_synced) {
if (report.screenshot_path && !report.linear_asset_url) {
const image = required(
await db.storage
.from("minegeo-support")
.download(report.screenshot_path),
);
report.linear_asset_url = await linear.upload(
new Uint8Array(await image.arrayBuffer()),
`bug-${id}.webp`,
);
required(
await db
.from("bug_reports")
.update({ linear_asset_url: report.linear_asset_url })
.eq("id", id)
.eq("lease_owner", worker)
.select("id")
.single(),
);
}
const issue = await linear.createIssue(report);
required(
await db
.from("bug_reports")
.update({
issue_synced: true,
linear_identifier: issue.identifier,
state: "open",
})
.eq("id", id)
.eq("lease_owner", worker)
.select("id")
.single(),
);
}
required(
await db
.from("bug_report_messages")
.update({ delivered: true })
.eq("id", id)
.select("id"),
);
const messages = required(
await db
.from("bug_report_messages")
.select("*")
.eq("report_id", id)
.eq("kind", "user")
.eq("delivered", false)
.neq("id", id)
.order("created_at")
.limit(50),
);
for (const message of messages) {
await linear.comment(message.id, id, message.author_name, message.body);
required(
await db
.from("bug_report_messages")
.update({ delivered: true })
.eq("id", message.id)
.select("id"),
);
}
required(
await db
.from("bug_reports")
.update({ lease_owner: null, lease_until: null, retry_at: null })
.eq("id", id)
.eq("lease_owner", worker)
.select("id"),
);
} catch {
console.error("Bug report delivery paused; the saved report will retry.");
required(
await db
.from("bug_reports")
.update({
lease_owner: null,
lease_until: null,
retry_at: new Date(Date.now() + 60_000).toISOString(),
})
.eq("id", id)
.eq("lease_owner", worker)
.select("id"),
);
}
}
export function syncBugAfterResponse(id: string) {
after(() => syncBugReport(id));
}