mirror of
https://github.com/ReVanced/revanced-bots.git
synced 2026-01-11 13:56:15 +00:00
feat!: big feature changes
BREAKING CHANGES: - Heartbeating removed - `config.consoleLogLevel` -> `config.logLevel` NEW FEATURES: - Training messages - Sequence number system - WebSocket close codes used instead of disconnect packets FIXES: - Improved error handling - Some performance improvements - Made code more clean - Updated dependencies
This commit is contained in:
@@ -1,40 +1,40 @@
|
||||
{
|
||||
"name": "@revanced/bot-shared",
|
||||
"type": "module",
|
||||
"version": "0.1.0",
|
||||
"description": "🙌🏻 Shared components for bots assisting ReVanced",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "bun bundle && bun types",
|
||||
"watch": "conc --raw \"bun bundle:watch\" \"bun types:watch\"",
|
||||
"bundle": "bun build src/index.ts --outdir=dist --sourcemap=external --target=bun --minify",
|
||||
"bundle:watch": "bun run bundle --watch",
|
||||
"types": "tsc --declaration --emitDeclarationOnly",
|
||||
"types:watch": "bun types --watch --preserveWatchOutput",
|
||||
"types:clean": "bun types --build --clean"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/revanced/revanced-helper.git",
|
||||
"directory": "packages/shared"
|
||||
},
|
||||
"author": "Palm <palmpasuthorn@gmail.com> (https://github.com/PalmDevs)",
|
||||
"contributors": [
|
||||
"Palm <palmpasuthorn@gmail.com> (https://github.com/PalmDevs)",
|
||||
"ReVanced <nosupport@revanced.app> (https://github.com/revanced)"
|
||||
],
|
||||
"license": "GPL-3.0-or-later",
|
||||
"bugs": {
|
||||
"url": "https://github.com/revanced/revanced-helper/issues"
|
||||
},
|
||||
"homepage": "https://github.com/revanced/revanced-helper#readme",
|
||||
"dependencies": {
|
||||
"bson": "^6.2.0",
|
||||
"chalk": "^5.3.0",
|
||||
"supports-color": "^9.4.0",
|
||||
"tracer": "^1.3.0",
|
||||
"valibot": "^0.21.0",
|
||||
"zod": "^3.22.4"
|
||||
}
|
||||
"name": "@revanced/bot-shared",
|
||||
"type": "module",
|
||||
"version": "0.1.0",
|
||||
"description": "🙌🏻 Shared components for bots assisting ReVanced",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "bun bundle && bun types",
|
||||
"watch": "conc --raw \"bun bundle:watch\" \"bun types:watch\"",
|
||||
"bundle": "bun build src/index.ts --outdir=dist --sourcemap=external --target=bun --minify",
|
||||
"bundle:watch": "bun run bundle --watch",
|
||||
"types": "tsc --declaration --emitDeclarationOnly",
|
||||
"types:watch": "bun types --watch --preserveWatchOutput",
|
||||
"types:clean": "bun types --build --clean"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/revanced/revanced-helper.git",
|
||||
"directory": "packages/shared"
|
||||
},
|
||||
"author": "Palm <palmpasuthorn@gmail.com> (https://github.com/PalmDevs)",
|
||||
"contributors": [
|
||||
"Palm <palmpasuthorn@gmail.com> (https://github.com/PalmDevs)",
|
||||
"ReVanced <nosupport@revanced.app> (https://github.com/revanced)"
|
||||
],
|
||||
"license": "GPL-3.0-or-later",
|
||||
"bugs": {
|
||||
"url": "https://github.com/revanced/revanced-helper/issues"
|
||||
},
|
||||
"homepage": "https://github.com/revanced/revanced-helper#readme",
|
||||
"dependencies": {
|
||||
"bson": "^6.5.0",
|
||||
"chalk": "^5.3.0",
|
||||
"supports-color": "^9.4.0",
|
||||
"tracer": "^1.3.0",
|
||||
"valibot": "^0.30.0",
|
||||
"zod": "^3.22.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,29 +3,33 @@
|
||||
*/
|
||||
enum DisconnectReason {
|
||||
/**
|
||||
* Unknown reason
|
||||
* The client disconnected on its own (**CLIENT-ONLY**)
|
||||
*/
|
||||
Generic = 1,
|
||||
/**
|
||||
* The client did not respond in time
|
||||
*/
|
||||
TimedOut = 2,
|
||||
PlannedDisconnect = 1000,
|
||||
/**
|
||||
* The client sent an invalid packet (unserializable or invalid JSON)
|
||||
*/
|
||||
InvalidPacket = 3,
|
||||
InvalidPacket = 1007,
|
||||
/**
|
||||
* The server has encountered an internal error
|
||||
*/
|
||||
ServerError = 4,
|
||||
ServerError = 1011,
|
||||
/**
|
||||
* The client had never connected to the server (**CLIENT-ONLY**)
|
||||
* Unknown reason
|
||||
*/
|
||||
NeverConnected = 5,
|
||||
Generic = 4000,
|
||||
/**
|
||||
* The client disconnected on its own (**CLIENT-ONLY**)
|
||||
* The client did not respond with a heartbeat in time
|
||||
*/
|
||||
PlannedDisconnect = 6,
|
||||
TimedOut = 4001,
|
||||
/**
|
||||
* The receiving end didn't have an open socket
|
||||
*/
|
||||
NoOpenSocket = 4003,
|
||||
/**
|
||||
* The client was not ready in time (**CLIENT-ONLY**)
|
||||
*/
|
||||
TooSlow = 4002,
|
||||
}
|
||||
|
||||
export default DisconnectReason
|
||||
|
||||
@@ -4,12 +4,14 @@ import DisconnectReason from './DisconnectReason'
|
||||
* Humanized disconnect reasons for logs
|
||||
*/
|
||||
const HumanizedDisconnectReason = {
|
||||
[DisconnectReason.InvalidPacket]: 'has sent invalid packet',
|
||||
[DisconnectReason.Generic]: 'has been disconnected for unknown reasons',
|
||||
[DisconnectReason.TimedOut]: 'has timed out',
|
||||
[DisconnectReason.ServerError]: 'has been disconnected due to an internal server error',
|
||||
[DisconnectReason.NeverConnected]: 'had never connected to the server',
|
||||
[DisconnectReason.PlannedDisconnect]: 'has disconnected on its own',
|
||||
} as const satisfies Record<DisconnectReason, string>
|
||||
[1006]: 'the receiving end had unexpectedly closed the connection',
|
||||
[DisconnectReason.InvalidPacket]: 'the client has sent invalid packet',
|
||||
[DisconnectReason.Generic]: '(unknown reason)',
|
||||
[DisconnectReason.TimedOut]: 'the client did not respond with a heartbeat in time',
|
||||
[DisconnectReason.ServerError]: 'the server had an internal server error',
|
||||
[DisconnectReason.TooSlow]: 'the client was not ready in time',
|
||||
[DisconnectReason.PlannedDisconnect]: 'the client has disconnected on its own',
|
||||
[DisconnectReason.NoOpenSocket]: 'the receiving end did not have an open socket',
|
||||
} as const satisfies Record<DisconnectReason | number, string>
|
||||
|
||||
export default HumanizedDisconnectReason
|
||||
|
||||
@@ -2,33 +2,28 @@
|
||||
* Client operation codes for the gateway
|
||||
*/
|
||||
export enum ClientOperation {
|
||||
/**
|
||||
* Client's heartbeat (to check if the connection is dead or not)
|
||||
*/
|
||||
Heartbeat = 100,
|
||||
|
||||
/**
|
||||
* Client's request to parse text
|
||||
*/
|
||||
ParseText = 110,
|
||||
ParseText = 100,
|
||||
/**
|
||||
* Client's request to parse image
|
||||
*/
|
||||
ParseImage = 111,
|
||||
ParseImage = 101,
|
||||
/**
|
||||
* Client's request to train a message
|
||||
*/
|
||||
TrainMessage = 102,
|
||||
}
|
||||
|
||||
/**
|
||||
* Server operation codes for the gateway
|
||||
*/
|
||||
export enum ServerOperation {
|
||||
/**
|
||||
* Server's acknowledgement of a client's heartbeat
|
||||
*/
|
||||
HeartbeatAck = 1,
|
||||
/**
|
||||
* Server's initial response to a client's connection
|
||||
*/
|
||||
Hello = 2,
|
||||
Hello = 1,
|
||||
|
||||
/**
|
||||
* Server's response to client's request to parse text
|
||||
@@ -46,6 +41,14 @@ export enum ServerOperation {
|
||||
* Server's failure response to client's request to parse image
|
||||
*/
|
||||
ParseImageFailed = 13,
|
||||
/**
|
||||
* Server's response to client's request to train a message
|
||||
*/
|
||||
TrainedMessage = 14,
|
||||
/**
|
||||
* Server's failure response to client's request to train a message
|
||||
*/
|
||||
TrainMessageFailed = 15,
|
||||
|
||||
/**
|
||||
* Server's disconnect message
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export * from './constants/index'
|
||||
export * from './schemas/index'
|
||||
export * from './utils/index'
|
||||
export * from './constants'
|
||||
export * from './schemas'
|
||||
export * from './utils'
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import {
|
||||
url,
|
||||
AnySchema,
|
||||
NullSchema,
|
||||
ObjectSchema,
|
||||
Output,
|
||||
type AnySchema,
|
||||
type NullSchema,
|
||||
type ObjectSchema,
|
||||
type Output,
|
||||
array,
|
||||
enum_,
|
||||
null_,
|
||||
number,
|
||||
object,
|
||||
parse,
|
||||
special,
|
||||
@@ -30,6 +29,8 @@ export const PacketSchema = special<Packet>(input => {
|
||||
'd' in input &&
|
||||
typeof input.d === 'object'
|
||||
) {
|
||||
if (input.op in ServerOperation && !('s' in input && typeof input.s === 'number')) return false
|
||||
|
||||
try {
|
||||
parse(PacketDataSchemas[input.op as Operation], input.d)
|
||||
return true
|
||||
@@ -44,14 +45,8 @@ export const PacketSchema = special<Packet>(input => {
|
||||
* Schema to validate packet data for each possible operations
|
||||
*/
|
||||
export const PacketDataSchemas = {
|
||||
[ServerOperation.Hello]: object({
|
||||
heartbeatInterval: number(),
|
||||
}),
|
||||
[ServerOperation.HeartbeatAck]: object({
|
||||
nextHeartbeat: number(),
|
||||
}),
|
||||
[ServerOperation.Hello]: null_(),
|
||||
[ServerOperation.ParsedText]: object({
|
||||
id: string(),
|
||||
labels: array(
|
||||
object({
|
||||
name: string(),
|
||||
@@ -60,35 +55,38 @@ export const PacketDataSchemas = {
|
||||
),
|
||||
}),
|
||||
[ServerOperation.ParsedImage]: object({
|
||||
id: string(),
|
||||
text: string(),
|
||||
}),
|
||||
[ServerOperation.ParseTextFailed]: object({
|
||||
id: string(),
|
||||
}),
|
||||
[ServerOperation.ParseImageFailed]: object({
|
||||
id: string(),
|
||||
}),
|
||||
[ServerOperation.ParseTextFailed]: null_(),
|
||||
[ServerOperation.ParseImageFailed]: null_(),
|
||||
[ServerOperation.Disconnect]: object({
|
||||
reason: enum_(DisconnectReason),
|
||||
}),
|
||||
[ServerOperation.TrainedMessage]: null_(),
|
||||
[ServerOperation.TrainMessageFailed]: null_(),
|
||||
|
||||
[ClientOperation.Heartbeat]: null_(),
|
||||
[ClientOperation.ParseText]: object({
|
||||
id: string(),
|
||||
text: string(),
|
||||
}),
|
||||
[ClientOperation.ParseImage]: object({
|
||||
id: string(),
|
||||
image_url: string([url()]),
|
||||
}),
|
||||
[ClientOperation.TrainMessage]: object({
|
||||
text: string(),
|
||||
label: string(),
|
||||
}),
|
||||
} as const satisfies Record<
|
||||
Operation,
|
||||
// biome-ignore lint/suspicious/noExplicitAny: This is a schema, it's not possible to type it
|
||||
ObjectSchema<any> | AnySchema | NullSchema
|
||||
>
|
||||
|
||||
export type Packet<TOp extends Operation = Operation> = {
|
||||
export type Packet<TOp extends Operation = Operation> = TOp extends ServerOperation
|
||||
? PacketWithSequenceNumber<TOp>
|
||||
: Omit<PacketWithSequenceNumber<TOp>, 's'>
|
||||
|
||||
type PacketWithSequenceNumber<TOp extends Operation> = {
|
||||
op: TOp
|
||||
d: Output<(typeof PacketDataSchemas)[TOp]>
|
||||
s: number
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ClientOperation, Operation, ServerOperation } from '../constants/Operation'
|
||||
import { Packet } from '../schemas/Packet'
|
||||
import { ClientOperation, type Operation, ServerOperation } from '../constants/Operation'
|
||||
import type { Packet } from '../schemas/Packet'
|
||||
|
||||
/**
|
||||
* Checks whether a packet is trying to do the given operation
|
||||
@@ -21,7 +21,7 @@ export function isClientPacket(packet: Packet): packet is Packet<ClientOperation
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this packet is a server packet **(this does NOT validate the data)**
|
||||
* Checks whether this packet is a server packet **(this does NOT validate the data or the sequence number)**
|
||||
* @param packet A packet
|
||||
* @returns Whether this packet is a server packet
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Chalk, supportsColor, supportsColorStderr } from 'chalk'
|
||||
import { console as uncoloredConsole, Tracer, colorConsole } from 'tracer'
|
||||
import { type Tracer, colorConsole, console as uncoloredConsole } from 'tracer'
|
||||
|
||||
const chalk = new Chalk()
|
||||
const DefaultConfig = {
|
||||
@@ -8,19 +8,16 @@ const DefaultConfig = {
|
||||
'{{message}}',
|
||||
{
|
||||
error: `${chalk.bgRedBright.whiteBright(' ERROR ')} {{message}}\n${chalk.gray('{{stack}}')}`,
|
||||
debug: chalk.gray('DEBUG: {{message}}\n{{stack}}'),
|
||||
warn: `${chalk.bgYellowBright.whiteBright(' WARN ')} ${chalk.yellowBright('{{message}}')}\n${chalk.gray(
|
||||
'{{stack}}',
|
||||
)}`,
|
||||
debug: chalk.gray('DEBUG: {{message}}'),
|
||||
warn: `${chalk.bgYellowBright.whiteBright(' WARN ')} ${chalk.yellowBright('{{message}}')}`,
|
||||
info: `${chalk.bgBlueBright.whiteBright(' INFO ')} ${chalk.cyanBright('{{message}}')}`,
|
||||
fatal: `${chalk.bgRedBright.whiteBright(' FATAL ')} ${chalk.redBright('{{message}}')}\n${chalk.white(
|
||||
'{{stack}}',
|
||||
)}`,
|
||||
log: '{{message}}',
|
||||
trace: chalk.gray('[{{timestamp}}] TRACE: {{message}}\n{{stack}}'),
|
||||
},
|
||||
],
|
||||
methods: ['debug', 'trace', 'log', 'info', 'warn', 'error', 'fatal'],
|
||||
methods: ['debug', 'log', 'info', 'warn', 'error', 'fatal'],
|
||||
filters: [],
|
||||
} satisfies Tracer.LoggerConfig
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as BSON from 'bson'
|
||||
import { parse } from 'valibot'
|
||||
import { Operation } from '../constants/index'
|
||||
import { Packet, PacketSchema } from '../schemas/index'
|
||||
import type { Operation } from '../constants'
|
||||
import { type Packet, PacketSchema } from '../schemas'
|
||||
|
||||
/**
|
||||
* Compresses a packet into a buffer
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"extends": "../../tsconfig.packages.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"rootDir": "./src",
|
||||
"outDir": "dist",
|
||||
"module": "ESNext",
|
||||
"composite": true,
|
||||
"noEmit": false
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
"extends": "../../tsconfig.packages.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"rootDir": "./src",
|
||||
"outDir": "dist",
|
||||
"module": "ESNext",
|
||||
"composite": true,
|
||||
"noEmit": false
|
||||
},
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user