Plugin API Reference
Plugin API Reference
Complete reference for the @ohcnetwork/leaderboard-api package.
Plugin Interface
interface Plugin {
name: string;
version: string;
setup?: (ctx: PluginContext) => Promise<void>;
scrape: (ctx: PluginContext) => Promise<void>;
}
Properties
name (required)
- Type:
string - Description: Unique identifier for the plugin
- Example:
'github-scraper'
version (required)
- Type:
string - Description: Semantic version of the plugin
- Example:
'1.0.0'
Methods
setup(ctx) (optional)
Initialize the plugin and define activity types.
Parameters:
ctx(PluginContext): Plugin context
Returns: Promise<void>
Example:
async setup(ctx) {
await ctx.db.execute(`
INSERT OR IGNORE INTO activity_definition
(slug, name, description, points, icon)
VALUES (?, ?, ?, ?, ?)
`, ['pr_merged', 'PR Merged', 'Pull request merged', 10, 'git-merge']);
}
scrape(ctx) (required)
Fetch data and store activities.
Parameters:
ctx(PluginContext): Plugin context
Returns: Promise<void>
Example:
async scrape(ctx) {
const data = await fetchFromAPI(ctx.config.apiKey);
for (const item of data) {
await ctx.db.execute(`
INSERT OR IGNORE INTO activity (...)
VALUES (...)
`, [...]);
}
}
PluginContext
Context object passed to plugin methods.
interface PluginContext {
db: Database;
config: PluginConfig;
orgConfig: OrgConfig;
logger: Logger;
}
ctx.db
Database instance for storing data.
Type: Database
Methods:
execute(sql, params)- Execute single SQL statementbatch(statements)- Execute multiple statements in transactionclose()- Close database connection
ctx.config
Plugin-specific configuration from config.yaml.
Type: Record<string, unknown>
Example:
plugins:
github:
config:
token: xxx
org: myorg
const { token, org } = ctx.config;
ctx.orgConfig
Organization information.
Type: OrgConfig
Properties:
name- Organization namedescription- Organization descriptionurl- Organization websitelogo_url- Logo URLsocials- Social media links
ctx.logger
Structured logger instance.
Type: Logger
Methods:
debug(message, meta?)- Debug logsinfo(message, meta?)- Info logswarn(message, meta?)- Warning logserror(message, error?, meta?)- Error logs
Database
Database interface for executing SQL queries.
interface Database {
execute(sql: string, params?: unknown[]): Promise<ExecuteResult>;
batch(statements: BatchStatement[]): Promise<BatchResult[]>;
close(): Promise<void>;
}
execute(sql, params?)
Execute a single SQL statement.
Parameters:
sql(string): SQL queryparams(unknown[], optional): Query parameters
Returns: Promise<ExecuteResult>
Example:
const result = await ctx.db.execute(
'SELECT * FROM contributor WHERE username = ?',
['alice']
);
console.log(result.rows); // Array of rows
console.log(result.rowsAffected); // Number of affected rows
batch(statements)
Execute multiple SQL statements in a transaction.
Parameters:
statements(BatchStatement[]): Array of SQL statements
Returns: Promise<BatchResult[]>
Example:
await ctx.db.batch([
{
sql: 'INSERT INTO activity (...) VALUES (...)',
params: [...]
},
{
sql: 'INSERT INTO activity (...) VALUES (...)',
params: [...]
}
]);
Logger
Structured logging interface.
interface Logger {
debug(message: string, meta?: Record<string, unknown>): void;
info(message: string, meta?: Record<string, unknown>): void;
warn(message: string, meta?: Record<string, unknown>): void;
error(message: string, error?: Error, meta?: Record<string, unknown>): void;
}
Methods
debug(message, meta?)
Log debug information.
Example:
ctx.logger.debug('Processing item', { id: item.id, type: item.type });
info(message, meta?)
Log informational messages.
Example:
ctx.logger.info('Fetched data', { count: items.length });
warn(message, meta?)
Log warnings.
Example:
ctx.logger.warn('API rate limit approaching', { remaining: 10 });
error(message, error?, meta?)
Log errors.
Example:
try {
await fetchData();
} catch (error) {
ctx.logger.error('Failed to fetch data', error, { retries: 3 });
}
Database Schema
contributor
Contributor profiles.
CREATE TABLE contributor (
username VARCHAR PRIMARY KEY,
name VARCHAR,
role VARCHAR,
title VARCHAR,
avatar_url VARCHAR,
bio TEXT,
social_profiles JSON,
joining_date DATE,
meta JSON
);
activity_definition
Activity types defined by plugins.
CREATE TABLE activity_definition (
slug VARCHAR PRIMARY KEY,
name VARCHAR NOT NULL,
description TEXT NOT NULL,
points SMALLINT,
icon VARCHAR
);
activity
Individual activity records.
CREATE TABLE activity (
slug VARCHAR PRIMARY KEY,
contributor VARCHAR REFERENCES contributor(username) NOT NULL,
activity_definition VARCHAR REFERENCES activity_definition(slug) NOT NULL,
title VARCHAR,
occured_at TIMESTAMP NOT NULL,
link VARCHAR,
text TEXT,
points SMALLINT,
meta JSON
);
Indexes:
idx_activity_occured_atonoccured_atidx_activity_contributoroncontributoridx_activity_definitiononactivity_definition
Type Definitions
OrgConfig
interface OrgConfig {
name: string;
description: string;
url: string;
logo_url: string;
start_date?: string;
socials?: {
github?: string;
slack?: string;
linkedin?: string;
youtube?: string;
email?: string;
[key: string]: string | undefined;
};
}
Contributor
interface Contributor {
username: string;
name: string | null;
role: string | null;
title: string | null;
avatar_url: string | null;
bio: string | null;
social_profiles: Record<string, string> | null;
joining_date: string | null;
meta: Record<string, unknown> | null;
}
ActivityDefinition
interface ActivityDefinition {
slug: string;
name: string;
description: string;
points: number | null;
icon: string | null;
}
Activity
interface Activity {
slug: string;
contributor: string;
activity_definition: string;
title: string | null;
occured_at: string;
link: string | null;
text: string | null;
points: number | null;
meta: Record<string, unknown> | null;
}
Error Handling
Plugins should throw errors for unrecoverable failures:
async scrape(ctx) {
if (!ctx.config.apiKey) {
throw new Error('apiKey is required');
}
try {
await fetchData(ctx);
} catch (error) {
ctx.logger.error('Scrape failed', error);
throw error; // Re-throw to fail the plugin run
}
}
The plugin runner will catch and log the error, then exit with a non-zero code.
Best Practices
- Always use parameterized queries to prevent SQL injection
- Use
INSERT OR IGNOREto prevent duplicate activities - Log progress to help with debugging
- Validate configuration before making API calls
- Handle rate limits appropriately
- Use batch inserts for better performance
- Store unique slugs to identify activities
Examples
See the Creating Plugins guide for complete examples.