@tryty/easydc-js 1.2.0 → 1.2.2

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/examples/basic.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // Jalankan: TOKEN=token_bot_kamu node examples/basic.js
2
- const { Bot } = require('easydc-js'); // saat dicoba dari folder ini: require('../src')
2
+ const { Bot } = require('@tryty/easydc-js'); // saat dicoba dari folder ini: require('../src')
3
3
 
4
4
  const bot = new Bot({
5
5
  token: process.env.TOKEN,
package/examples/mongo.js CHANGED
@@ -1,8 +1,8 @@
1
1
  // Bot dengan database MongoDB.
2
- // Pasang dulu: npm install easydc-js discord.js mongodb
2
+ // Pasang dulu: npm install @tryty/easydc-js discord.js mongodb
3
3
  // Jalankan: TOKEN=token_bot MONGO_URI="mongodb+srv://..." node examples/mongo.js
4
- const { Bot } = require('easydc-js'); // saat dicoba dari folder ini: require('../src')
5
- const { mongodb } = require('easydc-js/mongodb'); // saat dicoba dari folder ini: require('../src/plugins/mongodb')
4
+ const { Bot } = require('@tryty/easydc-js'); // saat dicoba dari folder ini: require('../src')
5
+ const { mongodb } = require('@tryty/easydc-js/mongodb'); // saat dicoba dari folder ini: require('../src/plugins/mongodb')
6
6
 
7
7
  const bot = new Bot({ token: process.env.TOKEN, prefix: '!', timezone: 'Asia/Jakarta' });
8
8
 
package/index.d.ts CHANGED
@@ -111,6 +111,8 @@ export class Bot {
111
111
  contextMenu(def: ContextMenuDef): this;
112
112
  /** Pasang command eval siap pakai (butuh `eval: true` dan `owners`). */
113
113
  evalCommand(def?: { name?: string; aliases?: string[] }): this;
114
+ /** Pasang command tes otomatis di Discord asli (butuh `owners`). `ui: true` menambah /tesauto & menu klik-kanan uji. */
115
+ selfTestCommand(def?: { name?: string; aliases?: string[]; ui?: boolean }): this;
114
116
  event(def: EventDef): this;
115
117
  onMemberBan(code: string | Omit<EventDef, 'type'>): this;
116
118
  onMemberUnban(code: string | Omit<EventDef, 'type'>): this;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tryty/easydc-js",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Super easy Discord bot on top of discord.js: write commands with $function[arg] syntax.",
5
5
  "main": "src/index.js",
6
6
  "types": "index.d.ts",
@@ -9,6 +9,7 @@
9
9
  "examples",
10
10
  "index.d.ts",
11
11
  "mongodb.d.ts",
12
+ "voice.d.ts",
12
13
  "README.md",
13
14
  "LICENSE"
14
15
  ],
@@ -21,8 +22,11 @@
21
22
  "discord",
22
23
  "discord.js",
23
24
  "easy",
25
+ "lavalink",
24
26
  "mongodb",
27
+ "music",
25
28
  "plugin",
29
+ "voice",
26
30
  "wrapper"
27
31
  ],
28
32
  "author": "",
@@ -42,14 +46,22 @@
42
46
  "types": "./mongodb.d.ts",
43
47
  "default": "./src/plugins/mongodb.js"
44
48
  },
45
- "./package.json": "./package.json"
49
+ "./package.json": "./package.json",
50
+ "./voice": {
51
+ "types": "./voice.d.ts",
52
+ "default": "./src/plugins/voice.js"
53
+ }
46
54
  },
47
55
  "peerDependencies": {
48
- "mongodb": ">=5.0.0"
56
+ "mongodb": ">=5.0.0",
57
+ "shoukaku": ">=4.0.0"
49
58
  },
50
59
  "peerDependenciesMeta": {
51
60
  "mongodb": {
52
61
  "optional": true
62
+ },
63
+ "shoukaku": {
64
+ "optional": true
53
65
  }
54
66
  }
55
67
  }
package/src/bot.js CHANGED
@@ -2,6 +2,7 @@
2
2
  const fs = require('node:fs');
3
3
  const path = require('node:path');
4
4
  const { BotError, Stop, ValidationError } = require('./errors');
5
+ const { normalizeOwners } = require('./owners');
5
6
  const { parse } = require('./parser');
6
7
  const { Interpreter } = require('./interpreter');
7
8
  const { Context } = require('./context');
@@ -80,7 +81,7 @@ class Bot {
80
81
  };
81
82
  opts.prefix = (Array.isArray(opts.prefix) ? opts.prefix : [opts.prefix]).filter((p) => typeof p === 'string' && p !== '');
82
83
  if (!opts.prefix.length && !opts.mentionPrefix) throw new BotError('Isi minimal satu prefix atau aktifkan mentionPrefix');
83
- opts.owners = (Array.isArray(opts.owners) ? opts.owners : [opts.owners]).filter(Boolean).map(String);
84
+ opts.owners = normalizeOwners(opts.owners);
84
85
  opts.messages = {
85
86
  cooldown: '⏳ Tunggu %time% lagi sebelum memakai perintah ini.',
86
87
  error: '❌ Terjadi kesalahan saat menjalankan perintah.',
@@ -256,6 +257,16 @@ class Bot {
256
257
  return this.command({ name, aliases, code: EVAL_CODE });
257
258
  }
258
259
 
260
+ /**
261
+ * Pasang command tes otomatis (khusus owner) untuk menguji bot di Discord asli.
262
+ * bot.selfTestCommand(); // lalu ketik: !selftest atau !selftest full
263
+ * bot.selfTestCommand({ ui: true }); // + /tesauto & 2 menu klik-kanan untuk dicoba manual
264
+ */
265
+ selfTestCommand(def) {
266
+ // eslint-disable-next-line global-require
267
+ return require('./selftest').installSelfTest(this, def);
268
+ }
269
+
259
270
  /** Handler event. { type, channel?, code } */
260
271
  event(def) {
261
272
  if (!def || !EVENT_TYPES.includes(def.type)) {
@@ -2,6 +2,7 @@
2
2
  const { BotError, Stop } = require('../errors');
3
3
  const { parseTime, formatDuration } = require('../util');
4
4
  const { f, list, cleanId } = require('./helpers');
5
+ const { isOwner } = require('../owners');
5
6
 
6
7
  const MAX_WAIT = 60 * 1000;
7
8
  const MAX_DELETE_IN = 24 * 60 * 60 * 1000;
@@ -45,7 +46,7 @@ module.exports = [
45
46
  }),
46
47
  f('onlyOwner', { max: 1, lazy: true, s: '[pesan?]', d: 'Lanjut hanya jika pengirim ada di opsi owners' },
47
48
  async (ctx, args, api) => {
48
- if (ctx.bot.options.owners.includes(ctx.user?.id)) return '';
49
+ if (isOwner(ctx, '$onlyOwner')) return '';
49
50
  throw new Stop(await msgOf(api, args, 0));
50
51
  }),
51
52
  f('onlyForIDs', { b: 'required', min: 1, max: 2, lazy: true, s: '[id1,id2;pesan?]', d: 'Lanjut hanya untuk user dengan ID tertentu' },
@@ -3,6 +3,7 @@ const util = require('node:util');
3
3
  const { BotError, Stop } = require('../errors');
4
4
  const { parse } = require('../parser');
5
5
  const { f } = require('./helpers');
6
+ const { isOwner } = require('../owners');
6
7
 
7
8
  const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor;
8
9
  const MAX_OUTPUT = 1800;
@@ -13,7 +14,7 @@ function guard(ctx, label) {
13
14
  if (!ctx.bot.options.eval) {
14
15
  throw new Stop(`❌ ${label} dimatikan. Nyalakan dengan new Bot({ eval: true, owners: ['ID_KAMU'] }).`);
15
16
  }
16
- if (!ctx.bot.options.owners.includes(ctx.user?.id)) throw new Stop('❌ Hanya owner bot yang boleh memakai eval.');
17
+ if (!isOwner(ctx, label)) throw new Stop('❌ Hanya owner bot yang boleh memakai eval.');
17
18
  }
18
19
 
19
20
  function clean(ctx, text) {
@@ -88,8 +88,8 @@ module.exports = [
88
88
  return '';
89
89
  }),
90
90
 
91
- f('createThread', { b: 'required', min: 1, max: 3, s: '[nama;messageID?;arsipOtomatisMenit?]', d: 'Buat thread (dari pesan bila messageID diisi). Arsip: 60/1440/4320/10080. Mengembalikan ID thread' },
92
- async (ctx, [name, mid, archive]) => {
91
+ f('createThread', { b: 'required', min: 1, max: 4, s: '[nama;messageID?;arsipOtomatisMenit?;channelID?]', d: 'Buat thread (dari pesan bila messageID diisi; channelID = channel tempat pesan itu, bawaan channel ini). Arsip: 60/1440/4320/10080. Mengembalikan ID thread' },
92
+ async (ctx, [name, mid, archive, cid]) => {
93
93
  if (!name.trim()) throw new BotError('Nama thread tidak boleh kosong');
94
94
  const opts = { name: limit('nama', name.trim(), 100) };
95
95
  if (has(archive)) {
@@ -99,10 +99,11 @@ module.exports = [
99
99
  }
100
100
  let thread;
101
101
  if (has(mid)) {
102
- thread = await (await fetchMessage(ctx, mid)).startThread(opts);
102
+ thread = await (await fetchMessage(ctx, mid, cid)).startThread(opts);
103
103
  } else {
104
- if (!ctx.channel?.threads || typeof ctx.channel.threads.create !== 'function') throw new BotError('Channel ini tidak mendukung thread');
105
- thread = await ctx.channel.threads.create(opts);
104
+ const ch = await channelOrCurrent(ctx, cid);
105
+ if (!ch.threads || typeof ch.threads.create !== 'function') throw new BotError('Channel ini tidak mendukung thread');
106
+ thread = await ch.threads.create(opts);
106
107
  }
107
108
  return thread.id;
108
109
  }),
package/src/owners.js ADDED
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+ const { BotError } = require('./errors');
3
+
4
+ /** Rapikan daftar owners: wajib string; angka besar ditolak karena ID Discord kehilangan ketelitian. */
5
+ function normalizeOwners(input) {
6
+ const list = Array.isArray(input) ? input : [input];
7
+ const out = [];
8
+ for (const raw of list) {
9
+ if (raw === undefined || raw === null || raw === '' || raw === false) continue;
10
+ if (typeof raw === 'number' && !Number.isSafeInteger(raw)) {
11
+ throw new BotError(
12
+ `owners: angka ${raw} tidak akurat karena ID Discord terlalu besar untuk angka JavaScript. ` +
13
+ 'Tulis ID dengan tanda kutip, contoh: owners: ["123456789012345678"]',
14
+ );
15
+ }
16
+ let id = String(raw).trim();
17
+ const mention = /^<@!?(\d+)>$/.exec(id);
18
+ if (mention) id = mention[1];
19
+ id = id.replace(/[​-‍]/g, '');
20
+ if (id) out.push(id);
21
+ }
22
+ return out;
23
+ }
24
+
25
+ /** Cek owner; bila ditolak, tulis petunjuk ke konsol agar mudah dicari penyebabnya. */
26
+ function isOwner(ctx, label) {
27
+ const id = ctx.user?.id;
28
+ const owners = ctx.bot.options.owners;
29
+ if (owners.includes(id)) return true;
30
+ // eslint-disable-next-line no-console
31
+ console.warn(`[easydc] ${label} ditolak: ID pengirim = "${id}", owners yang terdaftar = ${JSON.stringify(owners)}. ` +
32
+ 'Salin ID pengirim ke owners (dengan tanda kutip) bila itu memang akunmu.');
33
+ return false;
34
+ }
35
+
36
+ module.exports = { normalizeOwners, isOwner };
@@ -125,7 +125,7 @@ class MongoDatabase {
125
125
 
126
126
  /**
127
127
  * Plugin MongoDB untuk Bot.
128
- * const { mongodb } = require('easydc-js/mongodb');
128
+ * const { mongodb } = require('@tryty/easydc-js/mongodb');
129
129
  * bot.use(mongodb({ uri: process.env.MONGO_URI, dbName: 'botku' }));
130
130
  */
131
131
  function mongodb(options) {