mirror of
https://github.com/danbulant/discord.js
synced 2026-07-05 11:10:38 +00:00
commit
0ca50889ae
27 changed files with 579 additions and 36 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
|
"root": true,
|
||||||
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
|
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
|
||||||
"plugins": ["import"],
|
"plugins": ["import"],
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
|
|
|
||||||
8
.github/workflows/deploy.yml
vendored
8
.github/workflows/deploy.yml
vendored
|
|
@ -15,10 +15,10 @@ jobs:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@master
|
||||||
|
|
||||||
- name: Install Node v12
|
- name: Install Node v14
|
||||||
uses: actions/setup-node@master
|
uses: actions/setup-node@master
|
||||||
with:
|
with:
|
||||||
node-version: 12
|
node-version: 14
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
@ -35,10 +35,10 @@ jobs:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@master
|
uses: actions/checkout@master
|
||||||
|
|
||||||
- name: Install Node v12
|
- name: Install Node v14
|
||||||
uses: actions/setup-node@master
|
uses: actions/setup-node@master
|
||||||
with:
|
with:
|
||||||
node-version: 12
|
node-version: 14
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
|
||||||
16
.github/workflows/test-cron.yml
vendored
16
.github/workflows/test-cron.yml
vendored
|
|
@ -10,10 +10,10 @@ jobs:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
- name: Install Node v12
|
- name: Install Node v14
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12
|
node-version: 14
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
@ -28,10 +28,10 @@ jobs:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
- name: Install Node v12
|
- name: Install Node v14
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12
|
node-version: 14
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
@ -46,10 +46,10 @@ jobs:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install Node v12
|
- name: Install Node v14
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12
|
node-version: 14
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
@ -67,10 +67,10 @@ jobs:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v1
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
- name: Install Node v12
|
- name: Install Node v14
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12
|
node-version: 14
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
|
||||||
16
.github/workflows/test.yml
vendored
16
.github/workflows/test.yml
vendored
|
|
@ -8,10 +8,10 @@ jobs:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install Node v12
|
- name: Install Node v14
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12
|
node-version: 14
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
@ -26,10 +26,10 @@ jobs:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install Node v12
|
- name: Install Node v14
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12
|
node-version: 14
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
@ -44,10 +44,10 @@ jobs:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install Node v12
|
- name: Install Node v14
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12
|
node-version: 14
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
@ -65,10 +65,10 @@ jobs:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
- name: Install Node v12
|
- name: Install Node v14
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v1
|
||||||
with:
|
with:
|
||||||
node-version: 12
|
node-version: 14
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ discord.js is a powerful [Node.js](https://nodejs.org) module that allows you to
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
**Node.js 12.0.0 or newer is required.**
|
**Node.js 14.0.0 or newer is required.**
|
||||||
Ignore any warnings about unmet peer dependencies, as they're all optional.
|
Ignore any warnings about unmet peer dependencies, as they're all optional.
|
||||||
|
|
||||||
Without voice support: `npm install discord.js`
|
Without voice support: `npm install discord.js`
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ These questions are some of the most frequently asked.
|
||||||
|
|
||||||
## No matter what, I get `SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode`‽
|
## No matter what, I get `SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode`‽
|
||||||
|
|
||||||
Update to Node.js 12.0.0 or newer.
|
Update to Node.js 14.0.0 or newer.
|
||||||
|
|
||||||
## How do I get voice working?
|
## How do I get voice working?
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ discord.js is a powerful [Node.js](https://nodejs.org) module that allows you to
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
**Node.js 12.0.0 or newer is required.**
|
**Node.js 14.0.0 or newer is required.**
|
||||||
Ignore any warnings about unmet peer dependencies, as they're all optional.
|
Ignore any warnings about unmet peer dependencies, as they're all optional.
|
||||||
|
|
||||||
Without voice support: `npm install discord.js`
|
Without voice support: `npm install discord.js`
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@
|
||||||
"webpack-cli": "^3.3.12"
|
"webpack-cli": "^3.3.12"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.0.0"
|
"node": ">=14.0.0"
|
||||||
},
|
},
|
||||||
"browser": {
|
"browser": {
|
||||||
"@discordjs/opus": false,
|
"@discordjs/opus": false,
|
||||||
|
|
@ -110,9 +110,9 @@
|
||||||
"src/client/voice/receiver/PacketHandler.js": false,
|
"src/client/voice/receiver/PacketHandler.js": false,
|
||||||
"src/client/voice/receiver/Receiver.js": false,
|
"src/client/voice/receiver/Receiver.js": false,
|
||||||
"src/client/voice/util/PlayInterface.js": false,
|
"src/client/voice/util/PlayInterface.js": false,
|
||||||
"src/client/voice/util/Secretbox.js": false,
|
|
||||||
"src/client/voice/util/Silence.js": false,
|
"src/client/voice/util/Silence.js": false,
|
||||||
"src/client/voice/util/VolumeInterface.js": false
|
"src/client/voice/util/VolumeInterface.js": false,
|
||||||
|
"src/util/Sodium.js": false
|
||||||
},
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
"hooks": {
|
"hooks": {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const BaseClient = require('./BaseClient');
|
const BaseClient = require('./BaseClient');
|
||||||
|
const InteractionClient = require('./InteractionClient');
|
||||||
const ActionsManager = require('./actions/ActionsManager');
|
const ActionsManager = require('./actions/ActionsManager');
|
||||||
const ClientVoiceManager = require('./voice/ClientVoiceManager');
|
const ClientVoiceManager = require('./voice/ClientVoiceManager');
|
||||||
const WebSocketManager = require('./websocket/WebSocketManager');
|
const WebSocketManager = require('./websocket/WebSocketManager');
|
||||||
|
|
@ -103,6 +104,12 @@ class Client extends BaseClient {
|
||||||
? ShardClientUtil.singleton(this, process.env.SHARDING_MANAGER_MODE)
|
? ShardClientUtil.singleton(this, process.env.SHARDING_MANAGER_MODE)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interaction client.
|
||||||
|
* @type {InteractionClient}
|
||||||
|
*/
|
||||||
|
this.interactionClient = new InteractionClient(options, this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All of the {@link User} objects that have been cached at any point, mapped by their IDs
|
* All of the {@link User} objects that have been cached at any point, mapped by their IDs
|
||||||
* @type {UserManager}
|
* @type {UserManager}
|
||||||
|
|
@ -166,7 +173,7 @@ class Client extends BaseClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All custom emojis that the client has access to, mapped by their IDs
|
* All custom emojis that the client has access to, mapped by their IDs
|
||||||
* @type {GuildEmojiManager}
|
* @type {BaseGuildEmojiManager}
|
||||||
* @readonly
|
* @readonly
|
||||||
*/
|
*/
|
||||||
get emojis() {
|
get emojis() {
|
||||||
|
|
|
||||||
207
src/client/InteractionClient.js
Normal file
207
src/client/InteractionClient.js
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const BaseClient = require('./BaseClient');
|
||||||
|
const ApplicationCommand = require('../structures/ApplicationCommand');
|
||||||
|
const Interaction = require('../structures/Interaction');
|
||||||
|
const { Events, ApplicationCommandOptionType, InteractionType, InteractionResponseType } = require('../util/Constants');
|
||||||
|
|
||||||
|
let sodium;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interaction client is used for interactions.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* const client = new InteractionClient({
|
||||||
|
* token: ABC,
|
||||||
|
* publicKey: XYZ,
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* client.on('interactionCreate', () => {
|
||||||
|
* // automatically handles long responses
|
||||||
|
* if (will take a long time) {
|
||||||
|
* doSomethingLong.then((d) => {
|
||||||
|
* interaction.reply({
|
||||||
|
* content: 'wow that took long',
|
||||||
|
* });
|
||||||
|
* });
|
||||||
|
* } else {
|
||||||
|
* interaction.reply('hi!');
|
||||||
|
* }
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class InteractionClient extends BaseClient {
|
||||||
|
/**
|
||||||
|
* @param {Options} options Options for the client.
|
||||||
|
* @param {undefined} client For internal use.
|
||||||
|
*/
|
||||||
|
constructor(options, client) {
|
||||||
|
super(options);
|
||||||
|
|
||||||
|
Object.defineProperty(this, 'token', {
|
||||||
|
value: options.token,
|
||||||
|
writable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(this, 'clientID', {
|
||||||
|
value: options.clientID,
|
||||||
|
writable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(this, 'publicKey', {
|
||||||
|
value: options.publicKey ? Buffer.from(options.publicKey, 'hex') : undefined,
|
||||||
|
writable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Compat for direct usage
|
||||||
|
this.client = client || this;
|
||||||
|
this.interactionClient = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get registered slash commands.
|
||||||
|
* @param {Snowflake} [guildID] Optional guild ID.
|
||||||
|
* @returns {Command[]}
|
||||||
|
*/
|
||||||
|
async getCommands(guildID) {
|
||||||
|
let path = this.client.api.applications('@me');
|
||||||
|
if (guildID) {
|
||||||
|
path = path.guilds(guildID);
|
||||||
|
}
|
||||||
|
const commands = await path.commands.get();
|
||||||
|
return commands.map(c => new ApplicationCommand(this, c, guildID));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a command.
|
||||||
|
* @param {Object} command The command description.
|
||||||
|
* @param {Snowflake?} guildID Optional guild ID.
|
||||||
|
* @returns {ApplicationCommand} The created command.
|
||||||
|
*/
|
||||||
|
createCommand(command, guildID) {
|
||||||
|
let path = this.client.api.applications('@me');
|
||||||
|
if (guildID) {
|
||||||
|
path = path.guilds(guildID);
|
||||||
|
}
|
||||||
|
const c = path.commands.post({
|
||||||
|
data: {
|
||||||
|
name: command.name,
|
||||||
|
description: command.description,
|
||||||
|
options: command.options.map(function m(o) {
|
||||||
|
return {
|
||||||
|
type: ApplicationCommandOptionType[o.type],
|
||||||
|
name: o.name,
|
||||||
|
description: o.description,
|
||||||
|
default: o.default,
|
||||||
|
required: o.required,
|
||||||
|
choices: o.choices,
|
||||||
|
options: o.options ? o.options.map(m) : undefined,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return new ApplicationCommand(this, c, guildID);
|
||||||
|
}
|
||||||
|
|
||||||
|
handle(data) {
|
||||||
|
switch (data.type) {
|
||||||
|
case InteractionType.PING:
|
||||||
|
return {
|
||||||
|
type: InteractionResponseType.PONG,
|
||||||
|
};
|
||||||
|
case InteractionType.APPLICATION_COMMAND: {
|
||||||
|
let timedOut = false;
|
||||||
|
let resolve;
|
||||||
|
const directPromise = new Promise(r => {
|
||||||
|
resolve = r;
|
||||||
|
this.client.setTimeout(() => {
|
||||||
|
timedOut = true;
|
||||||
|
r({
|
||||||
|
type: InteractionResponseType.ACKNOWLEDGE_WITH_SOURCE,
|
||||||
|
});
|
||||||
|
}, 250);
|
||||||
|
});
|
||||||
|
|
||||||
|
const syncHandle = {
|
||||||
|
acknowledge() {
|
||||||
|
if (!timedOut) {
|
||||||
|
resolve({
|
||||||
|
type: InteractionResponseType.ACKNOWLEDGE_WITH_SOURCE,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reply(resolved) {
|
||||||
|
if (timedOut) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
resolve({
|
||||||
|
type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
|
||||||
|
data: resolved.data,
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const interaction = new Interaction(this.client, data, syncHandle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted when an interaction is created.
|
||||||
|
* @event Client#interactionCreate
|
||||||
|
* @param {Interaction} interaction The interaction which was created.
|
||||||
|
*/
|
||||||
|
this.client.emit(Events.INTERACTION_CREATE, interaction);
|
||||||
|
|
||||||
|
return directPromise;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new RangeError('Invalid interaction data');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An express-like middleware factory which can be used
|
||||||
|
* with webhook interactions.
|
||||||
|
* @returns {Function} The middleware function.
|
||||||
|
*/
|
||||||
|
middleware() {
|
||||||
|
return async (req, res) => {
|
||||||
|
const timestamp = req.get('x-signature-timestamp');
|
||||||
|
const signature = req.get('x-signature-ed25519');
|
||||||
|
|
||||||
|
const chunks = [];
|
||||||
|
for await (const chunk of req) {
|
||||||
|
chunks.push(chunk);
|
||||||
|
}
|
||||||
|
const body = Buffer.concat(chunks);
|
||||||
|
|
||||||
|
if (sodium === undefined) {
|
||||||
|
sodium = require('../util/Sodium');
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
!sodium.methods.verify(
|
||||||
|
Buffer.from(signature, 'hex'),
|
||||||
|
Buffer.concat([Buffer.from(timestamp), body]),
|
||||||
|
this.publicKey,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
res.status(403).end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = JSON.parse(body.toString());
|
||||||
|
|
||||||
|
const result = await this.handle(data);
|
||||||
|
res.status(200).end(JSON.stringify(result));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleFromGateway(data) {
|
||||||
|
const result = await this.handle(data);
|
||||||
|
|
||||||
|
await this.client.api.interactions(data.id, data.token).callback.post({
|
||||||
|
data: result,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = InteractionClient;
|
||||||
|
|
@ -37,6 +37,7 @@ class ActionsManager {
|
||||||
this.register(require('./GuildIntegrationsUpdate'));
|
this.register(require('./GuildIntegrationsUpdate'));
|
||||||
this.register(require('./WebhooksUpdate'));
|
this.register(require('./WebhooksUpdate'));
|
||||||
this.register(require('./TypingStart'));
|
this.register(require('./TypingStart'));
|
||||||
|
this.register(require('./InteractionCreate'));
|
||||||
}
|
}
|
||||||
|
|
||||||
register(Action) {
|
register(Action) {
|
||||||
|
|
|
||||||
15
src/client/actions/InteractionCreate.js
Normal file
15
src/client/actions/InteractionCreate.js
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Action = require('./Action');
|
||||||
|
|
||||||
|
class InteractionCreateAction extends Action {
|
||||||
|
handle(data) {
|
||||||
|
this.client.interactionClient.handleFromGateway(data).catch(e => {
|
||||||
|
this.client.emit('error', e);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = InteractionCreateAction;
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { Writable } = require('stream');
|
const { Writable } = require('stream');
|
||||||
const secretbox = require('../util/Secretbox');
|
const secretbox = require('../../../util/Sodium');
|
||||||
const Silence = require('../util/Silence');
|
const Silence = require('../util/Silence');
|
||||||
const VolumeInterface = require('../util/VolumeInterface');
|
const VolumeInterface = require('../util/VolumeInterface');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
|
const sodium = require('../../../util/Sodium');
|
||||||
const Speaking = require('../../../util/Speaking');
|
const Speaking = require('../../../util/Speaking');
|
||||||
const secretbox = require('../util/Secretbox');
|
|
||||||
const { SILENCE_FRAME } = require('../util/Silence');
|
const { SILENCE_FRAME } = require('../util/Silence');
|
||||||
|
|
||||||
// The delay between packets when a user is considered to have stopped speaking
|
// The delay between packets when a user is considered to have stopped speaking
|
||||||
|
|
@ -58,7 +58,7 @@ class PacketHandler extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open packet
|
// Open packet
|
||||||
let packet = secretbox.methods.open(buffer.slice(12, end), this.nonce, secret_key);
|
let packet = sodium.methods.open(buffer.slice(12, end), this.nonce, secret_key);
|
||||||
if (!packet) return new Error('Failed to decrypt voice packet');
|
if (!packet) return new Error('Failed to decrypt voice packet');
|
||||||
packet = Buffer.from(packet);
|
packet = Buffer.from(packet);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ class WebSocketManager extends EventEmitter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current status of this WebSocketManager
|
* The current status of this WebSocketManager
|
||||||
* @type {number}
|
* @type {Status}
|
||||||
*/
|
*/
|
||||||
this.status = Status.IDLE;
|
this.status = Status.IDLE;
|
||||||
|
|
||||||
|
|
|
||||||
5
src/client/websocket/handlers/INTERACTION_CREATE.js
Normal file
5
src/client/websocket/handlers/INTERACTION_CREATE.js
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
module.exports = (client, packet) => {
|
||||||
|
client.actions.InteractionCreate.handle(packet.d);
|
||||||
|
};
|
||||||
|
|
@ -6,6 +6,7 @@ module.exports = {
|
||||||
// "Root" classes (starting points)
|
// "Root" classes (starting points)
|
||||||
BaseClient: require('./client/BaseClient'),
|
BaseClient: require('./client/BaseClient'),
|
||||||
Client: require('./client/Client'),
|
Client: require('./client/Client'),
|
||||||
|
InteractionClient: require('./client/InteractionClient'),
|
||||||
Shard: require('./sharding/Shard'),
|
Shard: require('./sharding/Shard'),
|
||||||
ShardClientUtil: require('./sharding/ShardClientUtil'),
|
ShardClientUtil: require('./sharding/ShardClientUtil'),
|
||||||
ShardingManager: require('./sharding/ShardingManager'),
|
ShardingManager: require('./sharding/ShardingManager'),
|
||||||
|
|
@ -58,6 +59,7 @@ module.exports = {
|
||||||
|
|
||||||
// Structures
|
// Structures
|
||||||
Application: require('./structures/interfaces/Application'),
|
Application: require('./structures/interfaces/Application'),
|
||||||
|
ApplicationCommand: require('./structures/ApplicationCommand'),
|
||||||
Base: require('./structures/Base'),
|
Base: require('./structures/Base'),
|
||||||
Activity: require('./structures/Presence').Activity,
|
Activity: require('./structures/Presence').Activity,
|
||||||
APIMessage: require('./structures/APIMessage'),
|
APIMessage: require('./structures/APIMessage'),
|
||||||
|
|
@ -80,6 +82,7 @@ module.exports = {
|
||||||
GuildPreview: require('./structures/GuildPreview'),
|
GuildPreview: require('./structures/GuildPreview'),
|
||||||
GuildTemplate: require('./structures/GuildTemplate'),
|
GuildTemplate: require('./structures/GuildTemplate'),
|
||||||
Integration: require('./structures/Integration'),
|
Integration: require('./structures/Integration'),
|
||||||
|
Interaction: require('./structures/Interaction'),
|
||||||
Invite: require('./structures/Invite'),
|
Invite: require('./structures/Invite'),
|
||||||
Message: require('./structures/Message'),
|
Message: require('./structures/Message'),
|
||||||
MessageAttachment: require('./structures/MessageAttachment'),
|
MessageAttachment: require('./structures/MessageAttachment'),
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,16 @@ class APIMessage {
|
||||||
return this.target instanceof Message;
|
return this.target instanceof Message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the target is an interaction
|
||||||
|
* @type {boolean}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get isInteraction() {
|
||||||
|
const Interaction = require('./Interaction');
|
||||||
|
return this.target instanceof Interaction;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes the content of this message.
|
* Makes the content of this message.
|
||||||
* @returns {?(string|string[])}
|
* @returns {?(string|string[])}
|
||||||
|
|
@ -166,6 +176,8 @@ class APIMessage {
|
||||||
if (this.isMessage) {
|
if (this.isMessage) {
|
||||||
// eslint-disable-next-line eqeqeq
|
// eslint-disable-next-line eqeqeq
|
||||||
flags = this.options.flags != null ? new MessageFlags(this.options.flags).bitfield : this.target.flags.bitfield;
|
flags = this.options.flags != null ? new MessageFlags(this.options.flags).bitfield : this.target.flags.bitfield;
|
||||||
|
} else if (this.isInteraction) {
|
||||||
|
flags = this.options.ephemeral ? MessageFlags.EPHEMERAL : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
let allowedMentions =
|
let allowedMentions =
|
||||||
|
|
|
||||||
102
src/structures/ApplicationCommand.js
Normal file
102
src/structures/ApplicationCommand.js
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Base = require('./Base');
|
||||||
|
const { ApplicationCommandOptionType } = require('../util/Constants');
|
||||||
|
const Snowflake = require('../util/Snowflake');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an application command, see {@link InteractionClient}.
|
||||||
|
* @extends {Base}
|
||||||
|
*/
|
||||||
|
class ApplicationCommand extends Base {
|
||||||
|
constructor(client, data, guildID) {
|
||||||
|
super(client);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the guild this command is part of, if any.
|
||||||
|
* @type {Snowflake?}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.guildID = guildID || null;
|
||||||
|
|
||||||
|
this._patch(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
_patch(data) {
|
||||||
|
/**
|
||||||
|
* The ID of this command.
|
||||||
|
* @type {Snowflake}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.id = data.id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the application which owns this command.
|
||||||
|
* @type {Snowflake}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.appplicationID = data.application_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of this command.
|
||||||
|
* @type {string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.name = data.name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The description of this command.
|
||||||
|
* @type {string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.description = data.description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The options of this command.
|
||||||
|
* @type {Object[]}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.options = data.options.map(function m(o) {
|
||||||
|
return {
|
||||||
|
type: ApplicationCommandOptionType[o.type],
|
||||||
|
name: o.name,
|
||||||
|
description: o.description,
|
||||||
|
default: o.default,
|
||||||
|
required: o.required,
|
||||||
|
choices: o.choices,
|
||||||
|
options: o.options ? o.options.map(m) : undefined,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The timestamp the command was created at.
|
||||||
|
* @type {number}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get createdTimestamp() {
|
||||||
|
return Snowflake.deconstruct(this.id).timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time the command was created at.
|
||||||
|
* @type {Date}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get createdAt() {
|
||||||
|
return new Date(this.createdTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete this command.
|
||||||
|
*/
|
||||||
|
async delete() {
|
||||||
|
let path = this.client.api.applications('@me');
|
||||||
|
if (this.guildID) {
|
||||||
|
path = path.guilds(this.guildID);
|
||||||
|
}
|
||||||
|
await path.commands(this.id).delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = ApplicationCommand;
|
||||||
|
|
@ -17,7 +17,7 @@ class BaseGuildEmoji extends Emoji {
|
||||||
*/
|
*/
|
||||||
this.guild = guild;
|
this.guild = guild;
|
||||||
|
|
||||||
this.requireColons = null;
|
this.requiresColons = null;
|
||||||
this.managed = null;
|
this.managed = null;
|
||||||
this.available = null;
|
this.available = null;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1432,6 +1432,23 @@ class Guild extends Base {
|
||||||
.then(() => this);
|
.then(() => this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the commands associated with this guild.
|
||||||
|
* @returns {ApplicationCommand[]} A list of commands.
|
||||||
|
*/
|
||||||
|
getCommands() {
|
||||||
|
return this.client.interactionClient.getCommands(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a command. See {@link InteractionClient}.
|
||||||
|
* @param {Object} command The command description.
|
||||||
|
* @returns {ApplicationCommand} The created command.
|
||||||
|
*/
|
||||||
|
createCommand(command) {
|
||||||
|
return this.client.interactionClient.createCommand(command, this.id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Leaves the guild.
|
* Leaves the guild.
|
||||||
* @returns {Promise<Guild>}
|
* @returns {Promise<Guild>}
|
||||||
|
|
|
||||||
133
src/structures/Interaction.js
Normal file
133
src/structures/Interaction.js
Normal file
|
|
@ -0,0 +1,133 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const APIMessage = require('./APIMessage');
|
||||||
|
const Base = require('./Base');
|
||||||
|
const Snowflake = require('../util/Snowflake');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an interaction, see {@link InteractionClient}.
|
||||||
|
* @extends {Base}
|
||||||
|
*/
|
||||||
|
class Interaction extends Base {
|
||||||
|
constructor(client, data, syncHandle) {
|
||||||
|
super(client);
|
||||||
|
this.syncHandle = syncHandle;
|
||||||
|
this._patch(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
_patch(data) {
|
||||||
|
/**
|
||||||
|
* The ID of this interaction.
|
||||||
|
* @type {Snowflake}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.id = data.id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The token of this interaction.
|
||||||
|
* @type {string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.token = data.token;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ID of the invoked command.
|
||||||
|
* @type {Snowflake}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.commandID = data.data.id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the invoked command.
|
||||||
|
* @type {string}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.commandName = data.data.name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The options passed to the command.
|
||||||
|
* @type {Object}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.options = data.data.options;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The channel this interaction was sent in.
|
||||||
|
* @type {?Channel}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.channel = this.client.channels?.cache.get(data.channel_id) || null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The guild this interaction was sent in, if any.
|
||||||
|
* @type {?Guild}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.guild = data.guild_id ? this.client.guilds?.cache.get(data.guild_id) : null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this interaction was sent in a guild, the member which sent it.
|
||||||
|
* @type {?Member}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
this.member = data.member ? this.guild?.members.add(data.member, false) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The timestamp the interaction was created at.
|
||||||
|
* @type {number}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get createdTimestamp() {
|
||||||
|
return Snowflake.deconstruct(this.id).timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time the interaction was created at.
|
||||||
|
* @type {Date}
|
||||||
|
* @readonly
|
||||||
|
*/
|
||||||
|
get createdAt() {
|
||||||
|
return new Date(this.createdTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acknowledge this interaction without content.
|
||||||
|
*/
|
||||||
|
async acknowledge() {
|
||||||
|
await this.syncHandle.acknowledge();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reply to this interaction.
|
||||||
|
* @param {(StringResolvable | APIMessage)?} content The content for the message.
|
||||||
|
* @param {(MessageOptions | MessageAdditions)?} options The options to provide.
|
||||||
|
*/
|
||||||
|
async reply(content, options) {
|
||||||
|
let apiMessage;
|
||||||
|
|
||||||
|
if (content instanceof APIMessage) {
|
||||||
|
apiMessage = content.resolveData();
|
||||||
|
} else {
|
||||||
|
apiMessage = APIMessage.create(this, content, options).resolveData();
|
||||||
|
if (Array.isArray(apiMessage.data.content)) {
|
||||||
|
throw new Error('Message is too long');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolved = await apiMessage.resolveFiles();
|
||||||
|
|
||||||
|
if (!this.syncHandle.reply(resolved)) {
|
||||||
|
const clientID =
|
||||||
|
this.client.interactionClient.clientID || (await this.client.api.oauth2.applications('@me').get()).id;
|
||||||
|
|
||||||
|
await this.client.api.webhooks(clientID, this.token).post({
|
||||||
|
auth: false,
|
||||||
|
data: resolved.data,
|
||||||
|
files: resolved.files,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Interaction;
|
||||||
|
|
@ -278,7 +278,7 @@ class User extends Base {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches this user's flags.
|
* Fetches this user's flags.
|
||||||
* @param {boolean} [force=false] Whether to skip the cache check and request the AP
|
* @param {boolean} [force=false] Whether to skip the cache check and request the API
|
||||||
* @returns {Promise<UserFlags>}
|
* @returns {Promise<UserFlags>}
|
||||||
*/
|
*/
|
||||||
async fetchFlags(force = false) {
|
async fetchFlags(force = false) {
|
||||||
|
|
@ -290,7 +290,7 @@ class User extends Base {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches this user.
|
* Fetches this user.
|
||||||
* @param {boolean} [force=false] Whether to skip the cache check and request the AP
|
* @param {boolean} [force=false] Whether to skip the cache check and request the API
|
||||||
* @returns {Promise<User>}
|
* @returns {Promise<User>}
|
||||||
*/
|
*/
|
||||||
fetch(force = false) {
|
fetch(force = false) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
|
const { TypeError } = require('../../errors');
|
||||||
const Collection = require('../../util/Collection');
|
const Collection = require('../../util/Collection');
|
||||||
const Util = require('../../util/Util');
|
const Util = require('../../util/Util');
|
||||||
|
|
||||||
|
|
@ -74,6 +75,10 @@ class Collector extends EventEmitter {
|
||||||
*/
|
*/
|
||||||
this._idletimeout = null;
|
this._idletimeout = null;
|
||||||
|
|
||||||
|
if (typeof filter !== 'function') {
|
||||||
|
throw new TypeError('INVALID_TYPE', 'filter', 'function');
|
||||||
|
}
|
||||||
|
|
||||||
this.handleCollect = this.handleCollect.bind(this);
|
this.handleCollect = this.handleCollect.bind(this);
|
||||||
this.handleDispose = this.handleDispose.bind(this);
|
this.handleDispose = this.handleDispose.bind(this);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,14 +77,14 @@ exports.DefaultOptions = {
|
||||||
/**
|
/**
|
||||||
* HTTP options
|
* HTTP options
|
||||||
* @typedef {Object} HTTPOptions
|
* @typedef {Object} HTTPOptions
|
||||||
* @property {number} [version=7] API version to use
|
* @property {number} [version=8] API version to use
|
||||||
* @property {string} [api='https://discord.com/api'] Base url of the API
|
* @property {string} [api='https://discord.com/api'] Base url of the API
|
||||||
* @property {string} [cdn='https://cdn.discordapp.com'] Base url of the CDN
|
* @property {string} [cdn='https://cdn.discordapp.com'] Base url of the CDN
|
||||||
* @property {string} [invite='https://discord.gg'] Base url of invites
|
* @property {string} [invite='https://discord.gg'] Base url of invites
|
||||||
* @property {string} [template='https://discord.new'] Base url of templates
|
* @property {string} [template='https://discord.new'] Base url of templates
|
||||||
*/
|
*/
|
||||||
http: {
|
http: {
|
||||||
version: 7,
|
version: 8,
|
||||||
api: 'https://discord.com/api',
|
api: 'https://discord.com/api',
|
||||||
cdn: 'https://cdn.discordapp.com',
|
cdn: 'https://cdn.discordapp.com',
|
||||||
invite: 'https://discord.gg',
|
invite: 'https://discord.gg',
|
||||||
|
|
@ -282,6 +282,7 @@ exports.Events = {
|
||||||
SHARD_READY: 'shardReady',
|
SHARD_READY: 'shardReady',
|
||||||
SHARD_RESUME: 'shardResume',
|
SHARD_RESUME: 'shardResume',
|
||||||
INVALIDATED: 'invalidated',
|
INVALIDATED: 'invalidated',
|
||||||
|
INTERACTION_CREATE: 'interactionCreate',
|
||||||
RAW: 'raw',
|
RAW: 'raw',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -345,6 +346,7 @@ exports.PartialTypes = keyMirror(['USER', 'CHANNEL', 'GUILD_MEMBER', 'MESSAGE',
|
||||||
* * VOICE_STATE_UPDATE
|
* * VOICE_STATE_UPDATE
|
||||||
* * VOICE_SERVER_UPDATE
|
* * VOICE_SERVER_UPDATE
|
||||||
* * WEBHOOKS_UPDATE
|
* * WEBHOOKS_UPDATE
|
||||||
|
* * INTERACTION_CREATE
|
||||||
* @typedef {string} WSEventType
|
* @typedef {string} WSEventType
|
||||||
*/
|
*/
|
||||||
exports.WSEvents = keyMirror([
|
exports.WSEvents = keyMirror([
|
||||||
|
|
@ -384,6 +386,7 @@ exports.WSEvents = keyMirror([
|
||||||
'VOICE_STATE_UPDATE',
|
'VOICE_STATE_UPDATE',
|
||||||
'VOICE_SERVER_UPDATE',
|
'VOICE_SERVER_UPDATE',
|
||||||
'WEBHOOKS_UPDATE',
|
'WEBHOOKS_UPDATE',
|
||||||
|
'INTERACTION_CREATE',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -676,6 +679,33 @@ exports.WebhookTypes = [
|
||||||
'Channel Follower',
|
'Channel Follower',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
exports.ApplicationCommandOptionType = {
|
||||||
|
SUB_COMMAND: 1,
|
||||||
|
SUB_COMMAND_GROUP: 2,
|
||||||
|
STRING: 3,
|
||||||
|
INTEGER: 4,
|
||||||
|
BOOLEAN: 5,
|
||||||
|
USER: 6,
|
||||||
|
CHANNEL: 7,
|
||||||
|
ROLE: 8,
|
||||||
|
};
|
||||||
|
Object.entries(exports.ApplicationCommandOptionType).forEach(([k, v]) => {
|
||||||
|
exports.ApplicationCommandOptionType[v] = k;
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.InteractionType = {
|
||||||
|
PING: 1,
|
||||||
|
APPLICATION_COMMAND: 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.InteractionResponseType = {
|
||||||
|
PONG: 1,
|
||||||
|
ACKNOWLEDGE: 2,
|
||||||
|
CHANNEL_MESSAGE: 3,
|
||||||
|
CHANNEL_MESSAGE_WITH_SOURCE: 4,
|
||||||
|
ACKNOWLEDGE_WITH_SOURCE: 5,
|
||||||
|
};
|
||||||
|
|
||||||
function keyMirror(arr) {
|
function keyMirror(arr) {
|
||||||
let tmp = Object.create(null);
|
let tmp = Object.create(null);
|
||||||
for (const value of arr) tmp[value] = value;
|
for (const value of arr) tmp[value] = value;
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ class MessageFlags extends BitField {}
|
||||||
* * `SUPPRESS_EMBEDS`
|
* * `SUPPRESS_EMBEDS`
|
||||||
* * `SOURCE_MESSAGE_DELETED`
|
* * `SOURCE_MESSAGE_DELETED`
|
||||||
* * `URGENT`
|
* * `URGENT`
|
||||||
|
* * `EPHEMERAL`
|
||||||
* @type {Object}
|
* @type {Object}
|
||||||
* @see {@link https://discord.com/developers/docs/resources/channel#message-object-message-flags}
|
* @see {@link https://discord.com/developers/docs/resources/channel#message-object-message-flags}
|
||||||
*/
|
*/
|
||||||
|
|
@ -31,6 +32,7 @@ MessageFlags.FLAGS = {
|
||||||
SUPPRESS_EMBEDS: 1 << 2,
|
SUPPRESS_EMBEDS: 1 << 2,
|
||||||
SOURCE_MESSAGE_DELETED: 1 << 3,
|
SOURCE_MESSAGE_DELETED: 1 << 3,
|
||||||
URGENT: 1 << 4,
|
URGENT: 1 << 4,
|
||||||
|
EPHEMERAL: 1 << 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = MessageFlags;
|
module.exports = MessageFlags;
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,19 @@ const libs = {
|
||||||
open: sodium.api.crypto_secretbox_open_easy,
|
open: sodium.api.crypto_secretbox_open_easy,
|
||||||
close: sodium.api.crypto_secretbox_easy,
|
close: sodium.api.crypto_secretbox_easy,
|
||||||
random: n => sodium.randombytes_buf(n),
|
random: n => sodium.randombytes_buf(n),
|
||||||
|
verify: sodium.api.crypto_sign_verify_detached,
|
||||||
}),
|
}),
|
||||||
'libsodium-wrappers': sodium => ({
|
'libsodium-wrappers': sodium => ({
|
||||||
open: sodium.crypto_secretbox_open_easy,
|
open: sodium.crypto_secretbox_open_easy,
|
||||||
close: sodium.crypto_secretbox_easy,
|
close: sodium.crypto_secretbox_easy,
|
||||||
random: n => sodium.randombytes_buf(n),
|
random: n => sodium.randombytes_buf(n),
|
||||||
|
verify: sodium.crypto_sign_verify_detached,
|
||||||
}),
|
}),
|
||||||
tweetnacl: tweetnacl => ({
|
tweetnacl: tweetnacl => ({
|
||||||
open: tweetnacl.secretbox.open,
|
open: tweetnacl.secretbox.open,
|
||||||
close: tweetnacl.secretbox,
|
close: tweetnacl.secretbox,
|
||||||
random: n => tweetnacl.randomBytes(n),
|
random: n => tweetnacl.randomBytes(n),
|
||||||
|
verify: (s, d, p) => tweetnacl.sign.detached.verify(d, s, p),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
Loading…
Reference in a new issue