fix: adapt code to modernized libraries
- Migrate validation.ts from class-transformer/class-validator to Zod - Apply Biome auto-fixes (import sorting, nodejs protocol) - Fix duplicate type identifier in validation.ts Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
203aa9a589
commit
29fcde69e4
+17
-6
@@ -1,13 +1,22 @@
|
||||
import "dotenv/config";
|
||||
import Database from "better-sqlite3";
|
||||
import { drizzle as drizzleSqlite } from "drizzle-orm/better-sqlite3";
|
||||
import { migrate as migrateSqlite } from "drizzle-orm/better-sqlite3/migrator";
|
||||
import { migrate } from "drizzle-orm/node-postgres/migrator";
|
||||
import { migrate as migratePostgres } from "drizzle-orm/node-postgres/migrator";
|
||||
import { config } from "../config";
|
||||
import { createChildLogger } from "../logger";
|
||||
import { initializeDatabase } from "./drizzle";
|
||||
|
||||
const logger = createChildLogger("migrate");
|
||||
|
||||
export async function initializeMigrationSqliteDatabase(
|
||||
path = ".muxer-queue.db",
|
||||
) {
|
||||
const sqlite = new Database(path);
|
||||
sqlite.pragma("journal_mode = WAL");
|
||||
return { sqlite, db: drizzleSqlite(sqlite) };
|
||||
}
|
||||
|
||||
export async function runMigrations(): Promise<void> {
|
||||
try {
|
||||
logger.info("Starting database migrations");
|
||||
@@ -15,14 +24,16 @@ export async function runMigrations(): Promise<void> {
|
||||
if (config.DATABASE_TYPE === "postgres") {
|
||||
logger.info("Running PostgreSQL migrations");
|
||||
const db = await initializeDatabase();
|
||||
await migrate(db as any, { migrationsFolder: "./drizzle/migrations" });
|
||||
await migratePostgres(db as any, {
|
||||
migrationsFolder: "./drizzle/migrations",
|
||||
});
|
||||
logger.info("PostgreSQL migrations completed successfully");
|
||||
} else {
|
||||
logger.info("Running SQLite migrations");
|
||||
const sqlite = new Database(".muxer-queue.db");
|
||||
sqlite.pragma("journal_mode = WAL");
|
||||
const db = require("drizzle-orm/better-sqlite3").drizzle(sqlite);
|
||||
const { sqlite, db } = await initializeMigrationSqliteDatabase();
|
||||
migrateSqlite(db, { migrationsFolder: "./drizzle/migrations" });
|
||||
// Ensure the SQLite connection is closed after migrations
|
||||
sqlite.close();
|
||||
logger.info("SQLite migrations completed successfully");
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -35,7 +46,7 @@ export async function runMigrations(): Promise<void> {
|
||||
}
|
||||
|
||||
// Run migrations if called directly
|
||||
if (require.main === module) {
|
||||
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||
runMigrations()
|
||||
.then(() => {
|
||||
logger.info("Migrations completed");
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ for (let i = 0; i < 256; i++) {
|
||||
CRC_TABLE[i] = r >>> 0;
|
||||
}
|
||||
|
||||
const Module = require("module");
|
||||
const Module = require("node:module");
|
||||
const originalRequire = Module.prototype.require;
|
||||
Module.prototype.require = function (id: string) {
|
||||
if (id === "node-crc") {
|
||||
|
||||
@@ -34,9 +34,9 @@ export async function captureMessage(
|
||||
guild_id: message.guildId!,
|
||||
channel_id: location.channelId,
|
||||
thread_id: location.threadId,
|
||||
user_id: message.author!.id,
|
||||
username: message.author!.username,
|
||||
avatar_url: message.author!.avatarURL() || null,
|
||||
user_id: message.author?.id,
|
||||
username: message.author?.username,
|
||||
avatar_url: message.author?.avatarURL() || null,
|
||||
content: getDisplayContent(message),
|
||||
edited_content: null,
|
||||
created_at: message.createdTimestamp,
|
||||
@@ -67,7 +67,7 @@ export async function captureMessage(
|
||||
guild_id: message.guildId!,
|
||||
channel_id: location.channelId,
|
||||
thread_id: location.threadId,
|
||||
user_id: message.author!.id,
|
||||
user_id: message.author?.id,
|
||||
filename: attachment.name || "unknown",
|
||||
size: attachment.size,
|
||||
type: attachment.contentType || "application/octet-stream",
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import ffmpeg from "fluent-ffmpeg";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
const recordingsDir = process.env.RECORDINGS_DIR ?? "./recordings";
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import ffmpeg from "fluent-ffmpeg";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
const recordingsDir = process.env.RECORDINGS_DIR ?? "./recordings";
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { Transform, TransformCallback } from "stream";
|
||||
import { Transform, TransformCallback } from "node:stream";
|
||||
|
||||
/**
|
||||
* Transform stream untuk memfilter audio packets yang terlalu kecil
|
||||
|
||||
+1
-1
@@ -1,3 +1,4 @@
|
||||
import { Readable } from "node:stream";
|
||||
import {
|
||||
AudioPlayer,
|
||||
AudioPlayerStatus,
|
||||
@@ -6,7 +7,6 @@ import {
|
||||
StreamType,
|
||||
VoiceConnection,
|
||||
} from "@discordjs/voice";
|
||||
import { Readable } from "stream";
|
||||
|
||||
export class DiscordPlayer {
|
||||
private player: AudioPlayer;
|
||||
|
||||
+13
-29
@@ -1,38 +1,22 @@
|
||||
import { plainToClass } from "class-transformer";
|
||||
import { IsBoolean, IsString, validate } from "class-validator";
|
||||
import { z } from "zod";
|
||||
|
||||
export class UserStateUpdate {
|
||||
@IsString()
|
||||
userId!: string;
|
||||
export const userStateUpdateSchema = z.object({
|
||||
userId: z.string(),
|
||||
username: z.string(),
|
||||
avatar: z.string(),
|
||||
speaking: z.boolean(),
|
||||
});
|
||||
|
||||
@IsString()
|
||||
username!: string;
|
||||
export type UserStateUpdate = z.infer<typeof userStateUpdateSchema>;
|
||||
|
||||
@IsString()
|
||||
avatar!: string;
|
||||
|
||||
@IsBoolean()
|
||||
speaking!: boolean;
|
||||
}
|
||||
|
||||
export class AudioMessage {
|
||||
data!: Buffer;
|
||||
userId!: string;
|
||||
export interface AudioMessage {
|
||||
data: Buffer;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export async function validateUserStateUpdate(
|
||||
data: unknown,
|
||||
): Promise<UserStateUpdate | null> {
|
||||
if (typeof data !== "object" || data === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const obj = plainToClass(UserStateUpdate, data);
|
||||
const errors = await validate(obj);
|
||||
|
||||
if (errors.length > 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return obj;
|
||||
const result = userStateUpdateSchema.safeParse(data);
|
||||
return result.success ? result.data : null;
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
import fs from "node:fs";
|
||||
import http from "node:http";
|
||||
import path from "node:path";
|
||||
import type { Client } from "discord.js-selfbot-v13";
|
||||
import express from "express";
|
||||
import fs from "fs";
|
||||
import helmet from "helmet";
|
||||
import http from "http";
|
||||
import path from "path";
|
||||
import * as prism from "prism-media";
|
||||
import { WebSocketServer } from "ws";
|
||||
import { AppError } from "./errors";
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { expect, test } from "vitest";
|
||||
import { UserStateUpdate, validateUserStateUpdate } from "../src/validation";
|
||||
|
||||
test("valid object returns typed object", async () => {
|
||||
const input = {
|
||||
userId: "123",
|
||||
username: "testuser",
|
||||
avatar: "avatar.png",
|
||||
speaking: true,
|
||||
};
|
||||
const result = await validateUserStateUpdate(input);
|
||||
expect(result).toEqual(input as UserStateUpdate);
|
||||
});
|
||||
|
||||
test("non-object input returns null", async () => {
|
||||
// @ts-expect-error testing invalid input
|
||||
const result = await validateUserStateUpdate("not an object");
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
|
||||
test("invalid field types return null", async () => {
|
||||
const input = {
|
||||
userId: "123",
|
||||
username: "testuser",
|
||||
avatar: "avatar.png",
|
||||
speaking: "true", // invalid type
|
||||
};
|
||||
const result = await validateUserStateUpdate(input as unknown);
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
Reference in New Issue
Block a user