Add player bug reports and profile identity features
This commit is contained in:
123
lib/support-sync.ts
Normal file
123
lib/support-sync.ts
Normal 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));
|
||||
}
|
||||
Reference in New Issue
Block a user