mirror of
https://github.com/danbulant/discord.js-structures
synced 2026-06-24 17:21:57 +00:00
basic proxy setup
This commit is contained in:
parent
16664d7154
commit
bdb72158fd
12 changed files with 286 additions and 64 deletions
40
index.js
Normal file
40
index.js
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
const discord = require("discord.js");
|
||||||
|
const proxyHandlers = require("./proxies/handlers");
|
||||||
|
const Module = require("module");
|
||||||
|
const StructuresDef = require("./proxies/structures.js");
|
||||||
|
|
||||||
|
const original = discord;
|
||||||
|
const Structures = StructuresDef;
|
||||||
|
|
||||||
|
const proxy = new Proxy(discord, {
|
||||||
|
get(target, property, receiver) {
|
||||||
|
if(property in proxyHandlers) return proxyHandlers[property];
|
||||||
|
if(property === "original") return original;
|
||||||
|
if(property === "Structures") return Structures;
|
||||||
|
if(property === "hook") return hook;
|
||||||
|
return Reflect.get(target, property, receiver);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hooks discord.js-structures into discord.js require, which should fix errors in 3rd party libraries trying to use Structures.
|
||||||
|
* Overwrites global require function
|
||||||
|
* @see [StackOverflow source](https://stackoverflow.com/a/24602188/8404532)
|
||||||
|
*/
|
||||||
|
function hook() {
|
||||||
|
var origRequire = Module.prototype.require;
|
||||||
|
var _require = function(context, path) {
|
||||||
|
return origRequire.call(context, path);
|
||||||
|
};
|
||||||
|
|
||||||
|
Module.prototype.require = function(path) {
|
||||||
|
if(path === "discord.js") {
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _require(this, path);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = proxy;
|
||||||
31
index.mjs
31
index.mjs
|
|
@ -1,31 +0,0 @@
|
||||||
import discord from "discord.js";
|
|
||||||
import { defaultProxy } from "./proxies/index.mjs";
|
|
||||||
import Module from "module";
|
|
||||||
|
|
||||||
/** The proxied version, in case you like named params */
|
|
||||||
export const proxy = new Proxy(discord, defaultProxy);
|
|
||||||
|
|
||||||
/** The original discord.js, unmodified. Useful when using discord.js-structures hooked */
|
|
||||||
export const original = discord;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hooks discord.js-structures into discord.js require, which should fix errors in 3rd party libraries trying to use Structures.
|
|
||||||
* Overwrites global require function
|
|
||||||
* @see [StackOverflow source](https://stackoverflow.com/a/24602188/8404532)
|
|
||||||
*/
|
|
||||||
export function hook() {
|
|
||||||
var origRequire = Module.prototype.require;
|
|
||||||
var _require = function(context, path) {
|
|
||||||
return origRequire.call(context, path);
|
|
||||||
};
|
|
||||||
|
|
||||||
Module.prototype.require = function(path) {
|
|
||||||
if(path === "discord.js") {
|
|
||||||
return proxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _require(this, path);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default proxy;
|
|
||||||
|
|
@ -4,12 +4,15 @@
|
||||||
"description": "Adds discord.js structures back into discord.js",
|
"description": "Adds discord.js structures back into discord.js",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "node test/index.js"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"discord.js": ">=13.0.0-dev.0"
|
"discord.js": ">=13.0.0-dev.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"discord.js": ">=13.0.0-dev.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
proxies/cache.js
Normal file
2
proxies/cache.js
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
module.exports = new WeakMap();
|
||||||
9
proxies/client.js
Normal file
9
proxies/client.js
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {ProxyHandler<import("discord.js").Client>}
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
get(target, property, receiver) {
|
||||||
|
return Reflect.get(target, property, receiver);
|
||||||
|
}
|
||||||
|
}
|
||||||
81
proxies/eventProxy.js
Normal file
81
proxies/eventProxy.js
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
|
||||||
|
module.exports = class EventProxy {
|
||||||
|
proxies = new Map();
|
||||||
|
once = new Map();
|
||||||
|
on = new Map();
|
||||||
|
targetEvents = new WeakMap();
|
||||||
|
handlers = new Map();
|
||||||
|
|
||||||
|
setProxy(event, handler) {
|
||||||
|
this.proxies.set(event, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEvent(event, args) {
|
||||||
|
if(proxies.has(event)) {
|
||||||
|
args = proxies.get(event)(...args);
|
||||||
|
}
|
||||||
|
for(const handler of (proxy.on.get(event) || [])) {
|
||||||
|
handler(...args);
|
||||||
|
}
|
||||||
|
for(const handler of (proxy.once.get(event) || [])) {
|
||||||
|
handler(...args);
|
||||||
|
}
|
||||||
|
proxy.once.delete(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
get proxy() {
|
||||||
|
const proxy = this;
|
||||||
|
/** @type {ProxyHandler} */
|
||||||
|
const handler = {
|
||||||
|
get(target, property) {
|
||||||
|
const events = proxy.targetEvents.get(target) || [];
|
||||||
|
switch(property) {
|
||||||
|
case "on":
|
||||||
|
return (event, handler) => {
|
||||||
|
const handlers = proxy.on.get(event) || [];
|
||||||
|
handlers.push(handler);
|
||||||
|
proxy.on.set(event, handlers);
|
||||||
|
if(!events.includes(event)) {
|
||||||
|
const handler = (...args) => proxy.handleEvent(event, args);
|
||||||
|
proxy.handlers.set(event, handler);
|
||||||
|
target.on(event, handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "once":
|
||||||
|
return (event, handler) => {
|
||||||
|
const handlers = proxy.once.get(event) || [];
|
||||||
|
handlers.push(handler);
|
||||||
|
proxy.once.set(event, handlers);
|
||||||
|
if(!events.includes(event)) {
|
||||||
|
const handler = (...args) => proxy.handleEvent(event, args);
|
||||||
|
proxy.handlers.set(event, handler);
|
||||||
|
target.on(event, handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "off":
|
||||||
|
return (event, handler) => {
|
||||||
|
const handlers = proxy.on.get(event) || [];
|
||||||
|
if(handlers.includes(handler)) handlers.splice(handlers.indexOf(handler), 1);
|
||||||
|
if(handlers.length) {
|
||||||
|
proxy.on.set(event, handlers);
|
||||||
|
} else {
|
||||||
|
proxy.on.delete(event);
|
||||||
|
}
|
||||||
|
const handlers2 = proxy.once.get(event) || [];
|
||||||
|
if(handlers2.includes(handler)) handlers.splice(handlers.indexOf(handler), 1);
|
||||||
|
if(handlers2.length) {
|
||||||
|
proxy.once.set(event, handlers2);
|
||||||
|
} else {
|
||||||
|
proxy.once.delete(event);
|
||||||
|
}
|
||||||
|
if(!handlers.length && !handlers2.length) {
|
||||||
|
target.off(event, proxy.handlers.get(event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Reflect.get(...arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
proxies/handlers.js
Normal file
13
proxies/handlers.js
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
const Structures = require("./structures.js");
|
||||||
|
const discord = require("discord.js");
|
||||||
|
const EventProxy = require("./eventProxy.js");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
Client: class Client {
|
||||||
|
constructor(...params) {
|
||||||
|
var proxy = new EventProxy();
|
||||||
|
return new Proxy(new Proxy(new discord.Client(...params), require("./client.js")), proxy.proxy);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Structures: Structures
|
||||||
|
};
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
|
|
||||||
const proxyHandlers = {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {ProxyHandler<import("discord.js")>}
|
|
||||||
*/
|
|
||||||
export const defaultProxy = {
|
|
||||||
get(target, property, receiver) {
|
|
||||||
if(property in proxyHandlers) return proxyHandlers[property];
|
|
||||||
return Reflect.get(target, property, receiver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
112
proxies/structures.js
Normal file
112
proxies/structures.js
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
const discord = require("discord.js");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An extendable structure:
|
||||||
|
* * **`GuildEmoji`**
|
||||||
|
* * **`DMChannel`**
|
||||||
|
* * **`TextChannel`**
|
||||||
|
* * **`VoiceChannel`**
|
||||||
|
* * **`CategoryChannel`**
|
||||||
|
* * **`NewsChannel`**
|
||||||
|
* * **`StoreChannel`**
|
||||||
|
* * **`GuildMember`**
|
||||||
|
* * **`Guild`**
|
||||||
|
* * **`Message`**
|
||||||
|
* * **`MessageReaction`**
|
||||||
|
* * **`Presence`**
|
||||||
|
* * **`ClientPresence`**
|
||||||
|
* * **`VoiceState`**
|
||||||
|
* * **`Role`**
|
||||||
|
* * **`User`**
|
||||||
|
* @typedef {string} ExtendableStructure
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows for the extension of built-in Discord.js structures that are instantiated by {@link BaseManager Managers}.
|
||||||
|
*/
|
||||||
|
class Structures {
|
||||||
|
constructor() {
|
||||||
|
throw new Error(`The ${this.constructor.name} class may not be instantiated.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a structure class.
|
||||||
|
* @param {string} structure Name of the structure to retrieve
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
static get(structure) {
|
||||||
|
if (typeof structure === 'string') return structures[structure];
|
||||||
|
throw new TypeError(`"structure" argument must be a string (received ${typeof structure})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends a structure.
|
||||||
|
* <warn> Make sure to extend all structures before instantiating your client.
|
||||||
|
* Extending after doing so may not work as expected. </warn>
|
||||||
|
* @param {ExtendableStructure} structure Name of the structure class to extend
|
||||||
|
* @param {Function} extender Function that takes the base class to extend as its only parameter and returns the
|
||||||
|
* extended class/prototype
|
||||||
|
* @returns {Function} Extended class/prototype returned from the extender
|
||||||
|
* @example
|
||||||
|
* const { Structures } = require('discord.js');
|
||||||
|
*
|
||||||
|
* Structures.extend('Guild', Guild => {
|
||||||
|
* class CoolGuild extends Guild {
|
||||||
|
* constructor(client, data) {
|
||||||
|
* super(client, data);
|
||||||
|
* this.cool = true;
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* return CoolGuild;
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
static extend(structure, extender) {
|
||||||
|
if (!structures[structure]) throw new RangeError(`"${structure}" is not a valid extensible structure.`);
|
||||||
|
if (typeof extender !== 'function') {
|
||||||
|
const received = `(received ${typeof extender})`;
|
||||||
|
throw new TypeError(
|
||||||
|
`"extender" argument must be a function that returns the extended structure class/prototype ${received}.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const extended = extender(structures[structure]);
|
||||||
|
if (typeof extended !== 'function') {
|
||||||
|
const received = `(received ${typeof extended})`;
|
||||||
|
throw new TypeError(`The extender function must return the extended structure class/prototype ${received}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(extended.prototype instanceof structures[structure])) {
|
||||||
|
const prototype = Object.getPrototypeOf(extended);
|
||||||
|
const received = `${extended.name || 'unnamed'}${prototype.name ? ` extends ${prototype.name}` : ''}`;
|
||||||
|
throw new Error(
|
||||||
|
'The class/prototype returned from the extender function must extend the existing structure class/prototype' +
|
||||||
|
` (received function ${received}; expected extension of ${structures[structure].name}).`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
structures[structure] = extended;
|
||||||
|
return extended;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const structures = {
|
||||||
|
GuildEmoji: discord.GuildEmoji,
|
||||||
|
DMChannel: discord.DMChannel,
|
||||||
|
TextChannel: discord.TextChannel,
|
||||||
|
VoiceChannel: discord.VoiceChannel,
|
||||||
|
CategoryChannel: discord.CategoryChannel,
|
||||||
|
NewsChannel: discord.NewsChannel,
|
||||||
|
StoreChannel: discord.StoreChannel,
|
||||||
|
GuildMember: discord.GuildMember,
|
||||||
|
Guild: discord.Guild,
|
||||||
|
Message: discord.Message,
|
||||||
|
MessageReaction: discord.MessageReaction,
|
||||||
|
Presence: discord.Presence,
|
||||||
|
ClientPresence: discord.ClientPresence,
|
||||||
|
VoiceState: discord.VoiceState,
|
||||||
|
Role: discord.Role,
|
||||||
|
User: discord.User,
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Structures;
|
||||||
25
test/index.js
Normal file
25
test/index.js
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
const discord = require("../index");
|
||||||
|
const config = require("./config.json");
|
||||||
|
|
||||||
|
discord.Structures.extend('Message', Message => {
|
||||||
|
class BetterMessage extends Message {
|
||||||
|
constructor(client, data) {
|
||||||
|
super(client, data);
|
||||||
|
this.cool = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BetterMessage;
|
||||||
|
});
|
||||||
|
|
||||||
|
const client = new discord.Client({
|
||||||
|
intents: ["GUILDS", "GUILD_MESSAGES"]
|
||||||
|
});
|
||||||
|
client.login(config.token);
|
||||||
|
|
||||||
|
client.on("ready", () => {
|
||||||
|
console.log("Ready as", client.user.tag);
|
||||||
|
})
|
||||||
|
client.on("message", (msg) => {
|
||||||
|
console.log(msg);
|
||||||
|
});
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
import discord from "../index.mjs";
|
|
||||||
import config from "./config.json";
|
|
||||||
|
|
||||||
discord.Structures.extend('Message', Message => {
|
|
||||||
class BetterMessage extends Message {
|
|
||||||
constructor(client, data) {
|
|
||||||
super(client, data);
|
|
||||||
this.cool = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return BetterMessage;
|
|
||||||
});
|
|
||||||
|
|
||||||
const client = new discord.Client();
|
|
||||||
client.login(config.token);
|
|
||||||
|
|
||||||
client.on("message", (msg) => {
|
|
||||||
console.log(msg);
|
|
||||||
});
|
|
||||||
Loading…
Reference in a new issue