init commit
This commit is contained in:
commit
dcf0853e20
54 changed files with 7720 additions and 0 deletions
7
.dockerignore
Normal file
7
.dockerignore
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
dist
|
||||
node_modules
|
||||
.env
|
||||
.git
|
||||
.trash
|
||||
|
||||
packages/db/generated
|
||||
1
.editorconfig
Normal file
1
.editorconfig
Normal file
|
|
@ -0,0 +1 @@
|
|||
tab=4
|
||||
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
node_modules
|
||||
|
||||
.trash
|
||||
|
||||
dist
|
||||
packages/generated
|
||||
|
||||
.env
|
||||
cache
|
||||
1
.node-version
Normal file
1
.node-version
Normal file
|
|
@ -0,0 +1 @@
|
|||
v24.13.0
|
||||
9
Dockerfile
Normal file
9
Dockerfile
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
FROM node:24-slim
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
|
||||
COPY . .
|
||||
RUN npm run init
|
||||
|
||||
CMD [ "node", "dist" ]
|
||||
19
docker-compose.yml
Normal file
19
docker-compose.yml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
services:
|
||||
discord-bot:
|
||||
build: .
|
||||
environment:
|
||||
- DISCORD_TOKEN=MTQ2MDU5NTMyMzczODI2MzU3Mg.Gn2Mn-.dIRJ9MGKRs9mmUkDbDpZ4h_NSjiNVquKk9VPpo
|
||||
- APPLICATION_ID=1460595323738263572
|
||||
- TYPECAST_TOKEN=__pltP9LVqfCqTGAk353JZsEKey49ivoWw799Lp9CM7Ru
|
||||
- DATABASE_URL=postgresql://yaeju:251205Yaeji@localhost:5432/discord_bot?schema=public
|
||||
db:
|
||||
image: postgres:17
|
||||
restart: always
|
||||
environment:
|
||||
POSTGRES_USER: yaejy
|
||||
POSTGRES_PASSWORD: 251205Yaeji
|
||||
POSTGRES_DB: yaejudb
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
33
package.json
Normal file
33
package.json
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"scripts": {
|
||||
"init": "prisma db push && npm run build",
|
||||
"prismabuild": "prisma format && prisma generate",
|
||||
"build": "npm run prismabuild && tsc",
|
||||
"start": "npm run build && node dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@discordjs/opus": "^0.10.0",
|
||||
"@discordjs/voice": "^0.19.0",
|
||||
"@prisma/adapter-pg": "^7.2.0",
|
||||
"@prisma/client": "^7.2.0",
|
||||
"@snazzah/davey": "^0.1.9",
|
||||
"discord.js": "^14.25.1",
|
||||
"dotenv": "^17.2.3",
|
||||
"fastify": "^5.7.1",
|
||||
"ffprobe-static": "^3.1.0",
|
||||
"libsodium-wrappers": "^0.8.0",
|
||||
"node-fetch": "^3.3.2",
|
||||
"opusscript": "^0.0.8",
|
||||
"pg": "^8.17.1",
|
||||
"play-dl": "^1.9.7",
|
||||
"pnpm": "^10.28.0",
|
||||
"prism-media": "^1.3.5",
|
||||
"prisma": "^7.2.0",
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/ffprobe-static": "^2.0.3",
|
||||
"@types/node": "25.0.9",
|
||||
"@types/pg": "^8.16.0"
|
||||
}
|
||||
}
|
||||
7
packages/bot/admin.ts
Normal file
7
packages/bot/admin.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import { setUserCanTypecast } from "./db";
|
||||
|
||||
export const AdminUsers = [ "858173387775148073", "367946917197381644" ];
|
||||
|
||||
AdminUsers.forEach(userid => {
|
||||
setUserCanTypecast(userid, true);
|
||||
});
|
||||
41
packages/bot/command.ts
Normal file
41
packages/bot/command.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import { ChatInputCommandInteraction, SlashCommandBuilder, SlashCommandOptionsOnlyBuilder, SlashCommandSubcommandBuilder } from "discord.js";
|
||||
import { join } from "node:path";
|
||||
import { requireDirectorySync } from "../utils/requireDirectory";
|
||||
import { AdminUsers } from "./admin";
|
||||
|
||||
export type DiscordCommandData = SlashCommandBuilder | SlashCommandOptionsOnlyBuilder | SlashCommandSubcommandBuilder
|
||||
export type DiscordCommandExecute = (interaction: ChatInputCommandInteraction) => Promise<any>
|
||||
|
||||
export interface DiscordCommand {
|
||||
data: DiscordCommandData
|
||||
execute: DiscordCommandExecute
|
||||
}
|
||||
|
||||
export function defineCommand(
|
||||
data: DiscordCommandData,
|
||||
execute: DiscordCommandExecute,
|
||||
isAdminCommand=false,
|
||||
): DiscordCommand {
|
||||
if (isAdminCommand) {
|
||||
return {
|
||||
data: data,
|
||||
execute: async (interaction: ChatInputCommandInteraction): Promise<any> => {
|
||||
if (AdminUsers.includes(interaction.user.id)) {
|
||||
execute(interaction);
|
||||
} else {
|
||||
interaction.reply("당신은 어드민이 아닙니다");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
data: data,
|
||||
execute: execute,
|
||||
}
|
||||
}
|
||||
|
||||
export const commandDirectory = join(__dirname, "commands");
|
||||
export const commandMap = requireDirectorySync<DiscordCommand>(commandDirectory);
|
||||
export const commandExecuteNameHashMap: {
|
||||
[key: string]: DiscordCommandExecute
|
||||
} = Object.fromEntries(commandMap.map(command => [command.data.name, command.execute]));
|
||||
28
packages/bot/commands/getReadChannels.ts
Normal file
28
packages/bot/commands/getReadChannels.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { ChatInputCommandInteraction, MessageFlags, SlashCommandBuilder } from "discord.js";
|
||||
import { defineCommand } from "../command";
|
||||
import { getGuildProfile } from "../db";
|
||||
|
||||
export default defineCommand(
|
||||
new SlashCommandBuilder()
|
||||
.setName("읽는채널")
|
||||
.setDescription("예주가 읽어주는 채널들을 말해줘요"),
|
||||
async (interaction: ChatInputCommandInteraction): Promise<any> => {
|
||||
await interaction.deferReply({
|
||||
flags: [MessageFlags.Ephemeral]
|
||||
});
|
||||
|
||||
const guildId = interaction.guildId;
|
||||
|
||||
if (guildId == null)
|
||||
return await interaction.editReply("알수없는 서버에요!");
|
||||
|
||||
try {
|
||||
const guildProfile = await getGuildProfile(guildId);
|
||||
const readChannel = guildProfile.readChannel;
|
||||
|
||||
await interaction.editReply(readChannel.map(channel => `<#${channel}>`).join("\n") || "아무 채널도 읽지 않아요!");
|
||||
} catch {
|
||||
await interaction.editReply("서버 프로필을 가져오는데 문제가 생겼어요");
|
||||
}
|
||||
}
|
||||
)
|
||||
22
packages/bot/commands/getStatus.ts
Normal file
22
packages/bot/commands/getStatus.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import { AttachmentBuilder, ChatInputCommandInteraction, MessageFlags, SlashCommandBuilder } from "discord.js";
|
||||
import { defineCommand } from "../command";
|
||||
import { OutputHandler } from "../../utils/outputHandler";
|
||||
|
||||
export default defineCommand(
|
||||
new SlashCommandBuilder()
|
||||
.setName("상태")
|
||||
.setDescription("예주의 상태를 확인해요"),
|
||||
async (interaction: ChatInputCommandInteraction): Promise<any> => {
|
||||
if (interaction.guild == null)
|
||||
return interaction.reply("올바르지 않은 서버에요");
|
||||
|
||||
const buffer = Buffer.from(await OutputHandler.getErrorLog(), 'utf-8');
|
||||
const attachment = new AttachmentBuilder(buffer, { name: 'result.txt' });
|
||||
|
||||
await interaction.reply({
|
||||
content: "제 상태에요",
|
||||
files: [attachment]
|
||||
});
|
||||
},
|
||||
true
|
||||
)
|
||||
48
packages/bot/commands/joinVoiceChannel.ts
Normal file
48
packages/bot/commands/joinVoiceChannel.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import { Channel, ChannelType, ChatInputCommandInteraction, GuildMember, MessageFlags, SlashCommandBuilder } from "discord.js";
|
||||
import { defineCommand } from "../command";
|
||||
import { joinVoiceChannel } from "@discordjs/voice";
|
||||
|
||||
export default defineCommand(
|
||||
new SlashCommandBuilder()
|
||||
.setName("등장")
|
||||
.setDescription("예주가 등장해요")
|
||||
.addChannelOption(option =>
|
||||
option
|
||||
.setName("channel")
|
||||
.setDescription("예주가 등장할 채널이에요")
|
||||
.addChannelTypes(ChannelType.GuildVoice)
|
||||
),
|
||||
async (interaction: ChatInputCommandInteraction): Promise<any> => {
|
||||
await interaction.deferReply({
|
||||
flags: [MessageFlags.Ephemeral]
|
||||
});
|
||||
|
||||
const member = interaction.member as GuildMember | null;
|
||||
if (member == null)
|
||||
return;
|
||||
|
||||
if (interaction.guild == null)
|
||||
return interaction.reply({
|
||||
content: "올바르지 않은 서버에요",
|
||||
ephemeral: true,
|
||||
});
|
||||
|
||||
const channel = interaction.options.getChannel("channel") as Channel || member.voice.channel;
|
||||
|
||||
if (channel == null)
|
||||
return interaction.reply({
|
||||
content: "통화방에 들어가거나 채널을 지정해주세요!",
|
||||
ephemeral: true,
|
||||
});
|
||||
|
||||
joinVoiceChannel({
|
||||
channelId: channel.id,
|
||||
guildId: interaction.guild.id,
|
||||
adapterCreator: interaction.guild.voiceAdapterCreator,
|
||||
selfDeaf: false,
|
||||
selfMute: false,
|
||||
});
|
||||
|
||||
await interaction.editReply("등장했어요!");
|
||||
}
|
||||
)
|
||||
25
packages/bot/commands/leaveVoiceChannel.ts
Normal file
25
packages/bot/commands/leaveVoiceChannel.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { ChatInputCommandInteraction, MessageFlags, SlashCommandBuilder } from "discord.js";
|
||||
import { defineCommand, DiscordCommand } from "../command";
|
||||
import { getVoiceConnection } from "@discordjs/voice";
|
||||
|
||||
export default defineCommand(
|
||||
new SlashCommandBuilder()
|
||||
.setName("퇴장")
|
||||
.setDescription("예주가 퇴장해요"),
|
||||
async (interaction: ChatInputCommandInteraction): Promise<any> => {
|
||||
await interaction.deferReply({
|
||||
flags: [MessageFlags.Ephemeral]
|
||||
});
|
||||
|
||||
if (interaction.guild == null)
|
||||
return interaction.editReply("올바르지 않은 서버에요");
|
||||
|
||||
const connection = getVoiceConnection(interaction.guild.id);
|
||||
if (!connection)
|
||||
return interaction.editReply("예주는 통화방에 존제하지 않아요");
|
||||
|
||||
connection.disconnect();
|
||||
|
||||
await interaction.editReply("퇴장했어요!");
|
||||
}
|
||||
)
|
||||
36
packages/bot/commands/playVoice.ts
Normal file
36
packages/bot/commands/playVoice.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import { ChatInputCommandInteraction, MessageFlags, SlashCommandSubcommandBuilder } from "discord.js";
|
||||
import { defineCommand } from "../command";
|
||||
import { playVoice } from "../tts";
|
||||
import { getUserProfile } from "../db";
|
||||
|
||||
export default defineCommand(
|
||||
new SlashCommandSubcommandBuilder()
|
||||
.setName("말")
|
||||
.setDescription("구구가가")
|
||||
.addStringOption(option =>
|
||||
option
|
||||
.setName("content")
|
||||
.setDescription("예주가 말해준데요")
|
||||
.setRequired(true)
|
||||
),
|
||||
async (interaction: ChatInputCommandInteraction): Promise<any> => {
|
||||
await interaction.deferReply({
|
||||
flags: [MessageFlags.Ephemeral]
|
||||
});
|
||||
|
||||
if (interaction.guild == null)
|
||||
return await interaction.editReply("올바르지 않은 서버에요");
|
||||
|
||||
try {
|
||||
await playVoice(
|
||||
interaction.guild,
|
||||
await getUserProfile(interaction.user.id),
|
||||
interaction.options.getString("content") as string
|
||||
);
|
||||
|
||||
await interaction.editReply("말했어요!");
|
||||
} catch {
|
||||
await interaction.editReply("오늘따라 말이 꼬이네요 ㅜ.ㅜ");
|
||||
}
|
||||
}
|
||||
)
|
||||
35
packages/bot/commands/readChannel.ts
Normal file
35
packages/bot/commands/readChannel.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { Channel, ChatInputCommandInteraction, MessageFlags, SlashCommandSubcommandBuilder } from "discord.js";
|
||||
import { defineCommand, DiscordCommand } from "../command";
|
||||
import { insertGuildReadChannel } from "../db";
|
||||
|
||||
export default defineCommand(
|
||||
new SlashCommandSubcommandBuilder()
|
||||
.setName("읽어")
|
||||
.setDescription("예주가 해당 채널을 읽어줘요")
|
||||
.addChannelOption(option =>
|
||||
option
|
||||
.setName("channel")
|
||||
.setDescription("예주가 읽을 채널이에요")
|
||||
.setRequired(true)
|
||||
),
|
||||
async (interaction: ChatInputCommandInteraction): Promise<any> => {
|
||||
await interaction.deferReply({
|
||||
flags: [MessageFlags.Ephemeral]
|
||||
});
|
||||
|
||||
const channel = interaction.options.getChannel("channel") as Channel;
|
||||
const guildId = interaction.guildId;
|
||||
|
||||
if (guildId == null)
|
||||
return await interaction.editReply("알수없는 서버에요!");
|
||||
|
||||
try {
|
||||
await insertGuildReadChannel(guildId, channel.id);
|
||||
} catch {
|
||||
return await interaction.editReply("읽는대 너무 어려워요..");
|
||||
}
|
||||
|
||||
await interaction.editReply("예주가 이제 이 채널을 읽어요!");
|
||||
},
|
||||
true
|
||||
)
|
||||
19
packages/bot/commands/setNya.ts
Normal file
19
packages/bot/commands/setNya.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { ChatInputCommandInteraction, GuildMember, MessageFlags, SlashCommandBuilder } from "discord.js";
|
||||
import { defineCommand } from "../command";
|
||||
import { getUserProfile, setUserNya } from "../db";
|
||||
|
||||
export default defineCommand(
|
||||
new SlashCommandBuilder()
|
||||
.setName("냥")
|
||||
.setDescription("???"),
|
||||
async (interaction: ChatInputCommandInteraction): Promise<any> => {
|
||||
await interaction.deferReply({
|
||||
flags: [MessageFlags.Ephemeral]
|
||||
});
|
||||
|
||||
const profile = await getUserProfile(interaction.user.id);
|
||||
setUserNya(interaction.user.id, !profile.nya);
|
||||
|
||||
await interaction.editReply(profile.nya ? "냐앙..." : "냐앙!!");
|
||||
}
|
||||
)
|
||||
30
packages/bot/commands/setVoice.ts
Normal file
30
packages/bot/commands/setVoice.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { ChatInputCommandInteraction, MessageFlags, SlashCommandSubcommandBuilder } from "discord.js";
|
||||
import { defineCommand } from "../command";
|
||||
import { Voice } from "../../db/generated/prisma/enums";
|
||||
import { setUserVoice } from "../db";
|
||||
|
||||
export default defineCommand(
|
||||
new SlashCommandSubcommandBuilder()
|
||||
.setName("목소리")
|
||||
.setDescription("예주의 목소리를 설정해요")
|
||||
.addStringOption(option =>
|
||||
option
|
||||
.setName("voice")
|
||||
.setDescription("사용할수 있는 목소리들이에요")
|
||||
.setRequired(true)
|
||||
.addChoices(
|
||||
{ name: "TypeCast", value: "TypeCast" },
|
||||
{ name: "Papago", value: "Papago" }
|
||||
)
|
||||
),
|
||||
async (interaction: ChatInputCommandInteraction): Promise<any> => {
|
||||
await interaction.deferReply({
|
||||
flags: [MessageFlags.Ephemeral]
|
||||
});
|
||||
|
||||
const voice = interaction.options.getString("voice") as Voice;
|
||||
setUserVoice(interaction.user.id, voice);
|
||||
|
||||
await interaction.editReply("예주의 목소리를 변경했어요!");
|
||||
}
|
||||
)
|
||||
35
packages/bot/commands/unreadChannel.ts
Normal file
35
packages/bot/commands/unreadChannel.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { Channel, ChatInputCommandInteraction, MessageFlags, SlashCommandSubcommandBuilder } from "discord.js";
|
||||
import { defineCommand, DiscordCommand } from "../command";
|
||||
import { insertGuildReadChannel, removeGuildReadChannel } from "../db";
|
||||
|
||||
export default defineCommand(
|
||||
new SlashCommandSubcommandBuilder()
|
||||
.setName("읽지마")
|
||||
.setDescription("예주가 해당 채널을 더이상 읽지 않아요")
|
||||
.addChannelOption(option =>
|
||||
option
|
||||
.setName("channel")
|
||||
.setDescription("예주가 더이상 읽지 않을 채널이에요")
|
||||
.setRequired(true)
|
||||
),
|
||||
async (interaction: ChatInputCommandInteraction): Promise<any> => {
|
||||
await interaction.deferReply({
|
||||
flags: [MessageFlags.Ephemeral]
|
||||
});
|
||||
|
||||
const channel = interaction.options.getChannel("channel") as Channel;
|
||||
const guildId = interaction.guildId;
|
||||
|
||||
if (guildId == null)
|
||||
return await interaction.editReply("알수없는 서버에요!");
|
||||
|
||||
try {
|
||||
await removeGuildReadChannel(guildId, channel.id);
|
||||
} catch {
|
||||
return await interaction.editReply("읽지 않는것을 실패했어요 ?ㄴ");
|
||||
}
|
||||
|
||||
await interaction.editReply("예주가 이제 이 채널을 읽지않아요!");
|
||||
},
|
||||
true
|
||||
)
|
||||
134
packages/bot/db.ts
Normal file
134
packages/bot/db.ts
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
import { prisma } from "../db/prisma";
|
||||
import { DiscordUserProfile, DiscordGuildProfile, Voice } from "../db/generated/prisma/client";
|
||||
|
||||
export function getUserProfile(userId: string): Promise<DiscordUserProfile> {
|
||||
return prisma.discordUserProfile.upsert({
|
||||
where: {
|
||||
userId: userId
|
||||
},
|
||||
update: {},
|
||||
create: {
|
||||
userId: userId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function setUserProfile(userId: string, profile: DiscordUserProfile): Promise<void> {
|
||||
await prisma.discordUserProfile.upsert({
|
||||
where: {
|
||||
userId: userId
|
||||
},
|
||||
update: {
|
||||
voice: profile.voice,
|
||||
nya: profile.nya
|
||||
},
|
||||
create: {
|
||||
userId: userId,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function setUserNya(userId: string, nya: boolean): Promise<void> {
|
||||
await prisma.discordUserProfile.upsert({
|
||||
where: {
|
||||
userId: userId
|
||||
},
|
||||
update: {
|
||||
nya: nya
|
||||
},
|
||||
create: {
|
||||
userId: userId,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function setUserVoice(userId: string, voice: Voice): Promise<void> {
|
||||
await prisma.discordUserProfile.upsert({
|
||||
where: {
|
||||
userId: userId
|
||||
},
|
||||
update: {
|
||||
voice: voice
|
||||
},
|
||||
create: {
|
||||
userId: userId,
|
||||
voice: voice
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function setUserCanTypecast(userId: string, canTypecast: boolean): Promise<void> {
|
||||
await prisma.discordUserProfile.upsert({
|
||||
where: {
|
||||
userId: userId
|
||||
},
|
||||
update: {
|
||||
canTypecast: canTypecast
|
||||
},
|
||||
create: {
|
||||
userId: userId,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function getGuildProfile(guildId: string): Promise<DiscordGuildProfile> {
|
||||
return prisma.discordGuildProfile.upsert({
|
||||
where: { guildId: guildId },
|
||||
update: {},
|
||||
create: {
|
||||
guildId: guildId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function hasGuildReadChannel(guildId: string, channelId: string): Promise<boolean> {
|
||||
return (
|
||||
await prisma.discordGuildProfile.findFirst({
|
||||
where: {
|
||||
guildId: guildId,
|
||||
readChannel: { has: channelId }
|
||||
}
|
||||
})
|
||||
) != null;
|
||||
}
|
||||
|
||||
export async function removeGuildReadChannel(guildId: string, channelId: string): Promise<void> {
|
||||
const guildProfile = await prisma.discordGuildProfile.findUnique({
|
||||
where: {
|
||||
guildId: guildId
|
||||
},
|
||||
});
|
||||
|
||||
if (guildProfile) {
|
||||
await prisma.discordGuildProfile.update({
|
||||
where: {
|
||||
guildId: guildId
|
||||
},
|
||||
data: {
|
||||
readChannel: guildProfile.readChannel.filter(channel => channel != channelId),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function insertGuildReadChannel(guildId: string, channelId: string): Promise<void> {
|
||||
await prisma.discordGuildProfile.upsert({
|
||||
where: {
|
||||
guildId: guildId,
|
||||
NOT: {
|
||||
readChannel: {
|
||||
has: channelId,
|
||||
},
|
||||
}
|
||||
},
|
||||
update: {
|
||||
readChannel: {
|
||||
push: channelId,
|
||||
},
|
||||
},
|
||||
create: {
|
||||
guildId: guildId,
|
||||
readChannel: [channelId],
|
||||
},
|
||||
});
|
||||
}
|
||||
21
packages/bot/event.ts
Normal file
21
packages/bot/event.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { ClientEvents } from "discord.js";
|
||||
import { join } from "node:path";
|
||||
import { requireDirectorySync } from "../utils/requireDirectory";
|
||||
|
||||
export interface DiscordEvent<Event extends keyof ClientEvents> {
|
||||
event: Event
|
||||
callback: (...args: ClientEvents[Event]) => Promise<void>
|
||||
}
|
||||
|
||||
export function defineEvent<Event extends keyof ClientEvents>(
|
||||
event: Event,
|
||||
callback: (...args: ClientEvents[Event]) => Promise<void>
|
||||
): DiscordEvent<Event> {
|
||||
return {
|
||||
event: event,
|
||||
callback: callback,
|
||||
}
|
||||
}
|
||||
|
||||
export const eventDirectory = join(__dirname, "events");
|
||||
export const eventMap = requireDirectorySync<DiscordEvent<any>>(eventDirectory);
|
||||
61
packages/bot/events/readChannel.ts
Normal file
61
packages/bot/events/readChannel.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import { getOrCreateVoiceConnection } from "../util";
|
||||
import { getUserProfile, hasGuildReadChannel } from "../db";
|
||||
import { defineEvent } from "../event";
|
||||
import { playVoice } from "../tts";
|
||||
|
||||
export default defineEvent("messageCreate", async (message) => {
|
||||
if (message.author.bot)
|
||||
return;
|
||||
|
||||
const guild = message.guild;
|
||||
if (guild == null)
|
||||
return;
|
||||
|
||||
const hasChannel = await hasGuildReadChannel(guild.id, message.channelId);
|
||||
if (!hasChannel)
|
||||
return;
|
||||
|
||||
const profile = await getUserProfile(message.author.id);
|
||||
|
||||
let content = message.cleanContent;
|
||||
let voice: string | null = null
|
||||
if (content.startsWith("$t ")) {
|
||||
voice = "TypeCast"
|
||||
} else if (content.startsWith("$p ")) {
|
||||
voice = "Papago"
|
||||
}
|
||||
|
||||
if (voice) {
|
||||
content = content.replace(/^\$[^ ]+ +/, "")
|
||||
} else {
|
||||
voice = profile.voice;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!await getOrCreateVoiceConnection(guild))
|
||||
return;
|
||||
|
||||
if (!guild.members.me?.voice.channel)
|
||||
return;
|
||||
|
||||
if (message.content === "") {
|
||||
return await playVoice(
|
||||
guild,
|
||||
profile,
|
||||
content =
|
||||
message.attachments.size > 0
|
||||
? `${message.attachments.size} 개의 첨부파일`
|
||||
: "알수없는 메시지"
|
||||
);
|
||||
} else {
|
||||
await playVoice(
|
||||
guild,
|
||||
profile,
|
||||
content = content
|
||||
);
|
||||
}
|
||||
|
||||
} catch(err) {
|
||||
message.reply("말이 꼬이네요 ㅜ.ㅜ");
|
||||
}
|
||||
})
|
||||
11
packages/bot/events/useCommand.ts
Normal file
11
packages/bot/events/useCommand.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { commandExecuteNameHashMap, DiscordCommand, DiscordCommandExecute } from "../command";
|
||||
import { defineEvent } from "../event";
|
||||
|
||||
export default defineEvent("interactionCreate", async (interaction) => {
|
||||
if (!interaction.isChatInputCommand())
|
||||
return;
|
||||
|
||||
if (commandExecuteNameHashMap[interaction.commandName]) {
|
||||
await commandExecuteNameHashMap[interaction.commandName](interaction);
|
||||
}
|
||||
})
|
||||
66
packages/bot/index.ts
Normal file
66
packages/bot/index.ts
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
import { Client, Events, GatewayIntentBits, REST, Routes } from "discord.js";
|
||||
import { commandMap, DiscordCommand } from "./command";
|
||||
import { eventMap } from "./event";
|
||||
import { OutputHandler } from "../utils/outputHandler";
|
||||
import { APPLICATION_ID, GUILD_ID } from "../env";
|
||||
|
||||
export class DiscordBot {
|
||||
rest: REST;
|
||||
client: Client;
|
||||
|
||||
constructor(token: string) {
|
||||
this.client = new Client({
|
||||
intents: [
|
||||
GatewayIntentBits.Guilds,
|
||||
GatewayIntentBits.GuildMessages,
|
||||
GatewayIntentBits.GuildVoiceStates,
|
||||
GatewayIntentBits.MessageContent,
|
||||
],
|
||||
});
|
||||
this.rest = new REST({ version: "10" }).setToken(token);
|
||||
}
|
||||
|
||||
private async putCommands(commands: DiscordCommand[]): Promise<void> {
|
||||
if (!this.client.isReady())
|
||||
throw new Error("Client is not ready");
|
||||
|
||||
await this.rest.put(
|
||||
Routes.applicationGuildCommands(this.client.application.id, GUILD_ID),
|
||||
{
|
||||
body: commands.map((command) => command.data.toJSON()),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public async registerCommands(): Promise<void> {
|
||||
try {
|
||||
if (!this.client.isReady()) {
|
||||
await this.client.once(Events.ClientReady, () => this.putCommands(commandMap));
|
||||
} else {
|
||||
await this.putCommands(commandMap);
|
||||
}
|
||||
} catch(err) {
|
||||
OutputHandler.errorLog("[Command Register Error]", err);
|
||||
}
|
||||
}
|
||||
|
||||
public async deleteCommand(commandId: string): Promise<void> {
|
||||
if (!this.client.isReady())
|
||||
throw new Error("Client is not ready");
|
||||
|
||||
await this.rest.delete(
|
||||
Routes.applicationCommand(this.client.application.id, commandId)
|
||||
);
|
||||
}
|
||||
|
||||
public registerEvents() {
|
||||
try {
|
||||
for (let index = 0; index < eventMap.length; index++) {
|
||||
const event = eventMap[index];
|
||||
this.client.on(event.event, event.callback);
|
||||
}
|
||||
} catch(err) {
|
||||
OutputHandler.errorLog("[Event Register Error]", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
81
packages/bot/music.ts
Normal file
81
packages/bot/music.ts
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import { AudioPlayerStatus, AudioResource, createAudioPlayer, createAudioResource, VoiceConnection } from "@discordjs/voice";
|
||||
import { stream as createStream } from "play-dl";
|
||||
import { Guild } from "discord.js";
|
||||
import { getOrCreateVoiceConnection } from "./util";
|
||||
import { OutputHandler } from "../utils/outputHandler";
|
||||
import play from "play-dl";
|
||||
|
||||
namespace InitPlayDl {
|
||||
let initialized = false;
|
||||
export async function init() {
|
||||
if (initialized)
|
||||
return;
|
||||
|
||||
await play.getFreeClientID();
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
class MusicQueue {
|
||||
private connection: VoiceConnection;
|
||||
private list: AudioResource[];
|
||||
constructor(connection: VoiceConnection) {
|
||||
this.connection = connection;
|
||||
this.list = [];
|
||||
}
|
||||
public static fromConnection(connection: VoiceConnection): MusicQueue {
|
||||
return (connection as any).queue ??= new MusicQueue(connection);
|
||||
}
|
||||
private play() {
|
||||
if (!this.list[0]) return;
|
||||
const player = createAudioPlayer();
|
||||
this.connection.subscribe(player);
|
||||
player.once(AudioPlayerStatus.Idle, this.next.bind(this));
|
||||
player.play(this.list[0]);
|
||||
}
|
||||
public enqueue(resource: AudioResource) {
|
||||
this.list.push(resource);
|
||||
if (this.list.length == 1) {
|
||||
this.play();
|
||||
return;
|
||||
}
|
||||
}
|
||||
public next() {
|
||||
this.list.shift();
|
||||
this.play();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 토큰 설정하고 플레이돼게 만들기
|
||||
export async function playMusic(guild: Guild, url: string) {
|
||||
try {
|
||||
const connection = await getOrCreateVoiceConnection(guild);
|
||||
if (!connection)
|
||||
throw new Error("Yaeju is not joined VoiceChat");
|
||||
|
||||
await InitPlayDl.init();
|
||||
|
||||
const validation = play.yt_validate(url);
|
||||
|
||||
if (validation !== "video" && validation !== "playlist")
|
||||
throw new Error("Invalid YouTube URL: " + validation);
|
||||
|
||||
const stream = await play.stream(url);
|
||||
MusicQueue.fromConnection(connection).enqueue(
|
||||
createAudioResource(stream.stream, {
|
||||
inputType: stream.type
|
||||
})
|
||||
);
|
||||
} catch(err) {
|
||||
OutputHandler.errorLog("[PlayMusic Error]", err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
export async function skipMusic(guild: Guild) {
|
||||
const connection = await getOrCreateVoiceConnection(guild);
|
||||
if (!connection)
|
||||
throw new Error("Yaeju is not joined VoiceChat");
|
||||
|
||||
MusicQueue.fromConnection(connection).next();
|
||||
}
|
||||
92
packages/bot/tts.ts
Normal file
92
packages/bot/tts.ts
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
import { AudioPlayerStatus, AudioResource, createAudioPlayer, VoiceConnection } from "@discordjs/voice";
|
||||
import { Voice } from "../db/generated/prisma/enums";
|
||||
import TTSTypecastModel from "../tts/typecast";
|
||||
import TTSPapagoModel from "../tts/papago";
|
||||
import { Guild } from "discord.js";
|
||||
import { getOrCreateVoiceConnection } from "./util";
|
||||
import TTSModelBase from "../tts";
|
||||
import { DiscordUserProfile } from "../db/generated/prisma/client";
|
||||
import { nyaize } from "../utils/nyaize";
|
||||
import { OutputHandler } from "../utils/outputHandler";
|
||||
|
||||
export async function createVoiceBuffer(voice: Voice, text: string): Promise<Buffer> {
|
||||
if (voice == "TypeCast") {
|
||||
const content = TTSTypecastModel.instance.ttsify(text);
|
||||
|
||||
if (!content.length)
|
||||
throw new Error("Empty content");
|
||||
|
||||
return await TTSTypecastModel.instance.getMemcachedVoice(
|
||||
TTSTypecastModel.instance.createRequestId(content)
|
||||
);
|
||||
} else if (voice == "Papago") {
|
||||
const content = TTSTypecastModel.instance.ttsify(text);
|
||||
if (!content.length)
|
||||
throw new Error("Empty content");
|
||||
|
||||
return await TTSPapagoModel.instance.getMemcachedVoice(
|
||||
TTSPapagoModel.instance.createRequestId(content)
|
||||
);
|
||||
} else {
|
||||
throw new Error(`Unknown voice type: ${voice}`);
|
||||
}
|
||||
}
|
||||
|
||||
class VoiceQueue {
|
||||
private connection: VoiceConnection;
|
||||
private list: AudioResource[];
|
||||
constructor(connection: VoiceConnection) {
|
||||
this.connection = connection;
|
||||
this.list = [];
|
||||
}
|
||||
public static fromConnection(connection: VoiceConnection): VoiceQueue {
|
||||
return (connection as any).queue ??= new VoiceQueue(connection);
|
||||
}
|
||||
private play() {
|
||||
if (!this.list[0]) return;
|
||||
const player = createAudioPlayer();
|
||||
this.connection.subscribe(player);
|
||||
player.once(AudioPlayerStatus.Idle, this.next.bind(this));
|
||||
player.play(this.list[0]);
|
||||
}
|
||||
public enqueue(resource: AudioResource) {
|
||||
this.list.push(resource);
|
||||
if (this.list.length == 1) {
|
||||
this.play();
|
||||
return;
|
||||
}
|
||||
}
|
||||
public next() {
|
||||
this.list.shift();
|
||||
this.play();
|
||||
}
|
||||
}
|
||||
|
||||
export async function playVoice(guild: Guild, profile: DiscordUserProfile, text: string) {
|
||||
if (profile.nya)
|
||||
text = nyaize(text);
|
||||
|
||||
try {
|
||||
let connection = await getOrCreateVoiceConnection(guild);
|
||||
if (!connection)
|
||||
throw new Error("Yaeju is not joined VoiceChat");
|
||||
|
||||
let voiceBuffer: Buffer;
|
||||
if (profile.voice == "TypeCast") {
|
||||
if (profile.canTypecast) {
|
||||
voiceBuffer = await createVoiceBuffer(profile.voice, text);
|
||||
} else {
|
||||
throw new Error(`the user ${profile.userId} is not admin`);
|
||||
}
|
||||
} else {
|
||||
voiceBuffer = await createVoiceBuffer(profile.voice, text);
|
||||
}
|
||||
|
||||
VoiceQueue.fromConnection(connection).enqueue(
|
||||
TTSModelBase.bufferToAudioResource(voiceBuffer)
|
||||
);
|
||||
} catch(err) {
|
||||
OutputHandler.errorLog("[PlayVoice Error]", err);
|
||||
throw new Error(err as any);
|
||||
}
|
||||
}
|
||||
25
packages/bot/util.ts
Normal file
25
packages/bot/util.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import { getVoiceConnection as defaultGetVoiceConnection, EndBehaviorType, joinVoiceChannel, VoiceConnection } from "@discordjs/voice";
|
||||
import { Guild } from "discord.js";
|
||||
|
||||
export async function getOrCreateVoiceConnection(guild: Guild): Promise<VoiceConnection | undefined> {
|
||||
let connection = defaultGetVoiceConnection(guild.id);
|
||||
|
||||
if (!connection) {
|
||||
if (!guild.members.me?.voice.channel)
|
||||
return;
|
||||
|
||||
const channel = guild.members.me.voice.channel;
|
||||
|
||||
connection = joinVoiceChannel({
|
||||
channelId: channel.id,
|
||||
guildId: channel.guild.id,
|
||||
adapterCreator: channel.guild.voiceAdapterCreator,
|
||||
selfDeaf: false,
|
||||
selfMute: false,
|
||||
});
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
11
packages/cli/remove_command.ts
Normal file
11
packages/cli/remove_command.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { bot } from "..";
|
||||
|
||||
export default function remove() {
|
||||
bot.deleteCommand("1463496119135899671");
|
||||
bot.deleteCommand("1463496119135899675");
|
||||
bot.deleteCommand("1463496119135899676");
|
||||
bot.deleteCommand("1463496119135899677");
|
||||
bot.deleteCommand("1463496119286759606");
|
||||
bot.deleteCommand("1464993345427476648");
|
||||
bot.deleteCommand("1464993345427476649");
|
||||
}
|
||||
29
packages/db/generated/prisma/browser.ts
Normal file
29
packages/db/generated/prisma/browser.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
// @ts-nocheck
|
||||
/*
|
||||
* This file should be your main import to use Prisma-related types and utilities in a browser.
|
||||
* Use it to get access to models, enums, and input types.
|
||||
*
|
||||
* This file does not contain a `PrismaClient` class, nor several other helpers that are intended as server-side only.
|
||||
* See `client.ts` for the standard, server-side entry point.
|
||||
*
|
||||
* 🟢 You can import this file directly.
|
||||
*/
|
||||
|
||||
import * as Prisma from './internal/prismaNamespaceBrowser'
|
||||
export { Prisma }
|
||||
export * as $Enums from './enums'
|
||||
export * from './enums';
|
||||
/**
|
||||
* Model DiscordUserProfile
|
||||
*
|
||||
*/
|
||||
export type DiscordUserProfile = Prisma.DiscordUserProfileModel
|
||||
/**
|
||||
* Model DiscordGuildProfile
|
||||
*
|
||||
*/
|
||||
export type DiscordGuildProfile = Prisma.DiscordGuildProfileModel
|
||||
49
packages/db/generated/prisma/client.ts
Normal file
49
packages/db/generated/prisma/client.ts
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
// @ts-nocheck
|
||||
/*
|
||||
* This file should be your main import to use Prisma. Through it you get access to all the models, enums, and input types.
|
||||
* If you're looking for something you can import in the client-side of your application, please refer to the `browser.ts` file instead.
|
||||
*
|
||||
* 🟢 You can import this file directly.
|
||||
*/
|
||||
|
||||
import * as process from 'node:process'
|
||||
import * as path from 'node:path'
|
||||
|
||||
import * as runtime from "@prisma/client/runtime/client"
|
||||
import * as $Enums from "./enums"
|
||||
import * as $Class from "./internal/class"
|
||||
import * as Prisma from "./internal/prismaNamespace"
|
||||
|
||||
export * as $Enums from './enums'
|
||||
export * from "./enums"
|
||||
/**
|
||||
* ## Prisma Client
|
||||
*
|
||||
* Type-safe database client for TypeScript
|
||||
* @example
|
||||
* ```
|
||||
* const prisma = new PrismaClient()
|
||||
* // Fetch zero or more DiscordUserProfiles
|
||||
* const discordUserProfiles = await prisma.discordUserProfile.findMany()
|
||||
* ```
|
||||
*
|
||||
* Read more in our [docs](https://pris.ly/d/client).
|
||||
*/
|
||||
export const PrismaClient = $Class.getPrismaClientClass()
|
||||
export type PrismaClient<LogOpts extends Prisma.LogLevel = never, OmitOpts extends Prisma.PrismaClientOptions["omit"] = Prisma.PrismaClientOptions["omit"], ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = $Class.PrismaClient<LogOpts, OmitOpts, ExtArgs>
|
||||
export { Prisma }
|
||||
|
||||
/**
|
||||
* Model DiscordUserProfile
|
||||
*
|
||||
*/
|
||||
export type DiscordUserProfile = Prisma.DiscordUserProfileModel
|
||||
/**
|
||||
* Model DiscordGuildProfile
|
||||
*
|
||||
*/
|
||||
export type DiscordGuildProfile = Prisma.DiscordGuildProfileModel
|
||||
152
packages/db/generated/prisma/commonInputTypes.ts
Normal file
152
packages/db/generated/prisma/commonInputTypes.ts
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
// @ts-nocheck
|
||||
/*
|
||||
* This file exports various common sort, input & filter types that are not directly linked to a particular model.
|
||||
*
|
||||
* 🟢 You can import this file directly.
|
||||
*/
|
||||
|
||||
import type * as runtime from "@prisma/client/runtime/client"
|
||||
import * as $Enums from "./enums"
|
||||
import type * as Prisma from "./internal/prismaNamespace"
|
||||
|
||||
|
||||
export type StringFilter<$PrismaModel = never> = {
|
||||
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
mode?: Prisma.QueryMode
|
||||
not?: Prisma.NestedStringFilter<$PrismaModel> | string
|
||||
}
|
||||
|
||||
export type EnumVoiceFilter<$PrismaModel = never> = {
|
||||
equals?: $Enums.Voice | Prisma.EnumVoiceFieldRefInput<$PrismaModel>
|
||||
in?: $Enums.Voice[] | Prisma.ListEnumVoiceFieldRefInput<$PrismaModel>
|
||||
notIn?: $Enums.Voice[] | Prisma.ListEnumVoiceFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedEnumVoiceFilter<$PrismaModel> | $Enums.Voice
|
||||
}
|
||||
|
||||
export type BoolFilter<$PrismaModel = never> = {
|
||||
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean
|
||||
}
|
||||
|
||||
export type StringWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
mode?: Prisma.QueryMode
|
||||
not?: Prisma.NestedStringWithAggregatesFilter<$PrismaModel> | string
|
||||
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||
_min?: Prisma.NestedStringFilter<$PrismaModel>
|
||||
_max?: Prisma.NestedStringFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type EnumVoiceWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: $Enums.Voice | Prisma.EnumVoiceFieldRefInput<$PrismaModel>
|
||||
in?: $Enums.Voice[] | Prisma.ListEnumVoiceFieldRefInput<$PrismaModel>
|
||||
notIn?: $Enums.Voice[] | Prisma.ListEnumVoiceFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedEnumVoiceWithAggregatesFilter<$PrismaModel> | $Enums.Voice
|
||||
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||
_min?: Prisma.NestedEnumVoiceFilter<$PrismaModel>
|
||||
_max?: Prisma.NestedEnumVoiceFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type BoolWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean
|
||||
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||
_min?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||
_max?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type NestedStringFilter<$PrismaModel = never> = {
|
||||
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedStringFilter<$PrismaModel> | string
|
||||
}
|
||||
|
||||
export type NestedEnumVoiceFilter<$PrismaModel = never> = {
|
||||
equals?: $Enums.Voice | Prisma.EnumVoiceFieldRefInput<$PrismaModel>
|
||||
in?: $Enums.Voice[] | Prisma.ListEnumVoiceFieldRefInput<$PrismaModel>
|
||||
notIn?: $Enums.Voice[] | Prisma.ListEnumVoiceFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedEnumVoiceFilter<$PrismaModel> | $Enums.Voice
|
||||
}
|
||||
|
||||
export type NestedBoolFilter<$PrismaModel = never> = {
|
||||
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedBoolFilter<$PrismaModel> | boolean
|
||||
}
|
||||
|
||||
export type NestedStringWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
in?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||
notIn?: string[] | Prisma.ListStringFieldRefInput<$PrismaModel>
|
||||
lt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
lte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
gt?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
gte?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
contains?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
startsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
endsWith?: string | Prisma.StringFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedStringWithAggregatesFilter<$PrismaModel> | string
|
||||
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||
_min?: Prisma.NestedStringFilter<$PrismaModel>
|
||||
_max?: Prisma.NestedStringFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type NestedIntFilter<$PrismaModel = never> = {
|
||||
equals?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||
in?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
||||
notIn?: number[] | Prisma.ListIntFieldRefInput<$PrismaModel>
|
||||
lt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||
lte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||
gt?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||
gte?: number | Prisma.IntFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedIntFilter<$PrismaModel> | number
|
||||
}
|
||||
|
||||
export type NestedEnumVoiceWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: $Enums.Voice | Prisma.EnumVoiceFieldRefInput<$PrismaModel>
|
||||
in?: $Enums.Voice[] | Prisma.ListEnumVoiceFieldRefInput<$PrismaModel>
|
||||
notIn?: $Enums.Voice[] | Prisma.ListEnumVoiceFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedEnumVoiceWithAggregatesFilter<$PrismaModel> | $Enums.Voice
|
||||
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||
_min?: Prisma.NestedEnumVoiceFilter<$PrismaModel>
|
||||
_max?: Prisma.NestedEnumVoiceFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
export type NestedBoolWithAggregatesFilter<$PrismaModel = never> = {
|
||||
equals?: boolean | Prisma.BooleanFieldRefInput<$PrismaModel>
|
||||
not?: Prisma.NestedBoolWithAggregatesFilter<$PrismaModel> | boolean
|
||||
_count?: Prisma.NestedIntFilter<$PrismaModel>
|
||||
_min?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||
_max?: Prisma.NestedBoolFilter<$PrismaModel>
|
||||
}
|
||||
|
||||
|
||||
17
packages/db/generated/prisma/enums.ts
Normal file
17
packages/db/generated/prisma/enums.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
// @ts-nocheck
|
||||
/*
|
||||
* This file exports all enum related types from the schema.
|
||||
*
|
||||
* 🟢 You can import this file directly.
|
||||
*/
|
||||
|
||||
export const Voice = {
|
||||
TypeCast: 'TypeCast',
|
||||
Papago: 'Papago'
|
||||
} as const
|
||||
|
||||
export type Voice = (typeof Voice)[keyof typeof Voice]
|
||||
200
packages/db/generated/prisma/internal/class.ts
Normal file
200
packages/db/generated/prisma/internal/class.ts
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
// @ts-nocheck
|
||||
/*
|
||||
* WARNING: This is an internal file that is subject to change!
|
||||
*
|
||||
* 🛑 Under no circumstances should you import this file directly! 🛑
|
||||
*
|
||||
* Please import the `PrismaClient` class from the `client.ts` file instead.
|
||||
*/
|
||||
|
||||
import * as runtime from "@prisma/client/runtime/client"
|
||||
import type * as Prisma from "./prismaNamespace"
|
||||
|
||||
|
||||
const config: runtime.GetPrismaClientConfig = {
|
||||
"previewFeatures": [],
|
||||
"clientVersion": "7.2.0",
|
||||
"engineVersion": "0c8ef2ce45c83248ab3df073180d5eda9e8be7a3",
|
||||
"activeProvider": "postgresql",
|
||||
"inlineSchema": "// This is your Prisma schema file,\n// learn more about it in the docs: https://pris.ly/d/prisma-schema\n\n// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?\n// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init\n\ngenerator client {\n provider = \"prisma-client\"\n specifying = [\"prismaSchemaFolder\"]\n output = \"../packages/db/generated/prisma\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n}\n\nenum Voice {\n TypeCast\n Papago\n}\n\nmodel DiscordUserProfile {\n id String @id @default(cuid())\n userId String @unique\n voice Voice @default(Papago)\n nya Boolean @default(false)\n canTypecast Boolean @default(false)\n}\n\nmodel DiscordGuildProfile {\n id String @id @default(cuid())\n guildId String @unique\n readChannel String[] @default([])\n}\n",
|
||||
"runtimeDataModel": {
|
||||
"models": {},
|
||||
"enums": {},
|
||||
"types": {}
|
||||
}
|
||||
}
|
||||
|
||||
config.runtimeDataModel = JSON.parse("{\"models\":{\"DiscordUserProfile\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"userId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"voice\",\"kind\":\"enum\",\"type\":\"Voice\"},{\"name\":\"nya\",\"kind\":\"scalar\",\"type\":\"Boolean\"},{\"name\":\"canTypecast\",\"kind\":\"scalar\",\"type\":\"Boolean\"}],\"dbName\":null},\"DiscordGuildProfile\":{\"fields\":[{\"name\":\"id\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"guildId\",\"kind\":\"scalar\",\"type\":\"String\"},{\"name\":\"readChannel\",\"kind\":\"scalar\",\"type\":\"String\"}],\"dbName\":null}},\"enums\":{},\"types\":{}}")
|
||||
|
||||
async function decodeBase64AsWasm(wasmBase64: string): Promise<WebAssembly.Module> {
|
||||
const { Buffer } = await import('node:buffer')
|
||||
const wasmArray = Buffer.from(wasmBase64, 'base64')
|
||||
return new WebAssembly.Module(wasmArray)
|
||||
}
|
||||
|
||||
config.compilerWasm = {
|
||||
getRuntime: async () => await import("@prisma/client/runtime/query_compiler_bg.postgresql.js"),
|
||||
|
||||
getQueryCompilerWasmModule: async () => {
|
||||
const { wasm } = await import("@prisma/client/runtime/query_compiler_bg.postgresql.wasm-base64.js")
|
||||
return await decodeBase64AsWasm(wasm)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
export type LogOptions<ClientOptions extends Prisma.PrismaClientOptions> =
|
||||
'log' extends keyof ClientOptions ? ClientOptions['log'] extends Array<Prisma.LogLevel | Prisma.LogDefinition> ? Prisma.GetEvents<ClientOptions['log']> : never : never
|
||||
|
||||
export interface PrismaClientConstructor {
|
||||
/**
|
||||
* ## Prisma Client
|
||||
*
|
||||
* Type-safe database client for TypeScript
|
||||
* @example
|
||||
* ```
|
||||
* const prisma = new PrismaClient()
|
||||
* // Fetch zero or more DiscordUserProfiles
|
||||
* const discordUserProfiles = await prisma.discordUserProfile.findMany()
|
||||
* ```
|
||||
*
|
||||
* Read more in our [docs](https://pris.ly/d/client).
|
||||
*/
|
||||
|
||||
new <
|
||||
Options extends Prisma.PrismaClientOptions = Prisma.PrismaClientOptions,
|
||||
LogOpts extends LogOptions<Options> = LogOptions<Options>,
|
||||
OmitOpts extends Prisma.PrismaClientOptions['omit'] = Options extends { omit: infer U } ? U : Prisma.PrismaClientOptions['omit'],
|
||||
ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs
|
||||
>(options: Prisma.Subset<Options, Prisma.PrismaClientOptions> ): PrismaClient<LogOpts, OmitOpts, ExtArgs>
|
||||
}
|
||||
|
||||
/**
|
||||
* ## Prisma Client
|
||||
*
|
||||
* Type-safe database client for TypeScript
|
||||
* @example
|
||||
* ```
|
||||
* const prisma = new PrismaClient()
|
||||
* // Fetch zero or more DiscordUserProfiles
|
||||
* const discordUserProfiles = await prisma.discordUserProfile.findMany()
|
||||
* ```
|
||||
*
|
||||
* Read more in our [docs](https://pris.ly/d/client).
|
||||
*/
|
||||
|
||||
export interface PrismaClient<
|
||||
in LogOpts extends Prisma.LogLevel = never,
|
||||
in out OmitOpts extends Prisma.PrismaClientOptions['omit'] = undefined,
|
||||
in out ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs
|
||||
> {
|
||||
[K: symbol]: { types: Prisma.TypeMap<ExtArgs>['other'] }
|
||||
|
||||
$on<V extends LogOpts>(eventType: V, callback: (event: V extends 'query' ? Prisma.QueryEvent : Prisma.LogEvent) => void): PrismaClient;
|
||||
|
||||
/**
|
||||
* Connect with the database
|
||||
*/
|
||||
$connect(): runtime.Types.Utils.JsPromise<void>;
|
||||
|
||||
/**
|
||||
* Disconnect from the database
|
||||
*/
|
||||
$disconnect(): runtime.Types.Utils.JsPromise<void>;
|
||||
|
||||
/**
|
||||
* Executes a prepared raw query and returns the number of affected rows.
|
||||
* @example
|
||||
* ```
|
||||
* const result = await prisma.$executeRaw`UPDATE User SET cool = ${true} WHERE email = ${'user@email.com'};`
|
||||
* ```
|
||||
*
|
||||
* Read more in our [docs](https://pris.ly/d/raw-queries).
|
||||
*/
|
||||
$executeRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise<number>;
|
||||
|
||||
/**
|
||||
* Executes a raw query and returns the number of affected rows.
|
||||
* Susceptible to SQL injections, see documentation.
|
||||
* @example
|
||||
* ```
|
||||
* const result = await prisma.$executeRawUnsafe('UPDATE User SET cool = $1 WHERE email = $2 ;', true, 'user@email.com')
|
||||
* ```
|
||||
*
|
||||
* Read more in our [docs](https://pris.ly/d/raw-queries).
|
||||
*/
|
||||
$executeRawUnsafe<T = unknown>(query: string, ...values: any[]): Prisma.PrismaPromise<number>;
|
||||
|
||||
/**
|
||||
* Performs a prepared raw query and returns the `SELECT` data.
|
||||
* @example
|
||||
* ```
|
||||
* const result = await prisma.$queryRaw`SELECT * FROM User WHERE id = ${1} OR email = ${'user@email.com'};`
|
||||
* ```
|
||||
*
|
||||
* Read more in our [docs](https://pris.ly/d/raw-queries).
|
||||
*/
|
||||
$queryRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise<T>;
|
||||
|
||||
/**
|
||||
* Performs a raw query and returns the `SELECT` data.
|
||||
* Susceptible to SQL injections, see documentation.
|
||||
* @example
|
||||
* ```
|
||||
* const result = await prisma.$queryRawUnsafe('SELECT * FROM User WHERE id = $1 OR email = $2;', 1, 'user@email.com')
|
||||
* ```
|
||||
*
|
||||
* Read more in our [docs](https://pris.ly/d/raw-queries).
|
||||
*/
|
||||
$queryRawUnsafe<T = unknown>(query: string, ...values: any[]): Prisma.PrismaPromise<T>;
|
||||
|
||||
|
||||
/**
|
||||
* Allows the running of a sequence of read/write operations that are guaranteed to either succeed or fail as a whole.
|
||||
* @example
|
||||
* ```
|
||||
* const [george, bob, alice] = await prisma.$transaction([
|
||||
* prisma.user.create({ data: { name: 'George' } }),
|
||||
* prisma.user.create({ data: { name: 'Bob' } }),
|
||||
* prisma.user.create({ data: { name: 'Alice' } }),
|
||||
* ])
|
||||
* ```
|
||||
*
|
||||
* Read more in our [docs](https://www.prisma.io/docs/concepts/components/prisma-client/transactions).
|
||||
*/
|
||||
$transaction<P extends Prisma.PrismaPromise<any>[]>(arg: [...P], options?: { isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise<runtime.Types.Utils.UnwrapTuple<P>>
|
||||
|
||||
$transaction<R>(fn: (prisma: Omit<PrismaClient, runtime.ITXClientDenyList>) => runtime.Types.Utils.JsPromise<R>, options?: { maxWait?: number, timeout?: number, isolationLevel?: Prisma.TransactionIsolationLevel }): runtime.Types.Utils.JsPromise<R>
|
||||
|
||||
$extends: runtime.Types.Extensions.ExtendsHook<"extends", Prisma.TypeMapCb<OmitOpts>, ExtArgs, runtime.Types.Utils.Call<Prisma.TypeMapCb<OmitOpts>, {
|
||||
extArgs: ExtArgs
|
||||
}>>
|
||||
|
||||
/**
|
||||
* `prisma.discordUserProfile`: Exposes CRUD operations for the **DiscordUserProfile** model.
|
||||
* Example usage:
|
||||
* ```ts
|
||||
* // Fetch zero or more DiscordUserProfiles
|
||||
* const discordUserProfiles = await prisma.discordUserProfile.findMany()
|
||||
* ```
|
||||
*/
|
||||
get discordUserProfile(): Prisma.DiscordUserProfileDelegate<ExtArgs, { omit: OmitOpts }>;
|
||||
|
||||
/**
|
||||
* `prisma.discordGuildProfile`: Exposes CRUD operations for the **DiscordGuildProfile** model.
|
||||
* Example usage:
|
||||
* ```ts
|
||||
* // Fetch zero or more DiscordGuildProfiles
|
||||
* const discordGuildProfiles = await prisma.discordGuildProfile.findMany()
|
||||
* ```
|
||||
*/
|
||||
get discordGuildProfile(): Prisma.DiscordGuildProfileDelegate<ExtArgs, { omit: OmitOpts }>;
|
||||
}
|
||||
|
||||
export function getPrismaClientClass(): PrismaClientConstructor {
|
||||
return runtime.getPrismaClient(config) as unknown as PrismaClientConstructor
|
||||
}
|
||||
844
packages/db/generated/prisma/internal/prismaNamespace.ts
Normal file
844
packages/db/generated/prisma/internal/prismaNamespace.ts
Normal file
|
|
@ -0,0 +1,844 @@
|
|||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
// @ts-nocheck
|
||||
/*
|
||||
* WARNING: This is an internal file that is subject to change!
|
||||
*
|
||||
* 🛑 Under no circumstances should you import this file directly! 🛑
|
||||
*
|
||||
* All exports from this file are wrapped under a `Prisma` namespace object in the client.ts file.
|
||||
* While this enables partial backward compatibility, it is not part of the stable public API.
|
||||
*
|
||||
* If you are looking for your Models, Enums, and Input Types, please import them from the respective
|
||||
* model files in the `model` directory!
|
||||
*/
|
||||
|
||||
import * as runtime from "@prisma/client/runtime/client"
|
||||
import type * as Prisma from "../models"
|
||||
import { type PrismaClient } from "./class"
|
||||
|
||||
export type * from '../models'
|
||||
|
||||
export type DMMF = typeof runtime.DMMF
|
||||
|
||||
export type PrismaPromise<T> = runtime.Types.Public.PrismaPromise<T>
|
||||
|
||||
/**
|
||||
* Prisma Errors
|
||||
*/
|
||||
|
||||
export const PrismaClientKnownRequestError = runtime.PrismaClientKnownRequestError
|
||||
export type PrismaClientKnownRequestError = runtime.PrismaClientKnownRequestError
|
||||
|
||||
export const PrismaClientUnknownRequestError = runtime.PrismaClientUnknownRequestError
|
||||
export type PrismaClientUnknownRequestError = runtime.PrismaClientUnknownRequestError
|
||||
|
||||
export const PrismaClientRustPanicError = runtime.PrismaClientRustPanicError
|
||||
export type PrismaClientRustPanicError = runtime.PrismaClientRustPanicError
|
||||
|
||||
export const PrismaClientInitializationError = runtime.PrismaClientInitializationError
|
||||
export type PrismaClientInitializationError = runtime.PrismaClientInitializationError
|
||||
|
||||
export const PrismaClientValidationError = runtime.PrismaClientValidationError
|
||||
export type PrismaClientValidationError = runtime.PrismaClientValidationError
|
||||
|
||||
/**
|
||||
* Re-export of sql-template-tag
|
||||
*/
|
||||
export const sql = runtime.sqltag
|
||||
export const empty = runtime.empty
|
||||
export const join = runtime.join
|
||||
export const raw = runtime.raw
|
||||
export const Sql = runtime.Sql
|
||||
export type Sql = runtime.Sql
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Decimal.js
|
||||
*/
|
||||
export const Decimal = runtime.Decimal
|
||||
export type Decimal = runtime.Decimal
|
||||
|
||||
export type DecimalJsLike = runtime.DecimalJsLike
|
||||
|
||||
/**
|
||||
* Extensions
|
||||
*/
|
||||
export type Extension = runtime.Types.Extensions.UserArgs
|
||||
export const getExtensionContext = runtime.Extensions.getExtensionContext
|
||||
export type Args<T, F extends runtime.Operation> = runtime.Types.Public.Args<T, F>
|
||||
export type Payload<T, F extends runtime.Operation = never> = runtime.Types.Public.Payload<T, F>
|
||||
export type Result<T, A, F extends runtime.Operation> = runtime.Types.Public.Result<T, A, F>
|
||||
export type Exact<A, W> = runtime.Types.Public.Exact<A, W>
|
||||
|
||||
export type PrismaVersion = {
|
||||
client: string
|
||||
engine: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Prisma Client JS version: 7.2.0
|
||||
* Query Engine version: 0c8ef2ce45c83248ab3df073180d5eda9e8be7a3
|
||||
*/
|
||||
export const prismaVersion: PrismaVersion = {
|
||||
client: "7.2.0",
|
||||
engine: "0c8ef2ce45c83248ab3df073180d5eda9e8be7a3"
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility Types
|
||||
*/
|
||||
|
||||
export type Bytes = runtime.Bytes
|
||||
export type JsonObject = runtime.JsonObject
|
||||
export type JsonArray = runtime.JsonArray
|
||||
export type JsonValue = runtime.JsonValue
|
||||
export type InputJsonObject = runtime.InputJsonObject
|
||||
export type InputJsonArray = runtime.InputJsonArray
|
||||
export type InputJsonValue = runtime.InputJsonValue
|
||||
|
||||
|
||||
export const NullTypes = {
|
||||
DbNull: runtime.NullTypes.DbNull as (new (secret: never) => typeof runtime.DbNull),
|
||||
JsonNull: runtime.NullTypes.JsonNull as (new (secret: never) => typeof runtime.JsonNull),
|
||||
AnyNull: runtime.NullTypes.AnyNull as (new (secret: never) => typeof runtime.AnyNull),
|
||||
}
|
||||
/**
|
||||
* Helper for filtering JSON entries that have `null` on the database (empty on the db)
|
||||
*
|
||||
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
|
||||
*/
|
||||
export const DbNull = runtime.DbNull
|
||||
|
||||
/**
|
||||
* Helper for filtering JSON entries that have JSON `null` values (not empty on the db)
|
||||
*
|
||||
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
|
||||
*/
|
||||
export const JsonNull = runtime.JsonNull
|
||||
|
||||
/**
|
||||
* Helper for filtering JSON entries that are `Prisma.DbNull` or `Prisma.JsonNull`
|
||||
*
|
||||
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
|
||||
*/
|
||||
export const AnyNull = runtime.AnyNull
|
||||
|
||||
|
||||
type SelectAndInclude = {
|
||||
select: any
|
||||
include: any
|
||||
}
|
||||
|
||||
type SelectAndOmit = {
|
||||
select: any
|
||||
omit: any
|
||||
}
|
||||
|
||||
/**
|
||||
* From T, pick a set of properties whose keys are in the union K
|
||||
*/
|
||||
type Prisma__Pick<T, K extends keyof T> = {
|
||||
[P in K]: T[P];
|
||||
};
|
||||
|
||||
export type Enumerable<T> = T | Array<T>;
|
||||
|
||||
/**
|
||||
* Subset
|
||||
* @desc From `T` pick properties that exist in `U`. Simple version of Intersection
|
||||
*/
|
||||
export type Subset<T, U> = {
|
||||
[key in keyof T]: key extends keyof U ? T[key] : never;
|
||||
};
|
||||
|
||||
/**
|
||||
* SelectSubset
|
||||
* @desc From `T` pick properties that exist in `U`. Simple version of Intersection.
|
||||
* Additionally, it validates, if both select and include are present. If the case, it errors.
|
||||
*/
|
||||
export type SelectSubset<T, U> = {
|
||||
[key in keyof T]: key extends keyof U ? T[key] : never
|
||||
} &
|
||||
(T extends SelectAndInclude
|
||||
? 'Please either choose `select` or `include`.'
|
||||
: T extends SelectAndOmit
|
||||
? 'Please either choose `select` or `omit`.'
|
||||
: {})
|
||||
|
||||
/**
|
||||
* Subset + Intersection
|
||||
* @desc From `T` pick properties that exist in `U` and intersect `K`
|
||||
*/
|
||||
export type SubsetIntersection<T, U, K> = {
|
||||
[key in keyof T]: key extends keyof U ? T[key] : never
|
||||
} &
|
||||
K
|
||||
|
||||
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
|
||||
|
||||
/**
|
||||
* XOR is needed to have a real mutually exclusive union type
|
||||
* https://stackoverflow.com/questions/42123407/does-typescript-support-mutually-exclusive-types
|
||||
*/
|
||||
export type XOR<T, U> =
|
||||
T extends object ?
|
||||
U extends object ?
|
||||
(Without<T, U> & U) | (Without<U, T> & T)
|
||||
: U : T
|
||||
|
||||
|
||||
/**
|
||||
* Is T a Record?
|
||||
*/
|
||||
type IsObject<T extends any> = T extends Array<any>
|
||||
? False
|
||||
: T extends Date
|
||||
? False
|
||||
: T extends Uint8Array
|
||||
? False
|
||||
: T extends BigInt
|
||||
? False
|
||||
: T extends object
|
||||
? True
|
||||
: False
|
||||
|
||||
|
||||
/**
|
||||
* If it's T[], return T
|
||||
*/
|
||||
export type UnEnumerate<T extends unknown> = T extends Array<infer U> ? U : T
|
||||
|
||||
/**
|
||||
* From ts-toolbelt
|
||||
*/
|
||||
|
||||
type __Either<O extends object, K extends Key> = Omit<O, K> &
|
||||
{
|
||||
// Merge all but K
|
||||
[P in K]: Prisma__Pick<O, P & keyof O> // With K possibilities
|
||||
}[K]
|
||||
|
||||
type EitherStrict<O extends object, K extends Key> = Strict<__Either<O, K>>
|
||||
|
||||
type EitherLoose<O extends object, K extends Key> = ComputeRaw<__Either<O, K>>
|
||||
|
||||
type _Either<
|
||||
O extends object,
|
||||
K extends Key,
|
||||
strict extends Boolean
|
||||
> = {
|
||||
1: EitherStrict<O, K>
|
||||
0: EitherLoose<O, K>
|
||||
}[strict]
|
||||
|
||||
export type Either<
|
||||
O extends object,
|
||||
K extends Key,
|
||||
strict extends Boolean = 1
|
||||
> = O extends unknown ? _Either<O, K, strict> : never
|
||||
|
||||
export type Union = any
|
||||
|
||||
export type PatchUndefined<O extends object, O1 extends object> = {
|
||||
[K in keyof O]: O[K] extends undefined ? At<O1, K> : O[K]
|
||||
} & {}
|
||||
|
||||
/** Helper Types for "Merge" **/
|
||||
export type IntersectOf<U extends Union> = (
|
||||
U extends unknown ? (k: U) => void : never
|
||||
) extends (k: infer I) => void
|
||||
? I
|
||||
: never
|
||||
|
||||
export type Overwrite<O extends object, O1 extends object> = {
|
||||
[K in keyof O]: K extends keyof O1 ? O1[K] : O[K];
|
||||
} & {};
|
||||
|
||||
type _Merge<U extends object> = IntersectOf<Overwrite<U, {
|
||||
[K in keyof U]-?: At<U, K>;
|
||||
}>>;
|
||||
|
||||
type Key = string | number | symbol;
|
||||
type AtStrict<O extends object, K extends Key> = O[K & keyof O];
|
||||
type AtLoose<O extends object, K extends Key> = O extends unknown ? AtStrict<O, K> : never;
|
||||
export type At<O extends object, K extends Key, strict extends Boolean = 1> = {
|
||||
1: AtStrict<O, K>;
|
||||
0: AtLoose<O, K>;
|
||||
}[strict];
|
||||
|
||||
export type ComputeRaw<A extends any> = A extends Function ? A : {
|
||||
[K in keyof A]: A[K];
|
||||
} & {};
|
||||
|
||||
export type OptionalFlat<O> = {
|
||||
[K in keyof O]?: O[K];
|
||||
} & {};
|
||||
|
||||
type _Record<K extends keyof any, T> = {
|
||||
[P in K]: T;
|
||||
};
|
||||
|
||||
// cause typescript not to expand types and preserve names
|
||||
type NoExpand<T> = T extends unknown ? T : never;
|
||||
|
||||
// this type assumes the passed object is entirely optional
|
||||
export type AtLeast<O extends object, K extends string> = NoExpand<
|
||||
O extends unknown
|
||||
? | (K extends keyof O ? { [P in K]: O[P] } & O : O)
|
||||
| {[P in keyof O as P extends K ? P : never]-?: O[P]} & O
|
||||
: never>;
|
||||
|
||||
type _Strict<U, _U = U> = U extends unknown ? U & OptionalFlat<_Record<Exclude<Keys<_U>, keyof U>, never>> : never;
|
||||
|
||||
export type Strict<U extends object> = ComputeRaw<_Strict<U>>;
|
||||
/** End Helper Types for "Merge" **/
|
||||
|
||||
export type Merge<U extends object> = ComputeRaw<_Merge<Strict<U>>>;
|
||||
|
||||
export type Boolean = True | False
|
||||
|
||||
export type True = 1
|
||||
|
||||
export type False = 0
|
||||
|
||||
export type Not<B extends Boolean> = {
|
||||
0: 1
|
||||
1: 0
|
||||
}[B]
|
||||
|
||||
export type Extends<A1 extends any, A2 extends any> = [A1] extends [never]
|
||||
? 0 // anything `never` is false
|
||||
: A1 extends A2
|
||||
? 1
|
||||
: 0
|
||||
|
||||
export type Has<U extends Union, U1 extends Union> = Not<
|
||||
Extends<Exclude<U1, U>, U1>
|
||||
>
|
||||
|
||||
export type Or<B1 extends Boolean, B2 extends Boolean> = {
|
||||
0: {
|
||||
0: 0
|
||||
1: 1
|
||||
}
|
||||
1: {
|
||||
0: 1
|
||||
1: 1
|
||||
}
|
||||
}[B1][B2]
|
||||
|
||||
export type Keys<U extends Union> = U extends unknown ? keyof U : never
|
||||
|
||||
export type GetScalarType<T, O> = O extends object ? {
|
||||
[P in keyof T]: P extends keyof O
|
||||
? O[P]
|
||||
: never
|
||||
} : never
|
||||
|
||||
type FieldPaths<
|
||||
T,
|
||||
U = Omit<T, '_avg' | '_sum' | '_count' | '_min' | '_max'>
|
||||
> = IsObject<T> extends True ? U : T
|
||||
|
||||
export type GetHavingFields<T> = {
|
||||
[K in keyof T]: Or<
|
||||
Or<Extends<'OR', K>, Extends<'AND', K>>,
|
||||
Extends<'NOT', K>
|
||||
> extends True
|
||||
? // infer is only needed to not hit TS limit
|
||||
// based on the brilliant idea of Pierre-Antoine Mills
|
||||
// https://github.com/microsoft/TypeScript/issues/30188#issuecomment-478938437
|
||||
T[K] extends infer TK
|
||||
? GetHavingFields<UnEnumerate<TK> extends object ? Merge<UnEnumerate<TK>> : never>
|
||||
: never
|
||||
: {} extends FieldPaths<T[K]>
|
||||
? never
|
||||
: K
|
||||
}[keyof T]
|
||||
|
||||
/**
|
||||
* Convert tuple to union
|
||||
*/
|
||||
type _TupleToUnion<T> = T extends (infer E)[] ? E : never
|
||||
type TupleToUnion<K extends readonly any[]> = _TupleToUnion<K>
|
||||
export type MaybeTupleToUnion<T> = T extends any[] ? TupleToUnion<T> : T
|
||||
|
||||
/**
|
||||
* Like `Pick`, but additionally can also accept an array of keys
|
||||
*/
|
||||
export type PickEnumerable<T, K extends Enumerable<keyof T> | keyof T> = Prisma__Pick<T, MaybeTupleToUnion<K>>
|
||||
|
||||
/**
|
||||
* Exclude all keys with underscores
|
||||
*/
|
||||
export type ExcludeUnderscoreKeys<T extends string> = T extends `_${string}` ? never : T
|
||||
|
||||
|
||||
export type FieldRef<Model, FieldType> = runtime.FieldRef<Model, FieldType>
|
||||
|
||||
type FieldRefInputType<Model, FieldType> = Model extends never ? never : FieldRef<Model, FieldType>
|
||||
|
||||
|
||||
export const ModelName = {
|
||||
DiscordUserProfile: 'DiscordUserProfile',
|
||||
DiscordGuildProfile: 'DiscordGuildProfile'
|
||||
} as const
|
||||
|
||||
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
|
||||
|
||||
|
||||
|
||||
export interface TypeMapCb<GlobalOmitOptions = {}> extends runtime.Types.Utils.Fn<{extArgs: runtime.Types.Extensions.InternalArgs }, runtime.Types.Utils.Record<string, any>> {
|
||||
returns: TypeMap<this['params']['extArgs'], GlobalOmitOptions>
|
||||
}
|
||||
|
||||
export type TypeMap<ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs, GlobalOmitOptions = {}> = {
|
||||
globalOmitOptions: {
|
||||
omit: GlobalOmitOptions
|
||||
}
|
||||
meta: {
|
||||
modelProps: "discordUserProfile" | "discordGuildProfile"
|
||||
txIsolationLevel: TransactionIsolationLevel
|
||||
}
|
||||
model: {
|
||||
DiscordUserProfile: {
|
||||
payload: Prisma.$DiscordUserProfilePayload<ExtArgs>
|
||||
fields: Prisma.DiscordUserProfileFieldRefs
|
||||
operations: {
|
||||
findUnique: {
|
||||
args: Prisma.DiscordUserProfileFindUniqueArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordUserProfilePayload> | null
|
||||
}
|
||||
findUniqueOrThrow: {
|
||||
args: Prisma.DiscordUserProfileFindUniqueOrThrowArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordUserProfilePayload>
|
||||
}
|
||||
findFirst: {
|
||||
args: Prisma.DiscordUserProfileFindFirstArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordUserProfilePayload> | null
|
||||
}
|
||||
findFirstOrThrow: {
|
||||
args: Prisma.DiscordUserProfileFindFirstOrThrowArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordUserProfilePayload>
|
||||
}
|
||||
findMany: {
|
||||
args: Prisma.DiscordUserProfileFindManyArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordUserProfilePayload>[]
|
||||
}
|
||||
create: {
|
||||
args: Prisma.DiscordUserProfileCreateArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordUserProfilePayload>
|
||||
}
|
||||
createMany: {
|
||||
args: Prisma.DiscordUserProfileCreateManyArgs<ExtArgs>
|
||||
result: BatchPayload
|
||||
}
|
||||
createManyAndReturn: {
|
||||
args: Prisma.DiscordUserProfileCreateManyAndReturnArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordUserProfilePayload>[]
|
||||
}
|
||||
delete: {
|
||||
args: Prisma.DiscordUserProfileDeleteArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordUserProfilePayload>
|
||||
}
|
||||
update: {
|
||||
args: Prisma.DiscordUserProfileUpdateArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordUserProfilePayload>
|
||||
}
|
||||
deleteMany: {
|
||||
args: Prisma.DiscordUserProfileDeleteManyArgs<ExtArgs>
|
||||
result: BatchPayload
|
||||
}
|
||||
updateMany: {
|
||||
args: Prisma.DiscordUserProfileUpdateManyArgs<ExtArgs>
|
||||
result: BatchPayload
|
||||
}
|
||||
updateManyAndReturn: {
|
||||
args: Prisma.DiscordUserProfileUpdateManyAndReturnArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordUserProfilePayload>[]
|
||||
}
|
||||
upsert: {
|
||||
args: Prisma.DiscordUserProfileUpsertArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordUserProfilePayload>
|
||||
}
|
||||
aggregate: {
|
||||
args: Prisma.DiscordUserProfileAggregateArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.Optional<Prisma.AggregateDiscordUserProfile>
|
||||
}
|
||||
groupBy: {
|
||||
args: Prisma.DiscordUserProfileGroupByArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.Optional<Prisma.DiscordUserProfileGroupByOutputType>[]
|
||||
}
|
||||
count: {
|
||||
args: Prisma.DiscordUserProfileCountArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.Optional<Prisma.DiscordUserProfileCountAggregateOutputType> | number
|
||||
}
|
||||
}
|
||||
}
|
||||
DiscordGuildProfile: {
|
||||
payload: Prisma.$DiscordGuildProfilePayload<ExtArgs>
|
||||
fields: Prisma.DiscordGuildProfileFieldRefs
|
||||
operations: {
|
||||
findUnique: {
|
||||
args: Prisma.DiscordGuildProfileFindUniqueArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordGuildProfilePayload> | null
|
||||
}
|
||||
findUniqueOrThrow: {
|
||||
args: Prisma.DiscordGuildProfileFindUniqueOrThrowArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordGuildProfilePayload>
|
||||
}
|
||||
findFirst: {
|
||||
args: Prisma.DiscordGuildProfileFindFirstArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordGuildProfilePayload> | null
|
||||
}
|
||||
findFirstOrThrow: {
|
||||
args: Prisma.DiscordGuildProfileFindFirstOrThrowArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordGuildProfilePayload>
|
||||
}
|
||||
findMany: {
|
||||
args: Prisma.DiscordGuildProfileFindManyArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordGuildProfilePayload>[]
|
||||
}
|
||||
create: {
|
||||
args: Prisma.DiscordGuildProfileCreateArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordGuildProfilePayload>
|
||||
}
|
||||
createMany: {
|
||||
args: Prisma.DiscordGuildProfileCreateManyArgs<ExtArgs>
|
||||
result: BatchPayload
|
||||
}
|
||||
createManyAndReturn: {
|
||||
args: Prisma.DiscordGuildProfileCreateManyAndReturnArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordGuildProfilePayload>[]
|
||||
}
|
||||
delete: {
|
||||
args: Prisma.DiscordGuildProfileDeleteArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordGuildProfilePayload>
|
||||
}
|
||||
update: {
|
||||
args: Prisma.DiscordGuildProfileUpdateArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordGuildProfilePayload>
|
||||
}
|
||||
deleteMany: {
|
||||
args: Prisma.DiscordGuildProfileDeleteManyArgs<ExtArgs>
|
||||
result: BatchPayload
|
||||
}
|
||||
updateMany: {
|
||||
args: Prisma.DiscordGuildProfileUpdateManyArgs<ExtArgs>
|
||||
result: BatchPayload
|
||||
}
|
||||
updateManyAndReturn: {
|
||||
args: Prisma.DiscordGuildProfileUpdateManyAndReturnArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordGuildProfilePayload>[]
|
||||
}
|
||||
upsert: {
|
||||
args: Prisma.DiscordGuildProfileUpsertArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.PayloadToResult<Prisma.$DiscordGuildProfilePayload>
|
||||
}
|
||||
aggregate: {
|
||||
args: Prisma.DiscordGuildProfileAggregateArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.Optional<Prisma.AggregateDiscordGuildProfile>
|
||||
}
|
||||
groupBy: {
|
||||
args: Prisma.DiscordGuildProfileGroupByArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.Optional<Prisma.DiscordGuildProfileGroupByOutputType>[]
|
||||
}
|
||||
count: {
|
||||
args: Prisma.DiscordGuildProfileCountArgs<ExtArgs>
|
||||
result: runtime.Types.Utils.Optional<Prisma.DiscordGuildProfileCountAggregateOutputType> | number
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} & {
|
||||
other: {
|
||||
payload: any
|
||||
operations: {
|
||||
$executeRaw: {
|
||||
args: [query: TemplateStringsArray | Sql, ...values: any[]],
|
||||
result: any
|
||||
}
|
||||
$executeRawUnsafe: {
|
||||
args: [query: string, ...values: any[]],
|
||||
result: any
|
||||
}
|
||||
$queryRaw: {
|
||||
args: [query: TemplateStringsArray | Sql, ...values: any[]],
|
||||
result: any
|
||||
}
|
||||
$queryRawUnsafe: {
|
||||
args: [query: string, ...values: any[]],
|
||||
result: any
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enums
|
||||
*/
|
||||
|
||||
export const TransactionIsolationLevel = runtime.makeStrictEnum({
|
||||
ReadUncommitted: 'ReadUncommitted',
|
||||
ReadCommitted: 'ReadCommitted',
|
||||
RepeatableRead: 'RepeatableRead',
|
||||
Serializable: 'Serializable'
|
||||
} as const)
|
||||
|
||||
export type TransactionIsolationLevel = (typeof TransactionIsolationLevel)[keyof typeof TransactionIsolationLevel]
|
||||
|
||||
|
||||
export const DiscordUserProfileScalarFieldEnum = {
|
||||
id: 'id',
|
||||
userId: 'userId',
|
||||
voice: 'voice',
|
||||
nya: 'nya',
|
||||
canTypecast: 'canTypecast'
|
||||
} as const
|
||||
|
||||
export type DiscordUserProfileScalarFieldEnum = (typeof DiscordUserProfileScalarFieldEnum)[keyof typeof DiscordUserProfileScalarFieldEnum]
|
||||
|
||||
|
||||
export const DiscordGuildProfileScalarFieldEnum = {
|
||||
id: 'id',
|
||||
guildId: 'guildId',
|
||||
readChannel: 'readChannel'
|
||||
} as const
|
||||
|
||||
export type DiscordGuildProfileScalarFieldEnum = (typeof DiscordGuildProfileScalarFieldEnum)[keyof typeof DiscordGuildProfileScalarFieldEnum]
|
||||
|
||||
|
||||
export const SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
} as const
|
||||
|
||||
export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder]
|
||||
|
||||
|
||||
export const QueryMode = {
|
||||
default: 'default',
|
||||
insensitive: 'insensitive'
|
||||
} as const
|
||||
|
||||
export type QueryMode = (typeof QueryMode)[keyof typeof QueryMode]
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Field references
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'String'
|
||||
*/
|
||||
export type StringFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'String'>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'String[]'
|
||||
*/
|
||||
export type ListStringFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'String[]'>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'Voice'
|
||||
*/
|
||||
export type EnumVoiceFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Voice'>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'Voice[]'
|
||||
*/
|
||||
export type ListEnumVoiceFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Voice[]'>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'Boolean'
|
||||
*/
|
||||
export type BooleanFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Boolean'>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'Int'
|
||||
*/
|
||||
export type IntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Int'>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Reference to a field of type 'Int[]'
|
||||
*/
|
||||
export type ListIntFieldRefInput<$PrismaModel> = FieldRefInputType<$PrismaModel, 'Int[]'>
|
||||
|
||||
|
||||
/**
|
||||
* Batch Payload for updateMany & deleteMany & createMany
|
||||
*/
|
||||
export type BatchPayload = {
|
||||
count: number
|
||||
}
|
||||
|
||||
export const defineExtension = runtime.Extensions.defineExtension as unknown as runtime.Types.Extensions.ExtendsHook<"define", TypeMapCb, runtime.Types.Extensions.DefaultArgs>
|
||||
export type DefaultPrismaClient = PrismaClient
|
||||
export type ErrorFormat = 'pretty' | 'colorless' | 'minimal'
|
||||
export type PrismaClientOptions = ({
|
||||
/**
|
||||
* Instance of a Driver Adapter, e.g., like one provided by `@prisma/adapter-pg`.
|
||||
*/
|
||||
adapter: runtime.SqlDriverAdapterFactory
|
||||
accelerateUrl?: never
|
||||
} | {
|
||||
/**
|
||||
* Prisma Accelerate URL allowing the client to connect through Accelerate instead of a direct database.
|
||||
*/
|
||||
accelerateUrl: string
|
||||
adapter?: never
|
||||
}) & {
|
||||
/**
|
||||
* @default "colorless"
|
||||
*/
|
||||
errorFormat?: ErrorFormat
|
||||
/**
|
||||
* @example
|
||||
* ```
|
||||
* // Shorthand for `emit: 'stdout'`
|
||||
* log: ['query', 'info', 'warn', 'error']
|
||||
*
|
||||
* // Emit as events only
|
||||
* log: [
|
||||
* { emit: 'event', level: 'query' },
|
||||
* { emit: 'event', level: 'info' },
|
||||
* { emit: 'event', level: 'warn' }
|
||||
* { emit: 'event', level: 'error' }
|
||||
* ]
|
||||
*
|
||||
* / Emit as events and log to stdout
|
||||
* og: [
|
||||
* { emit: 'stdout', level: 'query' },
|
||||
* { emit: 'stdout', level: 'info' },
|
||||
* { emit: 'stdout', level: 'warn' }
|
||||
* { emit: 'stdout', level: 'error' }
|
||||
*
|
||||
* ```
|
||||
* Read more in our [docs](https://pris.ly/d/logging).
|
||||
*/
|
||||
log?: (LogLevel | LogDefinition)[]
|
||||
/**
|
||||
* The default values for transactionOptions
|
||||
* maxWait ?= 2000
|
||||
* timeout ?= 5000
|
||||
*/
|
||||
transactionOptions?: {
|
||||
maxWait?: number
|
||||
timeout?: number
|
||||
isolationLevel?: TransactionIsolationLevel
|
||||
}
|
||||
/**
|
||||
* Global configuration for omitting model fields by default.
|
||||
*
|
||||
* @example
|
||||
* ```
|
||||
* const prisma = new PrismaClient({
|
||||
* omit: {
|
||||
* user: {
|
||||
* password: true
|
||||
* }
|
||||
* }
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
omit?: GlobalOmitConfig
|
||||
/**
|
||||
* SQL commenter plugins that add metadata to SQL queries as comments.
|
||||
* Comments follow the sqlcommenter format: https://google.github.io/sqlcommenter/
|
||||
*
|
||||
* @example
|
||||
* ```
|
||||
* const prisma = new PrismaClient({
|
||||
* adapter,
|
||||
* comments: [
|
||||
* traceContext(),
|
||||
* queryInsights(),
|
||||
* ],
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
comments?: runtime.SqlCommenterPlugin[]
|
||||
}
|
||||
export type GlobalOmitConfig = {
|
||||
discordUserProfile?: Prisma.DiscordUserProfileOmit
|
||||
discordGuildProfile?: Prisma.DiscordGuildProfileOmit
|
||||
}
|
||||
|
||||
/* Types for Logging */
|
||||
export type LogLevel = 'info' | 'query' | 'warn' | 'error'
|
||||
export type LogDefinition = {
|
||||
level: LogLevel
|
||||
emit: 'stdout' | 'event'
|
||||
}
|
||||
|
||||
export type CheckIsLogLevel<T> = T extends LogLevel ? T : never;
|
||||
|
||||
export type GetLogType<T> = CheckIsLogLevel<
|
||||
T extends LogDefinition ? T['level'] : T
|
||||
>;
|
||||
|
||||
export type GetEvents<T extends any[]> = T extends Array<LogLevel | LogDefinition>
|
||||
? GetLogType<T[number]>
|
||||
: never;
|
||||
|
||||
export type QueryEvent = {
|
||||
timestamp: Date
|
||||
query: string
|
||||
params: string
|
||||
duration: number
|
||||
target: string
|
||||
}
|
||||
|
||||
export type LogEvent = {
|
||||
timestamp: Date
|
||||
message: string
|
||||
target: string
|
||||
}
|
||||
/* End Types for Logging */
|
||||
|
||||
|
||||
export type PrismaAction =
|
||||
| 'findUnique'
|
||||
| 'findUniqueOrThrow'
|
||||
| 'findMany'
|
||||
| 'findFirst'
|
||||
| 'findFirstOrThrow'
|
||||
| 'create'
|
||||
| 'createMany'
|
||||
| 'createManyAndReturn'
|
||||
| 'update'
|
||||
| 'updateMany'
|
||||
| 'updateManyAndReturn'
|
||||
| 'upsert'
|
||||
| 'delete'
|
||||
| 'deleteMany'
|
||||
| 'executeRaw'
|
||||
| 'queryRaw'
|
||||
| 'aggregate'
|
||||
| 'count'
|
||||
| 'runCommandRaw'
|
||||
| 'findRaw'
|
||||
| 'groupBy'
|
||||
|
||||
/**
|
||||
* `PrismaClient` proxy available in interactive transactions.
|
||||
*/
|
||||
export type TransactionClient = Omit<DefaultPrismaClient, runtime.ITXClientDenyList>
|
||||
|
||||
108
packages/db/generated/prisma/internal/prismaNamespaceBrowser.ts
Normal file
108
packages/db/generated/prisma/internal/prismaNamespaceBrowser.ts
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
// @ts-nocheck
|
||||
/*
|
||||
* WARNING: This is an internal file that is subject to change!
|
||||
*
|
||||
* 🛑 Under no circumstances should you import this file directly! 🛑
|
||||
*
|
||||
* All exports from this file are wrapped under a `Prisma` namespace object in the browser.ts file.
|
||||
* While this enables partial backward compatibility, it is not part of the stable public API.
|
||||
*
|
||||
* If you are looking for your Models, Enums, and Input Types, please import them from the respective
|
||||
* model files in the `model` directory!
|
||||
*/
|
||||
|
||||
import * as runtime from "@prisma/client/runtime/index-browser"
|
||||
|
||||
export type * from '../models'
|
||||
export type * from './prismaNamespace'
|
||||
|
||||
export const Decimal = runtime.Decimal
|
||||
|
||||
|
||||
export const NullTypes = {
|
||||
DbNull: runtime.NullTypes.DbNull as (new (secret: never) => typeof runtime.DbNull),
|
||||
JsonNull: runtime.NullTypes.JsonNull as (new (secret: never) => typeof runtime.JsonNull),
|
||||
AnyNull: runtime.NullTypes.AnyNull as (new (secret: never) => typeof runtime.AnyNull),
|
||||
}
|
||||
/**
|
||||
* Helper for filtering JSON entries that have `null` on the database (empty on the db)
|
||||
*
|
||||
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
|
||||
*/
|
||||
export const DbNull = runtime.DbNull
|
||||
|
||||
/**
|
||||
* Helper for filtering JSON entries that have JSON `null` values (not empty on the db)
|
||||
*
|
||||
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
|
||||
*/
|
||||
export const JsonNull = runtime.JsonNull
|
||||
|
||||
/**
|
||||
* Helper for filtering JSON entries that are `Prisma.DbNull` or `Prisma.JsonNull`
|
||||
*
|
||||
* @see https://www.prisma.io/docs/concepts/components/prisma-client/working-with-fields/working-with-json-fields#filtering-on-a-json-field
|
||||
*/
|
||||
export const AnyNull = runtime.AnyNull
|
||||
|
||||
|
||||
export const ModelName = {
|
||||
DiscordUserProfile: 'DiscordUserProfile',
|
||||
DiscordGuildProfile: 'DiscordGuildProfile'
|
||||
} as const
|
||||
|
||||
export type ModelName = (typeof ModelName)[keyof typeof ModelName]
|
||||
|
||||
/*
|
||||
* Enums
|
||||
*/
|
||||
|
||||
export const TransactionIsolationLevel = {
|
||||
ReadUncommitted: 'ReadUncommitted',
|
||||
ReadCommitted: 'ReadCommitted',
|
||||
RepeatableRead: 'RepeatableRead',
|
||||
Serializable: 'Serializable'
|
||||
} as const
|
||||
|
||||
export type TransactionIsolationLevel = (typeof TransactionIsolationLevel)[keyof typeof TransactionIsolationLevel]
|
||||
|
||||
|
||||
export const DiscordUserProfileScalarFieldEnum = {
|
||||
id: 'id',
|
||||
userId: 'userId',
|
||||
voice: 'voice',
|
||||
nya: 'nya',
|
||||
canTypecast: 'canTypecast'
|
||||
} as const
|
||||
|
||||
export type DiscordUserProfileScalarFieldEnum = (typeof DiscordUserProfileScalarFieldEnum)[keyof typeof DiscordUserProfileScalarFieldEnum]
|
||||
|
||||
|
||||
export const DiscordGuildProfileScalarFieldEnum = {
|
||||
id: 'id',
|
||||
guildId: 'guildId',
|
||||
readChannel: 'readChannel'
|
||||
} as const
|
||||
|
||||
export type DiscordGuildProfileScalarFieldEnum = (typeof DiscordGuildProfileScalarFieldEnum)[keyof typeof DiscordGuildProfileScalarFieldEnum]
|
||||
|
||||
|
||||
export const SortOrder = {
|
||||
asc: 'asc',
|
||||
desc: 'desc'
|
||||
} as const
|
||||
|
||||
export type SortOrder = (typeof SortOrder)[keyof typeof SortOrder]
|
||||
|
||||
|
||||
export const QueryMode = {
|
||||
default: 'default',
|
||||
insensitive: 'insensitive'
|
||||
} as const
|
||||
|
||||
export type QueryMode = (typeof QueryMode)[keyof typeof QueryMode]
|
||||
|
||||
13
packages/db/generated/prisma/models.ts
Normal file
13
packages/db/generated/prisma/models.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
/* !!! This is code generated by Prisma. Do not edit directly. !!! */
|
||||
/* eslint-disable */
|
||||
// biome-ignore-all lint: generated file
|
||||
// @ts-nocheck
|
||||
/*
|
||||
* This is a barrel export file for all models and their related types.
|
||||
*
|
||||
* 🟢 You can import this file directly.
|
||||
*/
|
||||
export type * from './models/DiscordUserProfile'
|
||||
export type * from './models/DiscordGuildProfile'
|
||||
export type * from './commonInputTypes'
|
||||
1099
packages/db/generated/prisma/models/DiscordGuildProfile.ts
Normal file
1099
packages/db/generated/prisma/models/DiscordGuildProfile.ts
Normal file
File diff suppressed because it is too large
Load diff
1156
packages/db/generated/prisma/models/DiscordUserProfile.ts
Normal file
1156
packages/db/generated/prisma/models/DiscordUserProfile.ts
Normal file
File diff suppressed because it is too large
Load diff
17
packages/db/prisma.ts
Normal file
17
packages/db/prisma.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { PrismaClient } from "./generated/prisma/client";
|
||||
import { PrismaPg } from "@prisma/adapter-pg";
|
||||
import { Pool } from "pg";
|
||||
import { DATABASE_URL } from "../env"
|
||||
import { OutputHandler } from "../utils/outputHandler";
|
||||
|
||||
const pool = new Pool({ connectionString: DATABASE_URL });
|
||||
const adapter = new PrismaPg(pool);
|
||||
|
||||
pool.connect((err, client, release) => {
|
||||
if (err)
|
||||
return OutputHandler.errorLog("[PG Error]", err.message);
|
||||
|
||||
release();
|
||||
});
|
||||
|
||||
export const prisma = new PrismaClient({ adapter });
|
||||
9
packages/env.ts
Normal file
9
packages/env.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { config } from "dotenv"
|
||||
|
||||
config({ quiet: true });
|
||||
|
||||
export const DISCORD_TOKEN = process.env.DISCORD_TOKEN as string;
|
||||
export const APPLICATION_ID = process.env.APPLICATION_ID as string;
|
||||
export const GUILD_ID = process.env.GUILD_ID as string;
|
||||
export const TYPECAST_TOKENS = (process.env.TYPECAST_TOKEN as string).split(",");
|
||||
export const DATABASE_URL = process.env.DATABASE_URL as string;
|
||||
20
packages/index.ts
Normal file
20
packages/index.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { Routes } from "discord.js";
|
||||
import { DiscordBot } from "./bot";
|
||||
import { APPLICATION_ID, DISCORD_TOKEN } from "./env";
|
||||
import remove from "./cli/remove_command";
|
||||
|
||||
export const bot = new DiscordBot(DISCORD_TOKEN);
|
||||
|
||||
bot.client.once("ready", async (client) => {
|
||||
await bot.registerCommands();
|
||||
await bot.registerEvents();
|
||||
|
||||
console.log(
|
||||
"registerCommands: \n" +
|
||||
(
|
||||
(await client.rest.get(Routes.applicationCommands(APPLICATION_ID))) as any[]
|
||||
).map(info => `name: ${info.name} id: ${info.id}`).join("\n")
|
||||
);
|
||||
});
|
||||
|
||||
bot.client.login(DISCORD_TOKEN);
|
||||
95
packages/tts/index.ts
Normal file
95
packages/tts/index.ts
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import { writeFile, mkdir, stat, readFile } from "fs/promises";
|
||||
import { dirname } from "path";
|
||||
import { AudioResource, createAudioResource, StreamType } from "@discordjs/voice";
|
||||
import { Readable } from "stream";
|
||||
import { createHash } from "node:crypto";
|
||||
import { join } from "node:path";
|
||||
import { existsSync } from "node:fs";
|
||||
|
||||
export abstract class TTSModelBase<RequestId> {
|
||||
public ttsify(input: string): string {
|
||||
return input
|
||||
.replace(/:[^:]+:/g, (text: string): string => (TTSModelBase.EMOJI_MAP[text] ?? "이모지"))
|
||||
.replace(/[:*"<>|]/g, "")
|
||||
.replace(/[\t\n]/g, " ")
|
||||
}
|
||||
public abstract createRequestId(text: string): RequestId
|
||||
public abstract getVoiceBuffer(id: RequestId): Promise<ArrayBuffer>
|
||||
public abstract getVoicePath(id: RequestId): string
|
||||
|
||||
/**
|
||||
* id로 부터 음성을 생성하여 캐시 파일에 저장합니다
|
||||
* 생성된 음성을 반환합니다
|
||||
*/
|
||||
public async createVoice(id: RequestId, audioPath?: string): Promise<Buffer> {
|
||||
const voiceBuffer = await this.getVoiceBuffer(id);
|
||||
audioPath ??= this.getVoicePath(id);
|
||||
const buffer = Buffer.from(voiceBuffer);
|
||||
|
||||
await mkdir(dirname(audioPath), { recursive: true });
|
||||
await writeFile(audioPath, buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
/**
|
||||
* id로 부터 파일에 캐싱된 음성을 얻거나 없는 경우 생성합니다
|
||||
*/
|
||||
public async getVoice(id: RequestId, audioPath?: string): Promise<Buffer> {
|
||||
audioPath ??= this.getVoicePath(id);
|
||||
|
||||
if (existsSync(audioPath)) {
|
||||
const buffer = await readFile(audioPath);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
return this.createVoice(id, audioPath);
|
||||
}
|
||||
/**
|
||||
* id로 부터 메모리에 캐싱된 음성을 얻거나, 파일에 캐싱된
|
||||
* 음성을 얻거나, 없는 경우 생성합니다
|
||||
*/
|
||||
protected abstract cachedVoice: Map<String, Promise<Buffer>>
|
||||
public async getMemcachedVoice(id: RequestId): Promise<Buffer> {
|
||||
const path = this.getVoicePath(id);
|
||||
|
||||
const cached = this.cachedVoice.get(path);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
const waitter = this.getVoice(id);
|
||||
this.cachedVoice.set(path, waitter);
|
||||
setTimeout(
|
||||
() => this.cachedVoice.delete(path),
|
||||
TTSModelBase.MemCacheTTL
|
||||
);
|
||||
return await waitter;
|
||||
}
|
||||
}
|
||||
export namespace TTSModelBase {
|
||||
export const EMOJI_MAP: { [key: string]: string } = {
|
||||
":heart:": "하트",
|
||||
":huck:": "헉헉!",
|
||||
":star:": "초롱초롱!"
|
||||
}
|
||||
export const AudioCachePath = join(
|
||||
process.cwd(),
|
||||
"cache",
|
||||
"audio",
|
||||
);
|
||||
export function bufferToAudioResource(buf: Buffer): AudioResource {
|
||||
const stream = Readable.from(buf);
|
||||
const resource = createAudioResource(stream, {
|
||||
inlineVolume: true,
|
||||
inputType: StreamType.Arbitrary,
|
||||
});
|
||||
|
||||
resource.volume?.setVolume(0.3);
|
||||
return resource;
|
||||
}
|
||||
export function hashAudioFile(audio: string, suffix: string = ""): string {
|
||||
return createHash("md5").update(audio).digest("hex") + suffix + ".mp3";
|
||||
}
|
||||
export const MemCacheTTL = 60 * 60 * 1000
|
||||
}
|
||||
export default TTSModelBase;
|
||||
101
packages/tts/papago.ts
Normal file
101
packages/tts/papago.ts
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
import { createHmac } from "crypto";
|
||||
import { join } from "path";
|
||||
import fetch from "../utils/fetch";
|
||||
import TTSModelBase from ".";
|
||||
|
||||
export class TTSPapagoModel extends TTSModelBase<TTSPapagoModel.RequestId> {
|
||||
protected cachedVoice: Map<String, Promise<Buffer>>
|
||||
constructor() {
|
||||
super()
|
||||
this.cachedVoice = new Map();
|
||||
}
|
||||
public getVoicePath(id: TTSPapagoModel.RequestId): string {
|
||||
const audioFileName = TTSModelBase.hashAudioFile(id.text, `.${id.speaker}.${id.speed.replace(/\-/g, "_")}`);
|
||||
const audioPath = join(
|
||||
TTSPapagoModel.PapagoAudioCachePath,
|
||||
audioFileName
|
||||
);
|
||||
return audioPath;
|
||||
}
|
||||
async getVoiceBuffer(id: TTSPapagoModel.RequestId, voiceId?: string): Promise<ArrayBuffer> {
|
||||
voiceId ??= await TTSPapagoModel.getVoiceId(id)
|
||||
const response = await fetch(`https://papago.naver.com/apis/tts/${voiceId}`);
|
||||
return await response.arrayBuffer();
|
||||
}
|
||||
createRequestId(text: string, speaker?: string, speed?: string): TTSPapagoModel.RequestId {
|
||||
return {
|
||||
text,
|
||||
speed: speed ?? "-1",
|
||||
speaker: speaker ?? "kyuri",
|
||||
};
|
||||
}
|
||||
}
|
||||
export namespace TTSPapagoModel {
|
||||
export const instance = new TTSPapagoModel();
|
||||
export type RequestId = {
|
||||
speaker: string;
|
||||
speed: string;
|
||||
text: string;
|
||||
};
|
||||
export const GenerateTokenKey = "v1.9.3_3bdf0438a8";
|
||||
export function hmacMD5(key: string, plaintext: string) {
|
||||
const hmac = createHmac("md5", key);
|
||||
const data = hmac.update(plaintext);
|
||||
|
||||
return data.digest("base64");
|
||||
}
|
||||
export function generateToken(time: number) {
|
||||
const e = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (e) => {
|
||||
var t = (time + 16 * Math.random()) % 16 | 0;
|
||||
return (time = Math.floor(time / 16)), ("x" === e ? t : (3 & t) | 8).toString(16);
|
||||
});
|
||||
|
||||
const plain = `${e}\n${"https://papago.naver.com/apis/tts/makeID"}\n${time}`;
|
||||
|
||||
return `PPG ${e}:${hmacMD5(GenerateTokenKey, plain)}`;
|
||||
}
|
||||
export async function getVoiceId(id: RequestId): Promise<string> {
|
||||
const input = {
|
||||
alpha: "0",
|
||||
pitch: "0",
|
||||
speaker: id.speaker,
|
||||
speed: id.speed,
|
||||
text: id.text,
|
||||
};
|
||||
|
||||
const time = new Date().getTime();
|
||||
const token = TTSPapagoModel.generateToken(time);
|
||||
|
||||
const reqbody = new URLSearchParams(Object.entries(input)).toString();
|
||||
const response = await fetch("https://papago.naver.com/apis/tts/makeID", {
|
||||
headers: {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
|
||||
Accept: "application/json",
|
||||
"Accept-Language": "en",
|
||||
"Sec-GPC": "1",
|
||||
"Sec-Fetch-Dest": "empty",
|
||||
"Sec-Fetch-Mode": "no-cors",
|
||||
"Sec-Fetch-Site": "same-origin",
|
||||
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
Authorization: token,
|
||||
Timestamp: time.toString(),
|
||||
Pragma: "no-cache",
|
||||
"Cache-Control": "no-cache",
|
||||
},
|
||||
referrer: "https://papago.naver.com/",
|
||||
body: reqbody,
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`TTS makeID request failed: ${response.status}: ${await response.text()}`);
|
||||
}
|
||||
|
||||
return ((await response.json()) as any).id;
|
||||
}
|
||||
export const PapagoAudioCachePath = join(
|
||||
TTSModelBase.AudioCachePath,
|
||||
"papago"
|
||||
);
|
||||
}
|
||||
export default TTSPapagoModel;
|
||||
176
packages/tts/typecast.ts
Normal file
176
packages/tts/typecast.ts
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
import { join } from "path";
|
||||
import { TYPECAST_TOKENS } from "../env";
|
||||
import fetch from "../utils/fetch";
|
||||
import TTSModelBase from ".";
|
||||
import CallingNumberKorean from "../utils/callingNumberKorean";
|
||||
import IntegerKorean from "../utils/integerKorean";
|
||||
import FloatKorean from "../utils/floatKorean";
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
import { cwd, env } from "process";
|
||||
|
||||
export class TTSTypecastModel extends TTSModelBase<TTSTypecastModel.RequestId> {
|
||||
protected cachedVoice: Map<String, Promise<Buffer>>
|
||||
private lastUseApiKeyPath: string
|
||||
constructor() {
|
||||
super()
|
||||
this.cachedVoice = new Map();
|
||||
this.lastUseApiKeyPath = join(cwd(), "cache", "typecast", "lastUseApiToken");
|
||||
}
|
||||
ttsify(input: string): string {
|
||||
|
||||
return super.ttsify(
|
||||
input
|
||||
.replace(/\.+$/, "")
|
||||
.replace(/\.\.+/g, "")
|
||||
.replace(/\.[ \t]/g, " ")
|
||||
.replace(/^[\?\!\'\"]+$/, (total)=>(
|
||||
[...total].map(element => TTSTypecastModel.IsolatedSymbolMap[
|
||||
element as keyof typeof TTSTypecastModel.IsolatedSymbolMap
|
||||
]).join("")
|
||||
))
|
||||
.replace(/\`\`\`.+?\`\`\`/g, "코드블럭")
|
||||
.replace(/https\S+/g, "링크")
|
||||
.replace(/ㄴㄴ/g, "노노")
|
||||
.replace(/ㅇㅋ/g, "오키")
|
||||
.replace(/ㅜㅜ/g, "눙물")
|
||||
.replace(/빵/g, "빵 크크")
|
||||
.replace(/[\?]+ *ㄴ/g, "물음표ㄴ")
|
||||
.replace(/(\d+)[ \t\n]*([개살])/g, (_, num: string, postfix: string)=>{
|
||||
const intNum = parseInt(num)
|
||||
if (CallingNumberKorean.canConvert(intNum)) {
|
||||
return CallingNumberKorean.convert(intNum) + postfix;
|
||||
} else {
|
||||
return IntegerKorean.convertFromString(num) + postfix;
|
||||
}
|
||||
})
|
||||
.replace(/(v?)([\d\.]+)([ab]?)/g, (_, suffix: string, num: string, postfix: string) => {
|
||||
const dotCount = [...num.matchAll(/\./g)].length;
|
||||
const hasNoSuffix = suffix == "";
|
||||
|
||||
if (hasNoSuffix && dotCount == 0) {
|
||||
return IntegerKorean.convertFromString(num) + postfix;
|
||||
} else if (hasNoSuffix && dotCount == 1) {
|
||||
const [intPart, floatPart] = num.split(/\./);
|
||||
return (
|
||||
IntegerKorean.convertFromString(intPart)
|
||||
+ "쩜"
|
||||
+ FloatKorean.convert(floatPart)
|
||||
+ postfix
|
||||
)
|
||||
} else if (suffix == "v") {
|
||||
return (
|
||||
"버전"
|
||||
+ FloatKorean.convert(num)
|
||||
+ (TTSTypecastModel.VersionPostfix[
|
||||
postfix as keyof typeof TTSTypecastModel.VersionPostfix
|
||||
] ?? "")
|
||||
);
|
||||
} else {
|
||||
return FloatKorean.convert(num) + postfix;
|
||||
}
|
||||
})
|
||||
.replace(/[\%\^\&\*\#\@\.\-\+\_\=\/\\♡\$]/g, (t) => (
|
||||
TTSTypecastModel.SymbolMap[t as keyof typeof TTSTypecastModel.SymbolMap]
|
||||
))
|
||||
.replace(/\?+/g, "?")
|
||||
.replace(/\!+/g, "!")
|
||||
)
|
||||
}
|
||||
private async getTypecastResponse(apiKey: string, voiceId: TTSTypecastModel.RequestId) {
|
||||
const payload = {
|
||||
text: voiceId.text,
|
||||
model: "ssfm-v21",
|
||||
voice_id: voiceId.voiceId,
|
||||
language: "kor",
|
||||
prompt: {
|
||||
emotion_preset: "happy", // Options: normal, happy, sad, angry, tonemid, toneup
|
||||
emotion_intensity: 1 // Range: 0.0 to 2.0
|
||||
},
|
||||
output: {
|
||||
volume: 45, // Range: 0 to 200
|
||||
audio_pitch: 1, // Range: -12 to +12 semitones
|
||||
audio_tempo: 1, // Range: 0.5x to 2.0x
|
||||
audio_format: "mp3" // Options: wav, mp3
|
||||
},
|
||||
seed: 22 // For reproducible results
|
||||
};
|
||||
|
||||
return await fetch(TTSTypecastModel.TypecastApiUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"X-API-KEY": apiKey,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
}
|
||||
async getVoiceBuffer(voiceId: TTSTypecastModel.RequestId): Promise<ArrayBuffer> {
|
||||
let response: Response | undefined;
|
||||
|
||||
for (let i = 0; i < TYPECAST_TOKENS.length; i++) {
|
||||
response = await this.getTypecastResponse(readFileSync(this.lastUseApiKeyPath, "utf-8"), voiceId) as Response;
|
||||
|
||||
if (response.ok)
|
||||
return await response.arrayBuffer();;
|
||||
|
||||
if (response.status === 402) {
|
||||
writeFileSync(this.lastUseApiKeyPath, TYPECAST_TOKENS[i]);
|
||||
} else {
|
||||
throw new Error(`TTS makeID request failed: ${response.status}: ${await response.text()}`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
throw new Error("Typecast Api use all credit");
|
||||
}
|
||||
public getVoicePath(id: TTSTypecastModel.RequestId): string {
|
||||
const audioFileName = TTSModelBase.hashAudioFile(id.text);
|
||||
const audioPath = join(
|
||||
TTSTypecastModel.TypecastAudioCachePath,
|
||||
id.voiceId,
|
||||
audioFileName
|
||||
);
|
||||
return audioPath;
|
||||
}
|
||||
public createRequestId(text: string, voiceId?: string): TTSTypecastModel.RequestId {
|
||||
return {
|
||||
text,
|
||||
voiceId: voiceId ?? TTSTypecastModel.DefaultVoiceId,
|
||||
};
|
||||
}
|
||||
}
|
||||
export namespace TTSTypecastModel {
|
||||
export const IsolatedSymbolMap = {
|
||||
"?": "물음표",
|
||||
"!": "느낌표",
|
||||
"'": "쿼트",
|
||||
"\"": "더블쿼트",
|
||||
}
|
||||
export const SymbolMap = {
|
||||
"%": "퍼센트",
|
||||
"$": "달러싸인",
|
||||
"^": "캐럿",
|
||||
"&": "엠퍼센드",
|
||||
"*": "스타",
|
||||
"#": "해시",
|
||||
"@": "엣",
|
||||
".": "쩜",
|
||||
"-": "마이너스",
|
||||
"+": "플러스",
|
||||
"_": "언더바",
|
||||
"=": "이퀄",
|
||||
"/": "슬래쉬",
|
||||
"\\": "역슬래쉬",
|
||||
"♡": "하투 ",
|
||||
};
|
||||
export const VersionPostfix = {
|
||||
"a": "알파",
|
||||
"b": "베타",
|
||||
};
|
||||
export const instance = new TTSTypecastModel();
|
||||
export type RequestId = { text: string, voiceId: string };
|
||||
export const TypecastAudioCachePath = join(TTSModelBase.AudioCachePath, "typecast");
|
||||
export const TypecastApiUrl = "https://api.typecast.ai/v1/text-to-speech";
|
||||
export const DefaultVoiceId = "tc_6731b292d944a485bc406efb";
|
||||
}
|
||||
export default TTSTypecastModel;
|
||||
31
packages/utils/callingNumberKorean.ts
Normal file
31
packages/utils/callingNumberKorean.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
export default class CallingNumberKorean {
|
||||
// 개, 살 이 붙는 경우 발음법
|
||||
static SecondDigit = [
|
||||
"열", "스물", "서른", "마흔", "쉰",
|
||||
"예순", "일흔", "여든", "아흔",
|
||||
]
|
||||
static FirstDigit = [
|
||||
"", "한", "두", "세", "네", "다섯",
|
||||
"여섯", "일곱", "여덟", "아홉", "열",
|
||||
]
|
||||
static FirstDigitSingle = [
|
||||
"영", "한", "두", "세", "네", "다섯",
|
||||
"여섯", "일곱", "여덟", "아홉", "열",
|
||||
]
|
||||
static canConvert(num: number): boolean {
|
||||
return num < 100 && num >= 0 && !Number.isInteger(num)
|
||||
}
|
||||
static convert(num: number): string {
|
||||
const firstDigit = num % 10;
|
||||
const secondDigit = Math.floor(num / 10);
|
||||
|
||||
if (secondDigit) {
|
||||
return (
|
||||
this.SecondDigit[secondDigit]
|
||||
+ this.FirstDigit[firstDigit]
|
||||
);
|
||||
} else {
|
||||
return this.FirstDigitSingle[firstDigit];
|
||||
}
|
||||
}
|
||||
}
|
||||
15
packages/utils/fetch.ts
Normal file
15
packages/utils/fetch.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { Response as NodeFetchResponse, RequestInit, RequestInfo } from "node-fetch";
|
||||
import defaultFetch from "node-fetch";
|
||||
|
||||
export default async function(url: URL | RequestInfo, request: RequestInit={}, time: number=5000): Promise<NodeFetchResponse | Response> {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), time);
|
||||
|
||||
request.signal ??= controller.signal;
|
||||
|
||||
try {
|
||||
return await defaultFetch(url, request);;
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
}
|
||||
16
packages/utils/floatKorean.ts
Normal file
16
packages/utils/floatKorean.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
export default class FloatKorean {
|
||||
static Digits = [
|
||||
"영", "일", "이", "삼", "사", "오", "육", "칠", "팔", "구"
|
||||
];
|
||||
static convert(num: string): string {
|
||||
const buf = new Array(num.length);
|
||||
for (let idx = 0; idx < num.length; idx++) {
|
||||
if (num[idx] == ".") {
|
||||
buf[idx] = "쩜";
|
||||
} else {
|
||||
buf[idx] = this.Digits[+num[idx]];
|
||||
}
|
||||
}
|
||||
return buf.join("");
|
||||
}
|
||||
}
|
||||
109
packages/utils/integerKorean.ts
Normal file
109
packages/utils/integerKorean.ts
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
export default class IntegerKorean {
|
||||
static DigitName = [ "영", "일", "이", "삼", "사", "오", "육", "칠", "팔", "구" ];
|
||||
static DigitModifier = ["", "십", "백", "천"];
|
||||
static Unit = [ "", "만", "억", "조", "경", "해", "자", "양", "구", "간", "정", "재", "극", "항하사", "아승기", "나유타", "불가사의", "무량대수" ];
|
||||
|
||||
private static stringifyKDigits(
|
||||
first: number, second: number, third: number, forth: number
|
||||
): string {
|
||||
const buf = [];
|
||||
|
||||
if (forth) {
|
||||
if (forth >= 2) buf.push(this.DigitName[forth]);
|
||||
buf.push(this.DigitModifier[3]);
|
||||
}
|
||||
if (third) {
|
||||
if (third >= 2) buf.push(this.DigitName[third]);
|
||||
buf.push(this.DigitModifier[2]);
|
||||
}
|
||||
if (second) {
|
||||
if (second >= 2) buf.push(this.DigitName[second]);
|
||||
buf.push(this.DigitModifier[1]);
|
||||
}
|
||||
if (first || (!forth && !third && !second)) {
|
||||
buf.push(this.DigitName[first]);
|
||||
}
|
||||
|
||||
return buf.join("");
|
||||
}
|
||||
private static parseKDigitsFromNumber(num: number): string {
|
||||
const first = num % 10;
|
||||
const second = Math.floor(num / 10) % 10;
|
||||
const third = Math.floor(num / 100) % 10;
|
||||
const forth = Math.floor(num / 1000) % 10;
|
||||
|
||||
return this.stringifyKDigits(first, second, third, forth);
|
||||
}
|
||||
private static parseKDigitsFromString(num: string, offset: number): string {
|
||||
const first = +num[offset];
|
||||
const second = offset >= 1 ? +num[offset - 1] : 0;
|
||||
const third = offset >= 2 ? +num[offset - 2] : 0;
|
||||
const forth = offset >= 3 ? +num[offset - 3] : 0;
|
||||
|
||||
return this.stringifyKDigits(first, second, third, forth);
|
||||
}
|
||||
|
||||
static convertFromString(num: string): string {
|
||||
let isNegative = false;
|
||||
if (num.startsWith("-")) {
|
||||
num = num.slice(1, -1);
|
||||
isNegative = true;
|
||||
}
|
||||
if (num == "0") {
|
||||
return isNegative ? "마이너스영" : "영";
|
||||
}
|
||||
|
||||
const unitStack = [];
|
||||
let offset = num.length - 1;
|
||||
while (offset >= 0) {
|
||||
unitStack.push(this.parseKDigitsFromString(num, offset));
|
||||
offset -= 4;
|
||||
}
|
||||
|
||||
const buf = [];
|
||||
if (isNegative) buf.push("마이너스");
|
||||
for (let i = unitStack.length - 1; i >= 0; i--) {
|
||||
const currUnit = this.Unit[i];
|
||||
let currKDigits = unitStack[i];
|
||||
|
||||
if (currKDigits == "영") continue;
|
||||
if (i == 1 && currKDigits == "일")
|
||||
currKDigits = "";
|
||||
|
||||
buf.push(currKDigits + currUnit);
|
||||
}
|
||||
|
||||
return buf.join("");
|
||||
}
|
||||
static convertFromNumber(num: number): string {
|
||||
let isNegative = false;
|
||||
if (num < 0) {
|
||||
isNegative = true;
|
||||
num *= -1;
|
||||
}
|
||||
if (num == 0) {
|
||||
return "영";
|
||||
}
|
||||
|
||||
const unitStack = [];
|
||||
while (num) {
|
||||
unitStack.push(this.parseKDigitsFromNumber(num));
|
||||
num = Math.floor(num / 10000);
|
||||
}
|
||||
|
||||
const buf = [];
|
||||
if (isNegative) buf.push("마이너스");
|
||||
for (let i = unitStack.length - 1; i >= 0; i--) {
|
||||
const currUnit = this.Unit[i];
|
||||
let currKDigits = unitStack[i];
|
||||
|
||||
if (currKDigits == "영") continue;
|
||||
if (i == 1 && currKDigits == "일")
|
||||
currKDigits = "";
|
||||
|
||||
buf.push(currKDigits + currUnit);
|
||||
}
|
||||
|
||||
return buf.join("");
|
||||
}
|
||||
}
|
||||
137
packages/utils/nyaize.ts
Normal file
137
packages/utils/nyaize.ts
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
export const nyaWords = {
|
||||
'나': "냐",
|
||||
'낙': "냑",
|
||||
'낚': "냒",
|
||||
'낛': "냓",
|
||||
'난': "냔",
|
||||
'낝': "냕",
|
||||
'낞': "냖",
|
||||
'낟': "냗",
|
||||
'날': "냘",
|
||||
'낡': "냙",
|
||||
'낢': "냚",
|
||||
'낣': "냛",
|
||||
'낤': "냜",
|
||||
'낥': "냝",
|
||||
'낦': "냞",
|
||||
'낧': "냟",
|
||||
'남': "냠",
|
||||
'납': "냡",
|
||||
'낪': "냢",
|
||||
'낫': "냣",
|
||||
'났': "냤",
|
||||
'낭': "냥",
|
||||
'낮': "냦",
|
||||
'낯': "냧",
|
||||
'낰': "냨",
|
||||
'낱': "냩",
|
||||
'낲': "냪",
|
||||
'낳': "냫",
|
||||
};
|
||||
|
||||
export const nyaWords2 = {
|
||||
'내': "냥",
|
||||
'넹': "냥",
|
||||
'넴': "냥",
|
||||
'넵': "냥",
|
||||
'냐': "냥",
|
||||
'님': "냥",
|
||||
'니': "냥",
|
||||
'다': "다냥",
|
||||
'까': "까냥",
|
||||
'네': "네냥",
|
||||
'야': "야냥",
|
||||
'꺼': "꺼냥",
|
||||
'래': "래냥",
|
||||
'해': "해냥",
|
||||
'지': "지냥",
|
||||
'라': "라냥",
|
||||
'요': "요냥",
|
||||
'가': "가냥",
|
||||
'데': "데냥",
|
||||
'돼': "돼냥",
|
||||
'줘': "줘냥",
|
||||
'마': "마냥",
|
||||
'와': "와냥",
|
||||
'어': "어냥",
|
||||
'자': "자냥",
|
||||
'죠': "죠냥",
|
||||
'서': "서냥",
|
||||
'게': "게냥",
|
||||
};
|
||||
|
||||
function replacePunctuation(input: string): string {
|
||||
return input.replace(/(^|\s)([?!,.;~^@()]+)/g, (match, p1, p2) => {
|
||||
const firstChar = p2[0];
|
||||
let transformed;
|
||||
|
||||
if (firstChar === '?') transformed = '냥?';
|
||||
else if (firstChar === '!') transformed = '냥!';
|
||||
else if (firstChar === ',') transformed = '냥,';
|
||||
else if (firstChar === '.') transformed = '냥.';
|
||||
else if (firstChar === ';') transformed = '냥;';
|
||||
else if (firstChar === '~') transformed = '냥~';
|
||||
else if (firstChar === '^') transformed = '냥^';
|
||||
else if (firstChar === '@') transformed = '냥@';
|
||||
else if (firstChar === '(') transformed = '냥(';
|
||||
else if (firstChar === ')') transformed = '냥)';
|
||||
else transformed = p2;
|
||||
|
||||
return p1 + transformed + p2.slice(1);
|
||||
});
|
||||
}
|
||||
|
||||
function addNyangAtMWord(sentence: string): string {
|
||||
return sentence.split(' ').map((word) => {
|
||||
const match = word.match(/^([가-힣]+)([?!,.;~^@()]*)$/);
|
||||
|
||||
if (!match) return word;
|
||||
|
||||
const baseWord = match[1];
|
||||
const punctuation = match[2];
|
||||
|
||||
const lastChar = baseWord[baseWord.length - 1];
|
||||
const charCode = lastChar.charCodeAt(0);
|
||||
|
||||
if (charCode >= 0xAC00 && charCode <= 0xD7A3) {
|
||||
const baseCode = charCode - 0xAC00;
|
||||
const jongseong = baseCode % 28;
|
||||
|
||||
if (jongseong === 16) {
|
||||
return baseWord + "냥" + punctuation;
|
||||
}
|
||||
}
|
||||
|
||||
return word;
|
||||
}).join(' ');
|
||||
}
|
||||
|
||||
export function nyaize(text: string): string {
|
||||
for (let key in nyaWords2) {
|
||||
text = text.replaceAll(key + ".", nyaWords2[key as keyof typeof nyaWords2] + "."); // yeah I gotta optimize these
|
||||
text = text.replaceAll(key + ",", nyaWords2[key as keyof typeof nyaWords2] + ",");
|
||||
text = text.replaceAll(key + "?", nyaWords2[key as keyof typeof nyaWords2] + "?");
|
||||
text = text.replaceAll(key + "!", nyaWords2[key as keyof typeof nyaWords2] + "!");
|
||||
text = text.replaceAll(key + ";", nyaWords2[key as keyof typeof nyaWords2] + ";");
|
||||
text = text.replaceAll(key + "~", nyaWords2[key as keyof typeof nyaWords2] + "~");
|
||||
text = text.replaceAll(key + "^", nyaWords2[key as keyof typeof nyaWords2] + "^");
|
||||
text = text.replaceAll(key + "@", nyaWords2[key as keyof typeof nyaWords2] + "@");
|
||||
text = text.replaceAll(key + "(", nyaWords2[key as keyof typeof nyaWords2] + "(");
|
||||
text = text.replaceAll(key + ")", nyaWords2[key as keyof typeof nyaWords2] + ")");
|
||||
text = text.replaceAll(key + " ", nyaWords2[key as keyof typeof nyaWords2] + " ");
|
||||
|
||||
if (text.endsWith(key)) {
|
||||
text = text.slice(0, -1) + nyaWords2[key as keyof typeof nyaWords2];
|
||||
}
|
||||
}
|
||||
|
||||
for (let key in nyaWords) {
|
||||
text = text.replaceAll(key, nyaWords[key as keyof typeof nyaWords]);
|
||||
}
|
||||
|
||||
text = replacePunctuation(text);
|
||||
|
||||
text = addNyangAtMWord(text);
|
||||
|
||||
return text;
|
||||
}
|
||||
40
packages/utils/outputHandler.ts
Normal file
40
packages/utils/outputHandler.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import { dirname, join } from "path";
|
||||
import { mkdir, open, readFile } from "fs/promises"
|
||||
|
||||
export namespace OutputHandler {
|
||||
export const LogCachePath = join(
|
||||
process.cwd(),
|
||||
"cache",
|
||||
"log",
|
||||
);
|
||||
export const ErrorLogPath = join(LogCachePath, "error.log" );
|
||||
export function getErrorOutput(...args: any[]) {
|
||||
const timestamp = new Date().toISOString();
|
||||
|
||||
const message = args
|
||||
.map(arg => {
|
||||
if (arg instanceof Error) {
|
||||
return `${arg.name}: ${arg.message}\n${arg.stack}`;
|
||||
}
|
||||
if (typeof arg === 'object') {
|
||||
return JSON.stringify(arg);
|
||||
}
|
||||
return String(arg);
|
||||
})
|
||||
.join(' ');
|
||||
|
||||
|
||||
return `[${timestamp}] ${message}`;
|
||||
}
|
||||
export async function errorLog(...args: any[]): Promise<void> {
|
||||
const output = getErrorOutput(...args);
|
||||
await mkdir(dirname(ErrorLogPath), { recursive: true });
|
||||
|
||||
const fileHandle = await open(ErrorLogPath, "a");
|
||||
fileHandle.write(output + "\n");
|
||||
fileHandle.close();
|
||||
}
|
||||
export async function getErrorLog(): Promise<string> {
|
||||
return (await readFile(ErrorLogPath)).toString();
|
||||
}
|
||||
}
|
||||
13
packages/utils/requireDirectory.ts
Normal file
13
packages/utils/requireDirectory.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { readdirSync } from "fs";
|
||||
import { readdir } from "fs/promises";
|
||||
import { join } from "path";
|
||||
|
||||
export async function requireDirectory<T>(directory: string): Promise<T[]> {
|
||||
const requireFiles = (await readdir(directory)).filter(file => file.endsWith(".js"));
|
||||
return requireFiles.map(file => require(join(directory, file)).default as T);
|
||||
}
|
||||
|
||||
export function requireDirectorySync<T>(directory: string): T[] {
|
||||
const requireFiles = readdirSync(directory).filter(file => file.endsWith(".js"));
|
||||
return requireFiles.map(file => require(join(directory, file)).default as T).filter(x=>x);
|
||||
}
|
||||
2305
pnpm-lock.yaml
Normal file
2305
pnpm-lock.yaml
Normal file
File diff suppressed because it is too large
Load diff
14
prisma.config.ts
Normal file
14
prisma.config.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// This file was generated by Prisma, and assumes you have installed the following:
|
||||
// npm install --save-dev prisma dotenv
|
||||
import "dotenv/config";
|
||||
import { defineConfig } from "prisma/config";
|
||||
|
||||
export default defineConfig({
|
||||
schema: "prisma/schema.prisma",
|
||||
migrations: {
|
||||
path: "prisma/migrations",
|
||||
},
|
||||
datasource: {
|
||||
url: process.env["DATABASE_URL"],
|
||||
},
|
||||
});
|
||||
34
prisma/schema.prisma
Normal file
34
prisma/schema.prisma
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
||||
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client"
|
||||
specifying = ["prismaSchemaFolder"]
|
||||
output = "../packages/db/generated/prisma"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
}
|
||||
|
||||
enum Voice {
|
||||
TypeCast
|
||||
Papago
|
||||
}
|
||||
|
||||
model DiscordUserProfile {
|
||||
id String @id @default(cuid())
|
||||
userId String @unique
|
||||
voice Voice @default(Papago)
|
||||
nya Boolean @default(false)
|
||||
canTypecast Boolean @default(false)
|
||||
}
|
||||
|
||||
model DiscordGuildProfile {
|
||||
id String @id @default(cuid())
|
||||
guildId String @unique
|
||||
readChannel String[] @default([])
|
||||
}
|
||||
14
tsconfig.json
Normal file
14
tsconfig.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES6",
|
||||
"module": "commonjs",
|
||||
"lib": [ "ES2021", "DOM", "DOM.Iterable" ],
|
||||
"moduleResolution": "node",
|
||||
"outDir": "dist",
|
||||
"strict": true,
|
||||
"exactOptionalPropertyTypes": false,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": ["./packages/**/*"]
|
||||
}
|
||||
Loading…
Reference in a new issue