Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

snowtransfer

Package Overview
Dependencies
Maintainers
2
Versions
49
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

snowtransfer - npm Package Compare versions

Comparing version 0.5.0 to 0.5.1

20

dist/LocalBucket.d.ts

@@ -0,1 +1,2 @@

/// <reference types="node" />
/**

@@ -19,3 +20,3 @@ * Bucket used for saving ratelimits

*/
protected _remaining: number;
remaining: number;
/**

@@ -26,5 +27,5 @@ * Timeframe in milliseconds until the ratelimit resets

/**
* The Date time in which the bucket will reset
* Timeout that calls the reset function once the timeframe passed
*/
resetAt: number | null;
resetTimeout: NodeJS.Timeout | null;
/**

@@ -35,8 +36,10 @@ * ratelimiter used for ratelimiting requests

/**
* Key used internally to routify requests
*/
routeKey: string;
/**
* Create a new bucket
* @param ratelimiter ratelimiter used for ratelimiting requests
*/
constructor(ratelimiter: import("./Ratelimiter"));
get remaining(): number;
set remaining(value: number);
constructor(ratelimiter: import("./Ratelimiter"), routeKey: string);
/**

@@ -47,3 +50,4 @@ * Queue a function to be executed

*/
queue(fn: (bucket: LocalBucket) => any | Promise<any>): Promise<any>;
queue(fn: (bucket: LocalBucket) => any): Promise<any>;
runTimer(): void;
/**

@@ -54,3 +58,3 @@ * Check if there are any functions in the queue that haven't been executed yet

/**
* Reset the remaining tokens to the base limit
* Reset the remaining tokens to the base limit and removes the bucket from the rate limiter to save memory
*/

@@ -57,0 +61,0 @@ resetRemaining(): void;

58

dist/LocalBucket.js

@@ -10,20 +10,26 @@ "use strict";

*/
constructor(ratelimiter) {
constructor(ratelimiter, routeKey) {
/**
* array of functions waiting to be executed
*/
this.fnQueue = [];
/**
* Number of functions that may be executed during the timeframe set in limitReset
*/
this.limit = 5;
this._remaining = 1;
/**
* Remaining amount of executions during the current timeframe
*/
this.remaining = 1;
/**
* Timeframe in milliseconds until the ratelimit resets
*/
this.reset = 5000;
this.resetAt = null;
/**
* Timeout that calls the reset function once the timeframe passed
*/
this.resetTimeout = null;
this.ratelimiter = ratelimiter;
this.routeKey = routeKey;
}
get remaining() {
if (this.resetAt && this.resetAt <= Date.now()) {
this._remaining = this.limit;
this.resetAt = null;
}
return this._remaining;
}
set remaining(value) {
this._remaining = value;
}
/**

@@ -35,6 +41,4 @@ * Queue a function to be executed

queue(fn) {
return new Promise((res, rej) => {
return new Promise(res => {
const wrapFn = () => {
if (fn instanceof Promise)
return fn.then(res).catch(rej);
return res(fn(this));

@@ -46,2 +50,7 @@ };

}
runTimer() {
if (this.resetTimeout)
clearTimeout(this.resetTimeout);
this.resetTimeout = setTimeout(() => this.resetRemaining(), this.ratelimiter.global ? this.ratelimiter.globalReset : this.reset);
}
/**

@@ -53,6 +62,9 @@ * Check if there are any functions in the queue that haven't been executed yet

this.reset = 100;
if (this.ratelimiter.global && this.ratelimiter.globalResetAt > Date.now())
return;
if (this.ratelimiter.global)
return this.runTimer();
if (this.remaining === 0)
this.runTimer();
if (this.fnQueue.length > 0 && this.remaining !== 0) {
const queuedFunc = this.fnQueue.splice(0, 1)[0];
this.remaining--;
queuedFunc.callback();

@@ -63,8 +75,10 @@ this.checkQueue();

/**
* Reset the remaining tokens to the base limit
* Reset the remaining tokens to the base limit and removes the bucket from the rate limiter to save memory
*/
resetRemaining() {
this._remaining = this.limit;
this.resetAt = null;
this.checkQueue();
this.remaining = this.limit;
if (this.resetTimeout)
clearTimeout(this.resetTimeout);
this.resetTimeout = null;
delete this.ratelimiter.buckets[this.routeKey];
}

@@ -71,0 +85,0 @@ /**

@@ -192,15 +192,2 @@ /// <reference types="node" />

/**
* Batch edits permissions for all commands in a guild. Takes an Array of partial [guild application command permission](https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-guild-application-command-permissions-structure) objects.
* You can only add up to 10 permission overwrites for a command
* @param appId The Id of the application
* @param guildId The Id of the guild
* @param permissions New application command permissions data Array
* @returns An Array of [guild application command permission](https://discord.com/developers/docs/interactions/slash-commands#application-command-permissions-object-guild-application-command-permissions-structure) objects
*
* @example
* const client = new SnowTransfer("TOKEN")
* const permissions = await client.interaction.bulkEditGuildApplicationCommandPermissions("appId", "guildId", [{ id: "cmdId", permissions: [{ type: 2, id: "userId", permission: true }] }])
*/
batchEditGuildApplicationCommandPermissions(appId: string, guildId: string, permissions: Array<Pick<import("discord-typings").GuildApplicationCommandPermission, "id" | "permissions">>): Promise<Array<import("discord-typings").GuildApplicationCommandPermission>>;
/**
* Create a response to an Interaction

@@ -207,0 +194,0 @@ *

@@ -209,17 +209,2 @@ "use strict";

/**
* Batch edits permissions for all commands in a guild. Takes an Array of partial [guild application command permission](https://discord.com/developers/docs/interactions/application-commands#application-command-permissions-object-guild-application-command-permissions-structure) objects.
* You can only add up to 10 permission overwrites for a command
* @param appId The Id of the application
* @param guildId The Id of the guild
* @param permissions New application command permissions data Array
* @returns An Array of [guild application command permission](https://discord.com/developers/docs/interactions/slash-commands#application-command-permissions-object-guild-application-command-permissions-structure) objects
*
* @example
* const client = new SnowTransfer("TOKEN")
* const permissions = await client.interaction.bulkEditGuildApplicationCommandPermissions("appId", "guildId", [{ id: "cmdId", permissions: [{ type: 2, id: "userId", permission: true }] }])
*/
batchEditGuildApplicationCommandPermissions(appId, guildId, permissions) {
return this.requestHandler.request(Endpoints_1.default.APPLICATION_GUILD_COMMANDS_PERMISSIONS(appId, guildId), "put", "json", permissions);
}
/**
* Create a response to an Interaction

@@ -226,0 +211,0 @@ *

@@ -1,2 +0,1 @@

/// <reference types="node" />
import LocalBucket from "./LocalBucket";

@@ -12,12 +11,3 @@ /**

global: boolean;
globalResetAt: number;
/**
* This is an interval to constantly check Buckets which should be reset or unreferenced from the RateLimiter to be swept by the garbage collector.
* This 1 timeout is more performant as compared to potentially many more ticking timers to reset individual bucket remaining values.
*
* YOU SHOULD NEVER OVERRIDE THIS UNLESS YOU KNOW WHAT YOU'RE DOING. REQUESTS MAY POSSIBLY NEVER EXECUTE WITHOUT THIS AND/OR MEMORY MAY SLOWLY CLIMB OVER TIME.
*/
protected _timeout: NodeJS.Timeout;
protected _timeoutFN: () => void;
protected _timeoutDuration: number;
globalReset: number;
constructor();

@@ -24,0 +14,0 @@ /**

@@ -12,24 +12,5 @@ "use strict";

constructor() {
this._timeoutDuration = 1000;
this.buckets = {};
this.global = false;
this.globalResetAt = 0;
this._timeoutFN = () => {
for (const routeKey of Object.keys(this.buckets)) {
const bkt = this.buckets[routeKey];
if (bkt.resetAt && bkt.resetAt < Date.now()) {
if (bkt.fnQueue.length)
bkt.resetRemaining();
else
delete this.buckets[routeKey];
}
else if (!bkt.resetAt && this.global && this.globalResetAt < Date.now()) {
if (bkt.fnQueue.length)
bkt.checkQueue();
else
delete this.buckets[routeKey];
}
}
};
this._timeout = setInterval(() => { this._timeoutFN(); }, this._timeoutDuration);
this.globalReset = 0;
}

@@ -60,3 +41,3 @@ /**

if (!this.buckets[routeKey])
this.buckets[routeKey] = new LocalBucket_1.default(this);
this.buckets[routeKey] = new LocalBucket_1.default(this, routeKey);
this.buckets[routeKey].queue(fn);

@@ -63,0 +44,0 @@ }

@@ -76,6 +76,5 @@ /// <reference types="node" />

* @param data data to send, if any
* @param amount amount of requests previously executed
* @returns Result of the request
*/
request(endpoint: string, method: HTTPMethod, dataType?: "json" | "multipart", data?: any | undefined, amount?: number): Promise<any>;
request(endpoint: string, method: HTTPMethod, dataType?: "json" | "multipart", data?: any | undefined): Promise<any>;
/**

@@ -92,3 +91,2 @@ * Apply the received ratelimit headers to the ratelimit bucket

* @param useParams Whether to send the data in the body or use query params
* @param amount amount of requests previously executed
* @returns Result of the request

@@ -95,0 +93,0 @@ */

@@ -74,6 +74,5 @@ "use strict";

* @param data data to send, if any
* @param amount amount of requests previously executed
* @returns Result of the request
*/
request(endpoint, method, dataType = "json", data = {}, amount = 0) {
request(endpoint, method, dataType = "json", data = {}) {
if (typeof data === "number")

@@ -90,23 +89,20 @@ data = String(data);

if (dataType == "json")
request = await this._request(endpoint, method, data, (method === "get" || endpoint.includes("/bans") || endpoint.includes("/prune")), amount);
request = await this._request(endpoint, method, data, (method === "get" || endpoint.includes("/bans") || endpoint.includes("/prune")));
else if (dataType == "multipart")
request = await this._multiPartRequest(endpoint, method, data, amount);
else {
const e = new Error("Forbidden dataType. Use json or multipart");
e.stack = stack;
throw e;
request = await this._multiPartRequest(endpoint, method, data);
else
throw new Error("Forbidden dataType. Use json or multipart");
if (request.statusCode && !Constants_1.default.OK_STATUS_CODES.includes(request.statusCode) && request.statusCode !== 429)
throw new DiscordAPIError(endpoint, ((_a = request.headers["content-type"]) === null || _a === void 0 ? void 0 : _a.startsWith("application/json")) ? await request.json() : request.body.toString(), method, request.statusCode);
this._applyRatelimitHeaders(bkt, request.headers);
if (request.statusCode === 429) {
const b = JSON.parse(request.body.toString()); // Discord says it will be a JSON, so if there's an error, sucks
if (b.global)
this.ratelimiter.global = true;
if (b.reset_after)
bkt.reset = b.reset_after * 1000;
bkt.runTimer();
this.emit("rateLimit", { timeout: bkt.reset, limit: bkt.limit, method: method, path: endpoint, route: this.ratelimiter.routify(endpoint, method) });
throw new DiscordAPIError(endpoint, b.message || "unknnown", method, request.statusCode);
}
// 429 and 502 are recoverable and will be re-tried automatically with 3 attempts max.
if (request.statusCode && !Constants_1.default.OK_STATUS_CODES.includes(request.statusCode) && ![429, 502].includes(request.statusCode)) {
const e = new DiscordAPIError(endpoint, ((_a = request.headers["content-type"]) === null || _a === void 0 ? void 0 : _a.startsWith("application/json")) ? await request.json() : request.body.toString(), method, request.statusCode);
e.stack = stack;
throw e;
}
if (request.statusCode && [429, 502].includes(request.statusCode)) {
if (request.statusCode === 429) {
this._applyRatelimitHeaders(bkt, request.headers);
this.emit("rateLimit", { timeout: bkt.reset, limit: bkt.limit, method: method, path: endpoint, route: this.ratelimiter.routify(endpoint, method) });
}
return this.request(endpoint, method, dataType, data, amount++);
}
this.emit("done", reqID, request);

@@ -141,17 +137,10 @@ if (request.body) {

_applyRatelimitHeaders(bkt, headers) {
if (headers["x-ratelimit-global"]) {
bkt.ratelimiter.global = true;
bkt.ratelimiter.globalResetAt = Date.now() + (parseFloat(headers["retry-after"]) * 1000);
}
if (headers["x-ratelimit-remaining"]) {
if (headers["x-ratelimit-remaining"])
bkt.remaining = parseInt(headers["x-ratelimit-remaining"]);
if (bkt.remaining === 0)
bkt.resetAt = Date.now() + bkt.reset;
}
else
bkt.remaining = 1;
if (headers["x-ratelimit-limit"])
bkt.limit = parseInt(headers["x-ratelimit-limit"]);
if (headers["retry-after"] && !headers["x-ratelimit-global"])
bkt.resetAt = Date.now() + (parseInt(headers["retry-after"]) * 1000); // The ms precision is not strictly necessary. It always rounds up, which is safe.
if (headers["x-ratelimit-reset"]) {
bkt.reset = parseInt(headers["x-ratelimit-reset"]) - Date.now();
bkt.runTimer();
}
}

@@ -163,8 +152,5 @@ /**

* @param useParams Whether to send the data in the body or use query params
* @param amount amount of requests previously executed
* @returns Result of the request
*/
async _request(endpoint, method, data, useParams = false, amount = 0) {
if (amount >= 3)
throw new Error("Max amount of rety attempts reached");
async _request(endpoint, method, data, useParams = false) {
const headers = {};

@@ -193,5 +179,3 @@ if (typeof data != "string" && data.reason) {

*/
async _multiPartRequest(endpoint, method, data, amount = 0) {
if (amount >= 3)
throw new Error("Max amount of rety attempts reached");
async _multiPartRequest(endpoint, method, data) {
const form = new form_data_1.default();

@@ -198,0 +182,0 @@ if (data.files && Array.isArray(data.files) && data.files.every(f => !!f.name && !!f.file)) {

@@ -20,8 +20,2 @@ import Ratelimiter from "./Ratelimiter";

disableEveryone: boolean;
sentryOptions: {
extra: {
snowtransferVersion: string;
};
};
useRedis: boolean;
};

@@ -28,0 +22,0 @@ token: string | undefined;

@@ -21,3 +21,2 @@ "use strict";

const Endpoints_1 = __importDefault(require("./Endpoints"));
const { version } = require("../package.json");
class SnowTransfer {

@@ -32,5 +31,5 @@ /**

throw new Error("Missing token");
if (token && !token.startsWith("Bot"))
if (token && (!token.startsWith("Bot") && !token.startsWith("Bearer")))
token = `Bot ${token}`;
this.options = { baseHost: Endpoints_1.default.BASE_HOST, disableEveryone: false, sentryOptions: { extra: { snowtransferVersion: version } }, useRedis: false };
this.options = { baseHost: Endpoints_1.default.BASE_HOST, disableEveryone: false };
this.token = token;

@@ -37,0 +36,0 @@ Object.assign(this.options, options);

{
"name": "snowtransfer",
"version": "0.5.0",
"version": "0.5.1",
"description": "Minimalistic Rest client for the Discord Api",

@@ -33,3 +33,3 @@ "main": "./dist/index.js",

"centra": "^2.5.0",
"discord-typings": "^10.1.0",
"discord-typings": "^10.1.2",
"form-data": "~4.0.0"

@@ -40,5 +40,5 @@ },

"@types/node": "^16.0.1",
"@typescript-eslint/eslint-plugin": "^5.18.0",
"@typescript-eslint/parser": "^5.18.0",
"eslint": "^8.13.0",
"@typescript-eslint/eslint-plugin": "^5.21.0",
"@typescript-eslint/parser": "^5.21.0",
"eslint": "^8.14.0",
"typedoc": "^0.22.15",

@@ -45,0 +45,0 @@ "typedoc-plugin-mdn-links": "^1.0.6",

@@ -15,2 +15,3 @@ # A minimalistic rest client for the discord api

- Well documented
- Supports both Bot and Bearer tokens (Bearer tokens will have much more limited access than Bot tokens)

@@ -17,0 +18,0 @@ ### General Usecase:

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc