104 lines
3.4 KiB
TypeScript
104 lines
3.4 KiB
TypeScript
/**
|
|
* Yonexus Server - Discord Notification Service
|
|
*
|
|
* Sends pairing notifications to the configured admin user via Discord DM.
|
|
*/
|
|
|
|
import type { PairingRequest } from "../services/pairing.js";
|
|
import { redactPairingCode } from "../core/logging.js";
|
|
|
|
export interface DiscordNotificationService {
|
|
/**
|
|
* Send a pairing code notification to the admin user.
|
|
* @returns Whether the notification was sent successfully
|
|
*/
|
|
sendPairingNotification(request: PairingRequest): Promise<boolean>;
|
|
}
|
|
|
|
export interface DiscordNotificationConfig {
|
|
botToken: string;
|
|
adminUserId: string;
|
|
}
|
|
|
|
/**
|
|
* Create a Discord notification service.
|
|
*
|
|
* Note: This is a framework stub. Full implementation requires:
|
|
* - Discord bot client integration (e.g., using discord.js)
|
|
* - DM channel creation/fetching
|
|
* - Error handling for blocked DMs, invalid tokens, etc.
|
|
*
|
|
* For v1, this provides the interface and a mock implementation
|
|
* that logs to console. Production deployments should replace
|
|
* this with actual Discord bot integration.
|
|
*/
|
|
export function createDiscordNotificationService(
|
|
config: DiscordNotificationConfig
|
|
): DiscordNotificationService {
|
|
return {
|
|
async sendPairingNotification(request: PairingRequest): Promise<boolean> {
|
|
const redactedCode = redactPairingCode(request.pairingCode);
|
|
|
|
// Log to console (visible in OpenClaw logs)
|
|
console.log("[Yonexus.Server] Pairing notification (Discord DM stub):", {
|
|
identifier: request.identifier,
|
|
pairingCode: redactedCode,
|
|
expiresAt: request.expiresAt,
|
|
ttlSeconds: request.ttlSeconds,
|
|
adminUserId: config.adminUserId
|
|
});
|
|
|
|
// TODO: Replace with actual Discord bot integration
|
|
// Example with discord.js:
|
|
// const client = new Client({ intents: [GatewayIntentBits.DirectMessages] });
|
|
// await client.login(config.botToken);
|
|
// const user = await client.users.fetch(config.adminUserId);
|
|
// await user.send(message);
|
|
|
|
// For now, return true to allow pairing flow to continue
|
|
// In production, this should return false if DM fails
|
|
return true;
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Format a pairing request as a Discord DM message.
|
|
*/
|
|
export function formatPairingMessage(request: PairingRequest): string {
|
|
const expiresDate = new Date(request.expiresAt * 1000);
|
|
const expiresStr = expiresDate.toISOString();
|
|
|
|
return [
|
|
"🔐 **Yonexus Pairing Request**",
|
|
"",
|
|
`**Identifier:** \`${request.identifier}\``,
|
|
`**Pairing Code:** \`${request.pairingCode}\``,
|
|
`**Expires At:** ${expiresStr}`,
|
|
`**TTL:** ${request.ttlSeconds} seconds`,
|
|
"",
|
|
"Please relay this pairing code to the client operator via a trusted out-of-band channel.",
|
|
"Do not share this code over the Yonexus WebSocket connection."
|
|
].join("\n");
|
|
}
|
|
|
|
/**
|
|
* Create a mock notification service for testing.
|
|
* Returns success/failure based on configuration.
|
|
*/
|
|
export function createMockNotificationService(
|
|
options: { shouldSucceed?: boolean } = {}
|
|
): DiscordNotificationService {
|
|
const shouldSucceed = options.shouldSucceed ?? true;
|
|
|
|
return {
|
|
async sendPairingNotification(request: PairingRequest): Promise<boolean> {
|
|
console.log("[Yonexus.Server] Mock pairing notification:");
|
|
console.log(` Identifier: ${request.identifier}`);
|
|
console.log(` Pairing Code: ${redactPairingCode(request.pairingCode)}`);
|
|
console.log(` Success: ${shouldSucceed}`);
|
|
return shouldSucceed;
|
|
}
|
|
};
|
|
}
|