clear the remaining type errors

- DiscordAccount seeded DiscordStatus without its two nullable fields.
- bug-report typed reporter.name as string, but users.name is nullable; and the
  Discord upload wrapped a Buffer directly in a Blob.
- Lucide icons take no `title` prop, so the sync spinner's tooltip moved to a
  wrapping span.
- DesktopView cast its dynamic import to a type that included `| null`.
- dock PUT cast the request body straight to string[]; it now rejects anything
  that is not an array of strings instead of writing it to the database.
- buildZodSchema assembles a mutable record, since z.ZodRawShape is readonly in
  zod v4.
- The dev-server proxy forwards Bun's `string | Buffer` frames through a helper
  that satisfies WebSocket.send without copying.

bunx tsgo is now clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
brunorezio
2026-07-25 23:30:20 +01:00
co-authored by Claude Opus 5
parent 0041fcbd47
commit 0d67e2af26
7 changed files with 197 additions and 79 deletions
+18 -5
View File
@@ -51,8 +51,13 @@ bugReportRouter.post('/', async (ctx) => {
type BugReport = {
description: string;
context: { url?: string; userAgent?: string; viewport?: { width: number; height: number }; apiError?: { status: number; message: string } | null } | null;
reporter: { id: number; email: string; name: string };
context: {
url?: string;
userAgent?: string;
viewport?: { width: number; height: number };
apiError?: { status: number; message: string } | null;
} | null;
reporter: { id: number; email: string; name: string | null };
createdAt: string;
};
@@ -64,21 +69,29 @@ async function sendToDiscord(report: BugReport, screenshot: Buffer | null) {
fields: [
{ name: 'Reporter', value: `${report.reporter.name} (${report.reporter.email})`, inline: true },
{ name: 'URL', value: report.context?.url ?? 'N/A', inline: false },
{ name: 'Viewport', value: report.context?.viewport ? `${report.context.viewport.width}x${report.context.viewport.height}` : 'N/A', inline: true },
{
name: 'Viewport',
value: report.context?.viewport ? `${report.context.viewport.width}x${report.context.viewport.height}` : 'N/A',
inline: true,
},
{ name: 'Browser', value: shortenUA(report.context?.userAgent), inline: true },
],
timestamp: report.createdAt,
};
if (report.context?.apiError) {
embed.fields.push({ name: 'Last API Error', value: `${report.context.apiError.status}: ${report.context.apiError.message}`, inline: false });
embed.fields.push({
name: 'Last API Error',
value: `${report.context.apiError.status}: ${report.context.apiError.message}`,
inline: false,
});
}
const form = new FormData();
form.append('payload_json', JSON.stringify({ embeds: [embed] }));
if (screenshot) {
form.append('files[0]', new Blob([screenshot], { type: 'image/png' }), 'screenshot.png');
form.append('files[0]', new Blob([new Uint8Array(screenshot)], { type: 'image/png' }), 'screenshot.png');
}
const res = await fetch(DISCORD_WEBHOOK_URL!, { method: 'POST', body: form });
+6 -1
View File
@@ -1,5 +1,6 @@
import { createRouter } from '../../create-router';
import { getDockPaths, setDockPaths } from 'officerdb';
import * as errors from '@@/custom-errors';
export const dockRouter = createRouter();
@@ -13,7 +14,11 @@ dockRouter.get('/', async (ctx) => {
// PUT / — full replacement of dock paths array
dockRouter.put('/', async (ctx) => {
const userId = ctx.get('user').id;
const paths = ctx.get('body') as string[];
const body = ctx.get('body') as unknown;
if (!Array.isArray(body) || body.some((p) => typeof p !== 'string')) {
throw errors.BAD_REQUEST('Expected an array of dock paths');
}
const paths = body as string[];
await setDockPaths(userId, paths);
return ctx.json(paths);
});