Skip to content

Latest commit

 

History

History
668 lines (393 loc) · 25 KB

DOCUMENTATION.md

File metadata and controls

668 lines (393 loc) · 25 KB

nibblrjr documentation

API Reference

# input

equal to IRC.command.input

printing text

# print(string{, options})

prints text using the colour parser from IRC.colors. options are;

  • log - boolean   setting false will omit bot messages from the log
  • target - string   channel / user to send to (only works if the command is included in the broadcastCommands config array)

# log(object{, options})

alias for print.log

# notice(string{, options})

same as print but for notices

# action(string{, options})

same as print but for actions

each of the above functions has additional properties;

# printer.log(object{, options})

renders and prints an object using IRC.inspect

options can be those of print and IRC.inspect

# printer.raw(string{, options})

prints text without parsing the colour DSL

# printer.error(error{, options})

prints errors with IRC.colors.error. also used to print thrown errors

# printer.info(string{, options})

prints text with IRC.colors.info

# printer.success(string{, options})

prints text with IRC.colors.success

fetching data

# fetchSync(url{, options}) -> data

works the same as fetch but is synchronous. options are the same as fetch with the addition;

  • type - string   can be text, json or dom
  • form - object   send multipart/form-data fetchSync('https://example.com', { form: { key: 'value' } })

fetchSync blocks, but each command is run concurrently in a separate vm - so other features continue to be responsive

# fetchSync.json(url{, options}) -> object

same as fetchSync, except parses the response as JSON and returns an object

# fetchSync.dom(url{, options}) -> DOM

same as fetchSync, except parses the response as HTML and returns a window object

useful for scraping websites or RSS feeds

const { window, document } = fetchSync.dom('http://google.com');

# jsdom() -> { JSDOM, ... }

helper to set up the environment to run JSDOM and return the library

storing data

key-value store

data is scoped by server and command. data will be stored in the server database

# store.set(key, value)

a simple key-value store. the value can be either string, or undefined|null to remove the value

# store.get(key) -> string|undefined

retrieve the stored value

# store.save(key, value)

a convenience function that JSON stringifies the value sent to the store

# store.load(key{, default value}) -> value

a convenience function that JSON parses the value retrieved from the store

# store.all() -> array

returns an array of objects have have the properties key and value corresponding to the data in the store

# store.clear()

removes all values from the store

# store.namespace

equal to IRC.command.root

different commands store data in different namespaces, only commands with the same root share the same namespace

read more about command.root in IRC.command

SQLite store

the SQLite store is scoped by command namespace only, so data is shared between servers

each command will have a seperate database file. various restrictions on execution time, filesize, and available features of the language have been made for safety reasons

statements have a prepare cache, so repeating the same query is as cheap as if you had prepared it

# SQL.run(query[, ...params]) -> array

run an SQLite statement

# SQL.one(query[, ...params]) -> result

retrieve a single result from a query

# SQL.many(query[, ...params]) -> info

retrieve all results of a query

# SQL.exec(query)

run multiple statements. worse performing, no caching

an example use of the API could be like this; SQL.one('SELECT ?', 1)

however, the SQLite API also allows you to use tagged template strings for safe and easy statement escaping;

SQL.run`INSERT INTO foo (bar) VALUES (${userInput})`

using npm packages

# require(packagename) -> object

download a package from npm and bundle it with esbuild. npm scripts are ignored for safety. subsequent accesses of the same package are cached

packagename can include the version and a path, like - require('react-dom/[email protected]').renderToString( ... )

events

the event system runs in a dedicated long running vm. each server connection has their own vm

by convention, events are stored in commands with the prefix event., but any command can be an event by setting the option in a command editor

only admins have access to changing events

the remote debugger is useful for event development

# IRC.listen(eventname, callback {, options})

run a callback each time an event happens

available events are

the tick event happens every second

the message event happens for each message

the webhook.name events happen when a request is sent to a webhook

the callback will receive some eventData object that always contains a target property with the channel or username

available options are

  • showErrors - boolean   should errors in this event be printed
  • filter - function   provide a callback to dictate if an event should run or not

some additional APIs are only available in events;

# IRC.queryConfig(key{, default value}) -> value

query user-defined config values

will first check the channel config, then server, and then top level

# fetch(url{, options}) -> Promise

API to match browser fetch

async APIs are favoured in events as blocking would cause the event system to pause

# SQL.async.run(query[, ...params]) -> Promise

# SQL.async.one(query[, ...params]) -> Promise

# SQL.async.many(query[, ...params]) -> Promise

# SQL.async.exec(query) -> Promise

async versions of the SQLite API

# IRC.setNamespace(namespace)

change the namespace the key-value and SQLite stores use. this gives the events full access to all command data

webhooks

multiple webhooks can be created on the fly to allow pushing data to the bot

the following route structure is used; https://host/api/webhook/somename

webhooks support any http method, and provide body data and query params as part of the eventData object

for example, the following event;

IRC.listen('webhook.print', (event) => {
    if (IRC.queryConfig('hasPrintWebhook')) {
        print(event.query.message);
    }
})

will cause the request http://host/api/webhook/print?message=foo to print 'foo' to the channel

auth is left as an exercise for the user. it can be as complex or simple as you like

here's a simple tripcode example;

const tripcode = require('tripcode');

IRC.listen('webhook.test', event => {
    const authed = tripcode(event.body.passcode) === IRC.queryConfig('testCode');
    print(authed ? 'pass' : 'fail');
});

which can be used with;

curl -X POST --data-binary '{"passcode":"demo"}' -H "Content-Type: application/json" http://localhost:8888/api/webhook/test

the IRC object

the IRC object includes data and helper functions for IRC-related things, but also contains some general things that didnt quite make it into the big league global scope

# IRC.trigger

a config-defined string denoting the prefix to run commands with

can be revealed by running .bots with no prefix if IBIP is enabled

# IRC.message

an object with information about the current message that triggered the command. has the folowing properties:

  • from - string   nickname of the message sender
  • to - string   where the message was sent
  • text - string   full text of the message
  • message - object   raw information about the message
  • target - string   where the response message is aimed
  • isPM - boolean   if the original message was in PM

# IRC.nick

the current nickname of the bot

# IRC.server

the address the server has connected to

# IRC.channel

the current channel. undefined if message is a PM

# IRC.setNick(string)

change the bot's nick. only works if the user is an admin or the channel has the setNick config option enabled

used in the nick command

# IRC.command

a parsed representation of the current command. uses IRC.parseCommand

  • path - string   the actual command requested ( ~full.path )
  • list - array   the path, split by the . character
  • params - array   list of strings from the command ( ~full.path(param, ...) )
  • root - string   the command namespace ( ~full.path )
  • input - string   the text after the command ( ~command some text )

# IRC.parseCommand(object) -> object

used internally to parse commands. object has the following properties;

  • trigger - string|undefined   the command prefix to use, if at all
  • text - string   the full message

# IRC.webAddress

config-defined URL pointing to the web frontend

# IRC.epoch

date object indicating when the node process was started

# IRC.version

bot version

# IRC.nodeVersion

node.js version

# IRC.secret

a config-defined value for a specific command root. useful for API keys

# IRC.wordList

an array of words from /usr/share/dict/words

# IRC.resetBuffer()

cancel all pending messages (to suppress spam). used in the reset command

# IRC.whois(nick) -> object

provides whois information for a user. properties are: nick, user, host, realname, channels, server, serverinfo, account, accountinfo

# IRC.ping(host) -> promise

runs the CLI ping command at the specified host and provides the output

# IRC.inspect(value{, options}) -> string

object inspector designed for IRC specifically. takes the following options;

  • depth - number   what level of of the tree should be rendered
  • truncate - number   at which point to truncate the output
  • colors - bool   should output be formatted with colours

values of zero will show the maximum instead

colours / formatting

# IRC.colors(string) -> string

DSL parsing function. colours can be disabled entirely in the config

colours

{r}red
{dr}dark red
{w}white
{bl}black
{c}cyan
{dc}dark cyan
{b}blue
{db}dark blue
{g}green
{dg}dark green
{p}magenta
{dp}dark magenta
{o}orange
{y}yellow
{gr}grey
{dgr}dark grey

formatting

{bo}bold
{u}underline
{i}italic

misc

{rb}rainbow
{g,r}background
{rand}random colour
{bell}ascii beep
{/}cancel effects

for example

{r}red{/} and {bo}bold{/} and {rb}rainbow{/} and {r,g}red with green background

# IRC.colors.hash(string) -> string

produces a colour hashed from the input string

# IRC.colors.nick(string[, boolean]) -> string

uses hashing to render a nickname. additionally pass false to not render the angle brackets

# IRC.colors.link(string) -> string

a simple function to render a hyperlink

# IRC.colors.cmd(name[, args, params]) -> string

renders a command with usage information. args and params can be a string or an array of strings

# IRC.colors.error(error|string) -> string

renders an error's name (if different to 'Error') and message

# IRC.colors.info(string) -> string

renders a neutral message

# IRC.colors.success(string) -> string

renders a successful message

# IRC.colors.strip(string) -> string

removes (rendered) colour codes and formatting from a string

dealing with time

# IRC.parseTime(string) -> date

used in the memo and remind commands

parses a string into a date object. it accepts various formats

absolute times

YYYY-MM-DD
HH:MM
HH:MM:SS
3am
3pm
sunday
feb
3rd
march
2019
tomorrow

relative times

3 weeks
1y
4 mins
10 hours
7d

each format can be combined to create a time offset

see here for a full list of strings that are accepted

reading logs

used in the log command and subcommands, but also used to create sed like functionality for messages

# IRC.log.get(text[, limit[, offset]]) -> array

retrieve messages from the channel

# IRC.log.count(text) -> number

return the number of lines that match the provided string

# IRC.log.user(nick, text[, limit[, offset]]) -> array

retrieves messages from a specific user

# IRC.log.random([quantity]) -> array

pull random messages from the log

# IRC.log.regex(string[, limit[, offset]]) -> array

takes a regex as a string to search the database with

text / HTML hosting

# IRC.paste(content, name)

host some content as HTML or text. HTML is sandboxed

manipulating commands

used in the command command and subcommands. commands can also be manipulated via the web frontend

# IRC.commandFns.get(name) -> object|undefined

returns information on a command. properties are;

  • name - string   name of the command
  • command - string   code snippet that is run when the command is triggered
  • locked - boolean   if the command is locked from editing
  • starred - boolean   if the command is a star ★

commands that share the same root also share the same locked / starred state

# IRC.commandFns.list() -> array

returns an array of all command information

# IRC.commandFns.names() -> array

returns an array of all the command names

# IRC.commandFns.count() -> number

returns the number of commands

# IRC.commandFns.setSafe(name, code) -> boolean

sets the code for a particular command. returns true if successful

# IRC.commandFns.deleteSafe(name, code) -> boolean

deletes the command. returns true if successful

# sleep(milliseconds)

blocks the current thread for the specified time. other commands will continue to run

async timers may be added in future

authentication

# IRC.auth()

if the user is not authenticated with nickserv, throws an error. otherwise does nothing

# IRC.sudo() -> object

checks the user is authenticated to nickserv, and checks if the user is in the admins config option for that server, otherwise throw an error

the returned object has the following properties

  • exit - function   kills the main process
  • node - proxy   a bridge out of the vm to the channel's internal node object in the main process

the node proxy allows you to send raw commands and update config options on the fly. examples of its use can be seen in the following commands; reload, reboot, update, join, part, mode, topic, kick, nick, redirect, ignore, debug

update can be used to update the bot without rebooting

modules

# IRC.require(name) -> object

loads a command as a module. the object is whatever was added to module.exports

some useful utilities are available as subcommands of the module command. for example:

IRC.require('module.paste')('hello world') == 'https://paste.rs/PN2'

# module.exports

an object to place functions you would like to export on

# module.required

a boolean indicating if the current command has been required or not. allows commands to be used as commands or modules

configuration

all properties are optional. see the example config

if the configuration file is edited while the bot is running, these changes will be reflected in its behaviour, to the extent that if you change the server address it will leave the old one and rejoin the new one

  • servers array   list of IRC servers to connect to
    • address string   for example: irc.libera.chat
    • password string   password to use for services authentication
    • channels array   list of channels to join.
      • name string   channel name to join. for example: ##rust

the following properties are top level, but can also placed inside the server for a local override

  • trigger string   the prefix to use for running commands (default: ~)
  • nickname string   nickname
  • userName string   username shown in whois information
  • realName string   real name shown in whois information
  • quitMessage string   message to provide when the bot leaves a server
  • floodProtection boolean   should flood protection be enabled (default: true)
  • floodProtectionDelay number   set flood protection time delay in ms (default: 250)
  • autoRejoin boolean   should the bot autorejoin channels when kicked (default: true)
  • ignoreHosts array   list of hostnames to ignore for events and messages entirely
  • admins array   list of nicknames of users that have access to IRC.sudo
  • secrets object   keys in this object correspond to commands that have an IRC.secret value
  • broadcastCommands array   list of commands that are able to use the target property of print

the following properties are top level, but can also placed inside the server or channel for a local override

  • lineLimit number   maximum number of lines a command can display (default: 10)
  • charLimit number   maximum number of characters a command can display (default: false)
  • colLimit number   maximum number of characters per line a command can display (default: 400)
  • colors boolean   should colours and formatting be enabled (default: true)
  • setNick boolean   does anyone in this channel have access to IRC.setNick (default: false)
  • enableEvents boolean   should channel run events system (default: true)
  • enableCommands boolean   should commands be triggerable (default: true)

the following properties are top level only

  • timezone string   timezone to use for dates (default: Europe/London)
  • web object   configuration for the web frontend
    • url string   web address for the frontend, available at IRC.webAddress
    • port number   port to host the content at
    • password string   logging in to the web interface allows you to modify locked commands

these used to be part of the core, but are now user-defined configuration values

  • enableIBIP boolean   should the bot conform to IBIP standard (default: true)
  • fetchURL boolean   should URLs posted in channel have their titles displayed (default: true)
  • fetchURLAll boolean   should every scraped URL be shown, or just 'useful' ones (default: false)

REPL

to run code in a JS interpreter, combine the trigger prefix with one of the following symbols

> prints the returned value and >>, # or % run code in an async IIFE

the REPL works as a command like any other, and > takes optional params. the params look like:

>(depth, truncate)

which correspond to the options from IRC.inspect

remote debugger

console output is available in real-time via a HTTP stream. this is useful for live monitoring and development

combine with IRC.sudo().node.debug.set(true) and IRC.sudo().node.parent.dev.set(true) to show deeper levels of debug information

to connect using curl: curl -u io:webpassword https://host/api/iostream