mirror of
https://github.com/ReVanced/revanced-bots.git
synced 2026-01-12 06:06:21 +00:00
Compare commits
33 Commits
@revanced/
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c8740e489 | ||
|
|
6fe15301a2 | ||
|
|
6885e18976 | ||
|
|
42038e6b38 | ||
|
|
51c0252b44 | ||
|
|
399c201f8c | ||
|
|
0a5a9c3e27 | ||
|
|
50a205c430 | ||
|
|
dd3e7d2ee0 | ||
|
|
567c5d2c7f | ||
|
|
8cc2377cbf | ||
|
|
f3c199d573 | ||
|
|
42c0facef1 | ||
|
|
96a9b83c48 | ||
|
|
fbd9480036 | ||
|
|
cc02c0a775 | ||
|
|
c83e219088 | ||
|
|
6164e6c1a5 | ||
|
|
47d2f8c015 | ||
|
|
c68cfd1c01 | ||
|
|
2b1928e116 | ||
|
|
670cc70057 | ||
|
|
439f301872 | ||
|
|
aeccf12906 | ||
|
|
b4ac8433f4 | ||
|
|
b01a4accee | ||
|
|
858e989bdc | ||
|
|
3a0f0fe786 | ||
|
|
409e850768 | ||
|
|
6e89b874cd | ||
|
|
b4a5c62549 | ||
|
|
495f686292 | ||
|
|
71eb11b67f |
5
.github/workflows/release.yml
vendored
5
.github/workflows/release.yml
vendored
@@ -20,11 +20,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
|
||||||
# Make sure the release step uses its own credentials:
|
|
||||||
# https://github.com/cycjimmy/semantic-release-action#private-packages
|
|
||||||
persist-credentials: false
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Cache dependencies
|
- name: Cache dependencies
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
|
|||||||
@@ -1,3 +1,12 @@
|
|||||||
|
# @revanced/bot-websocket-api [1.1.0](https://github.com/revanced/revanced-bots/compare/@revanced/bot-websocket-api@1.0.2...@revanced/bot-websocket-api@1.1.0) (2025-07-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **apis/websocket:** support training without label ([670cc70](https://github.com/revanced/revanced-bots/commit/670cc700570b32924738c3f24acb9f5312d2dcdb))
|
||||||
|
|
||||||
|
## @revanced/bot-websocket-api [1.0.2](https://github.com/revanced/revanced-bots/compare/@revanced/bot-websocket-api@1.0.1...@revanced/bot-websocket-api@1.0.2) (2025-06-23)
|
||||||
|
|
||||||
## @revanced/bot-websocket-api [1.0.1](https://github.com/revanced/revanced-bots/compare/@revanced/bot-websocket-api@1.0.0...@revanced/bot-websocket-api@1.0.1) (2025-04-09)
|
## @revanced/bot-websocket-api [1.0.1](https://github.com/revanced/revanced-bots/compare/@revanced/bot-websocket-api@1.0.0...@revanced/bot-websocket-api@1.0.1) (2025-04-09)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "@revanced/bot-websocket-api",
|
"name": "@revanced/bot-websocket-api",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.1",
|
"version": "1.1.0",
|
||||||
"description": "🧦 WebSocket API server for bots assisting ReVanced",
|
"description": "🧦 WebSocket API server for bots assisting ReVanced",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -29,9 +29,9 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@revanced/bot-shared": "workspace:*",
|
"@revanced/bot-shared": "workspace:*",
|
||||||
"@sapphire/async-queue": "^1.5.5",
|
"@sapphire/async-queue": "^1.5.5",
|
||||||
"chalk": "^5.4.1",
|
"chalk": "^5.6.2",
|
||||||
"tesseract.js": "^5.1.1",
|
"tesseract.js": "^6.0.1",
|
||||||
"ws": "^8.18.1"
|
"ws": "^8.18.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import { EventEmitter } from 'events'
|
|
||||||
import {
|
import {
|
||||||
ClientOperation,
|
ClientOperation,
|
||||||
DisconnectReason,
|
DisconnectReason,
|
||||||
type Packet,
|
|
||||||
ServerOperation,
|
|
||||||
deserializePacket,
|
deserializePacket,
|
||||||
isClientPacket,
|
isClientPacket,
|
||||||
|
type Packet,
|
||||||
|
ServerOperation,
|
||||||
serializePacket,
|
serializePacket,
|
||||||
uncapitalize,
|
uncapitalize,
|
||||||
} from '@revanced/bot-shared'
|
} from '@revanced/bot-shared'
|
||||||
|
import { EventEmitter } from 'events'
|
||||||
import type TypedEmitter from 'typed-emitter'
|
import type TypedEmitter from 'typed-emitter'
|
||||||
import type { RawData, WebSocket } from 'ws'
|
import type { RawData, WebSocket } from 'ws'
|
||||||
|
|
||||||
@@ -100,7 +99,7 @@ export default class Client {
|
|||||||
// @ts-expect-error TypeScript doesn't know that the above line will negate the type enough
|
// @ts-expect-error TypeScript doesn't know that the above line will negate the type enough
|
||||||
packet,
|
packet,
|
||||||
)
|
)
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
// TODO: add error fields to sent packet so we can log what went wrong
|
// TODO: add error fields to sent packet so we can log what went wrong
|
||||||
this.disconnect(DisconnectReason.InvalidPacket)
|
this.disconnect(DisconnectReason.InvalidPacket)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { OEM, createWorker as createTesseractWorker } from 'tesseract.js'
|
|
||||||
|
|
||||||
import { join as joinPath } from 'path'
|
|
||||||
import { createLogger } from '@revanced/bot-shared'
|
import { createLogger } from '@revanced/bot-shared'
|
||||||
import { exists as pathExists } from 'fs/promises'
|
import { exists as pathExists } from 'fs/promises'
|
||||||
|
import { join as joinPath } from 'path'
|
||||||
|
import { createWorker as createTesseractWorker, OEM } from 'tesseract.js'
|
||||||
import { getConfig } from './utils/config'
|
import { getConfig } from './utils/config'
|
||||||
|
|
||||||
export const config = getConfig()
|
export const config = getConfig()
|
||||||
@@ -24,12 +23,12 @@ export const wit = {
|
|||||||
|
|
||||||
if (!res.ok) throw new Error(`Failed to fetch from Wit.ai: ${res.statusText} (${res.status})`)
|
if (!res.ok) throw new Error(`Failed to fetch from Wit.ai: ${res.statusText} (${res.status})`)
|
||||||
|
|
||||||
return await res.json()
|
return (await res.json()) as WitMessageResponse
|
||||||
},
|
},
|
||||||
message(text: string) {
|
message(text: string) {
|
||||||
return this.fetch(`/message?q=${encodeURIComponent(text)}&n=8`) as Promise<WitMessageResponse>
|
return this.fetch(`/message?q=${encodeURIComponent(text)}&n=8`) as Promise<WitMessageResponse>
|
||||||
},
|
},
|
||||||
async train(text: string, label: string) {
|
async train(text: string, label?: string) {
|
||||||
await this.fetch('/utterances', {
|
await this.fetch('/utterances', {
|
||||||
body: JSON.stringify([
|
body: JSON.stringify([
|
||||||
{
|
{
|
||||||
@@ -42,7 +41,14 @@ export const wit = {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
} as const
|
} satisfies Wit
|
||||||
|
|
||||||
|
export interface Wit {
|
||||||
|
token: string
|
||||||
|
fetch(route: string, options?: RequestInit): Promise<WitMessageResponse>
|
||||||
|
message(text: string): Promise<WitMessageResponse>
|
||||||
|
train(text: string, label?: string): Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
export interface WitMessageResponse {
|
export interface WitMessageResponse {
|
||||||
text: string
|
text: string
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import type { ClientOperation } from '@revanced/bot-shared'
|
import type { ClientOperation, Logger } from '@revanced/bot-shared'
|
||||||
import type { Logger } from '@revanced/bot-shared'
|
|
||||||
import type { Worker as TesseractWorker } from 'tesseract.js'
|
import type { Worker as TesseractWorker } from 'tesseract.js'
|
||||||
import type { ClientPacketObject } from '../classes/Client'
|
import type { ClientPacketObject } from '../classes/Client'
|
||||||
import type { WitMessageResponse } from '../context'
|
import type { Wit } from '../context'
|
||||||
import type { Config } from '../utils/config'
|
import type { Config } from '../utils/config'
|
||||||
|
|
||||||
export { default as parseTextEventHandler } from './parseText'
|
|
||||||
export { default as parseImageEventHandler } from './parseImage'
|
export { default as parseImageEventHandler } from './parseImage'
|
||||||
|
export { default as parseTextEventHandler } from './parseText'
|
||||||
export { default as trainMessageEventHandler } from './trainMessage'
|
export { default as trainMessageEventHandler } from './trainMessage'
|
||||||
|
|
||||||
export type EventHandler<POp extends ClientOperation> = (
|
export type EventHandler<POp extends ClientOperation> = (
|
||||||
@@ -15,10 +14,7 @@ export type EventHandler<POp extends ClientOperation> = (
|
|||||||
) => void | Promise<void>
|
) => void | Promise<void>
|
||||||
|
|
||||||
export type EventContext = {
|
export type EventContext = {
|
||||||
wit: {
|
wit: Wit
|
||||||
train(text: string, label: string): Promise<void>
|
|
||||||
message(text: string): Promise<WitMessageResponse>
|
|
||||||
}
|
|
||||||
tesseract: TesseractWorker
|
tesseract: TesseractWorker
|
||||||
logger: Logger
|
logger: Logger
|
||||||
config: Config
|
config: Config
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { type ClientOperation, ServerOperation } from '@revanced/bot-shared'
|
import { type ClientOperation, ServerOperation } from '@revanced/bot-shared'
|
||||||
import { AsyncQueue } from '@sapphire/async-queue'
|
import { AsyncQueue } from '@sapphire/async-queue'
|
||||||
|
|
||||||
import type { EventHandler } from '.'
|
import type { EventHandler } from '.'
|
||||||
|
|
||||||
const queue = new AsyncQueue()
|
const queue = new AsyncQueue()
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { type ClientOperation, ServerOperation } from '@revanced/bot-shared'
|
import { type ClientOperation, ServerOperation } from '@revanced/bot-shared'
|
||||||
|
|
||||||
import type { EventHandler } from '.'
|
import type { EventHandler } from '.'
|
||||||
|
|
||||||
const parseTextEventHandler: EventHandler<ClientOperation.ParseText> = async (packet, { wit, logger }) => {
|
const parseTextEventHandler: EventHandler<ClientOperation.ParseText> = async (packet, { wit, logger }) => {
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { type ClientOperation, ServerOperation } from '@revanced/bot-shared'
|
import { type ClientOperation, ServerOperation } from '@revanced/bot-shared'
|
||||||
|
|
||||||
import type { EventHandler } from '.'
|
import type { EventHandler } from '.'
|
||||||
|
|
||||||
const trainMessageEventHandler: EventHandler<ClientOperation.TrainMessage> = async (packet, { wit, logger }) => {
|
const trainMessageEventHandler: EventHandler<ClientOperation.TrainMessage> = async (packet, { wit, logger }) => {
|
||||||
@@ -11,7 +10,7 @@ const trainMessageEventHandler: EventHandler<ClientOperation.TrainMessage> = asy
|
|||||||
const nextSeq = client.currentSequence++
|
const nextSeq = client.currentSequence++
|
||||||
const actualText = text.slice(0, 279)
|
const actualText = text.slice(0, 279)
|
||||||
|
|
||||||
logger.debug(`${client.id} requested to train label ${label} (${nextSeq}) with:`, actualText)
|
logger.debug(`${client.id} requested to train label ${label ?? '<out of scope>'} (${nextSeq}) with:`, actualText)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await wit.train(actualText, label)
|
await wit.train(actualText, label)
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
import { inspect as inspectObject } from 'util'
|
|
||||||
|
|
||||||
import Client from './classes/Client'
|
|
||||||
|
|
||||||
import { type EventContext, parseImageEventHandler, parseTextEventHandler, trainMessageEventHandler } from './events'
|
|
||||||
|
|
||||||
import { DisconnectReason, HumanizedDisconnectReason } from '@revanced/bot-shared'
|
import { DisconnectReason, HumanizedDisconnectReason } from '@revanced/bot-shared'
|
||||||
|
|
||||||
import { createServer } from 'http'
|
import { createServer } from 'http'
|
||||||
|
import { inspect as inspectObject } from 'util'
|
||||||
import { type WebSocket, WebSocketServer } from 'ws'
|
import { type WebSocket, WebSocketServer } from 'ws'
|
||||||
|
import Client from './classes/Client'
|
||||||
import { config, logger, tesseract, wit } from './context'
|
import { config, logger, tesseract, wit } from './context'
|
||||||
|
import { type EventContext, parseImageEventHandler, parseTextEventHandler, trainMessageEventHandler } from './events'
|
||||||
|
|
||||||
// Load config, init logger, check environment
|
// Load config, init logger, check environment
|
||||||
|
|
||||||
|
|||||||
37
biome.json
37
biome.json
@@ -1,6 +1,20 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://biomejs.dev/schemas/1.8.2/schema.json",
|
"$schema": "https://biomejs.dev/schemas/2.0.5/schema.json",
|
||||||
"organizeImports": {
|
"assist": {
|
||||||
|
"actions": {
|
||||||
|
"source": {
|
||||||
|
"organizeImports": {
|
||||||
|
"level": "on",
|
||||||
|
"options": {
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"type": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"enabled": true
|
"enabled": true
|
||||||
},
|
},
|
||||||
"linter": {
|
"linter": {
|
||||||
@@ -24,7 +38,15 @@
|
|||||||
},
|
},
|
||||||
"useNumberNamespace": {
|
"useNumberNamespace": {
|
||||||
"level": "off"
|
"level": "off"
|
||||||
}
|
},
|
||||||
|
"noParameterAssign": "error",
|
||||||
|
"useAsConstAssertion": "error",
|
||||||
|
"useDefaultParameterLast": "error",
|
||||||
|
"useSelfClosingElements": "error",
|
||||||
|
"useSingleVarDeclarator": "error",
|
||||||
|
"noUnusedTemplateLiteral": "error",
|
||||||
|
"noInferrableTypes": "error",
|
||||||
|
"noUselessElse": "error"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -54,7 +76,12 @@
|
|||||||
},
|
},
|
||||||
"files": {
|
"files": {
|
||||||
"ignoreUnknown": true,
|
"ignoreUnknown": true,
|
||||||
"include": ["*.js", "*.json", "*.ts"],
|
"includes": [
|
||||||
"ignore": ["dist/**/*", "node_modules/**/*"]
|
"**/*.js",
|
||||||
|
"**/*.json",
|
||||||
|
"**/*.ts",
|
||||||
|
"!**/dist/**/*",
|
||||||
|
"!**/node_modules/**/*"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,80 @@
|
|||||||
|
## @revanced/discord-bot [1.5.2](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.5.1...@revanced/discord-bot@1.5.2) (2025-09-25)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bots/discord:** correct `respondToReply` logic ([6fe1530](https://github.com/revanced/revanced-bots/commit/6fe15301a21fdc196fded8d6fb13236a7bb826f5))
|
||||||
|
|
||||||
|
## @revanced/discord-bot [1.5.1](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.5.0...@revanced/discord-bot@1.5.1) (2025-09-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bots/discord:** only fetch reference when it exists when `respondToReply` is set ([42038e6](https://github.com/revanced/revanced-bots/commit/42038e6b38983fefe79481359bad300dcb5e83b4))
|
||||||
|
|
||||||
|
# @revanced/discord-bot [1.5.0](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.4.1...@revanced/discord-bot@1.5.0) (2025-09-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **bots/discord:** add additional options for `respondToReply` ([399c201](https://github.com/revanced/revanced-bots/commit/399c201f8c3e9e116050b49c2ffccdd79b02f39b))
|
||||||
|
|
||||||
|
## @revanced/discord-bot [1.4.1](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.4.0...@revanced/discord-bot@1.4.1) (2025-09-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bots/discord/database:** use non-deprecated way to create indexes ([8cc2377](https://github.com/revanced/revanced-bots/commit/8cc2377cbfcc74c2c3228ed18da2495b4efd45aa))
|
||||||
|
* **bots/discord:** allow partial users ([dd3e7d2](https://github.com/revanced/revanced-bots/commit/dd3e7d2ee0cdf40e083af7f6db35ac3508ddf763))
|
||||||
|
* **bots/discord:** error in cache `keepOverLimit` comparison ([567c5d2](https://github.com/revanced/revanced-bots/commit/567c5d2c7f41dae7d7fec9946a7dd2ac1b10cc2a))
|
||||||
|
|
||||||
|
# @revanced/discord-bot [1.4.0](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.3.0...@revanced/discord-bot@1.4.0) (2025-07-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bots/discord:** pass non-empty out of scope label to discord ([fbd9480](https://github.com/revanced/revanced-bots/commit/fbd948003631b48a1914eb7b2551ead4b05089b7))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **bots/discord:** react to label classified response ([96a9b83](https://github.com/revanced/revanced-bots/commit/96a9b83c486fdc6e78f4c59e197fa6c1dab09161))
|
||||||
|
|
||||||
|
# @revanced/discord-bot [1.3.0](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.2.3...@revanced/discord-bot@1.3.0) (2025-07-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **bots/discord:** support training without label ([c68cfd1](https://github.com/revanced/revanced-bots/commit/c68cfd1c01703fad17f233ad4e13cf81913afbb6))
|
||||||
|
|
||||||
|
## @revanced/discord-bot [1.2.3](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.2.2...@revanced/discord-bot@1.2.3) (2025-06-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bots/discord:** disable unneeded cache, enable message cache sweeping ([3a0f0fe](https://github.com/revanced/revanced-bots/commit/3a0f0fe7861d73a4d81ecaba0e12bd60c06f8eb8))
|
||||||
|
|
||||||
|
## @revanced/discord-bot [1.2.2](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.2.1...@revanced/discord-bot@1.2.2) (2025-06-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bots/discord:** use intervals for checking expired presets ([6e89b87](https://github.com/revanced/revanced-bots/commit/6e89b874cdfee8a1c215559271c741f43ba578ce))
|
||||||
|
|
||||||
|
## @revanced/discord-bot [1.2.1](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.2.0...@revanced/discord-bot@1.2.1) (2025-05-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **bots/discord:** fix timeout overflow check for role presets ([495f686](https://github.com/revanced/revanced-bots/commit/495f686292ebdcf51902c1dc75ac1510d7fdbd9c))
|
||||||
|
|
||||||
|
# @revanced/discord-bot [1.2.0](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.1.2...@revanced/discord-bot@1.2.0) (2025-05-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **bots/discord:** switch duration parser to `@sapphire/duration` ([04ce825](https://github.com/revanced/revanced-bots/commit/04ce8252c05a23dbb4a91fded4f1a3d63b5c8a64))
|
||||||
|
|
||||||
## @revanced/discord-bot [1.1.2](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.1.1...@revanced/discord-bot@1.1.2) (2025-04-16)
|
## @revanced/discord-bot [1.1.2](https://github.com/revanced/revanced-bots/compare/@revanced/discord-bot@1.1.1...@revanced/discord-bot@1.1.2) (2025-04-16)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
humanCorrections: {
|
humanCorrections: {
|
||||||
falsePositiveLabel: 'false_positive',
|
|
||||||
allow: {
|
allow: {
|
||||||
members: {
|
members: {
|
||||||
permissions: 8n,
|
permissions: 8n,
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ export type Config = {
|
|||||||
blacklist?: Filter
|
blacklist?: Filter
|
||||||
}
|
}
|
||||||
humanCorrections: {
|
humanCorrections: {
|
||||||
falsePositiveLabel: string
|
|
||||||
allow?: {
|
allow?: {
|
||||||
users?: string[]
|
users?: string[]
|
||||||
members?: {
|
members?: {
|
||||||
@@ -72,8 +71,8 @@ export type ConfigMessageScanResponse = {
|
|||||||
image?: Array<RegExp>
|
image?: Array<RegExp>
|
||||||
}
|
}
|
||||||
filterOverride?: NonNullable<Config['messageScan']>['filter']
|
filterOverride?: NonNullable<Config['messageScan']>['filter']
|
||||||
response: ConfigMessageScanResponseMessage | null
|
response: ConfigMessageScanResponseMessage
|
||||||
respondToReply?: boolean
|
respondToReply?: boolean | 'only_regex' | 'only_labeled'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ConfigMessageScanResponseLabelConfig = {
|
export type ConfigMessageScanResponseLabelConfig = {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "@revanced/discord-bot",
|
"name": "@revanced/discord-bot",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.1.2",
|
"version": "1.5.2",
|
||||||
"description": "🤖 Discord bot assisting ReVanced",
|
"description": "🤖 Discord bot assisting ReVanced",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -28,19 +28,19 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/revanced/revanced-bots#readme",
|
"homepage": "https://github.com/revanced/revanced-bots#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/builders": "^1.10.1",
|
"@discordjs/builders": "^1.11.3",
|
||||||
"@discordjs/rest": "^2.4.3",
|
"@discordjs/rest": "^2.6.0",
|
||||||
"@revanced/bot-api": "workspace:*",
|
"@revanced/bot-api": "workspace:*",
|
||||||
"@revanced/bot-shared": "workspace:*",
|
"@revanced/bot-shared": "workspace:*",
|
||||||
"@sapphire/duration": "^1.2.0",
|
"@sapphire/duration": "^1.2.0",
|
||||||
"chalk": "^5.4.1",
|
"chalk": "^5.6.2",
|
||||||
"decancer": "^3.2.8",
|
"decancer": "^3.3.3",
|
||||||
"discord.js": "^14.18.0",
|
"discord.js": "^14.22.1",
|
||||||
"drizzle-orm": "^0.31.4"
|
"drizzle-orm": "^0.44.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@libsql/client": "^0.7.0",
|
"@libsql/client": "^0.15.15",
|
||||||
"discord-api-types": "^0.37.119",
|
"discord-api-types": "^0.38.24",
|
||||||
"drizzle-kit": "^0.22.8"
|
"drizzle-kit": "^0.31.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
import { ApplicationCommandOptionType, ApplicationCommandType } from 'discord.js'
|
import { ApplicationCommandOptionType, ApplicationCommandType } from 'discord.js'
|
||||||
|
import { config } from '../context'
|
||||||
import { isAdmin } from '../utils/discord/permissions'
|
import { isAdmin } from '../utils/discord/permissions'
|
||||||
|
|
||||||
import CommandError, { CommandErrorType } from './CommandError'
|
import CommandError, { CommandErrorType } from './CommandError'
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
APIApplicationCommandChannelOption,
|
APIApplicationCommandChannelOption,
|
||||||
CacheType,
|
CacheType,
|
||||||
@@ -20,7 +19,6 @@ import type {
|
|||||||
UserContextMenuCommandInteraction,
|
UserContextMenuCommandInteraction,
|
||||||
UserResolvable,
|
UserResolvable,
|
||||||
} from 'discord.js'
|
} from 'discord.js'
|
||||||
import { config } from '../context'
|
|
||||||
|
|
||||||
export enum CommandType {
|
export enum CommandType {
|
||||||
ChatGlobal = 1,
|
ChatGlobal = 1,
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
|
import { ApplicationCommandOptionType, MessageFlags } from 'discord.js'
|
||||||
import { unlinkSync, writeFileSync } from 'fs'
|
import { unlinkSync, writeFileSync } from 'fs'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { inspect } from 'util'
|
import { inspect } from 'util'
|
||||||
import { createContext, runInContext } from 'vm'
|
import { createContext, runInContext } from 'vm'
|
||||||
import { ApplicationCommandOptionType, MessageFlags } from 'discord.js'
|
|
||||||
|
|
||||||
import { AdminCommand } from '$/classes/Command'
|
import { AdminCommand } from '$/classes/Command'
|
||||||
import { createSuccessEmbed } from '$/utils/discord/embeds'
|
import { createSuccessEmbed } from '$/utils/discord/embeds'
|
||||||
import { parseDuration } from '$/utils/duration'
|
import { parseDuration } from '$/utils/duration'
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { ApplicationCommandOptionType } from 'discord.js'
|
import { ApplicationCommandOptionType } from 'discord.js'
|
||||||
|
|
||||||
import { AdminCommand } from '$/classes/Command'
|
import { AdminCommand } from '$/classes/Command'
|
||||||
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { AdminCommand } from '$/classes/Command'
|
|
||||||
import { type CommandInteraction, MessageFlags } from 'discord.js'
|
import { type CommandInteraction, MessageFlags } from 'discord.js'
|
||||||
|
import { AdminCommand } from '$/classes/Command'
|
||||||
|
|
||||||
export default new AdminCommand({
|
export default new AdminCommand({
|
||||||
name: 'reload',
|
name: 'reload',
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { ApplicationCommandOptionType, Routes } from 'discord.js'
|
import { ApplicationCommandOptionType, Routes } from 'discord.js'
|
||||||
|
|
||||||
import { AdminCommand } from '$/classes/Command'
|
import { AdminCommand } from '$/classes/Command'
|
||||||
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
||||||
|
|
||||||
import { createSuccessEmbed } from '$/utils/discord/embeds'
|
import { createSuccessEmbed } from '$/utils/discord/embeds'
|
||||||
|
|
||||||
const SubcommandOptions = {
|
const SubcommandOptions = {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { AdminCommand } from '$/classes/Command'
|
|
||||||
import { MessageFlags } from 'discord.js'
|
import { MessageFlags } from 'discord.js'
|
||||||
|
import { AdminCommand } from '$/classes/Command'
|
||||||
|
|
||||||
export default new AdminCommand({
|
export default new AdminCommand({
|
||||||
name: 'stop',
|
name: 'stop',
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { EmbedBuilder, MessageFlags } from 'discord.js'
|
import { EmbedBuilder, MessageFlags } from 'discord.js'
|
||||||
|
|
||||||
import Command from '$/classes/Command'
|
import Command from '$/classes/Command'
|
||||||
import { applyCommonEmbedStyles } from '$/utils/discord/embeds'
|
import { applyCommonEmbedStyles } from '$/utils/discord/embeds'
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
|
||||||
import { ApplicationCommandOptionType, Message, MessageFlags } from 'discord.js'
|
import { ApplicationCommandOptionType, Message, MessageFlags } from 'discord.js'
|
||||||
|
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
||||||
import { ModerationCommand } from '../../classes/Command'
|
import { ModerationCommand } from '../../classes/Command'
|
||||||
|
|
||||||
export default new ModerationCommand({
|
export default new ModerationCommand({
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
import { MessageFlags } from 'discord.js'
|
||||||
import { ModerationCommand } from '$/classes/Command'
|
import { ModerationCommand } from '$/classes/Command'
|
||||||
import { createSuccessEmbed } from '$/utils/discord/embeds'
|
import { createSuccessEmbed } from '$/utils/discord/embeds'
|
||||||
import { cureNickname } from '$/utils/discord/moderation'
|
import { cureNickname } from '$/utils/discord/moderation'
|
||||||
import { MessageFlags } from 'discord.js'
|
|
||||||
|
|
||||||
export default new ModerationCommand({
|
export default new ModerationCommand({
|
||||||
name: 'cure',
|
name: 'cure',
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
|||||||
import { createModerationActionEmbed } from '$/utils/discord/embeds'
|
import { createModerationActionEmbed } from '$/utils/discord/embeds'
|
||||||
import { sendModerationReplyAndLogs } from '$/utils/discord/moderation'
|
import { sendModerationReplyAndLogs } from '$/utils/discord/moderation'
|
||||||
import { applyRolePreset, removeRolePreset } from '$/utils/discord/rolePresets'
|
import { applyRolePreset, removeRolePreset } from '$/utils/discord/rolePresets'
|
||||||
import { parseDuration } from '$/utils/duration'
|
import { isSafeTimeoutDuration, parseDuration } from '$/utils/duration'
|
||||||
|
|
||||||
export default new ModerationCommand({
|
export default new ModerationCommand({
|
||||||
name: 'mute',
|
name: 'mute',
|
||||||
@@ -63,7 +63,7 @@ export default new ModerationCommand({
|
|||||||
createModerationActionEmbed('Muted', user, executor.user, reason, Math.ceil(expires / 1000)),
|
createModerationActionEmbed('Muted', user, executor.user, reason, Math.ceil(expires / 1000)),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (Number.isSafeInteger(expires))
|
if (isSafeTimeoutDuration(duration))
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
removeRolePreset(member, 'mute')
|
removeRolePreset(member, 'mute')
|
||||||
}, duration)
|
}, duration)
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { EmbedBuilder } from 'discord.js'
|
import { EmbedBuilder } from 'discord.js'
|
||||||
|
|
||||||
import { ModerationCommand } from '$/classes/Command'
|
import { ModerationCommand } from '$/classes/Command'
|
||||||
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
||||||
import { applyCommonEmbedStyles } from '$/utils/discord/embeds'
|
import { applyCommonEmbedStyles } from '$/utils/discord/embeds'
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { ModerationCommand } from '$/classes/Command'
|
|||||||
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
||||||
import { sendPresetReplyAndLogs } from '$/utils/discord/moderation'
|
import { sendPresetReplyAndLogs } from '$/utils/discord/moderation'
|
||||||
import { applyRolePreset, removeRolePreset } from '$/utils/discord/rolePresets'
|
import { applyRolePreset, removeRolePreset } from '$/utils/discord/rolePresets'
|
||||||
import { parseDuration } from '$/utils/duration'
|
import { isSafeTimeoutDuration, parseDuration } from '$/utils/duration'
|
||||||
|
|
||||||
const SubcommandOptions = {
|
const SubcommandOptions = {
|
||||||
member: {
|
member: {
|
||||||
@@ -78,7 +78,7 @@ export default new ModerationCommand({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Number.isSafeInteger(expires))
|
if (expires && isSafeTimeoutDuration(expires))
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
removeRolePreset(member, preset)
|
removeRolePreset(member, preset)
|
||||||
}, expires)
|
}, expires)
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { createSuccessEmbed } from '$/utils/discord/embeds'
|
import { ChannelType } from 'discord.js'
|
||||||
import { durationToString, parseDuration } from '$/utils/duration'
|
|
||||||
|
|
||||||
import { ModerationCommand } from '$/classes/Command'
|
import { ModerationCommand } from '$/classes/Command'
|
||||||
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
||||||
import { ChannelType } from 'discord.js'
|
import { createSuccessEmbed } from '$/utils/discord/embeds'
|
||||||
|
import { durationToString, parseDuration } from '$/utils/duration'
|
||||||
|
|
||||||
export default new ModerationCommand({
|
export default new ModerationCommand({
|
||||||
name: 'slowmode',
|
name: 'slowmode',
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
|
import { and, eq } from 'drizzle-orm'
|
||||||
import { ModerationCommand } from '$/classes/Command'
|
import { ModerationCommand } from '$/classes/Command'
|
||||||
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
||||||
import { appliedPresets } from '$/database/schemas'
|
import { appliedPresets } from '$/database/schemas'
|
||||||
import { createModerationActionEmbed } from '$/utils/discord/embeds'
|
import { createModerationActionEmbed } from '$/utils/discord/embeds'
|
||||||
import { sendModerationReplyAndLogs } from '$/utils/discord/moderation'
|
import { sendModerationReplyAndLogs } from '$/utils/discord/moderation'
|
||||||
import { removeRolePreset } from '$/utils/discord/rolePresets'
|
import { removeRolePreset } from '$/utils/discord/rolePresets'
|
||||||
import { and, eq } from 'drizzle-orm'
|
|
||||||
|
|
||||||
export default new ModerationCommand({
|
export default new ModerationCommand({
|
||||||
name: 'unmute',
|
name: 'unmute',
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
|
import { type FetchMessageOptions, MessageFlags, type MessageResolvable } from 'discord.js'
|
||||||
import Command from '$/classes/Command'
|
import Command from '$/classes/Command'
|
||||||
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
||||||
import { createSuccessEmbed } from '$/utils/discord/embeds'
|
import { createSuccessEmbed } from '$/utils/discord/embeds'
|
||||||
import type { ConfigMessageScanResponseLabelConfig } from 'config.schema'
|
|
||||||
import { type FetchMessageOptions, MessageFlags, type MessageResolvable } from 'discord.js'
|
|
||||||
import { config } from '../../../context'
|
import { config } from '../../../context'
|
||||||
|
import type { ConfigMessageScanResponseLabelConfig } from 'config.schema'
|
||||||
|
|
||||||
const msRcConfig = config.messageScan?.humanCorrections?.allow
|
const msRcConfig = config.messageScan?.humanCorrections?.allow
|
||||||
|
|
||||||
export default new Command({
|
export default new Command({
|
||||||
name: 'train',
|
name: 'train',
|
||||||
description: 'Train a specific message or text to a specific label',
|
description: 'Train a specific message to a specific label',
|
||||||
type: Command.Type.ChatGuild,
|
type: Command.Type.ChatGuild,
|
||||||
requirements: {
|
requirements: {
|
||||||
users: msRcConfig?.users,
|
users: msRcConfig?.users,
|
||||||
@@ -26,9 +26,9 @@ export default new Command({
|
|||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
description: 'The label to train the message as',
|
description: 'The label to train the message as (leave empty for out of scope)',
|
||||||
type: Command.OptionType.String,
|
type: Command.OptionType.String,
|
||||||
required: true,
|
required: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
allowMessageCommand: true,
|
allowMessageCommand: true,
|
||||||
@@ -49,7 +49,7 @@ export default new Command({
|
|||||||
'This command can only be used in or on text channels',
|
'This command can only be used in or on text channels',
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!labels.includes(label))
|
if (label && !labels.includes(label))
|
||||||
throw new CommandError(
|
throw new CommandError(
|
||||||
CommandErrorType.InvalidArgument,
|
CommandErrorType.InvalidArgument,
|
||||||
`The provided label is invalid.\nValid labels are:${labels.map(l => `\n- \`${l}\``).join('')}`,
|
`The provided label is invalid.\nValid labels are:${labels.map(l => `\n- \`${l}\``).join('')}`,
|
||||||
@@ -60,14 +60,14 @@ export default new Command({
|
|||||||
)
|
)
|
||||||
if (!refMsg) throw new CommandError(CommandErrorType.InvalidArgument, 'The provided message does not exist.')
|
if (!refMsg) throw new CommandError(CommandErrorType.InvalidArgument, 'The provided message does not exist.')
|
||||||
|
|
||||||
logger.debug(`User ${context.executor.id} is training message ${refMsg?.id} as ${label}`)
|
logger.debug(`User ${context.executor.id} is training message ${refMsg?.id} as ${label ?? 'out of scope'}`)
|
||||||
|
|
||||||
await context.api.client.trainMessage(refMsg.content, label)
|
await context.api.client.trainMessage(refMsg.content, label)
|
||||||
await trigger.reply({
|
await trigger.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
createSuccessEmbed(
|
createSuccessEmbed(
|
||||||
'Message trained',
|
'Message trained',
|
||||||
`The provided message has been trained as \`${label}\`. Thank you for your contribution!`,
|
`The provided message has been trained as ${label ? `\`${label}\`` : 'out of scope'}. Thank you for your contribution!`,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
flags: MessageFlags.Ephemeral,
|
flags: MessageFlags.Ephemeral,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import { type APIStringSelectComponent, ComponentType, MessageFlags } from 'discord.js'
|
||||||
import Command from '$/classes/Command'
|
import Command from '$/classes/Command'
|
||||||
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
import CommandError, { CommandErrorType } from '$/classes/CommandError'
|
||||||
import type { ConfigMessageScanResponseLabelConfig } from 'config.schema'
|
|
||||||
import { type APIStringSelectComponent, ComponentType, MessageFlags } from 'discord.js'
|
|
||||||
import { config } from '../../../context'
|
import { config } from '../../../context'
|
||||||
|
import type { ConfigMessageScanResponseLabelConfig } from 'config.schema'
|
||||||
|
|
||||||
const msRcConfig = config.messageScan?.humanCorrections?.allow
|
const msRcConfig = config.messageScan?.humanCorrections?.allow
|
||||||
|
|
||||||
@@ -37,7 +37,10 @@ export default new Command({
|
|||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
custom_id: `tr_${trigger.targetMessage.channelId}_${trigger.targetId}`,
|
custom_id: `tr_${trigger.targetMessage.channelId}_${trigger.targetId}`,
|
||||||
options: labels.map(label => ({ label, value: label })),
|
options: [
|
||||||
|
...labels.map(label => ({ label, value: label })),
|
||||||
|
{ label: 'Out of scope', value: OutOfScopeLabel, emoji: { name: '❌' } },
|
||||||
|
],
|
||||||
type: ComponentType.StringSelect,
|
type: ComponentType.StringSelect,
|
||||||
} satisfies APIStringSelectComponent,
|
} satisfies APIStringSelectComponent,
|
||||||
],
|
],
|
||||||
@@ -48,3 +51,5 @@ export default new Command({
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const OutOfScopeLabel = '<out of scope>'
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
import { Database } from 'bun:sqlite'
|
import { Database } from 'bun:sqlite'
|
||||||
import { existsSync, readFileSync, readdirSync } from 'fs'
|
|
||||||
import { join } from 'path'
|
|
||||||
import { Client as APIClient } from '@revanced/bot-api'
|
import { Client as APIClient } from '@revanced/bot-api'
|
||||||
import { createLogger } from '@revanced/bot-shared'
|
import { createLogger } from '@revanced/bot-shared'
|
||||||
import { Client as DiscordClient, type Message, Partials } from 'discord.js'
|
import { Client as DiscordClient, type Message, Options, Partials } from 'discord.js'
|
||||||
import { drizzle } from 'drizzle-orm/bun-sqlite'
|
import { drizzle } from 'drizzle-orm/bun-sqlite'
|
||||||
|
import { existsSync, readdirSync, readFileSync } from 'fs'
|
||||||
import * as schemas from './database/schemas'
|
import { join } from 'path'
|
||||||
|
|
||||||
import type { default as Command, CommandOptionsOptions, CommandType } from './classes/Command'
|
|
||||||
|
|
||||||
import { __getConfig, config } from './config'
|
import { __getConfig, config } from './config'
|
||||||
|
import * as schemas from './database/schemas'
|
||||||
|
import type { default as Command, CommandOptionsOptions, CommandType } from './classes/Command'
|
||||||
export { config, __getConfig }
|
export { config, __getConfig }
|
||||||
|
|
||||||
export const logger = createLogger({
|
export const logger = createLogger({
|
||||||
@@ -80,7 +77,52 @@ export const discord = {
|
|||||||
parse: ['users'],
|
parse: ['users'],
|
||||||
repliedUser: true,
|
repliedUser: true,
|
||||||
},
|
},
|
||||||
partials: [Partials.Message, Partials.Reaction, Partials.GuildMember],
|
sweepers: {
|
||||||
|
...Options.DefaultSweeperSettings,
|
||||||
|
messages: {
|
||||||
|
interval: 1_800, // Every 30m
|
||||||
|
lifetime: 3_600, // Remove messages older than 1h
|
||||||
|
},
|
||||||
|
},
|
||||||
|
makeCache: Options.cacheWithLimits({
|
||||||
|
...Options.DefaultMakeCacheSettings,
|
||||||
|
UserManager: 50,
|
||||||
|
GuildMemberManager: {
|
||||||
|
maxSize: 50,
|
||||||
|
// Always keep client guild member in cache
|
||||||
|
keepOverLimit: member => member.id === member.client.user.id,
|
||||||
|
},
|
||||||
|
ThreadManager: {
|
||||||
|
maxSize: 0,
|
||||||
|
// Always keep threads that are used for moderation logging
|
||||||
|
keepOverLimit: thread => config.moderation?.log?.thread === thread.id,
|
||||||
|
},
|
||||||
|
GuildMessageManager: {
|
||||||
|
maxSize: 0,
|
||||||
|
// Always keep messages posted by the client in cache
|
||||||
|
keepOverLimit: message => message.author?.id === message.client.user.id,
|
||||||
|
},
|
||||||
|
// Unneeded cache
|
||||||
|
MessageManager: 0,
|
||||||
|
ReactionManager: 0,
|
||||||
|
VoiceStateManager: 0,
|
||||||
|
ThreadMemberManager: 0,
|
||||||
|
StageInstanceManager: 0,
|
||||||
|
ReactionUserManager: 0,
|
||||||
|
PresenceManager: 0,
|
||||||
|
GuildTextThreadManager: 0,
|
||||||
|
GuildStickerManager: 0,
|
||||||
|
DMMessageManager: 0,
|
||||||
|
GuildEmojiManager: 0,
|
||||||
|
GuildBanManager: 0,
|
||||||
|
GuildScheduledEventManager: 0,
|
||||||
|
EntitlementManager: 0,
|
||||||
|
AutoModerationRuleManager: 0,
|
||||||
|
GuildForumThreadManager: 0,
|
||||||
|
BaseGuildEmojiManager: 0,
|
||||||
|
GuildInviteManager: 0,
|
||||||
|
}),
|
||||||
|
partials: [Partials.Message, Partials.Reaction, Partials.GuildMember, Partials.User],
|
||||||
}),
|
}),
|
||||||
commands: Object.fromEntries(Object.values(commands).map(cmd => [cmd.name, cmd])) as Record<
|
commands: Object.fromEntries(Object.values(commands).map(cmd => [cmd.name, cmd])) as Record<
|
||||||
string,
|
string,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { InferSelectModel } from 'drizzle-orm'
|
|
||||||
import { integer, sqliteTable, text, uniqueIndex } from 'drizzle-orm/sqlite-core'
|
import { integer, sqliteTable, text, uniqueIndex } from 'drizzle-orm/sqlite-core'
|
||||||
|
import type { InferSelectModel } from 'drizzle-orm'
|
||||||
|
|
||||||
export const responses = sqliteTable('responses', {
|
export const responses = sqliteTable('responses', {
|
||||||
replyId: text('reply').primaryKey().notNull(),
|
replyId: text('reply').primaryKey().notNull(),
|
||||||
@@ -20,9 +20,7 @@ export const appliedPresets = sqliteTable(
|
|||||||
preset: text('preset').notNull(),
|
preset: text('preset').notNull(),
|
||||||
until: integer('until'),
|
until: integer('until'),
|
||||||
},
|
},
|
||||||
table => ({
|
table => [uniqueIndex('unique_composite').on(table.memberId, table.preset, table.guildId)],
|
||||||
uniqueComposite: uniqueIndex('unique_composite').on(table.memberId, table.preset, table.guildId),
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
export type Response = InferSelectModel<typeof responses>
|
export type Response = InferSelectModel<typeof responses>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { on, withContext } from '$utils/api/events'
|
|
||||||
import { DisconnectReason, HumanizedDisconnectReason } from '@revanced/bot-shared'
|
import { DisconnectReason, HumanizedDisconnectReason } from '@revanced/bot-shared'
|
||||||
|
import { on, withContext } from '$utils/api/events'
|
||||||
|
|
||||||
withContext(on, 'disconnect', ({ api, config, logger }, reason, msg) => {
|
withContext(on, 'disconnect', ({ api, config, logger }, reason, msg) => {
|
||||||
if (reason === DisconnectReason.PlannedDisconnect && api.intentionallyDisconnecting) return
|
if (reason === DisconnectReason.PlannedDisconnect && api.intentionallyDisconnecting) return
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
import { and, eq, gt } from 'drizzle-orm'
|
||||||
import { appliedPresets } from '$/database/schemas'
|
import { appliedPresets } from '$/database/schemas'
|
||||||
import { on, withContext } from '$/utils/discord/events'
|
import { on, withContext } from '$/utils/discord/events'
|
||||||
import { applyRolesUsingPreset } from '$/utils/discord/rolePresets'
|
import { applyRolesUsingPreset } from '$/utils/discord/rolePresets'
|
||||||
import { and, eq, gt } from 'drizzle-orm'
|
|
||||||
|
|
||||||
withContext(on, 'guildMemberAdd', async ({ database }, member) => {
|
withContext(on, 'guildMemberAdd', async ({ database }, member) => {
|
||||||
const applieds = await database.query.appliedPresets.findMany({
|
const applieds = await database.query.appliedPresets.findMany({
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
import { MessageFlags } from 'discord.js'
|
||||||
import CommandError from '$/classes/CommandError'
|
import CommandError from '$/classes/CommandError'
|
||||||
import { createStackTraceEmbed } from '$utils/discord/embeds'
|
import { createStackTraceEmbed } from '$utils/discord/embeds'
|
||||||
import { on, withContext } from '$utils/discord/events'
|
import { on, withContext } from '$utils/discord/events'
|
||||||
import { MessageFlags } from 'discord.js'
|
|
||||||
|
|
||||||
withContext(on, 'interactionCreate', async (context, interaction) => {
|
withContext(on, 'interactionCreate', async (context, interaction) => {
|
||||||
if (!interaction.isChatInputCommand()) return
|
if (!interaction.isChatInputCommand()) return
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
import { MessageFlags } from 'discord.js'
|
||||||
import CommandError from '$/classes/CommandError'
|
import CommandError from '$/classes/CommandError'
|
||||||
import { createStackTraceEmbed } from '$utils/discord/embeds'
|
import { createStackTraceEmbed } from '$utils/discord/embeds'
|
||||||
import { on, withContext } from '$utils/discord/events'
|
import { on, withContext } from '$utils/discord/events'
|
||||||
import { MessageFlags } from 'discord.js'
|
|
||||||
|
|
||||||
withContext(on, 'interactionCreate', async (context, interaction) => {
|
withContext(on, 'interactionCreate', async (context, interaction) => {
|
||||||
if (!interaction.isContextMenuCommand()) return
|
if (!interaction.isContextMenuCommand()) return
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
import { responses } from '$/database/schemas'
|
|
||||||
import { handleUserResponseCorrection } from '$/utils/discord/messageScan'
|
|
||||||
import { createErrorEmbed, createStackTraceEmbed, createSuccessEmbed } from '$utils/discord/embeds'
|
|
||||||
import { on, withContext } from '$utils/discord/events'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
type ButtonInteraction,
|
type ButtonInteraction,
|
||||||
MessageFlags,
|
MessageFlags,
|
||||||
@@ -10,6 +5,10 @@ import {
|
|||||||
type TextBasedChannel,
|
type TextBasedChannel,
|
||||||
} from 'discord.js'
|
} from 'discord.js'
|
||||||
import { eq } from 'drizzle-orm'
|
import { eq } from 'drizzle-orm'
|
||||||
|
import { responses } from '$/database/schemas'
|
||||||
|
import { handleUserResponseCorrection } from '$/utils/discord/messageScan'
|
||||||
|
import { createErrorEmbed, createStackTraceEmbed, createSuccessEmbed } from '$utils/discord/embeds'
|
||||||
|
import { on, withContext } from '$utils/discord/events'
|
||||||
|
|
||||||
// No permission check required as it is already done when the user reacts to a bot response
|
// No permission check required as it is already done when the user reacts to a bot response
|
||||||
withContext(on, 'interactionCreate', async (context, interaction) => {
|
withContext(on, 'interactionCreate', async (context, interaction) => {
|
||||||
@@ -59,8 +58,8 @@ withContext(on, 'interactionCreate', async (context, interaction) => {
|
|||||||
|
|
||||||
const editMessage = (content: string, description?: string) =>
|
const editMessage = (content: string, description?: string) =>
|
||||||
editInteractionMessage(interaction, msg.url, content, description)
|
editInteractionMessage(interaction, msg.url, content, description)
|
||||||
const handleCorrection = (label: string) =>
|
const handleCorrection = (label?: string) =>
|
||||||
handleUserResponseCorrection(context, response, msg, label, interaction.user)
|
handleUserResponseCorrection(context, response, msg, interaction.user, label)
|
||||||
|
|
||||||
if (response.correctedById)
|
if (response.correctedById)
|
||||||
return await editMessage(
|
return await editMessage(
|
||||||
@@ -83,7 +82,7 @@ withContext(on, 'interactionCreate', async (context, interaction) => {
|
|||||||
await editMessage('Canceled', 'You canceled this interaction. 😞')
|
await editMessage('Canceled', 'You canceled this interaction. 😞')
|
||||||
break
|
break
|
||||||
case 'delete':
|
case 'delete':
|
||||||
await handleCorrection(msConfig.humanCorrections.falsePositiveLabel)
|
await handleCorrection()
|
||||||
await editMessage(
|
await editMessage(
|
||||||
'Marked as false positive',
|
'Marked as false positive',
|
||||||
'The response has been deleted and marked as a false positive. Thank you for your feedback. 🎉',
|
'The response has been deleted and marked as a false positive. Thank you for your feedback. 🎉',
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import { MessageFlags, type TextBasedChannel } from 'discord.js'
|
||||||
|
import { OutOfScopeLabel } from '$/commands/support/train/context-menu'
|
||||||
import { createErrorEmbed, createStackTraceEmbed, createSuccessEmbed } from '$utils/discord/embeds'
|
import { createErrorEmbed, createStackTraceEmbed, createSuccessEmbed } from '$utils/discord/embeds'
|
||||||
import { on, withContext } from '$utils/discord/events'
|
import { on, withContext } from '$utils/discord/events'
|
||||||
import { MessageFlags, type TextBasedChannel } from 'discord.js'
|
|
||||||
|
|
||||||
withContext(on, 'interactionCreate', async (context, interaction) => {
|
withContext(on, 'interactionCreate', async (context, interaction) => {
|
||||||
const {
|
const {
|
||||||
@@ -30,8 +31,11 @@ withContext(on, 'interactionCreate', async (context, interaction) => {
|
|||||||
flags: MessageFlags.Ephemeral,
|
flags: MessageFlags.Ephemeral,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const selectedLabel = interaction.values[0]!
|
const selectedLabel = interaction.values[0]
|
||||||
await context.api.client.trainMessage(msg.content, selectedLabel)
|
await context.api.client.trainMessage(
|
||||||
|
msg.content,
|
||||||
|
selectedLabel === OutOfScopeLabel ? undefined : selectedLabel,
|
||||||
|
)
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
embeds: [
|
embeds: [
|
||||||
createSuccessEmbed(
|
createSuccessEmbed(
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { MessageScanLabeledResponseReactions } from '$/constants'
|
||||||
import { responses } from '$/database/schemas'
|
import { responses } from '$/database/schemas'
|
||||||
import { getResponseFromText, messageMatchesFilter } from '$/utils/discord/messageScan'
|
import { getResponseFromText, messageMatchesFilter } from '$/utils/discord/messageScan'
|
||||||
import { createMessageScanResponseEmbed } from '$utils/discord/embeds'
|
import { createMessageScanResponseEmbed } from '$utils/discord/embeds'
|
||||||
@@ -32,7 +33,13 @@ withContext(on, 'messageCreate', async (context, msg) => {
|
|||||||
if (response) {
|
if (response) {
|
||||||
logger.debug('Response found')
|
logger.debug('Response found')
|
||||||
|
|
||||||
const toReply = respondToReply ? (msg.reference?.messageId ? await msg.fetchReference() : msg) : msg
|
const toReply =
|
||||||
|
msg.reference?.messageId &&
|
||||||
|
(respondToReply === true ||
|
||||||
|
(label === undefined ? respondToReply === 'only_regex' : respondToReply === 'only_labeled'))
|
||||||
|
? await msg.fetchReference()
|
||||||
|
: msg
|
||||||
|
|
||||||
const reply = await toReply.reply({
|
const reply = await toReply.reply({
|
||||||
...response,
|
...response,
|
||||||
embeds: response.embeds?.map(createMessageScanResponseEmbed),
|
embeds: response.embeds?.map(createMessageScanResponseEmbed),
|
||||||
@@ -47,6 +54,8 @@ withContext(on, 'messageCreate', async (context, msg) => {
|
|||||||
label,
|
label,
|
||||||
content: msg.content,
|
content: msg.content,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await Promise.all(Object.values(MessageScanLabeledResponseReactions).map(name => reply.react(name)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -1,7 +1,3 @@
|
|||||||
import { MessageScanLabeledResponseReactions as Reactions } from '$/constants'
|
|
||||||
import { createErrorEmbed, createStackTraceEmbed, createSuccessEmbed } from '$/utils/discord/embeds'
|
|
||||||
import { on, withContext } from '$/utils/discord/events'
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ActionRowBuilder,
|
ActionRowBuilder,
|
||||||
ButtonBuilder,
|
ButtonBuilder,
|
||||||
@@ -9,12 +5,14 @@ import {
|
|||||||
StringSelectMenuBuilder,
|
StringSelectMenuBuilder,
|
||||||
StringSelectMenuOptionBuilder,
|
StringSelectMenuOptionBuilder,
|
||||||
} from 'discord.js'
|
} from 'discord.js'
|
||||||
|
import { eq } from 'drizzle-orm'
|
||||||
import type { ConfigMessageScanResponseLabelConfig } from '$/../config.schema'
|
import { MessageScanLabeledResponseReactions as Reactions } from '$/constants'
|
||||||
import { responses } from '$/database/schemas'
|
import { responses } from '$/database/schemas'
|
||||||
|
import { createErrorEmbed, createStackTraceEmbed, createSuccessEmbed } from '$/utils/discord/embeds'
|
||||||
|
import { on, withContext } from '$/utils/discord/events'
|
||||||
import { handleUserResponseCorrection } from '$/utils/discord/messageScan'
|
import { handleUserResponseCorrection } from '$/utils/discord/messageScan'
|
||||||
import { isAdmin } from '$/utils/discord/permissions'
|
import { isAdmin } from '$/utils/discord/permissions'
|
||||||
import { eq } from 'drizzle-orm'
|
import type { ConfigMessageScanResponseLabelConfig } from '$/../config.schema'
|
||||||
|
|
||||||
const PossibleReactions = Object.values(Reactions) as string[]
|
const PossibleReactions = Object.values(Reactions) as string[]
|
||||||
|
|
||||||
@@ -65,8 +63,8 @@ withContext(on, 'messageReactionAdd', async (context, rct, user) => {
|
|||||||
|
|
||||||
logger.debug(`User ${user.id} is trying to correct the response ${rct.message.id}`)
|
logger.debug(`User ${user.id} is trying to correct the response ${rct.message.id}`)
|
||||||
|
|
||||||
const handleCorrection = (label: string) =>
|
const handleCorrection = (label?: string) =>
|
||||||
handleUserResponseCorrection(context, response, reactionMessage, label, user)
|
handleUserResponseCorrection(context, response, reactionMessage, user, label)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (reaction.emoji.name === Reactions.train) {
|
if (reaction.emoji.name === Reactions.train) {
|
||||||
@@ -108,7 +106,7 @@ withContext(on, 'messageReactionAdd', async (context, rct, user) => {
|
|||||||
.setCustomId(`${componentPrefix}_cancel`),
|
.setCustomId(`${componentPrefix}_cancel`),
|
||||||
new ButtonBuilder()
|
new ButtonBuilder()
|
||||||
.setEmoji(Reactions.delete)
|
.setEmoji(Reactions.delete)
|
||||||
.setLabel('Delete (mark as false positive)')
|
.setLabel('Delete (mark as out of scope)')
|
||||||
.setStyle(ButtonStyle.Danger)
|
.setStyle(ButtonStyle.Danger)
|
||||||
.setCustomId(`${componentPrefix}_delete`),
|
.setCustomId(`${componentPrefix}_delete`),
|
||||||
),
|
),
|
||||||
@@ -119,8 +117,8 @@ withContext(on, 'messageReactionAdd', async (context, rct, user) => {
|
|||||||
components: rows,
|
components: rows,
|
||||||
})
|
})
|
||||||
} else if (reaction.emoji.name === Reactions.delete) {
|
} else if (reaction.emoji.name === Reactions.delete) {
|
||||||
await handleCorrection(msConfig.humanCorrections.falsePositiveLabel)
|
await handleCorrection()
|
||||||
await user.send({ content: 'The response has been deleted and marked as a false positive.' })
|
await user.send({ content: 'The response has been deleted and marked as out of scope.' })
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('Failed to correct response:', e)
|
logger.error('Failed to correct response:', e)
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
|
import { type Client, DiscordAPIError } from 'discord.js'
|
||||||
|
import { and, eq, lt } from 'drizzle-orm'
|
||||||
import { database, logger } from '$/context'
|
import { database, logger } from '$/context'
|
||||||
import { appliedPresets } from '$/database/schemas'
|
import { appliedPresets } from '$/database/schemas'
|
||||||
import { on, withContext } from '$/utils/discord/events'
|
import { on, withContext } from '$/utils/discord/events'
|
||||||
import { removeRolePreset } from '$/utils/discord/rolePresets'
|
import { removeRolePreset } from '$/utils/discord/rolePresets'
|
||||||
import { and, eq, lt } from 'drizzle-orm'
|
|
||||||
|
|
||||||
import { type Client, DiscordAPIError } from 'discord.js'
|
|
||||||
|
|
||||||
export default withContext(on, 'ready', async ({ config }, client) => {
|
export default withContext(on, 'ready', async ({ config }, client) => {
|
||||||
if (config.rolePresets) {
|
if (config.rolePresets) {
|
||||||
removeExpiredPresets(client)
|
removeExpiredPresets(client)
|
||||||
setTimeout(() => removeExpiredPresets(client), config.rolePresets.checkExpiredEvery)
|
setInterval(() => removeExpiredPresets(client), config.rolePresets.checkExpiredEvery)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { api, discord, logger } from '$/context'
|
|
||||||
import { getMissingEnvironmentVariables } from '@revanced/bot-shared'
|
import { getMissingEnvironmentVariables } from '@revanced/bot-shared'
|
||||||
|
import { api, discord, logger } from '$/context'
|
||||||
|
|
||||||
import './events/register'
|
import './events/register'
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { ClientWebSocketEvents } from '@revanced/bot-api'
|
|
||||||
import * as context from '../../context'
|
import * as context from '../../context'
|
||||||
|
import type { ClientWebSocketEvents } from '@revanced/bot-api'
|
||||||
|
|
||||||
const { client } = context.api
|
const { client } = context.api
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { DefaultEmbedColor, ReVancedLogoURL } from '$/constants'
|
|
||||||
import { type APIEmbed, EmbedBuilder, type EmbedField, type JSONEncodable, type User } from 'discord.js'
|
import { type APIEmbed, EmbedBuilder, type EmbedField, type JSONEncodable, type User } from 'discord.js'
|
||||||
|
import { DefaultEmbedColor, ReVancedLogoURL } from '$/constants'
|
||||||
import type { ConfigMessageScanResponseMessage } from '../../../config.schema'
|
import type { ConfigMessageScanResponseMessage } from '../../../config.schema'
|
||||||
|
|
||||||
export const createErrorEmbed = (title: string | null, description?: string) =>
|
export const createErrorEmbed = (title: string | null, description?: string) =>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { type Response, responses } from '$/database/schemas'
|
|
||||||
import type { Config, ConfigMessageScanResponse, ConfigMessageScanResponseLabelConfig } from 'config.schema'
|
|
||||||
import { ButtonStyle, ComponentType } from 'discord.js'
|
import { ButtonStyle, ComponentType } from 'discord.js'
|
||||||
import type { APIActionRowComponent, APIButtonComponent, Message, PartialUser, User } from 'discord.js'
|
|
||||||
import { eq } from 'drizzle-orm'
|
import { eq } from 'drizzle-orm'
|
||||||
|
import { type Response, responses } from '$/database/schemas'
|
||||||
import { createMessageScanResponseEmbed } from './embeds'
|
import { createMessageScanResponseEmbed } from './embeds'
|
||||||
|
import type { Config, ConfigMessageScanResponse, ConfigMessageScanResponseLabelConfig } from 'config.schema'
|
||||||
|
import type { APIActionRowComponent, APIButtonComponent, Message, PartialUser, User } from 'discord.js'
|
||||||
|
|
||||||
export const getResponseFromText = async (
|
export const getResponseFromText = async (
|
||||||
content: string,
|
content: string,
|
||||||
@@ -17,7 +17,7 @@ export const getResponseFromText = async (
|
|||||||
type ResponseConfig = Awaited<ReturnType<typeof getResponseFromText>>
|
type ResponseConfig = Awaited<ReturnType<typeof getResponseFromText>>
|
||||||
let responseConfig: Omit<ResponseConfig, 'triggers'> & { triggers?: ResponseConfig['triggers'] } = {
|
let responseConfig: Omit<ResponseConfig, 'triggers'> & { triggers?: ResponseConfig['triggers'] } = {
|
||||||
triggers: undefined,
|
triggers: undefined,
|
||||||
response: null,
|
response: null!,
|
||||||
}
|
}
|
||||||
|
|
||||||
const firstLabelIndexes: number[] = []
|
const firstLabelIndexes: number[] = []
|
||||||
@@ -143,15 +143,22 @@ export const handleUserResponseCorrection = async (
|
|||||||
{ api, database: db, config: { messageScan: msConfig }, logger }: typeof import('$/context'),
|
{ api, database: db, config: { messageScan: msConfig }, logger }: typeof import('$/context'),
|
||||||
response: Response,
|
response: Response,
|
||||||
reply: Message,
|
reply: Message,
|
||||||
label: string,
|
|
||||||
user: User | PartialUser,
|
user: User | PartialUser,
|
||||||
|
label?: string,
|
||||||
) => {
|
) => {
|
||||||
|
if (!label) {
|
||||||
|
await Promise.all([reply.delete(), api.client.trainMessage(response.content, label)]).finally(() =>
|
||||||
|
logger.debug(`User ${user.id} trained message ${response.replyId} as out of scope`),
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const correctLabelResponse = msConfig!.responses!.find(r =>
|
const correctLabelResponse = msConfig!.responses!.find(r =>
|
||||||
r.triggers.text!.some(t => 'label' in t && t.label === label),
|
r.triggers.text!.some(t => 'label' in t && t.label === label),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!correctLabelResponse) throw new Error('Cannot find label config for the selected label')
|
if (!correctLabelResponse) throw new Error('Cannot find label config for the selected label')
|
||||||
if (!correctLabelResponse.response) return void (await reply.delete())
|
|
||||||
|
|
||||||
if (response.label !== label) {
|
if (response.label !== label) {
|
||||||
db.update(responses)
|
db.update(responses)
|
||||||
@@ -168,12 +175,12 @@ export const handleUserResponseCorrection = async (
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
await api.client.trainMessage(response.content, label)
|
await Promise.all([
|
||||||
logger.debug(`User ${user.id} trained message ${response.replyId} as ${label} (positive)`)
|
api.client.trainMessage(response.content, label),
|
||||||
|
reply.edit({
|
||||||
await reply.edit({
|
components: [],
|
||||||
components: [],
|
}),
|
||||||
})
|
]).finally(() => logger.debug(`User ${user.id} trained message ${response.replyId} as ${label}`))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createMessageScanResponseComponents = (reply: Message<true>) => [
|
export const createMessageScanResponseComponents = (reply: Message<true>) => [
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { config, logger } from '$/context'
|
|
||||||
import decancer from 'decancer'
|
import decancer from 'decancer'
|
||||||
import type { CommandInteraction, EmbedBuilder, Guild, GuildMember, Message, User } from 'discord.js'
|
import { config, logger } from '$/context'
|
||||||
import { applyReferenceToModerationActionEmbed, createModerationActionEmbed } from './embeds'
|
import { applyReferenceToModerationActionEmbed, createModerationActionEmbed } from './embeds'
|
||||||
|
import type { CommandInteraction, EmbedBuilder, Guild, GuildMember, Message, User } from 'discord.js'
|
||||||
|
|
||||||
const PresetLogAction = {
|
const PresetLogAction = {
|
||||||
apply: 'Applied role preset to',
|
apply: 'Applied role preset to',
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
import { and, eq } from 'drizzle-orm'
|
||||||
import { config, database } from '$/context'
|
import { config, database } from '$/context'
|
||||||
import { appliedPresets } from '$/database/schemas'
|
import { appliedPresets } from '$/database/schemas'
|
||||||
import type { GuildMember } from 'discord.js'
|
import type { GuildMember } from 'discord.js'
|
||||||
import { and, eq } from 'drizzle-orm'
|
|
||||||
|
|
||||||
// TODO: Fix this type
|
// TODO: Fix this type
|
||||||
type PresetKey = string
|
type PresetKey = string
|
||||||
|
|||||||
@@ -38,3 +38,7 @@ export const durationToString = (duration: number) => {
|
|||||||
left: '',
|
left: '',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isSafeTimeoutDuration(duration: number) {
|
||||||
|
return duration > 0 && duration < 2 ** 31 - 1
|
||||||
|
}
|
||||||
|
|||||||
37
package.json
37
package.json
@@ -6,7 +6,11 @@
|
|||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"author": "Palm <contact@palmdevs.me> (https://palmdevs.me)",
|
"author": "Palm <contact@palmdevs.me> (https://palmdevs.me)",
|
||||||
"workspaces": ["packages/*", "apis/*", "bots/*"],
|
"workspaces": [
|
||||||
|
"packages/*",
|
||||||
|
"apis/*",
|
||||||
|
"bots/*"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:all": "turbo run build",
|
"build:all": "turbo run build",
|
||||||
"build:packages": "turbo build --filter=\"./packages/*\"",
|
"build:packages": "turbo build --filter=\"./packages/*\"",
|
||||||
@@ -27,25 +31,25 @@
|
|||||||
"Palm <contact@palmdevs.me> (https://palmdevs.me)",
|
"Palm <contact@palmdevs.me> (https://palmdevs.me)",
|
||||||
"ReVanced <nosupport@revanced.app> (https://revanced.app)"
|
"ReVanced <nosupport@revanced.app> (https://revanced.app)"
|
||||||
],
|
],
|
||||||
"packageManager": "bun@1.1.20",
|
"packageManager": "bun@1.2.17",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@anolilab/multi-semantic-release": "^1.1.10",
|
"@anolilab/multi-semantic-release": "^2.0.3",
|
||||||
"@biomejs/biome": "^1.9.4",
|
"@biomejs/biome": "^2.2.4",
|
||||||
"@codedependant/semantic-release-docker": "^5.1.0",
|
"@codedependant/semantic-release-docker": "^5.1.1",
|
||||||
"@commitlint/cli": "^19.8.0",
|
"@commitlint/cli": "^19.8.1",
|
||||||
"@commitlint/config-conventional": "^19.8.0",
|
"@commitlint/config-conventional": "^19.8.1",
|
||||||
"@saithodev/semantic-release-backmerge": "^4.0.1",
|
"@saithodev/semantic-release-backmerge": "^4.0.1",
|
||||||
"@semantic-release/changelog": "^6.0.3",
|
"@semantic-release/changelog": "^6.0.3",
|
||||||
"@semantic-release/exec": "^6.0.3",
|
"@semantic-release/exec": "^7.1.0",
|
||||||
"@semantic-release/git": "^10.0.1",
|
"@semantic-release/git": "^10.0.1",
|
||||||
"@tsconfig/strictest": "^2.0.5",
|
"@tsconfig/strictest": "^2.0.5",
|
||||||
"@types/bun": "^1.2.8",
|
"@types/bun": "^1.2.21",
|
||||||
"conventional-changelog-conventionalcommits": "^7.0.2",
|
"conventional-changelog-conventionalcommits": "^9.1.0",
|
||||||
"lefthook": "^1.11.6",
|
"lefthook": "^1.13.0",
|
||||||
"portainer-service-webhook": "https://github.com/newarifrh/portainer-service-webhook#v1",
|
"portainer-service-webhook": "https://github.com/newarifrh/portainer-service-webhook#v1",
|
||||||
"semantic-release": "^24.2.3",
|
"semantic-release": "^24.2.8",
|
||||||
"turbo": "^2.5.0",
|
"turbo": "^2.5.6",
|
||||||
"typescript": "^5.8.2"
|
"typescript": "^5.9.2"
|
||||||
},
|
},
|
||||||
"trustedDependencies": [
|
"trustedDependencies": [
|
||||||
"@biomejs/biome",
|
"@biomejs/biome",
|
||||||
@@ -54,9 +58,6 @@
|
|||||||
"lefthook"
|
"lefthook"
|
||||||
],
|
],
|
||||||
"patchedDependencies": {
|
"patchedDependencies": {
|
||||||
"@semantic-release/npm@12.0.1": "patches/@semantic-release%2Fnpm@12.0.1.patch",
|
"@semantic-release/npm@12.0.2": "patches/@semantic-release%2Fnpm@12.0.2.patch"
|
||||||
"drizzle-kit@0.22.8": "patches/drizzle-kit@0.22.8.patch",
|
|
||||||
"decancer@3.2.4": "patches/decancer@3.2.4.patch",
|
|
||||||
"discord.js@14.18.0": "patches/discord.js@14.18.0.patch"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
"homepage": "https://github.com/revanced/revanced-bots#readme",
|
"homepage": "https://github.com/revanced/revanced-bots#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@revanced/bot-shared": "workspace:*",
|
"@revanced/bot-shared": "workspace:*",
|
||||||
"ws": "^8.18.1"
|
"ws": "^8.18.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ export default class Client {
|
|||||||
return packet
|
return packet
|
||||||
}
|
}
|
||||||
|
|
||||||
async trainMessage(text: string, label: string) {
|
async trainMessage(text: string, label?: string) {
|
||||||
this.#throwIfNotReady()
|
this.#throwIfNotReady()
|
||||||
|
|
||||||
this.ws.send({
|
this.ws.send({
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import { EventEmitter } from 'events'
|
|
||||||
import {
|
import {
|
||||||
type ClientOperation,
|
type ClientOperation,
|
||||||
DisconnectReason,
|
DisconnectReason,
|
||||||
type Packet,
|
|
||||||
ServerOperation,
|
|
||||||
deserializePacket,
|
deserializePacket,
|
||||||
isServerPacket,
|
isServerPacket,
|
||||||
|
type Packet,
|
||||||
|
ServerOperation,
|
||||||
serializePacket,
|
serializePacket,
|
||||||
uncapitalize,
|
uncapitalize,
|
||||||
} from '@revanced/bot-shared'
|
} from '@revanced/bot-shared'
|
||||||
import type TypedEmitter from 'typed-emitter'
|
import { EventEmitter } from 'events'
|
||||||
import { type RawData, WebSocket } from 'ws'
|
import { type RawData, WebSocket } from 'ws'
|
||||||
|
import type TypedEmitter from 'typed-emitter'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The class that handles the WebSocket connection to the server.
|
* The class that handles the WebSocket connection to the server.
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export { default as Client } from './Client'
|
|
||||||
export * from './Client'
|
export * from './Client'
|
||||||
|
export { default as Client } from './Client'
|
||||||
export * from './ClientWebSocket'
|
export * from './ClientWebSocket'
|
||||||
|
|||||||
@@ -30,9 +30,9 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/revanced/revanced-bots#readme",
|
"homepage": "https://github.com/revanced/revanced-bots#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bson": "^6.10.3",
|
"bson": "^6.10.4",
|
||||||
"chalk": "^5.4.1",
|
"chalk": "^5.6.2",
|
||||||
"tracer": "^1.3.0",
|
"tracer": "^1.3.0",
|
||||||
"valibot": "^0.30.0"
|
"valibot": "^1.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
import {
|
import {
|
||||||
url,
|
|
||||||
type AnySchema,
|
|
||||||
type BooleanSchema,
|
|
||||||
type NullSchema,
|
|
||||||
type ObjectSchema,
|
|
||||||
type Output,
|
|
||||||
array,
|
array,
|
||||||
boolean,
|
boolean,
|
||||||
|
custom,
|
||||||
enum_,
|
enum_,
|
||||||
|
type InferOutput,
|
||||||
null_,
|
null_,
|
||||||
object,
|
object,
|
||||||
|
optional,
|
||||||
parse,
|
parse,
|
||||||
special,
|
pipe,
|
||||||
string,
|
string,
|
||||||
|
url,
|
||||||
// merge
|
// merge
|
||||||
} from 'valibot'
|
} from 'valibot'
|
||||||
import DisconnectReason from '../constants/DisconnectReason'
|
import DisconnectReason from '../constants/DisconnectReason'
|
||||||
@@ -21,7 +19,7 @@ import { ClientOperation, Operation, ServerOperation } from '../constants/Operat
|
|||||||
/**
|
/**
|
||||||
* Schema to validate packets
|
* Schema to validate packets
|
||||||
*/
|
*/
|
||||||
export const PacketSchema = special<Packet>(input => {
|
export const PacketSchema = custom<Packet>(input => {
|
||||||
if (
|
if (
|
||||||
typeof input === 'object' &&
|
typeof input === 'object' &&
|
||||||
input &&
|
input &&
|
||||||
@@ -51,7 +49,7 @@ export const PacketDataSchemas = {
|
|||||||
labels: array(
|
labels: array(
|
||||||
object({
|
object({
|
||||||
name: string(),
|
name: string(),
|
||||||
confidence: special<number>(input => typeof input === 'number' && input >= 0 && input <= 1),
|
confidence: custom<number>(input => typeof input === 'number' && input >= 0 && input <= 1),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
@@ -70,17 +68,13 @@ export const PacketDataSchemas = {
|
|||||||
text: string(),
|
text: string(),
|
||||||
}),
|
}),
|
||||||
[ClientOperation.ParseImage]: object({
|
[ClientOperation.ParseImage]: object({
|
||||||
image_url: string([url()]),
|
image_url: pipe(string(), url()),
|
||||||
}),
|
}),
|
||||||
[ClientOperation.TrainMessage]: object({
|
[ClientOperation.TrainMessage]: object({
|
||||||
text: string(),
|
text: string(),
|
||||||
label: string(),
|
label: optional(string()),
|
||||||
}),
|
}),
|
||||||
} as const satisfies Record<
|
} as const
|
||||||
Operation,
|
|
||||||
// biome-ignore lint/suspicious/noExplicitAny: This is a schema, it's not possible to type it
|
|
||||||
ObjectSchema<any> | AnySchema | NullSchema | BooleanSchema
|
|
||||||
>
|
|
||||||
|
|
||||||
export type Packet<TOp extends Operation = Operation> = TOp extends ServerOperation
|
export type Packet<TOp extends Operation = Operation> = TOp extends ServerOperation
|
||||||
? PacketWithSequenceNumber<TOp>
|
? PacketWithSequenceNumber<TOp>
|
||||||
@@ -88,6 +82,6 @@ export type Packet<TOp extends Operation = Operation> = TOp extends ServerOperat
|
|||||||
|
|
||||||
type PacketWithSequenceNumber<TOp extends Operation> = {
|
type PacketWithSequenceNumber<TOp extends Operation> = {
|
||||||
op: TOp
|
op: TOp
|
||||||
d: Output<(typeof PacketDataSchemas)[TOp]>
|
d: InferOutput<(typeof PacketDataSchemas)[TOp]>
|
||||||
s: number
|
s: number
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Chalk, supportsColor, supportsColorStderr } from 'chalk'
|
import { Chalk, supportsColor, supportsColorStderr } from 'chalk'
|
||||||
import { type Tracer, colorConsole, console as uncoloredConsole } from 'tracer'
|
import { colorConsole, type Tracer, console as uncoloredConsole } from 'tracer'
|
||||||
|
|
||||||
const chalk = new Chalk()
|
const chalk = new Chalk()
|
||||||
const DefaultConfig = {
|
const DefaultConfig = {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as BSON from 'bson'
|
import * as BSON from 'bson'
|
||||||
import { parse } from 'valibot'
|
import { parse } from 'valibot'
|
||||||
import type { Operation } from '../constants'
|
|
||||||
import { type Packet, PacketSchema } from '../schemas'
|
import { type Packet, PacketSchema } from '../schemas'
|
||||||
|
import type { Operation } from '../constants'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compresses a packet into a buffer
|
* Compresses a packet into a buffer
|
||||||
|
|||||||
@@ -1,12 +1,3 @@
|
|||||||
diff --git a/node_modules/@semantic-release/npm/.bun-tag-3853154e196b7721 b/.bun-tag-3853154e196b7721
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
|
|
||||||
diff --git a/node_modules/@semantic-release/npm/.bun-tag-550461f23a8ec245 b/.bun-tag-550461f23a8ec245
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
|
|
||||||
diff --git a/node_modules/@semantic-release/npm/.bun-tag-c9c8130945517add b/.bun-tag-c9c8130945517add
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
|
|
||||||
diff --git a/lib/prepare.js b/lib/prepare.js
|
diff --git a/lib/prepare.js b/lib/prepare.js
|
||||||
index 3e76bec44cf595a1b4141728336bed904d4d518d..4b25ca64879bbee2a600f2b23b738c86136ad9c6 100644
|
index 3e76bec44cf595a1b4141728336bed904d4d518d..4b25ca64879bbee2a600f2b23b738c86136ad9c6 100644
|
||||||
--- a/lib/prepare.js
|
--- a/lib/prepare.js
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
diff --git a/src/lib.js b/src/lib.js
|
|
||||||
index de45d7dbe82975b09eff3742d0718accae2107fc..0575daa03dfabdd5c96928458ff4270cb8f7188a 100644
|
|
||||||
--- a/src/lib.js
|
|
||||||
+++ b/src/lib.js
|
|
||||||
@@ -42,7 +42,7 @@ function isMusl() {
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBinding(name) {
|
|
||||||
- const path = join(__dirname, '..', `decancer.${name}.node`)
|
|
||||||
+ const path = join(import.meta.dir, '..', `decancer.${name}.node`)
|
|
||||||
|
|
||||||
return require(existsSync(path) ? path : `@vierofernando/decancer-${name}`)
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# Make Message#reply work with { flags: MessageFlags.Ephemeral } in typings
|
|
||||||
# So our Command system doesn't break
|
|
||||||
diff --git a/typings/index.d.mts b/typings/index.d.mts
|
|
||||||
index 645b870..fa93158 100644
|
|
||||||
--- a/typings/index.d.mts
|
|
||||||
+++ b/typings/index.d.mts
|
|
||||||
@@ -6764,8 +6764,8 @@ export interface MessageCreateOptions extends BaseMessageOptionsWithPoll {
|
|
||||||
stickers?: readonly StickerResolvable[];
|
|
||||||
flags?:
|
|
||||||
| BitFieldResolvable<
|
|
||||||
- Extract<MessageFlagsString, 'SuppressEmbeds' | 'SuppressNotifications'>,
|
|
||||||
- MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications
|
|
||||||
+ Extract<MessageFlagsString, 'SuppressEmbeds' | 'SuppressNotifications' | 'Ephemeral'>,
|
|
||||||
+ MessageFlags.SuppressEmbeds | MessageFlags.SuppressNotifications | MessageFlags.Ephemeral
|
|
||||||
>
|
|
||||||
| undefined;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
diff --git a/bin.cjs b/bin.cjs
|
|
||||||
index 142ed9c20f28dc1080bebfb52325fa308c6cb771..9d3bea0787f6c05df11567c6821bc85743286340 100644
|
|
||||||
--- a/bin.cjs
|
|
||||||
+++ b/bin.cjs
|
|
||||||
@@ -22053,7 +22053,7 @@ var init_sqliteImports = __esm({
|
|
||||||
const { unregister } = await safeRegister();
|
|
||||||
for (let i2 = 0; i2 < imports.length; i2++) {
|
|
||||||
const it = imports[i2];
|
|
||||||
- const i0 = require(`${it}`);
|
|
||||||
+ const i0 = await import(`${it}`);
|
|
||||||
const prepared = prepareFromExports3(i0);
|
|
||||||
tables.push(...prepared.tables);
|
|
||||||
}
|
|
||||||
@@ -129572,6 +129572,7 @@ var generateCommand = new Command("generate").option("--dialect <dialect>", "Dat
|
|
||||||
} else {
|
|
||||||
assertUnreachable(dialect7);
|
|
||||||
}
|
|
||||||
+ process.exit(0);
|
|
||||||
});
|
|
||||||
var migrateCommand = new Command("migrate").option(
|
|
||||||
"--config <config>",
|
|
||||||
Reference in New Issue
Block a user