Shared utilities, types, and constants for Revenge Developer Tools.
The shared package provides common functionality used by both the client and server packages:
- Constants - Protocol version, message types, log levels, and default settings
- Types - TypeScript type definitions for messages and settings
- Serializer - Advanced object serialization with depth limiting
- Logger - Terminal logging utilities with prompt preservation (server-side)
The package exports four main modules:
import { LogLevel, MessageType, PROTOCOL_VERSION, DEFAULT_SETTINGS } from '@revenge-mod/devtools-shared/constants'
import type { Message, LogMessage, RunMessage, HelloMessage, HiMessage, Settings } from '@revenge-mod/devtools-shared/types'
import { serialize, deserialize, createDepthLimitedProxy } from '@revenge-mod/devtools-shared/serializer'
import { logger, createClientLogger, setPrompt, clearPromptLine } from '@revenge-mod/devtools-shared/logger'Defines the available log levels:
export const LogLevel = {
Debug: 0, // Verbose debug information
Default: 1, // Normal logs
Warn: 2, // Warning messages
Error: 3, // Error messages
} as constDefines the WebSocket message types:
export const MessageType = {
Hello: 1, // Client introduces itself
Hi: 2, // Server acknowledges connection
Log: 3, // Client sends logs
Run: 4, // Server executes code
} as constCurrent protocol version (2). Used for client-server compatibility checks.
Default configuration for client and server:
export const DEFAULT_SETTINGS: Settings = {
client: {
log: {
level: LogLevel.Default,
inspectDepth: 2,
interceptConsole: true,
},
},
server: {
watch: {
command: false,
},
},
}Base message interface:
interface Message {
type: MessageType
data?: any
}Message for sending logs to the server:
interface LogMessage extends Message {
type: MessageType<'Log'>
data: {
level: LogLevel
message: any[]
}
}Message for executing code on the client:
interface RunMessage extends Message {
type: MessageType<'Run'>
data: {
code: string
mappings: Record<string, string> // Variable name -> path in client scope
}
}Initial client handshake:
interface HelloMessage extends Message {
type: MessageType<'Hello'>
data: {
version: number
info?: string // Optional client description
}
}Server response to handshake:
interface HiMessage extends Message {
type: MessageType<'Hi'>
data: {
version: number
supported: boolean // Whether client version is compatible
settings: ClientSettings
}
}Configuration for the client:
interface ClientSettings {
log: {
level: LogLevel // Minimum log level
interceptConsole: boolean // Whether to intercept console
inspectDepth: number // Max depth for object inspection
}
}Configuration for the server:
interface ServerSettings {
watch: {
command: string | false // Command to run on file changes
}
}Combined settings:
interface Settings {
client: ClientSettings
server: ServerSettings
}The serializer uses superjson with custom transformers for React Native compatibility.
Serialize a value to a JSON string with support for:
- Functions (serialized by name)
- Symbols
- Objects with
Symbol.toStringTag - Circular references
- Special types (Date, RegExp, etc.)
import { serialize } from '@revenge-mod/devtools-shared/serializer'
const data = { fn: () => {}, sym: Symbol('test') }
const json = serialize(data)Deserialize a JSON string back to its original value:
import { deserialize } from '@revenge-mod/devtools-shared/serializer'
const data = deserialize<MyType>(json)Create a proxy that limits object traversal depth to prevent excessive serialization:
import { createDepthLimitedProxy } from '@revenge-mod/devtools-shared/serializer'
const obj = { deep: { nested: { structure: { here: 'value' } } } }
const limited = createDepthLimitedProxy(obj, 2)
// Accessing beyond depth 2 returns special markers:
// limited.deep.nested.structure // Returns [Object]The proxy handles:
- Objects - Replaced with
[Object]at max depth - Functions - Replaced with
[Function: name]at max depth - Getters - Replaced with
[Getter]at max depth - Setters - Replaced with
[Setter]at max depth - Getter/Setter pairs - Replaced with
[Getter/Setter]at max depth - Arrays - Each element is proxied recursively
These markers are rendered with colors in Node.js environments.
Server-side logging utilities that preserve the terminal prompt.
Main logger instance with colored output:
import { logger } from '@revenge-mod/devtools-shared/logger'
logger.debug('Debug message') // Plain output
logger.log('Normal message') // Plain output
logger.info('Info message') // ℹ️ prefix
logger.warn('Warning') // ⚠️ prefix
logger.error('Error') // 🛑 prefix
logger.success('Success') // ✅ prefix
logger.server('Server message') // [SERVER] prefix in magenta
logger.client('a1b2c3d4', 'Client') // [a1b2c3d4] prefix in cyanCreate a logger instance for a specific client:
import { createClientLogger } from '@revenge-mod/devtools-shared/logger'
const clientLog = createClientLogger('a1b2c3d4')
clientLog.log('Message') // [a1b2c3d4] Message
clientLog.warn('Warning') // ⚠️ [a1b2c3d4] Warning
clientLog.error('Error') // 🛑 [a1b2c3d4] ErrorSet the current prompt for preservation during logging:
import { setPrompt } from '@revenge-mod/devtools-shared/logger'
setPrompt('> ', 'user input')Clear the current input line:
import { clearPromptLine } from '@revenge-mod/devtools-shared/logger'
clearPromptLine()The serializer handles complex JavaScript objects:
// Functions are preserved by name
const fn = function namedFunction() {}
serialize({ fn }) // Preserves function name
// Symbols are preserved
const sym = Symbol('description')
serialize({ sym }) // Preserves symbol description
// Special objects maintain their string representation
const map = new Map()
serialize({ map }) // Preserves [object Map] representationPrevents excessive serialization and circular references:
const circular = { a: {} }
circular.a.b = circular
const proxy = createDepthLimitedProxy(circular, 2)
// Access beyond depth returns markers instead of recursing infinitelyThe logger clears and restores the terminal prompt when logging:
// User is typing: "> hello world"
logger.log('New message')
// Output:
// New message
// > hello world (prompt restored)This project is licensed under CC0 1.0. See LICENSE for more details.