Task verifiers for ecodrops system - Twitter, Telegram, URL click
npm install tasks-verifiersA TypeScript package providing task verification services for social media platforms (Twitter, Telegram) and URL click tracking. This package offers black-box verifiers that are completely independent of your backend infrastructure, making them easy to integrate and test.
- 🔐 Black-box architecture - No dependencies on your database, ORM, or framework
- 🎯 Simple API - Pass data directly, get boolean results
- 🐛 Built-in logging - Optional logger interface for debugging
- 📦 Zero external dependencies - Pure TypeScript implementation
- ✅ Type-safe - Full TypeScript support with exported types
``bash`
npm install tasks-verifiersor
yarn add tasks-verifiersor
pnpm add tasks-verifiers
`typescript
import {
TelegramVerifier,
TwitterFollowingVerifier,
TwitterReplyVerifier,
UrlClickVerifier,
} from "tasks-verifiers";
// Telegram verification
const telegramVerifier = new TelegramVerifier("your-bot-token");
const isMember = await telegramVerifier.verify(
"user-telegram-id",
"@channel_name"
);
// Twitter following verification
const twitterVerifier = new TwitterFollowingVerifier("your-api-key");
const isFollowing = await twitterVerifier.verify("username", "target-user-id");
// Twitter reply verification
const replyVerifier = new TwitterReplyVerifier("your-api-key");
const hasKeyword = await replyVerifier.verify("username");
// URL click verification
const clickVerifier = new UrlClickVerifier("", undefined, {
checkClick: async (taskId, userId) => {
// Your custom click checking logic
return false;
},
});
const clicked = await clickVerifier.verify("task-id", "user-id");
`
Verifies if a user is a member of a Telegram channel or group.
#### Constructor
`typescript`
constructor(apiKey: string, logger?: Logger, config?: TelegramVerifierConfig)
Parameters:
- apiKey (required): Telegram bot tokenlogger
- (optional): Logger instance implementing the Logger interfaceconfig
- (optional): Configuration objectbotToken?: string
- - Override bot token (defaults to apiKey)
#### Methods
##### verify(userTelegramId: string, chatId: string): Promise
Verifies if a user is a member of the specified Telegram channel/group.
Parameters:
- userTelegramId: Telegram User ID of the user to checkchatId
- : Channel/group ID (e.g., @channel_name or numeric ID like -1001234567890)
Returns: true if user is a member (status is not "left" or "kicked"), false otherwise
Example:
`typescript
import { TelegramVerifier } from "tasks-verifiers";
const verifier = new TelegramVerifier("123456789:ABCdefGHIjklMNOpqrsTUVwxyz");
// Using channel username
const isMember = await verifier.verify("123456789", "@my_channel");
// Using numeric chat ID
const isMember2 = await verifier.verify("123456789", "-1001234567890");
console.log(isMember); // true or false
`
#### Configuration
`typescript`
interface TelegramVerifierConfig {
botToken?: string;
}
Verifies if a user is following a specific Twitter account.
#### Constructor
`typescript`
constructor(apiKey: string, logger?: Logger, config?: TwitterFollowingVerifierConfig)
Parameters:
- apiKey (required): TwitterAPI.io API keylogger
- (optional): Logger instanceconfig
- (optional): Configuration objectapiKey?: string
- - Override API key (defaults to constructor parameter)
#### Methods
##### verify(userTwitterId: string, targetGroupId: string): Promise
Checks if a user is following the target Twitter account.
Parameters:
- userTwitterId: Twitter username without @ (e.g., username, not @username)targetGroupId
- : Twitter User ID of the account to check following status
Returns: true if user is following, false otherwise
Example:
`typescript
import { TwitterFollowingVerifier } from "tasks-verifiers";
const verifier = new TwitterFollowingVerifier("your-twitterapi-io-key");
// Check if user "johndoe" is following account with ID "123456789"
const isFollowing = await verifier.verify("johndoe", "123456789");
console.log(isFollowing); // true or false
`
Note: This verifier uses pagination to check all followings, so it may take some time for users with many followings.
Verifies if a user has tweets or replies containing specific keywords.
#### Constructor
`typescript`
constructor(apiKey: string, logger?: Logger, config?: TwitterReplyVerifierConfig)
Parameters:
- apiKey (required): TwitterAPI.io API keylogger
- (optional): Logger instanceconfig
- (optional): Configuration objectapiKey?: string
- - Override API keykeywords?: string[]
- - Keywords to search for (default: ['@BuildOnLumia', '$LUMIA'])maxPages?: number
- - Maximum number of pages to check (default: 5, each page = 20 tweets)
#### Methods
##### verify(userTwitterId: string): Promise
Checks if a user has tweets/replies containing the specified keywords.
Parameters:
- userTwitterId: Twitter username without @ (e.g., username)
Returns: true if matching tweet is found, false otherwise
Example:
`typescript
import { TwitterReplyVerifier } from "tasks-verifiers";
// With default keywords
const verifier = new TwitterReplyVerifier("your-api-key");
const hasKeywords = await verifier.verify("username");
// With custom keywords
const customVerifier = new TwitterReplyVerifier("your-api-key", undefined, {
keywords: ["@MyBrand", "$MYTOKEN"],
maxPages: 10, // Check up to 200 tweets (10 pages × 20 tweets)
});
const found = await customVerifier.verify("username");
`
Keyword Matching:
- Case-insensitive text matching in tweet content
- Also checks user mentions in tweet entities (e.g., @BuildOnLumia)
Verifies if a click record exists for a task and user through a custom function.
#### Constructor
`typescript`
constructor(apiKey: string, logger?: Logger, config?: UrlClickVerifierConfig)
Parameters:
- apiKey: Not used, but required for consistency (can be empty string)logger
- (optional): Logger instanceconfig
- (required): Configuration objectcheckClick: (taskId: string, userId: string) => Promise
- - Function to check if click exists
#### Methods
##### verify(taskId: string, userId: string): Promise
Checks if a click record exists using the provided checkClick function.
Parameters:
- taskId: Task IDuserId
- : User ID
Returns: Result from the checkClick function
Example:
`typescript
import { UrlClickVerifier } from "tasks-verifiers";
const verifier = new UrlClickVerifier("", undefined, {
checkClick: async (taskId: string, userId: string) => {
// Your database check logic
const record = await db.clicks.findOne({
where: { taskId, userId },
});
return !!record;
},
});
const clicked = await verifier.verify("task-123", "user-456");
`
All verifiers support an optional logger that implements the following interface:
`typescript`
interface Logger {
debug?(message: string, ...args: any[]): void;
log(message: string, ...args: any[]): void;
warn(message: string, ...args: any[]): void;
error(message: string, ...args: any[]): void;
}
Example with NestJS Logger:
`typescript
import { Logger } from "@nestjs/common";
import { TelegramVerifier } from "tasks-verifiers";
const nestLogger = new Logger("MyService");
const verifier = new TelegramVerifier("bot-token", nestLogger);
`
Example with custom logger:
`typescript[DEBUG] ${msg}
const customLogger: Logger = {
debug: (msg, ...args) => console.debug(, ...args),[LOG] ${msg}
log: (msg, ...args) => console.log(, ...args),[WARN] ${msg}
warn: (msg, ...args) => console.warn(, ...args),[ERROR] ${msg}
error: (msg, ...args) => console.error(, ...args),
};
const verifier = new TwitterFollowingVerifier("api-key", customLogger);
`
The package exports TypeScript types for all verifiers and their configurations:
`typescript
// Verifier classes
export { TelegramVerifier } from "tasks-verifiers";
export { TwitterFollowingVerifier } from "tasks-verifiers";
export { TwitterReplyVerifier } from "tasks-verifiers";
export { UrlClickVerifier } from "tasks-verifiers";
// Configuration types
export type { TelegramVerifierConfig } from "tasks-verifiers";
export type { TwitterFollowingVerifierConfig } from "tasks-verifiers";
export type { TwitterReplyVerifierConfig } from "tasks-verifiers";
export type { UrlClickVerifierConfig } from "tasks-verifiers";
// Logger interface
export type { Logger } from "tasks-verifiers";
// Twitter types
export type {
TwitterTweet,
TwitterTweetEntities,
TwitterUserMention,
TwitterLastTweetsResponse,
TwitterFollowing,
TwitterFollowingResponse,
} from "tasks-verifiers";
`
`typescript
import { Injectable, Logger } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { TelegramVerifier as PackageTelegramVerifier } from "tasks-verifiers";
import { User } from "./entities/user.entity";
@Injectable()
export class TelegramVerifier {
private readonly logger = new Logger(TelegramVerifier.name);
private readonly verifier: PackageTelegramVerifier;
constructor(
@InjectRepository(User)
private readonly userRepository: Repository
private readonly configService: ConfigService
) {
const botToken = this.configService.get
this.verifier = new PackageTelegramVerifier(botToken, this.logger);
}
async verify(userId: string, chatId: string): Promise
const user = await this.userRepository.findOne({
where: { id: userId },
select: ["telegramId"],
});
if (!user?.telegramId) {
return false;
}
return this.verifier.verify(user.telegramId, chatId);
}
}
`
`typescript
import express from "express";
import { TwitterFollowingVerifier } from "tasks-verifiers";
const app = express();
const verifier = new TwitterFollowingVerifier(process.env.TWITTER_API_KEY);
app.post("/verify-following", async (req, res) => {
const { username, targetId } = req.body;
try {
const isFollowing = await verifier.verify(username, targetId);
res.json({ isFollowing });
} catch (error) {
res.status(500).json({ error: "Verification failed" });
}
});
`
`typescript
import { TwitterReplyVerifier } from "tasks-verifiers";
async function checkUserTweets(username: string): Promise
const verifier = new TwitterReplyVerifier(
process.env.TWITTER_API_KEY!,
console, // Using console as logger
{
keywords: ["@MyBrand", "$MYTOKEN"],
maxPages: 3,
}
);
const hasKeywords = await verifier.verify(username);
if (hasKeywords) {
console.log(User ${username} has tweets with required keywords);User ${username} does not have matching tweets
} else {
console.log();`
}
}
- Requires a Telegram bot token
- Uses Telegram Bot API: getChatMemberhttps://api.telegram.org/bot{token}/getChatMember
- Endpoint:
- Requires TwitterAPI.io API key
- Uses TwitterAPI.io endpoints:
- Following check: https://api.twitterapi.io/twitter/user/followingshttps://api.twitterapi.io/twitter/user/last_tweets
- Last tweets:
All verifiers return false on error. Errors are logged if a logger is provided. Common error scenarios:
- Missing API keys or tokens
- Invalid user IDs or usernames
- Network errors
- API authentication failures (401, 403)
- Rate limiting
1. Always handle errors: Even though verifiers return false` on error, you should still wrap calls in try-catch for critical operations.
2. Use loggers: Pass a logger instance to enable debugging and monitoring.
3. Cache results: Consider caching verification results to reduce API calls.
4. Rate limiting: Be aware of API rate limits for Twitter and Telegram APIs.
5. User input validation: Validate user IDs and usernames before passing them to verifiers.
ISC
Lumia Team