1 Commits

Author SHA1 Message Date
nxbat 4eb3d2bb34 [CI] Create lint-and-build action. (#14) 2026-09-21 07:06:35 -07:00
14 changed files with 113 additions and 67 deletions
+32
View File
@@ -0,0 +1,32 @@
name: Lint and Build
on:
push:
branches: [master]
pull_request:
jobs:
lint-and-build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "24"
cache: npm
- name: Install dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Type check
run: npm run typecheck
- name: Build
run: npm run build
+2
View File
@@ -29,6 +29,8 @@
"scripts": { "scripts": {
"dev": "tsx watch --enable-source-maps src/index.ts", "dev": "tsx watch --enable-source-maps src/index.ts",
"start": "node dist/index.js", "start": "node dist/index.js",
"lint": "npx eslint .",
"typecheck": "npx tsc --noEmit",
"build": "npm run clean && node scripts/build.js && npm run copyfiles", "build": "npm run clean && node scripts/build.js && npm run copyfiles",
"clean": "rimraf dist", "clean": "rimraf dist",
"copyfiles": "copyfiles -u 1 \"./src/**/*.html\" ./dist", "copyfiles": "copyfiles -u 1 \"./src/**/*.html\" ./dist",
+4 -10
View File
@@ -1,13 +1,13 @@
import { Client as DiscordClient, GatewayIntentBits, MessageFlags, Partials } from 'discord.js'; import { Client as DiscordClient, GatewayIntentBits, MessageFlags, Partials } from 'discord.js';
import { config } from './config'; import { config } from './config';
import events from './events'; import events from './events';
import { ScheduledTasks, Scheduler } from './scheduler';
import { Database } from './shared/Database'; import { Database } from './shared/Database';
import { openRedisClient } from './shared/RedisClient'; import { openRedisClient } from './shared/RedisClient';
import { Handler } from './types'; import { Handler } from './types';
import { initIfNecessary, loadHandlersFrom, refreshCommands } from './utils'; import { initIfNecessary, loadHandlersFrom, refreshCommands } from './utils';
import { initializeWebserver } from './webserver'; import { initializeWebserver } from './webserver';
import { Encrypter } from './shared/Encrypter'; import { Encrypter } from './shared/Encrypter';
import tasks from './tasks';
let ready = false; let ready = false;
@@ -31,6 +31,8 @@ const client = new DiscordClient({
} }
}); });
const scheduler: Scheduler = new Scheduler(client);
const commands: Handler[] = []; const commands: Handler[] = [];
const contextMenus: Handler[] = []; const contextMenus: Handler[] = [];
const buttons: Handler[] = []; const buttons: Handler[] = [];
@@ -139,15 +141,7 @@ client.on('clientReady', async () => {
await initializeWebserver(client); await initializeWebserver(client);
tasks.forEach((task) => { ScheduledTasks.forEach(task => scheduler.add(task));
const handler = () => {
Promise.resolve(task.handle(client))
.catch(e => console.error(`Error in '${task.id}' task:`, e));
};
if (task.firstRun) handler();
setInterval(handler, task.interval);
});
events.forEach(event => events.forEach(event =>
client.on(event.event, (...args) => client.on(event.event, (...args) =>
+23
View File
@@ -0,0 +1,23 @@
import { Client } from 'discord.js';
import { Task } from '../types';
import ScheduledTasks from './tasks';
class Scheduler {
private tasks = new Map<Task, NodeJS.Timeout>();
private context: Client;
constructor(context: Client) {
this.context = context;
}
add(task: Task) {
const interval = setInterval(() => task.handle(this.context), task.interval);
if (task.firstRun) interval._onTimeout();
this.tasks.set(task, interval);
}
}
export {
ScheduledTasks, Scheduler
};
@@ -0,0 +1,14 @@
import { Client } from 'discord.js';
import { Task } from '../../types';
import { checkExpiredBans } from '../../utils';
class CheckExpiredBansTask implements Task {
interval: number = 300000;
firstRun: boolean = true;
async handle(context: Client): Promise<void> {
await checkExpiredBans(context);
}
}
export default new CheckExpiredBansTask();
@@ -0,0 +1,14 @@
import { Client } from 'discord.js';
import { Task } from '../../types';
import { closeOldTickets } from '../../utils';
class CloseStaleTicketsTask implements Task {
interval: number = 3.6e6;
firstRun: boolean = true;
async handle(context: Client): Promise<void> {
await closeOldTickets(context);
}
}
export default new CloseStaleTicketsTask();
+9
View File
@@ -0,0 +1,9 @@
import checkExpiredBansTask from './check-expired-bans-task';
import closeStaleTicketsTask from './close-stale-tickets-task';
import pruneOldMessagesTask from './prune-old-messages-task';
export default [
closeStaleTicketsTask,
checkExpiredBansTask,
pruneOldMessagesTask
];
@@ -0,0 +1,13 @@
import { Task } from '../../types';
import { Database } from '../../shared/Database';
class PruneOldMessagesTask implements Task {
interval: number = 3.6e6;
firstRun: boolean = true;
async handle(): Promise<void> {
await Database.pruneOldMessages();
}
}
export default new PruneOldMessagesTask();
-15
View File
@@ -1,15 +0,0 @@
import { Client } from 'discord.js';
import { Task } from '../types';
import { checkExpiredBans } from '../utils';
const task: Task = {
id: 'checkExpiredBans',
interval: 300000,
firstRun: true,
handle: async (context: Client) => {
await checkExpiredBans(context);
},
};
export default task;
-15
View File
@@ -1,15 +0,0 @@
import { Client } from 'discord.js';
import { Task } from '../types';
import { closeOldTickets } from '../utils';
const task: Task = {
id: 'closeStaleTickets',
interval: 3.6e6,
firstRun: true,
handle: async (context: Client) => {
await closeOldTickets(context);
},
};
export default task;
-9
View File
@@ -1,9 +0,0 @@
import checkExpiredBansTask from './checkExpiredBansTask';
import closeStaleTicketsTask from './closeStaleTicketsTask';
import pruneOldMessagesTask from './pruneOldMessagesTask';
export default [
closeStaleTicketsTask,
checkExpiredBansTask,
pruneOldMessagesTask
];
-15
View File
@@ -1,15 +0,0 @@
import { Client } from 'discord.js';
import { Database } from '../shared/Database';
import { Task } from '../types';
const task: Task = {
id: 'pruneOldMessages',
interval: 3.6e6,
firstRun: true,
handle: async (context: Client) => {
await Database.pruneOldMessages();
},
};
export default task;
+1 -1
View File
@@ -3,4 +3,4 @@ export * from './database-types.d';
export * from './e621-types.d'; export * from './e621-types.d';
export * from './handler.d'; export * from './handler.d';
export * from './helper-types.d'; export * from './helper-types.d';
export * from './task.d'; export * from './scheduler.d';
+1 -2
View File
@@ -1,9 +1,8 @@
import { Client } from 'discord.js'; import { Client } from 'discord.js';
export interface Task { export interface Task {
id: string;
interval: number; interval: number;
firstRun: boolean; firstRun: boolean;
handle(context: Client): Promise<void>; handle(context: Client): Promise<void>;
} };