Building Adapters
Create custom adapters to integrate YAKMESH with any database, API, or platform.
What is an Adapter?
Adapters are plugins that connect YAKMESH to external systems. They implement a standard interface for fetching changes, applying updates, and synchronizing data across the mesh network.
BaseAdapter Interface
All adapters extend the BaseAdapter class:
import { BaseAdapter } from '@yakmesh/core/adapters';
class MyAdapter extends BaseAdapter {
constructor(config) {
super('my-adapter', '1.0.0');
this.config = config;
}
async init() {
// Initialize connection to your system
this.db = await connectToDatabase(this.config.connectionString);
}
getSchema() {
// Define what data this adapter manages
return {
tables: ['users', 'posts'],
primaryKeys: { users: 'id', posts: 'id' }
};
}
async fetchChanges(since) {
// Return changes since the given timestamp
return await this.db.query(
'SELECT * FROM changes WHERE updated_at > ?',
[since]
);
}
async applyChange(change) {
// Apply a change received from the mesh
await this.db.query(
'INSERT OR REPLACE INTO ?? SET ?',
[change.table, change.data]
);
}
async validate(data) {
// Validate data before applying
return { valid: true };
}
}
Required Methods
init()
Called once when the adapter is loaded. Initialize connections here.
getSchema()
Returns the data schema this adapter manages.
fetchChanges(since)
Returns all changes since the given timestamp for sync.
applyChange(change)
Applies a change received from another node.
validate(data)
Validates data before applying. Return { valid: true } or { valid: false, error: '...' }.
Registering Your Adapter
import { YAKMESHNode } from '@yakmesh/core';
import { MyAdapter } from './my-adapter.js';
const node = new YAKMESHNode();
// Register the adapter
node.registerAdapter(new MyAdapter({
connectionString: 'postgres://localhost/mydb'
}));
// Start the node
await node.start();
Example: SQLite Adapter
import { BaseAdapter } from '@yakmesh/core/adapters';
import initSqlJs from 'sql.js';
class SQLiteAdapter extends BaseAdapter {
constructor(dbPath) {
super('sqlite', '1.0.0');
this.dbPath = dbPath;
}
async init() {
const SQL = await initSqlJs();
const data = fs.readFileSync(this.dbPath);
this.db = new SQL.Database(data);
}
getSchema() {
const tables = this.db.exec(
"SELECT name FROM sqlite_master WHERE type='table'"
);
return { tables: tables[0].values.flat() };
}
async fetchChanges(since) {
// Implementation depends on your change tracking strategy
}
async applyChange(change) {
this.db.run(change.sql, change.params);
}
}
Pro Tip
Use the this.emit() method inherited from BaseAdapter to emit events
that the mesh can react to, like 'change', 'error', or custom events.
Content Adapters v3.0
Content Adapters serve documents via DARSHAN streaming with optional chat integration. They implement a capability-based security model.
ContentAdapter Interface
import { ContentAdapter, CONTENT_CAPABILITIES } from '@yakmesh/adapters/content-adapter';
class MyContentAdapter extends ContentAdapter {
constructor(config) {
super({
name: 'My Content Source',
id: 'my-content',
capabilities: [
CONTENT_CAPABILITIES.SERVE_PDF,
CONTENT_CAPABILITIES.SEARCH_REFERENCE,
CONTENT_CAPABILITIES.CHAT_QUOTE,
],
...config,
});
}
async lookupReference(reference) {
// Parse and look up the reference
return { reference, text: 'Content here...', found: true };
}
async getContentStream(contentId) {
// Return a stream for DARSHAN's view-not-copy paradigm
return fs.createReadStream(this.getContentPath(contentId));
}
}
Capabilities
| Capability | Description |
|---|---|
SERVE_PDF |
Serve PDF documents via DARSHAN |
SERVE_TEXT |
Serve plain text content |
SEARCH_REFERENCE |
Support looking up by reference |
CHAT_QUOTE |
Generate quote cards for KATHA chat |
STREAM_NETWORK |
Stream content over the mesh |
Chat Mod Adapters v3.0
Chat Mod Adapters extend KATHA chat with slash commands and interactive features. They include security measures to prevent abuse.
ChatModAdapter Interface
import { ChatModAdapter, ChatModManifest, CHAT_MOD_CAPABILITIES } from '@yakmesh/adapters/chat-mod-adapter';
class MyChatMod extends ChatModAdapter {
constructor() {
super(new ChatModManifest({
id: 'my-chat-mod',
version: '1.0.0',
capabilities: [
CHAT_MOD_CAPABILITIES.CMD_SLASH,
CHAT_MOD_CAPABILITIES.GEN_QUOTE,
],
commands: ['/mycommand', '/help'],
rateLimit: { maxPerMinute: 30 },
}));
}
async handleCommand(command, args, context) {
if (command === '/mycommand') {
return this._signResponse({
type: 'text',
content: 'Hello from my adapter!',
});
}
}
}
Security Features
Capability Declaration
Adapters must declare what they can do upfront. Undeclared capabilities are blocked.
Rate Limiting
Default 30 messages per minute per user. Configurable per adapter.
Response Signing
All responses include adapter ID, version, and manifest hash for verification.
Context Sanitization
Adapters only receive context data matching their declared capabilities.
Example: MLV Bible Adapter
The MLV Bible Adapter demonstrates content + chat integration for scripture distribution.
It serves the Modern Literal Version Bible via DARSHAN and adds /bible, /verse commands to KATHA.
import { MLVBibleAdapter } from '@yakmesh/adapters/adapter-mlv-bible';
// Create and initialize
const mlv = new MLVBibleAdapter({
contentPath: './mlv-content',
});
await mlv.init();
// Register with DARSHAN for P2P streaming
await mlv.registerWithDarshan(darshan);
// Register with KATHA for chat commands
mlv.registerWithKatha(katha, chatModRegistry);
// Now users can:
// - Stream MLV PDFs via DARSHAN (view-not-copy)
// - Use /bible John 3:16 in chat
// - Use /verse Gen 1:1-5 for passage lookups
Anti-Censorship Philosophy
Content adapters embody Yakmesh's core principle: no central authority can block your content.
The MLV Bible Adapter is a template for creating adapters for any belief system or documents. Each user hosts their own content—peer-to-peer, cryptographically verified, censorship-resistant.