splatoon3.ink/app/social/clients/TwitterClient.mjs
Matt Isenhower ca632864f8 Add error handling and media validation to social media clients
Wrap send() methods in try-catch with descriptive error messages
and add early return when media is missing.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 20:03:56 -08:00

60 lines
1.5 KiB
JavaScript

import { TwitterApi } from 'twitter-api-v2';
import Client from './Client.mjs';
export default class TwitterClient extends Client
{
key = 'twitter';
name = 'Twitter';
/** @member {TwitterApi} */
#api;
async canSend() {
return process.env.TWITTER_CONSUMER_KEY
&& process.env.TWITTER_CONSUMER_SECRET
&& process.env.TWITTER_ACCESS_TOKEN_KEY
&& process.env.TWITTER_ACCESS_TOKEN_SECRET;
}
api() {
if (!this.#api) {
this.#api = new TwitterApi({
appKey: process.env.TWITTER_CONSUMER_KEY,
appSecret: process.env.TWITTER_CONSUMER_SECRET,
accessToken: process.env.TWITTER_ACCESS_TOKEN_KEY,
accessSecret: process.env.TWITTER_ACCESS_TOKEN_SECRET,
});
}
return this.#api;
}
async send(status, generator) {
if (!status.media?.length) {
console.error(`[${this.name}] No media provided for ${generator.key}`);
return;
}
try {
// Upload images
let mediaIds = await Promise.all(
status.media.map(async m => {
let id = await this.api().v1.uploadMedia(Buffer.from(m.file), { mimeType: m.type });
if (m.altText) {
await this.api().v1.createMediaMetadata(id, { alt_text: { text: m.altText } });
}
return id;
}),
);
// Send status
await this.api().v2.tweet(status.status, { media: { media_ids: mediaIds } });
} catch (error) {
console.error(`[${this.name}] Failed to post ${generator.key}:`, error.message);
throw error;
}
}
}