Add account based multiplayer hosting and bug report retention
This commit is contained in:
@@ -3,7 +3,14 @@ import {
|
||||
type BugReportRecord,
|
||||
} from "../shared/bug-reports";
|
||||
|
||||
type Issue = { id: string; identifier: string; team: { id: string } };
|
||||
type Issue = {
|
||||
id: string;
|
||||
identifier: string;
|
||||
team: { id: string };
|
||||
state?: { id: string; name: string; type: string };
|
||||
completedAt?: string | null;
|
||||
};
|
||||
export class LinearPermissionError extends Error {}
|
||||
export class LinearSupportClient {
|
||||
constructor(
|
||||
private key: string,
|
||||
@@ -34,13 +41,26 @@ export class LinearSupportClient {
|
||||
)
|
||||
)
|
||||
return null;
|
||||
if (
|
||||
response.status === 401 ||
|
||||
response.status === 403 ||
|
||||
result.errors?.some(
|
||||
(error: { message?: string; extensions?: { code?: string } }) =>
|
||||
/forbidden|permission|authentication|unauthorized/i.test(
|
||||
`${error.extensions?.code ?? ""} ${error.message ?? ""}`,
|
||||
),
|
||||
)
|
||||
)
|
||||
throw new LinearPermissionError(
|
||||
"Support delivery is temporarily unavailable. Check Linear Write permission.",
|
||||
);
|
||||
if (!response.ok || result.errors?.length || !result.data)
|
||||
throw new Error("Support delivery is temporarily unavailable");
|
||||
return result.data;
|
||||
}
|
||||
async issue(id: string): Promise<Issue | null> {
|
||||
const data = await this.graphql<{ issue: Issue }>(
|
||||
"query SupportIssue($id: String!) { issue(id: $id) { id identifier team { id } } }",
|
||||
"query SupportIssue($id: String!) { issue(id: $id) { id identifier team { id } state { id name type } completedAt } }",
|
||||
{ id },
|
||||
true,
|
||||
);
|
||||
@@ -49,6 +69,47 @@ export class LinearSupportClient {
|
||||
throw new Error("Support issue team mismatch");
|
||||
return issue;
|
||||
}
|
||||
async done(id: string) {
|
||||
const issue = await this.issue(id);
|
||||
if (!issue) throw new Error("Support issue was not found");
|
||||
if (
|
||||
issue.state?.type === "completed" &&
|
||||
issue.state.name.toLowerCase() === "done"
|
||||
)
|
||||
return;
|
||||
const data = await this.graphql<{
|
||||
team: { states: { nodes: { id: string; name: string; type: string }[] } };
|
||||
}>(
|
||||
"query SupportDoneState($team: String!) { team(id:$team) { states { nodes { id name type } } } }",
|
||||
{ team: this.team },
|
||||
);
|
||||
const state = data?.team.states.nodes.find(
|
||||
(s) => s.type === "completed" && s.name.toLowerCase() === "done",
|
||||
);
|
||||
if (!state)
|
||||
throw new Error("The support team needs a Done workflow status");
|
||||
const result = await this.graphql<{
|
||||
issueUpdate: { success: boolean; issue: Issue };
|
||||
}>(
|
||||
"mutation SupportDone($id: String!, $input: IssueUpdateInput!) { issueUpdate(id:$id,input:$input) { success issue { id state { id name type } } } }",
|
||||
{ id, input: { stateId: state.id } },
|
||||
);
|
||||
if (
|
||||
!result?.issueUpdate.success ||
|
||||
result.issueUpdate.issue.id !== id ||
|
||||
result.issueUpdate.issue.state?.id !== state.id
|
||||
)
|
||||
throw new Error("Support issue status was not confirmed");
|
||||
}
|
||||
async remove(id: string) {
|
||||
if (!(await this.issue(id))) return;
|
||||
const result = await this.graphql<{ issueDelete: { success: boolean } }>(
|
||||
"mutation SupportDelete($id: String!) { issueDelete(id:$id) { success } }",
|
||||
{ id },
|
||||
);
|
||||
if (!result?.issueDelete.success)
|
||||
throw new Error("Support issue deletion was not confirmed");
|
||||
}
|
||||
async createIssue(report: BugReportRecord): Promise<Issue> {
|
||||
const existing = await this.issue(report.id);
|
||||
if (existing) return existing;
|
||||
@@ -65,6 +126,7 @@ export class LinearSupportClient {
|
||||
"",
|
||||
"Reply to the player with #player-report-send followed by your message.",
|
||||
"Grant or remove the username reward with #player-report-glow grant or #player-report-glow revoke.",
|
||||
"Close this report with #player-report-close or move the issue to Done. Closed reports and issues are deleted after three days.",
|
||||
`Report reference: ${report.id}`,
|
||||
].join("\n");
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user