Skip to main content

Overview

The database module provides a JSON file-based storage system for guild settings and streamer tracking. All data is persisted to data/guilds.json.
import {
  getGuildSettings,
  getStreamers,
  addStreamer,
  removeStreamer,
  updateStreamer,
  updateStreamers,
  createStreamerId,
  parseStreamerId,
  getAllGuildsWithStreamers,
  getTotalStreamerCount,
} from './database/index.js';

Guild Management

getGuildSettings()

Get all settings for a guild, creating default settings if none exist.
const settings = getGuildSettings('123456789');
console.log(settings.streamers.length);
Signature:
export function getGuildSettings(guildId: string): GuildSettings
guildId
string
required
Discord guild (server) ID
return
GuildSettings
Guild settings object
Default Settings:
const defaultSettings: GuildSettings = {
  streamers: [],
};
Example:
const settings = getGuildSettings('987654321');
if (settings.streamers.length === 0) {
  console.log('No streamers tracked yet');
}

Streamer Queries

getStreamers()

Get all tracked streamers for a guild.
const streamers = getStreamers('123456789');
streamers.forEach(s => console.log(s.username));
Signature:
export function getStreamers(guildId: string): Streamer[]
guildId
string
required
Discord guild ID
return
Streamer[]
Array of streamer objects
Example:
const streamers = getStreamers('123456789');
const liveStreamers = streamers.filter(s => s.isLive);

console.log(`${liveStreamers.length} of ${streamers.length} are live`);

getStreamer()

Get a specific streamer by ID.
const streamer = getStreamer('123456789', 'twitch:xqc');
if (streamer) {
  console.log(streamer.username);
}
Signature:
export function getStreamer(
  guildId: string,
  streamerId: string
): Streamer | undefined
guildId
string
required
Discord guild ID
streamerId
string
required
Streamer ID in format platform:username
return
Streamer | undefined
Streamer object if found, otherwise undefined
Example:
const id = createStreamerId('twitch', 'xqc');
const streamer = getStreamer('123456789', id);

if (streamer) {
  console.log(`Found: ${streamer.username} on ${streamer.platform}`);
  console.log(`Live: ${streamer.isLive}`);
  console.log(`Channel: ${streamer.channelId}`);
}

getAllGuildsWithStreamers()

Get all guilds that have tracked streamers.
const guilds = getAllGuildsWithStreamers();
guilds.forEach(({ guildId, streamers }) => {
  console.log(`Guild ${guildId}: ${streamers.length} streamers`);
});
Signature:
export function getAllGuildsWithStreamers(): Array<{
  guildId: string;
  streamers: Streamer[];
}>
return
Array<{ guildId: string; streamers: Streamer[] }>
Array of objects containing guild ID and their streamers
Example:
const guilds = getAllGuildsWithStreamers();

for (const { guildId, streamers } of guilds) {
  console.log(`\nGuild ${guildId}:`);
  for (const streamer of streamers) {
    console.log(`  - ${streamer.username} (${streamer.platform})`);
  }
}

getTotalStreamerCount()

Get total number of tracked streamers across all guilds.
const total = getTotalStreamerCount();
console.log(`Tracking ${total} streamers`);
Signature:
export function getTotalStreamerCount(): number
return
number
Total streamer count across all guilds
Example:
const total = getTotalStreamerCount();
const guilds = getAllGuildsWithStreamers();
const avgPerGuild = (total / guilds.length).toFixed(1);

console.log(`${total} streamers across ${guilds.length} guilds`);
console.log(`Average: ${avgPerGuild} streamers per guild`);

Streamer Mutations

addStreamer()

Add a streamer to a guild’s tracking list.
const streamer = {
  id: 'twitch:xqc',
  platform: 'twitch',
  username: 'xqc',
  channelId: '123456789',
  isLive: false,
};

const success = addStreamer('987654321', streamer);
Signature:
export function addStreamer(guildId: string, streamer: Streamer): boolean
guildId
string
required
Discord guild ID
streamer
Streamer
required
Streamer object to add
return
boolean
true if added successfully, false if streamer already exists
Example:
import { addStreamer, createStreamerId } from './database/index.js';

const newStreamer = {
  id: createStreamerId('youtube', 'ludwig'),
  platform: 'youtube' as const,
  username: 'ludwig',
  channelId: '123456789',
  isLive: false,
};

if (addStreamer('987654321', newStreamer)) {
  console.log('Streamer added successfully');
} else {
  console.log('Streamer already exists');
}

removeStreamer()

Remove a streamer from a guild’s tracking list.
const removed = removeStreamer('123456789', 'twitch:xqc');
Signature:
export function removeStreamer(guildId: string, streamerId: string): boolean
guildId
string
required
Discord guild ID
streamerId
string
required
Streamer ID: platform:username
return
boolean
true if removed successfully, false if streamer not found
Example:
const id = createStreamerId('kick', 'trainwreckstv');
const removed = removeStreamer('123456789', id);

if (removed) {
  console.log('Streamer removed');
} else {
  console.log('Streamer not found');
}

updateStreamer()

Update a streamer’s data with partial updates.
const updated = updateStreamer('123456789', 'twitch:xqc', {
  isLive: true,
  viewers: 50000,
  title: 'GAMING',
});
Signature:
export function updateStreamer(
  guildId: string,
  streamerId: string,
  data: Partial<Streamer>
): boolean
guildId
string
required
Discord guild ID
streamerId
string
required
Streamer ID: platform:username
data
Partial<Streamer>
required
Partial streamer object with fields to update
return
boolean
true if updated successfully, false if streamer not found
Example:
// Update live status and viewer count
const success = updateStreamer('123', 'twitch:xqc', {
  isLive: true,
  viewers: 75000,
  title: 'VALORANT RANKED',
  startedAt: new Date().toISOString(),
});

if (success) {
  console.log('Streamer updated');
}

updateStreamers()

Replace all streamers for a guild with a new array.
updateStreamers('123456789', updatedStreamers);
Signature:
export function updateStreamers(guildId: string, streamers: Streamer[]): void
guildId
string
required
Discord guild ID
streamers
Streamer[]
required
New array of streamers (replaces existing)
Example:
import { getStreamers, updateStreamers } from './database/index.js';

const streamers = getStreamers('123456789');

// Update all streamers
const updated = streamers.map(s => ({
  ...s,
  isLive: false, // Mark all as offline
}));

updateStreamers('123456789', updated);
Use Case: This function is used by StreamPoller to batch update all streamers after a poll cycle:
const updatedStreamers: Streamer[] = [];

for (const streamer of streamers) {
  const status = await checkStreamer(streamer);
  const updated = await processStatus(guildId, streamer, status);
  updatedStreamers.push(updated);
}

// Save all changes at once
updateStreamers(guildId, updatedStreamers);

Streamer ID Utilities

createStreamerId()

Create a unique streamer ID from platform and username.
const id = createStreamerId('twitch', 'xQc');
console.log(id); // "twitch:xqc"
Signature:
export function createStreamerId(platform: Platform, username: string): string
platform
Platform
required
Platform name
username
string
required
Platform username (will be lowercased)
return
string
Streamer ID in format platform:username (username is lowercased)
Example:
const id1 = createStreamerId('twitch', 'xQc');
const id2 = createStreamerId('twitch', 'XQC');
const id3 = createStreamerId('twitch', 'xqc');

console.log(id1 === id2); // true
console.log(id2 === id3); // true
// All resolve to "twitch:xqc"

parseStreamerId()

Parse a streamer ID into platform and username.
const parsed = parseStreamerId('twitch:xqc');
if (parsed) {
  console.log(parsed.platform); // "twitch"
  console.log(parsed.username); // "xqc"
}
Signature:
export function parseStreamerId(
  id: string
): { platform: Platform; username: string } | null
id
string
required
Streamer ID to parse
return
{ platform: Platform; username: string } | null
Object with platform and username, or null if invalid format
Example:
const parsed = parseStreamerId('youtube:ludwig');

if (parsed) {
  const { platform, username } = parsed;
  console.log(`Platform: ${platform}`);
  console.log(`Username: ${username}`);
  
  // Use with platform checker
  const checker = getChecker(platform);
  const status = await checker(username);
}

// Invalid format returns null
const invalid = parseStreamerId('invalid-id');
console.log(invalid); // null

Data Persistence

File Storage

Data is automatically persisted to data/guilds.json on every mutation:
{
  "123456789": {
    "streamers": [
      {
        "id": "twitch:xqc",
        "platform": "twitch",
        "username": "xqc",
        "channelId": "987654321",
        "isLive": true,
        "title": "VALORANT RANKED",
        "viewers": 50000,
        "followers": 2000000,
        "lastLiveAt": "2026-03-01T12:00:00.000Z"
      }
    ]
  }
}

Loading

Database is loaded automatically on module import:
// Runs on import
loadFromDisk();

Saving

Automatic save after every mutation:
function saveToDisk(): void {
  ensureDataDir();
  
  try {
    const data = Object.fromEntries(cache);
    writeFileSync(DB_FILE, JSON.stringify(data, null, 2), 'utf-8');
  } catch (error) {
    logger.error('Failed to save database:', error);
  }
}

Full Usage Example

import {
  addStreamer,
  removeStreamer,
  getStreamers,
  updateStreamer,
  createStreamerId,
  getAllGuildsWithStreamers,
  getTotalStreamerCount,
} from './database/index.js';

const guildId = '123456789';
const channelId = '987654321';

// Add streamers
const twitchStreamer = {
  id: createStreamerId('twitch', 'xqc'),
  platform: 'twitch' as const,
  username: 'xqc',
  channelId,
  isLive: false,
};

const kickStreamer = {
  id: createStreamerId('kick', 'trainwreckstv'),
  platform: 'kick' as const,
  username: 'trainwreckstv',
  channelId,
  isLive: false,
};

addStreamer(guildId, twitchStreamer);
addStreamer(guildId, kickStreamer);

// List streamers
const streamers = getStreamers(guildId);
console.log(`Tracking ${streamers.length} streamers`);

streamers.forEach(s => {
  console.log(`  - ${s.username} on ${s.platform}`);
});

// Update a streamer
const updated = updateStreamer(guildId, 'twitch:xqc', {
  isLive: true,
  title: 'VARIETY STREAM',
  viewers: 60000,
});

if (updated) {
  console.log('Updated xqc status');
}

// Get stats
const total = getTotalStreamerCount();
const guilds = getAllGuildsWithStreamers();

console.log(`Total: ${total} streamers across ${guilds.length} guilds`);

// Remove a streamer
const removed = removeStreamer(guildId, 'kick:trainwreckstv');
if (removed) {
  console.log('Removed trainwreckstv from tracking');
}

Build docs developers (and LLMs) love