ecokind-moderation-sdk
Version:
EcoKind - A privacy-first moderation SDK powered by decentralized LLMs on the Internet Computer. Making the internet safer, one message at a time.
285 lines (245 loc) • 8.02 kB
JavaScript
const { Actor, HttpAgent } = require('@dfinity/agent');
const { Principal } = require('@dfinity/principal');
// Define the canister interface (IDL)
const idlFactory = ({ IDL }) => {
const Message = IDL.Record({
sender: IDL.Text,
receiver: IDL.Text,
content: IDL.Text,
timestamp: IDL.Int,
});
return IDL.Service({
sendMessage: IDL.Func([IDL.Text, IDL.Text, IDL.Text], [IDL.Bool], []),
receiveMessages: IDL.Func([IDL.Text], [IDL.Vec(Message)], ['query']),
editMessage: IDL.Func([IDL.Text, IDL.Nat, IDL.Text], [IDL.Bool], []),
deleteUserMessages: IDL.Func([IDL.Text], [IDL.Bool], []),
clearMessages: IDL.Func([], [IDL.Bool], []),
harassmentLevel: IDL.Func([IDL.Text], [IDL.Text], []),
suggestImprovedMessage: IDL.Func([IDL.Text], [IDL.Text], []),
validateKey: IDL.Func([IDL.Text, IDL.Text], [IDL.Bool], []),
});
};
class ICMessagingClient {
constructor(canisterId = 'usxsn-hyaaa-aaaad-aapxq-cai', options = {}) {
this.canisterId = canisterId;
this.host = options.host || 'https://icp-api.io';
this.agent = null;
this.actor = null;
this.isLocal = options.isLocal || false;
this.isAuthorized = false;
this.authorizedProject = null;
this.authorizedKey = null;
}
async initialize() {
try {
// Create HTTP agent
this.agent = new HttpAgent({
host: this.host,
});
// For local development, disable certificate verification
if (this.isLocal) {
await this.agent.fetchRootKey();
}
// Create actor
this.actor = Actor.createActor(idlFactory, {
agent: this.agent,
canisterId: this.canisterId,
});
console.log('IC Messaging Client initialized successfully');
return true;
} catch (error) {
console.error('Failed to initialize IC Messaging Client:', error);
throw error;
}
}
async authorize(project, key) {
if (!this.actor) {
throw new Error('Client not initialized. Call initialize() first.');
}
try {
const isValid = await this.actor.validateKey(project, key);
if (isValid) {
this.isAuthorized = true;
this.authorizedProject = project;
this.authorizedKey = key;
console.log(`✅ Authorization successful for project: ${project}`);
return true;
} else {
this.isAuthorized = false;
this.authorizedProject = null;
this.authorizedKey = null;
console.log(`❌ Authorization failed for project: ${project}`);
return false;
}
} catch (error) {
console.error('Error during authorization:', error);
throw error;
}
}
_checkAuthorization() {
if (!this.isAuthorized) {
throw new Error('Not authorized. Please call authorize(project, key) first with valid credentials.');
}
}
async sendMessage(sender, receiver, content) {
if (!this.actor) {
throw new Error('Client not initialized. Call initialize() first.');
}
this._checkAuthorization();
try {
const result = await this.actor.sendMessage(sender, receiver, content);
return result;
} catch (error) {
console.error('Error sending message:', error);
throw error;
}
}
async receiveMessages(userPrincipal) {
if (!this.actor) {
throw new Error('Client not initialized. Call initialize() first.');
}
this._checkAuthorization();
try {
const messages = await this.actor.receiveMessages(userPrincipal);
return messages.map(msg => ({
sender: msg.sender,
receiver: msg.receiver,
content: msg.content,
timestamp: Number(msg.timestamp),
}));
} catch (error) {
console.error('Error receiving messages:', error);
throw error;
}
}
async editMessage(address, index, newContent) {
if (!this.actor) {
throw new Error('Client not initialized. Call initialize() first.');
}
this._checkAuthorization();
try {
const result = await this.actor.editMessage(address, index, newContent);
return result;
} catch (error) {
console.error('Error editing message:', error);
throw error;
}
}
async deleteUserMessages(address) {
if (!this.actor) {
throw new Error('Client not initialized. Call initialize() first.');
}
this._checkAuthorization();
try {
const result = await this.actor.deleteUserMessages(address);
return result;
} catch (error) {
console.error('Error deleting user messages:', error);
throw error;
}
}
async clearMessages() {
if (!this.actor) {
throw new Error('Client not initialized. Call initialize() first.');
}
this._checkAuthorization();
try {
const result = await this.actor.clearMessages();
return result;
} catch (error) {
console.error('Error clearing messages:', error);
throw error;
}
}
async harassmentLevel(content) {
if (!this.actor) {
throw new Error('Client not initialized. Call initialize() first.');
}
this._checkAuthorization();
try {
const result = await this.actor.harassmentLevel(content);
return result;
} catch (error) {
console.error('Error checking harassment level:', error);
throw error;
}
}
async suggestImprovedMessage(content) {
if (!this.actor) {
throw new Error('Client not initialized. Call initialize() first.');
}
this._checkAuthorization();
try {
const result = await this.actor.suggestImprovedMessage(content);
return result;
} catch (error) {
console.error('Error suggesting improved message:', error);
throw error;
}
}
async validateKey(project, input) {
if (!this.actor) {
throw new Error('Client not initialized. Call initialize() first.');
}
// Note: validateKey is the only method that doesn't require authorization
// since it's used for authorization itself
try {
const result = await this.actor.validateKey(project, input);
return result;
} catch (error) {
console.error('Error validating key:', error);
throw error;
}
}
// Utility method to get canister status
async getCanisterStatus() {
if (!this.agent) {
throw new Error('Client not initialized. Call initialize() first.');
}
try {
const status = await this.agent.status();
return status;
} catch (error) {
console.error('Error getting canister status:', error);
throw error;
}
}
}
module.exports = ICMessagingClient;
// Example usage:
/*
const ICMessagingClient = require('./index.js');
async function example() {
const client = new ICMessagingClient();
try {
// Step 1: Initialize the client
await client.initialize();
// Step 2: Authorize with project name and key
const authorized = await client.authorize('machu', 'machu-1750486429293560682');
if (!authorized) {
console.log('Authorization failed!');
return;
}
// Step 3: Now you can use all other functions
const success = await client.sendMessage(
'elsnu-exgt6-a6c4w-zvlfc-3oqrj-5ifj3-adiil-cagsu-sdtml-yeed7-mae',
'xraya-wv56e-7ddrm-fwhih-wx6er-3tiru-agv3f-efbkp-uwqbn-od643-rae',
'Hello, how are you?'
);
console.log('Message sent:', success);
// Receive messages
const messages = await client.receiveMessages('xraya-wv56e-7ddrm-fwhih-wx6er-3tiru-agv3f-efbkp-uwqbn-od643-rae');
console.log('Received messages:', messages);
// Check harassment level
const level = await client.harassmentLevel('This is a test message');
console.log('Harassment level:', level);
// Suggest improved message
const improved = await client.suggestImprovedMessage('This is a rude message');
console.log('Improved message:', improved);
} catch (error) {
console.error('Error in example:', error);
}
}
// Uncomment to run example
// example();
*/