From 6057a62d506cfe8c38b36d674fa9ca8449a9d4bb Mon Sep 17 00:00:00 2001 From: PHIDIAS Date: Fri, 15 Aug 2025 20:07:44 +0900 Subject: [PATCH] Reapply "." This reverts commit 685260080e90a54c009a3886d6a336535f3c1c8b. --- controller.js | 193 +++++++++++++++++++++++++++++ controller.ts | 280 ------------------------------------------ info.js | 81 ++++++++++++ info.ts | 92 -------------- instance.js | 34 +++++ instance.ts | 47 ------- message.js | 33 +++++ message.ts | 25 ---- package.json | 20 +-- pnpm-workspace.yaml | 12 ++ tsconfig.browser.json | 4 - tsconfig.json | 6 - tsconfig.node.json | 5 - webpack.config.js | 2 +- 14 files changed, 364 insertions(+), 470 deletions(-) create mode 100644 controller.js delete mode 100644 controller.ts create mode 100644 info.js delete mode 100644 info.ts create mode 100644 instance.js delete mode 100644 instance.ts create mode 100644 message.js delete mode 100644 message.ts create mode 100644 pnpm-workspace.yaml delete mode 100644 tsconfig.browser.json delete mode 100644 tsconfig.json delete mode 100644 tsconfig.node.json diff --git a/controller.js b/controller.js new file mode 100644 index 0000000..9d94d06 --- /dev/null +++ b/controller.js @@ -0,0 +1,193 @@ +'use strict'; +const Discord = require('discord.js'); +const fetch = require('node-fetch'); +const {BaseControllerPlugin} = require('@clusterio/controller'); +const {InstanceActionEvent} = require('./info.js'); +const {ChatEvent} = require("./message.js"); + +const MAX_DISCORD_MESSAGE_LENGTH = 1950; +const MIN_CONFIDENCE_SCORE = 10.0; + +class LibreTranslateAPI { + constructor(url, apiKey, logger = console) { + if (!url || !apiKey) this.logger.error('[Chat Sync] LibreTranslate API configuration is incomplete.'); + try {new URL(url);} catch {this.logger.error('[Chat Sync] LibreTranslate url is invalid');} + this.url = url.endsWith('/') ? url : url + '/'; + this.apiKey = apiKey; + this.logger = logger; + } + + async handleResponse(response) { + if (!response.ok) this.logger.error(`[Chat Sync] API Request got HTTP ${response.status}`); + return response.json(); + } + + async init() { + try { + this.allowedLanguages = (await this.handleResponse(await fetch(`${this.url}languages?api_key=${this.apiKey}`, {method: 'GET'})))?.[0]?.targets || []; + } catch (err) { + this.logger.error(`[Chat Sync] failed to initialize languages:\n${err.stack}`); + } + } + + async translateRequest(q, source, target) { + try { + return (await this.handleResponse(await fetch(`${this.url}translate`, {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({q: q, api_key: this.apiKey, source: source, target: target})})))?.translatedText; + } catch (err) { + this.logger.error(`[Chat Sync] Translation failed:\n${err.stack}`); + } + } + + async detectLanguage(q) { + try { + return (await this.handleResponse(await fetch(`${this.url}detect`, {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({q: q, api_key: this.apiKey})})))?.[0]; + } catch (err) { + this.logger.error(`[Chat Sync] Detection failed:\n${err.stack}`); + } + } + + async translate(query, targetLanguages) { + console.log(query); + const result = {action: false, passage: []}; + + try { + const detection = await this.detectLanguage(query); + + if (!detection || typeof detection !== 'object' || !detection.confidence || !detection.language) { + this.logger.warn('[Chat Sync] Invalid language detection result:', detection); + return result; + } + + if (detection.confidence > MIN_CONFIDENCE_SCORE) { + for (const targetLang of targetLanguages) { + if (!((detection.language === 'zh-Hans' || detection.language === 'zh-Hant') && (targetLang === 'zh-Hans' || targetLang === 'zh-Hant')) && detection.language !== targetLang && this.allowedLanguages.includes(detection.language) && this.allowedLanguages.includes(targetLang)) { + result.action = true; + const translated = await this.translateRequest(query, detection.language, targetLang); + result.passage.push(`[${detection.language} -> ${targetLang}] ${translated}`); + } + } + } + + return result; + } catch (err) { + this.logger.error(`[Chat Sync] translation failed:\n${err.stack}`); + } + } +} + +class ControllerPlugin extends BaseControllerPlugin { + async init() { + this.controller.config.on('fieldChanged', (field, curr, prev) => { + if (field === 'ClusterChatSync.discord_bot_token') { + this.connect().catch(err => { + this.logger.error(`[Chat Sync] Discord bot token:\n${err.stack}`); + }); + } + }); + this.controller.handle(InstanceActionEvent, this.handleInstanceAction.bind(this)); + this.client = null; + await this.connect(); + } + + async clientDestroy() { + if (this.client) { + this.client.destroy(); + this.client = null; + } + } + + async connect() { + await this.clientDestroy(); + + if (!this.controller.config.get('ClusterChatSync.discord_bot_token')) { + this.logger.error('[Chat Sync] Discord bot token not configured.'); + return; + } + + this.client = new Discord.Client({intents: [Discord.GatewayIntentBits.Guilds, Discord.GatewayIntentBits.GuildMessages, Discord.GatewayIntentBits.MessageContent]}); + this.logger.info('[Chat Sync] Logging into Discord.'); + + try { + await this.client.login(this.controller.config.get('ClusterChatSync.discord_bot_token')); + } catch (err) { + this.logger.error(`[Chat Sync] Discord login error:\n${err.stack}`); + await this.clientDestroy(); + return; + } + + this.logger.info('[Chat Sync] Logged in Discord successfully.'); + + if (this.controller.config.get('ClusterChatSync.use_libretranslate')) { + this.translator = new LibreTranslateAPI(this.controller.config.get('ClusterChatSync.libretranslate_url'), this.controller.config.get('ClusterChatSync.libretranslate_key'), this.logger); + await this.translator.init(); + this.translator_language = this.controller.config.get('ClusterChatSync.libretranslate_language').trim().split(/\s+/) || ['zh-Hant', 'en']; + } + } + + async onShutdown() { + await this.clientDestroy(); + } + + async sendMessage(request, nrc_msg) { + const channel_id = this.controller.config.get('ClusterChatSync.discord_channel_mapping')[request.instanceName]; + if (!channel_id) return; + let channel; + + try { + channel = await this.client.channels.fetch(channel_id); + + if (channel === null) { + this.logger.error(`[Chat Sync] Discord Channel ID ${channel_id} not found.`); + return; + } + } catch (err) { + if (err.code !== 10003) { + this.logger.error(`[Chat Sync] Discord channel fetch error:\n${err.stack}`); + } + } + + if (this.controller.config.get('ClusterChatSync.datetime_on_message')) { + let now = new Date(); + nrc_msg = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}${String(now.getMinutes()).padStart(2, '0')}${String(now.getSeconds()).padStart(2, '0')} ${nrc_msg}` + } + + if (nrc_msg.length <= MAX_DISCORD_MESSAGE_LENGTH) { + await channel.send(nrc_msg, {allowedMentions: {parse: []}}); + } else { + while (nrc_msg.length > 0) { + let nrc_cmsg = nrc_msg.slice(0, MAX_DISCORD_MESSAGE_LENGTH); + let nrc_lindex = nrc_cmsg.lastIndexOf(' '); + + if (nrc_lindex !== -1) { + nrc_cmsg = nrc_cmsg.slice(0, nrc_lindex); + nrc_msg = nrc_msg.slice(nrc_lindex).trim(); + } else { + nrc_msg = nrc_msg.slice(MAX_DISCORD_MESSAGE_LENGTH).trim(); + } + + await channel.send(nrc_cmsg, {allowedMentions: {parse: []}}); + } + } + } + + async handleInstanceAction(request, src) { + if (request.action === 'CHAT' || request.action === 'SHOUT') { + const nrc = request.content.replace(/\[special-item=.*?\]/g, '').replace(/<@/g, '<@\u200c>'); + const nrc_index = nrc.indexOf(':'); + const nrc_username = nrc.substring(0, nrc_index); + const nrc_message = nrc.substring(nrc_index + 1).trim(); + await this.sendMessage(request, `**\`${nrc_username}\`**: ${nrc_message}`); + + if (this.controller.config.get('ClusterChatSync.use_libretranslate')) { + const result = await this.translator.translate(nrc_message, this.translator_language); + + if (result && result.action) { + await this.sendMessage(request, `**\`${nrc_username}\`**: ${result.passage}`); + this.instance.sendTo({ instanceId: this.instance.id }, new ChatEvent(this.instance.name, `[color=255,255,255]\`${nrc_username}\`: ${result}[/color]`)); + } + } + } + } +} + +module.exports = {ControllerPlugin}; diff --git a/controller.ts b/controller.ts deleted file mode 100644 index 2a2fdde..0000000 --- a/controller.ts +++ /dev/null @@ -1,280 +0,0 @@ -import { Client, GatewayIntentBits } from 'discord.js'; -import fetch from 'node-fetch'; -import { BaseControllerPlugin } from '@clusterio/controller'; -import { InstanceActionEvent } from './info'; -import { ChatEvent } from './message'; - -const MAX_DISCORD_MESSAGE_LENGTH = 1950; -const MIN_CONFIDENCE_SCORE = 10.0; - -interface TranslationResult { - action: boolean; - passage: string[]; -} - -interface LanguageDetection { - confidence: number; - language: string; - [key: string]: unknown; -} - -class LibreTranslateAPI { - private url: string; - private apiKey: string; - private logger: Console; - private allowedLanguages: string[] = []; - - constructor(url: string, apiKey: string, logger: Console = console) { - if (!url || !apiKey) { - logger.error('[Chat Sync] LibreTranslate API configuration is incomplete.'); - } - try { - new URL(url); - } catch { - logger.error('[Chat Sync] LibreTranslate url is invalid'); - } - this.url = url.endsWith('/') ? url : url + '/'; - this.apiKey = apiKey; - this.logger = logger; - } - - private async handleResponse(response: fetch.Response): Promise { - if (!response.ok) { - this.logger.error(`[Chat Sync] API Request got HTTP ${response.status}`); - } - return response.json(); - } - - async init(): Promise { - try { - const languages = await this.handleResponse( - await fetch(`${this.url}languages?api_key=${this.apiKey}`, { method: 'GET' }) - ); - this.allowedLanguages = languages?.[0]?.targets || []; - } catch (err) { - this.logger.error(`[Chat Sync] failed to initialize languages:\n${err.stack}`); - } - } - - async translateRequest(q: string, source: string, target: string): Promise { - try { - const response = await this.handleResponse( - await fetch(`${this.url}translate`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ q, api_key: this.apiKey, source, target }) - }) - ); - return response?.translatedText; - } catch (err) { - this.logger.error(`[Chat Sync] Translation failed:\n${err.stack}`); - } - } - - async detectLanguage(q: string): Promise { - try { - const response = await this.handleResponse( - await fetch(`${this.url}detect`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ q, api_key: this.apiKey }) - }) - ); - return response?.[0]; - } catch (err) { - this.logger.error(`[Chat Sync] Detection failed:\n${err.stack}`); - } - } - - async translate(query: string, targetLanguages: string[]): Promise { - const result: TranslationResult = { action: false, passage: [] }; - try { - const detection = await this.detectLanguage(query); - if (!detection || typeof detection !== 'object' || !detection.confidence || !detection.language) { - this.logger.warn('[Chat Sync] Invalid language detection result:', detection); - return result; - } - - if (detection.confidence > MIN_CONFIDENCE_SCORE) { - for (const targetLang of targetLanguages) { - if ( - !((detection.language === 'zh-Hans' || detection.language === 'zh-Hant') && - (targetLang === 'zh-Hans' || targetLang === 'zh-Hant')) && - detection.language !== targetLang && - this.allowedLanguages.includes(detection.language) && - this.allowedLanguages.includes(targetLang) - ) { - result.action = true; - const translated = await this.translateRequest(query, detection.language, targetLang); - if (translated) { - result.passage.push(`[${detection.language} -> ${targetLang}] ${translated}`); - } - } - } - } - } catch (err) { - this.logger.error(`[Chat Sync] translation failed:\n${err.stack}`); - } - return result; - } -} - -interface ControllerConfig { - get(key: string): any; - on(event: string, callback: (field: string, curr: any, prev: any) => void); -} - -interface InstanceInfo { - name: string; - id: number; - sendTo(target: string | { instanceId: number }, message: any): void; -} - -export class ControllerPlugin extends BaseControllerPlugin { - private client: Client | null = null; - private translator?: LibreTranslateAPI; - private translator_language: string[] = []; - - constructor( - private controller: { - config: ControllerConfig; - handle(event: any, handler: Function): void; - logger: Console; - }, - private instance: InstanceInfo - ) { - super(); - } - - async init(): Promise { - this.controller.config.on('fieldChanged', (field: string, curr: any, prev: any) => { - if (field === 'ClusterChatSync.discord_bot_token') { - this.connect().catch(err => { - this.controller.logger.error(`[Chat Sync] Discord bot token:\n${err.stack}`); - }); - } - }); - this.controller.handle(InstanceActionEvent, this.handleInstanceAction.bind(this)); - await this.connect(); - } - - private async clientDestroy(): Promise { - if (this.client) { - this.client.destroy(); - this.client = null; - } - } - - private async connect(): Promise { - await this.clientDestroy(); - const token = this.controller.config.get('ClusterChatSync.discord_bot_token'); - if (!token) { - this.controller.logger.error('[Chat Sync] Discord bot token not configured.'); - return; - } - - this.client = new Client({ - intents: [ - GatewayIntentBits.Guilds, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.MessageContent - ] - }); - - this.controller.logger.info('[Chat Sync] Logging into Discord.'); - try { - await this.client.login(token); - } catch (err) { - this.controller.logger.error(`[Chat Sync] Discord login error:\n${err.stack}`); - await this.clientDestroy(); - return; - } - - this.controller.logger.info('[Chat Sync] Logged in Discord successfully.'); - - if (this.controller.config.get('ClusterChatSync.use_libretranslate')) { - this.translator = new LibreTranslateAPI( - this.controller.config.get('ClusterChatSync.libretranslate_url'), - this.controller.config.get('ClusterChatSync.libretranslate_key'), - this.controller.logger - ); - await this.translator.init(); - this.translator_language = this.controller.config.get('ClusterChatSync.libretranslate_language') - .trim() - .split(/\s+/) || ['zh-Hant', 'en']; - } - } - - async onShutdown(): Promise { - await this.clientDestroy(); - } - - private async sendMessage(request: { instanceName: string }, message: string): Promise { - if (!this.client) return; - - const channelMapping = this.controller.config.get('ClusterChatSync.discord_channel_mapping'); - const channel_id = channelMapping[request.instanceName]; - if (!channel_id) return; - - try { - const channel = await this.client.channels.fetch(channel_id); - if (!channel || !channel.isTextBased()) { - this.controller.logger.error(`[Chat Sync] Discord Channel ID ${channel_id} not found or not text channel.`); - return; - } - - if (this.controller.config.get('ClusterChatSync.datetime_on_message')) { - const now = new Date(); - const timestamp = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')} ` + - `${String(now.getHours()).padStart(2, '0')}${String(now.getMinutes()).padStart(2, '0')}${String(now.getSeconds()).padStart(2, '0')}`; - message = `${timestamp} ${message}`; - } - - while (message.length > 0) { - let chunk = message.slice(0, MAX_DISCORD_MESSAGE_LENGTH); - const lastSpace = chunk.lastIndexOf(' '); - - if (lastSpace !== -1 && chunk.length === MAX_DISCORD_MESSAGE_LENGTH) { - chunk = chunk.slice(0, lastSpace); - message = message.slice(lastSpace).trim(); - } else { - message = message.slice(chunk.length).trim(); - } - - await channel.send(chunk, { allowedMentions: { parse: [] } }); - } - } catch (err: any) { - if (err.code !== 10003) { // Unknown Channel error - this.controller.logger.error(`[Chat Sync] Discord channel error:\n${err.stack}`); - } - } - } - - private async handleInstanceAction(request: { - action: string; - content: string; - instanceName: string - }): Promise { - if (request.action !== 'CHAT' && request.action !== 'SHOUT') return; - - const sanitizedContent = request.content - .replace(/\[special-item=.*?\]/g, '') - .replace(/<@/g, '<@\u200c>'); - const colonIndex = sanitizedContent.indexOf(':'); - const username = sanitizedContent.substring(0, colonIndex); - const message = sanitizedContent.substring(colonIndex + 1).trim(); - - await this.sendMessage(request, `**\`${username}\`**: ${message}`); - - if (this.translator && this.controller.config.get('ClusterChatSync.use_libretranslate')) { - const result = await this.translator.translate(message, this.translator_language); - if (result?.action) { - await this.sendMessage(request, `**\`${username}\`**: ${result.passage.join('\n')}`); - this.instance.sendTo( - { instanceId: this.instance.id }, - new ChatEvent(this.instance.name, `[color=255,255,255]\`${username}\`: ${result.passage.join('\n')}[/color]`) - ); - } - } - } -} diff --git a/info.js b/info.js new file mode 100644 index 0000000..a3652cc --- /dev/null +++ b/info.js @@ -0,0 +1,81 @@ +'use strict'; +const lib = require('@clusterio/lib'); + +class InstanceActionEvent { + static type = 'event'; + static src = 'instance'; + static dst = 'controller'; + static plugin = 'ClusterChatSync'; + + constructor(instanceName, action, content) { + this.instanceName = instanceName; + this.action = action; + this.content = content; + } + + static jsonSchema = { + type: 'object', + required: ['instanceName', 'action', 'content'], + properties: {'instanceName': {type: 'string'}, 'action': {type: 'string'}, 'content': {type: 'string'}} + } + + static fromJSON(json) { + return new this(json.instanceName, json.action, json.content); + } +} + +const plugin = { + name: 'ClusterChatSync', + title: 'Cluster Chat Sync', + description: 'One way chat sync.', + instanceEntrypoint: 'instance', + controllerEntrypoint: 'controller', + controllerConfigFields: { + 'ClusterChatSync.discord_bot_token': { + title: 'Discord Bot Token', + description: 'API Token', + type: 'string' + }, + 'ClusterChatSync.datetime_on_message': { + title: 'Message Datetime', + description: 'Append datetime in front', + type: 'boolean', + initialValue: true + }, + 'ClusterChatSync.discord_channel_mapping': { + title: 'Channels', + description: 'Putting the discord channel id and instance relations here', + type: 'object', + initialValue: { + 'S1': '123' + }, + }, + 'ClusterChatSync.use_libretranslate': { + title: 'Translate Message', + description: 'Using self host or paid service of libretranslate', + type: 'boolean', + initialValue: false + }, + 'ClusterChatSync.libretranslate_url': { + title: 'Translate Server URL', + description: 'Including http protocol, and the port if needed', + type: 'string', + initialValue: 'http://localhost:5000' + }, + 'ClusterChatSync.libretranslate_key': { + title: 'Translate Server API Key', + description: 'The API key for the translate server', + type: 'string', + initialValue: '123456' + }, + 'ClusterChatSync.libretranslate_language': { + title: 'Translate Server Target Language', + description: 'Put a space between each language, using ISO 639-1 codes', + type: 'string', + initialValue: 'zh-Hant en' + }, + }, + messages: [InstanceActionEvent], +}; + +module.exports = {plugin, InstanceActionEvent}; diff --git a/info.ts b/info.ts deleted file mode 100644 index 71798c3..0000000 --- a/info.ts +++ /dev/null @@ -1,92 +0,0 @@ -import type { PluginConfigFields, SerializedEvent } from '@clusterio/lib'; - -export class InstanceActionEvent { - static type = 'event'; - static src = 'instance'; - static dst = 'controller'; - static plugin = 'ClusterChatSync'; - - instanceName: string; - action: string; - content: string; - - constructor(instanceName: string, action: string, content: string) { - this.instanceName = instanceName; - this.action = action; - this.content = content; - } - - static jsonSchema = { - type: 'object', - required: ['instanceName', 'action', 'content'] as const, - properties: { - instanceName: { type: 'string' }, - action: { type: 'string' }, - content: { type: 'string' } - } - }; - - static fromJSON(json: SerializedEvent): InstanceActionEvent { - return new this(json.instanceName, json.action, json.content); - } -} - -interface ChannelMapping { - [instanceName: string]: string; -} - -const pluginConfigFields: PluginConfigFields = { - 'ClusterChatSync.discord_bot_token': { - title: 'Discord Bot Token', - description: 'API Token', - type: 'string', - }, - 'ClusterChatSync.datetime_on_message': { - title: 'Message Datetime', - description: 'Append datetime in front', - type: 'boolean', - initialValue: true, - }, - 'ClusterChatSync.discord_channel_mapping': { - title: 'Channels', - description: 'Putting the discord channel id and instance relations here', - type: 'object', - initialValue: { - 'S1': '123' - } as ChannelMapping, - }, - 'ClusterChatSync.use_libretranslate': { - title: 'Translate Message', - description: 'Using self host or paid service of libretranslate', - type: 'boolean', - initialValue: false, - }, - 'ClusterChatSync.libretranslate_url': { - title: 'Translate Server URL', - description: 'Including http protocol, and the port if needed', - type: 'string', - initialValue: 'http://localhost:5000', - }, - 'ClusterChatSync.libretranslate_key': { - title: 'Translate Server API Key', - description: 'The API key for the translate server', - type: 'string', - initialValue: '123456', - }, - 'ClusterChatSync.libretranslate_language': { - title: 'Translate Server Target Language', - description: 'Put a space between each language, using ISO 639-1 codes', - type: 'string', - initialValue: 'zh-Hant en', - }, -}; - -export const plugin = { - name: 'ClusterChatSync', - title: 'Cluster Chat Sync', - description: 'One way chat sync.', - instanceEntrypoint: 'instance', - controllerEntrypoint: 'controller', - controllerConfigFields: pluginConfigFields, - messages: [InstanceActionEvent], -}; diff --git a/instance.js b/instance.js new file mode 100644 index 0000000..5e2e83d --- /dev/null +++ b/instance.js @@ -0,0 +1,34 @@ +"use strict"; +const lib = require("@clusterio/lib"); +const {BaseInstancePlugin} = require("@clusterio/host"); +const {InstanceActionEvent} = require("./info.js"); + +class InstancePlugin extends BaseInstancePlugin { + async init() { + this.messageQueue = []; + } + + onControllerConnectionEvent(event) { + if (event === 'connect') { + for (const [action, content] of this.messageQueue) { + try { + this.instance.sendTo('controller', new InstanceActionEvent(this.instance.name, action, content)); + } catch (err) { + this.messageQueue.push([output.action, output.message]); + } + } + this.messageQueue = []; + } + } + + async onOutput(output) { + if (output.type !== 'action') return; + if (this.host.connector.connected) { + this.instance.sendTo('controller', new InstanceActionEvent(this.instance.name, output.action, output.message)); + } else { + this.messageQueue.push([output.action, output.message]); + } + } +} + +module.exports = {InstancePlugin}; diff --git a/instance.ts b/instance.ts deleted file mode 100644 index 4a5cc44..0000000 --- a/instance.ts +++ /dev/null @@ -1,47 +0,0 @@ -import * as lib from "@clusterio/lib"; -import { BaseInstancePlugin } from "@clusterio/host"; -import { InstanceActionEvent } from "./info"; - -type MessageQueueItem = [string, unknown]; // [action, content] -type ControllerEvent = 'connect' | 'disconnect' | string; -type OutputMessage = { - type: string; - action: string; - message: unknown; -}; - -export class InstancePlugin extends BaseInstancePlugin { - private messageQueue: MessageQueueItem[] = []; - - async init(): Promise { - this.messageQueue = []; - } - - onControllerConnectionEvent(event: ControllerEvent): void { - if (event === 'connect') { - for (const [action, content] of this.messageQueue) { - try { - this.instance.sendTo('controller', - new InstanceActionEvent(this.instance.name, action, content)); - } catch (err) { - this.messageQueue.push([action, content]); - - // Optional: Log the error - console.error('Failed to send queued message:', err); - } - } - this.messageQueue = []; - } - } - - async onOutput(output: OutputMessage): Promise { - if (output.type !== 'action') return; - - if (this.host.connector.connected) { - this.instance.sendTo('controller', - new InstanceActionEvent(this.instance.name, output.action, output.message)); - } else { - this.messageQueue.push([output.action, output.message]); - } - } -} diff --git a/message.js b/message.js new file mode 100644 index 0000000..4408e2e --- /dev/null +++ b/message.js @@ -0,0 +1,33 @@ +// import { Type, Static } from "@sinclair/typebox"; +const {Type, Static} = require("@sinclair/typebox"); + +export class ChatEvent { + // declare ["constructor"]: typeof ChatEvent; + // as const + static type = "event"; + // as const + static src = ["control", "instance"]; + // as const + static dst = "instance"; + // as const + static plugin = "global_chat"; + static permission = null; + + /* + constructor( + public instanceName: string, + public content: string, + ) { + } + */ + + static jsonSchema = Type.Object({ + "instanceName": Type.String(), + "content": Type.String(), + }); + + // json: Static + static fromJSON(json) { + return new this(json.instanceName, json.content); + } +} \ No newline at end of file diff --git a/message.ts b/message.ts deleted file mode 100644 index a6c8b5b..0000000 --- a/message.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Type, Static } from "@sinclair/typebox"; - -export class ChatEvent { - declare ["constructor"]: typeof ChatEvent; - static type = "event" as const; - static src = ["control", "instance"] as const; - static dst = "instance" as const; - static plugin = "global_chat" as const; - static permission = null; - - constructor( - public instanceName: string, - public content: string, - ) { - } - - static jsonSchema = Type.Object({ - "instanceName": Type.String(), - "content": Type.String(), - }); - - static fromJSON(json: Static) { - return new this(json.instanceName, json.content); - } -} \ No newline at end of file diff --git a/package.json b/package.json index ac853ae..8deb9ca 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@phidias0303/clusterio_chat_sync", "version": "1.0.2", "description": "One way chat sync", - "main": "info.ts", + "main": "info.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "prepare": "webpack-cli --env production" @@ -25,19 +25,19 @@ }, "homepage": "https://github.com/PHIDIAS0303/ClusterChatSync#readme", "peerDependencies": { - "@clusterio/lib": "^2.0.0-alpha.21" + "@clusterio/lib": "catalog:" }, "devDependencies": { - "@clusterio/lib": "^2.0.0-alpha.21", - "@clusterio/web_ui": "^2.0.0-alpha.21", - "webpack": "^5.99.9", - "webpack-cli": "^6.0.1", - "webpack-merge": "^6.0.1" + "@clusterio/lib": "catalog:", + "@clusterio/web_ui": "catalog:", + "webpack": "catalog:", + "webpack-cli": "catalog:", + "webpack-merge": "catalog:" }, "dependencies": { - "discord.js": "^14.19.3", - "@sinclair/typebox": "^0.30.4", - "node-fetch": "^3.3.2" + "discord.js": "catalog:", + "@sinclair/typebox": "catalog:", + "node-fetch": "catalog:" }, "publishConfig": { "access": "public" diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..e54b3c5 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,12 @@ +packages: + - "*" + +catalog: + "@clusterio/lib": ^2.0.0-alpha.21 + "@clusterio/web_ui": ^2.0.0-alpha.21 + "@sinclair/typebox": ^0.34.39 + "discord.js": ^14.21.0 + "webpack": ^5.101.2 + "webpack-cli": ^6.0.1 + "webpack-merge": ^6.0.1 + "node-fetch": ^3.3.2 diff --git a/tsconfig.browser.json b/tsconfig.browser.json deleted file mode 100644 index cc77ead..0000000 --- a/tsconfig.browser.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": "../tsconfig.browser.json", - "include": [ "web/**/*.tsx", "web/**/*.ts", "package.json" ], -} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index fe5912a..0000000 --- a/tsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "./tsconfig.node.json" } - ] -} \ No newline at end of file diff --git a/tsconfig.node.json b/tsconfig.node.json deleted file mode 100644 index 7087bbf..0000000 --- a/tsconfig.node.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "../tsconfig.node.json", - "include": ["./**/*.ts"], - "exclude": ["test/*", "./dist/*"], -} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index 6abcf45..13fb006 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -16,7 +16,7 @@ module.exports = (env = {}) => merge(common(env), { name: 'ClusterChatSync', library: {type: 'var', name: 'plugin_ClusterChatSync' }, exposes: { - './': './info.ts', + './': './info.js', './package.json': './package.json', }, shared: {