Compare commits
No commits in common. "b4a288154790b4bfd0831435a0f39d54a1dd8d89" and "9bb30097a40c91fb476af8d6d0480a96b0d111b3" have entirely different histories.
b4a2881547
...
9bb30097a4
18 changed files with 565 additions and 149 deletions
72
.drone.yml
72
.drone.yml
|
@ -1,72 +0,0 @@
|
||||||
kind: pipeline
|
|
||||||
type: docker
|
|
||||||
name: default
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: install
|
|
||||||
image: node:14
|
|
||||||
commands:
|
|
||||||
- echo ===== INSTALLING DEPENDENCIES =====
|
|
||||||
- yarn install
|
|
||||||
|
|
||||||
- name: build
|
|
||||||
image: node:14
|
|
||||||
commands:
|
|
||||||
- echo ===== BUILDING APPLICATION =====
|
|
||||||
- yarn build
|
|
||||||
|
|
||||||
- name: publish-dev
|
|
||||||
image: node:14
|
|
||||||
commands:
|
|
||||||
- echo ===== PUBLISHING APPLICATION =====
|
|
||||||
- echo "//registry.npmjs.org/:_authToken=$${NPM_TOKEN}" > ~/.npmrc
|
|
||||||
- yarn version $${(node -pe \'require("./package.json").version\')}-$${(git rev-parse HEAD)}.$${(date +%s)}
|
|
||||||
- npm publish --tag dev --access public
|
|
||||||
environment:
|
|
||||||
NPM_TOKEN:
|
|
||||||
from_secret: GITEA_TOKEN
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- master
|
|
||||||
- refactor/rewrite
|
|
||||||
event:
|
|
||||||
- push
|
|
||||||
|
|
||||||
- name: publish-stable
|
|
||||||
image: node:14
|
|
||||||
commands:
|
|
||||||
- echo ===== PUBLISHING APPLICATION =====
|
|
||||||
- yarn semantic-release
|
|
||||||
environment:
|
|
||||||
GITEA_URL: "https://code.relms.dev/NeonJS/library"
|
|
||||||
GITEA_TOKEN:
|
|
||||||
from_secret: GITEA_TOKEN
|
|
||||||
NPM_TOKEN:
|
|
||||||
from_secret: GITEA_TOKEN
|
|
||||||
GIT_AUTHOR_NAME: "DroneCI"
|
|
||||||
GIT_AUTHOR_EMAIL: "drone@relms.dev"
|
|
||||||
GIT_COMMITTER_NAME: "DroneCI"
|
|
||||||
GIT_COMMITTER_EMAIL: "drone@relms.dev"
|
|
||||||
when:
|
|
||||||
branch:
|
|
||||||
- stable
|
|
||||||
event:
|
|
||||||
- push
|
|
||||||
|
|
||||||
- name: discord-notification
|
|
||||||
image: appleboy/drone-discord
|
|
||||||
settings:
|
|
||||||
webhook_id:
|
|
||||||
from_secret: DISCORD_WEBHOOK_ID
|
|
||||||
webhook_token:
|
|
||||||
from_secret: DISCORD_WEBHOOK_TOKEN
|
|
||||||
message: >
|
|
||||||
{{#success build.status}}
|
|
||||||
Build {{build.number}} succeeded.
|
|
||||||
{{else}}
|
|
||||||
Build {{build.number}} failed.
|
|
||||||
{{/success}}
|
|
||||||
when:
|
|
||||||
status:
|
|
||||||
- success
|
|
||||||
- failure
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -674,4 +674,4 @@ DerivedData/
|
||||||
|
|
||||||
# ---> Project
|
# ---> Project
|
||||||
!.yarn/releases
|
!.yarn/releases
|
||||||
/types
|
types
|
||||||
|
|
103
Jenkinsfile
vendored
Normal file
103
Jenkinsfile
vendored
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
pipeline {
|
||||||
|
agent {
|
||||||
|
docker {
|
||||||
|
image 'node:14'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
environment {
|
||||||
|
GITEA_URL = 'https://code.relms.dev/NeonJS/library'
|
||||||
|
GITEA_TOKEN = credentials('GITEA_TOKEN')
|
||||||
|
NPM_TOKEN = credentials('NPM_TOKEN')
|
||||||
|
DISCORD_WEBHOOK = credentials('DISCORD_WEBHOOK')
|
||||||
|
GIT_AUTHOR_NAME = 'JenkinsCI'
|
||||||
|
GIT_AUTHOR_EMAIL = 'jenkins@relms.dev'
|
||||||
|
GIT_COMMITTER_NAME = 'JenkinsCI'
|
||||||
|
GIT_COMMITTER_EMAIL = 'jenkins@relms.dev'
|
||||||
|
}
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('Checkout') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
echo '==========Checking out=========='
|
||||||
|
if (sh (script: "git log -1 | grep '.*\\[ci skip\\].*'", returnStatus: true)) {
|
||||||
|
error "'[ci skip]' found in git commit message. Aborting."
|
||||||
|
currentBuild.result = 'NOT_BUILT'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Dependencies') {
|
||||||
|
steps {
|
||||||
|
echo '==========Installing Dependencies=========='
|
||||||
|
sh 'yarn install'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Build') {
|
||||||
|
steps {
|
||||||
|
echo '==========Bundling Application=========='
|
||||||
|
sh 'yarn build'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Publish') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
echo '==========Publishing to NPM=========='
|
||||||
|
if (env.BRANCH_NAME == 'master') {
|
||||||
|
echo '==========Publishing as Development Version=========='
|
||||||
|
sh 'echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc'
|
||||||
|
sh 'yarn version $(node -pe \'require("./package.json").version\')-$(git rev-parse HEAD).$(date +%s)'
|
||||||
|
sh 'npm publish --tag dev --access public'
|
||||||
|
} else if (env.BRANCH_NAME == 'stable') {
|
||||||
|
echo '==========Publishing as Stable Version=========='
|
||||||
|
sh 'semantic-release'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
deleteDir()
|
||||||
|
cleanWs()
|
||||||
|
}
|
||||||
|
success {
|
||||||
|
sh 'tar -cf - dist/ | xz -9 -c - > neonjs-library.tar.xz'
|
||||||
|
archiveArtifacts artifacts: 'neonjs-library.tar.xz', fingerprint: true
|
||||||
|
|
||||||
|
discordSend description: 'CI build was a Success',
|
||||||
|
link: env.BUILD_URL,
|
||||||
|
result: 'SUCCESS',
|
||||||
|
title: env.JOB_NAME,
|
||||||
|
webhookURL: env.DISCORD_WEBHOOK
|
||||||
|
}
|
||||||
|
unstable {
|
||||||
|
sh 'tar -cf - dist/ | xz -9 -c - > neonjs-library.tar.xz'
|
||||||
|
archiveArtifacts artifacts: 'neonjs-library.tar.xz', fingerprint: true
|
||||||
|
|
||||||
|
discordSend description: 'CI build was Unstable.',
|
||||||
|
link: env.BUILD_URL,
|
||||||
|
result: 'UNSTABLE',
|
||||||
|
title: env.JOB_NAME,
|
||||||
|
webhookURL: env.DISCORD_WEBHOOK
|
||||||
|
}
|
||||||
|
failure {
|
||||||
|
discordSend description: 'CI build has Failed.',
|
||||||
|
link: env.BUILD_URL,
|
||||||
|
result: 'FAILURE',
|
||||||
|
title: env.JOB_NAME,
|
||||||
|
webhookURL: env.DISCORD_WEBHOOK
|
||||||
|
}
|
||||||
|
aborted {
|
||||||
|
discordSend description: 'CI build was Aborted',
|
||||||
|
link: env.BUILD_URL,
|
||||||
|
result: 'ABORTED',
|
||||||
|
title: env.JOB_NAME,
|
||||||
|
webhookURL: env.DISCORD_WEBHOOK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import { ApiManager } from './apiManager';
|
import { ApiManager } from './apiManager';
|
||||||
|
|
||||||
import type { Client } from '../client/client';
|
import type { Client } from '../client/client';
|
||||||
import type { IRequestOptions } from '../utils/types/api';
|
import type { IRequestOptions } from '../utils/types';
|
||||||
|
|
||||||
export class ApiClient {
|
export class ApiClient {
|
||||||
public client: Client;
|
public client: Client;
|
||||||
|
|
|
@ -2,11 +2,10 @@ import { AsyncQueue } from '@sapphire/async-queue';
|
||||||
import { AbortController } from 'abort-controller';
|
import { AbortController } from 'abort-controller';
|
||||||
import FormData from 'form-data';
|
import FormData from 'form-data';
|
||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import { sleep } from '../utils/sleep';
|
|
||||||
|
|
||||||
import type { ApiManager } from './apiManager';
|
|
||||||
import type { Client } from '../client/client';
|
import type { Client } from '../client/client';
|
||||||
import type { IMakeRequestOptions, IRouteIdentifier } from '../utils/types/api';
|
import { sleep } from '../utils/sleep';
|
||||||
|
import type { IMakeRequestOptions, IRouteIdentifier } from '../utils/types';
|
||||||
|
import type { ApiManager } from './apiManager';
|
||||||
|
|
||||||
|
|
||||||
function calculateReset(reset: number, resetAfter: number, serverDate: number): number {
|
function calculateReset(reset: number, resetAfter: number, serverDate: number): number {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { ApiClient } from './apiClient';
|
import { ApiClient } from './apiClient';
|
||||||
|
|
||||||
import type { Client } from '../client/client';
|
import type { Client } from '../client/client';
|
||||||
|
import type { IApiCreateMessage, IApiCreateSlashCommand, IApiUser, IFile } from '../utils/types';
|
||||||
|
|
||||||
export class ApiHelper {
|
export class ApiHelper {
|
||||||
public apiClient: ApiClient;
|
public apiClient: ApiClient;
|
||||||
|
@ -14,4 +15,36 @@ export class ApiHelper {
|
||||||
|
|
||||||
this.apiClient = new ApiClient(this.client, this._token);
|
this.apiClient = new ApiClient(this.client, this._token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Return message object
|
||||||
|
public async createMessage(channelId: string, options: IApiCreateMessage, files?: IFile[]): Promise<void> {
|
||||||
|
await this.apiClient.post({
|
||||||
|
path: `/channels/${channelId}/messages`,
|
||||||
|
requireAuth: true,
|
||||||
|
body: options,
|
||||||
|
files: files,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getCurrentUser(): Promise<IApiUser> {
|
||||||
|
return await this.apiClient.get<IApiUser>({
|
||||||
|
path: '/users/@me',
|
||||||
|
requireAuth: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async createSlashCommand(options: IApiCreateSlashCommand): Promise<void> {
|
||||||
|
await this.apiClient.post({
|
||||||
|
path: `/applications/${this.client.user.id}/commands`,
|
||||||
|
requireAuth: true,
|
||||||
|
body: options,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getUser(id: string): Promise<IApiUser> {
|
||||||
|
return await this.apiClient.get<IApiUser>({
|
||||||
|
path: `/users/${id}`,
|
||||||
|
requireAuth: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@ import { Snowflake } from '../utils/snowflake';
|
||||||
import { ApiHandler } from './apiHandler';
|
import { ApiHandler } from './apiHandler';
|
||||||
|
|
||||||
import type { Client } from '../client/client';
|
import type { Client } from '../client/client';
|
||||||
import type { ApiMethods, IMakeRequestOptions, IRouteIdentifier } from '../utils/types/api';
|
import type { ApiMethods, IMakeRequestOptions, IRouteIdentifier } from '../utils/types';
|
||||||
|
|
||||||
|
|
||||||
export class ApiManager {
|
export class ApiManager {
|
||||||
public client: Client;
|
public client: Client;
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
import { ApiHelper } from '../api/apiHelper';
|
import { ApiHelper } from '../api/apiHelper';
|
||||||
|
import { ClientUser } from '../structures/clientUser';
|
||||||
|
import { GatewayClient } from '../gateway/gatewayClient';
|
||||||
import { defaults } from '../utils/defaults';
|
import { defaults } from '../utils/defaults';
|
||||||
|
|
||||||
import type { IClientOptions } from '../utils/types/client';
|
import type { DeepRequired, IClientOptions } from '../utils/types';
|
||||||
import type { DeepRequired } from '../utils/types/common';
|
|
||||||
|
|
||||||
export class Client extends EventEmitter {
|
export class Client extends EventEmitter {
|
||||||
public readonly api: ApiHelper;
|
public readonly api: ApiHelper;
|
||||||
public readonly options: DeepRequired<IClientOptions>;
|
public readonly options: DeepRequired<IClientOptions>;
|
||||||
|
public readonly user: ClientUser;
|
||||||
|
public readonly ws: GatewayClient;
|
||||||
|
|
||||||
private _token: string;
|
private _token: string;
|
||||||
|
|
||||||
|
@ -19,5 +22,11 @@ export class Client extends EventEmitter {
|
||||||
this._token = token;
|
this._token = token;
|
||||||
|
|
||||||
this.api = new ApiHelper(this, this._token);
|
this.api = new ApiHelper(this, this._token);
|
||||||
|
this.user = new ClientUser(this);
|
||||||
|
this.ws = new GatewayClient(this, this._token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async login(): Promise<void> {
|
||||||
|
await this.ws.connect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
91
src/gateway/gatewayClient.ts
Normal file
91
src/gateway/gatewayClient.ts
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
import zlib from 'fast-zlib';
|
||||||
|
import os from 'os';
|
||||||
|
import WebSocket from 'ws';
|
||||||
|
|
||||||
|
import type { Client } from '../client/client';
|
||||||
|
import type { GatewayReceiveMessage, GatewaySendMessage } from '../utils/types';
|
||||||
|
|
||||||
|
export class GatewayClient {
|
||||||
|
public client: Client;
|
||||||
|
public connection: WebSocket | null;
|
||||||
|
public inflate: zlib.Inflate;
|
||||||
|
|
||||||
|
private _heartbeatInterval: number;
|
||||||
|
private _heartbeatIntervalTimer: NodeJS.Timer | null;
|
||||||
|
private _sequence: number;
|
||||||
|
private _token: string;
|
||||||
|
|
||||||
|
public constructor(client: Client, token: string) {
|
||||||
|
this.client = client;
|
||||||
|
|
||||||
|
this.connection = null;
|
||||||
|
this.inflate = new zlib.Inflate();
|
||||||
|
|
||||||
|
this._heartbeatInterval = 0;
|
||||||
|
this._heartbeatIntervalTimer= null;
|
||||||
|
this._sequence = 0;
|
||||||
|
this._token= token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async close(): Promise<void> {
|
||||||
|
if (!this.connection) throw new Error('You are not connected to the Discord WebSocket Gateway!');
|
||||||
|
|
||||||
|
this.connection.close(1000);
|
||||||
|
if (this._heartbeatIntervalTimer) clearTimeout(this._heartbeatIntervalTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async connect(): Promise<void> {
|
||||||
|
if (this.connection) throw new Error('You are already connected to the Discord WebSocket Gateway!');
|
||||||
|
|
||||||
|
this.connection = new WebSocket(
|
||||||
|
`${this.client.options.ws.url}/?v=${this.client.options.ws.version}${this.client.options.ws.compression ? '&compress=zlib-stream' : ''}&encoding=${this.client.options.ws.encoding}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.connection.on('message', async (msg: Buffer | string) => {
|
||||||
|
let parsedMessage: GatewayReceiveMessage;
|
||||||
|
|
||||||
|
if (this.client.options.ws.compression && typeof msg === 'object') parsedMessage = JSON.parse(this.inflate.process(msg).toString('utf8'));
|
||||||
|
else if (!this.client.options.ws.compression && typeof msg === 'string') parsedMessage = JSON.parse(msg);
|
||||||
|
else parsedMessage = JSON.parse(msg.toString('utf8'));
|
||||||
|
|
||||||
|
// if (parsedMessage.s) this._sequence = parsedMessage.s;
|
||||||
|
|
||||||
|
this.client.emit('raw', parsedMessage);
|
||||||
|
|
||||||
|
switch (parsedMessage.op) {
|
||||||
|
case 10:
|
||||||
|
this._heartbeatInterval = parsedMessage.d.heartbeat_interval;
|
||||||
|
|
||||||
|
this.send({
|
||||||
|
op: 2, d: {
|
||||||
|
compress: this.client.options.ws.compression,
|
||||||
|
intents: this.client.options.ws.intents,
|
||||||
|
large_threshold: this.client.options.ws.largeThreshold,
|
||||||
|
presence: this.client.options.presence,
|
||||||
|
properties: {
|
||||||
|
$browser: '@neonjs/library',
|
||||||
|
$device: '@neonjs/library',
|
||||||
|
$os: os.platform(),
|
||||||
|
},
|
||||||
|
token: this._token,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this._heartbeatIntervalTimer = setInterval(() => this._sendHeartbeat(), this._heartbeatInterval * 1000);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public send(data: GatewaySendMessage): void {
|
||||||
|
if (!this.connection) throw new Error('You are not connected to the Discord WebSocket Gateway!');
|
||||||
|
|
||||||
|
this.connection.send(JSON.stringify(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
private _sendHeartbeat(): void {
|
||||||
|
this.send({ op: 1, d: this._sequence });
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,3 +6,4 @@ export * from './client/client';
|
||||||
export * from './utils/defaults';
|
export * from './utils/defaults';
|
||||||
export * from './utils/sleep';
|
export * from './utils/sleep';
|
||||||
export * from './utils/snowflake';
|
export * from './utils/snowflake';
|
||||||
|
export * from './utils/types';
|
||||||
|
|
9
src/structures/clientUser.ts
Normal file
9
src/structures/clientUser.ts
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
import { User } from './user';
|
||||||
|
|
||||||
|
import type { Client } from '../client/client';
|
||||||
|
|
||||||
|
export class ClientUser extends User {
|
||||||
|
public constructor(client: Client) {
|
||||||
|
super(client);
|
||||||
|
}
|
||||||
|
}
|
18
src/structures/user.ts
Normal file
18
src/structures/user.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import type { IApiUser } from '..';
|
||||||
|
import type { Client } from '../client/client';
|
||||||
|
|
||||||
|
export class User {
|
||||||
|
public client: Client;
|
||||||
|
public id: string;
|
||||||
|
|
||||||
|
private _options: IApiUser;
|
||||||
|
|
||||||
|
public constructor(client: Client, options: IApiUser) {
|
||||||
|
this.client = client;
|
||||||
|
this._options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async fetch(id: string): Promise<IApiUser> {
|
||||||
|
return this.client.api.getUser(id);
|
||||||
|
}
|
||||||
|
}
|
51
src/utils/cacheManager.ts
Normal file
51
src/utils/cacheManager.ts
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import cacheManager from 'cache-manager';
|
||||||
|
import redisStore from 'cache-manager-ioredis';
|
||||||
|
|
||||||
|
import type { Client } from '../client/client';
|
||||||
|
|
||||||
|
export class CacheManager {
|
||||||
|
public client: Client;
|
||||||
|
|
||||||
|
private readonly _cacheManager: cacheManager.Cache;
|
||||||
|
|
||||||
|
public constructor(client: Client) {
|
||||||
|
this.client = client;
|
||||||
|
|
||||||
|
if (this.client.options.cache.cache === 'redis') this._cacheManager = cacheManager.caching({
|
||||||
|
store: redisStore,
|
||||||
|
ttl: this.client.options.cache.ttl,
|
||||||
|
...this.client.options.cache.options,
|
||||||
|
});
|
||||||
|
else this._cacheManager = cacheManager.caching({
|
||||||
|
store: 'memory',
|
||||||
|
ttl: this.client.options.cache.ttl,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async del(key: string): Promise<void> {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
this._cacheManager.del(key, (err) => {
|
||||||
|
if (err) rej(err);
|
||||||
|
else res();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async get<T>(key: string): Promise<T | undefined> {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
this._cacheManager.get<T>(key, (err, result) => {
|
||||||
|
if (err) rej(err);
|
||||||
|
else res(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async set<T>(key: string, value: T): Promise<T> {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
this._cacheManager.set<T>(key, value, this.client.options.cache.ttl, (err) => {
|
||||||
|
if (err) rej(err);
|
||||||
|
else res(value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import type { IDefaultOptions } from './types/common';
|
import type { IDefaultOptions } from './types';
|
||||||
|
|
||||||
export const defaults: IDefaultOptions = {
|
export const defaults: IDefaultOptions = {
|
||||||
clientOptions: {
|
clientOptions: {
|
||||||
|
@ -10,5 +10,18 @@ export const defaults: IDefaultOptions = {
|
||||||
url: 'https://discord.com/api',
|
url: 'https://discord.com/api',
|
||||||
version: 9,
|
version: 9,
|
||||||
},
|
},
|
||||||
|
cache: {
|
||||||
|
cache: 'memory',
|
||||||
|
ttl: 60,
|
||||||
|
},
|
||||||
|
presence: {},
|
||||||
|
ws: {
|
||||||
|
compression: true,
|
||||||
|
encoding: 'json',
|
||||||
|
intents: 0,
|
||||||
|
largeThreshold: 250,
|
||||||
|
url: 'wss://gateway.discord.gg',
|
||||||
|
version: 9,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
227
src/utils/types.ts
Normal file
227
src/utils/types.ts
Normal file
|
@ -0,0 +1,227 @@
|
||||||
|
import type IORedis from 'ioredis';
|
||||||
|
|
||||||
|
// Interfaces
|
||||||
|
export interface IApiClientOptions {
|
||||||
|
offset?: number;
|
||||||
|
requestTimeout?: number;
|
||||||
|
retryLimit?: number;
|
||||||
|
sweepInterval?: number;
|
||||||
|
url?: string;
|
||||||
|
version?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICacheMemoryClientOptions {
|
||||||
|
cache?: 'memory';
|
||||||
|
ttl?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICacheRedisClientOptions {
|
||||||
|
cache?: 'redis';
|
||||||
|
ttl?: number;
|
||||||
|
options: IORedis.RedisOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IClientOptions {
|
||||||
|
api?: IApiClientOptions;
|
||||||
|
cache?: ICacheMemoryClientOptions | ICacheRedisClientOptions;
|
||||||
|
presence?: IUpdatePresence;
|
||||||
|
ws?: IWebSocketClientOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IDefaultOptions {
|
||||||
|
clientOptions: IClientOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IFile {
|
||||||
|
file: Buffer;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMakeRequestOptions extends IRequestOptions {
|
||||||
|
method: ApiMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMessageEmbed {
|
||||||
|
author?: { name?: string, url?: string };
|
||||||
|
color?: number;
|
||||||
|
description?: string;
|
||||||
|
fields?: { inline?: boolean, name: string, value: string }[];
|
||||||
|
footer?: { icon_url?: string, text?: string };
|
||||||
|
image?: { url?: string };
|
||||||
|
provider?: { name?: string, url?: string };
|
||||||
|
timestamp?: number;
|
||||||
|
title?: string;
|
||||||
|
thumbnail?: { url?: string };
|
||||||
|
type?: 'rich';
|
||||||
|
url?: string;
|
||||||
|
video?: { url?: string };
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRequestOptions {
|
||||||
|
body?: unknown;
|
||||||
|
files?: IFile[];
|
||||||
|
headers?: Record<string, string>;
|
||||||
|
path: string;
|
||||||
|
reason?: string;
|
||||||
|
requireAuth?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRouteIdentifier {
|
||||||
|
majorParameter: string;
|
||||||
|
route: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IUpdatePresence {
|
||||||
|
activities?: {
|
||||||
|
name?: string;
|
||||||
|
type?: EActivityType;
|
||||||
|
url?: string;
|
||||||
|
}[];
|
||||||
|
afk?: boolean;
|
||||||
|
since?: number;
|
||||||
|
status?: EStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IWebSocketClientOptions {
|
||||||
|
compression?: boolean;
|
||||||
|
encoding?: 'json';
|
||||||
|
intents?: number;
|
||||||
|
largeThreshold?: number;
|
||||||
|
url?: string;
|
||||||
|
version?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Api Interfaces
|
||||||
|
// TODO: Add message components
|
||||||
|
// Dont add the files option. That goes into a separate option when creating a request
|
||||||
|
export interface IApiCreateMessage {
|
||||||
|
allowed_mentions?: {
|
||||||
|
parse?: 'everyone' | 'roles' | 'users'[];
|
||||||
|
replied_user?: boolean;
|
||||||
|
roles?: string[];
|
||||||
|
users?: string[];
|
||||||
|
};
|
||||||
|
content?: string;
|
||||||
|
embeds?: IMessageEmbed[];
|
||||||
|
message_reference?: {
|
||||||
|
channel_id?: string;
|
||||||
|
fail_if_not_exists?: boolean;
|
||||||
|
guild_id?: string;
|
||||||
|
message_id?: string;
|
||||||
|
};
|
||||||
|
tts?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IApiUser {
|
||||||
|
avatar: string;
|
||||||
|
bot?: boolean;
|
||||||
|
discriminator: string;
|
||||||
|
email?: string;
|
||||||
|
flags?: number;
|
||||||
|
id: string;
|
||||||
|
locale?: string;
|
||||||
|
mfa_enabled?: boolean;
|
||||||
|
premium_type?: number;
|
||||||
|
public_flags?: number;
|
||||||
|
username: string;
|
||||||
|
system?: boolean;
|
||||||
|
verified?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IApiCreateSlashCommand {
|
||||||
|
allowed_mentions?: {
|
||||||
|
parse?: 'everyone' | 'roles' | 'users'[];
|
||||||
|
replied_user?: boolean;
|
||||||
|
roles?: string[];
|
||||||
|
users?: string[];
|
||||||
|
};
|
||||||
|
content?: string;
|
||||||
|
embeds?: IMessageEmbed[];
|
||||||
|
files?: IFile[];
|
||||||
|
message_reference?: {
|
||||||
|
channel_id?: string;
|
||||||
|
fail_if_not_exists?: boolean;
|
||||||
|
guild_id?: string;
|
||||||
|
message_id?: string;
|
||||||
|
};
|
||||||
|
tts?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// WebSocket Gateway Message Interfaces
|
||||||
|
export interface IGatewayHeartbeatSend {
|
||||||
|
op: 1;
|
||||||
|
d: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add sharding when i get to it
|
||||||
|
export interface IGatewayIdentify {
|
||||||
|
op: 2;
|
||||||
|
d: {
|
||||||
|
compress: boolean;
|
||||||
|
intents: number;
|
||||||
|
large_threshold: number;
|
||||||
|
presence?: IUpdatePresence;
|
||||||
|
properties: {
|
||||||
|
$browser: string;
|
||||||
|
$device: string;
|
||||||
|
$os: string;
|
||||||
|
};
|
||||||
|
token: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IGatewayHeartbeat {
|
||||||
|
op: 10;
|
||||||
|
d: {
|
||||||
|
heartbeat_interval: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IGatewayHeartbeatAck {
|
||||||
|
op: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enums
|
||||||
|
export enum EActivityType {
|
||||||
|
GAME = 0,
|
||||||
|
STREAMING = 1,
|
||||||
|
LISTENING = 2,
|
||||||
|
WATCHING = 3,
|
||||||
|
COMPETING = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum EStatus {
|
||||||
|
DND = 'dnd',
|
||||||
|
IDLE = 'idle',
|
||||||
|
INVISIBLE = 'invisible',
|
||||||
|
OFFLINE = 'offline',
|
||||||
|
ONLINE = 'online',
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type Aliases
|
||||||
|
export type ApiMethods = 'DELETE' | 'GET' | 'PATCH' | 'POST' | 'PUT' ;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
|
export type Builtin = Date | Error | Function | Primitives | RegExp;
|
||||||
|
export type DeepRequired<T> = T extends Builtin
|
||||||
|
? NonNullable<T>
|
||||||
|
: T extends Map<infer K, infer V>
|
||||||
|
? Map<DeepRequired<K>, DeepRequired<V>>
|
||||||
|
: T extends ReadonlyMap<infer K, infer V>
|
||||||
|
? ReadonlyMap<DeepRequired<K>, DeepRequired<V>>
|
||||||
|
: T extends WeakMap<infer K, infer V>
|
||||||
|
? WeakMap<DeepRequired<K>, DeepRequired<V>>
|
||||||
|
: T extends Set<infer U>
|
||||||
|
? Set<DeepRequired<U>>
|
||||||
|
: T extends ReadonlySet<infer U>
|
||||||
|
? ReadonlySet<DeepRequired<U>>
|
||||||
|
: T extends WeakSet<infer U>
|
||||||
|
? WeakSet<DeepRequired<U>>
|
||||||
|
: T extends Promise<infer U>
|
||||||
|
? Promise<DeepRequired<U>>
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||||
|
: T extends {}
|
||||||
|
? { [K in keyof T]-?: DeepRequired<T[K]> }
|
||||||
|
: NonNullable<T>;
|
||||||
|
export type GatewayReceiveMessage = IGatewayHeartbeat | IGatewayHeartbeatAck;
|
||||||
|
export type GatewaySendMessage = IGatewayHeartbeatSend | IGatewayIdentify;
|
||||||
|
export type Primitives = bigint | boolean | null | number | string | symbol | undefined;
|
|
@ -1,21 +0,0 @@
|
||||||
import type { IFile } from './common';
|
|
||||||
|
|
||||||
export interface IMakeRequestOptions extends IRequestOptions {
|
|
||||||
method: ApiMethods;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IRequestOptions {
|
|
||||||
body?: unknown;
|
|
||||||
files?: IFile[];
|
|
||||||
headers?: Record<string, string>;
|
|
||||||
path: string;
|
|
||||||
reason?: string;
|
|
||||||
requireAuth?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IRouteIdentifier {
|
|
||||||
majorParameter: string;
|
|
||||||
route: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ApiMethods = 'DELETE' | 'GET' | 'PATCH' | 'POST' | 'PUT' ;
|
|
|
@ -1,12 +0,0 @@
|
||||||
export interface IApiClientOptions {
|
|
||||||
offset?: number;
|
|
||||||
requestTimeout?: number;
|
|
||||||
retryLimit?: number;
|
|
||||||
sweepInterval?: number;
|
|
||||||
url?: string;
|
|
||||||
version?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IClientOptions {
|
|
||||||
api?: IApiClientOptions;
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
import type { IClientOptions } from './client';
|
|
||||||
|
|
||||||
export interface IDefaultOptions {
|
|
||||||
clientOptions: IClientOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IFile {
|
|
||||||
file: Buffer;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
||||||
export type Builtin = Date | Error | Function | Primitives | RegExp;
|
|
||||||
export type DeepRequired<T> = T extends Builtin
|
|
||||||
? NonNullable<T>
|
|
||||||
: T extends Map<infer K, infer V>
|
|
||||||
? Map<DeepRequired<K>, DeepRequired<V>>
|
|
||||||
: T extends ReadonlyMap<infer K, infer V>
|
|
||||||
? ReadonlyMap<DeepRequired<K>, DeepRequired<V>>
|
|
||||||
: T extends WeakMap<infer K, infer V>
|
|
||||||
? WeakMap<DeepRequired<K>, DeepRequired<V>>
|
|
||||||
: T extends Set<infer U>
|
|
||||||
? Set<DeepRequired<U>>
|
|
||||||
: T extends ReadonlySet<infer U>
|
|
||||||
? ReadonlySet<DeepRequired<U>>
|
|
||||||
: T extends WeakSet<infer U>
|
|
||||||
? WeakSet<DeepRequired<U>>
|
|
||||||
: T extends Promise<infer U>
|
|
||||||
? Promise<DeepRequired<U>>
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
||||||
: T extends {}
|
|
||||||
? { [K in keyof T]-?: DeepRequired<T[K]> }
|
|
||||||
: NonNullable<T>;
|
|
||||||
export type Primitives = bigint | boolean | null | number | string | symbol | undefined;
|
|
Reference in a new issue