oft-agt 0.5.13 → 0.5.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli.mjs +4 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/runtime/api-request.mjs +10 -0
- package/runtime/execute.mjs +3 -2
- package/runtime/presence.mjs +14 -0
- package/templates/bot.mjs +7 -1
- package/version.mjs +1 -1
package/cli.mjs
CHANGED
|
@@ -11,6 +11,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
11
11
|
import { spawn } from 'node:child_process';
|
|
12
12
|
import WebSocket from 'ws';
|
|
13
13
|
import {secretOperation,readApiSecret} from './runtime/api-secrets.mjs';
|
|
14
|
+
import {validatePresence} from './runtime/presence.mjs';
|
|
14
15
|
import {requestApi} from './runtime/api-request.mjs';
|
|
15
16
|
import { writeBot, compile } from './compiler.mjs';
|
|
16
17
|
import { acceptSecret } from './secret.mjs';
|
|
@@ -160,7 +161,7 @@ async function start(config) {
|
|
|
160
161
|
try { const response = await fetch('https://discord.com/api/v10/users/@me', { headers: { Authorization: 'Bot ' + secret.token }, signal: AbortSignal.timeout(15000) }); if (response.ok) { const user = await response.json(); profile = { id: user.id, username: user.username, avatar: user.avatar }; } } finally { secret.token = ''; }
|
|
161
162
|
} catch {}
|
|
162
163
|
}
|
|
163
|
-
send({ type: 'hello', agentVersion: AGENT_VERSION, updatesVersion: 1, officialUpdatesVersion: 1, protocol: 2, errorBranch: true, diagnosticsVersion: 2, optionsVersion: 1, conditionsVersion: 1, eventsVersion: 1, apiVersion: 1, complementaryBlocksVersion: 1, discordActionsVersion: 1, messageButtonsVersion: 2, variablesVersion: Number(process.versions.node.split('.')[0]) > 22 || (Number(process.versions.node.split('.')[0]) === 22 && Number(process.versions.node.split('.')[1]) >= 5) ? 1 : 0, metricsVersion: usageReady ? 1 : 0, profile, running: Boolean(child && child.exitCode === null && !child.signalCode), hasToken: await exists(secretPath), deploymentId: active });
|
|
164
|
+
send({ type: 'hello', agentVersion: AGENT_VERSION, updatesVersion: 1, officialUpdatesVersion: 1, protocol: 2, errorBranch: true, diagnosticsVersion: 2, optionsVersion: 1, conditionsVersion: 1, eventsVersion: 1, apiVersion: 1, presenceVersion:1, complementaryBlocksVersion: 1, discordActionsVersion: 1, messageButtonsVersion: 2, variablesVersion: Number(process.versions.node.split('.')[0]) > 22 || (Number(process.versions.node.split('.')[0]) === 22 && Number(process.versions.node.split('.')[1]) >= 5) ? 1 : 0, metricsVersion: usageReady ? 1 : 0, profile, running: Boolean(child && child.exitCode === null && !child.signalCode), hasToken: await exists(secretPath), deploymentId: active });
|
|
164
165
|
if (process.connected) process.send?.({ type: 'agent-ready' }, () => {});
|
|
165
166
|
await usage.flush(send).catch(() => console.error('Statistiques locales indisponibles.'));
|
|
166
167
|
usageTimer = setInterval(() => usage.flush(send).catch(() => console.error('Statistiques locales indisponibles.')), 60000);
|
|
@@ -195,6 +196,8 @@ async function start(config) {
|
|
|
195
196
|
if (message.command === 'stop') { await save(path.join(home, 'paused.json'), {}); await stopBot(); await usage.flush(send).catch(() => {}); send({ type: 'runtime-status', state: 'stopped' }); }
|
|
196
197
|
else if (message.command === 'restart') { await restartBot(config); if (await exists(path.join(home, 'paused.json'))) await unlink(path.join(home, 'paused.json')); send({ type: 'runtime-status', state: 'running' }); }
|
|
197
198
|
} catch { send({ type: 'runtime-status', state: 'failed' }); }
|
|
199
|
+
} else if(message.type==='presence'){
|
|
200
|
+
try{const presence=validatePresence(message.config);await save(path.join(home,'presence.json'),presence);if(child?.connected)child.send({type:'presence',config:presence});}catch{console.error('Presence invalide.');}return;
|
|
198
201
|
} else if(message.type==='api-tool'){try{const result=message.payload.op==='test'?await requestApi(message.payload.config,{resolveSecret:name=>readApiSecret(name,home)}):await secretOperation(home,config.agentId,message.payload);const encoded=Buffer.from(JSON.stringify({result})).toString('base64');if(encoded.length>560000)throw Error('Réponse trop volumineuse.');const total=Math.ceil(encoded.length/1400);for(let index=0;index<total;index++)send({type:'api-result',id:message.id,index,total,chunk:encoded.slice(index*1400,(index+1)*1400)});}catch{send({type:'api-result',id:message.id,error:'Opération API impossible. Vérifiez la requête et les secrets.'});}return;}
|
|
199
202
|
if (message.type === 'deploy') {
|
|
200
203
|
console.log(`[${new Date().toISOString()}] Nouveau déploiement reçu.`);
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oft-agt",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.15",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "oft-agt",
|
|
9
|
-
"version": "0.5.
|
|
9
|
+
"version": "0.5.15",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"discord.js": "^14.14.0",
|
|
12
12
|
"ws": "^8.18.0"
|
package/package.json
CHANGED
package/runtime/api-request.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {interpolateVariables} from './custom-variables.mjs';
|
|
1
2
|
import http from 'node:http';
|
|
2
3
|
import https from 'node:https';
|
|
3
4
|
import {lookup} from 'node:dns';
|
|
@@ -20,3 +21,12 @@ export async function requestApi(raw,{resolveSecret=async()=>{throw Error('Secre
|
|
|
20
21
|
export function responseVariables(c,result){const values={[c.name+'_status-code']:String(result.status),[c.name+'_status-text']:result.statusText,[c.name+'_response']:typeof result.response==='string'?result.response:JSON.stringify(result.response)};for(const o of c.outputs){let v=result.response;for(const key of o.path)v=v&&typeof v==='object'&&Object.hasOwn(v,key)?v[key]:undefined;values[c.name+'_'+o.name]=v===undefined?'':typeof v==='object'?JSON.stringify(v):String(v);}return values;}
|
|
21
22
|
|
|
22
23
|
export function redactApiResult(value,secrets){const redact=s=>{for(const secret of secrets)if(secret)s=s.split(secret).join('••••');return s;};if(typeof value==='string')return redact(value);if(Array.isArray(value))return value.map(v=>redactApiResult(v,secrets));if(value&&typeof value==='object')return Object.fromEntries(Object.entries(value).map(([k,v])=>[redact(k),redactApiResult(v,secrets)]));return value;}
|
|
24
|
+
|
|
25
|
+
export async function interpolateApiArguments(args, options) {
|
|
26
|
+
const {body = '', ...rest} = args;
|
|
27
|
+
const resolved = await interpolateVariables(rest, options);
|
|
28
|
+
if (['GET', 'HEAD'].includes(args.method)) return {...resolved, body: ''};
|
|
29
|
+
let json;
|
|
30
|
+
try { json = JSON.parse(body); } catch { return {...resolved, body: await interpolateVariables(body, options)}; }
|
|
31
|
+
return {...resolved, body: JSON.stringify(await interpolateVariables(json, options))};
|
|
32
|
+
}
|
package/runtime/execute.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import {interpolateApiArguments} from './api-request.mjs';
|
|
1
2
|
import { interpolateVariables, referencedVariables, VARIABLE_WARNING_CODES } from './custom-variables.mjs';
|
|
2
3
|
import { variableRuntimeOptions } from './variable-actions.mjs';
|
|
3
4
|
import { buttonRouter } from './button-router.mjs';
|
|
@@ -133,7 +134,7 @@ async function executeAdmitted(command, interaction, client, options) {
|
|
|
133
134
|
|
|
134
135
|
context.signal.throwIfAborted();
|
|
135
136
|
|
|
136
|
-
const args=await interpolateVariables(call.args,context.variableOptions);
|
|
137
|
+
const args=await (call.fn==='apiRequest'?interpolateApiArguments:interpolateVariables)(call.args,context.variableOptions);
|
|
137
138
|
const prepared=call.fn==='sendMessage'&&args.buttons?.length?(options.buttonRouter||buttonRouter).prepare(command,args.buttons,context,optionValues):null;
|
|
138
139
|
const invoke=async()=>{try{return await registry[call.fn](context,{...args,...(prepared?{components:prepared.components}:{})});}catch(error){prepared?.cancel();throw error;}};
|
|
139
140
|
|
|
@@ -160,7 +161,7 @@ async function executeAdmitted(command, interaction, client, options) {
|
|
|
160
161
|
|
|
161
162
|
context.signal.throwIfAborted();
|
|
162
163
|
|
|
163
|
-
const args=interpolateError(await interpolateVariables(call.args,{...context.variableOptions,base:{...context.variableOptions.base,...optionValues,...variables}}),variables);
|
|
164
|
+
const args=interpolateError(await (call.fn==='apiRequest'?interpolateApiArguments:interpolateVariables)(call.args,{...context.variableOptions,base:{...context.variableOptions.base,...optionValues,...variables}}),variables);
|
|
164
165
|
const prepared=call.fn==='sendMessage'&&args.buttons?.length?(options.buttonRouter||buttonRouter).prepare(command,args.buttons,context,{...optionValues,...variables}):null;
|
|
165
166
|
const invoke=async()=>{try{return await registry[call.fn](context,{...args,...(prepared?{components:prepared.components}:{})});}catch(error){prepared?.cancel();throw error;}};
|
|
166
167
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const DEFAULT_PRESENCE = Object.freeze({status:'online',type:'none',name:'',url:''});
|
|
2
|
+
export function validatePresence(value) {
|
|
3
|
+
if(!value||typeof value!=='object'||Array.isArray(value))throw Error('Présence invalide.');
|
|
4
|
+
const {status,type,name='',url=''}=value;
|
|
5
|
+
if(!['online','idle','dnd','invisible'].includes(status)||!['none','playing','streaming','listening','watching','competing','custom'].includes(type))throw Error('Statut ou activité invalide.');
|
|
6
|
+
if(typeof name!=='string'||name.trim().length>128||typeof url!=='string'||url.length>512)throw Error('Activité invalide.');
|
|
7
|
+
if(type!=='none'&&!name.trim())throw Error('Indiquez le texte de l’activité.');
|
|
8
|
+
if(type==='streaming'&&!/^https:\/\/(www\.)?(twitch\.tv\/[^\s]+|youtube\.com\/(watch\?v=|live\/)[^\s]+)$/.test(url))throw Error('Lien Twitch ou YouTube HTTPS requis.');
|
|
9
|
+
return {status,type,name:type==='none'?'':name.trim(),url:type==='streaming'?url:''};
|
|
10
|
+
}
|
|
11
|
+
export function discordPresence(config){
|
|
12
|
+
const c=validatePresence(config),types={playing:0,streaming:1,listening:2,watching:3,custom:4,competing:5};
|
|
13
|
+
return {status:c.status,afk:c.status==='idle',activities:c.type==='none'?[]:[{name:c.type==='custom'?'Custom Status':c.name,type:types[c.type],...(c.type==='custom'?{state:c.name}:{}),...(c.url?{url:c.url}:{})}]};
|
|
14
|
+
}
|
package/templates/bot.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import {DEFAULT_PRESENCE,discordPresence} from './runtime/presence.mjs';
|
|
2
|
+
import path from 'node:path';
|
|
1
3
|
import { EVENTS } from './runtime/events.mjs';
|
|
2
4
|
import { registerEvents } from './runtime/event-runtime.mjs';
|
|
3
5
|
import { fileURLToPath } from 'node:url';
|
|
@@ -29,7 +31,11 @@ if (process.argv.includes('--deploy')) {
|
|
|
29
31
|
const client = new Client({ intents:[...intentNames].map(name=>GatewayIntentBits[name]), partials:[Partials.Message,Partials.Channel,Partials.Reaction,Partials.User,Partials.GuildMember] });
|
|
30
32
|
registerEvents(client,eventGraphs,variableOptions);
|
|
31
33
|
const commands = new Map(plan.commands.filter(command=>!command.trigger).map(command => [command.name, command]));
|
|
32
|
-
|
|
34
|
+
let presenceConfig=DEFAULT_PRESENCE;
|
|
35
|
+
try{presenceConfig=JSON.parse(await readFile(path.join(process.env.OFTONE_API_HOME||'.','presence.json'),'utf8'));}catch{}
|
|
36
|
+
const applyPresence=config=>{client.user.setPresence(discordPresence(config));};
|
|
37
|
+
process.on('message',message=>{if(message?.type==='presence')try{discordPresence(message.config);presenceConfig=message.config;if(client.isReady())applyPresence(presenceConfig);}catch{}});
|
|
38
|
+
client.once('ready', () => {applyPresence(presenceConfig);console.log(`Bot connecté : ${client.user.tag}`);});
|
|
33
39
|
client.on('interactionCreate', async interaction => {
|
|
34
40
|
if(interaction.isButton?.()) {
|
|
35
41
|
try{await executeButtonInteraction(interaction,client,{...variableOptions,onExecution: sample => { if(process.connected&&process.send)try{process.send({type:'usage',hour:Math.floor(Date.now()/3600000)*3600000,...sample},()=>{});}catch{} }});}catch(error){
|
package/version.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const AGENT_VERSION = '0.5.
|
|
1
|
+
export const AGENT_VERSION = '0.5.15';
|